diff --git a/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json b/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json
index b165625a165..89077c0af02 100644
--- a/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json
+++ b/ethcore/res/tx_permission_tests/contract_ver_2_genesis.json
@@ -17,7 +17,8 @@
"minGasLimit": "0x1388",
"networkID" : "0x69",
"gasLimitBoundDivisor": "0x0400",
- "transactionPermissionContract": "0x0000000000000000000000000000000000000005"
+ "transactionPermissionContract": "0x0000000000000000000000000000000000000005",
+ "transactionPermissionContractTransition": "1"
},
"genesis": {
"seal": {
diff --git a/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json b/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json
index 92fde908089..dd858bee6c0 100644
--- a/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json
+++ b/ethcore/res/tx_permission_tests/deprecated_contract_genesis.json
@@ -17,7 +17,8 @@
"minGasLimit": "0x1388",
"networkID" : "0x69",
"gasLimitBoundDivisor": "0x0400",
- "transactionPermissionContract": "0x0000000000000000000000000000000000000005"
+ "transactionPermissionContract": "0x0000000000000000000000000000000000000005",
+ "transactionPermissionContractTransition": "1"
},
"genesis": {
"seal": {
diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs
index 5b2170609a3..d487fff9b77 100644
--- a/ethcore/src/machine.rs
+++ b/ethcore/src/machine.rs
@@ -343,7 +343,7 @@ impl EthereumMachine {
-> Result<(), transaction::Error>
{
if let Some(ref filter) = self.tx_filter.as_ref() {
- if !filter.transaction_allowed(header.parent_hash(), t, client) {
+ if !filter.transaction_allowed(header.parent_hash(), header.number(), t, client) {
return Err(transaction::Error::NotAllowed.into())
}
}
diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs
index 45f9a6c9556..e842835f7c8 100644
--- a/ethcore/src/spec/spec.rs
+++ b/ethcore/src/spec/spec.rs
@@ -139,6 +139,8 @@ pub struct CommonParams {
pub max_code_size_transition: BlockNumber,
/// Transaction permission managing contract address.
pub transaction_permission_contract: Option
,
+ /// Block at which the transaction permission contract should start being used.
+ pub transaction_permission_contract_transition: BlockNumber,
/// Maximum size of transaction's RLP payload
pub max_transaction_size: usize,
}
@@ -296,6 +298,8 @@ impl From for CommonParams {
max_transaction_size: p.max_transaction_size.map_or(MAX_TRANSACTION_SIZE, Into::into),
max_code_size_transition: p.max_code_size_transition.map_or(0, Into::into),
transaction_permission_contract: p.transaction_permission_contract.map(Into::into),
+ transaction_permission_contract_transition:
+ p.transaction_permission_contract_transition.map_or(0, Into::into),
wasm_activation_transition: p.wasm_activation_transition.map_or_else(
BlockNumber::max_value,
Into::into
diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs
index 585dc7e3d38..78b495b26ad 100644
--- a/ethcore/src/tx_filter.rs
+++ b/ethcore/src/tx_filter.rs
@@ -23,6 +23,7 @@ use client::{BlockInfo, CallContract, BlockId};
use parking_lot::Mutex;
use spec::CommonParams;
use transaction::{Action, SignedTransaction};
+use types::BlockNumber;
use hash::KECCAK_EMPTY;
use_contract!(transact_acl_deprecated, "TransactAclDeprecated", "res/contracts/tx_acl_deprecated.json");
@@ -44,6 +45,7 @@ pub struct TransactionFilter {
contract_deprecated: transact_acl_deprecated::TransactAclDeprecated,
contract: transact_acl::TransactAcl,
contract_address: Address,
+ transition_block: BlockNumber,
permission_cache: Mutex>,
contract_version_cache: Mutex>>
}
@@ -56,6 +58,7 @@ impl TransactionFilter {
contract_deprecated: transact_acl_deprecated::TransactAclDeprecated::default(),
contract: transact_acl::TransactAcl::default(),
contract_address: address,
+ transition_block: params.transaction_permission_contract_transition,
permission_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)),
contract_version_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)),
}
@@ -63,7 +66,9 @@ impl TransactionFilter {
}
/// Check if transaction is allowed at given block.
- pub fn transaction_allowed(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &C) -> bool {
+ pub fn transaction_allowed(&self, parent_hash: &H256, block_number: BlockNumber, transaction: &SignedTransaction, client: &C) -> bool {
+ if block_number < self.transition_block { return true; }
+
let mut permission_cache = self.permission_cache.lock();
let mut contract_version_cache = self.contract_version_cache.lock();
@@ -196,33 +201,38 @@ mod test {
basic_tx_with_ether_and_to_key6.value = U256::from(123123);
let genesis = client.block_hash(BlockId::Latest).unwrap();
-
- assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key1.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &create_tx.clone().sign(key1.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key1.secret(), None), &*client));
-
- assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key2.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key2.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key2.secret(), None), &*client));
-
- assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key3.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key3.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key3.secret(), None), &*client));
-
- assert!(!filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key4.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key4.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key4.secret(), None), &*client));
-
- assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key1.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &create_tx.clone().sign(key1.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key1.secret(), None), &*client));
-
- assert!(!filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key7.clone().sign(key5.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &call_tx_with_ether.clone().sign(key5.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key6.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key7.clone().sign(key6.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &basic_tx_to_key6.clone().sign(key7.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &basic_tx_with_ether_and_to_key6.clone().sign(key7.secret(), None), &*client));
+ let block_number = 1;
+
+ assert!(!filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key2.secret(), None), &*client));
+ // same tx but request is allowed because the contract only enables at block #1
+ assert!(filter.transaction_allowed(&genesis, 0, &create_tx.clone().sign(key2.secret(), None), &*client));
+
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key1.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key1.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &call_tx.clone().sign(key1.secret(), None), &*client));
+
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key2.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key2.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &call_tx.clone().sign(key2.secret(), None), &*client));
+
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key3.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key3.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &call_tx.clone().sign(key3.secret(), None), &*client));
+
+ assert!(!filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key4.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key4.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &call_tx.clone().sign(key4.secret(), None), &*client));
+
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key1.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key1.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &call_tx.clone().sign(key1.secret(), None), &*client));
+
+ assert!(!filter.transaction_allowed(&genesis, block_number, &basic_tx_with_ether_and_to_key7.clone().sign(key5.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &call_tx_with_ether.clone().sign(key5.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key6.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx_with_ether_and_to_key7.clone().sign(key6.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx_to_key6.clone().sign(key7.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &basic_tx_with_ether_and_to_key6.clone().sign(key7.secret(), None), &*client));
}
/// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a
@@ -254,21 +264,26 @@ mod test {
call_tx.action = Action::Call(Address::from("0000000000000000000000000000000000000005"));
let genesis = client.block_hash(BlockId::Latest).unwrap();
+ let block_number = 1;
+
+ assert!(!filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key2.secret(), None), &*client));
+ // same tx but request is allowed because the contract only enables at block #1
+ assert!(filter.transaction_allowed(&genesis, 0, &create_tx.clone().sign(key2.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key1.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &create_tx.clone().sign(key1.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key1.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key1.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key1.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &call_tx.clone().sign(key1.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key2.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key2.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &call_tx.clone().sign(key2.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key2.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key2.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &call_tx.clone().sign(key2.secret(), None), &*client));
- assert!(filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key3.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key3.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key3.secret(), None), &*client));
+ assert!(filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key3.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key3.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &call_tx.clone().sign(key3.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &basic_tx.clone().sign(key4.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &create_tx.clone().sign(key4.secret(), None), &*client));
- assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key4.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &basic_tx.clone().sign(key4.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &create_tx.clone().sign(key4.secret(), None), &*client));
+ assert!(!filter.transaction_allowed(&genesis, block_number, &call_tx.clone().sign(key4.secret(), None), &*client));
}
}
diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs
index 0fab68198ac..cf57e9af456 100644
--- a/json/src/spec/params.rs
+++ b/json/src/spec/params.rs
@@ -143,6 +143,9 @@ pub struct Params {
/// Transaction permission contract address.
#[serde(rename="transactionPermissionContract")]
pub transaction_permission_contract: Option,
+ /// Block at which the transaction permission contract should start being used.
+ #[serde(rename="transactionPermissionContractTransition")]
+ pub transaction_permission_contract_transition: Option,
/// Wasm activation block height, if not activated from start
#[serde(rename="wasmActivationTransition")]
pub wasm_activation_transition: Option,