Add TxPermission v4 (for EIP-1559)

This commit is contained in:
POA 2021-04-20 12:51:40 +03:00
parent 470f4ab866
commit 45be6b6c64
5 changed files with 452 additions and 336 deletions

View File

@ -1,340 +1,11 @@
pragma solidity 0.5.10;
import "./interfaces/ICertifier.sol";
import "./interfaces/IRandomAuRa.sol";
import "./interfaces/IStakingAuRa.sol";
import "./interfaces/ITxPermission.sol";
import "./interfaces/IValidatorSetAuRa.sol";
import "./upgradeability/UpgradeableOwned.sol";
import "./base/TxPermissionV3.sol";
//import "./base/TxPermissionV4.sol";
/// @dev Controls the use of zero gas price by validators in service transactions,
/// protecting the network against "transaction spamming" by malicious validators.
/// The protection logic is declared in the `allowedTxTypes` function.
contract TxPermission is UpgradeableOwned, ITxPermission {
contract TxPermission is TxPermissionV3 {}
// =============================================== Storage ========================================================
// WARNING: since this contract is upgradeable, do not remove
// existing storage variables, do not change their order,
// and do not change their types!
address[] internal _allowedSenders;
/// @dev The address of the `Certifier` contract.
ICertifier public certifierContract;
/// @dev A boolean flag indicating whether the specified address is allowed
/// to initiate transactions of any type. Used by the `allowedTxTypes` getter.
/// See also the `addAllowedSender` and `removeAllowedSender` functions.
mapping(address => bool) public isSenderAllowed;
/// @dev The address of the `ValidatorSetAuRa` contract.
IValidatorSetAuRa public validatorSetContract;
mapping(address => uint256) internal _deployerInputLengthLimit;
/// @dev The min gas price allowed for a specified sender, in Wei.
/// Zero means default min gas price.
mapping(address => uint256) public senderMinGasPrice;
// ============================================== Constants =======================================================
/// @dev A constant that defines a regular block gas limit.
/// Used by the `blockGasLimit` public getter.
uint256 public constant BLOCK_GAS_LIMIT = 12500000;
/// @dev A constant that defines a reduced block gas limit.
/// Used by the `blockGasLimit` public getter.
uint256 public constant BLOCK_GAS_LIMIT_REDUCED = 4000000;
// ================================================ Events ========================================================
/// @dev Emitted by the `setDeployerInputLengthLimit` function.
/// @param deployer The address of a contract deployer.
/// @param limit The maximum number of bytes in `input` field of deployment transaction.
event DeployerInputLengthLimitSet(address indexed deployer, uint256 limit);
/// @dev Emitted by the `setSenderMinGasPrice` function.
/// @param sender The address of transaction sender.
/// @param minGasPrice The min gas price in Wei. Zero to reset to default min gas price.
event SenderMinGasPriceSet(address indexed sender, uint256 minGasPrice);
// ============================================== Modifiers =======================================================
/// @dev Ensures the `initialize` function was called before.
modifier onlyInitialized {
require(isInitialized());
_;
}
// =============================================== Setters ========================================================
/// @dev Initializes the contract at network startup.
/// Can only be called by the constructor of the `InitializerAuRa` contract or owner.
/// @param _allowed The addresses for which transactions of any type must be allowed.
/// See the `allowedTxTypes` getter.
/// @param _certifier The address of the `Certifier` contract. It is used by `allowedTxTypes` function to know
/// whether some address is explicitly allowed to use zero gas price.
/// @param _validatorSet The address of the `ValidatorSetAuRa` contract.
function initialize(
address[] calldata _allowed,
address _certifier,
address _validatorSet
) external {
require(block.number == 0 || msg.sender == _admin());
require(!isInitialized());
require(_certifier != address(0));
require(_validatorSet != address(0));
for (uint256 i = 0; i < _allowed.length; i++) {
_addAllowedSender(_allowed[i]);
}
certifierContract = ICertifier(_certifier);
validatorSetContract = IValidatorSetAuRa(_validatorSet);
}
/// @dev Adds the address for which transactions of any type must be allowed.
/// Can only be called by the `owner`. See also the `allowedTxTypes` getter.
/// @param _sender The address for which transactions of any type must be allowed.
function addAllowedSender(address _sender) public onlyOwner onlyInitialized {
_addAllowedSender(_sender);
}
/// @dev Removes the specified address from the array of addresses allowed
/// to initiate transactions of any type. Can only be called by the `owner`.
/// See also the `addAllowedSender` function and `allowedSenders` getter.
/// @param _sender The removed address.
function removeAllowedSender(address _sender) public onlyOwner onlyInitialized {
require(isSenderAllowed[_sender]);
uint256 allowedSendersLength = _allowedSenders.length;
for (uint256 i = 0; i < allowedSendersLength; i++) {
if (_sender == _allowedSenders[i]) {
_allowedSenders[i] = _allowedSenders[allowedSendersLength - 1];
_allowedSenders.length--;
break;
}
}
isSenderAllowed[_sender] = false;
}
/// @dev Sets the limit of `input` transaction field length in bytes
/// for contract deployment transaction made by the specified deployer.
/// @param _deployer The address of a contract deployer.
/// @param _limit The maximum number of bytes in `input` field of deployment transaction.
/// Set it to zero to reset to default 24Kb limit defined by EIP 170.
function setDeployerInputLengthLimit(address _deployer, uint256 _limit) public onlyOwner onlyInitialized {
_deployerInputLengthLimit[_deployer] = _limit;
emit DeployerInputLengthLimitSet(_deployer, _limit);
}
/// @dev Sets the min gas price allowed for a specified sender.
/// @param _sender The address of transaction sender.
/// @param _minGasPrice The min gas price in Wei. Zero to reset to default min gas price.
function setSenderMinGasPrice(address _sender, uint256 _minGasPrice) public onlyOwner onlyInitialized {
senderMinGasPrice[_sender] = _minGasPrice;
emit SenderMinGasPriceSet(_sender, _minGasPrice);
}
// =============================================== Getters ========================================================
/// @dev Returns the contract's name recognizable by node's engine.
function contractName() public pure returns(string memory) {
return "TX_PERMISSION_CONTRACT";
}
/// @dev Returns the contract name hash needed for node's engine.
function contractNameHash() public pure returns(bytes32) {
return keccak256(abi.encodePacked(contractName()));
}
/// @dev Returns the contract's version number needed for node's engine.
function contractVersion() public pure returns(uint256) {
return 3;
}
/// @dev Returns the list of addresses allowed to initiate transactions of any type.
/// For these addresses the `allowedTxTypes` getter always returns the `ALL` bit mask
/// (see https://openethereum.github.io/Permissioning.html#how-it-works-1).
function allowedSenders() public view returns(address[] memory) {
return _allowedSenders;
}
/// @dev Defines the allowed transaction types which may be initiated by the specified sender with
/// the specified gas price and data. Used by node's engine each time a transaction is about to be
/// included into a block. See https://openethereum.github.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 (isSenderAllowed[_sender]) {
// Let the `_sender` initiate any transaction if the `_sender` is in the `allowedSenders` list
return (ALL, false);
}
if (_to == address(0) && _data.length > deployerInputLengthLimit(_sender)) {
// Don't let to deploy too big contracts
return (NONE, false);
}
// Get the called function's signature
bytes4 signature = bytes4(0);
assembly {
signature := shl(224, mload(add(_data, 4)))
}
if (_to == validatorSetContract.randomContract()) {
if (signature == COMMIT_HASH_SIGNATURE && _data.length > 4+32) {
bytes32 numberHash;
assembly { numberHash := mload(add(_data, 36)) }
return (IRandomAuRa(_to).commitHashCallable(_sender, numberHash) ? CALL : NONE, false);
} else if (
(signature == REVEAL_NUMBER_SIGNATURE || signature == REVEAL_SECRET_SIGNATURE) &&
_data.length == 4+32
) {
uint256 num;
assembly { num := mload(add(_data, 36)) }
return (IRandomAuRa(_to).revealNumberCallable(_sender, num) ? CALL : NONE, false);
} else {
return (NONE, false);
}
}
if (_to == address(validatorSetContract)) {
// The rules for the ValidatorSetAuRa contract
if (signature == EMIT_INITIATE_CHANGE_SIGNATURE) {
// The `emitInitiateChange()` can be called by anyone
// if `emitInitiateChangeCallable()` returns `true`
return (validatorSetContract.emitInitiateChangeCallable() ? CALL : NONE, false);
} else if (signature == REPORT_MALICIOUS_SIGNATURE && _data.length >= 4+64) {
address maliciousMiningAddress;
uint256 blockNumber;
assembly {
maliciousMiningAddress := mload(add(_data, 36))
blockNumber := mload(add(_data, 68))
}
// The `reportMalicious()` can only be called by the validator's mining address
// when the calling is allowed
(bool callable,) = validatorSetContract.reportMaliciousCallable(
_sender, maliciousMiningAddress, blockNumber
);
return (callable ? CALL : NONE, false);
} else if (_gasPrice > 0) {
// The other functions of ValidatorSetAuRa contract can be called
// by anyone except validators' mining addresses if gasPrice is not zero
return (validatorSetContract.isValidator(_sender) ? NONE : CALL, false);
}
}
if (validatorSetContract.isValidator(_sender) && _gasPrice > 0) {
// Let the validator's mining address send their accumulated tx fees to some wallet
return (_sender.balance > 0 ? BASIC : NONE, false);
}
if (validatorSetContract.isValidator(_to)) {
// Validator's mining address can't receive any coins
return (NONE, false);
}
// Don't let the `_sender` use a zero gas price, if it is not explicitly allowed by the `Certifier` contract
if (_gasPrice == 0) {
return (certifierContract.certifiedExplicitly(_sender) ? ALL : NONE, false);
}
// Disallow invalid gas price for the specified sender
if (_gasPrice < senderMinGasPrice[_sender]) {
return (NONE, false);
}
// In other cases let the `_sender` create any transaction with non-zero gas price
return (ALL, false);
}
/// @dev Returns the current block gas limit which depends on the stage of the current
/// staking epoch: the block gas limit is temporarily reduced for the latest block of the epoch.
function blockGasLimit() public view returns(uint256) {
address stakingContract = validatorSetContract.stakingContract();
uint256 stakingEpochEndBlock = IStakingAuRa(stakingContract).stakingEpochEndBlock();
if (block.number == stakingEpochEndBlock - 1 || block.number == stakingEpochEndBlock) {
return BLOCK_GAS_LIMIT_REDUCED;
}
return BLOCK_GAS_LIMIT;
}
/// @dev Returns the limit of `input` transaction field length in bytes
/// for contract deployment transaction made by the specified deployer.
/// @param _deployer The address of a contract deployer.
function deployerInputLengthLimit(address _deployer) public view returns(uint256) {
uint256 limit = _deployerInputLengthLimit[_deployer];
if (limit != 0) {
return limit;
} else {
return 30720; // default EIP 170 limit (24 Kb + overhead)
}
}
/// @dev Returns a boolean flag indicating if the `initialize` function has been called.
function isInitialized() public view returns(bool) {
return validatorSetContract != IValidatorSetAuRa(0);
}
// ============================================== Internal ========================================================
// Allowed transaction types mask
uint32 internal constant NONE = 0;
uint32 internal constant ALL = 0xffffffff;
uint32 internal constant BASIC = 0x01;
uint32 internal constant CALL = 0x02;
uint32 internal constant CREATE = 0x04;
uint32 internal constant PRIVATE = 0x08;
// Function signatures
// bytes4(keccak256("commitHash(bytes32,bytes)"))
bytes4 internal constant COMMIT_HASH_SIGNATURE = 0x0b61ba85;
// bytes4(keccak256("emitInitiateChange()"))
bytes4 internal constant EMIT_INITIATE_CHANGE_SIGNATURE = 0x93b4e25e;
// bytes4(keccak256("reportMalicious(address,uint256,bytes)"))
bytes4 internal constant REPORT_MALICIOUS_SIGNATURE = 0xc476dd40;
// bytes4(keccak256("revealSecret(uint256)"))
bytes4 internal constant REVEAL_SECRET_SIGNATURE = 0x98df67c6;
// bytes4(keccak256("revealNumber(uint256)"))
bytes4 internal constant REVEAL_NUMBER_SIGNATURE = 0xfe7d567d;
/// @dev An internal function used by the `addAllowedSender` and `initialize` functions.
/// @param _sender The address for which transactions of any type must be allowed.
function _addAllowedSender(address _sender) internal {
require(!isSenderAllowed[_sender]);
require(_sender != address(0));
_allowedSenders.push(_sender);
isSenderAllowed[_sender] = true;
}
}
// Uncomment this line and comment out the above one
// to activate TxPermission v4:
// contract TxPermission is TxPermissionV4 {}

