Merge pull request #760 from ethcore/tx_queue_gas_limit
Avoid importing transactions with gas above 1.1*block_gas_limit to transaction queue
This commit is contained in:
commit
2309e19fd9
@ -111,6 +111,7 @@ impl TestBlockChainClient {
|
|||||||
header.difficulty = From::from(n);
|
header.difficulty = From::from(n);
|
||||||
header.parent_hash = self.last_hash.read().unwrap().clone();
|
header.parent_hash = self.last_hash.read().unwrap().clone();
|
||||||
header.number = n as BlockNumber;
|
header.number = n as BlockNumber;
|
||||||
|
header.gas_limit = U256::from(1_000_000);
|
||||||
let uncles = match with {
|
let uncles = match with {
|
||||||
EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => {
|
EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => {
|
||||||
let mut uncles = RlpStream::new_list(1);
|
let mut uncles = RlpStream::new_list(1);
|
||||||
|
@ -79,6 +79,13 @@ pub enum TransactionError {
|
|||||||
/// Transaction cost
|
/// Transaction cost
|
||||||
cost: U256,
|
cost: U256,
|
||||||
},
|
},
|
||||||
|
/// Transactions gas is higher then current gas limit
|
||||||
|
GasLimitExceeded {
|
||||||
|
/// Current gas limit
|
||||||
|
limit: U256,
|
||||||
|
/// Declared transaction gas
|
||||||
|
got: U256,
|
||||||
|
},
|
||||||
/// Transaction's gas limit (aka gas) is invalid.
|
/// Transaction's gas limit (aka gas) is invalid.
|
||||||
InvalidGasLimit(OutOfBounds<U256>),
|
InvalidGasLimit(OutOfBounds<U256>),
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ use std::sync::atomic::AtomicBool;
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use util::{H256, U256, Address, Bytes, Uint};
|
use util::{H256, U256, Address, Bytes, Uint};
|
||||||
use ethcore::views::{BlockView};
|
use ethcore::views::{BlockView, HeaderView};
|
||||||
use ethcore::client::{BlockChainClient, BlockId};
|
use ethcore::client::{BlockChainClient, BlockId};
|
||||||
use ethcore::block::{ClosedBlock, IsBlock};
|
use ethcore::block::{ClosedBlock, IsBlock};
|
||||||
use ethcore::error::{Error};
|
use ethcore::error::{Error};
|
||||||
@ -94,6 +94,12 @@ impl Miner {
|
|||||||
pub fn set_minimal_gas_price(&self, min_gas_price: U256) {
|
pub fn set_minimal_gas_price(&self, min_gas_price: U256) {
|
||||||
self.transaction_queue.lock().unwrap().set_minimal_gas_price(min_gas_price);
|
self.transaction_queue.lock().unwrap().set_minimal_gas_price(min_gas_price);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_gas_limit(&self, chain: &BlockChainClient) {
|
||||||
|
let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit();
|
||||||
|
let mut queue = self.transaction_queue.lock().unwrap();
|
||||||
|
queue.set_gas_limit(gas_limit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MinerService for Miner {
|
impl MinerService for Miner {
|
||||||
@ -185,6 +191,11 @@ impl MinerService for Miner {
|
|||||||
let block = BlockView::new(&block);
|
let block = BlockView::new(&block);
|
||||||
block.transactions()
|
block.transactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First update gas limit in transaction queue
|
||||||
|
self.update_gas_limit(chain);
|
||||||
|
|
||||||
|
// Then import all transactions...
|
||||||
{
|
{
|
||||||
let out_of_chain = retracted
|
let out_of_chain = retracted
|
||||||
.par_iter()
|
.par_iter()
|
||||||
@ -201,7 +212,8 @@ impl MinerService for Miner {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// First import all transactions and after that remove old ones
|
|
||||||
|
// ...and after that remove old ones
|
||||||
{
|
{
|
||||||
let in_chain = {
|
let in_chain = {
|
||||||
let mut in_chain = HashSet::new();
|
let mut in_chain = HashSet::new();
|
||||||
@ -227,6 +239,7 @@ impl MinerService for Miner {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update mined block
|
||||||
if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
|
if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
|
||||||
self.prepare_sealing(chain);
|
self.prepare_sealing(chain);
|
||||||
}
|
}
|
||||||
|
@ -252,10 +252,16 @@ pub struct AccountDetails {
|
|||||||
pub balance: U256,
|
pub balance: U256,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue.
|
||||||
|
const GAS_LIMIT_HYSTERESIS: usize = 10; // %
|
||||||
|
|
||||||
/// TransactionQueue implementation
|
/// TransactionQueue implementation
|
||||||
pub struct TransactionQueue {
|
pub struct TransactionQueue {
|
||||||
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
|
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
|
||||||
minimal_gas_price: U256,
|
minimal_gas_price: U256,
|
||||||
|
/// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0)
|
||||||
|
gas_limit: U256,
|
||||||
/// Priority queue for transactions that can go to block
|
/// Priority queue for transactions that can go to block
|
||||||
current: TransactionSet,
|
current: TransactionSet,
|
||||||
/// Priority queue for transactions that has been received but are not yet valid to go to block
|
/// Priority queue for transactions that has been received but are not yet valid to go to block
|
||||||
@ -293,6 +299,7 @@ impl TransactionQueue {
|
|||||||
|
|
||||||
TransactionQueue {
|
TransactionQueue {
|
||||||
minimal_gas_price: U256::zero(),
|
minimal_gas_price: U256::zero(),
|
||||||
|
gas_limit: !U256::zero(),
|
||||||
current: current,
|
current: current,
|
||||||
future: future,
|
future: future,
|
||||||
by_hash: HashMap::new(),
|
by_hash: HashMap::new(),
|
||||||
@ -301,11 +308,22 @@ impl TransactionQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets new gas price threshold for incoming transactions.
|
/// Sets new gas price threshold for incoming transactions.
|
||||||
/// Any transactions already imported to the queue are not affected.
|
/// Any transaction already imported to the queue is not affected.
|
||||||
pub fn set_minimal_gas_price(&mut self, min_gas_price: U256) {
|
pub fn set_minimal_gas_price(&mut self, min_gas_price: U256) {
|
||||||
self.minimal_gas_price = min_gas_price;
|
self.minimal_gas_price = min_gas_price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets new gas limit. Transactions with gas slightly (`GAS_LIMIT_HYSTERESIS`) above the limit won't be imported.
|
||||||
|
/// Any transaction already imported to the queue is not affected.
|
||||||
|
pub fn set_gas_limit(&mut self, gas_limit: U256) {
|
||||||
|
let extra = gas_limit / U256::from(GAS_LIMIT_HYSTERESIS);
|
||||||
|
|
||||||
|
self.gas_limit = match gas_limit.overflowing_add(extra) {
|
||||||
|
(_, true) => !U256::zero(),
|
||||||
|
(val, false) => val,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns current status for this queue
|
/// Returns current status for this queue
|
||||||
pub fn status(&self) -> TransactionQueueStatus {
|
pub fn status(&self) -> TransactionQueueStatus {
|
||||||
TransactionQueueStatus {
|
TransactionQueueStatus {
|
||||||
@ -335,12 +353,24 @@ impl TransactionQueue {
|
|||||||
tx.hash(), tx.gas_price, self.minimal_gas_price
|
tx.hash(), tx.gas_price, self.minimal_gas_price
|
||||||
);
|
);
|
||||||
|
|
||||||
return Err(Error::Transaction(TransactionError::InsufficientGasPrice{
|
return Err(Error::Transaction(TransactionError::InsufficientGasPrice {
|
||||||
minimal: self.minimal_gas_price,
|
minimal: self.minimal_gas_price,
|
||||||
got: tx.gas_price,
|
got: tx.gas_price,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tx.gas > self.gas_limit {
|
||||||
|
trace!(target: "miner",
|
||||||
|
"Dropping transaction above gas limit: {:?} ({} > {})",
|
||||||
|
tx.hash(), tx.gas, self.gas_limit
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(Error::Transaction(TransactionError::GasLimitExceeded {
|
||||||
|
limit: self.gas_limit,
|
||||||
|
got: tx.gas,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let vtx = try!(VerifiedTransaction::new(tx));
|
let vtx = try!(VerifiedTransaction::new(tx));
|
||||||
let account = fetch_account(&vtx.sender());
|
let account = fetch_account(&vtx.sender());
|
||||||
@ -677,6 +707,37 @@ mod test {
|
|||||||
assert_eq!(stats.pending, 1);
|
assert_eq!(stats.pending, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gas_limit_should_never_overflow() {
|
||||||
|
// given
|
||||||
|
let mut txq = TransactionQueue::new();
|
||||||
|
txq.set_gas_limit(U256::zero());
|
||||||
|
assert_eq!(txq.gas_limit, U256::zero());
|
||||||
|
|
||||||
|
// when
|
||||||
|
txq.set_gas_limit(!U256::zero());
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(txq.gas_limit, !U256::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_not_import_transaction_above_gas_limit() {
|
||||||
|
// given
|
||||||
|
let mut txq = TransactionQueue::new();
|
||||||
|
let tx = new_tx();
|
||||||
|
txq.set_gas_limit(tx.gas / U256::from(2));
|
||||||
|
|
||||||
|
// when
|
||||||
|
txq.add(tx, &default_nonce).unwrap_err();
|
||||||
|
|
||||||
|
// then
|
||||||
|
let stats = txq.status();
|
||||||
|
assert_eq!(stats.pending, 0);
|
||||||
|
assert_eq!(stats.future, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_drop_transactions_from_senders_without_balance() {
|
fn should_drop_transactions_from_senders_without_balance() {
|
||||||
// given
|
// given
|
||||||
|
Loading…
Reference in New Issue
Block a user