Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

TxPermissions ver 3: gas price & data #11170

Merged
merged 1 commit into from
Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions ethcore/machine/res/tx_acl_gas_price.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
[
{
"constant": true,
"inputs": [],
"name": "contractNameHash",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "contractName",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "contractVersion",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "sender",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
},
{
"name": "gasPrice",
"type": "uint256"
},
{
"name": "data",
"type": "bytes"
}
],
"name": "allowedTxTypes",
"outputs": [
{
"name": "",
"type": "uint32"
},
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
]
63 changes: 60 additions & 3 deletions ethcore/machine/src/tx_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use keccak_hash::KECCAK_EMPTY;

use_contract!(transact_acl_deprecated, "res/tx_acl_deprecated.json");
use_contract!(transact_acl, "res/tx_acl.json");
use_contract!(transact_acl_gas_price, "res/tx_acl_gas_price.json");

const MAX_CACHE_SIZE: usize = 4096;

Expand Down Expand Up @@ -86,6 +87,7 @@ impl TransactionFilter {

let sender = transaction.sender();
let value = transaction.value;
let gas_price = transaction.gas_price;
let key = (*parent_hash, sender);

if let Some(permissions) = permission_cache.get_mut(&key) {
Expand Down Expand Up @@ -115,6 +117,19 @@ impl TransactionFilter {
(tx_permissions::NONE, true)
})
},
3 => {
trace!(target: "tx_filter", "Using filter with gas price and data");
let (data, decoder) = transact_acl_gas_price::functions::allowed_tx_types::call(
sender, to, value, gas_price, transaction.data.clone()
);
client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)
.and_then(|value| decoder.decode(&value).map_err(|e| e.to_string()))
.map(|(p, f)| (p.low_u32(), f))
.unwrap_or_else(|e| {
error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e);
(tx_permissions::NONE, true)
})
}
_ => {
error!(target: "tx_filter", "Unknown version of tx permissions contract is used");
(tx_permissions::NONE, true)
Expand All @@ -138,8 +153,8 @@ impl TransactionFilter {
permission_cache.insert((*parent_hash, sender), permissions);
}
trace!(target: "tx_filter",
"Given transaction data: sender: {:?} to: {:?} value: {}. Permissions required: {:X}, got: {:X}",
sender, to, value, tx_type, permissions
"Given transaction data: sender: {:?} to: {:?} value: {}, gas_price: {}. Permissions required: {:X}, got: {:X}",
sender, to, value, gas_price, tx_type, permissions
);
permissions & tx_type != 0
}
Expand Down Expand Up @@ -171,7 +186,7 @@ mod test {

/// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f
#[test]
fn transaction_filter() {
fn transaction_filter_ver_2() {
let spec_data = include_str!("../../res/tx_permission_tests/contract_ver_2_genesis.json");

let db = test_helpers::new_db();
Expand Down Expand Up @@ -248,6 +263,48 @@ mod test {
assert!(!filter.transaction_allowed(&genesis, block_number, &basic_tx_with_ether_and_to_key6.clone().sign(key7.secret(), None), &*client));
}

/// Contract code: res/tx_permission_tests/contract_ver_3.sol
#[test]
fn transaction_filter_ver_3() {
let spec_data = include_str!("../../res/tx_permission_tests/contract_ver_3_genesis.json");

let db = test_helpers::new_db();
let tempdir = TempDir::new("").unwrap();
let spec = Spec::load(&tempdir.path(), spec_data.as_bytes()).unwrap();

let client = Client::new(
ClientConfig::default(),
&spec,
db,
Arc::new(Miner::new_for_tests(&spec, None)),
IoChannel::disconnected(),
).unwrap();
let key1 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000001")).unwrap();

// The only difference to version 2 is that the contract now knows the transaction's gas price and data.
// So we only test those: The contract allows only transactions with either nonzero gas price or short data.

let filter = TransactionFilter::from_params(spec.params()).unwrap();
let mut tx = Transaction::default();
tx.action = Action::Call(Address::from_str("0000000000000000000000000000000000000042").unwrap());
tx.data = b"01234567".to_vec();
tx.gas_price = 0.into();

let genesis = client.block_hash(BlockId::Latest).unwrap();
let block_number = 1;

// Data too long and gas price zero. This transaction is not allowed.
assert!(!filter.transaction_allowed(&genesis, block_number, &tx.clone().sign(key1.secret(), None), &*client));

// But if we either set a nonzero gas price or short data or both, it is allowed.
tx.gas_price = 1.into();
assert!(filter.transaction_allowed(&genesis, block_number, &tx.clone().sign(key1.secret(), None), &*client));
tx.data = b"01".to_vec();
assert!(filter.transaction_allowed(&genesis, block_number, &tx.clone().sign(key1.secret(), None), &*client));
tx.gas_price = 0.into();
assert!(filter.transaction_allowed(&genesis, block_number, &tx.clone().sign(key1.secret(), None), &*client));
}

/// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a
#[test]
fn transaction_filter_deprecated() {
Expand Down
60 changes: 60 additions & 0 deletions ethcore/res/tx_permission_tests/contract_ver_3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
pragma solidity ^0.4.20;

// Adapted from https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f
// and: https://github.com/poanetwork/posdao-contracts/blob/master/contracts/TxPermission.sol

contract TxPermission {
/// Allowed transaction types mask
uint32 constant None = 0;
uint32 constant All = 0xffffffff;
uint32 constant Basic = 0x01;
uint32 constant Call = 0x02;
uint32 constant Create = 0x04;
uint32 constant Private = 0x08;

/// Contract name
function contractName() public constant returns (string) {
return "TX_PERMISSION_CONTRACT";
}

/// Contract name hash
function contractNameHash() public constant returns (bytes32) {
return keccak256(contractName());
}

/// Contract version
function contractVersion() public constant returns (uint256) {
return 3;
}

/// @dev Defines the allowed transaction types which may be initiated by the specified sender with
/// the specified gas price and data. Used by the Parity engine each time a transaction is about to be
/// included into a block. See https://wiki.parity.io/Permissioning.html#how-it-works-1
/// @param _sender Transaction sender address.
/// @param _to Transaction recipient address. If creating a contract, the `_to` address is zero.
/// @param _value Transaction amount in wei.
/// @param _gasPrice Gas price in wei for the transaction.
/// @param _data Transaction data.
/// @return `uint32 typesMask` - Set of allowed transactions for `_sender` depending on tx `_to` address,
/// `_gasPrice`, and `_data`. The result is represented as a set of flags:
/// 0x01 - basic transaction (e.g. ether transferring to user wallet);
/// 0x02 - contract call;
/// 0x04 - contract creation;
/// 0x08 - private transaction.
/// `bool cache` - If `true` is returned, the same permissions will be applied from the same
/// `_sender` without calling this contract again.
function allowedTxTypes(
address _sender,
address _to,
uint256 _value,
uint256 _gasPrice,
bytes memory _data
)
public
view
returns(uint32 typesMask, bool cache)
{
if (_gasPrice > 0 || _data.length < 4) return (All, false);
return (None, false);
}
}
44 changes: 44 additions & 0 deletions ethcore/res/tx_permission_tests/contract_ver_3_genesis.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "TestNodeFilterContract",
"engine": {
"authorityRound": {
"params": {
"stepDuration": 1,
"startStep": 2,
"validators": {
"contract": "0x0000000000000000000000000000000000000000"
}
}
}
},
"params": {
"accountStartNonce": "0x0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x69",
"gasLimitBoundDivisor": "0x0400",
"transactionPermissionContract": "0x0000000000000000000000000000000000000005",
"transactionPermissionContractTransition": "1"
},
"genesis": {
"seal": {
"generic": "0xc180"
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x222222"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0000000000000000000000000000000000000005": {
"balance": "1",
"constructor": "6060604052341561000f57600080fd5b61035e8061001e6000396000f300606060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063469ab1e31461006757806375d0c0dc14610098578063a0a8e46014610126578063b9056afa1461014f575b600080fd5b341561007257600080fd5b61007a610227565b60405180826000191660001916815260200191505060405180910390f35b34156100a357600080fd5b6100ab610298565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100eb5780820151818401526020810190506100d0565b50505050905090810190601f1680156101185780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013157600080fd5b6101396102db565b6040518082815260200191505060405180910390f35b341561015a57600080fd5b6101fa600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919050506102e4565b604051808363ffffffff1663ffffffff168152602001821515151581526020019250505060405180910390f35b6000610231610298565b6040518082805190602001908083835b6020831015156102665780518252602082019150602081019050602083039250610241565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905090565b6102a061031e565b6040805190810160405280601681526020017f54585f5045524d495353494f4e5f434f4e545241435400000000000000000000815250905090565b60006003905090565b60008060008411806102f7575060048351105b1561030c5763ffffffff600091509150610314565b600080915091505b9550959350505050565b6020604051908101604052806000815250905600a165627a7a72305820be61565bc09fec6e9223a1fecd2e94783ca5c6f506c03f71d479a8c3285493310029"
}
}
}