View File

@ -0,0 +1,344 @@
pragma solidity 0.5.10;
import "../interfaces/ICertifier.sol";
import "../interfaces/IRandomAuRa.sol";
import "../interfaces/IStakingAuRa.sol";
import "../interfaces/ITxPermission.sol";
import "../interfaces/IValidatorSetAuRa.sol";
import "../upgradeability/UpgradeableOwned.sol";
/// @dev Controls the use of zero gas price by validators in service transactions,
/// protecting the network against "transaction spamming" by malicious validators.
/// The protection logic is declared in the `allowedTxTypes` function.
contract TxPermissionBase is UpgradeableOwned, ITxPermission {
// =============================================== Storage ========================================================
// WARNING: since this contract is upgradeable, do not remove
// existing storage variables, do not change their order,
// and do not change their types!
address[] internal _allowedSenders;
/// @dev The address of the `Certifier` contract.
ICertifier public certifierContract;
/// @dev A boolean flag indicating whether the specified address is allowed
/// to initiate transactions of any type. Used by the `allowedTxTypes` getter.
/// See also the `addAllowedSender` and `removeAllowedSender` functions.
mapping(address => bool) public isSenderAllowed;
/// @dev The address of the `ValidatorSetAuRa` contract.
IValidatorSetAuRa public validatorSetContract;
mapping(address => uint256) internal _deployerInputLengthLimit;
/// @dev The min gas price allowed for a specified sender, in Wei.
/// Zero means default min gas price.
mapping(address => uint256) public senderMinGasPrice;
// ============================================== Constants =======================================================
/// @dev A constant that defines a regular block gas limit.
/// Used by the `blockGasLimit` public getter.
uint256 public constant BLOCK_GAS_LIMIT = 12500000;
/// @dev A constant that defines a reduced block gas limit.
/// Used by the `blockGasLimit` public getter.
uint256 public constant BLOCK_GAS_LIMIT_REDUCED = 4000000;
// ================================================ Events ========================================================
/// @dev Emitted by the `setDeployerInputLengthLimit` function.
/// @param deployer The address of a contract deployer.
/// @param limit The maximum number of bytes in `input` field of deployment transaction.
event DeployerInputLengthLimitSet(address indexed deployer, uint256 limit);
/// @dev Emitted by the `setSenderMinGasPrice` function.
/// @param sender The address of transaction sender.
/// @param minGasPrice The min gas price in Wei. Zero to reset to default min gas price.
event SenderMinGasPriceSet(address indexed sender, uint256 minGasPrice);
// ============================================== Modifiers =======================================================
/// @dev Ensures the `initialize` function was called before.
modifier onlyInitialized {
require(isInitialized());
_;
}
// =============================================== Setters ========================================================
/// @dev Initializes the contract at network startup.
/// Can only be called by the constructor of the `InitializerAuRa` contract or owner.
/// @param _allowed The addresses for which transactions of any type must be allowed.
/// See the `allowedTxTypes` getter.
/// @param _certifier The address of the `Certifier` contract. It is used by `allowedTxTypes` function to know
/// whether some address is explicitly allowed to use zero gas price.
/// @param _validatorSet The address of the `ValidatorSetAuRa` contract.
function initialize(
address[] calldata _allowed,
address _certifier,
address _validatorSet
) external {
require(block.number == 0 || msg.sender == _admin());
require(!isInitialized());
require(_certifier != address(0));
require(_validatorSet != address(0));
for (uint256 i = 0; i < _allowed.length; i++) {
_addAllowedSender(_allowed[i]);
}
certifierContract = ICertifier(_certifier);
validatorSetContract = IValidatorSetAuRa(_validatorSet);
}
/// @dev Adds the address for which transactions of any type must be allowed.
/// Can only be called by the `owner`. See also the `allowedTxTypes` getter.
/// @param _sender The address for which transactions of any type must be allowed.
function addAllowedSender(address _sender) public onlyOwner onlyInitialized {
_addAllowedSender(_sender);
}
/// @dev Removes the specified address from the array of addresses allowed
/// to initiate transactions of any type. Can only be called by the `owner`.
/// See also the `addAllowedSender` function and `allowedSenders` getter.
/// @param _sender The removed address.
function removeAllowedSender(address _sender) public onlyOwner onlyInitialized {
require(isSenderAllowed[_sender]);
uint256 allowedSendersLength = _allowedSenders.length;
for (uint256 i = 0; i < allowedSendersLength; i++) {
if (_sender == _allowedSenders[i]) {
_allowedSenders[i] = _allowedSenders[allowedSendersLength - 1];
_allowedSenders.length--;
break;
}
}
isSenderAllowed[_sender] = false;
}
/// @dev Sets the limit of `input` transaction field length in bytes
/// for contract deployment transaction made by the specified deployer.
/// @param _deployer The address of a contract deployer.
/// @param _limit The maximum number of bytes in `input` field of deployment transaction.
/// Set it to zero to reset to default 24Kb limit defined by EIP 170.
function setDeployerInputLengthLimit(address _deployer, uint256 _limit) public onlyOwner onlyInitialized {
_deployerInputLengthLimit[_deployer] = _limit;
emit DeployerInputLengthLimitSet(_deployer, _limit);
}
/// @dev Sets the min gas price allowed for a specified sender.
/// @param _sender The address of transaction sender.
/// @param _minGasPrice The min gas price in Wei. Zero to reset to default min gas price.
function setSenderMinGasPrice(address _sender, uint256 _minGasPrice) public onlyOwner onlyInitialized {
senderMinGasPrice[_sender] = _minGasPrice;
emit SenderMinGasPriceSet(_sender, _minGasPrice);
}
// =============================================== Getters ========================================================
/// @dev Returns the contract's name recognizable by node's engine.
function contractName() public pure returns(string memory) {
return "TX_PERMISSION_CONTRACT";
}
/// @dev Returns the contract name hash needed for node's engine.
function contractNameHash() public pure returns(bytes32) {
return keccak256(abi.encodePacked(contractName()));
}
/// @dev Returns the contract's version number needed for node's engine.
function contractVersion() public pure returns(uint256);
/// @dev Returns the list of addresses allowed to initiate transactions of any type.
/// For these addresses the `allowedTxTypes` getter always returns the `ALL` bit mask
/// (see https://openethereum.github.io/Permissioning.html#how-it-works-1).
function allowedSenders() public view returns(address[] memory) {
return _allowedSenders;
}
/// @dev Returns the current block gas limit which depends on the stage of the current
/// staking epoch: the block gas limit is temporarily reduced for the latest block of the epoch.
function blockGasLimit() public view returns(uint256) {
address stakingContract = validatorSetContract.stakingContract();
uint256 stakingEpochEndBlock = IStakingAuRa(stakingContract).stakingEpochEndBlock();
if (block.number == stakingEpochEndBlock - 1 || block.number == stakingEpochEndBlock) {
return BLOCK_GAS_LIMIT_REDUCED;
}
return BLOCK_GAS_LIMIT;
}
/// @dev Returns the limit of `input` transaction field length in bytes
/// for contract deployment transaction made by the specified deployer.
/// @param _deployer The address of a contract deployer.
function deployerInputLengthLimit(address _deployer) public view returns(uint256) {
uint256 limit = _deployerInputLengthLimit[_deployer];
if (limit != 0) {
return limit;
} else {
return 30720; // default EIP 170 limit (24 Kb + overhead)
}
}
/// @dev Returns a boolean flag indicating if the `initialize` function has been called.
function isInitialized() public view returns(bool) {
return validatorSetContract != IValidatorSetAuRa(0);
}
// ============================================== Internal ========================================================
// Allowed transaction types mask
uint32 internal constant NONE = 0;
uint32 internal constant ALL = 0xffffffff;
uint32 internal constant BASIC = 0x01;
uint32 internal constant CALL = 0x02;
uint32 internal constant CREATE = 0x04;
uint32 internal constant PRIVATE = 0x08;
// Function signatures
// bytes4(keccak256("commitHash(bytes32,bytes)"))
bytes4 internal constant COMMIT_HASH_SIGNATURE = 0x0b61ba85;
// bytes4(keccak256("emitInitiateChange()"))
bytes4 internal constant EMIT_INITIATE_CHANGE_SIGNATURE = 0x93b4e25e;
// bytes4(keccak256("reportMalicious(address,uint256,bytes)"))
bytes4 internal constant REPORT_MALICIOUS_SIGNATURE = 0xc476dd40;
// bytes4(keccak256("revealSecret(uint256)"))
bytes4 internal constant REVEAL_SECRET_SIGNATURE = 0x98df67c6;
// bytes4(keccak256("revealNumber(uint256)"))
bytes4 internal constant REVEAL_NUMBER_SIGNATURE = 0xfe7d567d;
/// @dev An internal function used by the `addAllowedSender` and `initialize` functions.
/// @param _sender The address for which transactions of any type must be allowed.
function _addAllowedSender(address _sender) internal {
require(!isSenderAllowed[_sender]);
require(_sender != address(0));
_allowedSenders.push(_sender);
isSenderAllowed[_sender] = true;
}
/// @dev Defines the allowed transaction types which may be initiated by the specified sender with
/// the specified gas price and data. Used by node's engine each time a transaction is about to be
/// included into a block. See https://openethereum.github.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 _maxFeePerGas The `maxFeePerGas` in Wei for EIP-1559 transaction, or gas price for a legacy transaction.
/// @param _maxInclusionFeePerGas The `maxInclusionFeePerGas` in Wei for EIP-1559 transaction.
/// Equals to gas price for a legacy transaction.
/// @param _gasLimit Gas limit 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 _maxFeePerGas, // equals to gasPrice for legacy transactions
uint256 _maxInclusionFeePerGas, // equals to gasPrice for legacy transactions
uint256 _gasLimit,
bytes memory _data
)
internal
view
returns(uint32 typesMask, bool cache)
{
if (isSenderAllowed[_sender]) {
// Let the `_sender` initiate any transaction if the `_sender` is in the `allowedSenders` list
return (ALL, false);
}
if (_to == address(0) && _data.length > deployerInputLengthLimit(_sender)) {
// Don't let to deploy too big contracts
return (NONE, false);
}
// Get the called function's signature
bytes4 signature = bytes4(0);
assembly {
signature := shl(224, mload(add(_data, 4)))
}
if (_to == validatorSetContract.randomContract()) {
if (signature == COMMIT_HASH_SIGNATURE && _data.length > 4+32) {
bytes32 numberHash;
assembly { numberHash := mload(add(_data, 36)) }
return (IRandomAuRa(_to).commitHashCallable(_sender, numberHash) ? CALL : NONE, false);
} else if (
(signature == REVEAL_NUMBER_SIGNATURE || signature == REVEAL_SECRET_SIGNATURE) &&
_data.length == 4+32
) {
uint256 num;
assembly { num := mload(add(_data, 36)) }
return (IRandomAuRa(_to).revealNumberCallable(_sender, num) ? CALL : NONE, false);
} else {
return (NONE, false);
}
}
if (_to == address(validatorSetContract)) {
// The rules for the ValidatorSetAuRa contract
if (signature == EMIT_INITIATE_CHANGE_SIGNATURE) {
// The `emitInitiateChange()` can be called by anyone
// if `emitInitiateChangeCallable()` returns `true`
return (validatorSetContract.emitInitiateChangeCallable() ? CALL : NONE, false);
} else if (signature == REPORT_MALICIOUS_SIGNATURE && _data.length >= 4+64) {
address maliciousMiningAddress;
uint256 blockNumber;
assembly {
maliciousMiningAddress := mload(add(_data, 36))
blockNumber := mload(add(_data, 68))
}
// The `reportMalicious()` can only be called by the validator's mining address
// when the calling is allowed
(bool callable,) = validatorSetContract.reportMaliciousCallable(
_sender, maliciousMiningAddress, blockNumber
);
return (callable ? CALL : NONE, false);
} else if (_maxFeePerGas > 0) {
// The other functions of ValidatorSetAuRa contract can be called
// by anyone except validators' mining addresses if gasPrice is not zero
return (validatorSetContract.isValidator(_sender) ? NONE : CALL, false);
}
}
if (validatorSetContract.isValidator(_sender) && _maxFeePerGas > 0) {
// Let the validator's mining address send their accumulated tx fees to some wallet
return (_sender.balance > 0 ? BASIC : NONE, false);
}
if (validatorSetContract.isValidator(_to)) {
// Validator's mining address can't receive any coins
return (NONE, false);
}
// Don't let the `_sender` use a zero gas price, if it is not explicitly allowed by the `Certifier` contract
if (_maxFeePerGas == 0) {
return (certifierContract.certifiedExplicitly(_sender) ? ALL : NONE, false);
}
// Disallow invalid gas price for the specified sender
if (_maxFeePerGas < senderMinGasPrice[_sender] || _maxInclusionFeePerGas < senderMinGasPrice[_sender]) {
return (NONE, false);
}
// In other cases let the `_sender` create any transaction with non-zero gas price
return (ALL, false);
}
}

