finishe signed transactions
This commit is contained in:
parent
e92c6ee719
commit
eab8410402
@ -56,7 +56,7 @@ pub trait Engine : Sync + Send {
|
|||||||
/// Additional verification for transactions in blocks.
|
/// Additional verification for transactions in blocks.
|
||||||
// TODO: Add flags for which bits of the transaction to check.
|
// TODO: Add flags for which bits of the transaction to check.
|
||||||
// TODO: consider including State in the params.
|
// TODO: consider including State in the params.
|
||||||
fn verify_transaction_basic(&self, _t: &Transaction, _header: &Header) -> Result<(), Error> { Ok(()) }
|
fn verify_transaction_basic(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) }
|
||||||
/// Verify a particular transaction is valid.
|
/// Verify a particular transaction is valid.
|
||||||
fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) }
|
fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) }
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ impl Engine for Ethash {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_transaction_basic(&self, t: &Transaction, header: &Header) -> result::Result<(), Error> {
|
fn verify_transaction_basic(&self, t: &SignedTransaction, header: &Header) -> result::Result<(), Error> {
|
||||||
if header.number() >= self.u64_param("frontierCompatibilityModeLimit") {
|
if header.number() >= self.u64_param("frontierCompatibilityModeLimit") {
|
||||||
try!(t.check_low_s());
|
try!(t.check_low_s());
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ impl<'a> Executive<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This funtion should be used to execute transaction.
|
/// This funtion should be used to execute transaction.
|
||||||
pub fn transact(&'a mut self, t: &Transaction) -> Result<Executed, Error> {
|
pub fn transact(&'a mut self, t: &SignedTransaction) -> Result<Executed, Error> {
|
||||||
let sender = try!(t.sender());
|
let sender = try!(t.sender());
|
||||||
let nonce = self.state.nonce(&sender);
|
let nonce = self.state.nonce(&sender);
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ impl<'a> Executive<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finalizes the transaction (does refunds and suicides).
|
/// Finalizes the transaction (does refunds and suicides).
|
||||||
fn finalize(&mut self, t: &Transaction, substate: Substate, result: evm::Result) -> ExecutionResult {
|
fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result) -> ExecutionResult {
|
||||||
let schedule = self.engine.schedule(self.info);
|
let schedule = self.engine.schedule(self.info);
|
||||||
|
|
||||||
// refunds from SSTORE nonzero -> zero
|
// refunds from SSTORE nonzero -> zero
|
||||||
@ -685,9 +685,15 @@ mod tests {
|
|||||||
// test is incorrect, mk
|
// test is incorrect, mk
|
||||||
evm_test_ignore!{test_transact_simple: test_transact_simple_jit, test_transact_simple_int}
|
evm_test_ignore!{test_transact_simple: test_transact_simple_jit, test_transact_simple_int}
|
||||||
fn test_transact_simple(factory: Factory) {
|
fn test_transact_simple(factory: Factory) {
|
||||||
let mut t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::zero(), U256::zero());
|
|
||||||
let keypair = KeyPair::create().unwrap();
|
let keypair = KeyPair::create().unwrap();
|
||||||
t.sign(&keypair.secret());
|
let t = Transaction {
|
||||||
|
action: Action::Create,
|
||||||
|
value: U256::from(17),
|
||||||
|
data: "3331600055".from_hex().unwrap(),
|
||||||
|
gas: U256::from(100_000),
|
||||||
|
gas_price: U256::zero(),
|
||||||
|
nonce: U256::zero()
|
||||||
|
}.sign(&keypair.secret());
|
||||||
let sender = t.sender().unwrap();
|
let sender = t.sender().unwrap();
|
||||||
let contract = contract_address(&sender, &U256::zero());
|
let contract = contract_address(&sender, &U256::zero());
|
||||||
|
|
||||||
@ -717,8 +723,14 @@ mod tests {
|
|||||||
|
|
||||||
evm_test!{test_transact_invalid_sender: test_transact_invalid_sender_jit, test_transact_invalid_sender_int}
|
evm_test!{test_transact_invalid_sender: test_transact_invalid_sender_jit, test_transact_invalid_sender_int}
|
||||||
fn test_transact_invalid_sender(factory: Factory) {
|
fn test_transact_invalid_sender(factory: Factory) {
|
||||||
let t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::zero(), U256::zero());
|
let t = Transaction {
|
||||||
|
action: Action::Create,
|
||||||
|
value: U256::from(17),
|
||||||
|
data: "3331600055".from_hex().unwrap(),
|
||||||
|
gas: U256::from(100_000),
|
||||||
|
gas_price: U256::zero(),
|
||||||
|
nonce: U256::zero()
|
||||||
|
}.fake_sign();
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
let mut info = EnvInfo::default();
|
let mut info = EnvInfo::default();
|
||||||
@ -738,9 +750,15 @@ mod tests {
|
|||||||
|
|
||||||
evm_test!{test_transact_invalid_nonce: test_transact_invalid_nonce_jit, test_transact_invalid_nonce_int}
|
evm_test!{test_transact_invalid_nonce: test_transact_invalid_nonce_jit, test_transact_invalid_nonce_int}
|
||||||
fn test_transact_invalid_nonce(factory: Factory) {
|
fn test_transact_invalid_nonce(factory: Factory) {
|
||||||
let mut t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::zero(), U256::one());
|
|
||||||
let keypair = KeyPair::create().unwrap();
|
let keypair = KeyPair::create().unwrap();
|
||||||
t.sign(&keypair.secret());
|
let t = Transaction {
|
||||||
|
action: Action::Create,
|
||||||
|
value: U256::from(17),
|
||||||
|
data: "3331600055".from_hex().unwrap(),
|
||||||
|
gas: U256::from(100_000),
|
||||||
|
gas_price: U256::zero(),
|
||||||
|
nonce: U256::one()
|
||||||
|
}.sign(&keypair.secret());
|
||||||
let sender = t.sender().unwrap();
|
let sender = t.sender().unwrap();
|
||||||
|
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
@ -764,9 +782,15 @@ mod tests {
|
|||||||
|
|
||||||
evm_test!{test_transact_gas_limit_reached: test_transact_gas_limit_reached_jit, test_transact_gas_limit_reached_int}
|
evm_test!{test_transact_gas_limit_reached: test_transact_gas_limit_reached_jit, test_transact_gas_limit_reached_int}
|
||||||
fn test_transact_gas_limit_reached(factory: Factory) {
|
fn test_transact_gas_limit_reached(factory: Factory) {
|
||||||
let mut t = Transaction::new_create(U256::from(17), "3331600055".from_hex().unwrap(), U256::from(80_001), U256::zero(), U256::zero());
|
|
||||||
let keypair = KeyPair::create().unwrap();
|
let keypair = KeyPair::create().unwrap();
|
||||||
t.sign(&keypair.secret());
|
let t = Transaction {
|
||||||
|
action: Action::Create,
|
||||||
|
value: U256::from(17),
|
||||||
|
data: "3331600055".from_hex().unwrap(),
|
||||||
|
gas: U256::from(80_001),
|
||||||
|
gas_price: U256::zero(),
|
||||||
|
nonce: U256::zero()
|
||||||
|
}.sign(&keypair.secret());
|
||||||
let sender = t.sender().unwrap();
|
let sender = t.sender().unwrap();
|
||||||
|
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
@ -791,9 +815,16 @@ mod tests {
|
|||||||
|
|
||||||
evm_test!{test_not_enough_cash: test_not_enough_cash_jit, test_not_enough_cash_int}
|
evm_test!{test_not_enough_cash: test_not_enough_cash_jit, test_not_enough_cash_int}
|
||||||
fn test_not_enough_cash(factory: Factory) {
|
fn test_not_enough_cash(factory: Factory) {
|
||||||
let mut t = Transaction::new_create(U256::from(18), "3331600055".from_hex().unwrap(), U256::from(100_000), U256::one(), U256::zero());
|
|
||||||
let keypair = KeyPair::create().unwrap();
|
let keypair = KeyPair::create().unwrap();
|
||||||
t.sign(&keypair.secret());
|
let t = Transaction {
|
||||||
|
action: Action::Create,
|
||||||
|
value: U256::from(18),
|
||||||
|
data: "3331600055".from_hex().unwrap(),
|
||||||
|
gas: U256::from(100_000),
|
||||||
|
gas_price: U256::one(),
|
||||||
|
nonce: U256::zero()
|
||||||
|
}.sign(&keypair.secret());
|
||||||
let sender = t.sender().unwrap();
|
let sender = t.sender().unwrap();
|
||||||
|
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
|
@ -33,7 +33,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
|||||||
|
|
||||||
flush!(" - {}...", name);
|
flush!(" - {}...", name);
|
||||||
|
|
||||||
let t = Transaction::from_json(&test["transaction"]);
|
let t = SignedTransaction::from_json(&test["transaction"]);
|
||||||
let env = EnvInfo::from_json(&test["env"]);
|
let env = EnvInfo::from_json(&test["env"]);
|
||||||
let _out = Bytes::from_json(&test["out"]);
|
let _out = Bytes::from_json(&test["out"]);
|
||||||
let post_state_root = xjson!(&test["postStateRoot"]);
|
let post_state_root = xjson!(&test["postStateRoot"]);
|
||||||
|
@ -6,7 +6,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
|||||||
let mut failed = Vec::new();
|
let mut failed = Vec::new();
|
||||||
let old_schedule = evm::Schedule::new_frontier();
|
let old_schedule = evm::Schedule::new_frontier();
|
||||||
let new_schedule = evm::Schedule::new_homestead();
|
let new_schedule = evm::Schedule::new_homestead();
|
||||||
let ot = RefCell::new(Transaction::new());
|
let ot = RefCell::new(None);
|
||||||
for (name, test) in json.as_object().unwrap() {
|
for (name, test) in json.as_object().unwrap() {
|
||||||
let mut fail = false;
|
let mut fail = false;
|
||||||
let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.clone()); println!("Transaction: {:?}", ot.borrow()); fail = true };
|
let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.clone()); println!("Transaction: {:?}", ot.borrow()); fail = true };
|
||||||
@ -15,7 +15,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
|||||||
.and_then(|s| BlockNumber::from_str(s).ok())
|
.and_then(|s| BlockNumber::from_str(s).ok())
|
||||||
.unwrap_or(0) { x if x < 1_000_000 => &old_schedule, _ => &new_schedule };
|
.unwrap_or(0) { x if x < 1_000_000 => &old_schedule, _ => &new_schedule };
|
||||||
let rlp = Bytes::from_json(&test["rlp"]);
|
let rlp = Bytes::from_json(&test["rlp"]);
|
||||||
let res = UntrustedRlp::new(&rlp).as_val().map_err(From::from).and_then(|t: Transaction| t.validate(schedule, schedule.have_delegate_call));
|
let res = UntrustedRlp::new(&rlp).as_val().map_err(From::from).and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call));
|
||||||
fail_unless(test.find("transaction").is_none() == res.is_err());
|
fail_unless(test.find("transaction").is_none() == res.is_err());
|
||||||
if let (Some(&Json::Object(ref tx)), Some(&Json::String(ref expect_sender))) = (test.find("transaction"), test.find("sender")) {
|
if let (Some(&Json::Object(ref tx)), Some(&Json::String(ref expect_sender))) = (test.find("transaction"), test.find("sender")) {
|
||||||
let t = res.unwrap();
|
let t = res.unwrap();
|
||||||
@ -26,10 +26,10 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
|||||||
fail_unless(t.nonce == xjson!(&tx["nonce"]));
|
fail_unless(t.nonce == xjson!(&tx["nonce"]));
|
||||||
fail_unless(t.value == xjson!(&tx["value"]));
|
fail_unless(t.value == xjson!(&tx["value"]));
|
||||||
if let Action::Call(ref to) = t.action {
|
if let Action::Call(ref to) = t.action {
|
||||||
*ot.borrow_mut() = t.clone();
|
*ot.borrow_mut() = Some(t.clone());
|
||||||
fail_unless(to == &xjson!(&tx["to"]));
|
fail_unless(to == &xjson!(&tx["to"]));
|
||||||
} else {
|
} else {
|
||||||
*ot.borrow_mut() = t.clone();
|
*ot.borrow_mut() = Some(t.clone());
|
||||||
fail_unless(Bytes::from_json(&tx["to"]).is_empty());
|
fail_unless(Bytes::from_json(&tx["to"]).is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ impl State {
|
|||||||
|
|
||||||
/// Execute a given transaction.
|
/// Execute a given transaction.
|
||||||
/// This will change the state accordingly.
|
/// This will change the state accordingly.
|
||||||
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult {
|
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction) -> ApplyResult {
|
||||||
// let old = self.to_pod();
|
// let old = self.to_pod();
|
||||||
|
|
||||||
let e = try!(Executive::new(self, env_info, engine).transact(t));
|
let e = try!(Executive::new(self, env_info, engine).transact(t));
|
||||||
|
@ -103,12 +103,12 @@ fn create_unverifiable_block(order: u32, parent_hash: H256) -> Bytes {
|
|||||||
create_test_block(&create_unverifiable_block_header(order, parent_hash))
|
create_test_block(&create_unverifiable_block_header(order, parent_hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_test_block_with_data(header: &Header, transactions: &[&Transaction], uncles: &[Header]) -> Bytes {
|
pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTransaction], uncles: &[Header]) -> Bytes {
|
||||||
let mut rlp = RlpStream::new_list(3);
|
let mut rlp = RlpStream::new_list(3);
|
||||||
rlp.append(header);
|
rlp.append(header);
|
||||||
rlp.begin_list(transactions.len());
|
rlp.begin_list(transactions.len());
|
||||||
for t in transactions {
|
for t in transactions {
|
||||||
rlp.append_raw(&t.rlp_bytes_opt(Seal::With), 1);
|
rlp.append_raw(&encode::<SignedTransaction>(t).to_vec(), 1);
|
||||||
}
|
}
|
||||||
rlp.append(&uncles);
|
rlp.append(&uncles);
|
||||||
rlp.out()
|
rlp.out()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
//! Transaction data structure.
|
//! Transaction data structure.
|
||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use basic_types::*;
|
|
||||||
use error::*;
|
use error::*;
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
|
|
||||||
@ -18,6 +17,16 @@ impl Default for Action {
|
|||||||
fn default() -> Action { Action::Create }
|
fn default() -> Action { Action::Create }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Decodable for Action {
|
||||||
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
|
let rlp = decoder.as_rlp();
|
||||||
|
match rlp.is_empty() {
|
||||||
|
true => Ok(Action::Create),
|
||||||
|
false => Ok(Action::Call(try!(rlp.as_val())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A set of information describing an externally-originating message call
|
/// A set of information describing an externally-originating message call
|
||||||
/// or contract creation operation.
|
/// or contract creation operation.
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
@ -34,18 +43,6 @@ pub struct Transaction {
|
|||||||
pub value: U256,
|
pub value: U256,
|
||||||
/// Transaction data.
|
/// Transaction data.
|
||||||
pub data: Bytes,
|
pub data: Bytes,
|
||||||
|
|
||||||
|
|
||||||
//// signature
|
|
||||||
///// The V field of the signature, either 27 or 28; helps describe the point on the curve.
|
|
||||||
//pub v: u8,
|
|
||||||
///// The R field of the signature; helps describe the point on the curve.
|
|
||||||
//pub r: U256,
|
|
||||||
///// The S field of the signature; helps describe the point on the curve.
|
|
||||||
//pub s: U256,
|
|
||||||
|
|
||||||
//hash: RefCell<Option<H256>>,
|
|
||||||
//sender: RefCell<Option<Address>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transaction {
|
impl Transaction {
|
||||||
@ -62,90 +59,11 @@ impl Transaction {
|
|||||||
s.append(&self.value);
|
s.append(&self.value);
|
||||||
s.append(&self.data);
|
s.append(&self.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new transaction.
|
|
||||||
#[cfg(test)]
|
|
||||||
#[cfg(feature = "json-tests")]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Transaction {
|
|
||||||
nonce: x!(0),
|
|
||||||
gas_price: x!(0),
|
|
||||||
gas: x!(0),
|
|
||||||
action: Action::Create,
|
|
||||||
value: x!(0),
|
|
||||||
data: vec![],
|
|
||||||
//v: 0,
|
|
||||||
//r: x!(0),
|
|
||||||
//s: x!(0),
|
|
||||||
//hash: RefCell::new(None),
|
|
||||||
//sender: RefCell::new(None),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new message-call transaction.
|
impl FromJson for SignedTransaction {
|
||||||
#[allow(dead_code)]
|
fn from_json(json: &Json) -> SignedTransaction {
|
||||||
pub fn new_call(to: Address, value: U256, data: Bytes, gas: U256, gas_price: U256, nonce: U256) -> Transaction {
|
let t = Transaction {
|
||||||
Transaction {
|
|
||||||
nonce: nonce,
|
|
||||||
gas_price: gas_price,
|
|
||||||
gas: gas,
|
|
||||||
action: Action::Call(to),
|
|
||||||
value: value,
|
|
||||||
data: data,
|
|
||||||
//v: 0,
|
|
||||||
//r: x!(0),
|
|
||||||
//s: x!(0),
|
|
||||||
//hash: RefCell::new(None),
|
|
||||||
//sender: RefCell::new(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new contract-creation transaction.
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn new_create(value: U256, data: Bytes, gas: U256, gas_price: U256, nonce: U256) -> Transaction {
|
|
||||||
Transaction {
|
|
||||||
nonce: nonce,
|
|
||||||
gas_price: gas_price,
|
|
||||||
gas: gas,
|
|
||||||
action: Action::Create,
|
|
||||||
value: value,
|
|
||||||
data: data,
|
|
||||||
//v: 0,
|
|
||||||
//r: x!(0),
|
|
||||||
//s: x!(0),
|
|
||||||
//hash: RefCell::new(None),
|
|
||||||
//sender: RefCell::new(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///// Append object into RLP stream, optionally with or without the signature.
|
|
||||||
//pub fn rlp_append_opt(&self, s: &mut RlpStream, with_seal: Seal) {
|
|
||||||
//s.begin_list(6 + match with_seal { Seal::With => 3, _ => 0 });
|
|
||||||
//s.append(&self.nonce);
|
|
||||||
//s.append(&self.gas_price);
|
|
||||||
//s.append(&self.gas);
|
|
||||||
//match self.action {
|
|
||||||
//Action::Create => s.append_empty_data(),
|
|
||||||
//Action::Call(ref to) => s.append(to),
|
|
||||||
//};
|
|
||||||
//s.append(&self.value);
|
|
||||||
//s.append(&self.data);
|
|
||||||
//if let Seal::With = with_seal {
|
|
||||||
//s.append(&(self.v as u16)).append(&self.r).append(&self.s);
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
///// Get the RLP serialisation of the object, optionally with or without the signature.
|
|
||||||
//pub fn rlp_bytes_opt(&self, with_seal: Seal) -> Bytes {
|
|
||||||
//let mut s = RlpStream::new();
|
|
||||||
//self.rlp_append_opt(&mut s, with_seal);
|
|
||||||
//s.out()
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromJson for Transaction {
|
|
||||||
fn from_json(json: &Json) -> Transaction {
|
|
||||||
let mut r = Transaction {
|
|
||||||
nonce: xjson!(&json["nonce"]),
|
nonce: xjson!(&json["nonce"]),
|
||||||
gas_price: xjson!(&json["gasPrice"]),
|
gas_price: xjson!(&json["gasPrice"]),
|
||||||
gas: xjson!(&json["gasLimit"]),
|
gas: xjson!(&json["gasLimit"]),
|
||||||
@ -155,41 +73,58 @@ impl FromJson for Transaction {
|
|||||||
},
|
},
|
||||||
value: xjson!(&json["value"]),
|
value: xjson!(&json["value"]),
|
||||||
data: xjson!(&json["data"]),
|
data: xjson!(&json["data"]),
|
||||||
//v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 },
|
|
||||||
//r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) },
|
|
||||||
//s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) },
|
|
||||||
//hash: RefCell::new(None),
|
|
||||||
//sender: match json.find("sender") {
|
|
||||||
//Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))),
|
|
||||||
//_ => RefCell::new(None),
|
|
||||||
//},
|
|
||||||
};
|
};
|
||||||
//if let Some(&Json::String(ref secret_key)) = json.find("secretKey") {
|
match json.find("secretKey") {
|
||||||
//r.sign(&h256_from_hex(clean(secret_key)));
|
Some(&Json::String(ref secret_key)) => t.sign(&h256_from_hex(clean(secret_key))),
|
||||||
//}
|
_ => SignedTransaction {
|
||||||
r
|
transaction: t,
|
||||||
|
v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 },
|
||||||
|
r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) },
|
||||||
|
s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) },
|
||||||
|
hash: RefCell::new(None),
|
||||||
|
sender: match json.find("sender") {
|
||||||
|
Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))),
|
||||||
|
_ => RefCell::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//impl Encodable for Transaction {
|
|
||||||
//fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_opt(s, Seal::With) }
|
|
||||||
//}
|
|
||||||
|
|
||||||
impl Transaction {
|
impl Transaction {
|
||||||
|
/// The message hash of the transaction.
|
||||||
|
pub fn message_hash(&self) -> H256 {
|
||||||
|
let mut stream = RlpStream::new();
|
||||||
|
self.rlp_append_unsigned_transaction(&mut stream);
|
||||||
|
stream.out().sha3()
|
||||||
|
}
|
||||||
|
|
||||||
/// Signs the transaction as coming from `sender`.
|
/// Signs the transaction as coming from `sender`.
|
||||||
//pub fn sign(&mut self, secret: &Secret) {
|
pub fn sign(self, secret: &Secret) -> SignedTransaction {
|
||||||
// TODO: make always low.
|
let sig = ec::sign(secret, &self.message_hash());
|
||||||
//let sig = ec::sign(secret, &self.message_hash());
|
let (r, s, v) = sig.unwrap().to_rsv();
|
||||||
//let (r, s, v) = sig.unwrap().to_rsv();
|
SignedTransaction {
|
||||||
//self.r = r;
|
transaction: self,
|
||||||
//self.s = s;
|
r: r,
|
||||||
//self.v = v + 27;
|
s: s,
|
||||||
//}
|
v: v + 27,
|
||||||
|
hash: RefCell::new(None),
|
||||||
|
sender: RefCell::new(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Signs the transaction as coming from `sender`.
|
/// Useful for test incorrectly signed transactions.
|
||||||
//#[cfg(test)]
|
#[cfg(test)]
|
||||||
//pub fn signed(self, secret: &Secret) -> Transaction { let mut r = self; r.sign(secret); r }
|
pub fn fake_sign(self) -> SignedTransaction {
|
||||||
|
SignedTransaction {
|
||||||
|
transaction: self,
|
||||||
|
r: U256::zero(),
|
||||||
|
s: U256::zero(),
|
||||||
|
v: 0,
|
||||||
|
hash: RefCell::new(None),
|
||||||
|
sender: RefCell::new(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the transaction cost in gas for the given params.
|
/// Get the transaction cost in gas for the given params.
|
||||||
pub fn gas_required_for(is_create: bool, data: &[u8], schedule: &Schedule) -> u64 {
|
pub fn gas_required_for(is_create: bool, data: &[u8], schedule: &Schedule) -> u64 {
|
||||||
@ -199,91 +134,27 @@ impl Transaction {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The message hash of the transaction.
|
|
||||||
pub fn message_hash(&self) -> H256 {
|
|
||||||
let mut stream = RlpStream::new();
|
|
||||||
self.rlp_append_unsigned_transaction(&mut stream);
|
|
||||||
stream.out().sha3()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sign(self, secret: &Secret) -> SignedTransaction {
|
|
||||||
let sig = ec::sign(secret, &self.message_hash());
|
|
||||||
let (r, s, v) = sig.unwrap().to_rsv();
|
|
||||||
SignedTransaction {
|
|
||||||
transaction: self,
|
|
||||||
r: r,
|
|
||||||
s: s,
|
|
||||||
v: v,
|
|
||||||
hash: RefCell::new(None),
|
|
||||||
sender: RefCell::new(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the transaction cost in gas for this transaction.
|
/// Get the transaction cost in gas for this transaction.
|
||||||
pub fn gas_required(&self, schedule: &Schedule) -> u64 {
|
pub fn gas_required(&self, schedule: &Schedule) -> u64 {
|
||||||
Self::gas_required_for(match self.action{Action::Create=>true, Action::Call(_)=>false}, &self.data, schedule)
|
Self::gas_required_for(match self.action{Action::Create=>true, Action::Call(_)=>false}, &self.data, schedule)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Do basic validation, checking for valid signature and minimum gas,
|
|
||||||
// TODO: consider use in block validation.
|
|
||||||
#[cfg(test)]
|
|
||||||
#[cfg(feature = "json-tests")]
|
|
||||||
pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result<Transaction, Error> {
|
|
||||||
if require_low && !ec::is_low_s(&self.s) {
|
|
||||||
return Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature)));
|
|
||||||
}
|
|
||||||
try!(self.sender());
|
|
||||||
if self.gas < U256::from(self.gas_required(&schedule)) {
|
|
||||||
Err(From::from(TransactionError::InvalidGasLimit(OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas})))
|
|
||||||
} else {
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decodable for Action {
|
|
||||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
|
||||||
let rlp = decoder.as_rlp();
|
|
||||||
if rlp.is_empty() {
|
|
||||||
Ok(Action::Create)
|
|
||||||
} else {
|
|
||||||
Ok(Action::Call(try!(rlp.as_val())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//impl Decodable for Transaction {
|
|
||||||
//fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
|
||||||
//let d = decoder.as_rlp();
|
|
||||||
//if d.item_count() != 9 {
|
|
||||||
//return Err(DecoderError::RlpIncorrectListLen);
|
|
||||||
//}
|
|
||||||
//Ok(Transaction {
|
|
||||||
//nonce: try!(d.val_at(0)),
|
|
||||||
//gas_price: try!(d.val_at(1)),
|
|
||||||
//gas: try!(d.val_at(2)),
|
|
||||||
//action: try!(d.val_at(3)),
|
|
||||||
//value: try!(d.val_at(4)),
|
|
||||||
//data: try!(d.val_at(5)),
|
|
||||||
//v: try!(d.val_at(6)),
|
|
||||||
//r: try!(d.val_at(7)),
|
|
||||||
//s: try!(d.val_at(8)),
|
|
||||||
//hash: RefCell::new(None),
|
|
||||||
//sender: RefCell::new(None),
|
|
||||||
//})
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SignedTransaction {
|
pub struct SignedTransaction {
|
||||||
|
/// Plain Transaction.
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
|
/// The V field of the signature, either 27 or 28; helps describe the point on the curve.
|
||||||
v: u8,
|
v: u8,
|
||||||
|
/// The R field of the signature; helps describe the point on the curve.
|
||||||
r: U256,
|
r: U256,
|
||||||
|
/// The S field of the signature; helps describe the point on the curve.
|
||||||
s: U256,
|
s: U256,
|
||||||
|
/// Cached hash.
|
||||||
hash: RefCell<Option<H256>>,
|
hash: RefCell<Option<H256>>,
|
||||||
|
/// Cached sender.
|
||||||
sender: RefCell<Option<Address>>
|
sender: RefCell<Option<Address>>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,13 +180,6 @@ impl Decodable for SignedTransaction {
|
|||||||
action: try!(d.val_at(3)),
|
action: try!(d.val_at(3)),
|
||||||
value: try!(d.val_at(4)),
|
value: try!(d.val_at(4)),
|
||||||
data: try!(d.val_at(5)),
|
data: try!(d.val_at(5)),
|
||||||
|
|
||||||
// to remove
|
|
||||||
v: 0,
|
|
||||||
r: From::from(0),
|
|
||||||
s: From::from(0),
|
|
||||||
hash: RefCell::new(None),
|
|
||||||
sender: RefCell::new(None)
|
|
||||||
},
|
},
|
||||||
v: try!(d.val_at(6)),
|
v: try!(d.val_at(6)),
|
||||||
r: try!(d.val_at(7)),
|
r: try!(d.val_at(7)),
|
||||||
@ -335,7 +199,7 @@ impl SignedTransaction {
|
|||||||
pub fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) {
|
pub fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) {
|
||||||
s.begin_list(9);
|
s.begin_list(9);
|
||||||
s.append(&self.nonce);
|
s.append(&self.nonce);
|
||||||
s.appned(&self.gas_price);
|
s.append(&self.gas_price);
|
||||||
s.append(&self.gas);
|
s.append(&self.gas);
|
||||||
match self.action {
|
match self.action {
|
||||||
Action::Create => s.append_empty_data(),
|
Action::Create => s.append_empty_data(),
|
||||||
@ -386,11 +250,27 @@ impl SignedTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Do basic validation, checking for valid signature and minimum gas,
|
||||||
|
// TODO: consider use in block validation.
|
||||||
|
#[cfg(test)]
|
||||||
|
#[cfg(feature = "json-tests")]
|
||||||
|
pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result<SignedTransaction, Error> {
|
||||||
|
if require_low && !ec::is_low_s(&self.s) {
|
||||||
|
return Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature)));
|
||||||
|
}
|
||||||
|
try!(self.sender());
|
||||||
|
if self.gas < U256::from(self.gas_required(&schedule)) {
|
||||||
|
Err(From::from(TransactionError::InvalidGasLimit(OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas})))
|
||||||
|
} else {
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sender_test() {
|
fn sender_test() {
|
||||||
let t: Transaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
|
let t: SignedTransaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
|
||||||
assert_eq!(t.data, b"");
|
assert_eq!(t.data, b"");
|
||||||
assert_eq!(t.gas, U256::from(0x5208u64));
|
assert_eq!(t.gas, U256::from(0x5208u64));
|
||||||
assert_eq!(t.gas_price, U256::from(0x01u64));
|
assert_eq!(t.gas_price, U256::from(0x01u64));
|
||||||
@ -405,6 +285,13 @@ fn sender_test() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn signing() {
|
fn signing() {
|
||||||
let key = KeyPair::create().unwrap();
|
let key = KeyPair::create().unwrap();
|
||||||
let t = Transaction::new_create(U256::from(42u64), b"Hello!".to_vec(), U256::from(3000u64), U256::from(50_000u64), U256::from(1u64)).signed(&key.secret());
|
let t = Transaction {
|
||||||
|
action: Action::Create,
|
||||||
|
nonce: U256::from(42),
|
||||||
|
gas_price: U256::from(3000),
|
||||||
|
gas: U256::from(50_000),
|
||||||
|
value: U256::from(1),
|
||||||
|
data: b"Hello!".to_vec()
|
||||||
|
}.sign(&key.secret());
|
||||||
assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap());
|
assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap());
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,6 @@ mod tests {
|
|||||||
use engine::*;
|
use engine::*;
|
||||||
use spec::*;
|
use spec::*;
|
||||||
use transaction::*;
|
use transaction::*;
|
||||||
use basic_types::*;
|
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
|
|
||||||
fn check_ok(result: Result<(), Error>) {
|
fn check_ok(result: Result<(), Error>) {
|
||||||
@ -309,8 +308,26 @@ mod tests {
|
|||||||
good.timestamp = 40;
|
good.timestamp = 40;
|
||||||
good.number = 10;
|
good.number = 10;
|
||||||
|
|
||||||
let tr1 = Transaction::new_create(x!(0), Bytes::new(), x!(30000), x!(40000), x!(1));
|
let keypair = KeyPair::create().unwrap();
|
||||||
let tr2 = Transaction::new_create(x!(0), Bytes::new(), x!(30000), x!(40000), x!(2));
|
|
||||||
|
let tr1 = Transaction {
|
||||||
|
action: Action::Create,
|
||||||
|
value: U256::from(0),
|
||||||
|
data: Bytes::new(),
|
||||||
|
gas: U256::from(30_000),
|
||||||
|
gas_price: U256::from(40_000),
|
||||||
|
nonce: U256::one()
|
||||||
|
}.sign(&keypair.secret());
|
||||||
|
|
||||||
|
let tr2 = Transaction {
|
||||||
|
action: Action::Create,
|
||||||
|
value: U256::from(0),
|
||||||
|
data: Bytes::new(),
|
||||||
|
gas: U256::from(30_000),
|
||||||
|
gas_price: U256::from(40_000),
|
||||||
|
nonce: U256::from(2)
|
||||||
|
}.sign(&keypair.secret());
|
||||||
|
|
||||||
let good_transactions = [ &tr1, &tr2 ];
|
let good_transactions = [ &tr1, &tr2 ];
|
||||||
|
|
||||||
let diff_inc = U256::from(0x40);
|
let diff_inc = U256::from(0x40);
|
||||||
@ -346,7 +363,7 @@ mod tests {
|
|||||||
let mut uncles_rlp = RlpStream::new();
|
let mut uncles_rlp = RlpStream::new();
|
||||||
uncles_rlp.append(&good_uncles);
|
uncles_rlp.append(&good_uncles);
|
||||||
let good_uncles_hash = uncles_rlp.as_raw().sha3();
|
let good_uncles_hash = uncles_rlp.as_raw().sha3();
|
||||||
let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| t.rlp_bytes_opt(Seal::With)).collect());
|
let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| encode::<SignedTransaction>(t).to_vec()).collect());
|
||||||
|
|
||||||
let mut parent = good.clone();
|
let mut parent = good.clone();
|
||||||
parent.number = 9;
|
parent.number = 9;
|
||||||
|
Loading…
Reference in New Issue
Block a user