TxPermissions ver 3: gas price & data (#11170)
This commit is contained in:
parent
9c8b7c23d1
commit
ff697b64b3
83
ethcore/machine/res/tx_acl_gas_price.json
Normal file
83
ethcore/machine/res/tx_acl_gas_price.json
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
]
|
@ -35,6 +35,7 @@ use keccak_hash::KECCAK_EMPTY;
|
|||||||
|
|
||||||
use_contract!(transact_acl_deprecated, "res/tx_acl_deprecated.json");
|
use_contract!(transact_acl_deprecated, "res/tx_acl_deprecated.json");
|
||||||
use_contract!(transact_acl, "res/tx_acl.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;
|
const MAX_CACHE_SIZE: usize = 4096;
|
||||||
|
|
||||||
@ -86,6 +87,7 @@ impl TransactionFilter {
|
|||||||
|
|
||||||
let sender = transaction.sender();
|
let sender = transaction.sender();
|
||||||
let value = transaction.value;
|
let value = transaction.value;
|
||||||
|
let gas_price = transaction.gas_price;
|
||||||
let key = (*parent_hash, sender);
|
let key = (*parent_hash, sender);
|
||||||
|
|
||||||
if let Some(permissions) = permission_cache.get_mut(&key) {
|
if let Some(permissions) = permission_cache.get_mut(&key) {
|
||||||
@ -115,6 +117,19 @@ impl TransactionFilter {
|
|||||||
(tx_permissions::NONE, true)
|
(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");
|
error!(target: "tx_filter", "Unknown version of tx permissions contract is used");
|
||||||
(tx_permissions::NONE, true)
|
(tx_permissions::NONE, true)
|
||||||
@ -138,8 +153,8 @@ impl TransactionFilter {
|
|||||||
permission_cache.insert((*parent_hash, sender), permissions);
|
permission_cache.insert((*parent_hash, sender), permissions);
|
||||||
}
|
}
|
||||||
trace!(target: "tx_filter",
|
trace!(target: "tx_filter",
|
||||||
"Given transaction data: sender: {:?} to: {:?} value: {}. Permissions required: {:X}, got: {:X}",
|
"Given transaction data: sender: {:?} to: {:?} value: {}, gas_price: {}. Permissions required: {:X}, got: {:X}",
|
||||||
sender, to, value, tx_type, permissions
|
sender, to, value, gas_price, tx_type, permissions
|
||||||
);
|
);
|
||||||
permissions & tx_type != 0
|
permissions & tx_type != 0
|
||||||
}
|
}
|
||||||
@ -171,7 +186,7 @@ mod test {
|
|||||||
|
|
||||||
/// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f
|
/// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f
|
||||||
#[test]
|
#[test]
|
||||||
fn transaction_filter() {
|
fn transaction_filter_ver_2() {
|
||||||
let spec_data = include_str!("../../res/tx_permission_tests/contract_ver_2_genesis.json");
|
let spec_data = include_str!("../../res/tx_permission_tests/contract_ver_2_genesis.json");
|
||||||
|
|
||||||
let db = test_helpers::new_db();
|
let db = test_helpers::new_db();
|
||||||
@ -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));
|
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
|
/// Contract code: https://gist.github.com/arkpar/38a87cb50165b7e683585eec71acb05a
|
||||||
#[test]
|
#[test]
|
||||||
fn transaction_filter_deprecated() {
|
fn transaction_filter_deprecated() {
|
||||||
|
60
ethcore/res/tx_permission_tests/contract_ver_3.sol
Normal file
60
ethcore/res/tx_permission_tests/contract_ver_3.sol
Normal file
@ -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
ethcore/res/tx_permission_tests/contract_ver_3_genesis.json
Normal file
44
ethcore/res/tx_permission_tests/contract_ver_3_genesis.json
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user