TypedTransaction (EIP-2718) and Optional access list (EIP-2930) (#135)
This commit is contained in:
@@ -120,6 +120,7 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
|
||||
};
|
||||
|
||||
Box::new(future::ok(FilledTransactionRequest {
|
||||
tx_type: request.tx_type,
|
||||
from,
|
||||
used_default_from: request.from.is_none(),
|
||||
to: request.to,
|
||||
@@ -133,6 +134,7 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
|
||||
value: request.value.unwrap_or_else(|| 0.into()),
|
||||
data: request.data.unwrap_or_else(Vec::new),
|
||||
condition: request.condition,
|
||||
access_list: request.access_list,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,10 @@ use bytes::Bytes;
|
||||
use crypto::DEFAULT_MAC;
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use ethkey::Signature;
|
||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
||||
use jsonrpc_core::{Error, ErrorCode};
|
||||
use types::transaction::{
|
||||
AccessListTx, Action, SignedTransaction, Transaction, TypedTransaction, TypedTxId,
|
||||
};
|
||||
|
||||
use jsonrpc_core::Result;
|
||||
use v1::helpers::{errors, FilledTransactionRequest};
|
||||
@@ -48,16 +51,28 @@ impl super::Accounts for Signer {
|
||||
nonce: U256,
|
||||
password: SignWith,
|
||||
) -> Result<WithToken<SignedTransaction>> {
|
||||
let t = Transaction {
|
||||
nonce: nonce,
|
||||
let legacy_tx = Transaction {
|
||||
nonce,
|
||||
action: filled.to.map_or(Action::Create, Action::Call),
|
||||
gas: filled.gas,
|
||||
gas_price: filled.gas_price,
|
||||
value: filled.value,
|
||||
data: filled.data,
|
||||
};
|
||||
let t = match filled.tx_type {
|
||||
TypedTxId::Legacy => TypedTransaction::Legacy(legacy_tx),
|
||||
TypedTxId::AccessList => {
|
||||
if filled.access_list.is_none() {
|
||||
return Err(Error::new(ErrorCode::InvalidParams));
|
||||
}
|
||||
TypedTransaction::AccessList(AccessListTx::new(
|
||||
legacy_tx,
|
||||
filled.access_list.unwrap(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let hash = t.hash(chain_id);
|
||||
let hash = t.signature_hash(chain_id);
|
||||
let signature = signature(&*self.accounts, filled.from, hash, password)?;
|
||||
|
||||
Ok(signature.map(|sig| {
|
||||
|
||||
@@ -399,7 +399,8 @@ pub fn transaction_message(error: &TransactionError) -> String {
|
||||
CodeBanned => "Code is banned in local queue.".into(),
|
||||
NotAllowed => "Transaction is not permitted.".into(),
|
||||
TooBig => "Transaction is too big, see chain specification for the limit.".into(),
|
||||
InvalidRlp(ref descr) => format!("Invalid RLP data: {}", descr),
|
||||
InvalidRlp(ref descr) => format!("Invalid RLP data: {}", descr),
|
||||
TransactionTypeNotEnabled => format!("Transaction type is not enabled for current block"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -256,6 +256,7 @@ mod test {
|
||||
|
||||
fn request() -> ConfirmationPayload {
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::from(1),
|
||||
used_default_from: false,
|
||||
to: Some(Address::from(2)),
|
||||
@@ -265,6 +266,7 @@ mod test {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::cmp::min;
|
||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
||||
use types::transaction::{
|
||||
AccessListTx, Action, SignedTransaction, Transaction, TypedTransaction, TypedTxId,
|
||||
};
|
||||
|
||||
use ethereum_types::U256;
|
||||
use jsonrpc_core::Error;
|
||||
@@ -25,14 +27,20 @@ pub fn sign_call(request: CallRequest) -> Result<SignedTransaction, Error> {
|
||||
let max_gas = U256::from(500_000_000);
|
||||
let gas = min(request.gas.unwrap_or(max_gas), max_gas);
|
||||
let from = request.from.unwrap_or_default();
|
||||
|
||||
Ok(Transaction {
|
||||
let tx_legacy = Transaction {
|
||||
nonce: request.nonce.unwrap_or_default(),
|
||||
action: request.to.map_or(Action::Create, Action::Call),
|
||||
gas,
|
||||
gas_price: request.gas_price.unwrap_or_default(),
|
||||
value: request.value.unwrap_or_default(),
|
||||
data: request.data.unwrap_or_default(),
|
||||
}
|
||||
.fake_sign(from))
|
||||
};
|
||||
let tx_typed = match request.tx_type {
|
||||
TypedTxId::Legacy => TypedTransaction::Legacy(tx_legacy),
|
||||
TypedTxId::AccessList => TypedTransaction::AccessList(AccessListTx::new(
|
||||
tx_legacy,
|
||||
request.access_list.unwrap_or_default(),
|
||||
)),
|
||||
};
|
||||
Ok(tx_typed.fake_sign(from))
|
||||
}
|
||||
|
||||
@@ -16,12 +16,15 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use types::transaction::{AccessList, TypedTxId};
|
||||
|
||||
use v1::types::{Origin, TransactionCondition};
|
||||
|
||||
/// Transaction request coming from RPC
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
||||
pub struct TransactionRequest {
|
||||
/// type of transaction.
|
||||
pub tx_type: TypedTxId,
|
||||
/// Sender
|
||||
pub from: Option<Address>,
|
||||
/// Recipient
|
||||
@@ -38,11 +41,15 @@ pub struct TransactionRequest {
|
||||
pub nonce: Option<U256>,
|
||||
/// Delay until this condition is met.
|
||||
pub condition: Option<TransactionCondition>,
|
||||
/// Access list
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
/// Transaction request coming from RPC with default values filled in.
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
||||
pub struct FilledTransactionRequest {
|
||||
/// type of transaction.
|
||||
pub tx_type: TypedTxId,
|
||||
/// Sender
|
||||
pub from: Address,
|
||||
/// Indicates if the sender was filled by default value.
|
||||
@@ -61,11 +68,14 @@ pub struct FilledTransactionRequest {
|
||||
pub nonce: Option<U256>,
|
||||
/// Delay until this condition is met.
|
||||
pub condition: Option<TransactionCondition>,
|
||||
/// Access list
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
impl From<FilledTransactionRequest> for TransactionRequest {
|
||||
fn from(r: FilledTransactionRequest) -> Self {
|
||||
TransactionRequest {
|
||||
tx_type: r.tx_type,
|
||||
from: Some(r.from),
|
||||
to: r.to,
|
||||
gas_price: Some(r.gas_price),
|
||||
@@ -74,6 +84,7 @@ impl From<FilledTransactionRequest> for TransactionRequest {
|
||||
data: Some(r.data),
|
||||
nonce: r.nonce,
|
||||
condition: r.condition,
|
||||
access_list: r.access_list,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +92,8 @@ impl From<FilledTransactionRequest> for TransactionRequest {
|
||||
/// Call request
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct CallRequest {
|
||||
/// type of transaction.
|
||||
pub tx_type: TypedTxId,
|
||||
/// From
|
||||
pub from: Option<Address>,
|
||||
/// To
|
||||
@@ -95,6 +108,8 @@ pub struct CallRequest {
|
||||
pub data: Option<Vec<u8>>,
|
||||
/// Nonce
|
||||
pub nonce: Option<U256>,
|
||||
/// Access list
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
/// Confirmation object
|
||||
|
||||
@@ -24,7 +24,6 @@ use std::{
|
||||
|
||||
use ethereum_types::{Address, H160, H256, H64, U256, U64};
|
||||
use parking_lot::Mutex;
|
||||
use rlp::Rlp;
|
||||
|
||||
use ethash::{self, SeedHashCompute};
|
||||
use ethcore::{
|
||||
@@ -42,7 +41,7 @@ use types::{
|
||||
encoded,
|
||||
filter::Filter as EthcoreFilter,
|
||||
header::Header,
|
||||
transaction::{LocalizedTransaction, SignedTransaction},
|
||||
transaction::{LocalizedTransaction, SignedTransaction, TypedTransaction},
|
||||
BlockNumber as EthBlockNumber,
|
||||
};
|
||||
|
||||
@@ -1065,8 +1064,7 @@ where
|
||||
}
|
||||
|
||||
fn send_raw_transaction(&self, raw: Bytes) -> Result<H256> {
|
||||
Rlp::new(&raw.into_vec())
|
||||
.as_val()
|
||||
TypedTransaction::decode(&raw.into_vec())
|
||||
.map_err(errors::rlp)
|
||||
.and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))
|
||||
.and_then(|signed_transaction| {
|
||||
|
||||
@@ -22,8 +22,7 @@ use ethereum_types::U256;
|
||||
use ethkey;
|
||||
use parity_runtime::Executor;
|
||||
use parking_lot::Mutex;
|
||||
use rlp::Rlp;
|
||||
use types::transaction::{PendingTransaction, SignedTransaction};
|
||||
use types::transaction::{PendingTransaction, SignedTransaction, TypedTransaction};
|
||||
|
||||
use jsonrpc_core::{
|
||||
futures::{future, future::Either, Future, IntoFuture},
|
||||
@@ -161,17 +160,17 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
|
||||
where
|
||||
F: FnOnce(PendingTransaction) -> Result<ConfirmationResponse>,
|
||||
{
|
||||
let signed_transaction = Rlp::new(&bytes.0).as_val().map_err(errors::rlp)?;
|
||||
let signed_transaction = TypedTransaction::decode(&bytes.0).map_err(errors::rlp)?;
|
||||
let signed_transaction = SignedTransaction::new(signed_transaction)
|
||||
.map_err(|e| errors::invalid_params("Invalid signature.", e))?;
|
||||
let sender = signed_transaction.sender();
|
||||
|
||||
// Verification
|
||||
let sender_matches = sender == request.from;
|
||||
let data_matches = signed_transaction.data == request.data;
|
||||
let value_matches = signed_transaction.value == request.value;
|
||||
let data_matches = signed_transaction.tx().data == request.data;
|
||||
let value_matches = signed_transaction.tx().value == request.value;
|
||||
let nonce_matches = match request.nonce {
|
||||
Some(nonce) => signed_transaction.nonce == nonce,
|
||||
Some(nonce) => signed_transaction.tx().nonce == nonce,
|
||||
None => true,
|
||||
};
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ use ethcore::client::{
|
||||
BlockChainClient, BlockId, Call, CallAnalytics, StateClient, StateInfo, TraceId, TransactionId,
|
||||
};
|
||||
use ethereum_types::H256;
|
||||
use rlp::Rlp;
|
||||
use types::transaction::SignedTransaction;
|
||||
use types::transaction::{SignedTransaction, TypedTransaction};
|
||||
|
||||
use jsonrpc_core::Result;
|
||||
use v1::{
|
||||
@@ -194,9 +193,8 @@ where
|
||||
) -> Result<TraceResults> {
|
||||
let block = block.unwrap_or_default();
|
||||
|
||||
let tx = Rlp::new(&raw_transaction.into_vec())
|
||||
.as_val()
|
||||
.map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?;
|
||||
let tx = TypedTransaction::decode(&raw_transaction.0)
|
||||
.map_err(|e| errors::invalid_params("Transaction is not in valid Format", e))?;
|
||||
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
|
||||
|
||||
let id = match block {
|
||||
|
||||
@@ -30,14 +30,13 @@ use ethereum_types::{Address, Bloom, H160, H256, U256};
|
||||
use miner::external::ExternalMiner;
|
||||
use parity_runtime::Runtime;
|
||||
use parking_lot::Mutex;
|
||||
use rlp;
|
||||
use rustc_hex::{FromHex, ToHex};
|
||||
use sync::SyncState;
|
||||
use types::{
|
||||
ids::{BlockId, TransactionId},
|
||||
log_entry::{LocalizedLogEntry, LogEntry},
|
||||
receipt::{LocalizedReceipt, RichReceipt, TransactionOutcome},
|
||||
transaction::{Action, Transaction},
|
||||
transaction::{Action, Transaction, TypedTransaction, TypedTxId},
|
||||
};
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
@@ -694,13 +693,12 @@ fn rpc_eth_transaction_count_by_number_pending() {
|
||||
#[test]
|
||||
fn rpc_eth_pending_transaction_by_hash() {
|
||||
use ethereum_types::H256;
|
||||
use rlp;
|
||||
use types::transaction::SignedTransaction;
|
||||
|
||||
let tester = EthTester::default();
|
||||
{
|
||||
let bytes = FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap();
|
||||
let tx = rlp::decode(&bytes).expect("decoding failure");
|
||||
let tx = TypedTransaction::decode(&bytes).expect("decoding failure");
|
||||
let tx = SignedTransaction::new(tx).unwrap();
|
||||
tester
|
||||
.miner
|
||||
@@ -1050,6 +1048,23 @@ fn rpc_eth_estimate_gas_default_block() {
|
||||
fn rpc_eth_send_raw_transaction_error() {
|
||||
let tester = EthTester::default();
|
||||
|
||||
let req = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_sendRawTransaction",
|
||||
"params": [
|
||||
"0x1123"
|
||||
],
|
||||
"id": 1
|
||||
}"#;
|
||||
let res = r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid RLP.","data":"Custom(\"Unknown transaction\")"},"id":1}"#.into();
|
||||
|
||||
assert_eq!(tester.io.handle_request_sync(&req), Some(res));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_eth_send_raw_01_transaction_error() {
|
||||
let tester = EthTester::default();
|
||||
|
||||
let req = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_sendRawTransaction",
|
||||
@@ -1075,7 +1090,7 @@ fn rpc_eth_send_raw_transaction() {
|
||||
.unlock_account_permanently(address, "abcd".into())
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@@ -1084,14 +1099,14 @@ fn rpc_eth_send_raw_transaction() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts_provider
|
||||
.sign(address, None, t.hash(None))
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let rlp = rlp::encode(&t).to_hex();
|
||||
let rlp = t.encode().to_hex();
|
||||
|
||||
let req = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
@@ -1118,6 +1133,7 @@ fn rpc_eth_transaction_receipt() {
|
||||
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
transaction_hash: H256::zero(),
|
||||
transaction_index: 0,
|
||||
transaction_type: TypedTxId::Legacy,
|
||||
block_hash: H256::from_str(
|
||||
"ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5",
|
||||
)
|
||||
@@ -1204,6 +1220,7 @@ fn rpc_eth_pending_receipt() {
|
||||
)
|
||||
.unwrap(),
|
||||
transaction_index: 0,
|
||||
transaction_type: TypedTxId::Legacy,
|
||||
cumulative_gas_used: U256::from(0x20),
|
||||
gas_used: U256::from(0x10),
|
||||
contract_address: None,
|
||||
|
||||
@@ -21,7 +21,10 @@ use ethstore::ethkey::{Generator, Random};
|
||||
use miner::pool::local_transactions::Status as LocalTransactionStatus;
|
||||
use std::sync::Arc;
|
||||
use sync::ManageNetwork;
|
||||
use types::receipt::{LocalizedReceipt, TransactionOutcome};
|
||||
use types::{
|
||||
receipt::{LocalizedReceipt, TransactionOutcome},
|
||||
transaction::TypedTxId,
|
||||
};
|
||||
|
||||
use super::manage_network::TestManageNetwork;
|
||||
use jsonrpc_core::IoHandler;
|
||||
@@ -368,16 +371,17 @@ fn rpc_parity_transactions_stats() {
|
||||
|
||||
#[test]
|
||||
fn rpc_parity_local_transactions() {
|
||||
use types::transaction::{Transaction, TypedTransaction};
|
||||
let deps = Dependencies::new();
|
||||
let io = deps.default_client();
|
||||
let tx = ::types::transaction::Transaction {
|
||||
let tx = TypedTransaction::Legacy(Transaction {
|
||||
value: 5.into(),
|
||||
gas: 3.into(),
|
||||
gas_price: 2.into(),
|
||||
action: ::types::transaction::Action::Create,
|
||||
data: vec![1, 2, 3],
|
||||
nonce: 0.into(),
|
||||
}
|
||||
})
|
||||
.fake_sign(3.into());
|
||||
let tx = Arc::new(::miner::pool::VerifiedTransaction::from_pending_block_transaction(tx));
|
||||
deps.miner
|
||||
@@ -466,6 +470,7 @@ fn rpc_parity_block_receipts() {
|
||||
TransactionId::Hash(1.into()),
|
||||
LocalizedReceipt {
|
||||
transaction_hash: 1.into(),
|
||||
transaction_type: TypedTxId::Legacy,
|
||||
transaction_index: 0,
|
||||
block_hash: 3.into(),
|
||||
block_number: 0,
|
||||
|
||||
@@ -178,7 +178,7 @@ fn rpc_parity_set_hash_content() {
|
||||
|
||||
#[test]
|
||||
fn rpc_parity_remove_transaction() {
|
||||
use types::transaction::{Action, Transaction};
|
||||
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
@@ -187,14 +187,14 @@ fn rpc_parity_remove_transaction() {
|
||||
let mut io = IoHandler::new();
|
||||
io.extend_with(parity_set_client(&client, &miner, &network).to_delegate());
|
||||
|
||||
let tx = Transaction {
|
||||
let tx = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 1.into(),
|
||||
gas_price: 0x9184e72a000u64.into(),
|
||||
gas: 0x76c0.into(),
|
||||
action: Action::Call(5.into()),
|
||||
value: 0x9184e72au64.into(),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signed = tx.fake_sign(2.into());
|
||||
let hash = signed.hash();
|
||||
|
||||
@@ -202,7 +202,7 @@ fn rpc_parity_remove_transaction() {
|
||||
.to_owned()
|
||||
+ &format!("0x{:x}", hash)
|
||||
+ r#""], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"chainId":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0xa2e0da8a8064e0b9f93e95a53c2db6d01280efb8ac72a708d25487e67dd0f8fc","input":"0x","nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a80800101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x0","value":"0x9184e72a"},"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"chainId":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0x49569012bc8523519642c337fded3f20ba987beab31e14c67223b3d31359956f","input":"0x","nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a801f0101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x1f","value":"0x9184e72a"},"id":1}"#;
|
||||
|
||||
miner.pending_transactions.lock().insert(hash, signed);
|
||||
assert_eq!(io.handle_request_sync(&request), Some(response.to_owned()));
|
||||
|
||||
@@ -24,7 +24,7 @@ use hash::keccak;
|
||||
use jsonrpc_core::IoHandler;
|
||||
use parity_runtime::Runtime;
|
||||
use parking_lot::Mutex;
|
||||
use types::transaction::{Action, Transaction};
|
||||
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||
|
||||
use ethkey::Secret;
|
||||
use serde_json::to_value;
|
||||
@@ -91,9 +91,6 @@ fn setup_with(c: Config) -> PersonalTester {
|
||||
tester
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use rustc_hex::ToHex;
|
||||
|
||||
#[test]
|
||||
fn accounts() {
|
||||
let tester = setup();
|
||||
@@ -265,7 +262,7 @@ fn sign_and_send_test(method: &str) {
|
||||
"id": 1
|
||||
}"#;
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@@ -274,12 +271,15 @@ fn sign_and_send_test(method: &str) {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
tester
|
||||
.accounts
|
||||
.unlock_account_temporarily(address, "password123".into())
|
||||
.unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned()
|
||||
@@ -293,7 +293,7 @@ fn sign_and_send_test(method: &str) {
|
||||
|
||||
tester.miner.increment_nonce(&address);
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::one(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@@ -302,12 +302,15 @@ fn sign_and_send_test(method: &str) {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
tester
|
||||
.accounts
|
||||
.unlock_account_temporarily(address, "password123".into())
|
||||
.unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned()
|
||||
|
||||
@@ -22,8 +22,7 @@ use accounts::AccountProvider;
|
||||
use ethcore::client::TestBlockChainClient;
|
||||
use parity_runtime::Runtime;
|
||||
use parking_lot::Mutex;
|
||||
use rlp::encode;
|
||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
||||
use types::transaction::{Action, SignedTransaction, Transaction, TypedTransaction};
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
use serde_json;
|
||||
@@ -92,6 +91,7 @@ fn should_return_list_of_items_to_confirm() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::from(1),
|
||||
used_default_from: false,
|
||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
@@ -101,6 +101,7 @@ fn should_return_list_of_items_to_confirm() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
@@ -137,6 +138,7 @@ fn should_reject_transaction_from_queue_without_dispatching() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::from(1),
|
||||
used_default_from: false,
|
||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
@@ -146,6 +148,7 @@ fn should_reject_transaction_from_queue_without_dispatching() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
@@ -173,6 +176,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::from(1),
|
||||
used_default_from: false,
|
||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
@@ -182,6 +186,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
@@ -237,6 +242,7 @@ fn should_confirm_transaction_and_dispatch() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: address,
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@@ -246,24 +252,28 @@ fn should_confirm_transaction_and_dispatch() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(0x50505),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
tester
|
||||
.accounts
|
||||
.unlock_account_temporarily(address, "test".into())
|
||||
.unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
@@ -297,6 +307,7 @@ fn should_alter_the_sender_and_nonce() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: 0.into(),
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@@ -306,24 +317,25 @@ fn should_alter_the_sender_and_nonce() {
|
||||
data: vec![],
|
||||
nonce: Some(10.into()),
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(0x50505),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
|
||||
let address = tester.accounts.new_account(&"test".into()).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, Some("test".into()), t.hash(None))
|
||||
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
@@ -361,6 +373,7 @@ fn should_confirm_transaction_with_token() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: address,
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@@ -370,22 +383,23 @@ fn should_confirm_transaction_with_token() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(10_000_000),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let (signature, token) = tester
|
||||
.accounts
|
||||
.sign_with_token(address, "test".into(), t.hash(None))
|
||||
.sign_with_token(address, "test".into(), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
@@ -427,6 +441,7 @@ fn should_confirm_transaction_with_rlp() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: address,
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@@ -436,25 +451,26 @@ fn should_confirm_transaction_with_rlp() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(10_000_000),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, Some("test".into()), t.hash(None))
|
||||
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
let rlp = encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
|
||||
@@ -491,6 +507,7 @@ fn should_return_error_when_sender_does_not_match() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::default(),
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@@ -500,26 +517,30 @@ fn should_return_error_when_sender_does_not_match() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(10_000_000),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
tester
|
||||
.accounts
|
||||
.unlock_account_temporarily(address, "test".into())
|
||||
.unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
let rlp = encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
|
||||
@@ -553,6 +574,7 @@ fn should_confirm_sign_transaction_with_rlp() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SignTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: address,
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@@ -562,26 +584,27 @@ fn should_confirm_sign_transaction_with_rlp() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(10_000_000),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, Some("test".into()), t.hash(None))
|
||||
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = SignedTransaction::new(t.with_signature(signature.clone(), None)).unwrap();
|
||||
let rlp = encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
// when
|
||||
let request = r#"{
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use rlp;
|
||||
use std::{str::FromStr, sync::Arc, thread, time::Duration};
|
||||
|
||||
use jsonrpc_core::{futures::Future, IoHandler, Success};
|
||||
@@ -40,7 +39,7 @@ use ethstore::ethkey::{Generator, Random};
|
||||
use parity_runtime::{Executor, Runtime};
|
||||
use parking_lot::Mutex;
|
||||
use serde_json;
|
||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
||||
use types::transaction::{Action, SignedTransaction, Transaction, TypedTransaction};
|
||||
|
||||
struct SigningTester {
|
||||
pub runtime: Runtime,
|
||||
@@ -379,7 +378,7 @@ fn should_add_sign_transaction_to_the_queue() {
|
||||
"id": 1
|
||||
}"#;
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::one(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@@ -388,15 +387,15 @@ fn should_add_sign_transaction_to_the_queue() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, Some("test".into()), t.hash(None))
|
||||
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
let t = SignedTransaction::new(t).unwrap();
|
||||
let signature = t.signature();
|
||||
let rlp = rlp::encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned()
|
||||
+ r#""raw":"0x"#
|
||||
@@ -459,7 +458,7 @@ fn should_dispatch_transaction_if_account_is_unlock() {
|
||||
.unlock_account_permanently(acc, "test".into())
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@@ -468,8 +467,11 @@ fn should_dispatch_transaction_if_account_is_unlock() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
let signature = tester.accounts.sign(acc, None, t.hash(None)).unwrap();
|
||||
});
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(acc, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
// when
|
||||
|
||||
@@ -21,9 +21,7 @@ use ethcore::client::TestBlockChainClient;
|
||||
use ethereum_types::{Address, U256};
|
||||
use parity_runtime::Runtime;
|
||||
use parking_lot::Mutex;
|
||||
use rlp;
|
||||
use rustc_hex::ToHex;
|
||||
use types::transaction::{Action, Transaction};
|
||||
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
use v1::{
|
||||
@@ -117,7 +115,7 @@ fn rpc_eth_send_transaction() {
|
||||
"id": 1
|
||||
}"#;
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@@ -126,10 +124,10 @@ fn rpc_eth_send_transaction() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts_provider
|
||||
.sign(address, None, t.hash(None))
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
@@ -141,7 +139,7 @@ fn rpc_eth_send_transaction() {
|
||||
|
||||
tester.miner.increment_nonce(&address);
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::one(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@@ -150,10 +148,10 @@ fn rpc_eth_send_transaction() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts_provider
|
||||
.sign(address, None, t.hash(None))
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
@@ -166,6 +164,7 @@ fn rpc_eth_send_transaction() {
|
||||
|
||||
#[test]
|
||||
fn rpc_eth_sign_transaction() {
|
||||
use rustc_hex::ToHex;
|
||||
let tester = EthTester::default();
|
||||
let address = tester.accounts_provider.new_account(&"".into()).unwrap();
|
||||
tester
|
||||
@@ -188,7 +187,7 @@ fn rpc_eth_sign_transaction() {
|
||||
"id": 1
|
||||
}"#;
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::one(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@@ -197,14 +196,14 @@ fn rpc_eth_sign_transaction() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts_provider
|
||||
.sign(address, None, t.hash(None))
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
let signature = t.signature();
|
||||
let rlp = rlp::encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned()
|
||||
+ r#""raw":"0x"#
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethereum_types::{H160, U256};
|
||||
use types::transaction::{AccessList, TypedTxId};
|
||||
use v1::{helpers::CallRequest as Request, types::Bytes};
|
||||
|
||||
/// Call request
|
||||
@@ -22,6 +23,9 @@ use v1::{helpers::CallRequest as Request, types::Bytes};
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallRequest {
|
||||
/// transaction type
|
||||
#[serde(default)]
|
||||
pub tx_type: TypedTxId,
|
||||
/// From
|
||||
pub from: Option<H160>,
|
||||
/// To
|
||||
@@ -36,11 +40,14 @@ pub struct CallRequest {
|
||||
pub data: Option<Bytes>,
|
||||
/// Nonce
|
||||
pub nonce: Option<U256>,
|
||||
/// Access list
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
impl Into<Request> for CallRequest {
|
||||
fn into(self) -> Request {
|
||||
Request {
|
||||
tx_type: self.tx_type,
|
||||
from: self.from.map(Into::into),
|
||||
to: self.to.map(Into::into),
|
||||
gas_price: self.gas_price.map(Into::into),
|
||||
@@ -48,6 +55,7 @@ impl Into<Request> for CallRequest {
|
||||
value: self.value.map(Into::into),
|
||||
data: self.data.map(Into::into),
|
||||
nonce: self.nonce.map(Into::into),
|
||||
access_list: self.access_list.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,6 +84,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
CallRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from(1)),
|
||||
to: Some(H160::from(2)),
|
||||
gas_price: Some(U256::from(1)),
|
||||
@@ -83,6 +92,7 @@ mod tests {
|
||||
value: Some(U256::from(3)),
|
||||
data: Some(vec![0x12, 0x34, 0x56].into()),
|
||||
nonce: Some(U256::from(4)),
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -100,13 +110,15 @@ mod tests {
|
||||
let deserialized: CallRequest = serde_json::from_str(s).unwrap();
|
||||
|
||||
assert_eq!(deserialized, CallRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
||||
to: Some(H160::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("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
||||
nonce: None
|
||||
nonce: None,
|
||||
access_list: None,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -118,6 +130,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
CallRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from(1)),
|
||||
to: None,
|
||||
gas_price: None,
|
||||
@@ -125,6 +138,7 @@ mod tests {
|
||||
value: None,
|
||||
data: None,
|
||||
nonce: None,
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -331,6 +331,7 @@ mod tests {
|
||||
id: 15.into(),
|
||||
payload: helpers::ConfirmationPayload::SendTransaction(
|
||||
helpers::FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: 0.into(),
|
||||
used_default_from: false,
|
||||
to: None,
|
||||
@@ -340,6 +341,7 @@ mod tests {
|
||||
data: vec![1, 2, 3],
|
||||
nonce: Some(1.into()),
|
||||
condition: None,
|
||||
access_list: None,
|
||||
},
|
||||
),
|
||||
origin: Origin::Signer { session: 5.into() },
|
||||
@@ -360,6 +362,7 @@ mod tests {
|
||||
id: 15.into(),
|
||||
payload: helpers::ConfirmationPayload::SignTransaction(
|
||||
helpers::FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: 0.into(),
|
||||
used_default_from: false,
|
||||
to: None,
|
||||
@@ -369,6 +372,7 @@ mod tests {
|
||||
data: vec![1, 2, 3],
|
||||
nonce: Some(1.into()),
|
||||
condition: None,
|
||||
access_list: None,
|
||||
},
|
||||
),
|
||||
origin: Origin::Unknown,
|
||||
|
||||
@@ -15,13 +15,19 @@
|
||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethereum_types::{Bloom as H2048, H160, H256, U256, U64};
|
||||
use types::receipt::{LocalizedReceipt, Receipt as EthReceipt, RichReceipt, TransactionOutcome};
|
||||
use types::{
|
||||
receipt::{LocalizedReceipt, RichReceipt, TransactionOutcome, TypedReceipt},
|
||||
transaction::TypedTxId,
|
||||
};
|
||||
use v1::types::Log;
|
||||
|
||||
/// Receipt
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Receipt {
|
||||
/// Transaction Type
|
||||
#[serde(skip_serializing)]
|
||||
pub transaction_type: TypedTxId,
|
||||
/// Transaction Hash
|
||||
pub transaction_hash: Option<H256>,
|
||||
/// Transaction index
|
||||
@@ -75,6 +81,7 @@ impl From<LocalizedReceipt> for Receipt {
|
||||
Receipt {
|
||||
to: r.to.map(Into::into),
|
||||
from: Some(r.from),
|
||||
transaction_type: r.transaction_type,
|
||||
transaction_hash: Some(r.transaction_hash),
|
||||
transaction_index: Some(r.transaction_index.into()),
|
||||
block_hash: Some(r.block_hash),
|
||||
@@ -95,6 +102,7 @@ impl From<RichReceipt> for Receipt {
|
||||
Receipt {
|
||||
from: Some(r.from),
|
||||
to: r.to.map(Into::into),
|
||||
transaction_type: r.transaction_type,
|
||||
transaction_hash: Some(r.transaction_hash),
|
||||
transaction_index: Some(r.transaction_index.into()),
|
||||
block_hash: None,
|
||||
@@ -110,11 +118,14 @@ impl From<RichReceipt> for Receipt {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EthReceipt> for Receipt {
|
||||
fn from(r: EthReceipt) -> Self {
|
||||
impl From<TypedReceipt> for Receipt {
|
||||
fn from(r: TypedReceipt) -> Self {
|
||||
let transaction_type = r.tx_type();
|
||||
let r = r.receipt().clone();
|
||||
Receipt {
|
||||
from: None,
|
||||
to: None,
|
||||
transaction_type,
|
||||
transaction_hash: None,
|
||||
transaction_index: None,
|
||||
block_hash: None,
|
||||
@@ -142,6 +153,7 @@ mod tests {
|
||||
let receipt = Receipt {
|
||||
from: None,
|
||||
to: None,
|
||||
transaction_type: Default::default(),
|
||||
transaction_hash: Some(0.into()),
|
||||
transaction_index: Some(0.into()),
|
||||
block_hash: Some(
|
||||
|
||||
@@ -20,7 +20,10 @@ use ethcore::{contract_address, CreateContractAddress};
|
||||
use ethereum_types::{H160, H256, H512, U256, U64};
|
||||
use miner;
|
||||
use serde::{ser::SerializeStruct, Serialize, Serializer};
|
||||
use types::transaction::{Action, LocalizedTransaction, PendingTransaction, SignedTransaction};
|
||||
use types::transaction::{
|
||||
AccessList, Action, LocalizedTransaction, PendingTransaction, SignedTransaction,
|
||||
TypedTransaction,
|
||||
};
|
||||
use v1::types::{Bytes, TransactionCondition};
|
||||
|
||||
/// Transaction
|
||||
@@ -67,6 +70,12 @@ pub struct Transaction {
|
||||
pub s: U256,
|
||||
/// Transaction activates at specified block.
|
||||
pub condition: Option<TransactionCondition>,
|
||||
/// transaction type
|
||||
#[serde(skip_serializing)]
|
||||
pub transaction_type: u8,
|
||||
/// optional access list
|
||||
#[serde(skip_serializing)]
|
||||
pub access_list: AccessList,
|
||||
}
|
||||
|
||||
/// Local Transaction Status
|
||||
@@ -176,26 +185,35 @@ impl Transaction {
|
||||
pub fn from_localized(mut t: LocalizedTransaction) -> Transaction {
|
||||
let signature = t.signature();
|
||||
let scheme = CreateContractAddress::FromSenderAndNonce;
|
||||
|
||||
let access_list = if let TypedTransaction::AccessList(al) = t.as_unsigned() {
|
||||
al.access_list.clone()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
Transaction {
|
||||
hash: t.hash(),
|
||||
nonce: t.nonce,
|
||||
nonce: t.tx().nonce,
|
||||
block_hash: Some(t.block_hash),
|
||||
block_number: Some(t.block_number.into()),
|
||||
transaction_index: Some(t.transaction_index.into()),
|
||||
from: t.sender(),
|
||||
to: match t.action {
|
||||
to: match t.tx().action {
|
||||
Action::Create => None,
|
||||
Action::Call(ref address) => Some(*address),
|
||||
},
|
||||
value: t.value,
|
||||
gas_price: t.gas_price,
|
||||
gas: t.gas,
|
||||
input: Bytes::new(t.data.clone()),
|
||||
creates: match t.action {
|
||||
Action::Create => Some(contract_address(scheme, &t.sender(), &t.nonce, &t.data).0),
|
||||
value: t.tx().value,
|
||||
gas_price: t.tx().gas_price,
|
||||
gas: t.tx().gas,
|
||||
input: Bytes::new(t.tx().data.clone()),
|
||||
creates: match t.tx().action {
|
||||
Action::Create => {
|
||||
Some(contract_address(scheme, &t.sender(), &t.tx().nonce, &t.tx().data).0)
|
||||
}
|
||||
Action::Call(_) => None,
|
||||
},
|
||||
raw: ::rlp::encode(&t.signed).into(),
|
||||
raw: Bytes::new(t.signed.encode()),
|
||||
public_key: t.recover_public().ok().map(Into::into),
|
||||
chain_id: t.chain_id().map(U64::from),
|
||||
standard_v: t.standard_v().into(),
|
||||
@@ -203,6 +221,8 @@ impl Transaction {
|
||||
r: signature.r().into(),
|
||||
s: signature.s().into(),
|
||||
condition: None,
|
||||
transaction_type: t.signed.tx_type() as u8,
|
||||
access_list,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,26 +230,33 @@ impl Transaction {
|
||||
pub fn from_signed(t: SignedTransaction) -> Transaction {
|
||||
let signature = t.signature();
|
||||
let scheme = CreateContractAddress::FromSenderAndNonce;
|
||||
let access_list = if let TypedTransaction::AccessList(al) = t.as_unsigned() {
|
||||
al.access_list.clone()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
Transaction {
|
||||
hash: t.hash(),
|
||||
nonce: t.nonce,
|
||||
nonce: t.tx().nonce,
|
||||
block_hash: None,
|
||||
block_number: None,
|
||||
transaction_index: None,
|
||||
from: t.sender(),
|
||||
to: match t.action {
|
||||
to: match t.tx().action {
|
||||
Action::Create => None,
|
||||
Action::Call(ref address) => Some(*address),
|
||||
},
|
||||
value: t.value,
|
||||
gas_price: t.gas_price,
|
||||
gas: t.gas,
|
||||
input: Bytes::new(t.data.clone()),
|
||||
creates: match t.action {
|
||||
Action::Create => Some(contract_address(scheme, &t.sender(), &t.nonce, &t.data).0),
|
||||
value: t.tx().value,
|
||||
gas_price: t.tx().gas_price,
|
||||
gas: t.tx().gas,
|
||||
input: Bytes::new(t.tx().data.clone()),
|
||||
creates: match t.tx().action {
|
||||
Action::Create => {
|
||||
Some(contract_address(scheme, &t.sender(), &t.tx().nonce, &t.tx().data).0)
|
||||
}
|
||||
Action::Call(_) => None,
|
||||
},
|
||||
raw: ::rlp::encode(&t).into(),
|
||||
raw: t.encode().into(),
|
||||
public_key: t.public_key().map(Into::into),
|
||||
chain_id: t.chain_id().map(U64::from),
|
||||
standard_v: t.standard_v().into(),
|
||||
@@ -237,6 +264,8 @@ impl Transaction {
|
||||
r: signature.r().into(),
|
||||
s: signature.s().into(),
|
||||
condition: None,
|
||||
transaction_type: t.tx_type() as u8,
|
||||
access_list,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +294,7 @@ impl LocalTransactionStatus {
|
||||
Canceled(tx) => LocalTransactionStatus::Canceled(convert(tx)),
|
||||
Replaced { old, new } => LocalTransactionStatus::Replaced(
|
||||
convert(old),
|
||||
new.signed().gas_price,
|
||||
new.signed().tx().gas_price,
|
||||
new.signed().hash(),
|
||||
),
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
use ansi_term::Colour;
|
||||
use ethereum_types::{H160, U256};
|
||||
use types::transaction::{AccessList, TypedTxId};
|
||||
use v1::{
|
||||
helpers,
|
||||
types::{Bytes, TransactionCondition},
|
||||
@@ -30,6 +31,10 @@ use std::fmt;
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransactionRequest {
|
||||
/// type of transaction. If none we assume it is legacy
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing)]
|
||||
pub tx_type: TypedTxId,
|
||||
/// Sender
|
||||
pub from: Option<H160>,
|
||||
/// Recipient
|
||||
@@ -46,6 +51,9 @@ pub struct TransactionRequest {
|
||||
pub nonce: Option<U256>,
|
||||
/// Delay until this block condition.
|
||||
pub condition: Option<TransactionCondition>,
|
||||
/// Access list
|
||||
#[serde(skip_serializing)]
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
pub fn format_ether(i: U256) -> String {
|
||||
@@ -97,6 +105,7 @@ impl fmt::Display for TransactionRequest {
|
||||
impl From<helpers::TransactionRequest> for TransactionRequest {
|
||||
fn from(r: helpers::TransactionRequest) -> Self {
|
||||
TransactionRequest {
|
||||
tx_type: r.tx_type,
|
||||
from: r.from.map(Into::into),
|
||||
to: r.to.map(Into::into),
|
||||
gas_price: r.gas_price.map(Into::into),
|
||||
@@ -105,6 +114,7 @@ impl From<helpers::TransactionRequest> for TransactionRequest {
|
||||
data: r.data.map(Into::into),
|
||||
nonce: r.nonce.map(Into::into),
|
||||
condition: r.condition.map(Into::into),
|
||||
access_list: r.access_list.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,6 +122,7 @@ impl From<helpers::TransactionRequest> for TransactionRequest {
|
||||
impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
||||
fn from(r: helpers::FilledTransactionRequest) -> Self {
|
||||
TransactionRequest {
|
||||
tx_type: r.tx_type,
|
||||
from: Some(r.from),
|
||||
to: r.to,
|
||||
gas_price: Some(r.gas_price),
|
||||
@@ -120,6 +131,7 @@ impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
||||
data: Some(r.data.into()),
|
||||
nonce: r.nonce,
|
||||
condition: r.condition,
|
||||
access_list: r.access_list,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,6 +139,7 @@ impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
||||
impl Into<helpers::TransactionRequest> for TransactionRequest {
|
||||
fn into(self) -> helpers::TransactionRequest {
|
||||
helpers::TransactionRequest {
|
||||
tx_type: self.tx_type,
|
||||
from: self.from.map(Into::into),
|
||||
to: self.to.map(Into::into),
|
||||
gas_price: self.gas_price.map(Into::into),
|
||||
@@ -135,6 +148,7 @@ impl Into<helpers::TransactionRequest> for TransactionRequest {
|
||||
data: self.data.map(Into::into),
|
||||
nonce: self.nonce.map(Into::into),
|
||||
condition: self.condition.map(Into::into),
|
||||
access_list: self.access_list.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,6 +179,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
TransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from(1)),
|
||||
to: Some(H160::from(2)),
|
||||
gas_price: Some(U256::from(1)),
|
||||
@@ -173,6 +188,7 @@ mod tests {
|
||||
data: Some(vec![0x12, 0x34, 0x56].into()),
|
||||
nonce: Some(U256::from(4)),
|
||||
condition: Some(TransactionCondition::Number(0x13)),
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -190,6 +206,7 @@ mod tests {
|
||||
let deserialized: TransactionRequest = serde_json::from_str(s).unwrap();
|
||||
|
||||
assert_eq!(deserialized, TransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
||||
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
||||
@@ -197,7 +214,8 @@ mod tests {
|
||||
value: Some(U256::from_str("9184e72a").unwrap()),
|
||||
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
||||
nonce: None,
|
||||
condition: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,6 +227,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
TransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from(1).into()),
|
||||
to: None,
|
||||
gas_price: None,
|
||||
@@ -217,6 +236,7 @@ mod tests {
|
||||
data: None,
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -236,6 +256,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
TransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from_str("b5f7502a2807cb23615c7456055e1d65b2508625").unwrap()),
|
||||
to: Some(H160::from_str("895d32f2db7d01ebb50053f9e48aacf26584fe40").unwrap()),
|
||||
gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
|
||||
@@ -244,6 +265,7 @@ mod tests {
|
||||
data: Some(vec![0x85, 0x95, 0xba, 0xb1].into()),
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user