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 b165625a1..89077c0af 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 92fde9080..dd858bee6 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 5b2170609..d487fff9b 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 45f9a6c95..e842835f7 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 585dc7e3d..78b495b26 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(); + let block_number = 1; - 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, &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(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(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(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(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(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(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(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(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, &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)); + 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, &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, &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(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(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(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(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(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(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)); } } diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 0fab68198..cf57e9af4 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,