View File

@ -0,0 +1,46 @@
pragma solidity 0.5.10;
import "./TxPermissionBase.sol";
contract TxPermissionV3 is TxPermissionBase {
// =============================================== Getters ========================================================
/// @dev Returns the contract's version number needed for node's engine.
function contractVersion() public pure 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 node's engine each time a transaction is about to be
/// included into a block. See https://openethereum.github.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. Must be equal to `maxFeePerGas` for EIP-1559 tx,
/// Equals to gas price for a legacy 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)
{
return _allowedTxTypes(_sender, _to, _value, _gasPrice, _gasPrice, 0, _data);
}
}

View File

@ -0,0 +1,50 @@
pragma solidity 0.5.10;
import "./TxPermissionBase.sol";
contract TxPermissionV4 is TxPermissionBase {
// =============================================== Getters ========================================================
/// @dev Returns the contract's version number needed for node's engine.
function contractVersion() public pure returns(uint256) {
return 4;
}
/// @dev Defines the allowed transaction types which may be initiated by the specified sender with
/// the specified gas price and data. Used by node's engine each time a transaction is about to be
/// included into a block. See https://openethereum.github.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 _maxFeePerGas The `maxFeePerGas` in Wei for EIP-1559 transaction, or gas price for a legacy transaction.
/// @param _maxInclusionFeePerGas The `maxInclusionFeePerGas` in Wei for EIP-1559 transaction.
/// Equals to gas price for a legacy transaction.
/// @param _gasLimit Gas limit 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 _maxFeePerGas, // equals to gasPrice for legacy transactions
uint256 _maxInclusionFeePerGas, // equals to gasPrice for legacy transactions
uint256 _gasLimit,
bytes memory _data
)
public
view
returns(uint32 typesMask, bool cache)
{
return _allowedTxTypes(_sender, _to, _value, _maxFeePerGas, _maxInclusionFeePerGas, _gasLimit, _data);
}
}

