Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tx filter version 3, and a unit test. #197

Merged
merged 1 commit into from
Oct 21, 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
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"
}
}
}
46 changes: 44 additions & 2 deletions ethcore/src/tx_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ impl TransactionFilter {
.and_then(|value| decoder.decode(&value).map_err(|e| e.to_string()))
.map(|(p, f)| (p.low_u32(), f))
}
0xffff_ffff_ffff_fffe => {
3 => {
trace!(target: "tx_filter", "Using filter with gas price");
let (data, decoder) = transact_acl_gas_price::functions::allowed_tx_types::call(
sender, to, value, gas_price, transaction.data.clone()
Expand Down Expand Up @@ -171,7 +171,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 +248,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("0000000000000000000000000000000000000042"));
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