Add additional service transactions checking to block verifier

This commit is contained in:
POA 2021-11-10 16:36:17 +03:00
parent 88eb7d3257
commit caa210107e
14 changed files with 72 additions and 23 deletions

View File

@ -1,3 +1,8 @@
## OpenEthereum v3.3.0-rc.16
Enhancements:
* Additionally check zero gas price transactions by block verifier
## OpenEthereum v3.3.0-rc.15 ## OpenEthereum v3.3.0-rc.15
* Revert eip1559BaseFeeMinValue activation on xDai at London hardfork block * Revert eip1559BaseFeeMinValue activation on xDai at London hardfork block

4
Cargo.lock generated
View File

@ -2932,7 +2932,7 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]] [[package]]
name = "openethereum" name = "openethereum"
version = "3.3.0-rc.15" version = "3.3.0-rc.16"
dependencies = [ dependencies = [
"ansi_term 0.10.2", "ansi_term 0.10.2",
"atty", "atty",
@ -3282,7 +3282,7 @@ dependencies = [
[[package]] [[package]]
name = "parity-version" name = "parity-version"
version = "3.3.0-rc.15" version = "3.3.0-rc.16"
dependencies = [ dependencies = [
"parity-bytes", "parity-bytes",
"rlp", "rlp",

View File

@ -2,7 +2,7 @@
description = "OpenEthereum" description = "OpenEthereum"
name = "openethereum" name = "openethereum"
# NOTE Make sure to update util/version/Cargo.toml as well # NOTE Make sure to update util/version/Cargo.toml as well
version = "3.3.0-rc.15" version = "3.3.0-rc.16"
license = "GPL-3.0" license = "GPL-3.0"
authors = [ authors = [
"OpenEthereum developers", "OpenEthereum developers",

View File

@ -189,8 +189,8 @@ impl txpool::VerifiedTransaction for VerifiedTransaction {
&self.sender &self.sender
} }
fn is_service(&self) -> bool { fn has_zero_gas_price(&self) -> bool {
self.transaction.is_service() self.transaction.has_zero_gas_price()
} }
} }

View File

@ -131,12 +131,12 @@ impl Transaction {
} }
} }
/// Cheeck if transaction is service transaction /// Check if transaction has zero gas price
pub fn is_service(&self) -> bool { pub fn has_zero_gas_price(&self) -> bool {
match *self { match *self {
Transaction::Unverified(ref tx) => tx.is_service(), Transaction::Unverified(ref tx) => tx.has_zero_gas_price(),
Transaction::Retracted(ref tx) => tx.is_service(), Transaction::Retracted(ref tx) => tx.has_zero_gas_price(),
Transaction::Local(ref tx) => tx.is_service(), Transaction::Local(ref tx) => tx.has_zero_gas_price(),
} }
} }
@ -243,13 +243,13 @@ impl<C: Client> txpool::Verifier<Transaction>
} }
let is_own = tx.is_local(); let is_own = tx.is_local();
let is_service = tx.is_service(); let has_zero_gas_price = tx.has_zero_gas_price();
// Quick exit for non-service and non-local transactions // Quick exit for non-service and non-local transactions
// //
// We're checking if the transaction is below configured minimal gas price // We're checking if the transaction is below configured minimal gas price
// or the effective minimal gas price in case the pool is full. // or the effective minimal gas price in case the pool is full.
if !is_service && !is_own { if !has_zero_gas_price && !is_own {
let effective_priority_fee = tx.effective_priority_fee(self.options.block_base_fee); let effective_priority_fee = tx.effective_priority_fee(self.options.block_base_fee);
if effective_priority_fee < self.options.minimal_gas_price { if effective_priority_fee < self.options.minimal_gas_price {

View File

@ -72,7 +72,7 @@ impl ServiceTransactionChecker {
SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(),
BlockId::Latest, BlockId::Latest,
) )
.ok_or_else(|| "contract is not configured")?; .ok_or_else(|| "Certifier contract is not configured")?;
self.call_contract(client, contract_address, sender) self.call_contract(client, contract_address, sender)
.and_then(|allowed| { .and_then(|allowed| {
if let Some(mut cache) = self.certified_addresses_cache.try_write() { if let Some(mut cache) = self.certified_addresses_cache.try_write() {

View File

@ -488,6 +488,50 @@ impl Importer {
.epoch_transition(parent.number(), *header.parent_hash()) .epoch_transition(parent.number(), *header.parent_hash())
.is_some(); .is_some();
// Check if zero gas price transactions are certified to be service transactions
// using the Certifier contract. If they are not certified, the block is treated as invalid.
let service_transaction_checker = self.miner.service_transaction_checker();
if service_transaction_checker.is_some() {
match service_transaction_checker.unwrap().refresh_cache(client) {
Ok(true) => {
trace!(target: "client", "Service transaction cache was refreshed successfully");
}
Ok(false) => {
trace!(target: "client", "Registrar or/and service transactions contract does not exist");
}
Err(e) => {
error!(target: "client", "Error occurred while refreshing service transaction cache: {}", e)
}
};
};
for t in &block.transactions {
if t.has_zero_gas_price() {
match self.miner.service_transaction_checker() {
None => {
let e = "Service transactions are not allowed. You need to enable Certifier contract.";
warn!(target: "client", "Service tx checker error: {:?}", e);
bail!(e);
}
Some(ref checker) => match checker.check(client, &t) {
Ok(true) => {}
Ok(false) => {
let e = format!(
"Service transactions are not allowed for the sender {:?}",
t.sender()
);
warn!(target: "client", "Service tx checker error: {:?}", e);
bail!(e);
}
Err(e) => {
debug!(target: "client", "Unable to verify service transaction: {:?}", e);
warn!(target: "client", "Service tx checker error: {:?}", e);
bail!(e);
}
},
}
};
}
// t_nb 8.0 Block enacting. Execution of transactions. // t_nb 8.0 Block enacting. Execution of transactions.
let enact_result = enact_verified( let enact_result = enact_verified(
block, block,

View File

@ -1207,7 +1207,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
} }
// ensure that the user was willing to at least pay the base fee // ensure that the user was willing to at least pay the base fee
if t.tx().gas_price < self.info.base_fee.unwrap_or_default() && !t.is_service() { if t.tx().gas_price < self.info.base_fee.unwrap_or_default() && !t.has_zero_gas_price() {
return Err(ExecutionError::GasPriceLowerThanBaseFee { return Err(ExecutionError::GasPriceLowerThanBaseFee {
gas_price: t.tx().gas_price, gas_price: t.tx().gas_price,
base_fee: self.info.base_fee.unwrap_or_default(), base_fee: self.info.base_fee.unwrap_or_default(),
@ -1516,7 +1516,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
// Up until now, fees_value is calculated for each type of transaction based on their gas prices // Up until now, fees_value is calculated for each type of transaction based on their gas prices
// Now, if eip1559 is activated, burn the base fee // Now, if eip1559 is activated, burn the base fee
// miner only receives the inclusion fee; note that the base fee is not given to anyone (it is burned) // miner only receives the inclusion fee; note that the base fee is not given to anyone (it is burned)
let burnt_fee = if schedule.eip1559 && !t.is_service() { let burnt_fee = if schedule.eip1559 && !t.has_zero_gas_price() {
let (fee, overflow_3) = let (fee, overflow_3) =
gas_used.overflowing_mul(self.info.base_fee.unwrap_or_default()); gas_used.overflowing_mul(self.info.base_fee.unwrap_or_default());
if overflow_3 { if overflow_3 {

View File

@ -376,7 +376,7 @@ impl EthereumMachine {
header: &Header, header: &Header,
) -> Result<SignedTransaction, transaction::Error> { ) -> Result<SignedTransaction, transaction::Error> {
// ensure that the user was willing to at least pay the base fee // ensure that the user was willing to at least pay the base fee
if t.tx().gas_price < header.base_fee().unwrap_or_default() && !t.is_service() { if t.tx().gas_price < header.base_fee().unwrap_or_default() && !t.has_zero_gas_price() {
return Err(transaction::Error::GasPriceLowerThanBaseFee { return Err(transaction::Error::GasPriceLowerThanBaseFee {
gas_price: t.tx().gas_price, gas_price: t.tx().gas_price,
base_fee: header.base_fee().unwrap_or_default(), base_fee: header.base_fee().unwrap_or_default(),

View File

@ -657,7 +657,7 @@ impl TypedTransaction {
.unwrap_or_default() .unwrap_or_default()
} }
pub fn is_service(&self) -> bool { pub fn has_zero_gas_price(&self) -> bool {
match self { match self {
Self::EIP1559Transaction(tx) => { Self::EIP1559Transaction(tx) => {
tx.tx().gas_price.is_zero() && tx.max_priority_fee_per_gas.is_zero() tx.tx().gas_price.is_zero() && tx.max_priority_fee_per_gas.is_zero()

View File

@ -114,6 +114,6 @@ pub trait VerifiedTransaction: fmt::Debug {
/// Transaction sender /// Transaction sender
fn sender(&self) -> &Self::Sender; fn sender(&self) -> &Self::Sender;
/// Is it a service transaction? /// Does it have zero gas price?
fn is_service(&self) -> bool; fn has_zero_gas_price(&self) -> bool;
} }

View File

@ -651,7 +651,7 @@ where
Readiness::Ready => { Readiness::Ready => {
//return transaction with score higher or equal to desired //return transaction with score higher or equal to desired
if score >= &self.includable_boundary if score >= &self.includable_boundary
|| tx.transaction.is_service() || tx.transaction.has_zero_gas_price()
{ {
return Some(tx.transaction.clone()); return Some(tx.transaction.clone());
} }
@ -740,7 +740,7 @@ where
if tx_state == Readiness::Ready { if tx_state == Readiness::Ready {
//return transaction with score higher or equal to desired //return transaction with score higher or equal to desired
if best.score >= self.includable_boundary if best.score >= self.includable_boundary
|| best.transaction.transaction.is_service() || best.transaction.transaction.has_zero_gas_price()
{ {
return Some(best.transaction.transaction); return Some(best.transaction.transaction);
} }

View File

@ -50,7 +50,7 @@ impl VerifiedTransaction for Transaction {
fn sender(&self) -> &Address { fn sender(&self) -> &Address {
&self.sender &self.sender
} }
fn is_service(&self) -> bool { fn has_zero_gas_price(&self) -> bool {
false false
} }
} }

View File

@ -1,7 +1,7 @@
[package] [package]
name = "parity-version" name = "parity-version"
# NOTE: this value is used for OpenEthereum version string (via env CARGO_PKG_VERSION) # NOTE: this value is used for OpenEthereum version string (via env CARGO_PKG_VERSION)
version = "3.3.0-rc.15" version = "3.3.0-rc.16"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs" build = "build.rs"