View File

@ -37,6 +37,10 @@ main();
// return web3.utils.keccak256(web3.eth.abi.encodeParameters(['uint256','uint256'], [key2, slot2]));
// }
function findMapLocation(slot, key) {
return web3.utils.keccak256(web3.eth.abi.encodeParameters(['uint256','uint256'], [key, slot]));
}
async function main() {
// web3.setProvider('https://rpc.xdaichain.com');
// console.log(await web3.eth.getStorageAt('0x42b20D645a372c2150962E6D4D3bB5d4F3231143', web3.utils.toBN(web3.utils.keccak256(web3.eth.abi.encodeParameters(['uint256'], ['0']))).add(new BN(0))));
@ -47,7 +51,8 @@ async function main() {
// return;
// web3.setProvider('https://rpc.xdaichain.com');
// const events = await ValidatorSet.getPastEvents('ReportedMalicious', {fromBlock: 15000000-50000, toBlock: 15000000});
// const events = await ValidatorSet.getPastEvents('ReportedMalicious', {fromBlock: 15000000, toBlock: 15530350});
// console.log(`events.length = ${events.length}`);
// for (let i = 0; i < events.length; i++) {
// console.log('ReportedMalicious:');
// console.log(` reportingValidator = ${events[i].returnValues.reportingValidator}`);