From d0132111c5eab3aab458092b71552e51ac57f3c0 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Wed, 14 Sep 2016 17:08:04 -0600 Subject: [PATCH 01/25] Initial commit for rewrite --- contracts/AccountingLib.sol | 125 ----- contracts/CallLib.sol | 622 ---------------------- contracts/Canary.sol | 99 ---- contracts/ClaimLib.sol | 27 + contracts/Digger.sol | 13 + contracts/Examples.sol | 106 ---- contracts/ExecutionLib.sol | 49 ++ contracts/GroveLib.sol | 2 +- contracts/PaymentLib.sol | 107 ++++ contracts/RequestFactoryInterface.sol | 7 + contracts/RequestLib.sol | 247 +++++++++ contracts/RequestMetaLib.sol | 23 + contracts/ScheduleLib.sol | 89 ++++ contracts/Scheduler.sol | 539 ------------------- contracts/SchedulerLib.sol | 217 -------- contracts/Testers.sol | 279 ---------- contracts/TransactionRequest.sol | 15 + contracts/TransactionRequestInterface.sol | 6 + 18 files changed, 584 insertions(+), 1988 deletions(-) delete mode 100644 contracts/AccountingLib.sol delete mode 100644 contracts/CallLib.sol delete mode 100644 contracts/Canary.sol create mode 100644 contracts/ClaimLib.sol create mode 100644 contracts/Digger.sol delete mode 100644 contracts/Examples.sol create mode 100644 contracts/ExecutionLib.sol create mode 100644 contracts/PaymentLib.sol create mode 100644 contracts/RequestFactoryInterface.sol create mode 100644 contracts/RequestLib.sol create mode 100644 contracts/RequestMetaLib.sol create mode 100644 contracts/ScheduleLib.sol delete mode 100644 contracts/Scheduler.sol delete mode 100644 contracts/SchedulerLib.sol delete mode 100644 contracts/Testers.sol create mode 100644 contracts/TransactionRequest.sol create mode 100644 contracts/TransactionRequestInterface.sol diff --git a/contracts/AccountingLib.sol b/contracts/AccountingLib.sol deleted file mode 100644 index be080d917..000000000 --- a/contracts/AccountingLib.sol +++ /dev/null @@ -1,125 +0,0 @@ -// Accounting v0.1 (not the same as the 0.1 release of this library) - -/// @title Accounting Lib - Accounting utilities -/// @author Piper Merriam - -library AccountingLib { - /* - * Address: 0x89efe605e9ecbe22849cd85d5449cc946c26f8f3 - */ - struct Bank { - mapping (address => uint) accountBalances; - } - - /// @dev Low level method for adding funds to an account. Protects against overflow. - /// @param self The Bank instance to operate on. - /// @param accountAddress The address of the account the funds should be added to. - /// @param value The amount that should be added to the account. - function addFunds(Bank storage self, address accountAddress, uint value) public { - if (self.accountBalances[accountAddress] + value < self.accountBalances[accountAddress]) { - // Prevent Overflow. - throw; - } - self.accountBalances[accountAddress] += value; - } - - event _Deposit(address indexed _from, address indexed accountAddress, uint value); - /// @dev Function wrapper around the _Deposit event so that it can be used by contracts. Can be used to log a deposit to an account. - /// @param _from The address that deposited the funds. - /// @param accountAddress The address of the account the funds were added to. - /// @param value The amount that was added to the account. - function Deposit(address _from, address accountAddress, uint value) public { - _Deposit(_from, accountAddress, value); - } - - - /// @dev Safe function for depositing funds. Returns boolean for whether the deposit was successful - /// @param self The Bank instance to operate on. - /// @param accountAddress The address of the account the funds should be added to. - /// @param value The amount that should be added to the account. - function deposit(Bank storage self, address accountAddress, uint value) public returns (bool) { - addFunds(self, accountAddress, value); - return true; - } - - event _Withdrawal(address indexed accountAddress, uint value); - - /// @dev Function wrapper around the _Withdrawal event so that it can be used by contracts. Can be used to log a withdrawl from an account. - /// @param accountAddress The address of the account the funds were withdrawn from. - /// @param value The amount that was withdrawn to the account. - function Withdrawal(address accountAddress, uint value) public { - _Withdrawal(accountAddress, value); - } - - event _InsufficientFunds(address indexed accountAddress, uint value, uint balance); - - /// @dev Function wrapper around the _InsufficientFunds event so that it can be used by contracts. Can be used to log a failed withdrawl from an account. - /// @param accountAddress The address of the account the funds were to be withdrawn from. - /// @param value The amount that was attempted to be withdrawn from the account. - /// @param balance The current balance of the account. - function InsufficientFunds(address accountAddress, uint value, uint balance) public { - _InsufficientFunds(accountAddress, value, balance); - } - - /// @dev Low level method for removing funds from an account. Protects against underflow. - /// @param self The Bank instance to operate on. - /// @param accountAddress The address of the account the funds should be deducted from. - /// @param value The amount that should be deducted from the account. - function deductFunds(Bank storage self, address accountAddress, uint value) public { - /* - * Helper function that should be used for any reduction of - * account funds. It has error checking to prevent - * underflowing the account balance which would be REALLY bad. - */ - if (value > self.accountBalances[accountAddress]) { - // Prevent Underflow. - throw; - } - self.accountBalances[accountAddress] -= value; - } - - /// @dev Safe function for withdrawing funds. Returns boolean for whether the deposit was successful as well as sending the amount in ether to the account address. - /// @param self The Bank instance to operate on. - /// @param accountAddress The address of the account the funds should be withdrawn from. - /// @param value The amount that should be withdrawn from the account. - function withdraw(Bank storage self, address accountAddress, uint value) public returns (bool) { - /* - * Public API for withdrawing funds. - */ - if (self.accountBalances[accountAddress] >= value) { - deductFunds(self, accountAddress, value); - if (!accountAddress.send(value)) { - // Potentially sending money to a contract that - // has a fallback function. So instead, try - // tranferring the funds with the call api. - if (!accountAddress.call.value(value)()) { - // Revert the entire transaction. No - // need to destroy the funds. - throw; - } - } - return true; - } - return false; - } - - uint constant DEFAULT_SEND_GAS = 100000; - - function sendRobust(address toAddress, uint value) public returns (bool) { - if (msg.gas < DEFAULT_SEND_GAS) { - return sendRobust(toAddress, value, msg.gas); - } - return sendRobust(toAddress, value, DEFAULT_SEND_GAS); - } - - function sendRobust(address toAddress, uint value, uint maxGas) public returns (bool) { - if (value > 0 && !toAddress.send(value)) { - // Potentially sending money to a contract that - // has a fallback function. So instead, try - // tranferring the funds with the call api. - if (!toAddress.call.gas(maxGas).value(value)()) { - return false; - } - } - return true; - } -} diff --git a/contracts/CallLib.sol b/contracts/CallLib.sol deleted file mode 100644 index 3563b1be7..000000000 --- a/contracts/CallLib.sol +++ /dev/null @@ -1,622 +0,0 @@ -import "contracts/AccountingLib.sol"; - - -library CallLib { - /* - * Address: 0x1deeda36e15ec9e80f3d7414d67a4803ae45fc80 - */ - struct Call { - address contractAddress; - bytes4 abiSignature; - bytes callData; - uint callValue; - uint anchorGasPrice; - uint requiredGas; - uint16 requiredStackDepth; - - address claimer; - uint claimAmount; - uint claimerDeposit; - - bool wasSuccessful; - bool wasCalled; - bool isCancelled; - } - - enum State { - Pending, - Unclaimed, - Claimed, - Frozen, - Callable, - Executed, - Cancelled, - Missed - } - - function state(Call storage self) constant returns (State) { - if (self.isCancelled) return State.Cancelled; - if (self.wasCalled) return State.Executed; - - var call = FutureBlockCall(this); - - if (block.number + CLAIM_GROWTH_WINDOW + MAXIMUM_CLAIM_WINDOW + BEFORE_CALL_FREEZE_WINDOW < call.targetBlock()) return State.Pending; - if (block.number + BEFORE_CALL_FREEZE_WINDOW < call.targetBlock()) { - if (self.claimer == 0x0) { - return State.Unclaimed; - } - else { - return State.Claimed; - } - } - if (block.number < call.targetBlock()) return State.Frozen; - if (block.number < call.targetBlock() + call.gracePeriod()) return State.Callable; - return State.Missed; - } - - // The number of blocks that each caller in the pool has to complete their - // call. - uint constant CALL_WINDOW_SIZE = 16; - - address constant creator = 0xd3cda913deb6f67967b99d67acdfa1712c293601; - - function extractCallData(Call storage call, bytes data) public { - call.callData.length = data.length - 4; - if (data.length > 4) { - for (uint i = 0; i < call.callData.length; i++) { - call.callData[i] = data[i + 4]; - } - } - } - - uint constant GAS_PER_DEPTH = 700; - - function sendSafe(address to_address, uint value) public returns (uint) { - if (value > address(this).balance) { - value = address(this).balance; - } - if (value > 0) { - AccountingLib.sendRobust(to_address, value); - return value; - } - return 0; - } - - function getGasScalar(uint base_gas_price, uint gas_price) constant returns (uint) { - /* - * Return a number between 0 - 200 to scale the donation based on the - * gas price set for the calling transaction as compared to the gas - * price of the scheduling transaction. - * - * - number approaches zero as the transaction gas price goes - * above the gas price recorded when the call was scheduled. - * - * - the number approaches 200 as the transaction gas price - * drops under the price recorded when the call was scheduled. - * - * This encourages lower gas costs as the lower the gas price - * for the executing transaction, the higher the payout to the - * caller. - */ - if (gas_price > base_gas_price) { - return 100 * base_gas_price / gas_price; - } - else { - return 200 - 100 * base_gas_price / (2 * base_gas_price - gas_price); - } - } - - event CallExecuted(address indexed executor, uint gasCost, uint payment, uint donation, bool success); - - bytes4 constant EMPTY_SIGNATURE = 0x0000; - - event CallAborted(address executor, bytes32 reason); - - function execute(Call storage self, - uint start_gas, - address executor, - uint overhead, - uint extraGas) public { - FutureCall call = FutureCall(this); - - // Mark the call has having been executed. - self.wasCalled = true; - - // Make the call - if (self.abiSignature == EMPTY_SIGNATURE && self.callData.length == 0) { - self.wasSuccessful = self.contractAddress.call.value(self.callValue).gas(msg.gas - overhead)(); - } - else if (self.abiSignature == EMPTY_SIGNATURE) { - self.wasSuccessful = self.contractAddress.call.value(self.callValue).gas(msg.gas - overhead)(self.callData); - } - else if (self.callData.length == 0) { - self.wasSuccessful = self.contractAddress.call.value(self.callValue).gas(msg.gas - overhead)(self.abiSignature); - } - else { - self.wasSuccessful = self.contractAddress.call.value(self.callValue).gas(msg.gas - overhead)(self.abiSignature, self.callData); - } - - call.origin().call(bytes4(sha3("updateDefaultPayment()"))); - - // Compute the scalar (0 - 200) for the donation. - uint gasScalar = getGasScalar(self.anchorGasPrice, tx.gasprice); - - uint basePayment; - if (self.claimer == executor) { - basePayment = self.claimAmount; - } - else { - basePayment = call.basePayment(); - } - uint payment = self.claimerDeposit + basePayment * gasScalar / 100; - uint donation = call.baseDonation() * gasScalar / 100; - - // zero out the deposit - self.claimerDeposit = 0; - - // Log how much gas this call used. EXTRA_CALL_GAS is a fixed - // amount that represents the gas usage of the commands that - // happen after this line. - uint gasCost = tx.gasprice * (start_gas - msg.gas + extraGas); - - // Now we need to pay the executor as well as keep donation. - payment = sendSafe(executor, payment + gasCost); - donation = sendSafe(creator, donation); - - // Log execution - CallExecuted(executor, gasCost, payment, donation, self.wasSuccessful); - } - - event Cancelled(address indexed cancelled_by); - - function cancel(Call storage self, address sender) public { - Cancelled(sender); - if (self.claimerDeposit >= 0) { - sendSafe(self.claimer, self.claimerDeposit); - } - var call = FutureCall(this); - sendSafe(call.schedulerAddress(), address(this).balance); - self.isCancelled = true; - } - - /* - * Bid API - * - Gas costs for this transaction are not covered so it - * must be up to the call executors to ensure that their actions - * remain profitable. Any form of bidding war is likely to eat into - * profits. - */ - event Claimed(address executor, uint claimAmount); - - // The duration (in blocks) during which the maximum claim will slowly rise - // towards the basePayment amount. - uint constant CLAIM_GROWTH_WINDOW = 240; - - // The duration (in blocks) after the CLAIM_WINDOW that claiming will - // remain open. - uint constant MAXIMUM_CLAIM_WINDOW = 15; - - // The duration (in blocks) before the call's target block during which - // all actions are frozen. This includes claiming, cancellation, - // registering call data. - uint constant BEFORE_CALL_FREEZE_WINDOW = 10; - - /* - * The maximum allowed claim amount slowly rises across a window of - * blocks CLAIM_GROWTH_WINDOW prior to the call. No claimer is - * allowed to claim above this value. This is intended to prevent - * bidding wars in that each caller should know how much they are - * willing to execute a call for. - */ - function getClaimAmountForBlock(uint block_number) constant returns (uint) { - /* - * [--growth-window--][--max-window--][--freeze-window--] - * - * - */ - var call = FutureBlockCall(this); - - uint cutoff = call.targetBlock() - BEFORE_CALL_FREEZE_WINDOW; - - // claim window has closed - if (block_number > cutoff) return call.basePayment(); - - cutoff -= MAXIMUM_CLAIM_WINDOW; - - // in the maximum claim window. - if (block_number > cutoff) return call.basePayment(); - - cutoff -= CLAIM_GROWTH_WINDOW; - - if (block_number > cutoff) { - uint x = block_number - cutoff; - - return call.basePayment() * x / CLAIM_GROWTH_WINDOW; - } - - return 0; - } - - function lastClaimBlock() constant returns (uint) { - var call = FutureBlockCall(this); - return call.targetBlock() - BEFORE_CALL_FREEZE_WINDOW; - } - - function maxClaimBlock() constant returns (uint) { - return lastClaimBlock() - MAXIMUM_CLAIM_WINDOW; - } - - function firstClaimBlock() constant returns (uint) { - return maxClaimBlock() - CLAIM_GROWTH_WINDOW; - } - - function claim(Call storage self, address executor, uint deposit_amount, uint basePayment) public returns (bool) { - /* - * Warning! this does not check whether the function is already - * claimed or whether we are within the claim window. This must be - * done at the contract level. - */ - // Insufficient Deposit - if (deposit_amount < 2 * basePayment) return false; - - self.claimAmount = getClaimAmountForBlock(block.number); - self.claimer = executor; - self.claimerDeposit = deposit_amount; - - // Log the claim. - Claimed(executor, self.claimAmount); - } - - function checkExecutionAuthorization(Call storage self, address executor, uint block_number) returns (bool) { - /* - * Check whether the given `executor` is authorized. - */ - var call = FutureBlockCall(this); - - uint targetBlock = call.targetBlock(); - - // Invalid, not in call window. - if (block_number < targetBlock || block_number > targetBlock + call.gracePeriod()) throw; - - // Within the reserved call window so if there is a claimer, the - // executor must be the claimdor. - if (block_number - targetBlock < CALL_WINDOW_SIZE) { - return (self.claimer == 0x0 || self.claimer == executor); - } - - // Must be in the free-for-all period. - return true; - } - - function isCancellable(Call storage self, address caller) returns (bool) { - var _state = state(self); - var call = FutureBlockCall(this); - - if (_state == State.Pending && caller == call.schedulerAddress()) { - return true; - } - - if (_state == State.Missed) return true; - - return false; - } - - function beforeExecuteForFutureBlockCall(Call storage self, address executor, uint startGas) returns (bool) { - bytes32 reason; - - var call = FutureBlockCall(this); - - if (startGas < self.requiredGas) { - // The executor has not provided sufficient gas - reason = "NOT_ENOUGH_GAS"; - } - else if (self.wasCalled) { - // Not being called within call window. - reason = "ALREADY_CALLED"; - } - else if (block.number < call.targetBlock() || block.number > call.targetBlock() + call.gracePeriod()) { - // Not being called within call window. - reason = "NOT_IN_CALL_WINDOW"; - } - else if (!checkExecutionAuthorization(self, executor, block.number)) { - // Someone has claimed this call and they currently have exclusive - // rights to execute it. - reason = "NOT_AUTHORIZED"; - } - else if (self.requiredStackDepth > 0 && executor != tx.origin && !call.checkDepth(self.requiredStackDepth)) { - reason = "STACK_TOO_DEEP"; - } - - if (reason != 0x0) { - CallAborted(executor, reason); - return false; - } - - return true; - } -} - - -contract FutureCall { - // The author (Piper Merriam) address. - address constant creator = 0xd3cda913deb6f67967b99d67acdfa1712c293601; - - address public schedulerAddress; - - uint public basePayment; - uint public baseDonation; - - CallLib.Call call; - - address public origin; - - function FutureCall(address _schedulerAddress, - uint _requiredGas, - uint16 _requiredStackDepth, - address _contractAddress, - bytes4 _abiSignature, - bytes _callData, - uint _callValue, - uint _basePayment, - uint _baseDonation) - { - origin = msg.sender; - schedulerAddress = _schedulerAddress; - - basePayment = _basePayment; - baseDonation = _baseDonation; - - call.requiredGas = _requiredGas; - call.requiredStackDepth = _requiredStackDepth; - call.anchorGasPrice = tx.gasprice; - call.contractAddress = _contractAddress; - call.abiSignature = _abiSignature; - call.callData = _callData; - call.callValue = _callValue; - } - - enum State { - Pending, - Unclaimed, - Claimed, - Frozen, - Callable, - Executed, - Cancelled, - Missed - } - - modifier in_state(State _state) { if (state() == _state) _ } - - function state() constant returns (State) { - return State(CallLib.state(call)); - } - - /* - * API for FutureXXXXCalls to implement. - */ - function beforeExecute(address executor, uint startGas) public returns (bool); - function afterExecute(address executor) internal; - function getOverhead() constant returns (uint); - function getExtraGas() constant returns (uint); - - /* - * Data accessor functions. - */ - function contractAddress() constant returns (address) { - return call.contractAddress; - } - - function abiSignature() constant returns (bytes4) { - return call.abiSignature; - } - - function callData() constant returns (bytes) { - return call.callData; - } - - function callValue() constant returns (uint) { - return call.callValue; - } - - function anchorGasPrice() constant returns (uint) { - return call.anchorGasPrice; - } - - function requiredGas() constant returns (uint) { - return call.requiredGas; - } - - function requiredStackDepth() constant returns (uint16) { - return call.requiredStackDepth; - } - - function claimer() constant returns (address) { - return call.claimer; - } - - function claimAmount() constant returns (uint) { - return call.claimAmount; - } - - function claimerDeposit() constant returns (uint) { - return call.claimerDeposit; - } - - function wasSuccessful() constant returns (bool) { - return call.wasSuccessful; - } - - function wasCalled() constant returns (bool) { - return call.wasCalled; - } - - function isCancelled() constant returns (bool) { - return call.isCancelled; - } - - /* - * Claim API helpers - */ - function getClaimAmountForBlock() constant returns (uint) { - return CallLib.getClaimAmountForBlock(block.number); - } - - function getClaimAmountForBlock(uint block_number) constant returns (uint) { - return CallLib.getClaimAmountForBlock(block_number); - } - - /* - * Call Data registration - */ - function () returns (bool) { - /* - * Fallback to allow sending funds to this contract. - * (also allows registering raw call data) - */ - // only scheduler can register call data. - if (msg.sender != schedulerAddress) return false; - // cannot write over call data - if (call.callData.length > 0) return false; - - var _state = state(); - if (_state != State.Pending && _state != State.Unclaimed && _state != State.Claimed) return false; - - call.callData = msg.data; - return true; - } - - function registerData() public returns (bool) { - // only scheduler can register call data. - if (msg.sender != schedulerAddress) return false; - // cannot write over call data - if (call.callData.length > 0) return false; - - var _state = state(); - if (_state != State.Pending && _state != State.Unclaimed && _state != State.Claimed) return false; - - CallLib.extractCallData(call, msg.data); - } - - function firstClaimBlock() constant returns (uint) { - return CallLib.firstClaimBlock(); - } - - function maxClaimBlock() constant returns (uint) { - return CallLib.maxClaimBlock(); - } - - function lastClaimBlock() constant returns (uint) { - return CallLib.lastClaimBlock(); - } - - function claim() public in_state(State.Unclaimed) returns (bool) { - bool success = CallLib.claim(call, msg.sender, msg.value, basePayment); - if (!success) { - if (!AccountingLib.sendRobust(msg.sender, msg.value)) throw; - } - return success; - } - - function checkExecutionAuthorization(address executor, uint block_number) constant returns (bool) { - return CallLib.checkExecutionAuthorization(call, executor, block_number); - } - - function sendSafe(address to_address, uint value) internal { - CallLib.sendSafe(to_address, value); - } - - function execute() public in_state(State.Callable) { - uint start_gas = msg.gas; - - // Check that the call should be executed now. - if (!beforeExecute(msg.sender, start_gas)) return; - - // Execute the call - CallLib.execute(call, start_gas, msg.sender, getOverhead(), getExtraGas()); - - // Any logic that needs to occur after the call has executed should - // go in afterExecute - afterExecute(msg.sender); - } -} - - -contract FutureBlockCall is FutureCall { - uint public targetBlock; - uint8 public gracePeriod; - - uint constant CALL_API_VERSION = 2; - - function callAPIVersion() constant returns (uint) { - return CALL_API_VERSION; - } - - function FutureBlockCall(address _schedulerAddress, - uint _targetBlock, - uint8 _gracePeriod, - address _contractAddress, - bytes4 _abiSignature, - bytes _callData, - uint _callValue, - uint _requiredGas, - uint16 _requiredStackDepth, - uint _basePayment, - uint _baseDonation) - FutureCall(_schedulerAddress, _requiredGas, _requiredStackDepth, _contractAddress, _abiSignature, _callData, _callValue, _basePayment, _baseDonation) - { - // parent contract FutureCall - schedulerAddress = _schedulerAddress; - - targetBlock = _targetBlock; - gracePeriod = _gracePeriod; - } - - uint constant GAS_PER_DEPTH = 700; - - function checkDepth(uint n) constant returns (bool) { - if (n == 0) return true; - return address(this).call.gas(GAS_PER_DEPTH * n)(bytes4(sha3("__dig(uint256)")), n - 1); - } - - function __dig(uint n) constant returns (bool) { - if (n == 0) return true; - if (!address(this).callcode(bytes4(sha3("__dig(uint256)")), n - 1)) throw; - } - - - function beforeExecute(address executor, uint startGas) public returns (bool) { - return CallLib.beforeExecuteForFutureBlockCall(call, executor, startGas); - } - - function afterExecute(address executor) internal { - // Refund any leftover funds. - CallLib.sendSafe(schedulerAddress, address(this).balance); - } - - uint constant GAS_OVERHEAD = 100000; - - function getOverhead() constant returns (uint) { - return GAS_OVERHEAD; - } - - uint constant EXTRA_GAS = 77000; - - function getExtraGas() constant returns (uint) { - return EXTRA_GAS; - } - - uint constant CLAIM_GROWTH_WINDOW = 240; - uint constant MAXIMUM_CLAIM_WINDOW = 15; - uint constant BEFORE_CALL_FREEZE_WINDOW = 10; - - function isCancellable() constant public returns (bool) { - return CallLib.isCancellable(call, msg.sender); - } - - function cancel() public { - if (CallLib.isCancellable(call, msg.sender)) { - CallLib.cancel(call, msg.sender); - } - } -} diff --git a/contracts/Canary.sol b/contracts/Canary.sol deleted file mode 100644 index 96c084a6c..000000000 --- a/contracts/Canary.sol +++ /dev/null @@ -1,99 +0,0 @@ -contract SchedulerInterface { - function scheduleCall(bytes4 abiSignature, - uint targetBlock, - uint requiredGas) public returns (address); - function isKnownCall(address callAddress) constant returns (bool); -} - -contract CallContractAPI { - function targetBlock() constant returns (uint); - function cancel() public; -} - - -contract Canary { - uint public aliveSince; - uint public lastHeartbeat; - uint public heartbeatCount; - SchedulerInterface scheduler; - CallContractAPI callContract; - - address public owner; - - function schedulerAddress() constant returns (address) { - return address(scheduler); - } - - function callContractAddress() constant returns (address) { - return address(callContract); - } - - uint16 public frequency; - - function Canary(address _scheduler, uint16 _frequency) { - owner = msg.sender; - scheduler = SchedulerInterface(_scheduler); - frequency = _frequency; - } - - function() { - if (this.balance < 2 ether) { - owner.send(this.balance); - } - } - - function cancel() public { - // not authorized - if (msg.sender != owner) throw; - // need to wait until the - if (callContract.balance > 0) { - callContract.cancel(); - } - owner.send(address(this).balance); - - } - - function initialize() public { - // ensure we are not already initialized. - if (aliveSince != 0) return; - - // mark when the canary came to life. - aliveSince = now; - - // schedule the first call - scheduleHeartbeat(); - } - - function scheduleHeartbeat() public { - // schedule the call (~2 hours from now) - address call_address = scheduler.scheduleCall.value(2 ether)( - 0x3defb962, - block.number + frequency, - 2000000); - if (call_address != 0x0) { - callContract = CallContractAPI(call_address); - } - } - - function heartbeat() public { - // Ran out of funds. - if (this.balance < 2 ether) return; - - // Not being called by the callContract. - if (msg.sender != address(callContract)) return; - - // The canary has died! - if (!isAlive()) return; - - // schedule the next call. - scheduleHeartbeat(); - - // Increment the heartbeat count - heartbeatCount += 1; - lastHeartbeat = now; - } - - function isAlive() constant returns (bool) { - return (aliveSince > 0 && block.number < callContract.targetBlock() + 255); - } -} diff --git a/contracts/ClaimLib.sol b/contracts/ClaimLib.sol new file mode 100644 index 000000000..2271ad8ca --- /dev/null +++ b/contracts/ClaimLib.sol @@ -0,0 +1,27 @@ +//pragma solidity 0.4.1; + + +library ClaimLib { + struct ClaimData { + // The address that has claimed this request + address claimedBy; + + // The deposit amount that was put down by the claimer. + uint claimDeposit; + + // An integer constrained between 0-100 that will be applied to the + // request payment as a percentage. + uint8 paymentModifier; + + // The number of temporal units that prior to the call freeze window + // during which the request will be claimable. + uint claimWindowSize; + } + + /* + * Helper: returns whether this request is claimed. + */ + function isClaimed(ClaimData storage self) returns (bool) { + return self.claimedBy != 0x0; + } +} diff --git a/contracts/Digger.sol b/contracts/Digger.sol new file mode 100644 index 000000000..04b2c1b2f --- /dev/null +++ b/contracts/Digger.sol @@ -0,0 +1,13 @@ +//pragma solidity 0.4.1; + + +contract Digger { + /* + * Recursively call this contracts code, each time extending the stack + * depth by 1 until the stack depth has been extended by `n` levels. + */ + function __dig(uint n) constant returns (bool) { + if (n == 0) return true; + if (!address(this).callcode(bytes4(sha3("__dig(uint256)")), n - 1)) throw; + } +} diff --git a/contracts/Examples.sol b/contracts/Examples.sol deleted file mode 100644 index b2e33e718..000000000 --- a/contracts/Examples.sol +++ /dev/null @@ -1,106 +0,0 @@ -contract ERC20Token { - /* - * https://github.com/ethereum/EIPs/issues/20 - */ - function totalSupply() constant returns (uint supply); - function balanceOf( address who ) constant returns (uint value); - function allowance(address owner, address spender) constant returns (uint _allowance); - function transfer( address to, uint value) returns (bool ok); - function transferFrom( address from, address to, uint value) returns (bool ok); - function approve(address spender, uint value) returns (bool ok); - event Transfer(address indexed from, address indexed to, uint value); - event Approval( address indexed owner, address indexed spender, uint value); -} - - -contract TrustFund { - /* - * This contract locks away whatever funds it was given until the - * `releaseBlock` - */ - address public beneficiary; - uint public releaseBlock; - - function TrustFund(address _beneficiary, uint _releaseBlock, address alarmScheduler) { - beneficiary = _beneficiary; - releaseBlock = _releaseBlock; - - // Schedule a call to happen at the block specified by release block. - alarmScheduler.call(bytes4(sha3("scheduleCall(uint256)")), releaseBlock); - } - - function releaseFunds() { - // only release the funds if there are sunds to be released and we've - // reached `releaseBlock` - if (this.balance == 0 || block.number < releaseBlock) return; - - beneficiary.send(this.balance); - } - - function () { - releaseFunds(); - } -} - - -contract TokenCallContract { - address public schedulerAddress; -} - -contract TokenScheduler { - function isKnownCall(address callAddress) public returns (bool); - function scheduleCall(bytes4 abiSignature, - uint targetBlock) public returns (address); -} - - -contract ERC20ScheduledTransfer is ERC20Token { - /* - * An ERC20 compliant token contract which supports scheduled funds - * transfers. - */ - // Note: this address should be filled out with the address of the Alarm - // Scheduler contract. - TokenScheduler public scheduler = TokenScheduler(0x0); - - mapping (address => uint) balances; - - function scheduleTransfer(address to, uint value, uint when) returns (bool) { - // Schedule the call; - var callAddress = scheduler.scheduleCall(bytes4(sha3("transferFrom(address,address,uint256)")), when); - // Register the call data - callAddress.call(msg.sender, to, value); - } - - function transferFrom(address from, address to, uint value) returns (bool) { - // Insufficient balance - if (value > balances[from]) return; - - bool isAuthorized; - - if (msg.sender == from) { - isAuthorized = true; - } - else if (scheduler.isKnownCall(msg.sender)) { - // If the caller is a known call contract with the scheduler we can - // trust it to tell us who scheduled it. - var call = TokenCallContract(msg.sender); - var schedulerAddress = call.schedulerAddress(); - - // The call is authorized if either this token contract or the - // `from` address was the scheduler of the call. - isAuthorized = (schedulerAddress == from || schedulerAddress == address(this)); - } - else { - isAuthorized = false; - } - - if (isAuthorized) { - balances[from] -= value; - balances[to] += value; - Transfer(from, to , value); - return true; - } - return false; - } -} diff --git a/contracts/ExecutionLib.sol b/contracts/ExecutionLib.sol new file mode 100644 index 000000000..ace47d893 --- /dev/null +++ b/contracts/ExecutionLib.sol @@ -0,0 +1,49 @@ +//pragma solidity 0.4.1; + + +library ExecutionLib { + struct ExecutionData { + // The address that the txn will be sent to. + address toAddress; + + // The bytes value that will be sent with the txn. + bytes callData; + + // The value in wei that will be sent with the txn. + uint callValue; + + // The amount of gas that will be sent with the txn + uint callGas; + + // The stack depth this txn requires. + uint requiredStackDepth; + } + + function sendTransaction(ExecutionData storage self) returns (bool) { + return self.toAddress.call.value(self.callValue) + .gas(self.callGas) + (self.callData); + } + + uint constant _GAS_PER_DEPTH = 700; + + function GAS_PER_DEPTH() returns (uint) { + return _GAS_PER_DEPTH; + } + + /* + * Verifies that the stack can currently be extended by the + * `requiredStackDepth`. For this function to work, the contract calling + * this library function must have implemented the interface found in the + * `contracts/Digger.sol` contract. + */ + function stackCanBeExtended(ExecutionData storage self) returns (bool) { + if (self.requiredStackDepth == 0) return true; + return address(this).call + .gas(_GAS_PER_DEPTH * self.requiredStackDepth) + ( + bytes4(sha3("__dig(uint256)")), + self.requiredStackDepth - 1 + ); + } +} diff --git a/contracts/GroveLib.sol b/contracts/GroveLib.sol index 063e38e3e..e996f62e0 100644 --- a/contracts/GroveLib.sol +++ b/contracts/GroveLib.sol @@ -1,4 +1,4 @@ -// Grove v0.2 +//pragma solidity 0.4.1; /// @title GroveLib - Library for queriable indexed ordered data. diff --git a/contracts/PaymentLib.sol b/contracts/PaymentLib.sol new file mode 100644 index 000000000..f57e7fccc --- /dev/null +++ b/contracts/PaymentLib.sol @@ -0,0 +1,107 @@ +//pragma solidity 0.4.1; + + +library PaymentLib { + struct PaymentData { + // The gas price that was used during creation of this request. + uint anchorGasPrice; + + // The amount in wei that will be payed to the address that executes + // this request. + uint payment; + + // The amount in wei that will be payed to the donationBenefactor address. + uint donation; + + // The address that the donation amount will be paid to. + address donationBenefactor; + } + + /* + * + */ + function hasBenefactor(PaymentData storage self) returns (bool) { + return self.donationBenefactor != 0x0; + } + + /* + * Return a number between 0 - 200 to scale the donation based on the + * gas price set for the calling transaction as compared to the gas + * price of the scheduling transaction. + * + * - number approaches zero as the transaction gas price goes + * above the gas price recorded when the call was scheduled. + * + * - the number approaches 200 as the transaction gas price + * drops under the price recorded when the call was scheduled. + * + * This encourages lower gas costs as the lower the gas price + * for the executing transaction, the higher the payout to the + * caller. + */ + function getMultiplier(PaymentData storage self) returns (uint) { + if (tx.gasprice > self.anchorGasPrice) { + return 100 * self.anchorGasPrice / tx.gasprice; + } + else { + return 200 - 100 * self.anchorGasPrice / (2 * self.anchorGasPrice - tx.gasprice); + } + } + + /* + * Computes the amount to send to the donationBenefactor + */ + function getDonation(PaymentData storage self) returns (uint) { + return self.donation * getMultiplier(self) / 100; + } + + /* + * Computes the amount to send to the address that fulfilled the request + */ + function getPayment(PaymentData storage self) returns (uint) { + return self.payment * getMultiplier(self) / 100; + } + + /* + * Computes the amount to send to the address that fulfilled the request + * with an additional modifier. This is used when the call was claimed. + */ + function getPaymentWithModifier(PaymentData storage self, + uint8 paymentModifier)returns (uint) { + return getPayment(self) * 100 / paymentModifier; + } + + event SendFailed(address to, uint value); + + uint constant DEFAULT_SEND_GAS = 90000; + + /* + * Send ether to an address. + * On failure log the `SendFailed` event. + * Returns the amount of wei that was sent (which will be 0 on failure). + */ + function safeSend(address to, uint value) internal returns (uint) { + return safeSend(to, value, DEFAULT_SEND_GAS); + } + + /* + * Same as `safeSend` but allows specifying the gas to be included with the + * send. + */ + function safeSend(address to, uint value, uint sendGas) internal returns (uint) { + if (value > this.balance) { + value = this.balance; + } + + if (value == 0) { + return 0; + } + + if (!to.call.value(value).gas(sendGas)()) { + SendFailed(to, value); + return 0; + } + + return 0; + } +} diff --git a/contracts/RequestFactoryInterface.sol b/contracts/RequestFactoryInterface.sol new file mode 100644 index 000000000..a963a5cc4 --- /dev/null +++ b/contracts/RequestFactoryInterface.sol @@ -0,0 +1,7 @@ +//pragma solidity 0.4.1; + + +contract RequestFactoryInterface { + function receiveExecutionNotification() returns (bool); + function isKnownRequest(address _address) returns (bool); +} diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol new file mode 100644 index 000000000..a92c6c0ee --- /dev/null +++ b/contracts/RequestLib.sol @@ -0,0 +1,247 @@ +//pragma solidity 0.4.1; + +import {ExecutionLib} from "contracts/ExecutionLib.sol"; +import {ScheduleLib} from "contracts/ScheduleLib.sol"; +import {ClaimLib} from "contracts/ClaimLib.sol"; +import {RequestMetaLib} from "contracts/RequestMetaLib.sol"; +import {PaymentLib} from "contracts/PaymentLib.sol"; + + +library RequestLib { + using ExecutionLib for ExecutionLib.ExecutionData; + using ScheduleLib for ScheduleLib.Schedule; + using ClaimLib for ClaimLib.ClaimData; + using RequestMetaLib for RequestMetaLib.RequestMeta; + using PaymentLib for PaymentLib.PaymentData; + + struct Result { + bool wasCalled; + bool wasSuccessful; + uint gasConsumption; + uint paymentOwed; + uint donationOwed; + } + + struct Request { + ExecutionLib.ExecutionData txnData; + Result result; + RequestMetaLib.RequestMeta meta; + PaymentLib.PaymentData paymentData; + ClaimLib.ClaimData claimData; + ScheduleLib.Schedule schedule; + } + + enum Reason { + WasCancelled, + AlreadyCalled, + BeforeCallWindow, + AfterCallWindow, + ReservedForClaimer, + StackTooDeep, + InsufficientGas + } + + event Aborted(Reason reason); + event Executed(uint payment, uint donation); + + /* + * Returns the entire data structure of the Request in a *serialized* + * format. This will be missing the `callData` which must be requested + * separately + * + * Parameter order is alphabetical by type, then namespace, then name + */ + function serialize(Request storage self) returns (address[5] addressValues, + bool[3] boolValues, + uint[16] uintValues, + uint8[1] uint8Values) { + // Address values + addressValues[0] = self.claimData.claimedBy; + addressValues[1] = self.meta.factoryAddress; + addressValues[2] = self.meta.owner; + addressValues[3] = self.paymentData.donationBenefactor; + addressValues[4] = self.txnData.toAddress; + + // Boolean values + boolValues[0] = self.meta.isCancelled; + boolValues[1] = self.result.wasCalled; + boolValues[2] = self.result.wasSuccessful; + + // UInt256 values + uintValues[0] = self.claimData.claimDeposit; + uintValues[1] = self.claimData.claimWindowSize; + uintValues[3] = self.paymentData.anchorGasPrice; + uintValues[4] = self.paymentData.donation; + uintValues[5] = self.paymentData.payment; + uintValues[6] = self.result.donationOwed; + uintValues[7] = self.result.gasConsumption; + uintValues[8] = self.result.paymentOwed; + uintValues[8] = self.schedule.freezePeriod; + uintValues[9] = self.schedule.reservedWindowSize; + uintValues[10] = uint(self.schedule.temporalUnit); + uintValues[11] = self.schedule.windowStart; + uintValues[12] = self.schedule.windowSize; + uintValues[13] = self.txnData.callGas; + uintValues[14] = self.txnData.callValue; + uintValues[15] = self.txnData.requiredStackDepth; + + // Uint8 values + uint8Values[0] = self.claimData.paymentModifier; + + return ( + addressValues, + boolValues, + uintValues, + uint8Values + ); + } + + function deserialize(Request storage self, + address[5] addressValues, + bool[3] boolValues, + uint[16] uintValues, + uint8[1] uint8Values, + bytes callData) returns (bool) { + // callData is special. + self.txnData.callData = callData; + + // Address values + self.claimData.claimedBy = addressValues[0]; + self.meta.factoryAddress = addressValues[1]; + self.meta.owner = addressValues[2]; + self.paymentData.donationBenefactor = addressValues[3]; + self.txnData.toAddress = addressValues[4]; + + // Boolean values + self.meta.isCancelled = boolValues[0]; + self.result.wasCalled = boolValues[1]; + self.result.wasSuccessful = boolValues[2]; + + // UInt values + self.claimData.claimDeposit = uintValues[0]; + self.claimData.claimWindowSize = uintValues[1]; + self.paymentData.anchorGasPrice = uintValues[3]; + self.paymentData.donation = uintValues[4]; + self.paymentData.payment = uintValues[5]; + self.result.donationOwed = uintValues[6]; + self.result.gasConsumption = uintValues[7]; + self.result.paymentOwed = uintValues[8]; + self.schedule.freezePeriod = uintValues[8]; + self.schedule.reservedWindowSize = uintValues[9]; + self.schedule.temporalUnit = ScheduleLib.TemporalUnit(uintValues[10]); + self.schedule.windowStart = uintValues[11]; + self.schedule.windowSize = uintValues[12]; + self.txnData.callGas = uintValues[13]; + self.txnData.callValue = uintValues[14]; + self.txnData.requiredStackDepth = uintValues[15]; + + // Uint8 values + self.claimData.paymentModifier = uint8Values[0]; + } + + function execute(Request storage self) returns (bool) { + /* + * Send the requested transaction. + * + * Must pass all of the following checks: + * + * 1. Not already called. + * 2. Not cancelled. + * 3. Not before the execution window. + * 4. Not after the execution window. + * 5. if (claimedBy == 0x0 or msg.sender == claimedBy): + * - windowStart <= block.number + * - block.number <= windowStart + windowSize + * else if (msg.sender != claimedBy): + * - windowStart + reservedWindowSize <= block.number + * - block.number <= windowStart + windowSize + * else: + * - throw (should be impossible) + * 6. if (msg.sender != tx.origin): + * - Verify stack can be increased by requiredStackDepth + * 7. msg.gas >= callGas + */ + var startGas = msg.gas; + var nowValue = self.schedule.getNow(); + + if (self.meta.isCancelled) { + Aborted(Reason.WasCancelled); + return false; + } else if (self.result.wasCalled) { + Aborted(Reason.AlreadyCalled); + return false; + } else if (self.schedule.isBeforeWindow()) { + Aborted(Reason.BeforeCallWindow); + return false; + } else if (self.schedule.isAfterWindow()) { + Aborted(Reason.AfterCallWindow); + return false; + } else if (self.claimData.isClaimed() && + msg.sender != self.claimData.claimedBy && + self.schedule.inReservedWindow()) { + Aborted(Reason.ReservedForClaimer); + return false; + } else if (msg.sender != tx.origin && !self.txnData.stackCanBeExtended()) { + Aborted(Reason.StackTooDeep); + return false; + } else if (msg.gas < self.txnData.callGas) { + Aborted(Reason.InsufficientGas); + return false; + } + + // Ensure the request is marked as having been called before sending + // the transaction to prevent re-entrance. + self.result.wasCalled = true; + + // Send the transaction + self.result.wasSuccessful = self.txnData.sendTransaction(); + + // Report execution back to the origin address. + self.meta.reportExecution(); + + // Compute the donation amount + if (self.paymentData.hasBenefactor()) { + self.result.donationOwed += self.paymentData.getDonation(); + } + + // Compute the payment amount + if (self.claimData.isClaimed()) { + self.result.paymentOwed += self.claimData.claimDeposit; + self.result.paymentOwed += self.paymentData.getPaymentWithModifier(self.claimData.paymentModifier); + } else { + self.result.paymentOwed += self.paymentData.getPayment(); + } + + // Record the amount of gas used by execution. + self.result.gasConsumption = startGas - msg.gas + EXTRA_GAS(); + + // NOTE: All code after this must be accounted for by EXTRA_GAS + + // Add the gas reimbursment amount to the payment. + self.result.paymentOwed += self.result.gasConsumption * tx.gasprice; + + // Log the two payment amounts. Otherwise it is non-trivial to figure + // out how much was payed. + Executed(self.result.paymentOwed, self.result.donationOwed); + + // Send the donation. This will be a noop if there is no benefactor or + // if the donation amount is 0. + self.result.donationOwed -= PaymentLib.safeSend(self.paymentData.donationBenefactor, self.result.donationOwed); + + // Send the payment. + self.result.paymentOwed -= PaymentLib.safeSend(msg.sender, self.result.paymentOwed); + + return true; + } + + // TODO: compute this + uint constant _EXTRA_GAS = 0; + + /* + * Returns the amount of gas used by the portion of the `execute` function + * that cannot be accounted for via gas tracking. + */ + function EXTRA_GAS() returns (uint) { + return _EXTRA_GAS; + } +} diff --git a/contracts/RequestMetaLib.sol b/contracts/RequestMetaLib.sol new file mode 100644 index 000000000..a40d94537 --- /dev/null +++ b/contracts/RequestMetaLib.sol @@ -0,0 +1,23 @@ +//pragma solidity 0.4.1; + +import {RequestFactoryInterface} from "contracts/RequestFactoryInterface.sol"; + + + +library RequestMetaLib { + struct RequestMeta { + // The address that created this request + address owner; + + // The address of the request factory that created this request. + address factoryAddress; + + // Was the request cancelled. + bool isCancelled; + } + + function reportExecution(RequestMeta storage self) returns (bool) { + var factory = RequestFactoryInterface(self.factoryAddress); + return factory.receiveExecutionNotification(); + } +} diff --git a/contracts/ScheduleLib.sol b/contracts/ScheduleLib.sol new file mode 100644 index 000000000..ca65957e3 --- /dev/null +++ b/contracts/ScheduleLib.sol @@ -0,0 +1,89 @@ +//pragma solidity 0.4.1; + + +library ScheduleLib { + enum TemporalUnit { + Seconds, + Blocks + } + + struct Schedule { + // The type of unit used to measure time. + TemporalUnit temporalUnit; + + // The temporal starting point when the request may be executed + uint windowStart; + + // The number of temporal units past the windowStart that the request + // may still be executed. + uint windowSize; + + // The number of temporal units before the window start during which no + // activity may occur. + uint freezePeriod; + + // The number of temporal units after the windowStart during which only + // the address that claimed the request may execute the request. + uint reservedWindowSize; + } + + /* + * Return what `now` is in the temporal units being used by this request. + * Currently supports block based times, and timestamp (seconds) based + * times. + */ + function getNow(Schedule storage self) returns (uint) { + if (self.temporalUnit == TemporalUnit.Seconds) { + return now; + } else if (self.temporalUnit == TemporalUnit.Blocks) { + return block.number; + } else { + // Unsupported unit. + throw; + } + } + + /* + * Helper: computes the end of the execution window. + */ + function windowEnd(Schedule storage self) returns (uint) { + return self.windowStart + self.windowSize; + } + + /* + * Helper: computes the end of the reserved portion of the execution + * window. + */ + function reservedWindowEnd(Schedule storage self) returns (uint) { + return self.windowStart + self.reservedWindowSize; + } + + /* + * Helper: Returns boolean if we are before the execution window. + */ + function isBeforeWindow(Schedule storage self) returns (bool) { + return getNow(self) < self.windowStart; + } + + /* + * Helper: Returns boolean if we are after the execution window. + */ + function isAfterWindow(Schedule storage self) returns (bool) { + return getNow(self) > self.windowStart; + } + + /* + * Helper: Returns boolean if we are inside the execution window. + */ + function inWindow(Schedule storage self) returns (bool) { + return self.windowStart <= getNow(self) && getNow(self) <= windowEnd(self); + } + + /* + * Helper: Returns boolean if we are inside the reserved portion of the + * execution window. + */ + function inReservedWindow(Schedule storage self) returns (bool) { + return self.windowStart <= getNow(self) && getNow(self) <= reservedWindowEnd(self); + } +} diff --git a/contracts/Scheduler.sol b/contracts/Scheduler.sol deleted file mode 100644 index 04bb7cf0d..000000000 --- a/contracts/Scheduler.sol +++ /dev/null @@ -1,539 +0,0 @@ -import "contracts/SchedulerLib.sol"; -import "contracts/CallLib.sol"; - - -contract Scheduler { - /* - * Address: 0x6c8f2a135f6ed072de4503bd7c4999a1a17f824b - */ - - // The starting value (0.01 USD at 1eth:$2 exchange rate) - uint constant INITIAL_DEFAUlT_PAYMENT = 5 finney; - - uint public defaultPayment; - - function Scheduler() { - defaultPayment = INITIAL_DEFAUlT_PAYMENT; - } - - // callIndex tracks the ordering of scheduled calls based on their block numbers. - GroveLib.Index callIndex; - - uint constant CALL_API_VERSION = 7; - - function callAPIVersion() constant returns (uint) { - return CALL_API_VERSION; - } - - /* - * Call Scheduling - */ - function getMinimumGracePeriod() constant returns (uint) { - return SchedulerLib.getMinimumGracePeriod(); - } - - // Default payment and donation values - modifier only_known_call { if (isKnownCall(msg.sender)) _ } - - function updateDefaultPayment() public only_known_call { - var call = FutureBlockCall(msg.sender); - var basePayment = call.basePayment(); - - if (call.wasCalled() && call.claimer() != 0x0 && basePayment > 0 && defaultPayment > 1) { - var index = call.claimAmount() * 100 / basePayment; - - if (index > 66 && defaultPayment <= basePayment) { - // increase by 0.01% - defaultPayment = defaultPayment * 10001 / 10000; - } - else if (index < 33 && defaultPayment >= basePayment) { - // decrease by 0.01% - defaultPayment = defaultPayment * 9999 / 10000; - } - } - } - - function getDefaultDonation() constant returns (uint) { - return defaultPayment / 100; - } - - function getMinimumCallGas() constant returns (uint) { - return SchedulerLib.getMinimumCallGas(); - } - - function getMaximumCallGas() constant returns (uint) { - return SchedulerLib.getMaximumCallGas(); - } - - function getMinimumEndowment() constant returns (uint) { - return SchedulerLib.getMinimumEndowment(defaultPayment, getDefaultDonation(), 0, getDefaultRequiredGas()); - } - - function getMinimumEndowment(uint basePayment) constant returns (uint) { - return SchedulerLib.getMinimumEndowment(basePayment, getDefaultDonation(), 0, getDefaultRequiredGas()); - } - - function getMinimumEndowment(uint basePayment, uint baseDonation) constant returns (uint) { - return SchedulerLib.getMinimumEndowment(basePayment, baseDonation, 0, getDefaultRequiredGas()); - } - - function getMinimumEndowment(uint basePayment, uint baseDonation, uint callValue) constant returns (uint) { - return SchedulerLib.getMinimumEndowment(basePayment, baseDonation, callValue, getDefaultRequiredGas()); - } - - function getMinimumEndowment(uint basePayment, uint baseDonation, uint callValue, uint requiredGas) constant returns (uint) { - return SchedulerLib.getMinimumEndowment(basePayment, baseDonation, callValue, requiredGas); - } - - function isKnownCall(address callAddress) constant returns (bool) { - return GroveLib.exists(callIndex, bytes32(callAddress)); - } - - function getFirstSchedulableBlock() constant returns (uint) { - return SchedulerLib.getFirstSchedulableBlock(); - } - - function getMinimumStackCheck() constant returns (uint16) { - return SchedulerLib.getMinimumStackCheck(); - } - - function getMaximumStackCheck() constant returns (uint16) { - return SchedulerLib.getMaximumStackCheck(); - } - - function getDefaultStackCheck() constant returns (uint16) { - return getMinimumStackCheck(); - } - - function getDefaultRequiredGas() constant returns (uint) { - return SchedulerLib.getMinimumCallGas(); - } - - function getDefaultGracePeriod() constant returns (uint8) { - return SchedulerLib.getDefaultGracePeriod(); - } - - bytes constant EMPTY_CALL_DATA = ""; - uint constant DEFAULT_CALL_VALUE = 0; - bytes4 constant DEFAULT_FN_SIGNATURE = 0x0000; - - function scheduleCall() public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - DEFAULT_FN_SIGNATURE, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(uint targetBlock) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - DEFAULT_FN_SIGNATURE, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes callData) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - DEFAULT_FN_SIGNATURE, callData, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature, - bytes callData) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, callData, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - DEFAULT_FN_SIGNATURE, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - uint callValue, - bytes4 abiSignature) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - callValue, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - bytes callData) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, callData, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - uint callValue, - bytes callData) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, callData, getDefaultGracePeriod(), getDefaultStackCheck(), - callValue, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(uint callValue, - address contractAddress) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - DEFAULT_FN_SIGNATURE, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - callValue, getFirstSchedulableBlock(), getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - uint targetBlock) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - DEFAULT_FN_SIGNATURE, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - uint targetBlock, - uint callValue) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - DEFAULT_FN_SIGNATURE, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - callValue, targetBlock, getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature, - uint targetBlock) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - uint targetBlock) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature, - bytes callData, - uint targetBlock) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, callData, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - bytes callData, - uint targetBlock) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, callData, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - uint callValue, - bytes callData, - uint targetBlock) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, callData, getDefaultGracePeriod(), getDefaultStackCheck(), - callValue, targetBlock, getDefaultRequiredGas(), defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature, - uint targetBlock, - uint requiredGas) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - uint targetBlock, - uint requiredGas) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, EMPTY_CALL_DATA, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature, - bytes callData, - uint targetBlock, - uint requiredGas) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, callData, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - bytes callData, - uint targetBlock, - uint requiredGas) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, callData, getDefaultGracePeriod(), getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature, - uint targetBlock, - uint requiredGas, - uint8 gracePeriod) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, EMPTY_CALL_DATA, gracePeriod, getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - uint callValue, - bytes4 abiSignature, - uint targetBlock, - uint requiredGas, - uint8 gracePeriod) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, EMPTY_CALL_DATA, gracePeriod, getDefaultStackCheck(), - callValue, targetBlock, requiredGas, defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - uint targetBlock, - uint requiredGas, - uint8 gracePeriod) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, EMPTY_CALL_DATA, gracePeriod, getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - bytes callData, - uint targetBlock, - uint requiredGas, - uint8 gracePeriod) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, callData, gracePeriod, getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, defaultPayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature, - uint targetBlock, - uint requiredGas, - uint8 gracePeriod, - uint basePayment) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, EMPTY_CALL_DATA, gracePeriod, getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, basePayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - uint callValue, - bytes4 abiSignature, - uint targetBlock, - uint requiredGas, - uint8 gracePeriod, - uint basePayment) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, EMPTY_CALL_DATA, gracePeriod, getDefaultStackCheck(), - callValue, targetBlock, requiredGas, basePayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - uint targetBlock, - uint requiredGas, - uint8 gracePeriod, - uint basePayment) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, EMPTY_CALL_DATA, gracePeriod, getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, basePayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature, - bytes callData, - uint targetBlock, - uint requiredGas, - uint8 gracePeriod, - uint basePayment) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, callData, gracePeriod, getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, basePayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - bytes callData, - uint8 gracePeriod, - uint[4] args) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, callData, gracePeriod, getDefaultStackCheck(), - // callValue, targetBlock, requiredGas, basePayment - args[0], args[1], args[2], args[3], getDefaultDonation(), msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - bytes callData, - uint targetBlock, - uint requiredGas, - uint8 gracePeriod, - uint basePayment) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, contractAddress, - abiSignature, callData, gracePeriod, getDefaultStackCheck(), - DEFAULT_CALL_VALUE, targetBlock, requiredGas, basePayment, getDefaultDonation(), msg.value - ); - } - - function scheduleCall(bytes4 abiSignature, - bytes callData, - uint16 requiredStackDepth, - uint8 gracePeriod, - uint callValue, - uint targetBlock, - uint requiredGas, - uint basePayment, - uint baseDonation) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - msg.sender, msg.sender, - abiSignature, callData, gracePeriod, requiredStackDepth, - callValue, targetBlock, requiredGas, basePayment, baseDonation, msg.value - ); - } - - function scheduleCall(address contractAddress, - bytes4 abiSignature, - bytes callData, - uint16 requiredStackDepth, - uint8 gracePeriod, - uint[5] args) public returns (address) { - return SchedulerLib.scheduleCall( - callIndex, - [msg.sender, contractAddress], - abiSignature, callData, gracePeriod, requiredStackDepth, - // callValue, targetBlock, requiredGas, basePayment, baseDonation - [args[0], args[1], args[2], args[3], args[4], msg.value] - ); - } - - /* - * Next Call API - */ - function getCallWindowSize() constant returns (uint) { - return SchedulerLib.getCallWindowSize(); - } - - function getNextCall(uint blockNumber) constant returns (address) { - return address(GroveLib.query(callIndex, ">=", int(blockNumber))); - } - - function getNextCallSibling(address callAddress) constant returns (address) { - return address(GroveLib.getNextNode(callIndex, bytes32(callAddress))); - } -} diff --git a/contracts/SchedulerLib.sol b/contracts/SchedulerLib.sol deleted file mode 100644 index 9ac7dddd9..000000000 --- a/contracts/SchedulerLib.sol +++ /dev/null @@ -1,217 +0,0 @@ -import "contracts/GroveLib.sol"; -import "contracts/AccountingLib.sol"; -import "contracts/CallLib.sol"; - - -library SchedulerLib { - /* - * Address: 0xe54d323f9ef17c1f0dede47ecc86a9718fe5ea34 - */ - /* - * Call Scheduling API - */ - function version() constant returns (uint16, uint16, uint16) { - return (0, 7, 0); - } - - // Ten minutes into the future. - uint constant MIN_BLOCKS_IN_FUTURE = 10; - - // max of uint8 - uint8 constant DEFAULT_GRACE_PERIOD = 255; - - // The minimum gas required to execute a scheduled call on a function that - // does almost nothing. This is an approximation and assumes the worst - // case scenario for gas consumption. - // - // Measured Minimum is closer to 95,000 - uint constant MINIMUM_CALL_GAS = 200000; - - // The minimum depth required to execute a call. - uint16 constant MINIMUM_STACK_CHECK = 10; - - // The maximum possible depth that stack depth checking can achieve. - // Actual check limit is 1021. Actual call limit is 1021 - uint16 constant MAXIMUM_STACK_CHECK = 1000; - - event CallScheduled(address call_address); - - event CallRejected(address indexed schedulerAddress, bytes32 reason); - - uint constant CALL_WINDOW_SIZE = 16; - - function getMinimumStackCheck() constant returns (uint16) { - return MINIMUM_STACK_CHECK; - } - - function getMaximumStackCheck() constant returns (uint16) { - return MAXIMUM_STACK_CHECK; - } - - function getCallWindowSize() constant returns (uint) { - return CALL_WINDOW_SIZE; - } - - function getMinimumGracePeriod() constant returns (uint) { - return 2 * CALL_WINDOW_SIZE; - } - - function getDefaultGracePeriod() constant returns (uint8) { - return DEFAULT_GRACE_PERIOD; - } - - function getMinimumCallGas() constant returns (uint) { - return MINIMUM_CALL_GAS; - } - - function getMaximumCallGas() constant returns (uint) { - return block.gaslimit - getMinimumCallGas(); - } - - function getMinimumCallCost(uint basePayment, uint baseDonation) constant returns (uint) { - return 2 * (baseDonation + basePayment) + MINIMUM_CALL_GAS * tx.gasprice; - } - - function getFirstSchedulableBlock() constant returns (uint) { - return block.number + MIN_BLOCKS_IN_FUTURE; - } - - function getMinimumEndowment(uint basePayment, - uint baseDonation, - uint callValue, - uint requiredGas) constant returns (uint endowment) { - endowment += tx.gasprice * requiredGas; - endowment += 2 * (basePayment + baseDonation); - endowment += callValue; - - return endowment; - } - - struct CallConfig { - address schedulerAddress; - address contractAddress; - bytes4 abiSignature; - bytes callData; - uint callValue; - uint8 gracePeriod; - uint16 requiredStackDepth; - uint targetBlock; - uint requiredGas; - uint basePayment; - uint baseDonation; - uint endowment; - } - - function scheduleCall(GroveLib.Index storage callIndex, - address schedulerAddress, - address contractAddress, - bytes4 abiSignature, - bytes callData, - uint8 gracePeriod, - uint16 requiredStackDepth, - uint callValue, - uint targetBlock, - uint requiredGas, - uint basePayment, - uint baseDonation, - uint endowment) public returns (address) { - CallConfig memory callConfig = CallConfig({ - schedulerAddress: schedulerAddress, - contractAddress: contractAddress, - abiSignature: abiSignature, - callData: callData, - gracePeriod: gracePeriod, - requiredStackDepth: requiredStackDepth, - callValue: callValue, - targetBlock: targetBlock, - requiredGas: requiredGas, - basePayment: basePayment, - baseDonation: baseDonation, - endowment: endowment, - }); - return _scheduleCall(callIndex, callConfig); - } - - function scheduleCall(GroveLib.Index storage callIndex, - address[2] addresses, - bytes4 abiSignature, - bytes callData, - uint8 gracePeriod, - uint16 requiredStackDepth, - uint[6] uints) public returns (address) { - CallConfig memory callConfig = CallConfig({ - schedulerAddress: addresses[0], - contractAddress: addresses[1], - abiSignature: abiSignature, - callData: callData, - gracePeriod: gracePeriod, - requiredStackDepth: requiredStackDepth, - callValue: uints[0], - targetBlock: uints[1], - requiredGas: uints[2], - basePayment: uints[3], - baseDonation: uints[4], - endowment: uints[5], - }); - return _scheduleCall(callIndex, callConfig); - - } - - function _scheduleCall(GroveLib.Index storage callIndex, CallConfig memory callConfig) internal returns (address) { - /* - * Primary API for scheduling a call. - * - * - No sooner than MIN_BLOCKS_IN_FUTURE - * - Grace Period must be longer than the minimum grace period. - * - msg.value must be >= MIN_GAS * tx.gasprice + 2 * (baseDonation + basePayment) - */ - bytes32 reason; - - if (callConfig.targetBlock < block.number + MIN_BLOCKS_IN_FUTURE) { - // Don't allow scheduling further than - // MIN_BLOCKS_IN_FUTURE - reason = "TOO_SOON"; - } - else if (getMinimumStackCheck() > callConfig.requiredStackDepth || callConfig.requiredStackDepth > getMaximumStackCheck()) { - // Cannot require stack depth greater than MAXIMUM_STACK_CHECK or - // less than MINIMUM_STACK_CHECK - reason = "STACK_CHECK_OUT_OF_RANGE"; - } - else if (callConfig.gracePeriod < getMinimumGracePeriod()) { - reason = "GRACE_TOO_SHORT"; - } - else if (callConfig.requiredGas < getMinimumCallGas() || callConfig.requiredGas > getMaximumCallGas()) { - reason = "REQUIRED_GAS_OUT_OF_RANGE"; - } - else if (callConfig.endowment < getMinimumEndowment(callConfig.basePayment, callConfig.baseDonation, callConfig.callValue, callConfig.requiredGas)) { - reason = "INSUFFICIENT_FUNDS"; - } - - if (reason != 0x0) { - CallRejected(callConfig.schedulerAddress, reason); - AccountingLib.sendRobust(callConfig.schedulerAddress, callConfig.endowment); - return; - } - - var call = (new FutureBlockCall).value(callConfig.endowment)( - callConfig.schedulerAddress, - callConfig.targetBlock, - callConfig.gracePeriod, - callConfig.contractAddress, - callConfig.abiSignature, - callConfig.callData, - callConfig.callValue, - callConfig.requiredGas, - callConfig.requiredStackDepth, - callConfig.basePayment, - callConfig.baseDonation - ); - - // Put the call into the grove index. - GroveLib.insert(callIndex, bytes32(address(call)), int(call.targetBlock())); - - CallScheduled(address(call)); - - return address(call); - } -} diff --git a/contracts/Testers.sol b/contracts/Testers.sol deleted file mode 100644 index 4096adf66..000000000 --- a/contracts/Testers.sol +++ /dev/null @@ -1,279 +0,0 @@ -contract owned { - address public owner; - - function Owned() { - owner = msg.sender; - } -} - - -contract SchedulerAPI { - function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock) public returns (address); - //function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas) public returns (address); - //function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod) public returns (address); - //function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod, uint basePayment) public returns (address); - - //function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod, uint basePayment, uint baseFee) public returns (address); -} - - -contract TestDataRegistry is owned { - uint8 public wasSuccessful = 0; - - function reset() public { - wasSuccessful = 0; - } - - function registerBool(address to, bool v) public { - bool result = to.call(bytes4(sha3("registerData()")), v); - if (result) { - wasSuccessful = 1; - } - else { - wasSuccessful = 2; - } - } - - function registerUInt(address to, uint v) public { - bool result = to.call(bytes4(sha3("registerData()")), v); - if (result) { - wasSuccessful = 1; - } - else { - wasSuccessful = 2; - } - } - - function registerInt(address to, int v) public { - bool result = to.call(bytes4(sha3("registerData()")), v); - if (result) { - wasSuccessful = 1; - } - else { - wasSuccessful = 2; - } - } - - function registerBytes32(address to, bytes32 v) public { - bool result = to.call(bytes4(sha3("registerData()")), v); - if (result) { - wasSuccessful = 1; - } - else { - wasSuccessful = 2; - } - } - - function registerBytes(address to, bytes v) public { - bool result = to.call(v); - //bool result = to.call(v); - if (result) { - wasSuccessful = 1; - } - else { - wasSuccessful = 2; - } - } - - function registerAddress(address to, address v) public { - bool result = to.call(bytes4(sha3("registerData()")), v); - if (result) { - wasSuccessful = 1; - } - else { - wasSuccessful = 2; - } - } - - function registerMany(address to, uint a, int b, uint c, bytes20 d, address e, bytes f) public { - bool result = to.call(bytes4(sha3("registerData()")), a, b, c, d, e, f.length, f); - if (result) { - wasSuccessful = 1; - } - else { - wasSuccessful = 2; - } - } - - function registerData(address to, int arg1, bytes32 arg2, address arg3) public { - // 0xb0f07e44 == bytes4(sha3("registerData()")) - bool result = to.call(0xb0f07e44, arg1, arg2, arg3); - if (result) { - wasSuccessful = 1; - } - else { - wasSuccessful = 2; - } - } -} - - -contract TestCallExecution is TestDataRegistry { - uint8 public wasSuccessful; - - function reset() public { - v_bool = false; - v_uint = 0; - v_int = 0; - v_bytes32 = 0x0; - v_address = 0x0; - v_bytes.length = 0; - - vm_a = 0; - vm_b = 0; - vm_c = 0; - vm_d = 0x0; - vm_e = 0x0; - vm_f.length = 0; - } - - function noop() { - } - - function doExecution(address to) { - bool result = to.call(bytes4(sha3("execute()"))); - if (result) { - wasSuccessful = 1; - } - else { - wasSuccessful = 2; - } - } - - function doLoops(uint iterations) { - for (uint i = 0; i < iterations; i++) { - address(this).send(1); - } - } - - bool public v_bool; - - function scheduleSetBool(address to, uint targetBlock, bool v) public { - SchedulerAPI arst = SchedulerAPI(to); - address call_address = arst.scheduleCall.value(this.balance)(address(this), bytes4(sha3("setBool()")), targetBlock); - call_address.call(bytes4(sha3("registerData()")), v); - } - - function setBool() public { - v_bool = true; - } - - uint public v_uint; - - function scheduleSetUInt(address to, uint targetBlock, uint v) public { - SchedulerAPI arst = SchedulerAPI(to); - address call_address = arst.scheduleCall.value(this.balance)(address(this), bytes4(sha3("setUInt(uint256)")), targetBlock); - call_address.call(bytes4(sha3("registerData()")), v); - } - - function setUInt(uint v) public { - v_uint = v; - } - - int public v_int; - - function setInt(int v) public { - v_int = v; - } - - address public v_address; - - function setAddress(address v) public { - v_address = v; - } - - bytes32 public v_bytes32; - - function setBytes32(bytes32 v) public { - v_bytes32 = v; - } - - bytes public v_bytes; - - function setBytes(bytes v) public { - v_bytes = v; - wasSuccessful = 1; - } - - function setCallData() public { - v_bytes = msg.data; - } - - uint public vm_a; - int public vm_b; - uint public vm_c; - bytes20 public vm_d; - address public vm_e; - bytes public vm_f; - - function setMany(uint a, int b, uint c, bytes20 d, address e, bytes f) public { - vm_a = a; - vm_b = b; - vm_c = c; - vm_d = d; - vm_e = e; - vm_f = f; - } -} - - -contract TestErrors is owned { - bool public value; - - function reset() public { - value = false; - } - - function doFail() public { - throw; - value = true; - } - - function doInfinite() public { - while (true) { - tx.origin.send(1); - } - value = true; - } - - address public callAddress; - - function setCallAddress(address _callAddress) { - callAddress = _callAddress; - } - - uint public d; - - function proxyCall(uint depth) public returns (bool) { - if (depth == 0) { - return callAddress.call(bytes4(sha3("execute()"))); - } - else if (msg.sender == address(this)) { - return address(this).callcode(bytes4(sha3("proxyCall(uint256)")), depth - 1); - } - else { - return address(this).call(bytes4(sha3("proxyCall(uint256)")), depth - 1); - } - } - - uint constant GAS_PER_DEPTH = 700; - - function checkDepth(uint n) constant returns (bool) { - if (n == 0) return true; - return address(this).call.gas(GAS_PER_DEPTH * n)(bytes4(sha3("__dig(uint256)")), n - 1); - } - - function __dig(uint n) constant returns (bool) { - if (n == 0) return true; - if (!address(this).callcode(bytes4(sha3("__dig(uint256)")), n - 1)) throw; - } - - function doStackExtension(uint depth) public { - if (!checkDepth(depth)) throw; - value = true; - - } - function allowance(address _owner, address _spender) constant returns (uint256 remaining) { - return 12345; - } -} diff --git a/contracts/TransactionRequest.sol b/contracts/TransactionRequest.sol new file mode 100644 index 000000000..d490df5e2 --- /dev/null +++ b/contracts/TransactionRequest.sol @@ -0,0 +1,15 @@ +//pragma solidity 0.4.1; + +import {RequestLib} from "contracts/RequestLib.sol"; +import {Digger} from "contracts/Digger.sol"; + + +contract TransactionRequest is Digger { + using RequestLib for RequestLib.Request; + + RequestLib.Request txnRequest; + + function execute() public returns (bool) { + return txnRequest.execute(); + } +} diff --git a/contracts/TransactionRequestInterface.sol b/contracts/TransactionRequestInterface.sol new file mode 100644 index 000000000..c38247089 --- /dev/null +++ b/contracts/TransactionRequestInterface.sol @@ -0,0 +1,6 @@ +//pragma solidity 0.4.1; + + +contract TransactionRequestInterface { + function execute() public returns (bool); +} From 66b00d3783d03346820abc2d6d005a7b08246b97 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Wed, 14 Sep 2016 17:18:13 -0600 Subject: [PATCH 02/25] dirty --- contracts/RequestLib.sol | 18 ++++++++++++++++-- contracts/RequestMetaLib.sol | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index a92c6c0ee..1b976547f 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -57,7 +57,7 @@ library RequestLib { uint8[1] uint8Values) { // Address values addressValues[0] = self.claimData.claimedBy; - addressValues[1] = self.meta.factoryAddress; + addressValues[1] = self.meta.createdBy; addressValues[2] = self.meta.owner; addressValues[3] = self.paymentData.donationBenefactor; addressValues[4] = self.txnData.toAddress; @@ -96,6 +96,11 @@ library RequestLib { ); } + /* + * Populates a Request object from the full output of `serialize`. + * + * Parameter order is alphabetical by type, then namespace, then name. + */ function deserialize(Request storage self, address[5] addressValues, bool[3] boolValues, @@ -107,7 +112,7 @@ library RequestLib { // Address values self.claimData.claimedBy = addressValues[0]; - self.meta.factoryAddress = addressValues[1]; + self.meta.createdBy = addressValues[1]; self.meta.owner = addressValues[2]; self.paymentData.donationBenefactor = addressValues[3]; self.txnData.toAddress = addressValues[4]; @@ -139,6 +144,15 @@ library RequestLib { self.claimData.paymentModifier = uint8Values[0]; } + function initialize(Request storage self, + address[5] addressValues, + uint[16] uintValues, + uint8[1] uint8Values, + bytes callData) returns (bool) { + // TODO: + throw; + } + function execute(Request storage self) returns (bool) { /* * Send the requested transaction. diff --git a/contracts/RequestMetaLib.sol b/contracts/RequestMetaLib.sol index a40d94537..7bef7058a 100644 --- a/contracts/RequestMetaLib.sol +++ b/contracts/RequestMetaLib.sol @@ -10,14 +10,14 @@ library RequestMetaLib { address owner; // The address of the request factory that created this request. - address factoryAddress; + address createdBy; // Was the request cancelled. bool isCancelled; } function reportExecution(RequestMeta storage self) returns (bool) { - var factory = RequestFactoryInterface(self.factoryAddress); + var factory = RequestFactoryInterface(self.createdBy); return factory.receiveExecutionNotification(); } } From 1fc1e3c60505f89f8753464fda7a1ad58b329d59 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Thu, 15 Sep 2016 00:31:47 -0600 Subject: [PATCH 03/25] more work on request creation --- contracts/ExecutionLib.sol | 38 ++++++++++ contracts/IterTools.sol | 13 ++++ contracts/PaymentLib.sol | 15 ++++ contracts/RequestFactory.sol | 69 +++++++++++++++++ contracts/RequestFactoryInterface.sol | 3 + contracts/RequestLib.sol | 105 ++++++++++++++++++++++++-- contracts/ScheduleLib.sol | 32 +++++++- contracts/TransactionRequest.sol | 12 +++ 8 files changed, 280 insertions(+), 7 deletions(-) create mode 100644 contracts/IterTools.sol create mode 100644 contracts/RequestFactory.sol diff --git a/contracts/ExecutionLib.sol b/contracts/ExecutionLib.sol index ace47d893..eaf773391 100644 --- a/contracts/ExecutionLib.sol +++ b/contracts/ExecutionLib.sol @@ -46,4 +46,42 @@ library ExecutionLib { self.requiredStackDepth - 1 ); } + + uint constant _MAX_STACK_DEPTH_REQUIREMENT = 1000; + + function MAX_STACK_DEPTH_REQUIREMENT() returns (uint) { + return _MAX_STACK_DEPTH_REQUIREMENT; + } + + /* + * Validation: ensure that the required stack depth is not above the + * MAX_STACK_DEPTH_REQUIREMENT + */ + function validateRequiredStackDepth(uint requiredStackDepth) returns (bool) { + return requiredStackDepth <= _MAX_STACK_DEPTH_REQUIREMENT; + } + + /* + * Returns the maximum possible gas consumption that a transaction request + * may consume. The EXTRA_GAS value represents the overhead involved in + * request execution. + */ + function CALL_GAS_CEILING(uint EXTRA_GAS) returns (uint) { + return block.gaslimit - EXTRA_GAS; + } + + /* + * Validation: ensure that the callGas is not above the total possible gas + * for a call. + */ + function validateCallGas(uint callGas, uint EXTRA_GAS) returns (bool) { + return callGas < CALL_GAS_CEILING(EXTRA_GAS); + } + + /* + * Validation: ensure that the toAddress is not set to the empty address. + */ + function validateToAddress(address toAddress) returns (bool) { + return toAddress != 0x0; + } } diff --git a/contracts/IterTools.sol b/contracts/IterTools.sol new file mode 100644 index 000000000..5df5ed185 --- /dev/null +++ b/contracts/IterTools.sol @@ -0,0 +1,13 @@ +library IterTools { + /* + * Return true if any of the values in the boolean array are true + */ + function any(bool[7] values) returns (bool) { + for (uint i = 0; i < values.length; i++) { + if (values[i]) { + return true; + } + } + return false; + } +} diff --git a/contracts/PaymentLib.sol b/contracts/PaymentLib.sol index f57e7fccc..896453f3f 100644 --- a/contracts/PaymentLib.sol +++ b/contracts/PaymentLib.sol @@ -104,4 +104,19 @@ library PaymentLib { return 0; } + + /* + * Validation: ensure that the request endowment is sufficient to cover. + * - payment * maxMultiplier + * - donation * maxMultiplier + * - gasReimbursment + * - callValue + */ + function validateEndowment(uint endowment, + uint payment, + uint donation, + uint callGas, + uint callValue) returns (bool) { + return endowment >= 2 * (payment + donation) + callGas * tx.gasprice + callValue; + } } diff --git a/contracts/RequestFactory.sol b/contracts/RequestFactory.sol new file mode 100644 index 000000000..cf09cadb6 --- /dev/null +++ b/contracts/RequestFactory.sol @@ -0,0 +1,69 @@ +//pragma solidity 0.4.1; + +import {RequestFactoryInterface} from "contracts/RequestFactoryInterface.sol"; +import {TransactionRequest} from "contracts/TransactionRequest.sol"; +import {RequestLib} from "contracts/RequestLib.sol"; +import {IterTools} from "contracts/IterTools.sol"; + + +contract RequestFactory is RequestFactoryInterface { + using IterTools for bool[7]; + + /* + * Error Codes + */ + event InsufficientEndowment(); + event ReservedWindowBiggerThanExecutionWindow(); + event InvalidTemporalUnit(); + event ExecutionWindowTooSoon(); + event InvalidRequiredStackDepth(); + event CallGasTooHigh(); + event EmptyToAddress(); + + /* + * The full interface for + */ + function createRequest(address[2] addressArgs, + uint[11] uintArgs, + bytes callData) returns (address) { + var errors = RequestLib.validate( + [address(this), msg.sender, addressArgs[0], addressArgs[1]], + uintArgs, + callData, + msg.value + ); + + if (errors.any()) { + if (errors[0]) InsufficientEndowment(); + if (errors[1]) ReservedWindowBiggerThanExecutionWindow(); + if (errors[2]) InvalidTemporalUnit(); + if (errors[3]) ExecutionWindowTooSoon(); + if (errors[4]) InvalidRequiredStackDepth(); + if (errors[5]) CallGasTooHigh(); + if (errors[6]) EmptyToAddress(); + } + + var request = (new TransactionRequest).value(msg.value)( + [msg.sender, addressArgs[0], addressArgs[1]], + uintArgs, + callData + ); + + // TODO: register with tracker + + return request; + } + + function receiveExecutionNotification() returns (bool) { + // TODO; + throw; + } + + mapping (address => bool) requests; + + function isKnownRequest(address _address) returns (bool) { + // TODO: decide whether this should be a local mapping or from tracker. + return requests[_address]; + } +} + diff --git a/contracts/RequestFactoryInterface.sol b/contracts/RequestFactoryInterface.sol index a963a5cc4..40280554a 100644 --- a/contracts/RequestFactoryInterface.sol +++ b/contracts/RequestFactoryInterface.sol @@ -2,6 +2,9 @@ contract RequestFactoryInterface { + function createRequest(address[4] addressArgs, + uint[11] uintArgs, + bytes callData) returns (address); function receiveExecutionNotification() returns (bool); function isKnownRequest(address _address) returns (bool); } diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index 1b976547f..f389cd5bb 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -145,12 +145,107 @@ library RequestLib { } function initialize(Request storage self, - address[5] addressValues, - uint[16] uintValues, - uint8[1] uint8Values, + address[4] addressArgs, + uint[11] uintArgs, bytes callData) returns (bool) { - // TODO: - throw; + address[5] memory addressValues = [ + 0x0, // self.claimData.claimedBy + addressArgs[0], // self.meta.createdBy + addressArgs[1], // self.meta.owner + addressArgs[2], // self.paymentData.donationBenefactor + addressArgs[3] // self.txnData.toAddress + ]; + + bool[3] memory boolValues = [false, false, false]; + + uint[16] memory uintValues = [ + 0, // self.claimData.claimDeposit + uintArgs[0], // self.claimData.claimWindowSize + tx.gasprice, // self.paymentData.anchorGasPrice + uintArgs[1], // self.paymentData.donation + uintArgs[2], // self.paymentData.payment + 0, // self.result.donationOwed + 0, // self.result.gasConsumption + 0, // self.result.paymentOwed + uintArgs[3], // self.schedule.freezePeriod + uintArgs[4], // self.schedule.reservedWindowSize + uintArgs[5], // self.schedule.temporalUnit + uintArgs[6], // self.schedule.windowStart + uintArgs[7], // self.schedule.windowSize + uintArgs[8], // self.txnData.callGas + uintArgs[9], // self.txnData.callValue + uintArgs[10] // self.txnData.requiredStackDepth + ]; + + uint8[1] memory uint8Values = [ + 0 + ]; + + deserialize(self, addressValues, boolValues, uintValues, uint8Values, callData); + + return true; + } + + function validate(address[4] addressValues, + uint[11] uintValues, + bytes callData, + uint endowment) returns (bool[7] errors) { + Request memory request; + + // callData is special. + request.txnData.callData = callData; + + // Address values + request.claimData.claimedBy = 0x0; + request.meta.createdBy = addressValues[0]; + request.meta.owner = addressValues[1]; + request.paymentData.donationBenefactor = addressValues[2]; + request.txnData.toAddress = addressValues[3]; + + // Boolean values + request.meta.isCancelled = false; + request.result.wasCalled = false; + request.result.wasSuccessful = false; + + // UInt values + request.claimData.claimDeposit = 0; + request.claimData.claimWindowSize = uintValues[0]; + request.paymentData.anchorGasPrice = tx.gasprice; + request.paymentData.donation = uintValues[1]; + request.paymentData.payment = uintValues[2]; + request.result.donationOwed = 0; + request.result.gasConsumption = 0; + request.result.paymentOwed = 0; + request.schedule.freezePeriod = uintValues[3]; + request.schedule.reservedWindowSize = uintValues[4]; + request.schedule.temporalUnit = ScheduleLib.TemporalUnit(uintValues[5]); + request.schedule.windowStart = uintValues[6]; + request.schedule.windowSize = uintValues[7]; + request.txnData.callGas = uintValues[8]; + request.txnData.callValue = uintValues[9]; + request.txnData.requiredStackDepth = uintValues[10]; + + // Uint8 values + request.claimData.paymentModifier = 0; + + // These errors must be in the same order as the RequestFactory.Errors + // enum. + errors[0] = PaymentLib.validateEndowment(endowment, + request.paymentData.payment, + request.paymentData.donation, + request.txnData.callGas, + request.txnData.callValue); + errors[1] = ScheduleLib.validateReservedWindowSize(request.schedule.reservedWindowSize, + request.schedule.windowSize); + errors[2] = ScheduleLib.validateTemporalUnit(uintValues[5]); + errors[3] = ScheduleLib.validateWindowStart(request.schedule.temporalUnit, + request.schedule.freezePeriod, + request.schedule.windowStart); + errors[4] = ExecutionLib.validateRequiredStackDepth(request.txnData.requiredStackDepth); + errors[5] = ExecutionLib.validateCallGas(request.txnData.callGas, _EXTRA_GAS); + errors[6] = ExecutionLib.validateToAddress(request.txnData.toAddress); + + return errors; } function execute(Request storage self) returns (bool) { diff --git a/contracts/ScheduleLib.sol b/contracts/ScheduleLib.sol index ca65957e3..55a6fb648 100644 --- a/contracts/ScheduleLib.sol +++ b/contracts/ScheduleLib.sol @@ -33,9 +33,13 @@ library ScheduleLib { * times. */ function getNow(Schedule storage self) returns (uint) { - if (self.temporalUnit == TemporalUnit.Seconds) { + return getNow(self.temporalUnit); + } + + function getNow(TemporalUnit temporalUnit) internal returns (uint) { + if (temporalUnit == TemporalUnit.Seconds) { return now; - } else if (self.temporalUnit == TemporalUnit.Blocks) { + } else if (temporalUnit == TemporalUnit.Blocks) { return block.number; } else { // Unsupported unit. @@ -86,4 +90,28 @@ library ScheduleLib { function inReservedWindow(Schedule storage self) returns (bool) { return self.windowStart <= getNow(self) && getNow(self) <= reservedWindowEnd(self); } + + /* + * Validation: ensure that the reservedWindowSize <= windowSize + */ + function validateReservedWindowSize(uint reservedWindowSize, + uint windowSize) returns (bool) { + return reservedWindowSize < windowSize; + } + + /* + * Validation: ensure that the startWindow is at least freezePeriod in the future + */ + function validateWindowStart(TemporalUnit temporalUnit, + uint freezePeriod, + uint windowStart) returns (bool) { + return getNow(temporalUnit) + freezePeriod <= windowStart; + } + + /* + * Validation: ensure that the temporal unit passed in is constrained to 0 or 1 + */ + function validateTemporalUnit(uint temporalUnitAsUInt) returns (bool) { + return temporalUnitAsUInt <= uint(TemporalUnit.Blocks); + } } diff --git a/contracts/TransactionRequest.sol b/contracts/TransactionRequest.sol index d490df5e2..46c217561 100644 --- a/contracts/TransactionRequest.sol +++ b/contracts/TransactionRequest.sol @@ -7,6 +7,18 @@ import {Digger} from "contracts/Digger.sol"; contract TransactionRequest is Digger { using RequestLib for RequestLib.Request; + function TransactionRequest(address[3] addressArgs, + uint[11] uintArgs, + bytes callData) { + address[4] memory addressValues = [ + msg.sender, + addressArgs[0], + addressArgs[1], + addressArgs[2] + ]; + txnRequest.initialize(addressValues, uintArgs, callData); + } + RequestLib.Request txnRequest; function execute() public returns (bool) { From 7585478c8dfd08b0ae22b63e7e1a6adb26901b6e Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Thu, 15 Sep 2016 21:32:06 -0600 Subject: [PATCH 04/25] a test --- contracts/GasLib.sol | 16 + contracts/PaymentLib.sol | 10 +- contracts/RequestFactory.sol | 67 +- contracts/RequestFactoryInterface.sol | 4 +- contracts/RequestLib.sol | 93 +- contracts/RequestMetaLib.sol | 9 +- contracts/TransactionRequest.sol | 19 +- migrations/0001_deploy_v7_alarm.py | 4294 ---------------- migrations/0002_deploy_v7_canary.py | 4304 ----------------- .../test_request_factory.py | 60 + 10 files changed, 218 insertions(+), 8658 deletions(-) create mode 100644 contracts/GasLib.sol delete mode 100644 migrations/0001_deploy_v7_alarm.py delete mode 100644 migrations/0002_deploy_v7_canary.py create mode 100644 tests/transaction-request/test_request_factory.py diff --git a/contracts/GasLib.sol b/contracts/GasLib.sol new file mode 100644 index 000000000..75a41405a --- /dev/null +++ b/contracts/GasLib.sol @@ -0,0 +1,16 @@ +library GasLib { + /* + * Returns a gas value that leaves at least reserveAmount leftover. This + * may return 0 if msg.gas < reserveAmount. The BUFFER value is present + * to prevent underflow in cases where msg.gas >= reserveAmount but the + * act of comparison drops msg.gas < reserveAmount. + */ + uint constant BUFFER = 10000; + + function getGas(uint reserveAmount) returns (uint) { + if (msg.gas < reserveAmount + BUFFER) { + return 0; + } + return msg.gas - reserveAmount; + } +} diff --git a/contracts/PaymentLib.sol b/contracts/PaymentLib.sol index 896453f3f..d19db827b 100644 --- a/contracts/PaymentLib.sol +++ b/contracts/PaymentLib.sol @@ -73,7 +73,11 @@ library PaymentLib { event SendFailed(address to, uint value); - uint constant DEFAULT_SEND_GAS = 90000; + uint constant _DEFAULT_SEND_GAS = 90000; + + function DEFAULT_SEND_GAS() returns (uint) { + return _DEFAULT_SEND_GAS; + } /* * Send ether to an address. @@ -81,7 +85,7 @@ library PaymentLib { * Returns the amount of wei that was sent (which will be 0 on failure). */ function safeSend(address to, uint value) internal returns (uint) { - return safeSend(to, value, DEFAULT_SEND_GAS); + return safeSend(to, value, _DEFAULT_SEND_GAS); } /* @@ -102,7 +106,7 @@ library PaymentLib { return 0; } - return 0; + return value; } /* diff --git a/contracts/RequestFactory.sol b/contracts/RequestFactory.sol index cf09cadb6..69f3841a0 100644 --- a/contracts/RequestFactory.sol +++ b/contracts/RequestFactory.sol @@ -10,52 +10,81 @@ contract RequestFactory is RequestFactoryInterface { using IterTools for bool[7]; /* - * Error Codes + * ValidationError */ - event InsufficientEndowment(); - event ReservedWindowBiggerThanExecutionWindow(); - event InvalidTemporalUnit(); - event ExecutionWindowTooSoon(); - event InvalidRequiredStackDepth(); - event CallGasTooHigh(); - event EmptyToAddress(); + enum Errors { + InsufficientEndowment, + ReservedWindowBiggerThanExecutionWindow, + InvalidTemporalUnit, + ExecutionWindowTooSoon, + InvalidRequiredStackDepth, + CallGasTooHigh, + EmptyToAddress + } + + event ValidationError(Errors error); /* - * The full interface for + * The lowest level interface for creating a transaction request. + * + * addressArgs[0]: paymentData.donationBenefactor + * addressArgs[1]: txnData.toAddress + * uintArgs[0], claimData.claimWindowSize + * uintArgs[1], paymentData.donation + * uintArgs[2], paymentData.payment + * uintArgs[3], schedule.freezePeriod + * uintArgs[4], schedule.reservedWindowSize + * uintArgs[5], schedule.temporalUnit + * uintArgs[6], schedule.windowStart + * uintArgs[7], schedule.windowSize + * uintArgs[8], txnData.callGas + * uintArgs[9], txnData.callValue + * uintArgs[10] txnData.requiredStackDepth */ function createRequest(address[2] addressArgs, uint[11] uintArgs, bytes callData) returns (address) { var errors = RequestLib.validate( - [address(this), msg.sender, addressArgs[0], addressArgs[1]], + [ + address(this), // meta.createdBy + msg.sender, // meta.owner + addressArgs[0], // paymentData.donationBenefactor + addressArgs[1] // txnData.toAddress + ], uintArgs, callData, msg.value ); if (errors.any()) { - if (errors[0]) InsufficientEndowment(); - if (errors[1]) ReservedWindowBiggerThanExecutionWindow(); - if (errors[2]) InvalidTemporalUnit(); - if (errors[3]) ExecutionWindowTooSoon(); - if (errors[4]) InvalidRequiredStackDepth(); - if (errors[5]) CallGasTooHigh(); - if (errors[6]) EmptyToAddress(); + if (errors[0]) ValidationError(Errors.InsufficientEndowment); + if (errors[1]) ValidationError(Errors.ReservedWindowBiggerThanExecutionWindow); + if (errors[2]) ValidationError(Errors.InvalidTemporalUnit); + if (errors[3]) ValidationError(Errors.ExecutionWindowTooSoon); + if (errors[4]) ValidationError(Errors.InvalidRequiredStackDepth); + if (errors[5]) ValidationError(Errors.CallGasTooHigh); + if (errors[6]) ValidationError(Errors.EmptyToAddress); } var request = (new TransactionRequest).value(msg.value)( - [msg.sender, addressArgs[0], addressArgs[1]], + [ + msg.sender, // meta.owner + addressArgs[0], // paymentData.donationBenefactor + addressArgs[1] // txnData.toAddress + ], uintArgs, callData ); + RequestCreated(address(request)); + // TODO: register with tracker return request; } function receiveExecutionNotification() returns (bool) { - // TODO; + // TODO handle this. throw; } diff --git a/contracts/RequestFactoryInterface.sol b/contracts/RequestFactoryInterface.sol index 40280554a..d8c7fa937 100644 --- a/contracts/RequestFactoryInterface.sol +++ b/contracts/RequestFactoryInterface.sol @@ -2,7 +2,9 @@ contract RequestFactoryInterface { - function createRequest(address[4] addressArgs, + event RequestCreated(address request); + + function createRequest(address[2] addressArgs, uint[11] uintArgs, bytes callData) returns (address); function receiveExecutionNotification() returns (bool); diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index f389cd5bb..de7e863ba 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -70,12 +70,12 @@ library RequestLib { // UInt256 values uintValues[0] = self.claimData.claimDeposit; uintValues[1] = self.claimData.claimWindowSize; - uintValues[3] = self.paymentData.anchorGasPrice; - uintValues[4] = self.paymentData.donation; - uintValues[5] = self.paymentData.payment; - uintValues[6] = self.result.donationOwed; - uintValues[7] = self.result.gasConsumption; - uintValues[8] = self.result.paymentOwed; + uintValues[2] = self.paymentData.anchorGasPrice; + uintValues[3] = self.paymentData.donation; + uintValues[4] = self.paymentData.payment; + uintValues[5] = self.result.donationOwed; + uintValues[6] = self.result.gasConsumption; + uintValues[7] = self.result.paymentOwed; uintValues[8] = self.schedule.freezePeriod; uintValues[9] = self.schedule.reservedWindowSize; uintValues[10] = uint(self.schedule.temporalUnit); @@ -125,12 +125,12 @@ library RequestLib { // UInt values self.claimData.claimDeposit = uintValues[0]; self.claimData.claimWindowSize = uintValues[1]; - self.paymentData.anchorGasPrice = uintValues[3]; - self.paymentData.donation = uintValues[4]; - self.paymentData.payment = uintValues[5]; - self.result.donationOwed = uintValues[6]; - self.result.gasConsumption = uintValues[7]; - self.result.paymentOwed = uintValues[8]; + self.paymentData.anchorGasPrice = uintValues[2]; + self.paymentData.donation = uintValues[3]; + self.paymentData.payment = uintValues[4]; + self.result.donationOwed = uintValues[5]; + self.result.gasConsumption = uintValues[6]; + self.result.paymentOwed = uintValues[7]; self.schedule.freezePeriod = uintValues[8]; self.schedule.reservedWindowSize = uintValues[9]; self.schedule.temporalUnit = ScheduleLib.TemporalUnit(uintValues[10]); @@ -271,14 +271,16 @@ library RequestLib { * 7. msg.gas >= callGas */ var startGas = msg.gas; - var nowValue = self.schedule.getNow(); - if (self.meta.isCancelled) { - Aborted(Reason.WasCancelled); + if (msg.gas < requiredExecutionGas(self)) { + Aborted(Reason.InsufficientGas); return false; } else if (self.result.wasCalled) { Aborted(Reason.AlreadyCalled); return false; + } else if (self.meta.isCancelled) { + Aborted(Reason.WasCancelled); + return false; } else if (self.schedule.isBeforeWindow()) { Aborted(Reason.BeforeCallWindow); return false; @@ -293,9 +295,6 @@ library RequestLib { } else if (msg.sender != tx.origin && !self.txnData.stackCanBeExtended()) { Aborted(Reason.StackTooDeep); return false; - } else if (msg.gas < self.txnData.callGas) { - Aborted(Reason.InsufficientGas); - return false; } // Ensure the request is marked as having been called before sending @@ -306,48 +305,84 @@ library RequestLib { self.result.wasSuccessful = self.txnData.sendTransaction(); // Report execution back to the origin address. - self.meta.reportExecution(); + self.meta.reportExecution(_GAS_TO_COMPLETE_EXECUTION); + + uint paymentOwed; + uint donationOwed; // Compute the donation amount if (self.paymentData.hasBenefactor()) { - self.result.donationOwed += self.paymentData.getDonation(); + donationOwed += self.paymentData.getDonation(); } // Compute the payment amount if (self.claimData.isClaimed()) { - self.result.paymentOwed += self.claimData.claimDeposit; - self.result.paymentOwed += self.paymentData.getPaymentWithModifier(self.claimData.paymentModifier); + paymentOwed += self.claimData.claimDeposit; + paymentOwed += self.paymentData.getPaymentWithModifier(self.claimData.paymentModifier); } else { - self.result.paymentOwed += self.paymentData.getPayment(); + paymentOwed += self.paymentData.getPayment(); } // Record the amount of gas used by execution. - self.result.gasConsumption = startGas - msg.gas + EXTRA_GAS(); + self.result.gasConsumption = (startGas - msg.gas) + EXTRA_GAS(); // NOTE: All code after this must be accounted for by EXTRA_GAS // Add the gas reimbursment amount to the payment. - self.result.paymentOwed += self.result.gasConsumption * tx.gasprice; + paymentOwed += self.result.gasConsumption * tx.gasprice; // Log the two payment amounts. Otherwise it is non-trivial to figure // out how much was payed. - Executed(self.result.paymentOwed, self.result.donationOwed); + Executed(paymentOwed, donationOwed); // Send the donation. This will be a noop if there is no benefactor or // if the donation amount is 0. - self.result.donationOwed -= PaymentLib.safeSend(self.paymentData.donationBenefactor, self.result.donationOwed); + donationOwed -= PaymentLib.safeSend(self.paymentData.donationBenefactor, donationOwed); // Send the payment. - self.result.paymentOwed -= PaymentLib.safeSend(msg.sender, self.result.paymentOwed); + paymentOwed -= PaymentLib.safeSend(msg.sender, paymentOwed); + + // These need to be set after the send so that there is not opportunity + // for re-entrance. + self.result.donationOwed = donationOwed; + self.result.paymentOwed = paymentOwed; return true; } + function requiredExecutionGas(Request storage self) returns (uint) { + return self.txnData.callGas + + _GAS_TO_COMPLETE_EXECUTION + + _GAS_TO_AUTHORIZE_EXECUTION + + 2 * PaymentLib.DEFAULT_SEND_GAS(); + } + + // TODO: compute this + uint constant _GAS_TO_AUTHORIZE_EXECUTION = 200000; + + /* + * The amount of gas needed to do all of the pre execution checks. + */ + function GAS_TO_AUTHORIZE_EXECUTION() returns (uint) { + return _GAS_TO_AUTHORIZE_EXECUTION; + } + + // TODO: compute this + uint constant _GAS_TO_COMPLETE_EXECUTION = 200000; + + /* + * The amount of gas needed to complete the execute method after + * the transaction has been sent. + */ + function GAS_TO_COMPLETE_EXECUTION() returns (uint) { + return _GAS_TO_COMPLETE_EXECUTION; + } + // TODO: compute this uint constant _EXTRA_GAS = 0; /* - * Returns the amount of gas used by the portion of the `execute` function + * The amount of gas used by the portion of the `execute` function * that cannot be accounted for via gas tracking. */ function EXTRA_GAS() returns (uint) { diff --git a/contracts/RequestMetaLib.sol b/contracts/RequestMetaLib.sol index 7bef7058a..5919c54e1 100644 --- a/contracts/RequestMetaLib.sol +++ b/contracts/RequestMetaLib.sol @@ -1,6 +1,6 @@ //pragma solidity 0.4.1; -import {RequestFactoryInterface} from "contracts/RequestFactoryInterface.sol"; +import {GasLib} from "contracts/GasLib.sol"; @@ -16,8 +16,9 @@ library RequestMetaLib { bool isCancelled; } - function reportExecution(RequestMeta storage self) returns (bool) { - var factory = RequestFactoryInterface(self.createdBy); - return factory.receiveExecutionNotification(); + function reportExecution(RequestMeta storage self, uint gasReserve) returns (bool) { + return self.createdBy.call. + gas(GasLib.getGas(gasReserve)) + (bytes4(sha3("receiveExecutionNotification()"))); } } diff --git a/contracts/TransactionRequest.sol b/contracts/TransactionRequest.sol index 46c217561..7fad03646 100644 --- a/contracts/TransactionRequest.sol +++ b/contracts/TransactionRequest.sol @@ -11,10 +11,10 @@ contract TransactionRequest is Digger { uint[11] uintArgs, bytes callData) { address[4] memory addressValues = [ - msg.sender, - addressArgs[0], - addressArgs[1], - addressArgs[2] + msg.sender, // meta.createdBy + addressArgs[0], // meta.owner + addressArgs[1], // paymentData.donationBenefactor + addressArgs[2] // txnData.toAddress ]; txnRequest.initialize(addressValues, uintArgs, callData); } @@ -24,4 +24,15 @@ contract TransactionRequest is Digger { function execute() public returns (bool) { return txnRequest.execute(); } + + function requestData() constant returns (address[5], + bool[3], + uint[16], + uint8[1]) { + return txnRequest.serialize(); + } + + function callData() constant returns (bytes) { + return txnRequest.txnData.callData; + } } diff --git a/migrations/0001_deploy_v7_alarm.py b/migrations/0001_deploy_v7_alarm.py deleted file mode 100644 index bf131cb5b..000000000 --- a/migrations/0001_deploy_v7_alarm.py +++ /dev/null @@ -1,4294 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from populus import migrations - - -class Migration(migrations.Migration): - - migration_id = '0001_initial' - dependencies = [] - operations = [ - migrations.DeployContract('GroveLib'), - migrations.DeployContract('AccountingLib'), - migrations.DeployContract('CallLib'), - migrations.DeployContract('SchedulerLib'), - migrations.DeployContract('Scheduler'), - ] - compiled_contracts = { - 'AccountingLib': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'toAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'sendRobust', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': '_from', - 'type': 'address', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Deposit', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - { - 'name': 'balance', - 'type': 'uint256', - }, - ], - 'name': 'InsufficientFunds', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'AccountingLib.Bank storage', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'addFunds', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Withdrawal', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'AccountingLib.Bank storage', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'deposit', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'AccountingLib.Bank storage', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'withdraw', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'toAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - { - 'name': 'maxGas', - 'type': 'uint256', - }, - ], - 'name': 'sendRobust', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'AccountingLib.Bank storage', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'deductFunds', - 'outputs': [], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': '_from', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': '_Deposit', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': '_Withdrawal', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - { - 'indexed': False, - 'name': 'balance', - 'type': 'uint256', - }, - ], - 'name': '_InsufficientFunds', - 'type': 'event', - }, - ], - 'code': '0x6060604052610398806100126000396000f365030600000000506060604052361561007f5760e060020a600035046312c82bcc81146100845780635548c837146100a55780635c54305e146101015780636b103966146101555780637fcf532c14610189578063b1df3d80146101d5578063b5bc6dbb146101ee578063c6ab451414610225578063e62af6c114610294575b610007565b6102c66004356024356000620186a05a10156102dc576102ee83835a610232565b6102da60043560243560443581600160a060020a031683600160a060020a03167f47a08955ce2b7f21ea62ff0024e1ea0ad87430953554a87e6bc65d777f18e639836040518082815260200191505060405180910390a3505050565b6102da60043560243560443560408051838152602081018390528151600160a060020a038616927f9b24879829bed3003de08d5c5d7e18dcbb8dc76faebd95cafc5d4dec8c61a3a5928290030190a2505050565b6102da6004356024356044355b600160a060020a03821660009081526020849052604090205480820110156102f557610007565b6102da600435602435604080518281529051600160a060020a038416917fd0c5cf41ee8ebf084ad0bce53de7cbc6e4693d9b53a4019ca36a2f91cdc20b3a919081900360200190a25050565b6102c66004356024356044356000610318848484610162565b6102c6600435602435604435600160a060020a0382166000908152602084905260408120548290106102ea576103228484846102a1565b6102c66004356024356044355b60006000831180156102615750604051600160a060020a03851690600090859082818181858883f19350505050155b1561031857604051600160a060020a03851690839085906000818181858888f193505050501515610318575060006102ee565b6102da6004356024356044355b600160a060020a03821660009081526020849052604090205481111561037457610007565b604080519115158252519081900360200190f35b005b6102ee8383620186a0610232565b5060005b9392505050565b600160a060020a0382166000908152602084905260409020805482019055505050565b5060019392505050565b604051600160a060020a03841690600090849082818181858883f19350505050151561031857604051600160a060020a038416908390600081818185876185025a03f192505050151561031857610007565b600160a060020a03821660009081526020849052604090208054829003905550505056', - 'code_runtime': '0x65030600000000506060604052361561007f5760e060020a600035046312c82bcc81146100845780635548c837146100a55780635c54305e146101015780636b103966146101555780637fcf532c14610189578063b1df3d80146101d5578063b5bc6dbb146101ee578063c6ab451414610225578063e62af6c114610294575b610007565b6102c66004356024356000620186a05a10156102dc576102ee83835a610232565b6102da60043560243560443581600160a060020a031683600160a060020a03167f47a08955ce2b7f21ea62ff0024e1ea0ad87430953554a87e6bc65d777f18e639836040518082815260200191505060405180910390a3505050565b6102da60043560243560443560408051838152602081018390528151600160a060020a038616927f9b24879829bed3003de08d5c5d7e18dcbb8dc76faebd95cafc5d4dec8c61a3a5928290030190a2505050565b6102da6004356024356044355b600160a060020a03821660009081526020849052604090205480820110156102f557610007565b6102da600435602435604080518281529051600160a060020a038416917fd0c5cf41ee8ebf084ad0bce53de7cbc6e4693d9b53a4019ca36a2f91cdc20b3a919081900360200190a25050565b6102c66004356024356044356000610318848484610162565b6102c6600435602435604435600160a060020a0382166000908152602084905260408120548290106102ea576103228484846102a1565b6102c66004356024356044355b60006000831180156102615750604051600160a060020a03851690600090859082818181858883f19350505050155b1561031857604051600160a060020a03851690839085906000818181858888f193505050501515610318575060006102ee565b6102da6004356024356044355b600160a060020a03821660009081526020849052604090205481111561037457610007565b604080519115158252519081900360200190f35b005b6102ee8383620186a0610232565b5060005b9392505050565b600160a060020a0382166000908152602084905260409020805482019055505050565b5060019392505050565b604051600160a060020a03841690600090849082818181858883f19350505050151561031857604051600160a060020a038416908390600081818185876185025a03f192505050151561031857610007565b600160a060020a03821660009081526020849052604090208054829003905550505056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'CallContractAPI': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'targetBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'cancel', - 'outputs': [], - 'type': 'function', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'CallLib': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'checkExecutionAuthorization', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'firstClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'deposit_amount', - 'type': 'uint256', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'claim', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - ], - 'name': 'state', - 'outputs': [ - { - 'name': '', - 'type': 'CallLib.State', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'call', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'data', - 'type': 'bytes', - }, - ], - 'name': 'extractCallData', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'sender', - 'type': 'address', - }, - ], - 'name': 'cancel', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'caller', - 'type': 'address', - }, - ], - 'name': 'isCancellable', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'startGas', - 'type': 'uint256', - }, - ], - 'name': 'beforeExecuteForFutureBlockCall', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'lastClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'base_gas_price', - 'type': 'uint256', - }, - { - 'name': 'gas_price', - 'type': 'uint256', - }, - ], - 'name': 'getGasScalar', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'to_address', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'sendSafe', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'maxClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'start_gas', - 'type': 'uint256', - }, - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'overhead', - 'type': 'uint256', - }, - { - 'name': 'extraGas', - 'type': 'uint256', - }, - ], - 'name': 'execute', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'executor', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'gasCost', - 'type': 'uint256', - }, - { - 'indexed': False, - 'name': 'payment', - 'type': 'uint256', - }, - { - 'indexed': False, - 'name': 'donation', - 'type': 'uint256', - }, - { - 'indexed': False, - 'name': 'success', - 'type': 'bool', - }, - ], - 'name': 'CallExecuted', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': False, - 'name': 'executor', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'reason', - 'type': 'bytes32', - }, - ], - 'name': 'CallAborted', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'cancelled_by', - 'type': 'address', - }, - ], - 'name': 'Cancelled', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': False, - 'name': 'executor', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'claimAmount', - 'type': 'uint256', - }, - ], - 'name': 'Claimed', - 'type': 'event', - }, - ], - 'code': '0x60606040526112ef806100126000396000f36503060000000050606060405236156100b65760e060020a60003504630bd295e681146100bb5780630fd1f94e1461016d5780630fee183d1461017c5780635054d98a1461019d5780637c0278fc146101c55780637e9265621461025d578063a0943154146102cc578063a1873db6146102e4578063a9d2293d1461032b578063b5d0f16e14610382578063c17e6817146103a3578063cc3471af1461043d578063da46be0a1461044d578063f556275314610507575b610007565b6105af6004356024356044355b60006000600030915081600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515191505080841080610163575081600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515160ff168201851190505b156105e557610007565b6105c3600060f061062f610441565b6105af6004356024356044356064356000816002028310156106b8576106b0565b6105c36004355b6008810154600090819062010000900460ff16156106cc57600691506106c6565b60408051602060248035600481810135601f81018590048502860185019096528585526105d5958135959194604494929390920191819084018382808284375094965050505050505060006004825103836001016000508181546001816001161561010002031660029004825481601f106108eb5782601f10610925575b826008026101000360020a8091040282800117835561093c565b6105d5600435602435604051600090600160a060020a038316907f398bd6b21ae4164ec322fb0eb8c2eb6277f36fd41903fbbed594dfe125591281908390a260078301548190106109fe57600783015460058401546109fc9162010000909104600160a060020a0316906103ad565b6105af600435602435600060006000610a6d856101a4565b6105af600435602435604435600483015460009081903090841015610aed577f4e4f545f454e4f5547485f4741530000000000000000000000000000000000009150610d30565b6105c35b60006000309050600a81600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151919091039250505b5090565b6105c36004356024355b600082821115610d85578183606402049050610d96565b6105c36004356024355b600030600160a060020a0316318211156103cf57600160a060020a0330163191505b6000821115610d9c5773__AccountingLib_________________________6312c82bcc84846040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100075750839250610d96915050565b6105c35b6000600f61062f61032f565b6105d560043560243560443560643560843560088501805461ff00191661010017905584543090600090819081908190819060a060020a900460e060020a02600160e060020a031916811480156104b857506001808c01546002918116156101000260001901160481145b15610da4578a5460028c0154600160a060020a039190911690895a60405191900391906000818181858888f193505050508b60080160006101000a81548160ff02191690830217905550610ff6565b6105c36004355b6000600060006000309250600a83600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515191909103925050818511156112335782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151945061122b9050565b604080519115158252519081900360200190f35b60408051918252519081900360200190f35b005b600192505b50509392505050565b601081850310156105d7576005860154620100009004600160a060020a03166000148061062857506005860154620100009004600160a060020a03908116908616145b92506105dc565b03905090565b6006860181905560058601805475ffffffffffffffffffffffffffffffffffffffff000019166201000087021790556007860184905560408051600160a060020a0387168152602081019290925280517fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9281900390910190a15b949350505050565b6106354361050e565b600291505b50919050565b6008830154610100900460ff16156106e757600591506106c6565b30905080600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515161010943011015905061073e57600091506106c6565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143600a01101590506107ad576005830154620100009004600160a060020a0316600014156106c157600191506106c6565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143101590506107fd57600391506106c6565b80600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040805180517f0a16697a000000000000000000000000000000000000000000000000000000008252915160ff9092169291630a16697a9160048181019260209290919082900301816000876161da5a03f115610007575050604051519190910143101590506108aa57600491506106c6565b600791506106c6565b5081800160010183558181151161093c57601f016020900481601f0160209004836000526020600020918201910161093c9190610911565b82601f106108b3575082600052602060002080549082601f01602090048101906109f191905b8082111561037e5760008155600101610911565b60ff19168360005260206000205581800160010183555b505050506004825111156109f7575060005b600180840154600291811615610100026000190116048110156109f757818160040181518110156100075790602001015160f860020a900460f860020a02836001016000508281546001816001161561010002031660029004811015610007578154600116156109cd5790600052602060002090602091828204019190065b601f036101000a81548160ff0219169060f860020a8404021790555060010161094e565b50610243565b505050565b505b309050610a4981600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515190316103ad565b505050600801805462ff0000191662010000179055565b600092505b505092915050565b9150309050600082148015610acd575080600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151600160a060020a039081169086161490505b15610adb5760019250610a65565b6007821415610a605760019250610a65565b6008860154610100900460ff1615610b27577f414c52454144595f43414c4c45440000000000000000000000000000000000009150610d30565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051514310905080610bfd575080600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050506040518051906020015060ff1681600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151909101431190505b15610c2a577f4e4f545f494e5f43414c4c5f57494e444f5700000000000000000000000000009150610d30565b610c358686436100c8565b1515610c63577f4e4f545f415554484f52495a45440000000000000000000000000000000000009150610d30565b6005860154600061ffff91909116118015610c90575032600160a060020a031685600160a060020a031614155b8015610d0757506040805160058801547f349501b700000000000000000000000000000000000000000000000000000000825261ffff1660048201529051600160a060020a0383169163349501b791602482810192602092919082900301816000876161da5a03f115610007575050604051511590505b15610d30577f535441434b5f544f4f5f4445455000000000000000000000000000000000000091505b600082146105d75760408051600160a060020a03871681526020810184905281517fdcb278834ca505ad219cf8e4b5d11f026080abef6ec68e249ea5e4d9bb3dc7b2929181900390910190a1600092506105dc565b818360020203836064020460c80390505b92915050565b506000610d96565b8a54600160e060020a031960a060020a90910460e060020a021660001415610e1f578a5460028c0154600160a060020a039190911690895a03908d6001016000506040518082805460018160011615610100020316600290048015610ee15780601f10610eb657610100808354040283529160200191610ee1565b60018b8101546002918116156101000260001901160460001415610f16578a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491906040518360e060020a028152600401809050600060405180830381858988f19450505050508b60080160006101000a81548160ff02191690830217905550610ff6565b820191906000526020600020905b815481529060010190602001808311610ec457829003601f168201915b5050915050600060405180830381858888f193505050508b60080160006101000a81548160ff02191690830217905550610ff6565b8a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491908e6001016000506040518460e060020a0281526004018082805460018160011615610100020316600290048015610fc45780601f10610f9957610100808354040283529160200191610fc4565b820191906000526020600020905b815481529060010190602001808311610fa757829003601f168201915b5050915050600060405180830381858988f19450505050508b60080160006101000a81548160ff021916908302179055505b85600160a060020a031663938b5f326040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040805180517f75706461746544656661756c745061796d656e742829000000000000000000008252825191829003601601822060e060020a9081900490810283529251600160a060020a039190911693506004828101926000929190829003018183876161da5a03f150505060038c01546110ad91503a61038c565b60058c0154909550620100009004600160a060020a03908116908a1614156110db5760068b0154935061111d565b85600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051519450505b6064858502048b6007016000505401925060648587600160a060020a031663625cc4656040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001500204915060008b60070160005081905550865a8b03013a02905061119c898285016103ad565b92506111bc73d3cda913deb6f67967b99d67acdfa1712c293601836103ad565b6040805160088e01548482526020820187905281830184905260ff16151560608201529051919350600160a060020a038b16917f4538b7ec91dae8fada01e66a052482086d3e690c3db5a80457fbcd55457b4ae19181900360800190a25050505050505050505050565b600093505b505050919050565b600e1991909101908185111561128a5782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151945061122b9050565b60ef19909101908185111561122657818503905060f08184600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001500204935061122b56', - 'code_runtime': '0x6503060000000050606060405236156100b65760e060020a60003504630bd295e681146100bb5780630fd1f94e1461016d5780630fee183d1461017c5780635054d98a1461019d5780637c0278fc146101c55780637e9265621461025d578063a0943154146102cc578063a1873db6146102e4578063a9d2293d1461032b578063b5d0f16e14610382578063c17e6817146103a3578063cc3471af1461043d578063da46be0a1461044d578063f556275314610507575b610007565b6105af6004356024356044355b60006000600030915081600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515191505080841080610163575081600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515160ff168201851190505b156105e557610007565b6105c3600060f061062f610441565b6105af6004356024356044356064356000816002028310156106b8576106b0565b6105c36004355b6008810154600090819062010000900460ff16156106cc57600691506106c6565b60408051602060248035600481810135601f81018590048502860185019096528585526105d5958135959194604494929390920191819084018382808284375094965050505050505060006004825103836001016000508181546001816001161561010002031660029004825481601f106108eb5782601f10610925575b826008026101000360020a8091040282800117835561093c565b6105d5600435602435604051600090600160a060020a038316907f398bd6b21ae4164ec322fb0eb8c2eb6277f36fd41903fbbed594dfe125591281908390a260078301548190106109fe57600783015460058401546109fc9162010000909104600160a060020a0316906103ad565b6105af600435602435600060006000610a6d856101a4565b6105af600435602435604435600483015460009081903090841015610aed577f4e4f545f454e4f5547485f4741530000000000000000000000000000000000009150610d30565b6105c35b60006000309050600a81600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151919091039250505b5090565b6105c36004356024355b600082821115610d85578183606402049050610d96565b6105c36004356024355b600030600160a060020a0316318211156103cf57600160a060020a0330163191505b6000821115610d9c5773__AccountingLib_________________________6312c82bcc84846040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100075750839250610d96915050565b6105c35b6000600f61062f61032f565b6105d560043560243560443560643560843560088501805461ff00191661010017905584543090600090819081908190819060a060020a900460e060020a02600160e060020a031916811480156104b857506001808c01546002918116156101000260001901160481145b15610da4578a5460028c0154600160a060020a039190911690895a60405191900391906000818181858888f193505050508b60080160006101000a81548160ff02191690830217905550610ff6565b6105c36004355b6000600060006000309250600a83600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515191909103925050818511156112335782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151945061122b9050565b604080519115158252519081900360200190f35b60408051918252519081900360200190f35b005b600192505b50509392505050565b601081850310156105d7576005860154620100009004600160a060020a03166000148061062857506005860154620100009004600160a060020a03908116908616145b92506105dc565b03905090565b6006860181905560058601805475ffffffffffffffffffffffffffffffffffffffff000019166201000087021790556007860184905560408051600160a060020a0387168152602081019290925280517fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9281900390910190a15b949350505050565b6106354361050e565b600291505b50919050565b6008830154610100900460ff16156106e757600591506106c6565b30905080600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515161010943011015905061073e57600091506106c6565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143600a01101590506107ad576005830154620100009004600160a060020a0316600014156106c157600191506106c6565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143101590506107fd57600391506106c6565b80600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040805180517f0a16697a000000000000000000000000000000000000000000000000000000008252915160ff9092169291630a16697a9160048181019260209290919082900301816000876161da5a03f115610007575050604051519190910143101590506108aa57600491506106c6565b600791506106c6565b5081800160010183558181151161093c57601f016020900481601f0160209004836000526020600020918201910161093c9190610911565b82601f106108b3575082600052602060002080549082601f01602090048101906109f191905b8082111561037e5760008155600101610911565b60ff19168360005260206000205581800160010183555b505050506004825111156109f7575060005b600180840154600291811615610100026000190116048110156109f757818160040181518110156100075790602001015160f860020a900460f860020a02836001016000508281546001816001161561010002031660029004811015610007578154600116156109cd5790600052602060002090602091828204019190065b601f036101000a81548160ff0219169060f860020a8404021790555060010161094e565b50610243565b505050565b505b309050610a4981600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515190316103ad565b505050600801805462ff0000191662010000179055565b600092505b505092915050565b9150309050600082148015610acd575080600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151600160a060020a039081169086161490505b15610adb5760019250610a65565b6007821415610a605760019250610a65565b6008860154610100900460ff1615610b27577f414c52454144595f43414c4c45440000000000000000000000000000000000009150610d30565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051514310905080610bfd575080600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050506040518051906020015060ff1681600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151909101431190505b15610c2a577f4e4f545f494e5f43414c4c5f57494e444f5700000000000000000000000000009150610d30565b610c358686436100c8565b1515610c63577f4e4f545f415554484f52495a45440000000000000000000000000000000000009150610d30565b6005860154600061ffff91909116118015610c90575032600160a060020a031685600160a060020a031614155b8015610d0757506040805160058801547f349501b700000000000000000000000000000000000000000000000000000000825261ffff1660048201529051600160a060020a0383169163349501b791602482810192602092919082900301816000876161da5a03f115610007575050604051511590505b15610d30577f535441434b5f544f4f5f4445455000000000000000000000000000000000000091505b600082146105d75760408051600160a060020a03871681526020810184905281517fdcb278834ca505ad219cf8e4b5d11f026080abef6ec68e249ea5e4d9bb3dc7b2929181900390910190a1600092506105dc565b818360020203836064020460c80390505b92915050565b506000610d96565b8a54600160e060020a031960a060020a90910460e060020a021660001415610e1f578a5460028c0154600160a060020a039190911690895a03908d6001016000506040518082805460018160011615610100020316600290048015610ee15780601f10610eb657610100808354040283529160200191610ee1565b60018b8101546002918116156101000260001901160460001415610f16578a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491906040518360e060020a028152600401809050600060405180830381858988f19450505050508b60080160006101000a81548160ff02191690830217905550610ff6565b820191906000526020600020905b815481529060010190602001808311610ec457829003601f168201915b5050915050600060405180830381858888f193505050508b60080160006101000a81548160ff02191690830217905550610ff6565b8a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491908e6001016000506040518460e060020a0281526004018082805460018160011615610100020316600290048015610fc45780601f10610f9957610100808354040283529160200191610fc4565b820191906000526020600020905b815481529060010190602001808311610fa757829003601f168201915b5050915050600060405180830381858988f19450505050508b60080160006101000a81548160ff021916908302179055505b85600160a060020a031663938b5f326040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040805180517f75706461746544656661756c745061796d656e742829000000000000000000008252825191829003601601822060e060020a9081900490810283529251600160a060020a039190911693506004828101926000929190829003018183876161da5a03f150505060038c01546110ad91503a61038c565b60058c0154909550620100009004600160a060020a03908116908a1614156110db5760068b0154935061111d565b85600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051519450505b6064858502048b6007016000505401925060648587600160a060020a031663625cc4656040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001500204915060008b60070160005081905550865a8b03013a02905061119c898285016103ad565b92506111bc73d3cda913deb6f67967b99d67acdfa1712c293601836103ad565b6040805160088e01548482526020820187905281830184905260ff16151560608201529051919350600160a060020a038b16917f4538b7ec91dae8fada01e66a052482086d3e690c3db5a80457fbcd55457b4ae19181900360800190a25050505050505050505050565b600093505b505050919050565b600e1991909101908185111561128a5782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151945061122b9050565b60ef19909101908185111561122657818503905060f08184600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001500204935061122b56', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'Canary': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'aliveSince', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'heartbeat', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callContractAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'isAlive', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'scheduleHeartbeat', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'lastHeartbeat', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'initialize', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'owner', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'schedulerAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'heartbeatCount', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'cancel', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'frequency', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'inputs': [ - { - 'name': '_scheduler', - 'type': 'address', - }, - { - 'name': '_frequency', - 'type': 'uint16', - }, - ], - 'type': 'constructor', - }, - ], - 'code': '0x60606040818152806104d0833960a09052516080516005805460038054600160a060020a0319908116861790915574010000000000000000000000000000000000000000840260a060020a61ffff0219919092163317161790555050610467806100696000396000f3606060405236156100985760e060020a60003504633896002781146100e15780633defb962146100ea5780633f4be8891461010c5780634136aa351461011f5780634a420138146101a157806369c1a7121461028f5780638129fc1c146102985780638da5cb5b146102a9578063ae45850b146102bb578063af3309d8146102cf578063ea8a1af0146102d8578063ead50da3146102f6575b61030a671bc16d674ec8000030600160a060020a03163110156100df57600554604051600160a060020a03918216916000913091909116319082818181858883f150505050505b565b61030c60005481565b61030a671bc16d674ec8000030600160a060020a0316311015610373576100df565b610322600454600160a060020a03165b90565b6103415b60008054819011801561019a575060408051600480547f0a16697a0000000000000000000000000000000000000000000000000000000083529251600160a060020a039390931692630a16697a92828101926020929182900301816000876161da5a03f1156100025750506040515160ff01431090505b905061011c565b61030a5b600554604080516003547f8c0e156d0000000000000000000000000000000000000000000000000000000082527f3defb96200000000000000000000000000000000000000000000000000000000600483015260a060020a90930461ffff1643016024820152621e848060448201529051600092600160a060020a031691638c0e156d91671bc16d674ec8000091606480820192602092909190829003018185886185025a03f1156100025750506040515192505050600160a060020a03811660001461028c576004805473ffffffffffffffffffffffffffffffffffffffff1916821790555b50565b61030c60015481565b61030a60008054146103ba576100df565b610322600554600160a060020a031681565b610322600354600160a060020a031661011c565b61030c60025481565b61030a60055433600160a060020a039081169116146103c657610002565b61035960055460a060020a900461ffff1681565b005b6040518082815260200191505060405180910390f35b6040518082600160a060020a0316815260200191505060405180910390f35b60405180821515815260200191505060405180910390f35b604051808261ffff16815260200191505060405180910390f35b60045433600160a060020a0390811691161461038e576100df565b610396610123565b15156103a1576100df565b6103a96101a5565b600280546001908101909155429055565b426000556100df6101a5565b6004546000600160a060020a039190911631111561043c5760408051600480547fea8a1af00000000000000000000000000000000000000000000000000000000083529251600160a060020a03939093169263ea8a1af0928281019260009291829003018183876161da5a03f115610002575050505b600554604051600160a060020a03918216916000913091909116319082818181858883f1505050505056', - 'code_runtime': '0x606060405236156100985760e060020a60003504633896002781146100e15780633defb962146100ea5780633f4be8891461010c5780634136aa351461011f5780634a420138146101a157806369c1a7121461028f5780638129fc1c146102985780638da5cb5b146102a9578063ae45850b146102bb578063af3309d8146102cf578063ea8a1af0146102d8578063ead50da3146102f6575b61030a671bc16d674ec8000030600160a060020a03163110156100df57600554604051600160a060020a03918216916000913091909116319082818181858883f150505050505b565b61030c60005481565b61030a671bc16d674ec8000030600160a060020a0316311015610373576100df565b610322600454600160a060020a03165b90565b6103415b60008054819011801561019a575060408051600480547f0a16697a0000000000000000000000000000000000000000000000000000000083529251600160a060020a039390931692630a16697a92828101926020929182900301816000876161da5a03f1156100025750506040515160ff01431090505b905061011c565b61030a5b600554604080516003547f8c0e156d0000000000000000000000000000000000000000000000000000000082527f3defb96200000000000000000000000000000000000000000000000000000000600483015260a060020a90930461ffff1643016024820152621e848060448201529051600092600160a060020a031691638c0e156d91671bc16d674ec8000091606480820192602092909190829003018185886185025a03f1156100025750506040515192505050600160a060020a03811660001461028c576004805473ffffffffffffffffffffffffffffffffffffffff1916821790555b50565b61030c60015481565b61030a60008054146103ba576100df565b610322600554600160a060020a031681565b610322600354600160a060020a031661011c565b61030c60025481565b61030a60055433600160a060020a039081169116146103c657610002565b61035960055460a060020a900461ffff1681565b005b6040518082815260200191505060405180910390f35b6040518082600160a060020a0316815260200191505060405180910390f35b60405180821515815260200191505060405180910390f35b604051808261ffff16815260200191505060405180910390f35b60045433600160a060020a0390811691161461038e576100df565b610396610123565b15156103a1576100df565b6103a96101a5565b600280546001908101909155429055565b426000556100df6101a5565b6004546000600160a060020a039190911631111561043c5760408051600480547fea8a1af00000000000000000000000000000000000000000000000000000000083529251600160a060020a03939093169263ea8a1af0928281019260009291829003018183876161da5a03f115610002575050505b600554604051600160a060020a03918216916000913091909116319082818181858883f1505050505056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'ERC20ScheduledTransfer': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'spender', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'approve', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'totalSupply', - 'outputs': [ - { - 'name': 'supply', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'from', - 'type': 'address', - }, - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'transferFrom', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'who', - 'type': 'address', - }, - ], - 'name': 'balanceOf', - 'outputs': [ - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - { - 'name': 'when', - 'type': 'uint256', - }, - ], - 'name': 'scheduleTransfer', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'transfer', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'scheduler', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'owner', - 'type': 'address', - }, - { - 'name': 'spender', - 'type': 'address', - }, - ], - 'name': 'allowance', - 'outputs': [ - { - 'name': '_allowance', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'from', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'to', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Transfer', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'owner', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'spender', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Approval', - 'type': 'event', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'ERC20Token': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'spender', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'approve', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'totalSupply', - 'outputs': [ - { - 'name': 'supply', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'from', - 'type': 'address', - }, - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'transferFrom', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'who', - 'type': 'address', - }, - ], - 'name': 'balanceOf', - 'outputs': [ - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'transfer', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'owner', - 'type': 'address', - }, - { - 'name': 'spender', - 'type': 'address', - }, - ], - 'name': 'allowance', - 'outputs': [ - { - 'name': '_allowance', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'from', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'to', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Transfer', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'owner', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'spender', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Approval', - 'type': 'event', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'FutureBlockCall': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'wasSuccessful', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'targetBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'firstClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getExtraGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'n', - 'type': 'uint256', - }, - ], - 'name': '__dig', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'checkExecutionAuthorization', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'requiredStackDepth', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callAPIVersion', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimerDeposit', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'n', - 'type': 'uint256', - }, - ], - 'name': 'checkDepth', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'anchorGasPrice', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'isCancellable', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callData', - 'outputs': [ - { - 'name': '', - 'type': 'bytes', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'claim', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'execute', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'baseDonation', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getOverhead', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'startGas', - 'type': 'uint256', - }, - ], - 'name': 'beforeExecute', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimAmount', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'origin', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'isCancelled', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'requiredGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'gracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'lastClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'schedulerAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'registerData', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'state', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'basePayment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'wasCalled', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'abiSignature', - 'outputs': [ - { - 'name': '', - 'type': 'bytes4', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'maxClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimer', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callValue', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'cancel', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'contractAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'inputs': [ - { - 'name': '_schedulerAddress', - 'type': 'address', - }, - { - 'name': '_targetBlock', - 'type': 'uint256', - }, - { - 'name': '_gracePeriod', - 'type': 'uint8', - }, - { - 'name': '_contractAddress', - 'type': 'address', - }, - { - 'name': '_abiSignature', - 'type': 'bytes4', - }, - { - 'name': '_callData', - 'type': 'bytes', - }, - { - 'name': '_callValue', - 'type': 'uint256', - }, - { - 'name': '_requiredGas', - 'type': 'uint256', - }, - { - 'name': '_requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': '_basePayment', - 'type': 'uint256', - }, - { - 'name': '_baseDonation', - 'type': 'uint256', - }, - ], - 'type': 'constructor', - }, - ], - 'code': '0x606060405260405161112038038061112083398101604052805160805160a05160c05160e05161010051610120516101405161016051610180516101a051999a98999798969795969490940194929391929091908a84848a8a8a8a8888600c8054600160a060020a031990811633179091556000805482168b1781556001848155600284815560078c90556008805461ffff19168c1790553a600655600380547c01000000000000000000000000000000000000000000000000000000008b04740100000000000000000000000000000000000000000295168b1760a060020a63ffffffff021916949094179093556004805488519382905290936020601f9383161561010002600019019092160482018190047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b908101939290918901908390106101d757805160ff19168380011785555b5061016e9291505b80821115610207576000815560010161015a565b505060058390555050505050505050508a600060006101000a815481600160a060020a030219169083021790555089600d6000508190555088600e60006101000a81548160ff021916908302179055505050505050505050505050610f158061020b6000396000f35b82800160010185558215610152579182015b828111156101525782518260005055916020019190600101906101e9565b509056606060405236156101ab5760e060020a60003504630924120081146101d05780630a16697a146101dd5780630fd1f94e146101e6578063137c638b1461023a57806321835af61461024757806324032866146102605780632f95b833146102e05780633017fe24146102ef5780633233c686146102f9578063349501b71461030457806337f4c00e1461031d5780634500054f146103285780634e417a98146103995780634e71d92d146104025780634f059a43146104145780636146195414610470578063625cc4651461048057806367ce940d146104895780637d298ee314610496578063830953ab14610516578063938b5f321461052157806395ee122114610533578063974654f414610547578063a06db7dc14610552578063a9d2293d1461055e578063ae45850b146105b2578063b0f07e44146105c4578063c19d93fb146105e6578063c6502da814610647578063c680362214610650578063ca94692d14610664578063cc3471af1461068d578063d379be23146106e1578063d62457f6146106fb578063ea8a1af014610706578063f556275314610808578063f6b4dfb414610867575b61087b60008054819033600160a060020a0390811691161461088f57600091506109a4565b61087b600b5460ff165b90565b6109a8600d5481565b6109a8600073__CallLib_______________________________630fd1f94e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a85b62012cc86101da565b61087b60043560008160001415610aa957506001610ba9565b61087b600435602435600073__CallLib_______________________________630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b6109ba60085461ffff166101da565b6109a860026101da565b6109a8600a546101da565b61087b60043560008160001415610b3057506001610ba9565b6109a86006546101da565b61087b600073__CallLib_______________________________63a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109d160408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610bd95780601f10610bae57610100808354040283529160200191610bd9565b61087b60006000600180610be56105ea565b6109a8600073__CallLib_______________________________63f5562753436040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a3f6000600480610cfe6105ea565b6109a860025481565b6109a85b620186a06101da565b61087b6004356024355b600073__CallLib_______________________________63a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506102da9050565b6109a86009546101da565b610a41600c54600160a060020a031681565b61087b600b5462010000900460ff166101da565b6109a86007546101da565b610a5e600e5460ff1681565b6109a8600073__CallLib_______________________________63a9d2293d6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600054600160a060020a031681565b61087b600080548190600160a060020a039081163390911614610e25576109a4565b6109a85b600073__CallLib_______________________________635054d98a60036000506040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a860015481565b61087b600b5460ff610100909104166101da565b610a7460035474010000000000000000000000000000000000000000900460e060020a026101da565b6109a8600073__CallLib_______________________________63cc3471af6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600854620100009004600160a060020a03166101da565b6109a86005546101da565b610a3f604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________9163a094315491604480830192602092919082900301818660325a03f4156100025750506040515115905061080657604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________91637e92656291604482810192600092919082900301818660325a03f415610002575050505b565b6109a8600435600073__CallLib_______________________________63f5562753836040518260e060020a028152600401808281526020019150506020604051808303818660325a03f415610002575050604051519150610ba99050565b610a41600354600160a060020a03166101da565b604080519115158252519081900360200190f35b60045460006002600019600184161561010002019092169190910411156108b957600091506109a4565b6108c16105ea565b9050600081141580156108d5575060018114155b80156108e2575060028114155b156108f057600091506109a4565b6004805460008281527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6020601f6002600186161561010002600019019095169490940484010481019236929083901061096d5782800160ff198235161785555b5061099d9291505b808211156109a45760008155600101610959565b82800160010185558215610951579182015b8281111561095157823582600050559160200191906001019061097f565b5050600191505b5090565b60408051918252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f2925050501515610ba957610002565b604080517f5f5f6469672875696e74323536290000000000000000000000000000000000008152815190819003600e01812060e060020a90819004908102825260001985016004830152915130600160a060020a031692916102bc86029160248281019260009291908290030181838887f19450505050505b919050565b820191906000526020600020905b815481529060010190602001808311610bbc57829003601f168201915b505050505090506101da565b1415610ceb57604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a031660248301523460448301526064820152905173__CallLib_______________________________91630fee183d91608480830192602092919082900301818660325a03f41561000257505060405151925050811515610cf05773__AccountingLib_________________________6312c82bcc33346040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100025750506040515115159050610cf057610002565b505090565b819250506109a4565b505b50565b1415610cf9575a9150610d1133836104a0565b1515610d1d5750610cfb565b73__CallLib_______________________________63da46be0a60038433610d4361048d565b610d4b61023e565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a03168152602001838152602001828152602001955050505050506000604051808303818660325a03f41561000257505050610cf933604080516000547fc17e6817000000000000000000000000000000000000000000000000000000008252600160a060020a0390811660048301523016316024820152905173__CallLib_______________________________9163c17e681791604480830192602092919082900301818660325a03f4156100025750505050565b6004546000600260018316156101000260001901909216919091041115610e4f57600091506109a4565b610e576105ea565b905060008114158015610e6b575060018114155b8015610e78575060028114155b15610e8657600091506109a4565b604080517f7c0278fc00000000000000000000000000000000000000000000000000000000815260036004820181815260248301938452366044840181905273__CallLib_______________________________94637c0278fc94600093919060640184848082843782019150509450505050506000604051808303818660325a03f41561000257505050509056', - 'code_runtime': '0x606060405236156101ab5760e060020a60003504630924120081146101d05780630a16697a146101dd5780630fd1f94e146101e6578063137c638b1461023a57806321835af61461024757806324032866146102605780632f95b833146102e05780633017fe24146102ef5780633233c686146102f9578063349501b71461030457806337f4c00e1461031d5780634500054f146103285780634e417a98146103995780634e71d92d146104025780634f059a43146104145780636146195414610470578063625cc4651461048057806367ce940d146104895780637d298ee314610496578063830953ab14610516578063938b5f321461052157806395ee122114610533578063974654f414610547578063a06db7dc14610552578063a9d2293d1461055e578063ae45850b146105b2578063b0f07e44146105c4578063c19d93fb146105e6578063c6502da814610647578063c680362214610650578063ca94692d14610664578063cc3471af1461068d578063d379be23146106e1578063d62457f6146106fb578063ea8a1af014610706578063f556275314610808578063f6b4dfb414610867575b61087b60008054819033600160a060020a0390811691161461088f57600091506109a4565b61087b600b5460ff165b90565b6109a8600d5481565b6109a8600073__CallLib_______________________________630fd1f94e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a85b62012cc86101da565b61087b60043560008160001415610aa957506001610ba9565b61087b600435602435600073__CallLib_______________________________630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b6109ba60085461ffff166101da565b6109a860026101da565b6109a8600a546101da565b61087b60043560008160001415610b3057506001610ba9565b6109a86006546101da565b61087b600073__CallLib_______________________________63a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109d160408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610bd95780601f10610bae57610100808354040283529160200191610bd9565b61087b60006000600180610be56105ea565b6109a8600073__CallLib_______________________________63f5562753436040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a3f6000600480610cfe6105ea565b6109a860025481565b6109a85b620186a06101da565b61087b6004356024355b600073__CallLib_______________________________63a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506102da9050565b6109a86009546101da565b610a41600c54600160a060020a031681565b61087b600b5462010000900460ff166101da565b6109a86007546101da565b610a5e600e5460ff1681565b6109a8600073__CallLib_______________________________63a9d2293d6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600054600160a060020a031681565b61087b600080548190600160a060020a039081163390911614610e25576109a4565b6109a85b600073__CallLib_______________________________635054d98a60036000506040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a860015481565b61087b600b5460ff610100909104166101da565b610a7460035474010000000000000000000000000000000000000000900460e060020a026101da565b6109a8600073__CallLib_______________________________63cc3471af6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600854620100009004600160a060020a03166101da565b6109a86005546101da565b610a3f604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________9163a094315491604480830192602092919082900301818660325a03f4156100025750506040515115905061080657604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________91637e92656291604482810192600092919082900301818660325a03f415610002575050505b565b6109a8600435600073__CallLib_______________________________63f5562753836040518260e060020a028152600401808281526020019150506020604051808303818660325a03f415610002575050604051519150610ba99050565b610a41600354600160a060020a03166101da565b604080519115158252519081900360200190f35b60045460006002600019600184161561010002019092169190910411156108b957600091506109a4565b6108c16105ea565b9050600081141580156108d5575060018114155b80156108e2575060028114155b156108f057600091506109a4565b6004805460008281527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6020601f6002600186161561010002600019019095169490940484010481019236929083901061096d5782800160ff198235161785555b5061099d9291505b808211156109a45760008155600101610959565b82800160010185558215610951579182015b8281111561095157823582600050559160200191906001019061097f565b5050600191505b5090565b60408051918252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f2925050501515610ba957610002565b604080517f5f5f6469672875696e74323536290000000000000000000000000000000000008152815190819003600e01812060e060020a90819004908102825260001985016004830152915130600160a060020a031692916102bc86029160248281019260009291908290030181838887f19450505050505b919050565b820191906000526020600020905b815481529060010190602001808311610bbc57829003601f168201915b505050505090506101da565b1415610ceb57604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a031660248301523460448301526064820152905173__CallLib_______________________________91630fee183d91608480830192602092919082900301818660325a03f41561000257505060405151925050811515610cf05773__AccountingLib_________________________6312c82bcc33346040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100025750506040515115159050610cf057610002565b505090565b819250506109a4565b505b50565b1415610cf9575a9150610d1133836104a0565b1515610d1d5750610cfb565b73__CallLib_______________________________63da46be0a60038433610d4361048d565b610d4b61023e565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a03168152602001838152602001828152602001955050505050506000604051808303818660325a03f41561000257505050610cf933604080516000547fc17e6817000000000000000000000000000000000000000000000000000000008252600160a060020a0390811660048301523016316024820152905173__CallLib_______________________________9163c17e681791604480830192602092919082900301818660325a03f4156100025750505050565b6004546000600260018316156101000260001901909216919091041115610e4f57600091506109a4565b610e576105ea565b905060008114158015610e6b575060018114155b8015610e78575060028114155b15610e8657600091506109a4565b604080517f7c0278fc00000000000000000000000000000000000000000000000000000000815260036004820181815260248301938452366044840181905273__CallLib_______________________________94637c0278fc94600093919060640184848082843782019150509450505050506000604051808303818660325a03f41561000257505050509056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'FutureCall': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'wasSuccessful', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'firstClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getExtraGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'checkExecutionAuthorization', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'requiredStackDepth', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimerDeposit', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'anchorGasPrice', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callData', - 'outputs': [ - { - 'name': '', - 'type': 'bytes', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'claim', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'execute', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'baseDonation', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getOverhead', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'startGas', - 'type': 'uint256', - }, - ], - 'name': 'beforeExecute', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimAmount', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'origin', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'isCancelled', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'requiredGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'lastClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'schedulerAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'registerData', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'state', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'basePayment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'wasCalled', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'abiSignature', - 'outputs': [ - { - 'name': '', - 'type': 'bytes4', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'maxClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimer', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callValue', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'contractAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'inputs': [ - { - 'name': '_schedulerAddress', - 'type': 'address', - }, - { - 'name': '_requiredGas', - 'type': 'uint256', - }, - { - 'name': '_requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': '_contractAddress', - 'type': 'address', - }, - { - 'name': '_abiSignature', - 'type': 'bytes4', - }, - { - 'name': '_callData', - 'type': 'bytes', - }, - { - 'name': '_callValue', - 'type': 'uint256', - }, - { - 'name': '_basePayment', - 'type': 'uint256', - }, - { - 'name': '_baseDonation', - 'type': 'uint256', - }, - ], - 'type': 'constructor', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'GroveLib': { - 'abi': [ - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeRightChild', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeLeftChild', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeParent', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeValue', - 'outputs': [ - { - 'name': '', - 'type': 'int256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeHeight', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'remove', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - { - 'name': 'value', - 'type': 'int256', - }, - ], - 'name': 'insert', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeId', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNextNode', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getPreviousNode', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'operator', - 'type': 'bytes2', - }, - { - 'name': 'value', - 'type': 'int256', - }, - ], - 'name': 'query', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'exists', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x60606040526111ef806100126000396000f36503060000000050606060405236156100a05760e060020a60003504630e9f1a3c81146100a55780632b4096b4146100c95780636ec13982146100eb578063a3119e571461010d578063a749f19b1461012f578063ab7366f714610151578063bacd695814610184578063bfdf87c0146101c2578063c4144b26146101e1578063caa46c9c14610240578063e6ce3a6a1461029f578063ed5bd7ea146102c2575b610007565b6102e560043560243560008181526001830160205260409020600401545b92915050565b6102e560043560243560008181526001830160205260409020600301546100c3565b6102e560043560243560008181526001830160205260409020600201546100c3565b6102e560043560243560008181526001838101602052604090912001546100c3565b6102e560043560243560008181526001830160205260409020600501546100c3565b6102f76004356024355b60008181526001830160205260408120805482918291829190861461030d575b50505050505050565b6102f7600435602435604435600082815260018401602052604081205481908190819086141561060157604081206001015485141561069c5761017b565b6102e560043560243560008181526001830160205260409020546100c3565b6102e56004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156107205760009350610717565b6102e56004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156108e55760009350610717565b6102e560043560243560443582546000908181811415610aa55760009250610acc565b6102f96004356024356000818152600183016020526040812060050154116100c3565b60408051918252519081900360200190f35b005b604080519115158252519081900360200190f35b6003810154600014158061032657506004810154600014155b1561034c5760038101546000146103a357805460018801906000906103b8908a9061024a565b60028101546000146105c45760028101546000908152600188016020526040902060038101548254919550141561038557600060038501555b80546004850154141561039a57600060048501555b835491506105c9565b805460018801906000906103cf908a906101eb565b8152602081019190915260400160002094506103e2565b8152602081019190915260400160002094505b6002850154600090815260018801602052604090206003810154865491955090925082141561043d5760048501546003850181905560001461043d576004850154600090815260018801602052604090208454600282015592505b60048401548554141561049b5760038501546004850181905560001461049b57866001016000506000866003016000505460001916815260200190815260200160002060005092508250836000016000505483600201600050819055505b6002808201549086018190556000146105185786600101600050600082600201600050546000191681526020019081526020016000206000509350835080600001600050546000191684600301600050546000191614156104fe57845460038501555b60048401548154141561051357845460048501555b61051d565b845487555b60038082015490860181905560001461056e57866001016000506000826003016000505460001916815260200190815260200160002060005092508250846000016000505483600201600050819055505b6004818101549086018190556000146105bf57866001016000506000826004016000505460001916815260200190815260200160002060005092508250846000016000505483600201600050819055505b6105c9565b600087555b60008082556001820181905560028201819055600382018190556004820181905560058201819055821461017b5761017b8783610647565b865460009250821415610612578587555b508554600090815260018701602052604090205b8054600014156106a657858155600281018290556001810185905561017b87875b60008181526001830160205260408120905b8154610da59085905b60008181526001830160205260408082206004810154835281832060059081015460038301548552929093209092015403905b5092915050565b610601878761015b565b8054600182015490925085126106e4576004810154600014156106cb57600481018690555b6004015460009081526001870160205260409020610626565b6003810154600014156106f957600381018690555b6003015460009081526001870160205260409020610626565b815193505b50505092915050565b60048301546000146107f757600483810154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201529181015460808301526005015460a082015291505b606082015160001461071257606091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015493810193909352600481015460808401526005015460a0830152610789565b60028301546000146108805750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b8151600382015414156108725780549350610717565b600281015460001415610889575b60009350610717565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a084015260009485529089019052912090915061085c565b60038301546000146109bc57600380840154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252918101546060830152600481015460808301526005015460a082015291505b608082015160001461071257608091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201526004820154938101939093526005015460a083015261094e565b60028301546000146108805750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b815160048201541415610a375780549350610717565b600281015460001415610a4957610880565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a0840152600094855290890190529120909150610a21565b50600081815260018601602052604090205b6001810154610ad5908686610b28565b805492505b50509392505050565b15610c0d57600160f060020a0319851660fa60020a600f021480610b0a5750600160f060020a0319851660f060020a613c3d02145b15610b4f57600481015460001415610bb65780549250610acc565b86865b6000600160f060020a0319831660f960020a601f021415610ffc57508083135b9392505050565b600160f060020a0319851660f960020a601f021480610b7f5750600160f060020a0319851660f060020a613e3d02145b80610b9b5750600160f060020a0319851660f060020a613d3d02145b15610c0d57600381015460001415610c585780549250610acc565b610bef610b25878360040160005054600081815260018301602052604081205b6003810154600014156110895760018101549150610695565b15610ac7576004015460009081526001860160205260409020610ab7565b600160f060020a0319851660fa60020a600f021480610c3d5750600160f060020a0319851660f060020a613c3d02145b15610caf57600381015460001415610cfa5760009250610acc565b610c91610b25878360030160005054600081815260018301602052604081205b6004810154600014156110a25760018101549150610695565b15610ac7576003015460009081526001860160205260409020610ab7565b600160f060020a0319851660f960020a601f021480610cdf5750600160f060020a0319851660f060020a613e3d02145b15610d1357600481015460001415610d505760009250610acc565b6003015460009081526001860160205260409020610ab7565b600160f060020a0319851660f060020a613d3d021415610d8c57600181015484901215610d6957600481015460001415610d505760009250610acc565b6004015460009081526001860160205260409020610ab7565b600181015484901315610d8c57600381015460001415610cfa5760009250610acc565b610ab7565b600282015460001415610fe0575b50505050565b90508060021415610e3d57610dc1848360030160005054610662565b6000191415610ddb57610ddb848360030160005054610e15565b8154610e3d9085905b600081815260018301602052604081206003810154909190819081908114156110d057610007565b8154610e719085905b60008181526001830160205260408120600481015490919081908190811415610e9657610007565b806001191415610e7157610e58848360040160005054610662565b60011415610e0c57610e0c848360040160005054610de4565b8060001913158015610e84575060018113155b15610d91578154610d91908590610f9d565b6004840180546000908152600188016020526040812060028088015490820181905592829055945014610f3257856001016000506000856002016000505460001916815260200190815260200160002060005091508360000160005054600019168260030160005054600019161415610f1d57826000016000505482600301600050819055505b835460048301541415610f3257825460048301555b6003830154600014610f63575060038201546000908152600186016020526040902080546004850155835460028201555b82546002808601919091558454600385015583015460001415610f9457826000016000505486600001600050819055505b83546110bb9087905b60008181526001830160205260408082206003810154835281832060059081015460048301548552928420015490926111db9291908183106111e85750816100c3565b6002909101546000908152600184016020526040902090610659565b600160f060020a0319831660fa60020a600f02141561101e5750808312610b48565b60f060020a613e3d02600160f060020a031984161415611042575080831215610b48565b600160f060020a0319831660f060020a613c3d021415611066575080831315610b48565b600160f060020a0319831660f060020a613d3d0214156100a05750828114610b48565b6003015460009081526001840160205260409020610bd6565b6004015460009081526001840160205260409020610c78565b82546110c8908790610f9d565b505050505050565b600384018054600090815260018801602052604081206002808801549082018190559282905594501461116c5785600101600050600085600201600050546000191681526020019081526020016000206000509150836000016000505460001916826003016000505460001916141561115757826000016000505482600301600050819055505b83546004830154141561116c57825460048301555b600483015460001461119e57506004820154600081815260018701602052604090206003850191909155835460028201555b82546002808601919091558454600485015583015460001415610f94578260000160005054866000016000508190555083546110bb908790610f9d565b6001016005820155505050565b50806100c356', - 'code_runtime': '0x6503060000000050606060405236156100a05760e060020a60003504630e9f1a3c81146100a55780632b4096b4146100c95780636ec13982146100eb578063a3119e571461010d578063a749f19b1461012f578063ab7366f714610151578063bacd695814610184578063bfdf87c0146101c2578063c4144b26146101e1578063caa46c9c14610240578063e6ce3a6a1461029f578063ed5bd7ea146102c2575b610007565b6102e560043560243560008181526001830160205260409020600401545b92915050565b6102e560043560243560008181526001830160205260409020600301546100c3565b6102e560043560243560008181526001830160205260409020600201546100c3565b6102e560043560243560008181526001838101602052604090912001546100c3565b6102e560043560243560008181526001830160205260409020600501546100c3565b6102f76004356024355b60008181526001830160205260408120805482918291829190861461030d575b50505050505050565b6102f7600435602435604435600082815260018401602052604081205481908190819086141561060157604081206001015485141561069c5761017b565b6102e560043560243560008181526001830160205260409020546100c3565b6102e56004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156107205760009350610717565b6102e56004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156108e55760009350610717565b6102e560043560243560443582546000908181811415610aa55760009250610acc565b6102f96004356024356000818152600183016020526040812060050154116100c3565b60408051918252519081900360200190f35b005b604080519115158252519081900360200190f35b6003810154600014158061032657506004810154600014155b1561034c5760038101546000146103a357805460018801906000906103b8908a9061024a565b60028101546000146105c45760028101546000908152600188016020526040902060038101548254919550141561038557600060038501555b80546004850154141561039a57600060048501555b835491506105c9565b805460018801906000906103cf908a906101eb565b8152602081019190915260400160002094506103e2565b8152602081019190915260400160002094505b6002850154600090815260018801602052604090206003810154865491955090925082141561043d5760048501546003850181905560001461043d576004850154600090815260018801602052604090208454600282015592505b60048401548554141561049b5760038501546004850181905560001461049b57866001016000506000866003016000505460001916815260200190815260200160002060005092508250836000016000505483600201600050819055505b6002808201549086018190556000146105185786600101600050600082600201600050546000191681526020019081526020016000206000509350835080600001600050546000191684600301600050546000191614156104fe57845460038501555b60048401548154141561051357845460048501555b61051d565b845487555b60038082015490860181905560001461056e57866001016000506000826003016000505460001916815260200190815260200160002060005092508250846000016000505483600201600050819055505b6004818101549086018190556000146105bf57866001016000506000826004016000505460001916815260200190815260200160002060005092508250846000016000505483600201600050819055505b6105c9565b600087555b60008082556001820181905560028201819055600382018190556004820181905560058201819055821461017b5761017b8783610647565b865460009250821415610612578587555b508554600090815260018701602052604090205b8054600014156106a657858155600281018290556001810185905561017b87875b60008181526001830160205260408120905b8154610da59085905b60008181526001830160205260408082206004810154835281832060059081015460038301548552929093209092015403905b5092915050565b610601878761015b565b8054600182015490925085126106e4576004810154600014156106cb57600481018690555b6004015460009081526001870160205260409020610626565b6003810154600014156106f957600381018690555b6003015460009081526001870160205260409020610626565b815193505b50505092915050565b60048301546000146107f757600483810154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201529181015460808301526005015460a082015291505b606082015160001461071257606091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015493810193909352600481015460808401526005015460a0830152610789565b60028301546000146108805750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b8151600382015414156108725780549350610717565b600281015460001415610889575b60009350610717565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a084015260009485529089019052912090915061085c565b60038301546000146109bc57600380840154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252918101546060830152600481015460808301526005015460a082015291505b608082015160001461071257608091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201526004820154938101939093526005015460a083015261094e565b60028301546000146108805750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b815160048201541415610a375780549350610717565b600281015460001415610a4957610880565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a0840152600094855290890190529120909150610a21565b50600081815260018601602052604090205b6001810154610ad5908686610b28565b805492505b50509392505050565b15610c0d57600160f060020a0319851660fa60020a600f021480610b0a5750600160f060020a0319851660f060020a613c3d02145b15610b4f57600481015460001415610bb65780549250610acc565b86865b6000600160f060020a0319831660f960020a601f021415610ffc57508083135b9392505050565b600160f060020a0319851660f960020a601f021480610b7f5750600160f060020a0319851660f060020a613e3d02145b80610b9b5750600160f060020a0319851660f060020a613d3d02145b15610c0d57600381015460001415610c585780549250610acc565b610bef610b25878360040160005054600081815260018301602052604081205b6003810154600014156110895760018101549150610695565b15610ac7576004015460009081526001860160205260409020610ab7565b600160f060020a0319851660fa60020a600f021480610c3d5750600160f060020a0319851660f060020a613c3d02145b15610caf57600381015460001415610cfa5760009250610acc565b610c91610b25878360030160005054600081815260018301602052604081205b6004810154600014156110a25760018101549150610695565b15610ac7576003015460009081526001860160205260409020610ab7565b600160f060020a0319851660f960020a601f021480610cdf5750600160f060020a0319851660f060020a613e3d02145b15610d1357600481015460001415610d505760009250610acc565b6003015460009081526001860160205260409020610ab7565b600160f060020a0319851660f060020a613d3d021415610d8c57600181015484901215610d6957600481015460001415610d505760009250610acc565b6004015460009081526001860160205260409020610ab7565b600181015484901315610d8c57600381015460001415610cfa5760009250610acc565b610ab7565b600282015460001415610fe0575b50505050565b90508060021415610e3d57610dc1848360030160005054610662565b6000191415610ddb57610ddb848360030160005054610e15565b8154610e3d9085905b600081815260018301602052604081206003810154909190819081908114156110d057610007565b8154610e719085905b60008181526001830160205260408120600481015490919081908190811415610e9657610007565b806001191415610e7157610e58848360040160005054610662565b60011415610e0c57610e0c848360040160005054610de4565b8060001913158015610e84575060018113155b15610d91578154610d91908590610f9d565b6004840180546000908152600188016020526040812060028088015490820181905592829055945014610f3257856001016000506000856002016000505460001916815260200190815260200160002060005091508360000160005054600019168260030160005054600019161415610f1d57826000016000505482600301600050819055505b835460048301541415610f3257825460048301555b6003830154600014610f63575060038201546000908152600186016020526040902080546004850155835460028201555b82546002808601919091558454600385015583015460001415610f9457826000016000505486600001600050819055505b83546110bb9087905b60008181526001830160205260408082206003810154835281832060059081015460048301548552928420015490926111db9291908183106111e85750816100c3565b6002909101546000908152600184016020526040902090610659565b600160f060020a0319831660fa60020a600f02141561101e5750808312610b48565b60f060020a613e3d02600160f060020a031984161415611042575080831215610b48565b600160f060020a0319831660f060020a613c3d021415611066575080831315610b48565b600160f060020a0319831660f060020a613d3d0214156100a05750828114610b48565b6003015460009081526001840160205260409020610bd6565b6004015460009081526001840160205260409020610c78565b82546110c8908790610f9d565b505050505050565b600384018054600090815260018801602052604081206002808801549082018190559282905594501461116c5785600101600050600085600201600050546000191681526020019081526020016000206000509150836000016000505460001916826003016000505460001916141561115757826000016000505482600301600050819055505b83546004830154141561116c57825460048301555b600483015460001461119e57506004820154600081815260018701602052604090206003850191909155835460028201555b82546002808601919091558454600485015583015460001415610f94578260000160005054866000016000508190555083546110bb908790610f9d565b6001016005820155505050565b50806100c356', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'Scheduler': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'args', - 'type': 'uint256[5]', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMaximumCallGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callAPIVersion', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'callAddress', - 'type': 'address', - }, - ], - 'name': 'getNextCallSibling', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'callAddress', - 'type': 'address', - }, - ], - 'name': 'isKnownCall', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMaximumStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'callData', - 'type': 'bytes', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'args', - 'type': 'uint256[4]', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'defaultPayment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultGracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumCallGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getCallWindowSize', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'blockNumber', - 'type': 'uint256', - }, - ], - 'name': 'getNextCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'contractAddress', - 'type': 'address', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getFirstSchedulableBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultDonation', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumGracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultRequiredGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'updateDefaultPayment', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'inputs': [], - 'type': 'constructor', - }, - ], - 'code': '0x60606040526611c37937e080006000556126a48061001d6000396000f36060604052361561027c5760e060020a600035046301991313811461027e57806303d22885146102ca5780630450991814610323578063049ae734146103705780630ce46c43146103c35780630e8502391461060f578063112e39a8146106825780631b4fa6ab146106cf5780631e74a2d3146106dd57806326a7985a1461070a5780633017fe241461075e578063346cabbc14610767578063373a1bc3146107e05780633a9e7433146108295780633c2c21a0146108795780633d9ce89b146108c5578063480b70bd1461093a578063481078431461098957806348f0518714610a185780634c471cde14610a905780634db3da8314610b13578063523ccfa814610b59578063586a69fa14610be95780635a9f2def14610c3d57806364ee49fe14610cb657806367beaccb14610d0c5780636840246014610d7b578063795b9a6f14610dd15780637b55c8b514610e485780637c73f84614610ee85780638c0e156d14610f1b5780638c1d01c814610f675780638e46afa914610f70578063938c430714610fc5578063971c803f146111625780639772c982146111b757806398c9cdf41461123357806398e00e54146112885780639f927be7146112dc578063a00aede914611389578063a1c0539d146113d9578063aff21c651461144f578063b152f19e1461147a578063b549793d146114cf578063b5b33eda1461154f578063bbc6eb1f1461159f578063c0f68859146115af578063c3a2c0c314611603578063c43d05751461164d578063d8e5c04814611696578063dbfef71014611233578063e29fb547146116e9578063e6470fbe1461173c578063ea27a8811461174e578063ee77fe86146117ce578063f158458c1461184e575b005b61187f600435602435604435600073__SchedulerLib__________________________6350d4e411600160005033878760206040519081016040528060008152602001506119fc610f74565b61187f60043560243560443560643560843560a43560c435600073__SchedulerLib__________________________6350d4e4116001600050338b8a602060405190810160405280600081526020015089611a1a6106d3565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503385600060e060020a026020604051908101604052806000815260200150611c42610f74565b61187f600435602435604435606435608435600073__SchedulerLib__________________________6350d4e4116001600050338989602060405190810160405280600081526020015088611c676106d3565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750506040805160a08082019092529597963596608435969095506101449450925060a491506005908390839080828437509095505050505050604080518082018252600160a060020a03338116825288166020820152815160c0810190925260009173__SchedulerLib__________________________9163e3042c0f91600191908a908a9089908b90808b8b9090602002015181526020018b60016005811015610002579090602002015181526020018b60026005811015610002579090602002015181526020018b60036005811015610002579090602002015181526020018b6004600581101561000257909060200201518152602001348152602001506040518860e060020a02815260040180888152602001876002602002808383829060006004602084601f0104600302600f01f15090500186600160e060020a0319168152602001806020018560ff1681526020018461ffff168152602001836006602002808383829060006004602084601f0104600302600f01f1509050018281038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105dc5780820380516001836020036101000a031916815260200191505b50985050505050505050506020604051808303818660325a03f415610002575050604051519150505b9695505050505050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f9581359591946044949293909201918190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e411600133808787611e94610f74565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611eb9610f74565b61189b5b6000611ecc611166565b6118b2600073__SchedulerLib__________________________63ea27a881600060005054611ed36115a3565b6118b2600073__SchedulerLib__________________________6326a7985a6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b6118b260075b90565b604080516020606435600481810135601f810184900484028501840190955284845261187f948135946024803595604435956084949201919081908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e411600133898988611f2e610f74565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503386866020604051908101604052806000815260200150611e94610f74565b61187f600435602435604435606435600073__SchedulerLib__________________________6350d4e411600160005033338960206040519081016040528060008152602001508861205a6106d3565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e4116001600050338786602060405190810160405280600081526020015061206c610f74565b60408051602060248035600481810135601f810185900485028601850190965285855261187f95813595919460449492939092019181908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e4116001338088886119fc610f74565b61187f600435602435604435606435600073__SchedulerLib__________________________6350d4e41160016000503388886020604051908101604052806000815260200150612085610f74565b61187f600435604080517fc4144b2600000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a0383166024820152905160009173__GroveLib______________________________9163c4144b269160448181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b604080516020604435600481810135601f810184900484028501840190955284845261187f9481359460248035959394606494929391019181908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e41160013388888861209f610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f94813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a43560c435600073__SchedulerLib__________________________6350d4e4116001338b8b8b896120bd6106d3565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503333866020604051908101604052806000815260200150611c42610f74565b6118c46004355b604080517fed5bd7ea00000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a0383166024820152905160009173__GroveLib______________________________9163ed5bd7ea9160448181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b61189b600073__SchedulerLib__________________________63586a69fa6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f9581359591946044949293909201918190840183828082843750949650509335935050606435915050600073__SchedulerLib__________________________6350d4e411600133808989612085610f74565b61187f60043560243560443560643560843560a435600073__SchedulerLib__________________________6350d4e4116001600050338a896020604051908101604052806000815260200150886120ca6106d3565b6040805160206004803580820135601f810184900484028501840190955284845261187f949193602493909291840191908190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e411600133808587611c42610f74565b61187f60043560243560443560643560843560a435600073__SchedulerLib__________________________6350d4e4116001600050338a8a6020604051908101604052806000815260200150896121e76106d3565b604080516020606435600481810135601f810184900484028501840190955284845261187f94813594602480359560443595608494920191908190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e4116001338888876121f4610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f9481359460248035959394606494929391019181908401838280828437505060408051608080820190925295979635969561010495509350608492508591508390839080828437509095505050505050600073__SchedulerLib__________________________6350d4e4116001338989898961220d6106d3565b6118b2600435602435604435600073__SchedulerLib__________________________63ea27a881858585612226611237565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e41160016000503333886020604051908101604052806000815260200150612277610f74565b6118b260005481565b6118d85b600073__SchedulerLib__________________________638e46afa96040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a43560c43560e43561010435600073__SchedulerLib__________________________6350d4e411600160005033338e8e8d8f8e8e8e8e8e346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111285780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519b9a5050505050505050505050565b61189b5b600073__SchedulerLib__________________________63971c803f6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750949650509335935050608435915050600073__SchedulerLib__________________________6350d4e411600133898989612291610f74565b6118b25b600073__SchedulerLib__________________________6398c9cdf46040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b6118b2600073__SchedulerLib__________________________6398e00e546040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b61187f600435604080517fe6ce3a6a000000000000000000000000000000000000000000000000000000008152600160048201527f3e3d000000000000000000000000000000000000000000000000000000000000602482015260448101839052905160009173__GroveLib______________________________9163e6ce3a6a9160648181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503385600060e060020a0260206040519081016040528060008152602001506122ab610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e4116001338787876122bc610f74565b6118b2600435600073__SchedulerLib__________________________63ea27a881836122ce6115a3565b6118b25b600073__SchedulerLib__________________________63b152f19e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a435600073__SchedulerLib__________________________6350d4e411600133808b8b896121e76106d3565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503386600060e060020a026020604051908101604052806000815260200150612329610f74565b6118b25b60005460649004610764565b6118b2600073__SchedulerLib__________________________63c0f688596040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b61187f600073__SchedulerLib__________________________6350d4e41160016000503333600060e060020a02602060405190810160405280600081526020015061233c610f74565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503333876020604051908101604052806000815260200150612329610f74565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e41160016000503387600060e060020a02602060405190810160405280600081526020015061246d610f74565b61187f600435602435604435606435608435600073__SchedulerLib__________________________6350d4e411600160005033338a60206040519081016040528060008152602001508961247f6106d3565b61027c60006000600061248c33610b60565b6118b2600435602435604435606435600073__SchedulerLib__________________________63ea27a881868686866040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506120529050565b604080516020604435600481810135601f810184900484028501840190955284845261187f94813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a435600073__SchedulerLib__________________________6350d4e4116001338a8a8a886126416106d3565b6118b2600435602435600073__SchedulerLib__________________________63ea27a88184846000612653611237565b60408051600160a060020a039092168252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60408051918252519081900360200190f35b604080519115158252519081900360200190f35b6040805160ff9092168252519081900360200190f35b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c65780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b9392505050565b611a046106d3565b60008b611a0f611237565b6000546118ee6115a3565b8f8e8e8d611a266115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611afe5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519998505050505050505050565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611c0e5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b919050565b611c4a6106d3565b6000611c5461147e565b611c5c611237565b600054611b366115a3565b60008d8d600060005054611c796115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611d515780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f41561000257505060405151979650505050505050565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611e5f5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b611e9c6106d3565b6000611ea661147e565b611eae611237565b600054611d876115a3565b611ec16106d3565b60008b611c5c611237565b9050610764565b6000611edd611237565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506107649050565b611f366106d3565b8c8b611f40611237565b600054611c796115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156120235780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b949350505050565b60008d8d600060005054611f4b6115a3565b6120746106d3565b8b61207d61147e565b611a0f611237565b61208d6106d3565b60008c8c600060005054611f4b6115a3565b6120a76106d3565b60008b6120b2611237565b600054611f4b6115a3565b60008e8e8d611a266115a3565b8e8d8d6000600050546120db6115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156121b35780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f4156100025750506040515191506106059050565b60008e8e8d6120db6115a3565b6121fc6106d3565b8b61220561147e565b6120b2611237565b8a5160208c015160408d015160608e0151611c796115a3565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506119f59050565b61227f6106d3565b60008c8c6000600050546118ee6115a3565b6122996106d3565b60008c8c600060005054611c796115a3565b6122b36106d3565b8b611ea661147e565b6122c46106d3565b600061207d61147e565b60006122d8611237565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f415610002575050604051519150611c3d9050565b6123316106d3565b60008b611eae611237565b6123446106d3565b600061234e61147e565b612356611237565b6000546123616115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156124395780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f4156100025750506040515191506107649050565b6124756106d3565b8a8c611a0f611237565b60008e8e8d611c796115a3565b1561263c5733925082600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fc6803622000000000000000000000000000000000000000000000000000000008252915191945063c680362291600482810192602092919082900301816000876161da5a03f115610002575050604051519050801561257d575082600160a060020a031663d379be236040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151600160a060020a03166000141590505b80156125895750600082115b80156125985750600054600190115b1561263c578183600160a060020a031663830953ab6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151606402919091049150506042811180156125f95750600054829011155b15612613576000805461271061271190910204905561263c565b6021811080156126265750600054829010155b1561263c576000805461271061270f9091020490555b505050565b60008d8d6000600050546120db6115a3565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f415610002575050604051519150611e8e905056', - 'code_runtime': '0x6060604052361561027c5760e060020a600035046301991313811461027e57806303d22885146102ca5780630450991814610323578063049ae734146103705780630ce46c43146103c35780630e8502391461060f578063112e39a8146106825780631b4fa6ab146106cf5780631e74a2d3146106dd57806326a7985a1461070a5780633017fe241461075e578063346cabbc14610767578063373a1bc3146107e05780633a9e7433146108295780633c2c21a0146108795780633d9ce89b146108c5578063480b70bd1461093a578063481078431461098957806348f0518714610a185780634c471cde14610a905780634db3da8314610b13578063523ccfa814610b59578063586a69fa14610be95780635a9f2def14610c3d57806364ee49fe14610cb657806367beaccb14610d0c5780636840246014610d7b578063795b9a6f14610dd15780637b55c8b514610e485780637c73f84614610ee85780638c0e156d14610f1b5780638c1d01c814610f675780638e46afa914610f70578063938c430714610fc5578063971c803f146111625780639772c982146111b757806398c9cdf41461123357806398e00e54146112885780639f927be7146112dc578063a00aede914611389578063a1c0539d146113d9578063aff21c651461144f578063b152f19e1461147a578063b549793d146114cf578063b5b33eda1461154f578063bbc6eb1f1461159f578063c0f68859146115af578063c3a2c0c314611603578063c43d05751461164d578063d8e5c04814611696578063dbfef71014611233578063e29fb547146116e9578063e6470fbe1461173c578063ea27a8811461174e578063ee77fe86146117ce578063f158458c1461184e575b005b61187f600435602435604435600073__SchedulerLib__________________________6350d4e411600160005033878760206040519081016040528060008152602001506119fc610f74565b61187f60043560243560443560643560843560a43560c435600073__SchedulerLib__________________________6350d4e4116001600050338b8a602060405190810160405280600081526020015089611a1a6106d3565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503385600060e060020a026020604051908101604052806000815260200150611c42610f74565b61187f600435602435604435606435608435600073__SchedulerLib__________________________6350d4e4116001600050338989602060405190810160405280600081526020015088611c676106d3565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750506040805160a08082019092529597963596608435969095506101449450925060a491506005908390839080828437509095505050505050604080518082018252600160a060020a03338116825288166020820152815160c0810190925260009173__SchedulerLib__________________________9163e3042c0f91600191908a908a9089908b90808b8b9090602002015181526020018b60016005811015610002579090602002015181526020018b60026005811015610002579090602002015181526020018b60036005811015610002579090602002015181526020018b6004600581101561000257909060200201518152602001348152602001506040518860e060020a02815260040180888152602001876002602002808383829060006004602084601f0104600302600f01f15090500186600160e060020a0319168152602001806020018560ff1681526020018461ffff168152602001836006602002808383829060006004602084601f0104600302600f01f1509050018281038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105dc5780820380516001836020036101000a031916815260200191505b50985050505050505050506020604051808303818660325a03f415610002575050604051519150505b9695505050505050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f9581359591946044949293909201918190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e411600133808787611e94610f74565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611eb9610f74565b61189b5b6000611ecc611166565b6118b2600073__SchedulerLib__________________________63ea27a881600060005054611ed36115a3565b6118b2600073__SchedulerLib__________________________6326a7985a6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b6118b260075b90565b604080516020606435600481810135601f810184900484028501840190955284845261187f948135946024803595604435956084949201919081908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e411600133898988611f2e610f74565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503386866020604051908101604052806000815260200150611e94610f74565b61187f600435602435604435606435600073__SchedulerLib__________________________6350d4e411600160005033338960206040519081016040528060008152602001508861205a6106d3565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e4116001600050338786602060405190810160405280600081526020015061206c610f74565b60408051602060248035600481810135601f810185900485028601850190965285855261187f95813595919460449492939092019181908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e4116001338088886119fc610f74565b61187f600435602435604435606435600073__SchedulerLib__________________________6350d4e41160016000503388886020604051908101604052806000815260200150612085610f74565b61187f600435604080517fc4144b2600000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a0383166024820152905160009173__GroveLib______________________________9163c4144b269160448181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b604080516020604435600481810135601f810184900484028501840190955284845261187f9481359460248035959394606494929391019181908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e41160013388888861209f610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f94813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a43560c435600073__SchedulerLib__________________________6350d4e4116001338b8b8b896120bd6106d3565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503333866020604051908101604052806000815260200150611c42610f74565b6118c46004355b604080517fed5bd7ea00000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a0383166024820152905160009173__GroveLib______________________________9163ed5bd7ea9160448181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b61189b600073__SchedulerLib__________________________63586a69fa6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f9581359591946044949293909201918190840183828082843750949650509335935050606435915050600073__SchedulerLib__________________________6350d4e411600133808989612085610f74565b61187f60043560243560443560643560843560a435600073__SchedulerLib__________________________6350d4e4116001600050338a896020604051908101604052806000815260200150886120ca6106d3565b6040805160206004803580820135601f810184900484028501840190955284845261187f949193602493909291840191908190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e411600133808587611c42610f74565b61187f60043560243560443560643560843560a435600073__SchedulerLib__________________________6350d4e4116001600050338a8a6020604051908101604052806000815260200150896121e76106d3565b604080516020606435600481810135601f810184900484028501840190955284845261187f94813594602480359560443595608494920191908190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e4116001338888876121f4610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f9481359460248035959394606494929391019181908401838280828437505060408051608080820190925295979635969561010495509350608492508591508390839080828437509095505050505050600073__SchedulerLib__________________________6350d4e4116001338989898961220d6106d3565b6118b2600435602435604435600073__SchedulerLib__________________________63ea27a881858585612226611237565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e41160016000503333886020604051908101604052806000815260200150612277610f74565b6118b260005481565b6118d85b600073__SchedulerLib__________________________638e46afa96040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a43560c43560e43561010435600073__SchedulerLib__________________________6350d4e411600160005033338e8e8d8f8e8e8e8e8e346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111285780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519b9a5050505050505050505050565b61189b5b600073__SchedulerLib__________________________63971c803f6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750949650509335935050608435915050600073__SchedulerLib__________________________6350d4e411600133898989612291610f74565b6118b25b600073__SchedulerLib__________________________6398c9cdf46040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b6118b2600073__SchedulerLib__________________________6398e00e546040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b61187f600435604080517fe6ce3a6a000000000000000000000000000000000000000000000000000000008152600160048201527f3e3d000000000000000000000000000000000000000000000000000000000000602482015260448101839052905160009173__GroveLib______________________________9163e6ce3a6a9160648181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503385600060e060020a0260206040519081016040528060008152602001506122ab610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e4116001338787876122bc610f74565b6118b2600435600073__SchedulerLib__________________________63ea27a881836122ce6115a3565b6118b25b600073__SchedulerLib__________________________63b152f19e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a435600073__SchedulerLib__________________________6350d4e411600133808b8b896121e76106d3565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503386600060e060020a026020604051908101604052806000815260200150612329610f74565b6118b25b60005460649004610764565b6118b2600073__SchedulerLib__________________________63c0f688596040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b61187f600073__SchedulerLib__________________________6350d4e41160016000503333600060e060020a02602060405190810160405280600081526020015061233c610f74565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503333876020604051908101604052806000815260200150612329610f74565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e41160016000503387600060e060020a02602060405190810160405280600081526020015061246d610f74565b61187f600435602435604435606435608435600073__SchedulerLib__________________________6350d4e411600160005033338a60206040519081016040528060008152602001508961247f6106d3565b61027c60006000600061248c33610b60565b6118b2600435602435604435606435600073__SchedulerLib__________________________63ea27a881868686866040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506120529050565b604080516020604435600481810135601f810184900484028501840190955284845261187f94813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a435600073__SchedulerLib__________________________6350d4e4116001338a8a8a886126416106d3565b6118b2600435602435600073__SchedulerLib__________________________63ea27a88184846000612653611237565b60408051600160a060020a039092168252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60408051918252519081900360200190f35b604080519115158252519081900360200190f35b6040805160ff9092168252519081900360200190f35b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c65780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b9392505050565b611a046106d3565b60008b611a0f611237565b6000546118ee6115a3565b8f8e8e8d611a266115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611afe5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519998505050505050505050565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611c0e5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b919050565b611c4a6106d3565b6000611c5461147e565b611c5c611237565b600054611b366115a3565b60008d8d600060005054611c796115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611d515780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f41561000257505060405151979650505050505050565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611e5f5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b611e9c6106d3565b6000611ea661147e565b611eae611237565b600054611d876115a3565b611ec16106d3565b60008b611c5c611237565b9050610764565b6000611edd611237565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506107649050565b611f366106d3565b8c8b611f40611237565b600054611c796115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156120235780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b949350505050565b60008d8d600060005054611f4b6115a3565b6120746106d3565b8b61207d61147e565b611a0f611237565b61208d6106d3565b60008c8c600060005054611f4b6115a3565b6120a76106d3565b60008b6120b2611237565b600054611f4b6115a3565b60008e8e8d611a266115a3565b8e8d8d6000600050546120db6115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156121b35780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f4156100025750506040515191506106059050565b60008e8e8d6120db6115a3565b6121fc6106d3565b8b61220561147e565b6120b2611237565b8a5160208c015160408d015160608e0151611c796115a3565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506119f59050565b61227f6106d3565b60008c8c6000600050546118ee6115a3565b6122996106d3565b60008c8c600060005054611c796115a3565b6122b36106d3565b8b611ea661147e565b6122c46106d3565b600061207d61147e565b60006122d8611237565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f415610002575050604051519150611c3d9050565b6123316106d3565b60008b611eae611237565b6123446106d3565b600061234e61147e565b612356611237565b6000546123616115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156124395780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f4156100025750506040515191506107649050565b6124756106d3565b8a8c611a0f611237565b60008e8e8d611c796115a3565b1561263c5733925082600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fc6803622000000000000000000000000000000000000000000000000000000008252915191945063c680362291600482810192602092919082900301816000876161da5a03f115610002575050604051519050801561257d575082600160a060020a031663d379be236040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151600160a060020a03166000141590505b80156125895750600082115b80156125985750600054600190115b1561263c578183600160a060020a031663830953ab6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151606402919091049150506042811180156125f95750600054829011155b15612613576000805461271061271190910204905561263c565b6021811080156126265750600054829010155b1561263c576000805461271061270f9091020490555b505050565b60008d8d6000600050546120db6115a3565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f415610002575050604051519150611e8e905056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'SchedulerAPI': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'SchedulerInterface': { - 'abi': [ - { - 'constant': True, - 'inputs': [ - { - 'name': 'callAddress', - 'type': 'address', - }, - ], - 'name': 'isKnownCall', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'SchedulerLib': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'getMaximumCallGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'callIndex', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'schedulerAddress', - 'type': 'address', - }, - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - { - 'name': 'endowment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'version', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - { - 'name': '', - 'type': 'uint16', - }, - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMaximumStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultGracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumCallCost', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumCallGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getCallWindowSize', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getFirstSchedulableBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumGracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'callIndex', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'addresses', - 'type': 'address[2]', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': 'uints', - 'type': 'uint256[6]', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': 'endowment', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': False, - 'name': 'call_address', - 'type': 'address', - }, - ], - 'name': 'CallScheduled', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'schedulerAddress', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'reason', - 'type': 'bytes32', - }, - ], - 'name': 'CallRejected', - 'type': 'event', - }, - ], - 'code': '0x6060604052611a4c806100126000396000f36503060000000050606060405236156100ab5760e060020a600035046326a7985a81146100b057806350d4e411146100be57806354fd4d501461023d578063586a69fa1461025d5780638e46afa91461026857806396cff3df14610272578063971c803f1461029657806398c9cdf4146102a157806398e00e54146102ae578063b152f19e146102b8578063c0f68859146102c4578063e3042c0f146102cf578063ea27a88114610476575b610007565b6102845b60006104e36102a5565b604080516020601f608435600481810135928301849004840285018401909552818452610497948035946024803595604435956064359560a494930191819084018382808284375094965050933593505060c43591505060e435610104356101243561014435610164356101843560006101806040519081016040528060008152602001600081526020016000815260200160206040519081016040528060008152602001508152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200150610180604051908101604052808f81526020018e81526020018d81526020018c81526020018981526020018b81526020018a81526020018881526020018781526020018681526020018581526020018481526020015090506104ec8f825b600060006000600a43018460e0015110156105f4577f544f4f5f534f4f4e000000000000000000000000000000000000000000000000915061053c565b604080516000808252600760208301528183015290519081900360600190f35b6104b45b6103e85b90565b6104cc60ff610265565b62030d403a0260026024356004350102015b60408051918252519081900360200190f35b6104b45b600a610265565b6102845b62030d40610265565b6102846010610265565b61028443600a01610265565b6102845b6020610265565b604080518082018252610497916004803592909160649190602490600290839083908082843780516020601f608435808c01359182018390048302840183019094528083529499983598975060a49650909450910191908190840183828082843750506040805160c0818101909252959796359660c435969095506101a49450925060e491506006908390839080828437509095505050505050604080516101808181018352600080835260208381018290528385018290528451908101855281815260608401526080830181905260a0830181905260c0830181905260e0830181905261010083018190526101208301819052610140830181905261016083018190528351918201909352808984602090810290910151825201896001602090810290910151825281018990526040810188905260600184600060209081029091015182528101879052604081018690526060018460016020908102909101518252018460026020908102909101518252018460036020908102909101518252018460046020908102909101518252018460056020020151905290506104ff8982610200565b6102846004356024356044356064355b3a0292909101600202919091010190565b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b6040805160ff929092168252519081900360200190f35b45039050610265565b9f9e505050505050505050505050505050565b9998505050505050505050565b846101600151101561053c577f494e53554646494349454e545f46554e4453000000000000000000000000000091505b60008214610703576040805185518482529151600160a060020a0392909216917f513485fc54ef019ef1bc1ea683ef7d5d522f2865224ae10871ff992749c0ba4f9181900360200190a273__AccountingLib_________________________6312c82bcc85600001518661016001516040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f415610007575050505b505092915050565b8360c0015161ffff1661060561029a565b61ffff1611806106275750610618610261565b61ffff168460c0015161ffff16115b15610654577f535441434b5f434845434b5f4f55545f4f465f52414e47450000000000000000915061053c565b61065c6102c8565b8460a0015160ff161015610692577f47524143455f544f4f5f53484f52540000000000000000000000000000000000915061053c565b61069a6102a5565b84610100015110806106b757506106af6100b4565b846101000151115b156106e4577f52455155495245445f4741535f4f55545f4f465f52414e474500000000000000915061053c565b61050c8461012001518561014001518660800151876101000151610486565b83610160015184600001518560e001518660a001518760200151886040015189606001518a608001518b61010001518c60c001518d61012001518e61014001516040516111208061092c833901808c600160a060020a031681526020018b81526020018a60ff16815260200189600160a060020a03168152602001887bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001806020018781526020018681526020018561ffff1681526020018481526020018381526020018281038252888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156108215780820380516001836020036101000a031916815260200191505b509c505050505050505050505050506040518091039082f09050905073__GroveLib______________________________63bacd69588683600160a060020a031660010284600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060408051805160e060020a87028252600482019590955260248101939093526044830193909352509051606482810192600092919082900301818660325a03f41561000757505060408051600160a060020a038416815290517f2b05d346f0b0b9fd470024751c52d3b5dac5c37796f077c1a66241f2eada44b792509081900360200190a18092506105ec56606060405260405161112038038061112083398101604052805160805160a05160c05160e05161010051610120516101405161016051610180516101a051999a98999798969795969490940194929391929091908a84848a8a8a8a8888600c8054600160a060020a031990811633179091556000805482168b1781556001848155600284815560078c90556008805461ffff19168c1790553a600655600380547c01000000000000000000000000000000000000000000000000000000008b04740100000000000000000000000000000000000000000295168b1760a060020a63ffffffff021916949094179093556004805488519382905290936020601f9383161561010002600019019092160482018190047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b908101939290918901908390106101d757805160ff19168380011785555b5061016e9291505b80821115610207576000815560010161015a565b505060058390555050505050505050508a600060006101000a815481600160a060020a030219169083021790555089600d6000508190555088600e60006101000a81548160ff021916908302179055505050505050505050505050610f158061020b6000396000f35b82800160010185558215610152579182015b828111156101525782518260005055916020019190600101906101e9565b509056606060405236156101ab5760e060020a60003504630924120081146101d05780630a16697a146101dd5780630fd1f94e146101e6578063137c638b1461023a57806321835af61461024757806324032866146102605780632f95b833146102e05780633017fe24146102ef5780633233c686146102f9578063349501b71461030457806337f4c00e1461031d5780634500054f146103285780634e417a98146103995780634e71d92d146104025780634f059a43146104145780636146195414610470578063625cc4651461048057806367ce940d146104895780637d298ee314610496578063830953ab14610516578063938b5f321461052157806395ee122114610533578063974654f414610547578063a06db7dc14610552578063a9d2293d1461055e578063ae45850b146105b2578063b0f07e44146105c4578063c19d93fb146105e6578063c6502da814610647578063c680362214610650578063ca94692d14610664578063cc3471af1461068d578063d379be23146106e1578063d62457f6146106fb578063ea8a1af014610706578063f556275314610808578063f6b4dfb414610867575b61087b60008054819033600160a060020a0390811691161461088f57600091506109a4565b61087b600b5460ff165b90565b6109a8600d5481565b6109a8600073__CallLib_______________________________630fd1f94e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a85b62012cc86101da565b61087b60043560008160001415610aa957506001610ba9565b61087b600435602435600073__CallLib_______________________________630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b6109ba60085461ffff166101da565b6109a860026101da565b6109a8600a546101da565b61087b60043560008160001415610b3057506001610ba9565b6109a86006546101da565b61087b600073__CallLib_______________________________63a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109d160408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610bd95780601f10610bae57610100808354040283529160200191610bd9565b61087b60006000600180610be56105ea565b6109a8600073__CallLib_______________________________63f5562753436040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a3f6000600480610cfe6105ea565b6109a860025481565b6109a85b620186a06101da565b61087b6004356024355b600073__CallLib_______________________________63a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506102da9050565b6109a86009546101da565b610a41600c54600160a060020a031681565b61087b600b5462010000900460ff166101da565b6109a86007546101da565b610a5e600e5460ff1681565b6109a8600073__CallLib_______________________________63a9d2293d6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600054600160a060020a031681565b61087b600080548190600160a060020a039081163390911614610e25576109a4565b6109a85b600073__CallLib_______________________________635054d98a60036000506040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a860015481565b61087b600b5460ff610100909104166101da565b610a7460035474010000000000000000000000000000000000000000900460e060020a026101da565b6109a8600073__CallLib_______________________________63cc3471af6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600854620100009004600160a060020a03166101da565b6109a86005546101da565b610a3f604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________9163a094315491604480830192602092919082900301818660325a03f4156100025750506040515115905061080657604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________91637e92656291604482810192600092919082900301818660325a03f415610002575050505b565b6109a8600435600073__CallLib_______________________________63f5562753836040518260e060020a028152600401808281526020019150506020604051808303818660325a03f415610002575050604051519150610ba99050565b610a41600354600160a060020a03166101da565b604080519115158252519081900360200190f35b60045460006002600019600184161561010002019092169190910411156108b957600091506109a4565b6108c16105ea565b9050600081141580156108d5575060018114155b80156108e2575060028114155b156108f057600091506109a4565b6004805460008281527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6020601f6002600186161561010002600019019095169490940484010481019236929083901061096d5782800160ff198235161785555b5061099d9291505b808211156109a45760008155600101610959565b82800160010185558215610951579182015b8281111561095157823582600050559160200191906001019061097f565b5050600191505b5090565b60408051918252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f2925050501515610ba957610002565b604080517f5f5f6469672875696e74323536290000000000000000000000000000000000008152815190819003600e01812060e060020a90819004908102825260001985016004830152915130600160a060020a031692916102bc86029160248281019260009291908290030181838887f19450505050505b919050565b820191906000526020600020905b815481529060010190602001808311610bbc57829003601f168201915b505050505090506101da565b1415610ceb57604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a031660248301523460448301526064820152905173__CallLib_______________________________91630fee183d91608480830192602092919082900301818660325a03f41561000257505060405151925050811515610cf05773__AccountingLib_________________________6312c82bcc33346040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100025750506040515115159050610cf057610002565b505090565b819250506109a4565b505b50565b1415610cf9575a9150610d1133836104a0565b1515610d1d5750610cfb565b73__CallLib_______________________________63da46be0a60038433610d4361048d565b610d4b61023e565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a03168152602001838152602001828152602001955050505050506000604051808303818660325a03f41561000257505050610cf933604080516000547fc17e6817000000000000000000000000000000000000000000000000000000008252600160a060020a0390811660048301523016316024820152905173__CallLib_______________________________9163c17e681791604480830192602092919082900301818660325a03f4156100025750505050565b6004546000600260018316156101000260001901909216919091041115610e4f57600091506109a4565b610e576105ea565b905060008114158015610e6b575060018114155b8015610e78575060028114155b15610e8657600091506109a4565b604080517f7c0278fc00000000000000000000000000000000000000000000000000000000815260036004820181815260248301938452366044840181905273__CallLib_______________________________94637c0278fc94600093919060640184848082843782019150509450505050506000604051808303818660325a03f41561000257505050509056', - 'code_runtime': '0x6503060000000050606060405236156100ab5760e060020a600035046326a7985a81146100b057806350d4e411146100be57806354fd4d501461023d578063586a69fa1461025d5780638e46afa91461026857806396cff3df14610272578063971c803f1461029657806398c9cdf4146102a157806398e00e54146102ae578063b152f19e146102b8578063c0f68859146102c4578063e3042c0f146102cf578063ea27a88114610476575b610007565b6102845b60006104e36102a5565b604080516020601f608435600481810135928301849004840285018401909552818452610497948035946024803595604435956064359560a494930191819084018382808284375094965050933593505060c43591505060e435610104356101243561014435610164356101843560006101806040519081016040528060008152602001600081526020016000815260200160206040519081016040528060008152602001508152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200150610180604051908101604052808f81526020018e81526020018d81526020018c81526020018981526020018b81526020018a81526020018881526020018781526020018681526020018581526020018481526020015090506104ec8f825b600060006000600a43018460e0015110156105f4577f544f4f5f534f4f4e000000000000000000000000000000000000000000000000915061053c565b604080516000808252600760208301528183015290519081900360600190f35b6104b45b6103e85b90565b6104cc60ff610265565b62030d403a0260026024356004350102015b60408051918252519081900360200190f35b6104b45b600a610265565b6102845b62030d40610265565b6102846010610265565b61028443600a01610265565b6102845b6020610265565b604080518082018252610497916004803592909160649190602490600290839083908082843780516020601f608435808c01359182018390048302840183019094528083529499983598975060a49650909450910191908190840183828082843750506040805160c0818101909252959796359660c435969095506101a49450925060e491506006908390839080828437509095505050505050604080516101808181018352600080835260208381018290528385018290528451908101855281815260608401526080830181905260a0830181905260c0830181905260e0830181905261010083018190526101208301819052610140830181905261016083018190528351918201909352808984602090810290910151825201896001602090810290910151825281018990526040810188905260600184600060209081029091015182528101879052604081018690526060018460016020908102909101518252018460026020908102909101518252018460036020908102909101518252018460046020908102909101518252018460056020020151905290506104ff8982610200565b6102846004356024356044356064355b3a0292909101600202919091010190565b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b6040805160ff929092168252519081900360200190f35b45039050610265565b9f9e505050505050505050505050505050565b9998505050505050505050565b846101600151101561053c577f494e53554646494349454e545f46554e4453000000000000000000000000000091505b60008214610703576040805185518482529151600160a060020a0392909216917f513485fc54ef019ef1bc1ea683ef7d5d522f2865224ae10871ff992749c0ba4f9181900360200190a273__AccountingLib_________________________6312c82bcc85600001518661016001516040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f415610007575050505b505092915050565b8360c0015161ffff1661060561029a565b61ffff1611806106275750610618610261565b61ffff168460c0015161ffff16115b15610654577f535441434b5f434845434b5f4f55545f4f465f52414e47450000000000000000915061053c565b61065c6102c8565b8460a0015160ff161015610692577f47524143455f544f4f5f53484f52540000000000000000000000000000000000915061053c565b61069a6102a5565b84610100015110806106b757506106af6100b4565b846101000151115b156106e4577f52455155495245445f4741535f4f55545f4f465f52414e474500000000000000915061053c565b61050c8461012001518561014001518660800151876101000151610486565b83610160015184600001518560e001518660a001518760200151886040015189606001518a608001518b61010001518c60c001518d61012001518e61014001516040516111208061092c833901808c600160a060020a031681526020018b81526020018a60ff16815260200189600160a060020a03168152602001887bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001806020018781526020018681526020018561ffff1681526020018481526020018381526020018281038252888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156108215780820380516001836020036101000a031916815260200191505b509c505050505050505050505050506040518091039082f09050905073__GroveLib______________________________63bacd69588683600160a060020a031660010284600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060408051805160e060020a87028252600482019590955260248101939093526044830193909352509051606482810192600092919082900301818660325a03f41561000757505060408051600160a060020a038416815290517f2b05d346f0b0b9fd470024751c52d3b5dac5c37796f077c1a66241f2eada44b792509081900360200190a18092506105ec56606060405260405161112038038061112083398101604052805160805160a05160c05160e05161010051610120516101405161016051610180516101a051999a98999798969795969490940194929391929091908a84848a8a8a8a8888600c8054600160a060020a031990811633179091556000805482168b1781556001848155600284815560078c90556008805461ffff19168c1790553a600655600380547c01000000000000000000000000000000000000000000000000000000008b04740100000000000000000000000000000000000000000295168b1760a060020a63ffffffff021916949094179093556004805488519382905290936020601f9383161561010002600019019092160482018190047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b908101939290918901908390106101d757805160ff19168380011785555b5061016e9291505b80821115610207576000815560010161015a565b505060058390555050505050505050508a600060006101000a815481600160a060020a030219169083021790555089600d6000508190555088600e60006101000a81548160ff021916908302179055505050505050505050505050610f158061020b6000396000f35b82800160010185558215610152579182015b828111156101525782518260005055916020019190600101906101e9565b509056606060405236156101ab5760e060020a60003504630924120081146101d05780630a16697a146101dd5780630fd1f94e146101e6578063137c638b1461023a57806321835af61461024757806324032866146102605780632f95b833146102e05780633017fe24146102ef5780633233c686146102f9578063349501b71461030457806337f4c00e1461031d5780634500054f146103285780634e417a98146103995780634e71d92d146104025780634f059a43146104145780636146195414610470578063625cc4651461048057806367ce940d146104895780637d298ee314610496578063830953ab14610516578063938b5f321461052157806395ee122114610533578063974654f414610547578063a06db7dc14610552578063a9d2293d1461055e578063ae45850b146105b2578063b0f07e44146105c4578063c19d93fb146105e6578063c6502da814610647578063c680362214610650578063ca94692d14610664578063cc3471af1461068d578063d379be23146106e1578063d62457f6146106fb578063ea8a1af014610706578063f556275314610808578063f6b4dfb414610867575b61087b60008054819033600160a060020a0390811691161461088f57600091506109a4565b61087b600b5460ff165b90565b6109a8600d5481565b6109a8600073__CallLib_______________________________630fd1f94e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a85b62012cc86101da565b61087b60043560008160001415610aa957506001610ba9565b61087b600435602435600073__CallLib_______________________________630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b6109ba60085461ffff166101da565b6109a860026101da565b6109a8600a546101da565b61087b60043560008160001415610b3057506001610ba9565b6109a86006546101da565b61087b600073__CallLib_______________________________63a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109d160408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610bd95780601f10610bae57610100808354040283529160200191610bd9565b61087b60006000600180610be56105ea565b6109a8600073__CallLib_______________________________63f5562753436040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a3f6000600480610cfe6105ea565b6109a860025481565b6109a85b620186a06101da565b61087b6004356024355b600073__CallLib_______________________________63a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506102da9050565b6109a86009546101da565b610a41600c54600160a060020a031681565b61087b600b5462010000900460ff166101da565b6109a86007546101da565b610a5e600e5460ff1681565b6109a8600073__CallLib_______________________________63a9d2293d6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600054600160a060020a031681565b61087b600080548190600160a060020a039081163390911614610e25576109a4565b6109a85b600073__CallLib_______________________________635054d98a60036000506040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a860015481565b61087b600b5460ff610100909104166101da565b610a7460035474010000000000000000000000000000000000000000900460e060020a026101da565b6109a8600073__CallLib_______________________________63cc3471af6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600854620100009004600160a060020a03166101da565b6109a86005546101da565b610a3f604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________9163a094315491604480830192602092919082900301818660325a03f4156100025750506040515115905061080657604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________91637e92656291604482810192600092919082900301818660325a03f415610002575050505b565b6109a8600435600073__CallLib_______________________________63f5562753836040518260e060020a028152600401808281526020019150506020604051808303818660325a03f415610002575050604051519150610ba99050565b610a41600354600160a060020a03166101da565b604080519115158252519081900360200190f35b60045460006002600019600184161561010002019092169190910411156108b957600091506109a4565b6108c16105ea565b9050600081141580156108d5575060018114155b80156108e2575060028114155b156108f057600091506109a4565b6004805460008281527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6020601f6002600186161561010002600019019095169490940484010481019236929083901061096d5782800160ff198235161785555b5061099d9291505b808211156109a45760008155600101610959565b82800160010185558215610951579182015b8281111561095157823582600050559160200191906001019061097f565b5050600191505b5090565b60408051918252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f2925050501515610ba957610002565b604080517f5f5f6469672875696e74323536290000000000000000000000000000000000008152815190819003600e01812060e060020a90819004908102825260001985016004830152915130600160a060020a031692916102bc86029160248281019260009291908290030181838887f19450505050505b919050565b820191906000526020600020905b815481529060010190602001808311610bbc57829003601f168201915b505050505090506101da565b1415610ceb57604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a031660248301523460448301526064820152905173__CallLib_______________________________91630fee183d91608480830192602092919082900301818660325a03f41561000257505060405151925050811515610cf05773__AccountingLib_________________________6312c82bcc33346040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100025750506040515115159050610cf057610002565b505090565b819250506109a4565b505b50565b1415610cf9575a9150610d1133836104a0565b1515610d1d5750610cfb565b73__CallLib_______________________________63da46be0a60038433610d4361048d565b610d4b61023e565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a03168152602001838152602001828152602001955050505050506000604051808303818660325a03f41561000257505050610cf933604080516000547fc17e6817000000000000000000000000000000000000000000000000000000008252600160a060020a0390811660048301523016316024820152905173__CallLib_______________________________9163c17e681791604480830192602092919082900301818660325a03f4156100025750505050565b6004546000600260018316156101000260001901909216919091041115610e4f57600091506109a4565b610e576105ea565b905060008114158015610e6b575060018114155b8015610e78575060028114155b15610e8657600091506109a4565b604080517f7c0278fc00000000000000000000000000000000000000000000000000000000815260036004820181815260248301938452366044840181905273__CallLib_______________________________94637c0278fc94600093919060640184848082843782019150509450505050506000604051808303818660325a03f41561000257505050509056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'TokenCallContract': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'schedulerAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x606060405260428060106000396000f3606060405260e060020a6000350463ae45850b8114601a575b005b603860005473ffffffffffffffffffffffffffffffffffffffff1681565b6060908152602090f3', - 'code_runtime': '0x606060405260e060020a6000350463ae45850b8114601a575b005b603860005473ffffffffffffffffffffffffffffffffffffffff1681565b6060908152602090f3', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'TokenScheduler': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'callAddress', - 'type': 'address', - }, - ], - 'name': 'isKnownCall', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'TrustFund': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'beneficiary', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'releaseBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'releaseFunds', - 'outputs': [], - 'type': 'function', - }, - { - 'inputs': [ - { - 'name': '_beneficiary', - 'type': 'address', - }, - { - 'name': '_releaseBlock', - 'type': 'uint256', - }, - { - 'name': 'alarmScheduler', - 'type': 'address', - }, - ], - 'type': 'constructor', - }, - ], - 'code': '0x606060405260405160608061015f83395060c06040525160805160a05160008054600160a060020a0319168417815560018390557f112e39a80000000000000000000000000000000000000000000000000000000060c090815260c4849052600160a060020a0383169163112e39a89160e4919060248183876161da5a03f15050505050505060cd806100926000396000f36060604052361560315760e060020a600035046338af3eed811460395780634c77a10f14604a57806369d89575146052575b607560736055565b6077600054600160a060020a031681565b609460015481565b60755b30600160a060020a03163160001480606e575060015443105b1560a6575b565b005b60408051600160a060020a03929092168252519081900360200190f35b60408051918252519081900360200190f35b60008054604051600160a060020a0391821692913016319082818181858883f1505050505056', - 'code_runtime': '0x6060604052361560315760e060020a600035046338af3eed811460395780634c77a10f14604a57806369d89575146052575b607560736055565b6077600054600160a060020a031681565b609460015481565b60755b30600160a060020a03163160001480606e575060015443105b1560a6575b565b005b60408051600160a060020a03929092168252519081900360200190f35b60408051918252519081900360200190f35b60008054604051600160a060020a0391821692913016319082818181858883f1505050505056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'owned': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'owner', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'Owned', - 'outputs': [], - 'type': 'function', - }, - ], - 'code': '0x6060604052606f8060106000396000f3606060405260e060020a60003504638da5cb5b81146024578063b303dcbd146042575b005b606560005473ffffffffffffffffffffffffffffffffffffffff1681565b60226000805473ffffffffffffffffffffffffffffffffffffffff191633179055565b6060908152602090f3', - 'code_runtime': '0x606060405260e060020a60003504638da5cb5b81146024578063b303dcbd146042575b005b606560005473ffffffffffffffffffffffffffffffffffffffff1681565b60226000805473ffffffffffffffffffffffffffffffffffffffff191633179055565b6060908152602090f3', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - } diff --git a/migrations/0002_deploy_v7_canary.py b/migrations/0002_deploy_v7_canary.py deleted file mode 100644 index de511a106..000000000 --- a/migrations/0002_deploy_v7_canary.py +++ /dev/null @@ -1,4304 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from populus import migrations - - -class Migration(migrations.Migration): - - migration_id = '0002_deploy_v7_canary' - dependencies = [ - '0001_initial', - ] - operations = [ - migrations.DeployContract( - contract_name='Canary', - arguments=[ - migrations.Address.defer(key='contract/Scheduler'), - 480, - ], - ), - migrations.TransactContract( - contract_address=migrations.Address.defer(key='contract/Canary'), - contract_name='Canary', - method_name='initialize', - transaction={'value': 6000000000000000000}, # 6 ether - ), - ] - compiled_contracts = { - 'AccountingLib': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'toAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'sendRobust', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': '_from', - 'type': 'address', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Deposit', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - { - 'name': 'balance', - 'type': 'uint256', - }, - ], - 'name': 'InsufficientFunds', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'AccountingLib.Bank storage', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'addFunds', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Withdrawal', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'AccountingLib.Bank storage', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'deposit', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'AccountingLib.Bank storage', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'withdraw', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'toAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - { - 'name': 'maxGas', - 'type': 'uint256', - }, - ], - 'name': 'sendRobust', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'AccountingLib.Bank storage', - }, - { - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'deductFunds', - 'outputs': [], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': '_from', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': '_Deposit', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': '_Withdrawal', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'accountAddress', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - { - 'indexed': False, - 'name': 'balance', - 'type': 'uint256', - }, - ], - 'name': '_InsufficientFunds', - 'type': 'event', - }, - ], - 'code': '0x6060604052610398806100126000396000f365030600000000506060604052361561007f5760e060020a600035046312c82bcc81146100845780635548c837146100a55780635c54305e146101015780636b103966146101555780637fcf532c14610189578063b1df3d80146101d5578063b5bc6dbb146101ee578063c6ab451414610225578063e62af6c114610294575b610007565b6102c66004356024356000620186a05a10156102dc576102ee83835a610232565b6102da60043560243560443581600160a060020a031683600160a060020a03167f47a08955ce2b7f21ea62ff0024e1ea0ad87430953554a87e6bc65d777f18e639836040518082815260200191505060405180910390a3505050565b6102da60043560243560443560408051838152602081018390528151600160a060020a038616927f9b24879829bed3003de08d5c5d7e18dcbb8dc76faebd95cafc5d4dec8c61a3a5928290030190a2505050565b6102da6004356024356044355b600160a060020a03821660009081526020849052604090205480820110156102f557610007565b6102da600435602435604080518281529051600160a060020a038416917fd0c5cf41ee8ebf084ad0bce53de7cbc6e4693d9b53a4019ca36a2f91cdc20b3a919081900360200190a25050565b6102c66004356024356044356000610318848484610162565b6102c6600435602435604435600160a060020a0382166000908152602084905260408120548290106102ea576103228484846102a1565b6102c66004356024356044355b60006000831180156102615750604051600160a060020a03851690600090859082818181858883f19350505050155b1561031857604051600160a060020a03851690839085906000818181858888f193505050501515610318575060006102ee565b6102da6004356024356044355b600160a060020a03821660009081526020849052604090205481111561037457610007565b604080519115158252519081900360200190f35b005b6102ee8383620186a0610232565b5060005b9392505050565b600160a060020a0382166000908152602084905260409020805482019055505050565b5060019392505050565b604051600160a060020a03841690600090849082818181858883f19350505050151561031857604051600160a060020a038416908390600081818185876185025a03f192505050151561031857610007565b600160a060020a03821660009081526020849052604090208054829003905550505056', - 'code_runtime': '0x65030600000000506060604052361561007f5760e060020a600035046312c82bcc81146100845780635548c837146100a55780635c54305e146101015780636b103966146101555780637fcf532c14610189578063b1df3d80146101d5578063b5bc6dbb146101ee578063c6ab451414610225578063e62af6c114610294575b610007565b6102c66004356024356000620186a05a10156102dc576102ee83835a610232565b6102da60043560243560443581600160a060020a031683600160a060020a03167f47a08955ce2b7f21ea62ff0024e1ea0ad87430953554a87e6bc65d777f18e639836040518082815260200191505060405180910390a3505050565b6102da60043560243560443560408051838152602081018390528151600160a060020a038616927f9b24879829bed3003de08d5c5d7e18dcbb8dc76faebd95cafc5d4dec8c61a3a5928290030190a2505050565b6102da6004356024356044355b600160a060020a03821660009081526020849052604090205480820110156102f557610007565b6102da600435602435604080518281529051600160a060020a038416917fd0c5cf41ee8ebf084ad0bce53de7cbc6e4693d9b53a4019ca36a2f91cdc20b3a919081900360200190a25050565b6102c66004356024356044356000610318848484610162565b6102c6600435602435604435600160a060020a0382166000908152602084905260408120548290106102ea576103228484846102a1565b6102c66004356024356044355b60006000831180156102615750604051600160a060020a03851690600090859082818181858883f19350505050155b1561031857604051600160a060020a03851690839085906000818181858888f193505050501515610318575060006102ee565b6102da6004356024356044355b600160a060020a03821660009081526020849052604090205481111561037457610007565b604080519115158252519081900360200190f35b005b6102ee8383620186a0610232565b5060005b9392505050565b600160a060020a0382166000908152602084905260409020805482019055505050565b5060019392505050565b604051600160a060020a03841690600090849082818181858883f19350505050151561031857604051600160a060020a038416908390600081818185876185025a03f192505050151561031857610007565b600160a060020a03821660009081526020849052604090208054829003905550505056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'CallContractAPI': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'targetBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'cancel', - 'outputs': [], - 'type': 'function', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'CallLib': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'checkExecutionAuthorization', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'firstClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'deposit_amount', - 'type': 'uint256', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'claim', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - ], - 'name': 'state', - 'outputs': [ - { - 'name': '', - 'type': 'CallLib.State', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'call', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'data', - 'type': 'bytes', - }, - ], - 'name': 'extractCallData', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'sender', - 'type': 'address', - }, - ], - 'name': 'cancel', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'caller', - 'type': 'address', - }, - ], - 'name': 'isCancellable', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'startGas', - 'type': 'uint256', - }, - ], - 'name': 'beforeExecuteForFutureBlockCall', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'lastClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'base_gas_price', - 'type': 'uint256', - }, - { - 'name': 'gas_price', - 'type': 'uint256', - }, - ], - 'name': 'getGasScalar', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'to_address', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'sendSafe', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'maxClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'self', - 'type': 'CallLib.Call storage', - }, - { - 'name': 'start_gas', - 'type': 'uint256', - }, - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'overhead', - 'type': 'uint256', - }, - { - 'name': 'extraGas', - 'type': 'uint256', - }, - ], - 'name': 'execute', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'executor', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'gasCost', - 'type': 'uint256', - }, - { - 'indexed': False, - 'name': 'payment', - 'type': 'uint256', - }, - { - 'indexed': False, - 'name': 'donation', - 'type': 'uint256', - }, - { - 'indexed': False, - 'name': 'success', - 'type': 'bool', - }, - ], - 'name': 'CallExecuted', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': False, - 'name': 'executor', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'reason', - 'type': 'bytes32', - }, - ], - 'name': 'CallAborted', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'cancelled_by', - 'type': 'address', - }, - ], - 'name': 'Cancelled', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': False, - 'name': 'executor', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'claimAmount', - 'type': 'uint256', - }, - ], - 'name': 'Claimed', - 'type': 'event', - }, - ], - 'code': '0x60606040526112ef806100126000396000f36503060000000050606060405236156100b65760e060020a60003504630bd295e681146100bb5780630fd1f94e1461016d5780630fee183d1461017c5780635054d98a1461019d5780637c0278fc146101c55780637e9265621461025d578063a0943154146102cc578063a1873db6146102e4578063a9d2293d1461032b578063b5d0f16e14610382578063c17e6817146103a3578063cc3471af1461043d578063da46be0a1461044d578063f556275314610507575b610007565b6105af6004356024356044355b60006000600030915081600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515191505080841080610163575081600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515160ff168201851190505b156105e557610007565b6105c3600060f061062f610441565b6105af6004356024356044356064356000816002028310156106b8576106b0565b6105c36004355b6008810154600090819062010000900460ff16156106cc57600691506106c6565b60408051602060248035600481810135601f81018590048502860185019096528585526105d5958135959194604494929390920191819084018382808284375094965050505050505060006004825103836001016000508181546001816001161561010002031660029004825481601f106108eb5782601f10610925575b826008026101000360020a8091040282800117835561093c565b6105d5600435602435604051600090600160a060020a038316907f398bd6b21ae4164ec322fb0eb8c2eb6277f36fd41903fbbed594dfe125591281908390a260078301548190106109fe57600783015460058401546109fc9162010000909104600160a060020a0316906103ad565b6105af600435602435600060006000610a6d856101a4565b6105af600435602435604435600483015460009081903090841015610aed577f4e4f545f454e4f5547485f4741530000000000000000000000000000000000009150610d30565b6105c35b60006000309050600a81600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151919091039250505b5090565b6105c36004356024355b600082821115610d85578183606402049050610d96565b6105c36004356024355b600030600160a060020a0316318211156103cf57600160a060020a0330163191505b6000821115610d9c5773__AccountingLib_________________________6312c82bcc84846040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100075750839250610d96915050565b6105c35b6000600f61062f61032f565b6105d560043560243560443560643560843560088501805461ff00191661010017905584543090600090819081908190819060a060020a900460e060020a02600160e060020a031916811480156104b857506001808c01546002918116156101000260001901160481145b15610da4578a5460028c0154600160a060020a039190911690895a60405191900391906000818181858888f193505050508b60080160006101000a81548160ff02191690830217905550610ff6565b6105c36004355b6000600060006000309250600a83600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515191909103925050818511156112335782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151945061122b9050565b604080519115158252519081900360200190f35b60408051918252519081900360200190f35b005b600192505b50509392505050565b601081850310156105d7576005860154620100009004600160a060020a03166000148061062857506005860154620100009004600160a060020a03908116908616145b92506105dc565b03905090565b6006860181905560058601805475ffffffffffffffffffffffffffffffffffffffff000019166201000087021790556007860184905560408051600160a060020a0387168152602081019290925280517fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9281900390910190a15b949350505050565b6106354361050e565b600291505b50919050565b6008830154610100900460ff16156106e757600591506106c6565b30905080600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515161010943011015905061073e57600091506106c6565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143600a01101590506107ad576005830154620100009004600160a060020a0316600014156106c157600191506106c6565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143101590506107fd57600391506106c6565b80600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040805180517f0a16697a000000000000000000000000000000000000000000000000000000008252915160ff9092169291630a16697a9160048181019260209290919082900301816000876161da5a03f115610007575050604051519190910143101590506108aa57600491506106c6565b600791506106c6565b5081800160010183558181151161093c57601f016020900481601f0160209004836000526020600020918201910161093c9190610911565b82601f106108b3575082600052602060002080549082601f01602090048101906109f191905b8082111561037e5760008155600101610911565b60ff19168360005260206000205581800160010183555b505050506004825111156109f7575060005b600180840154600291811615610100026000190116048110156109f757818160040181518110156100075790602001015160f860020a900460f860020a02836001016000508281546001816001161561010002031660029004811015610007578154600116156109cd5790600052602060002090602091828204019190065b601f036101000a81548160ff0219169060f860020a8404021790555060010161094e565b50610243565b505050565b505b309050610a4981600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515190316103ad565b505050600801805462ff0000191662010000179055565b600092505b505092915050565b9150309050600082148015610acd575080600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151600160a060020a039081169086161490505b15610adb5760019250610a65565b6007821415610a605760019250610a65565b6008860154610100900460ff1615610b27577f414c52454144595f43414c4c45440000000000000000000000000000000000009150610d30565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051514310905080610bfd575080600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050506040518051906020015060ff1681600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151909101431190505b15610c2a577f4e4f545f494e5f43414c4c5f57494e444f5700000000000000000000000000009150610d30565b610c358686436100c8565b1515610c63577f4e4f545f415554484f52495a45440000000000000000000000000000000000009150610d30565b6005860154600061ffff91909116118015610c90575032600160a060020a031685600160a060020a031614155b8015610d0757506040805160058801547f349501b700000000000000000000000000000000000000000000000000000000825261ffff1660048201529051600160a060020a0383169163349501b791602482810192602092919082900301816000876161da5a03f115610007575050604051511590505b15610d30577f535441434b5f544f4f5f4445455000000000000000000000000000000000000091505b600082146105d75760408051600160a060020a03871681526020810184905281517fdcb278834ca505ad219cf8e4b5d11f026080abef6ec68e249ea5e4d9bb3dc7b2929181900390910190a1600092506105dc565b818360020203836064020460c80390505b92915050565b506000610d96565b8a54600160e060020a031960a060020a90910460e060020a021660001415610e1f578a5460028c0154600160a060020a039190911690895a03908d6001016000506040518082805460018160011615610100020316600290048015610ee15780601f10610eb657610100808354040283529160200191610ee1565b60018b8101546002918116156101000260001901160460001415610f16578a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491906040518360e060020a028152600401809050600060405180830381858988f19450505050508b60080160006101000a81548160ff02191690830217905550610ff6565b820191906000526020600020905b815481529060010190602001808311610ec457829003601f168201915b5050915050600060405180830381858888f193505050508b60080160006101000a81548160ff02191690830217905550610ff6565b8a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491908e6001016000506040518460e060020a0281526004018082805460018160011615610100020316600290048015610fc45780601f10610f9957610100808354040283529160200191610fc4565b820191906000526020600020905b815481529060010190602001808311610fa757829003601f168201915b5050915050600060405180830381858988f19450505050508b60080160006101000a81548160ff021916908302179055505b85600160a060020a031663938b5f326040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040805180517f75706461746544656661756c745061796d656e742829000000000000000000008252825191829003601601822060e060020a9081900490810283529251600160a060020a039190911693506004828101926000929190829003018183876161da5a03f150505060038c01546110ad91503a61038c565b60058c0154909550620100009004600160a060020a03908116908a1614156110db5760068b0154935061111d565b85600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051519450505b6064858502048b6007016000505401925060648587600160a060020a031663625cc4656040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001500204915060008b60070160005081905550865a8b03013a02905061119c898285016103ad565b92506111bc73d3cda913deb6f67967b99d67acdfa1712c293601836103ad565b6040805160088e01548482526020820187905281830184905260ff16151560608201529051919350600160a060020a038b16917f4538b7ec91dae8fada01e66a052482086d3e690c3db5a80457fbcd55457b4ae19181900360800190a25050505050505050505050565b600093505b505050919050565b600e1991909101908185111561128a5782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151945061122b9050565b60ef19909101908185111561122657818503905060f08184600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001500204935061122b56', - 'code_runtime': '0x6503060000000050606060405236156100b65760e060020a60003504630bd295e681146100bb5780630fd1f94e1461016d5780630fee183d1461017c5780635054d98a1461019d5780637c0278fc146101c55780637e9265621461025d578063a0943154146102cc578063a1873db6146102e4578063a9d2293d1461032b578063b5d0f16e14610382578063c17e6817146103a3578063cc3471af1461043d578063da46be0a1461044d578063f556275314610507575b610007565b6105af6004356024356044355b60006000600030915081600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515191505080841080610163575081600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515160ff168201851190505b156105e557610007565b6105c3600060f061062f610441565b6105af6004356024356044356064356000816002028310156106b8576106b0565b6105c36004355b6008810154600090819062010000900460ff16156106cc57600691506106c6565b60408051602060248035600481810135601f81018590048502860185019096528585526105d5958135959194604494929390920191819084018382808284375094965050505050505060006004825103836001016000508181546001816001161561010002031660029004825481601f106108eb5782601f10610925575b826008026101000360020a8091040282800117835561093c565b6105d5600435602435604051600090600160a060020a038316907f398bd6b21ae4164ec322fb0eb8c2eb6277f36fd41903fbbed594dfe125591281908390a260078301548190106109fe57600783015460058401546109fc9162010000909104600160a060020a0316906103ad565b6105af600435602435600060006000610a6d856101a4565b6105af600435602435604435600483015460009081903090841015610aed577f4e4f545f454e4f5547485f4741530000000000000000000000000000000000009150610d30565b6105c35b60006000309050600a81600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151919091039250505b5090565b6105c36004356024355b600082821115610d85578183606402049050610d96565b6105c36004356024355b600030600160a060020a0316318211156103cf57600160a060020a0330163191505b6000821115610d9c5773__AccountingLib_________________________6312c82bcc84846040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100075750839250610d96915050565b6105c35b6000600f61062f61032f565b6105d560043560243560443560643560843560088501805461ff00191661010017905584543090600090819081908190819060a060020a900460e060020a02600160e060020a031916811480156104b857506001808c01546002918116156101000260001901160481145b15610da4578a5460028c0154600160a060020a039190911690895a60405191900391906000818181858888f193505050508b60080160006101000a81548160ff02191690830217905550610ff6565b6105c36004355b6000600060006000309250600a83600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515191909103925050818511156112335782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151945061122b9050565b604080519115158252519081900360200190f35b60408051918252519081900360200190f35b005b600192505b50509392505050565b601081850310156105d7576005860154620100009004600160a060020a03166000148061062857506005860154620100009004600160a060020a03908116908616145b92506105dc565b03905090565b6006860181905560058601805475ffffffffffffffffffffffffffffffffffffffff000019166201000087021790556007860184905560408051600160a060020a0387168152602081019290925280517fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9281900390910190a15b949350505050565b6106354361050e565b600291505b50919050565b6008830154610100900460ff16156106e757600591506106c6565b30905080600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515161010943011015905061073e57600091506106c6565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143600a01101590506107ad576005830154620100009004600160a060020a0316600014156106c157600191506106c6565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143101590506107fd57600391506106c6565b80600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040805180517f0a16697a000000000000000000000000000000000000000000000000000000008252915160ff9092169291630a16697a9160048181019260209290919082900301816000876161da5a03f115610007575050604051519190910143101590506108aa57600491506106c6565b600791506106c6565b5081800160010183558181151161093c57601f016020900481601f0160209004836000526020600020918201910161093c9190610911565b82601f106108b3575082600052602060002080549082601f01602090048101906109f191905b8082111561037e5760008155600101610911565b60ff19168360005260206000205581800160010183555b505050506004825111156109f7575060005b600180840154600291811615610100026000190116048110156109f757818160040181518110156100075790602001015160f860020a900460f860020a02836001016000508281546001816001161561010002031660029004811015610007578154600116156109cd5790600052602060002090602091828204019190065b601f036101000a81548160ff0219169060f860020a8404021790555060010161094e565b50610243565b505050565b505b309050610a4981600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515190316103ad565b505050600801805462ff0000191662010000179055565b600092505b505092915050565b9150309050600082148015610acd575080600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151600160a060020a039081169086161490505b15610adb5760019250610a65565b6007821415610a605760019250610a65565b6008860154610100900460ff1615610b27577f414c52454144595f43414c4c45440000000000000000000000000000000000009150610d30565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051514310905080610bfd575080600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050506040518051906020015060ff1681600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151909101431190505b15610c2a577f4e4f545f494e5f43414c4c5f57494e444f5700000000000000000000000000009150610d30565b610c358686436100c8565b1515610c63577f4e4f545f415554484f52495a45440000000000000000000000000000000000009150610d30565b6005860154600061ffff91909116118015610c90575032600160a060020a031685600160a060020a031614155b8015610d0757506040805160058801547f349501b700000000000000000000000000000000000000000000000000000000825261ffff1660048201529051600160a060020a0383169163349501b791602482810192602092919082900301816000876161da5a03f115610007575050604051511590505b15610d30577f535441434b5f544f4f5f4445455000000000000000000000000000000000000091505b600082146105d75760408051600160a060020a03871681526020810184905281517fdcb278834ca505ad219cf8e4b5d11f026080abef6ec68e249ea5e4d9bb3dc7b2929181900390910190a1600092506105dc565b818360020203836064020460c80390505b92915050565b506000610d96565b8a54600160e060020a031960a060020a90910460e060020a021660001415610e1f578a5460028c0154600160a060020a039190911690895a03908d6001016000506040518082805460018160011615610100020316600290048015610ee15780601f10610eb657610100808354040283529160200191610ee1565b60018b8101546002918116156101000260001901160460001415610f16578a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491906040518360e060020a028152600401809050600060405180830381858988f19450505050508b60080160006101000a81548160ff02191690830217905550610ff6565b820191906000526020600020905b815481529060010190602001808311610ec457829003601f168201915b5050915050600060405180830381858888f193505050508b60080160006101000a81548160ff02191690830217905550610ff6565b8a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491908e6001016000506040518460e060020a0281526004018082805460018160011615610100020316600290048015610fc45780601f10610f9957610100808354040283529160200191610fc4565b820191906000526020600020905b815481529060010190602001808311610fa757829003601f168201915b5050915050600060405180830381858988f19450505050508b60080160006101000a81548160ff021916908302179055505b85600160a060020a031663938b5f326040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040805180517f75706461746544656661756c745061796d656e742829000000000000000000008252825191829003601601822060e060020a9081900490810283529251600160a060020a039190911693506004828101926000929190829003018183876161da5a03f150505060038c01546110ad91503a61038c565b60058c0154909550620100009004600160a060020a03908116908a1614156110db5760068b0154935061111d565b85600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051519450505b6064858502048b6007016000505401925060648587600160a060020a031663625cc4656040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001500204915060008b60070160005081905550865a8b03013a02905061119c898285016103ad565b92506111bc73d3cda913deb6f67967b99d67acdfa1712c293601836103ad565b6040805160088e01548482526020820187905281830184905260ff16151560608201529051919350600160a060020a038b16917f4538b7ec91dae8fada01e66a052482086d3e690c3db5a80457fbcd55457b4ae19181900360800190a25050505050505050505050565b600093505b505050919050565b600e1991909101908185111561128a5782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151945061122b9050565b60ef19909101908185111561122657818503905060f08184600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001500204935061122b56', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'Canary': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'aliveSince', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'heartbeat', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callContractAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'isAlive', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'scheduleHeartbeat', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'lastHeartbeat', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'initialize', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'owner', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'schedulerAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'heartbeatCount', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'cancel', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'frequency', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'inputs': [ - { - 'name': '_scheduler', - 'type': 'address', - }, - { - 'name': '_frequency', - 'type': 'uint16', - }, - ], - 'type': 'constructor', - }, - ], - 'code': '0x60606040818152806104d0833960a09052516080516005805460038054600160a060020a0319908116861790915574010000000000000000000000000000000000000000840260a060020a61ffff0219919092163317161790555050610467806100696000396000f3606060405236156100985760e060020a60003504633896002781146100e15780633defb962146100ea5780633f4be8891461010c5780634136aa351461011f5780634a420138146101a157806369c1a7121461028f5780638129fc1c146102985780638da5cb5b146102a9578063ae45850b146102bb578063af3309d8146102cf578063ea8a1af0146102d8578063ead50da3146102f6575b61030a671bc16d674ec8000030600160a060020a03163110156100df57600554604051600160a060020a03918216916000913091909116319082818181858883f150505050505b565b61030c60005481565b61030a671bc16d674ec8000030600160a060020a0316311015610373576100df565b610322600454600160a060020a03165b90565b6103415b60008054819011801561019a575060408051600480547f0a16697a0000000000000000000000000000000000000000000000000000000083529251600160a060020a039390931692630a16697a92828101926020929182900301816000876161da5a03f1156100025750506040515160ff01431090505b905061011c565b61030a5b600554604080516003547f8c0e156d0000000000000000000000000000000000000000000000000000000082527f3defb96200000000000000000000000000000000000000000000000000000000600483015260a060020a90930461ffff1643016024820152621e848060448201529051600092600160a060020a031691638c0e156d91671bc16d674ec8000091606480820192602092909190829003018185886185025a03f1156100025750506040515192505050600160a060020a03811660001461028c576004805473ffffffffffffffffffffffffffffffffffffffff1916821790555b50565b61030c60015481565b61030a60008054146103ba576100df565b610322600554600160a060020a031681565b610322600354600160a060020a031661011c565b61030c60025481565b61030a60055433600160a060020a039081169116146103c657610002565b61035960055460a060020a900461ffff1681565b005b6040518082815260200191505060405180910390f35b6040518082600160a060020a0316815260200191505060405180910390f35b60405180821515815260200191505060405180910390f35b604051808261ffff16815260200191505060405180910390f35b60045433600160a060020a0390811691161461038e576100df565b610396610123565b15156103a1576100df565b6103a96101a5565b600280546001908101909155429055565b426000556100df6101a5565b6004546000600160a060020a039190911631111561043c5760408051600480547fea8a1af00000000000000000000000000000000000000000000000000000000083529251600160a060020a03939093169263ea8a1af0928281019260009291829003018183876161da5a03f115610002575050505b600554604051600160a060020a03918216916000913091909116319082818181858883f1505050505056', - 'code_runtime': '0x606060405236156100985760e060020a60003504633896002781146100e15780633defb962146100ea5780633f4be8891461010c5780634136aa351461011f5780634a420138146101a157806369c1a7121461028f5780638129fc1c146102985780638da5cb5b146102a9578063ae45850b146102bb578063af3309d8146102cf578063ea8a1af0146102d8578063ead50da3146102f6575b61030a671bc16d674ec8000030600160a060020a03163110156100df57600554604051600160a060020a03918216916000913091909116319082818181858883f150505050505b565b61030c60005481565b61030a671bc16d674ec8000030600160a060020a0316311015610373576100df565b610322600454600160a060020a03165b90565b6103415b60008054819011801561019a575060408051600480547f0a16697a0000000000000000000000000000000000000000000000000000000083529251600160a060020a039390931692630a16697a92828101926020929182900301816000876161da5a03f1156100025750506040515160ff01431090505b905061011c565b61030a5b600554604080516003547f8c0e156d0000000000000000000000000000000000000000000000000000000082527f3defb96200000000000000000000000000000000000000000000000000000000600483015260a060020a90930461ffff1643016024820152621e848060448201529051600092600160a060020a031691638c0e156d91671bc16d674ec8000091606480820192602092909190829003018185886185025a03f1156100025750506040515192505050600160a060020a03811660001461028c576004805473ffffffffffffffffffffffffffffffffffffffff1916821790555b50565b61030c60015481565b61030a60008054146103ba576100df565b610322600554600160a060020a031681565b610322600354600160a060020a031661011c565b61030c60025481565b61030a60055433600160a060020a039081169116146103c657610002565b61035960055460a060020a900461ffff1681565b005b6040518082815260200191505060405180910390f35b6040518082600160a060020a0316815260200191505060405180910390f35b60405180821515815260200191505060405180910390f35b604051808261ffff16815260200191505060405180910390f35b60045433600160a060020a0390811691161461038e576100df565b610396610123565b15156103a1576100df565b6103a96101a5565b600280546001908101909155429055565b426000556100df6101a5565b6004546000600160a060020a039190911631111561043c5760408051600480547fea8a1af00000000000000000000000000000000000000000000000000000000083529251600160a060020a03939093169263ea8a1af0928281019260009291829003018183876161da5a03f115610002575050505b600554604051600160a060020a03918216916000913091909116319082818181858883f1505050505056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'ERC20ScheduledTransfer': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'spender', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'approve', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'totalSupply', - 'outputs': [ - { - 'name': 'supply', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'from', - 'type': 'address', - }, - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'transferFrom', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'who', - 'type': 'address', - }, - ], - 'name': 'balanceOf', - 'outputs': [ - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - { - 'name': 'when', - 'type': 'uint256', - }, - ], - 'name': 'scheduleTransfer', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'transfer', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'scheduler', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'owner', - 'type': 'address', - }, - { - 'name': 'spender', - 'type': 'address', - }, - ], - 'name': 'allowance', - 'outputs': [ - { - 'name': '_allowance', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'from', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'to', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Transfer', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'owner', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'spender', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Approval', - 'type': 'event', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'ERC20Token': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'spender', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'approve', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'totalSupply', - 'outputs': [ - { - 'name': 'supply', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'from', - 'type': 'address', - }, - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'transferFrom', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'who', - 'type': 'address', - }, - ], - 'name': 'balanceOf', - 'outputs': [ - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'to', - 'type': 'address', - }, - { - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'transfer', - 'outputs': [ - { - 'name': 'ok', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'owner', - 'type': 'address', - }, - { - 'name': 'spender', - 'type': 'address', - }, - ], - 'name': 'allowance', - 'outputs': [ - { - 'name': '_allowance', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'from', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'to', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Transfer', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'owner', - 'type': 'address', - }, - { - 'indexed': True, - 'name': 'spender', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'value', - 'type': 'uint256', - }, - ], - 'name': 'Approval', - 'type': 'event', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'FutureBlockCall': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'wasSuccessful', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'targetBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'firstClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getExtraGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'n', - 'type': 'uint256', - }, - ], - 'name': '__dig', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'checkExecutionAuthorization', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'requiredStackDepth', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callAPIVersion', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimerDeposit', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'n', - 'type': 'uint256', - }, - ], - 'name': 'checkDepth', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'anchorGasPrice', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'isCancellable', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callData', - 'outputs': [ - { - 'name': '', - 'type': 'bytes', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'claim', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'execute', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'baseDonation', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getOverhead', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'startGas', - 'type': 'uint256', - }, - ], - 'name': 'beforeExecute', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimAmount', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'origin', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'isCancelled', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'requiredGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'gracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'lastClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'schedulerAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'registerData', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'state', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'basePayment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'wasCalled', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'abiSignature', - 'outputs': [ - { - 'name': '', - 'type': 'bytes4', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'maxClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimer', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callValue', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'cancel', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'contractAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'inputs': [ - { - 'name': '_schedulerAddress', - 'type': 'address', - }, - { - 'name': '_targetBlock', - 'type': 'uint256', - }, - { - 'name': '_gracePeriod', - 'type': 'uint8', - }, - { - 'name': '_contractAddress', - 'type': 'address', - }, - { - 'name': '_abiSignature', - 'type': 'bytes4', - }, - { - 'name': '_callData', - 'type': 'bytes', - }, - { - 'name': '_callValue', - 'type': 'uint256', - }, - { - 'name': '_requiredGas', - 'type': 'uint256', - }, - { - 'name': '_requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': '_basePayment', - 'type': 'uint256', - }, - { - 'name': '_baseDonation', - 'type': 'uint256', - }, - ], - 'type': 'constructor', - }, - ], - 'code': '0x606060405260405161112038038061112083398101604052805160805160a05160c05160e05161010051610120516101405161016051610180516101a051999a98999798969795969490940194929391929091908a84848a8a8a8a8888600c8054600160a060020a031990811633179091556000805482168b1781556001848155600284815560078c90556008805461ffff19168c1790553a600655600380547c01000000000000000000000000000000000000000000000000000000008b04740100000000000000000000000000000000000000000295168b1760a060020a63ffffffff021916949094179093556004805488519382905290936020601f9383161561010002600019019092160482018190047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b908101939290918901908390106101d757805160ff19168380011785555b5061016e9291505b80821115610207576000815560010161015a565b505060058390555050505050505050508a600060006101000a815481600160a060020a030219169083021790555089600d6000508190555088600e60006101000a81548160ff021916908302179055505050505050505050505050610f158061020b6000396000f35b82800160010185558215610152579182015b828111156101525782518260005055916020019190600101906101e9565b509056606060405236156101ab5760e060020a60003504630924120081146101d05780630a16697a146101dd5780630fd1f94e146101e6578063137c638b1461023a57806321835af61461024757806324032866146102605780632f95b833146102e05780633017fe24146102ef5780633233c686146102f9578063349501b71461030457806337f4c00e1461031d5780634500054f146103285780634e417a98146103995780634e71d92d146104025780634f059a43146104145780636146195414610470578063625cc4651461048057806367ce940d146104895780637d298ee314610496578063830953ab14610516578063938b5f321461052157806395ee122114610533578063974654f414610547578063a06db7dc14610552578063a9d2293d1461055e578063ae45850b146105b2578063b0f07e44146105c4578063c19d93fb146105e6578063c6502da814610647578063c680362214610650578063ca94692d14610664578063cc3471af1461068d578063d379be23146106e1578063d62457f6146106fb578063ea8a1af014610706578063f556275314610808578063f6b4dfb414610867575b61087b60008054819033600160a060020a0390811691161461088f57600091506109a4565b61087b600b5460ff165b90565b6109a8600d5481565b6109a8600073__CallLib_______________________________630fd1f94e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a85b62012cc86101da565b61087b60043560008160001415610aa957506001610ba9565b61087b600435602435600073__CallLib_______________________________630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b6109ba60085461ffff166101da565b6109a860026101da565b6109a8600a546101da565b61087b60043560008160001415610b3057506001610ba9565b6109a86006546101da565b61087b600073__CallLib_______________________________63a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109d160408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610bd95780601f10610bae57610100808354040283529160200191610bd9565b61087b60006000600180610be56105ea565b6109a8600073__CallLib_______________________________63f5562753436040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a3f6000600480610cfe6105ea565b6109a860025481565b6109a85b620186a06101da565b61087b6004356024355b600073__CallLib_______________________________63a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506102da9050565b6109a86009546101da565b610a41600c54600160a060020a031681565b61087b600b5462010000900460ff166101da565b6109a86007546101da565b610a5e600e5460ff1681565b6109a8600073__CallLib_______________________________63a9d2293d6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600054600160a060020a031681565b61087b600080548190600160a060020a039081163390911614610e25576109a4565b6109a85b600073__CallLib_______________________________635054d98a60036000506040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a860015481565b61087b600b5460ff610100909104166101da565b610a7460035474010000000000000000000000000000000000000000900460e060020a026101da565b6109a8600073__CallLib_______________________________63cc3471af6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600854620100009004600160a060020a03166101da565b6109a86005546101da565b610a3f604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________9163a094315491604480830192602092919082900301818660325a03f4156100025750506040515115905061080657604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________91637e92656291604482810192600092919082900301818660325a03f415610002575050505b565b6109a8600435600073__CallLib_______________________________63f5562753836040518260e060020a028152600401808281526020019150506020604051808303818660325a03f415610002575050604051519150610ba99050565b610a41600354600160a060020a03166101da565b604080519115158252519081900360200190f35b60045460006002600019600184161561010002019092169190910411156108b957600091506109a4565b6108c16105ea565b9050600081141580156108d5575060018114155b80156108e2575060028114155b156108f057600091506109a4565b6004805460008281527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6020601f6002600186161561010002600019019095169490940484010481019236929083901061096d5782800160ff198235161785555b5061099d9291505b808211156109a45760008155600101610959565b82800160010185558215610951579182015b8281111561095157823582600050559160200191906001019061097f565b5050600191505b5090565b60408051918252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f2925050501515610ba957610002565b604080517f5f5f6469672875696e74323536290000000000000000000000000000000000008152815190819003600e01812060e060020a90819004908102825260001985016004830152915130600160a060020a031692916102bc86029160248281019260009291908290030181838887f19450505050505b919050565b820191906000526020600020905b815481529060010190602001808311610bbc57829003601f168201915b505050505090506101da565b1415610ceb57604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a031660248301523460448301526064820152905173__CallLib_______________________________91630fee183d91608480830192602092919082900301818660325a03f41561000257505060405151925050811515610cf05773__AccountingLib_________________________6312c82bcc33346040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100025750506040515115159050610cf057610002565b505090565b819250506109a4565b505b50565b1415610cf9575a9150610d1133836104a0565b1515610d1d5750610cfb565b73__CallLib_______________________________63da46be0a60038433610d4361048d565b610d4b61023e565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a03168152602001838152602001828152602001955050505050506000604051808303818660325a03f41561000257505050610cf933604080516000547fc17e6817000000000000000000000000000000000000000000000000000000008252600160a060020a0390811660048301523016316024820152905173__CallLib_______________________________9163c17e681791604480830192602092919082900301818660325a03f4156100025750505050565b6004546000600260018316156101000260001901909216919091041115610e4f57600091506109a4565b610e576105ea565b905060008114158015610e6b575060018114155b8015610e78575060028114155b15610e8657600091506109a4565b604080517f7c0278fc00000000000000000000000000000000000000000000000000000000815260036004820181815260248301938452366044840181905273__CallLib_______________________________94637c0278fc94600093919060640184848082843782019150509450505050506000604051808303818660325a03f41561000257505050509056', - 'code_runtime': '0x606060405236156101ab5760e060020a60003504630924120081146101d05780630a16697a146101dd5780630fd1f94e146101e6578063137c638b1461023a57806321835af61461024757806324032866146102605780632f95b833146102e05780633017fe24146102ef5780633233c686146102f9578063349501b71461030457806337f4c00e1461031d5780634500054f146103285780634e417a98146103995780634e71d92d146104025780634f059a43146104145780636146195414610470578063625cc4651461048057806367ce940d146104895780637d298ee314610496578063830953ab14610516578063938b5f321461052157806395ee122114610533578063974654f414610547578063a06db7dc14610552578063a9d2293d1461055e578063ae45850b146105b2578063b0f07e44146105c4578063c19d93fb146105e6578063c6502da814610647578063c680362214610650578063ca94692d14610664578063cc3471af1461068d578063d379be23146106e1578063d62457f6146106fb578063ea8a1af014610706578063f556275314610808578063f6b4dfb414610867575b61087b60008054819033600160a060020a0390811691161461088f57600091506109a4565b61087b600b5460ff165b90565b6109a8600d5481565b6109a8600073__CallLib_______________________________630fd1f94e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a85b62012cc86101da565b61087b60043560008160001415610aa957506001610ba9565b61087b600435602435600073__CallLib_______________________________630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b6109ba60085461ffff166101da565b6109a860026101da565b6109a8600a546101da565b61087b60043560008160001415610b3057506001610ba9565b6109a86006546101da565b61087b600073__CallLib_______________________________63a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109d160408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610bd95780601f10610bae57610100808354040283529160200191610bd9565b61087b60006000600180610be56105ea565b6109a8600073__CallLib_______________________________63f5562753436040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a3f6000600480610cfe6105ea565b6109a860025481565b6109a85b620186a06101da565b61087b6004356024355b600073__CallLib_______________________________63a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506102da9050565b6109a86009546101da565b610a41600c54600160a060020a031681565b61087b600b5462010000900460ff166101da565b6109a86007546101da565b610a5e600e5460ff1681565b6109a8600073__CallLib_______________________________63a9d2293d6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600054600160a060020a031681565b61087b600080548190600160a060020a039081163390911614610e25576109a4565b6109a85b600073__CallLib_______________________________635054d98a60036000506040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a860015481565b61087b600b5460ff610100909104166101da565b610a7460035474010000000000000000000000000000000000000000900460e060020a026101da565b6109a8600073__CallLib_______________________________63cc3471af6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600854620100009004600160a060020a03166101da565b6109a86005546101da565b610a3f604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________9163a094315491604480830192602092919082900301818660325a03f4156100025750506040515115905061080657604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________91637e92656291604482810192600092919082900301818660325a03f415610002575050505b565b6109a8600435600073__CallLib_______________________________63f5562753836040518260e060020a028152600401808281526020019150506020604051808303818660325a03f415610002575050604051519150610ba99050565b610a41600354600160a060020a03166101da565b604080519115158252519081900360200190f35b60045460006002600019600184161561010002019092169190910411156108b957600091506109a4565b6108c16105ea565b9050600081141580156108d5575060018114155b80156108e2575060028114155b156108f057600091506109a4565b6004805460008281527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6020601f6002600186161561010002600019019095169490940484010481019236929083901061096d5782800160ff198235161785555b5061099d9291505b808211156109a45760008155600101610959565b82800160010185558215610951579182015b8281111561095157823582600050559160200191906001019061097f565b5050600191505b5090565b60408051918252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f2925050501515610ba957610002565b604080517f5f5f6469672875696e74323536290000000000000000000000000000000000008152815190819003600e01812060e060020a90819004908102825260001985016004830152915130600160a060020a031692916102bc86029160248281019260009291908290030181838887f19450505050505b919050565b820191906000526020600020905b815481529060010190602001808311610bbc57829003601f168201915b505050505090506101da565b1415610ceb57604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a031660248301523460448301526064820152905173__CallLib_______________________________91630fee183d91608480830192602092919082900301818660325a03f41561000257505060405151925050811515610cf05773__AccountingLib_________________________6312c82bcc33346040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100025750506040515115159050610cf057610002565b505090565b819250506109a4565b505b50565b1415610cf9575a9150610d1133836104a0565b1515610d1d5750610cfb565b73__CallLib_______________________________63da46be0a60038433610d4361048d565b610d4b61023e565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a03168152602001838152602001828152602001955050505050506000604051808303818660325a03f41561000257505050610cf933604080516000547fc17e6817000000000000000000000000000000000000000000000000000000008252600160a060020a0390811660048301523016316024820152905173__CallLib_______________________________9163c17e681791604480830192602092919082900301818660325a03f4156100025750505050565b6004546000600260018316156101000260001901909216919091041115610e4f57600091506109a4565b610e576105ea565b905060008114158015610e6b575060018114155b8015610e78575060028114155b15610e8657600091506109a4565b604080517f7c0278fc00000000000000000000000000000000000000000000000000000000815260036004820181815260248301938452366044840181905273__CallLib_______________________________94637c0278fc94600093919060640184848082843782019150509450505050506000604051808303818660325a03f41561000257505050509056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'FutureCall': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'wasSuccessful', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'firstClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getExtraGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'checkExecutionAuthorization', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'requiredStackDepth', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimerDeposit', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'anchorGasPrice', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callData', - 'outputs': [ - { - 'name': '', - 'type': 'bytes', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'claim', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'execute', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'baseDonation', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getOverhead', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'executor', - 'type': 'address', - }, - { - 'name': 'startGas', - 'type': 'uint256', - }, - ], - 'name': 'beforeExecute', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimAmount', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'origin', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'isCancelled', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'requiredGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'lastClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'schedulerAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'registerData', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'state', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'basePayment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'wasCalled', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'abiSignature', - 'outputs': [ - { - 'name': '', - 'type': 'bytes4', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'maxClaimBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'claimer', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callValue', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'block_number', - 'type': 'uint256', - }, - ], - 'name': 'getClaimAmountForBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'contractAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'inputs': [ - { - 'name': '_schedulerAddress', - 'type': 'address', - }, - { - 'name': '_requiredGas', - 'type': 'uint256', - }, - { - 'name': '_requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': '_contractAddress', - 'type': 'address', - }, - { - 'name': '_abiSignature', - 'type': 'bytes4', - }, - { - 'name': '_callData', - 'type': 'bytes', - }, - { - 'name': '_callValue', - 'type': 'uint256', - }, - { - 'name': '_basePayment', - 'type': 'uint256', - }, - { - 'name': '_baseDonation', - 'type': 'uint256', - }, - ], - 'type': 'constructor', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'GroveLib': { - 'abi': [ - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeRightChild', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeLeftChild', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeParent', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeValue', - 'outputs': [ - { - 'name': '', - 'type': 'int256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeHeight', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'remove', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - { - 'name': 'value', - 'type': 'int256', - }, - ], - 'name': 'insert', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNodeId', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getNextNode', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'getPreviousNode', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'operator', - 'type': 'bytes2', - }, - { - 'name': 'value', - 'type': 'int256', - }, - ], - 'name': 'query', - 'outputs': [ - { - 'name': '', - 'type': 'bytes32', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'index', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'id', - 'type': 'bytes32', - }, - ], - 'name': 'exists', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x60606040526111ef806100126000396000f36503060000000050606060405236156100a05760e060020a60003504630e9f1a3c81146100a55780632b4096b4146100c95780636ec13982146100eb578063a3119e571461010d578063a749f19b1461012f578063ab7366f714610151578063bacd695814610184578063bfdf87c0146101c2578063c4144b26146101e1578063caa46c9c14610240578063e6ce3a6a1461029f578063ed5bd7ea146102c2575b610007565b6102e560043560243560008181526001830160205260409020600401545b92915050565b6102e560043560243560008181526001830160205260409020600301546100c3565b6102e560043560243560008181526001830160205260409020600201546100c3565b6102e560043560243560008181526001838101602052604090912001546100c3565b6102e560043560243560008181526001830160205260409020600501546100c3565b6102f76004356024355b60008181526001830160205260408120805482918291829190861461030d575b50505050505050565b6102f7600435602435604435600082815260018401602052604081205481908190819086141561060157604081206001015485141561069c5761017b565b6102e560043560243560008181526001830160205260409020546100c3565b6102e56004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156107205760009350610717565b6102e56004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156108e55760009350610717565b6102e560043560243560443582546000908181811415610aa55760009250610acc565b6102f96004356024356000818152600183016020526040812060050154116100c3565b60408051918252519081900360200190f35b005b604080519115158252519081900360200190f35b6003810154600014158061032657506004810154600014155b1561034c5760038101546000146103a357805460018801906000906103b8908a9061024a565b60028101546000146105c45760028101546000908152600188016020526040902060038101548254919550141561038557600060038501555b80546004850154141561039a57600060048501555b835491506105c9565b805460018801906000906103cf908a906101eb565b8152602081019190915260400160002094506103e2565b8152602081019190915260400160002094505b6002850154600090815260018801602052604090206003810154865491955090925082141561043d5760048501546003850181905560001461043d576004850154600090815260018801602052604090208454600282015592505b60048401548554141561049b5760038501546004850181905560001461049b57866001016000506000866003016000505460001916815260200190815260200160002060005092508250836000016000505483600201600050819055505b6002808201549086018190556000146105185786600101600050600082600201600050546000191681526020019081526020016000206000509350835080600001600050546000191684600301600050546000191614156104fe57845460038501555b60048401548154141561051357845460048501555b61051d565b845487555b60038082015490860181905560001461056e57866001016000506000826003016000505460001916815260200190815260200160002060005092508250846000016000505483600201600050819055505b6004818101549086018190556000146105bf57866001016000506000826004016000505460001916815260200190815260200160002060005092508250846000016000505483600201600050819055505b6105c9565b600087555b60008082556001820181905560028201819055600382018190556004820181905560058201819055821461017b5761017b8783610647565b865460009250821415610612578587555b508554600090815260018701602052604090205b8054600014156106a657858155600281018290556001810185905561017b87875b60008181526001830160205260408120905b8154610da59085905b60008181526001830160205260408082206004810154835281832060059081015460038301548552929093209092015403905b5092915050565b610601878761015b565b8054600182015490925085126106e4576004810154600014156106cb57600481018690555b6004015460009081526001870160205260409020610626565b6003810154600014156106f957600381018690555b6003015460009081526001870160205260409020610626565b815193505b50505092915050565b60048301546000146107f757600483810154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201529181015460808301526005015460a082015291505b606082015160001461071257606091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015493810193909352600481015460808401526005015460a0830152610789565b60028301546000146108805750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b8151600382015414156108725780549350610717565b600281015460001415610889575b60009350610717565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a084015260009485529089019052912090915061085c565b60038301546000146109bc57600380840154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252918101546060830152600481015460808301526005015460a082015291505b608082015160001461071257608091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201526004820154938101939093526005015460a083015261094e565b60028301546000146108805750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b815160048201541415610a375780549350610717565b600281015460001415610a4957610880565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a0840152600094855290890190529120909150610a21565b50600081815260018601602052604090205b6001810154610ad5908686610b28565b805492505b50509392505050565b15610c0d57600160f060020a0319851660fa60020a600f021480610b0a5750600160f060020a0319851660f060020a613c3d02145b15610b4f57600481015460001415610bb65780549250610acc565b86865b6000600160f060020a0319831660f960020a601f021415610ffc57508083135b9392505050565b600160f060020a0319851660f960020a601f021480610b7f5750600160f060020a0319851660f060020a613e3d02145b80610b9b5750600160f060020a0319851660f060020a613d3d02145b15610c0d57600381015460001415610c585780549250610acc565b610bef610b25878360040160005054600081815260018301602052604081205b6003810154600014156110895760018101549150610695565b15610ac7576004015460009081526001860160205260409020610ab7565b600160f060020a0319851660fa60020a600f021480610c3d5750600160f060020a0319851660f060020a613c3d02145b15610caf57600381015460001415610cfa5760009250610acc565b610c91610b25878360030160005054600081815260018301602052604081205b6004810154600014156110a25760018101549150610695565b15610ac7576003015460009081526001860160205260409020610ab7565b600160f060020a0319851660f960020a601f021480610cdf5750600160f060020a0319851660f060020a613e3d02145b15610d1357600481015460001415610d505760009250610acc565b6003015460009081526001860160205260409020610ab7565b600160f060020a0319851660f060020a613d3d021415610d8c57600181015484901215610d6957600481015460001415610d505760009250610acc565b6004015460009081526001860160205260409020610ab7565b600181015484901315610d8c57600381015460001415610cfa5760009250610acc565b610ab7565b600282015460001415610fe0575b50505050565b90508060021415610e3d57610dc1848360030160005054610662565b6000191415610ddb57610ddb848360030160005054610e15565b8154610e3d9085905b600081815260018301602052604081206003810154909190819081908114156110d057610007565b8154610e719085905b60008181526001830160205260408120600481015490919081908190811415610e9657610007565b806001191415610e7157610e58848360040160005054610662565b60011415610e0c57610e0c848360040160005054610de4565b8060001913158015610e84575060018113155b15610d91578154610d91908590610f9d565b6004840180546000908152600188016020526040812060028088015490820181905592829055945014610f3257856001016000506000856002016000505460001916815260200190815260200160002060005091508360000160005054600019168260030160005054600019161415610f1d57826000016000505482600301600050819055505b835460048301541415610f3257825460048301555b6003830154600014610f63575060038201546000908152600186016020526040902080546004850155835460028201555b82546002808601919091558454600385015583015460001415610f9457826000016000505486600001600050819055505b83546110bb9087905b60008181526001830160205260408082206003810154835281832060059081015460048301548552928420015490926111db9291908183106111e85750816100c3565b6002909101546000908152600184016020526040902090610659565b600160f060020a0319831660fa60020a600f02141561101e5750808312610b48565b60f060020a613e3d02600160f060020a031984161415611042575080831215610b48565b600160f060020a0319831660f060020a613c3d021415611066575080831315610b48565b600160f060020a0319831660f060020a613d3d0214156100a05750828114610b48565b6003015460009081526001840160205260409020610bd6565b6004015460009081526001840160205260409020610c78565b82546110c8908790610f9d565b505050505050565b600384018054600090815260018801602052604081206002808801549082018190559282905594501461116c5785600101600050600085600201600050546000191681526020019081526020016000206000509150836000016000505460001916826003016000505460001916141561115757826000016000505482600301600050819055505b83546004830154141561116c57825460048301555b600483015460001461119e57506004820154600081815260018701602052604090206003850191909155835460028201555b82546002808601919091558454600485015583015460001415610f94578260000160005054866000016000508190555083546110bb908790610f9d565b6001016005820155505050565b50806100c356', - 'code_runtime': '0x6503060000000050606060405236156100a05760e060020a60003504630e9f1a3c81146100a55780632b4096b4146100c95780636ec13982146100eb578063a3119e571461010d578063a749f19b1461012f578063ab7366f714610151578063bacd695814610184578063bfdf87c0146101c2578063c4144b26146101e1578063caa46c9c14610240578063e6ce3a6a1461029f578063ed5bd7ea146102c2575b610007565b6102e560043560243560008181526001830160205260409020600401545b92915050565b6102e560043560243560008181526001830160205260409020600301546100c3565b6102e560043560243560008181526001830160205260409020600201546100c3565b6102e560043560243560008181526001838101602052604090912001546100c3565b6102e560043560243560008181526001830160205260409020600501546100c3565b6102f76004356024355b60008181526001830160205260408120805482918291829190861461030d575b50505050505050565b6102f7600435602435604435600082815260018401602052604081205481908190819086141561060157604081206001015485141561069c5761017b565b6102e560043560243560008181526001830160205260409020546100c3565b6102e56004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156107205760009350610717565b6102e56004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156108e55760009350610717565b6102e560043560243560443582546000908181811415610aa55760009250610acc565b6102f96004356024356000818152600183016020526040812060050154116100c3565b60408051918252519081900360200190f35b005b604080519115158252519081900360200190f35b6003810154600014158061032657506004810154600014155b1561034c5760038101546000146103a357805460018801906000906103b8908a9061024a565b60028101546000146105c45760028101546000908152600188016020526040902060038101548254919550141561038557600060038501555b80546004850154141561039a57600060048501555b835491506105c9565b805460018801906000906103cf908a906101eb565b8152602081019190915260400160002094506103e2565b8152602081019190915260400160002094505b6002850154600090815260018801602052604090206003810154865491955090925082141561043d5760048501546003850181905560001461043d576004850154600090815260018801602052604090208454600282015592505b60048401548554141561049b5760038501546004850181905560001461049b57866001016000506000866003016000505460001916815260200190815260200160002060005092508250836000016000505483600201600050819055505b6002808201549086018190556000146105185786600101600050600082600201600050546000191681526020019081526020016000206000509350835080600001600050546000191684600301600050546000191614156104fe57845460038501555b60048401548154141561051357845460048501555b61051d565b845487555b60038082015490860181905560001461056e57866001016000506000826003016000505460001916815260200190815260200160002060005092508250846000016000505483600201600050819055505b6004818101549086018190556000146105bf57866001016000506000826004016000505460001916815260200190815260200160002060005092508250846000016000505483600201600050819055505b6105c9565b600087555b60008082556001820181905560028201819055600382018190556004820181905560058201819055821461017b5761017b8783610647565b865460009250821415610612578587555b508554600090815260018701602052604090205b8054600014156106a657858155600281018290556001810185905561017b87875b60008181526001830160205260408120905b8154610da59085905b60008181526001830160205260408082206004810154835281832060059081015460038301548552929093209092015403905b5092915050565b610601878761015b565b8054600182015490925085126106e4576004810154600014156106cb57600481018690555b6004015460009081526001870160205260409020610626565b6003810154600014156106f957600381018690555b6003015460009081526001870160205260409020610626565b815193505b50505092915050565b60048301546000146107f757600483810154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201529181015460808301526005015460a082015291505b606082015160001461071257606091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015493810193909352600481015460808401526005015460a0830152610789565b60028301546000146108805750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b8151600382015414156108725780549350610717565b600281015460001415610889575b60009350610717565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a084015260009485529089019052912090915061085c565b60038301546000146109bc57600380840154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252918101546060830152600481015460808301526005015460a082015291505b608082015160001461071257608091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201526004820154938101939093526005015460a083015261094e565b60028301546000146108805750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b815160048201541415610a375780549350610717565b600281015460001415610a4957610880565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a0840152600094855290890190529120909150610a21565b50600081815260018601602052604090205b6001810154610ad5908686610b28565b805492505b50509392505050565b15610c0d57600160f060020a0319851660fa60020a600f021480610b0a5750600160f060020a0319851660f060020a613c3d02145b15610b4f57600481015460001415610bb65780549250610acc565b86865b6000600160f060020a0319831660f960020a601f021415610ffc57508083135b9392505050565b600160f060020a0319851660f960020a601f021480610b7f5750600160f060020a0319851660f060020a613e3d02145b80610b9b5750600160f060020a0319851660f060020a613d3d02145b15610c0d57600381015460001415610c585780549250610acc565b610bef610b25878360040160005054600081815260018301602052604081205b6003810154600014156110895760018101549150610695565b15610ac7576004015460009081526001860160205260409020610ab7565b600160f060020a0319851660fa60020a600f021480610c3d5750600160f060020a0319851660f060020a613c3d02145b15610caf57600381015460001415610cfa5760009250610acc565b610c91610b25878360030160005054600081815260018301602052604081205b6004810154600014156110a25760018101549150610695565b15610ac7576003015460009081526001860160205260409020610ab7565b600160f060020a0319851660f960020a601f021480610cdf5750600160f060020a0319851660f060020a613e3d02145b15610d1357600481015460001415610d505760009250610acc565b6003015460009081526001860160205260409020610ab7565b600160f060020a0319851660f060020a613d3d021415610d8c57600181015484901215610d6957600481015460001415610d505760009250610acc565b6004015460009081526001860160205260409020610ab7565b600181015484901315610d8c57600381015460001415610cfa5760009250610acc565b610ab7565b600282015460001415610fe0575b50505050565b90508060021415610e3d57610dc1848360030160005054610662565b6000191415610ddb57610ddb848360030160005054610e15565b8154610e3d9085905b600081815260018301602052604081206003810154909190819081908114156110d057610007565b8154610e719085905b60008181526001830160205260408120600481015490919081908190811415610e9657610007565b806001191415610e7157610e58848360040160005054610662565b60011415610e0c57610e0c848360040160005054610de4565b8060001913158015610e84575060018113155b15610d91578154610d91908590610f9d565b6004840180546000908152600188016020526040812060028088015490820181905592829055945014610f3257856001016000506000856002016000505460001916815260200190815260200160002060005091508360000160005054600019168260030160005054600019161415610f1d57826000016000505482600301600050819055505b835460048301541415610f3257825460048301555b6003830154600014610f63575060038201546000908152600186016020526040902080546004850155835460028201555b82546002808601919091558454600385015583015460001415610f9457826000016000505486600001600050819055505b83546110bb9087905b60008181526001830160205260408082206003810154835281832060059081015460048301548552928420015490926111db9291908183106111e85750816100c3565b6002909101546000908152600184016020526040902090610659565b600160f060020a0319831660fa60020a600f02141561101e5750808312610b48565b60f060020a613e3d02600160f060020a031984161415611042575080831215610b48565b600160f060020a0319831660f060020a613c3d021415611066575080831315610b48565b600160f060020a0319831660f060020a613d3d0214156100a05750828114610b48565b6003015460009081526001840160205260409020610bd6565b6004015460009081526001840160205260409020610c78565b82546110c8908790610f9d565b505050505050565b600384018054600090815260018801602052604081206002808801549082018190559282905594501461116c5785600101600050600085600201600050546000191681526020019081526020016000206000509150836000016000505460001916826003016000505460001916141561115757826000016000505482600301600050819055505b83546004830154141561116c57825460048301555b600483015460001461119e57506004820154600081815260018701602052604090206003850191909155835460028201555b82546002808601919091558454600485015583015460001415610f94578260000160005054866000016000508190555083546110bb908790610f9d565b6001016005820155505050565b50806100c356', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'Scheduler': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'args', - 'type': 'uint256[5]', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMaximumCallGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'callAPIVersion', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'callAddress', - 'type': 'address', - }, - ], - 'name': 'getNextCallSibling', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'callAddress', - 'type': 'address', - }, - ], - 'name': 'isKnownCall', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMaximumStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'callData', - 'type': 'bytes', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'args', - 'type': 'uint256[4]', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'defaultPayment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultGracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumCallGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getCallWindowSize', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'blockNumber', - 'type': 'uint256', - }, - ], - 'name': 'getNextCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'contractAddress', - 'type': 'address', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getFirstSchedulableBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultDonation', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumGracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultRequiredGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'updateDefaultPayment', - 'outputs': [], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'inputs': [], - 'type': 'constructor', - }, - ], - 'code': '0x60606040526611c37937e080006000556126a48061001d6000396000f36060604052361561027c5760e060020a600035046301991313811461027e57806303d22885146102ca5780630450991814610323578063049ae734146103705780630ce46c43146103c35780630e8502391461060f578063112e39a8146106825780631b4fa6ab146106cf5780631e74a2d3146106dd57806326a7985a1461070a5780633017fe241461075e578063346cabbc14610767578063373a1bc3146107e05780633a9e7433146108295780633c2c21a0146108795780633d9ce89b146108c5578063480b70bd1461093a578063481078431461098957806348f0518714610a185780634c471cde14610a905780634db3da8314610b13578063523ccfa814610b59578063586a69fa14610be95780635a9f2def14610c3d57806364ee49fe14610cb657806367beaccb14610d0c5780636840246014610d7b578063795b9a6f14610dd15780637b55c8b514610e485780637c73f84614610ee85780638c0e156d14610f1b5780638c1d01c814610f675780638e46afa914610f70578063938c430714610fc5578063971c803f146111625780639772c982146111b757806398c9cdf41461123357806398e00e54146112885780639f927be7146112dc578063a00aede914611389578063a1c0539d146113d9578063aff21c651461144f578063b152f19e1461147a578063b549793d146114cf578063b5b33eda1461154f578063bbc6eb1f1461159f578063c0f68859146115af578063c3a2c0c314611603578063c43d05751461164d578063d8e5c04814611696578063dbfef71014611233578063e29fb547146116e9578063e6470fbe1461173c578063ea27a8811461174e578063ee77fe86146117ce578063f158458c1461184e575b005b61187f600435602435604435600073__SchedulerLib__________________________6350d4e411600160005033878760206040519081016040528060008152602001506119fc610f74565b61187f60043560243560443560643560843560a43560c435600073__SchedulerLib__________________________6350d4e4116001600050338b8a602060405190810160405280600081526020015089611a1a6106d3565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503385600060e060020a026020604051908101604052806000815260200150611c42610f74565b61187f600435602435604435606435608435600073__SchedulerLib__________________________6350d4e4116001600050338989602060405190810160405280600081526020015088611c676106d3565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750506040805160a08082019092529597963596608435969095506101449450925060a491506005908390839080828437509095505050505050604080518082018252600160a060020a03338116825288166020820152815160c0810190925260009173__SchedulerLib__________________________9163e3042c0f91600191908a908a9089908b90808b8b9090602002015181526020018b60016005811015610002579090602002015181526020018b60026005811015610002579090602002015181526020018b60036005811015610002579090602002015181526020018b6004600581101561000257909060200201518152602001348152602001506040518860e060020a02815260040180888152602001876002602002808383829060006004602084601f0104600302600f01f15090500186600160e060020a0319168152602001806020018560ff1681526020018461ffff168152602001836006602002808383829060006004602084601f0104600302600f01f1509050018281038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105dc5780820380516001836020036101000a031916815260200191505b50985050505050505050506020604051808303818660325a03f415610002575050604051519150505b9695505050505050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f9581359591946044949293909201918190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e411600133808787611e94610f74565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611eb9610f74565b61189b5b6000611ecc611166565b6118b2600073__SchedulerLib__________________________63ea27a881600060005054611ed36115a3565b6118b2600073__SchedulerLib__________________________6326a7985a6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b6118b260075b90565b604080516020606435600481810135601f810184900484028501840190955284845261187f948135946024803595604435956084949201919081908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e411600133898988611f2e610f74565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503386866020604051908101604052806000815260200150611e94610f74565b61187f600435602435604435606435600073__SchedulerLib__________________________6350d4e411600160005033338960206040519081016040528060008152602001508861205a6106d3565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e4116001600050338786602060405190810160405280600081526020015061206c610f74565b60408051602060248035600481810135601f810185900485028601850190965285855261187f95813595919460449492939092019181908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e4116001338088886119fc610f74565b61187f600435602435604435606435600073__SchedulerLib__________________________6350d4e41160016000503388886020604051908101604052806000815260200150612085610f74565b61187f600435604080517fc4144b2600000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a0383166024820152905160009173__GroveLib______________________________9163c4144b269160448181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b604080516020604435600481810135601f810184900484028501840190955284845261187f9481359460248035959394606494929391019181908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e41160013388888861209f610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f94813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a43560c435600073__SchedulerLib__________________________6350d4e4116001338b8b8b896120bd6106d3565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503333866020604051908101604052806000815260200150611c42610f74565b6118c46004355b604080517fed5bd7ea00000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a0383166024820152905160009173__GroveLib______________________________9163ed5bd7ea9160448181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b61189b600073__SchedulerLib__________________________63586a69fa6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f9581359591946044949293909201918190840183828082843750949650509335935050606435915050600073__SchedulerLib__________________________6350d4e411600133808989612085610f74565b61187f60043560243560443560643560843560a435600073__SchedulerLib__________________________6350d4e4116001600050338a896020604051908101604052806000815260200150886120ca6106d3565b6040805160206004803580820135601f810184900484028501840190955284845261187f949193602493909291840191908190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e411600133808587611c42610f74565b61187f60043560243560443560643560843560a435600073__SchedulerLib__________________________6350d4e4116001600050338a8a6020604051908101604052806000815260200150896121e76106d3565b604080516020606435600481810135601f810184900484028501840190955284845261187f94813594602480359560443595608494920191908190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e4116001338888876121f4610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f9481359460248035959394606494929391019181908401838280828437505060408051608080820190925295979635969561010495509350608492508591508390839080828437509095505050505050600073__SchedulerLib__________________________6350d4e4116001338989898961220d6106d3565b6118b2600435602435604435600073__SchedulerLib__________________________63ea27a881858585612226611237565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e41160016000503333886020604051908101604052806000815260200150612277610f74565b6118b260005481565b6118d85b600073__SchedulerLib__________________________638e46afa96040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a43560c43560e43561010435600073__SchedulerLib__________________________6350d4e411600160005033338e8e8d8f8e8e8e8e8e346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111285780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519b9a5050505050505050505050565b61189b5b600073__SchedulerLib__________________________63971c803f6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750949650509335935050608435915050600073__SchedulerLib__________________________6350d4e411600133898989612291610f74565b6118b25b600073__SchedulerLib__________________________6398c9cdf46040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b6118b2600073__SchedulerLib__________________________6398e00e546040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b61187f600435604080517fe6ce3a6a000000000000000000000000000000000000000000000000000000008152600160048201527f3e3d000000000000000000000000000000000000000000000000000000000000602482015260448101839052905160009173__GroveLib______________________________9163e6ce3a6a9160648181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503385600060e060020a0260206040519081016040528060008152602001506122ab610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e4116001338787876122bc610f74565b6118b2600435600073__SchedulerLib__________________________63ea27a881836122ce6115a3565b6118b25b600073__SchedulerLib__________________________63b152f19e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a435600073__SchedulerLib__________________________6350d4e411600133808b8b896121e76106d3565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503386600060e060020a026020604051908101604052806000815260200150612329610f74565b6118b25b60005460649004610764565b6118b2600073__SchedulerLib__________________________63c0f688596040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b61187f600073__SchedulerLib__________________________6350d4e41160016000503333600060e060020a02602060405190810160405280600081526020015061233c610f74565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503333876020604051908101604052806000815260200150612329610f74565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e41160016000503387600060e060020a02602060405190810160405280600081526020015061246d610f74565b61187f600435602435604435606435608435600073__SchedulerLib__________________________6350d4e411600160005033338a60206040519081016040528060008152602001508961247f6106d3565b61027c60006000600061248c33610b60565b6118b2600435602435604435606435600073__SchedulerLib__________________________63ea27a881868686866040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506120529050565b604080516020604435600481810135601f810184900484028501840190955284845261187f94813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a435600073__SchedulerLib__________________________6350d4e4116001338a8a8a886126416106d3565b6118b2600435602435600073__SchedulerLib__________________________63ea27a88184846000612653611237565b60408051600160a060020a039092168252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60408051918252519081900360200190f35b604080519115158252519081900360200190f35b6040805160ff9092168252519081900360200190f35b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c65780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b9392505050565b611a046106d3565b60008b611a0f611237565b6000546118ee6115a3565b8f8e8e8d611a266115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611afe5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519998505050505050505050565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611c0e5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b919050565b611c4a6106d3565b6000611c5461147e565b611c5c611237565b600054611b366115a3565b60008d8d600060005054611c796115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611d515780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f41561000257505060405151979650505050505050565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611e5f5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b611e9c6106d3565b6000611ea661147e565b611eae611237565b600054611d876115a3565b611ec16106d3565b60008b611c5c611237565b9050610764565b6000611edd611237565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506107649050565b611f366106d3565b8c8b611f40611237565b600054611c796115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156120235780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b949350505050565b60008d8d600060005054611f4b6115a3565b6120746106d3565b8b61207d61147e565b611a0f611237565b61208d6106d3565b60008c8c600060005054611f4b6115a3565b6120a76106d3565b60008b6120b2611237565b600054611f4b6115a3565b60008e8e8d611a266115a3565b8e8d8d6000600050546120db6115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156121b35780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f4156100025750506040515191506106059050565b60008e8e8d6120db6115a3565b6121fc6106d3565b8b61220561147e565b6120b2611237565b8a5160208c015160408d015160608e0151611c796115a3565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506119f59050565b61227f6106d3565b60008c8c6000600050546118ee6115a3565b6122996106d3565b60008c8c600060005054611c796115a3565b6122b36106d3565b8b611ea661147e565b6122c46106d3565b600061207d61147e565b60006122d8611237565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f415610002575050604051519150611c3d9050565b6123316106d3565b60008b611eae611237565b6123446106d3565b600061234e61147e565b612356611237565b6000546123616115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156124395780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f4156100025750506040515191506107649050565b6124756106d3565b8a8c611a0f611237565b60008e8e8d611c796115a3565b1561263c5733925082600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fc6803622000000000000000000000000000000000000000000000000000000008252915191945063c680362291600482810192602092919082900301816000876161da5a03f115610002575050604051519050801561257d575082600160a060020a031663d379be236040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151600160a060020a03166000141590505b80156125895750600082115b80156125985750600054600190115b1561263c578183600160a060020a031663830953ab6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151606402919091049150506042811180156125f95750600054829011155b15612613576000805461271061271190910204905561263c565b6021811080156126265750600054829010155b1561263c576000805461271061270f9091020490555b505050565b60008d8d6000600050546120db6115a3565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f415610002575050604051519150611e8e905056', - 'code_runtime': '0x6060604052361561027c5760e060020a600035046301991313811461027e57806303d22885146102ca5780630450991814610323578063049ae734146103705780630ce46c43146103c35780630e8502391461060f578063112e39a8146106825780631b4fa6ab146106cf5780631e74a2d3146106dd57806326a7985a1461070a5780633017fe241461075e578063346cabbc14610767578063373a1bc3146107e05780633a9e7433146108295780633c2c21a0146108795780633d9ce89b146108c5578063480b70bd1461093a578063481078431461098957806348f0518714610a185780634c471cde14610a905780634db3da8314610b13578063523ccfa814610b59578063586a69fa14610be95780635a9f2def14610c3d57806364ee49fe14610cb657806367beaccb14610d0c5780636840246014610d7b578063795b9a6f14610dd15780637b55c8b514610e485780637c73f84614610ee85780638c0e156d14610f1b5780638c1d01c814610f675780638e46afa914610f70578063938c430714610fc5578063971c803f146111625780639772c982146111b757806398c9cdf41461123357806398e00e54146112885780639f927be7146112dc578063a00aede914611389578063a1c0539d146113d9578063aff21c651461144f578063b152f19e1461147a578063b549793d146114cf578063b5b33eda1461154f578063bbc6eb1f1461159f578063c0f68859146115af578063c3a2c0c314611603578063c43d05751461164d578063d8e5c04814611696578063dbfef71014611233578063e29fb547146116e9578063e6470fbe1461173c578063ea27a8811461174e578063ee77fe86146117ce578063f158458c1461184e575b005b61187f600435602435604435600073__SchedulerLib__________________________6350d4e411600160005033878760206040519081016040528060008152602001506119fc610f74565b61187f60043560243560443560643560843560a43560c435600073__SchedulerLib__________________________6350d4e4116001600050338b8a602060405190810160405280600081526020015089611a1a6106d3565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503385600060e060020a026020604051908101604052806000815260200150611c42610f74565b61187f600435602435604435606435608435600073__SchedulerLib__________________________6350d4e4116001600050338989602060405190810160405280600081526020015088611c676106d3565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750506040805160a08082019092529597963596608435969095506101449450925060a491506005908390839080828437509095505050505050604080518082018252600160a060020a03338116825288166020820152815160c0810190925260009173__SchedulerLib__________________________9163e3042c0f91600191908a908a9089908b90808b8b9090602002015181526020018b60016005811015610002579090602002015181526020018b60026005811015610002579090602002015181526020018b60036005811015610002579090602002015181526020018b6004600581101561000257909060200201518152602001348152602001506040518860e060020a02815260040180888152602001876002602002808383829060006004602084601f0104600302600f01f15090500186600160e060020a0319168152602001806020018560ff1681526020018461ffff168152602001836006602002808383829060006004602084601f0104600302600f01f1509050018281038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105dc5780820380516001836020036101000a031916815260200191505b50985050505050505050506020604051808303818660325a03f415610002575050604051519150505b9695505050505050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f9581359591946044949293909201918190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e411600133808787611e94610f74565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611eb9610f74565b61189b5b6000611ecc611166565b6118b2600073__SchedulerLib__________________________63ea27a881600060005054611ed36115a3565b6118b2600073__SchedulerLib__________________________6326a7985a6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b6118b260075b90565b604080516020606435600481810135601f810184900484028501840190955284845261187f948135946024803595604435956084949201919081908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e411600133898988611f2e610f74565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503386866020604051908101604052806000815260200150611e94610f74565b61187f600435602435604435606435600073__SchedulerLib__________________________6350d4e411600160005033338960206040519081016040528060008152602001508861205a6106d3565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e4116001600050338786602060405190810160405280600081526020015061206c610f74565b60408051602060248035600481810135601f810185900485028601850190965285855261187f95813595919460449492939092019181908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e4116001338088886119fc610f74565b61187f600435602435604435606435600073__SchedulerLib__________________________6350d4e41160016000503388886020604051908101604052806000815260200150612085610f74565b61187f600435604080517fc4144b2600000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a0383166024820152905160009173__GroveLib______________________________9163c4144b269160448181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b604080516020604435600481810135601f810184900484028501840190955284845261187f9481359460248035959394606494929391019181908401838280828437509496505093359350505050600073__SchedulerLib__________________________6350d4e41160013388888861209f610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f94813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a43560c435600073__SchedulerLib__________________________6350d4e4116001338b8b8b896120bd6106d3565b61187f600435600073__SchedulerLib__________________________6350d4e41160016000503333866020604051908101604052806000815260200150611c42610f74565b6118c46004355b604080517fed5bd7ea00000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a0383166024820152905160009173__GroveLib______________________________9163ed5bd7ea9160448181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b61189b600073__SchedulerLib__________________________63586a69fa6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f9581359591946044949293909201918190840183828082843750949650509335935050606435915050600073__SchedulerLib__________________________6350d4e411600133808989612085610f74565b61187f60043560243560443560643560843560a435600073__SchedulerLib__________________________6350d4e4116001600050338a896020604051908101604052806000815260200150886120ca6106d3565b6040805160206004803580820135601f810184900484028501840190955284845261187f949193602493909291840191908190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e411600133808587611c42610f74565b61187f60043560243560443560643560843560a435600073__SchedulerLib__________________________6350d4e4116001600050338a8a6020604051908101604052806000815260200150896121e76106d3565b604080516020606435600481810135601f810184900484028501840190955284845261187f94813594602480359560443595608494920191908190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e4116001338888876121f4610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f9481359460248035959394606494929391019181908401838280828437505060408051608080820190925295979635969561010495509350608492508591508390839080828437509095505050505050600073__SchedulerLib__________________________6350d4e4116001338989898961220d6106d3565b6118b2600435602435604435600073__SchedulerLib__________________________63ea27a881858585612226611237565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e41160016000503333886020604051908101604052806000815260200150612277610f74565b6118b260005481565b6118d85b600073__SchedulerLib__________________________638e46afa96040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a43560c43560e43561010435600073__SchedulerLib__________________________6350d4e411600160005033338e8e8d8f8e8e8e8e8e346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111285780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519b9a5050505050505050505050565b61189b5b600073__SchedulerLib__________________________63971c803f6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750949650509335935050608435915050600073__SchedulerLib__________________________6350d4e411600133898989612291610f74565b6118b25b600073__SchedulerLib__________________________6398c9cdf46040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b6118b2600073__SchedulerLib__________________________6398e00e546040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b61187f600435604080517fe6ce3a6a000000000000000000000000000000000000000000000000000000008152600160048201527f3e3d000000000000000000000000000000000000000000000000000000000000602482015260448101839052905160009173__GroveLib______________________________9163e6ce3a6a9160648181019260209290919082900301818660325a03f415610002575050604051519150611c3d9050565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503385600060e060020a0260206040519081016040528060008152602001506122ab610f74565b604080516020604435600481810135601f810184900484028501840190955284845261187f948135946024803595939460649492939101918190840183828082843750949650505050505050600073__SchedulerLib__________________________6350d4e4116001338787876122bc610f74565b6118b2600435600073__SchedulerLib__________________________63ea27a881836122ce6115a3565b6118b25b600073__SchedulerLib__________________________63b152f19e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b60408051602060248035600481810135601f810185900485028601850190965285855261187f958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a435600073__SchedulerLib__________________________6350d4e411600133808b8b896121e76106d3565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503386600060e060020a026020604051908101604052806000815260200150612329610f74565b6118b25b60005460649004610764565b6118b2600073__SchedulerLib__________________________63c0f688596040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506107649050565b61187f600073__SchedulerLib__________________________6350d4e41160016000503333600060e060020a02602060405190810160405280600081526020015061233c610f74565b61187f600435602435600073__SchedulerLib__________________________6350d4e41160016000503333876020604051908101604052806000815260200150612329610f74565b61187f600435602435604435600073__SchedulerLib__________________________6350d4e41160016000503387600060e060020a02602060405190810160405280600081526020015061246d610f74565b61187f600435602435604435606435608435600073__SchedulerLib__________________________6350d4e411600160005033338a60206040519081016040528060008152602001508961247f6106d3565b61027c60006000600061248c33610b60565b6118b2600435602435604435606435600073__SchedulerLib__________________________63ea27a881868686866040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506120529050565b604080516020604435600481810135601f810184900484028501840190955284845261187f94813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a435600073__SchedulerLib__________________________6350d4e4116001338a8a8a886126416106d3565b6118b2600435602435600073__SchedulerLib__________________________63ea27a88184846000612653611237565b60408051600160a060020a039092168252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60408051918252519081900360200190f35b604080519115158252519081900360200190f35b6040805160ff9092168252519081900360200190f35b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c65780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b9392505050565b611a046106d3565b60008b611a0f611237565b6000546118ee6115a3565b8f8e8e8d611a266115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611afe5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519998505050505050505050565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611c0e5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b919050565b611c4a6106d3565b6000611c5461147e565b611c5c611237565b600054611b366115a3565b60008d8d600060005054611c796115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611d515780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f41561000257505060405151979650505050505050565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611e5f5780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b611e9c6106d3565b6000611ea661147e565b611eae611237565b600054611d876115a3565b611ec16106d3565b60008b611c5c611237565b9050610764565b6000611edd611237565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506107649050565b611f366106d3565b8c8b611f40611237565b600054611c796115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156120235780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f415610002575050604051519150505b949350505050565b60008d8d600060005054611f4b6115a3565b6120746106d3565b8b61207d61147e565b611a0f611237565b61208d6106d3565b60008c8c600060005054611f4b6115a3565b6120a76106d3565b60008b6120b2611237565b600054611f4b6115a3565b60008e8e8d611a266115a3565b8e8d8d6000600050546120db6115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156121b35780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f4156100025750506040515191506106059050565b60008e8e8d6120db6115a3565b6121fc6106d3565b8b61220561147e565b6120b2611237565b8a5160208c015160408d015160608e0151611c796115a3565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f4156100025750506040515191506119f59050565b61227f6106d3565b60008c8c6000600050546118ee6115a3565b6122996106d3565b60008c8c600060005054611c796115a3565b6122b36106d3565b8b611ea661147e565b6122c46106d3565b600061207d61147e565b60006122d8611237565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f415610002575050604051519150611c3d9050565b6123316106d3565b60008b611eae611237565b6123446106d3565b600061234e61147e565b612356611237565b6000546123616115a3565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b600160e060020a0319168152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156124395780820380516001836020036101000a031916815260200191505b509e5050505050505050505050505050506020604051808303818660325a03f4156100025750506040515191506107649050565b6124756106d3565b8a8c611a0f611237565b60008e8e8d611c796115a3565b1561263c5733925082600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fc6803622000000000000000000000000000000000000000000000000000000008252915191945063c680362291600482810192602092919082900301816000876161da5a03f115610002575050604051519050801561257d575082600160a060020a031663d379be236040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151600160a060020a03166000141590505b80156125895750600082115b80156125985750600054600190115b1561263c578183600160a060020a031663830953ab6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151606402919091049150506042811180156125f95750600054829011155b15612613576000805461271061271190910204905561263c565b6021811080156126265750600054829010155b1561263c576000805461271061270f9091020490555b505050565b60008d8d6000600050546120db6115a3565b6040518560e060020a028152600401808581526020018481526020018381526020018281526020019450505050506020604051808303818660325a03f415610002575050604051519150611e8e905056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'SchedulerAPI': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'SchedulerInterface': { - 'abi': [ - { - 'constant': True, - 'inputs': [ - { - 'name': 'callAddress', - 'type': 'address', - }, - ], - 'name': 'isKnownCall', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'SchedulerLib': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'getMaximumCallGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'callIndex', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'schedulerAddress', - 'type': 'address', - }, - { - 'name': 'contractAddress', - 'type': 'address', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - { - 'name': 'endowment', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'version', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - { - 'name': '', - 'type': 'uint16', - }, - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMaximumStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getDefaultGracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint8', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumCallCost', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumStackCheck', - 'outputs': [ - { - 'name': '', - 'type': 'uint16', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumCallGas', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getCallWindowSize', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getFirstSchedulableBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'getMinimumGracePeriod', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'callIndex', - 'type': 'GroveLib.Index storage', - }, - { - 'name': 'addresses', - 'type': 'address[2]', - }, - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'callData', - 'type': 'bytes', - }, - { - 'name': 'gracePeriod', - 'type': 'uint8', - }, - { - 'name': 'requiredStackDepth', - 'type': 'uint16', - }, - { - 'name': 'uints', - 'type': 'uint256[6]', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [ - { - 'name': 'basePayment', - 'type': 'uint256', - }, - { - 'name': 'baseDonation', - 'type': 'uint256', - }, - { - 'name': 'callValue', - 'type': 'uint256', - }, - { - 'name': 'requiredGas', - 'type': 'uint256', - }, - ], - 'name': 'getMinimumEndowment', - 'outputs': [ - { - 'name': 'endowment', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': False, - 'name': 'call_address', - 'type': 'address', - }, - ], - 'name': 'CallScheduled', - 'type': 'event', - }, - { - 'anonymous': False, - 'inputs': [ - { - 'indexed': True, - 'name': 'schedulerAddress', - 'type': 'address', - }, - { - 'indexed': False, - 'name': 'reason', - 'type': 'bytes32', - }, - ], - 'name': 'CallRejected', - 'type': 'event', - }, - ], - 'code': '0x6060604052611a4c806100126000396000f36503060000000050606060405236156100ab5760e060020a600035046326a7985a81146100b057806350d4e411146100be57806354fd4d501461023d578063586a69fa1461025d5780638e46afa91461026857806396cff3df14610272578063971c803f1461029657806398c9cdf4146102a157806398e00e54146102ae578063b152f19e146102b8578063c0f68859146102c4578063e3042c0f146102cf578063ea27a88114610476575b610007565b6102845b60006104e36102a5565b604080516020601f608435600481810135928301849004840285018401909552818452610497948035946024803595604435956064359560a494930191819084018382808284375094965050933593505060c43591505060e435610104356101243561014435610164356101843560006101806040519081016040528060008152602001600081526020016000815260200160206040519081016040528060008152602001508152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200150610180604051908101604052808f81526020018e81526020018d81526020018c81526020018981526020018b81526020018a81526020018881526020018781526020018681526020018581526020018481526020015090506104ec8f825b600060006000600a43018460e0015110156105f4577f544f4f5f534f4f4e000000000000000000000000000000000000000000000000915061053c565b604080516000808252600760208301528183015290519081900360600190f35b6104b45b6103e85b90565b6104cc60ff610265565b62030d403a0260026024356004350102015b60408051918252519081900360200190f35b6104b45b600a610265565b6102845b62030d40610265565b6102846010610265565b61028443600a01610265565b6102845b6020610265565b604080518082018252610497916004803592909160649190602490600290839083908082843780516020601f608435808c01359182018390048302840183019094528083529499983598975060a49650909450910191908190840183828082843750506040805160c0818101909252959796359660c435969095506101a49450925060e491506006908390839080828437509095505050505050604080516101808181018352600080835260208381018290528385018290528451908101855281815260608401526080830181905260a0830181905260c0830181905260e0830181905261010083018190526101208301819052610140830181905261016083018190528351918201909352808984602090810290910151825201896001602090810290910151825281018990526040810188905260600184600060209081029091015182528101879052604081018690526060018460016020908102909101518252018460026020908102909101518252018460036020908102909101518252018460046020908102909101518252018460056020020151905290506104ff8982610200565b6102846004356024356044356064355b3a0292909101600202919091010190565b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b6040805160ff929092168252519081900360200190f35b45039050610265565b9f9e505050505050505050505050505050565b9998505050505050505050565b846101600151101561053c577f494e53554646494349454e545f46554e4453000000000000000000000000000091505b60008214610703576040805185518482529151600160a060020a0392909216917f513485fc54ef019ef1bc1ea683ef7d5d522f2865224ae10871ff992749c0ba4f9181900360200190a273__AccountingLib_________________________6312c82bcc85600001518661016001516040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f415610007575050505b505092915050565b8360c0015161ffff1661060561029a565b61ffff1611806106275750610618610261565b61ffff168460c0015161ffff16115b15610654577f535441434b5f434845434b5f4f55545f4f465f52414e47450000000000000000915061053c565b61065c6102c8565b8460a0015160ff161015610692577f47524143455f544f4f5f53484f52540000000000000000000000000000000000915061053c565b61069a6102a5565b84610100015110806106b757506106af6100b4565b846101000151115b156106e4577f52455155495245445f4741535f4f55545f4f465f52414e474500000000000000915061053c565b61050c8461012001518561014001518660800151876101000151610486565b83610160015184600001518560e001518660a001518760200151886040015189606001518a608001518b61010001518c60c001518d61012001518e61014001516040516111208061092c833901808c600160a060020a031681526020018b81526020018a60ff16815260200189600160a060020a03168152602001887bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001806020018781526020018681526020018561ffff1681526020018481526020018381526020018281038252888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156108215780820380516001836020036101000a031916815260200191505b509c505050505050505050505050506040518091039082f09050905073__GroveLib______________________________63bacd69588683600160a060020a031660010284600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060408051805160e060020a87028252600482019590955260248101939093526044830193909352509051606482810192600092919082900301818660325a03f41561000757505060408051600160a060020a038416815290517f2b05d346f0b0b9fd470024751c52d3b5dac5c37796f077c1a66241f2eada44b792509081900360200190a18092506105ec56606060405260405161112038038061112083398101604052805160805160a05160c05160e05161010051610120516101405161016051610180516101a051999a98999798969795969490940194929391929091908a84848a8a8a8a8888600c8054600160a060020a031990811633179091556000805482168b1781556001848155600284815560078c90556008805461ffff19168c1790553a600655600380547c01000000000000000000000000000000000000000000000000000000008b04740100000000000000000000000000000000000000000295168b1760a060020a63ffffffff021916949094179093556004805488519382905290936020601f9383161561010002600019019092160482018190047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b908101939290918901908390106101d757805160ff19168380011785555b5061016e9291505b80821115610207576000815560010161015a565b505060058390555050505050505050508a600060006101000a815481600160a060020a030219169083021790555089600d6000508190555088600e60006101000a81548160ff021916908302179055505050505050505050505050610f158061020b6000396000f35b82800160010185558215610152579182015b828111156101525782518260005055916020019190600101906101e9565b509056606060405236156101ab5760e060020a60003504630924120081146101d05780630a16697a146101dd5780630fd1f94e146101e6578063137c638b1461023a57806321835af61461024757806324032866146102605780632f95b833146102e05780633017fe24146102ef5780633233c686146102f9578063349501b71461030457806337f4c00e1461031d5780634500054f146103285780634e417a98146103995780634e71d92d146104025780634f059a43146104145780636146195414610470578063625cc4651461048057806367ce940d146104895780637d298ee314610496578063830953ab14610516578063938b5f321461052157806395ee122114610533578063974654f414610547578063a06db7dc14610552578063a9d2293d1461055e578063ae45850b146105b2578063b0f07e44146105c4578063c19d93fb146105e6578063c6502da814610647578063c680362214610650578063ca94692d14610664578063cc3471af1461068d578063d379be23146106e1578063d62457f6146106fb578063ea8a1af014610706578063f556275314610808578063f6b4dfb414610867575b61087b60008054819033600160a060020a0390811691161461088f57600091506109a4565b61087b600b5460ff165b90565b6109a8600d5481565b6109a8600073__CallLib_______________________________630fd1f94e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a85b62012cc86101da565b61087b60043560008160001415610aa957506001610ba9565b61087b600435602435600073__CallLib_______________________________630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b6109ba60085461ffff166101da565b6109a860026101da565b6109a8600a546101da565b61087b60043560008160001415610b3057506001610ba9565b6109a86006546101da565b61087b600073__CallLib_______________________________63a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109d160408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610bd95780601f10610bae57610100808354040283529160200191610bd9565b61087b60006000600180610be56105ea565b6109a8600073__CallLib_______________________________63f5562753436040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a3f6000600480610cfe6105ea565b6109a860025481565b6109a85b620186a06101da565b61087b6004356024355b600073__CallLib_______________________________63a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506102da9050565b6109a86009546101da565b610a41600c54600160a060020a031681565b61087b600b5462010000900460ff166101da565b6109a86007546101da565b610a5e600e5460ff1681565b6109a8600073__CallLib_______________________________63a9d2293d6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600054600160a060020a031681565b61087b600080548190600160a060020a039081163390911614610e25576109a4565b6109a85b600073__CallLib_______________________________635054d98a60036000506040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a860015481565b61087b600b5460ff610100909104166101da565b610a7460035474010000000000000000000000000000000000000000900460e060020a026101da565b6109a8600073__CallLib_______________________________63cc3471af6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600854620100009004600160a060020a03166101da565b6109a86005546101da565b610a3f604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________9163a094315491604480830192602092919082900301818660325a03f4156100025750506040515115905061080657604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________91637e92656291604482810192600092919082900301818660325a03f415610002575050505b565b6109a8600435600073__CallLib_______________________________63f5562753836040518260e060020a028152600401808281526020019150506020604051808303818660325a03f415610002575050604051519150610ba99050565b610a41600354600160a060020a03166101da565b604080519115158252519081900360200190f35b60045460006002600019600184161561010002019092169190910411156108b957600091506109a4565b6108c16105ea565b9050600081141580156108d5575060018114155b80156108e2575060028114155b156108f057600091506109a4565b6004805460008281527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6020601f6002600186161561010002600019019095169490940484010481019236929083901061096d5782800160ff198235161785555b5061099d9291505b808211156109a45760008155600101610959565b82800160010185558215610951579182015b8281111561095157823582600050559160200191906001019061097f565b5050600191505b5090565b60408051918252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f2925050501515610ba957610002565b604080517f5f5f6469672875696e74323536290000000000000000000000000000000000008152815190819003600e01812060e060020a90819004908102825260001985016004830152915130600160a060020a031692916102bc86029160248281019260009291908290030181838887f19450505050505b919050565b820191906000526020600020905b815481529060010190602001808311610bbc57829003601f168201915b505050505090506101da565b1415610ceb57604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a031660248301523460448301526064820152905173__CallLib_______________________________91630fee183d91608480830192602092919082900301818660325a03f41561000257505060405151925050811515610cf05773__AccountingLib_________________________6312c82bcc33346040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100025750506040515115159050610cf057610002565b505090565b819250506109a4565b505b50565b1415610cf9575a9150610d1133836104a0565b1515610d1d5750610cfb565b73__CallLib_______________________________63da46be0a60038433610d4361048d565b610d4b61023e565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a03168152602001838152602001828152602001955050505050506000604051808303818660325a03f41561000257505050610cf933604080516000547fc17e6817000000000000000000000000000000000000000000000000000000008252600160a060020a0390811660048301523016316024820152905173__CallLib_______________________________9163c17e681791604480830192602092919082900301818660325a03f4156100025750505050565b6004546000600260018316156101000260001901909216919091041115610e4f57600091506109a4565b610e576105ea565b905060008114158015610e6b575060018114155b8015610e78575060028114155b15610e8657600091506109a4565b604080517f7c0278fc00000000000000000000000000000000000000000000000000000000815260036004820181815260248301938452366044840181905273__CallLib_______________________________94637c0278fc94600093919060640184848082843782019150509450505050506000604051808303818660325a03f41561000257505050509056', - 'code_runtime': '0x6503060000000050606060405236156100ab5760e060020a600035046326a7985a81146100b057806350d4e411146100be57806354fd4d501461023d578063586a69fa1461025d5780638e46afa91461026857806396cff3df14610272578063971c803f1461029657806398c9cdf4146102a157806398e00e54146102ae578063b152f19e146102b8578063c0f68859146102c4578063e3042c0f146102cf578063ea27a88114610476575b610007565b6102845b60006104e36102a5565b604080516020601f608435600481810135928301849004840285018401909552818452610497948035946024803595604435956064359560a494930191819084018382808284375094965050933593505060c43591505060e435610104356101243561014435610164356101843560006101806040519081016040528060008152602001600081526020016000815260200160206040519081016040528060008152602001508152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200150610180604051908101604052808f81526020018e81526020018d81526020018c81526020018981526020018b81526020018a81526020018881526020018781526020018681526020018581526020018481526020015090506104ec8f825b600060006000600a43018460e0015110156105f4577f544f4f5f534f4f4e000000000000000000000000000000000000000000000000915061053c565b604080516000808252600760208301528183015290519081900360600190f35b6104b45b6103e85b90565b6104cc60ff610265565b62030d403a0260026024356004350102015b60408051918252519081900360200190f35b6104b45b600a610265565b6102845b62030d40610265565b6102846010610265565b61028443600a01610265565b6102845b6020610265565b604080518082018252610497916004803592909160649190602490600290839083908082843780516020601f608435808c01359182018390048302840183019094528083529499983598975060a49650909450910191908190840183828082843750506040805160c0818101909252959796359660c435969095506101a49450925060e491506006908390839080828437509095505050505050604080516101808181018352600080835260208381018290528385018290528451908101855281815260608401526080830181905260a0830181905260c0830181905260e0830181905261010083018190526101208301819052610140830181905261016083018190528351918201909352808984602090810290910151825201896001602090810290910151825281018990526040810188905260600184600060209081029091015182528101879052604081018690526060018460016020908102909101518252018460026020908102909101518252018460036020908102909101518252018460046020908102909101518252018460056020020151905290506104ff8982610200565b6102846004356024356044356064355b3a0292909101600202919091010190565b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b6040805160ff929092168252519081900360200190f35b45039050610265565b9f9e505050505050505050505050505050565b9998505050505050505050565b846101600151101561053c577f494e53554646494349454e545f46554e4453000000000000000000000000000091505b60008214610703576040805185518482529151600160a060020a0392909216917f513485fc54ef019ef1bc1ea683ef7d5d522f2865224ae10871ff992749c0ba4f9181900360200190a273__AccountingLib_________________________6312c82bcc85600001518661016001516040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f415610007575050505b505092915050565b8360c0015161ffff1661060561029a565b61ffff1611806106275750610618610261565b61ffff168460c0015161ffff16115b15610654577f535441434b5f434845434b5f4f55545f4f465f52414e47450000000000000000915061053c565b61065c6102c8565b8460a0015160ff161015610692577f47524143455f544f4f5f53484f52540000000000000000000000000000000000915061053c565b61069a6102a5565b84610100015110806106b757506106af6100b4565b846101000151115b156106e4577f52455155495245445f4741535f4f55545f4f465f52414e474500000000000000915061053c565b61050c8461012001518561014001518660800151876101000151610486565b83610160015184600001518560e001518660a001518760200151886040015189606001518a608001518b61010001518c60c001518d61012001518e61014001516040516111208061092c833901808c600160a060020a031681526020018b81526020018a60ff16815260200189600160a060020a03168152602001887bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001806020018781526020018681526020018561ffff1681526020018481526020018381526020018281038252888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156108215780820380516001836020036101000a031916815260200191505b509c505050505050505050505050506040518091039082f09050905073__GroveLib______________________________63bacd69588683600160a060020a031660010284600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060408051805160e060020a87028252600482019590955260248101939093526044830193909352509051606482810192600092919082900301818660325a03f41561000757505060408051600160a060020a038416815290517f2b05d346f0b0b9fd470024751c52d3b5dac5c37796f077c1a66241f2eada44b792509081900360200190a18092506105ec56606060405260405161112038038061112083398101604052805160805160a05160c05160e05161010051610120516101405161016051610180516101a051999a98999798969795969490940194929391929091908a84848a8a8a8a8888600c8054600160a060020a031990811633179091556000805482168b1781556001848155600284815560078c90556008805461ffff19168c1790553a600655600380547c01000000000000000000000000000000000000000000000000000000008b04740100000000000000000000000000000000000000000295168b1760a060020a63ffffffff021916949094179093556004805488519382905290936020601f9383161561010002600019019092160482018190047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b908101939290918901908390106101d757805160ff19168380011785555b5061016e9291505b80821115610207576000815560010161015a565b505060058390555050505050505050508a600060006101000a815481600160a060020a030219169083021790555089600d6000508190555088600e60006101000a81548160ff021916908302179055505050505050505050505050610f158061020b6000396000f35b82800160010185558215610152579182015b828111156101525782518260005055916020019190600101906101e9565b509056606060405236156101ab5760e060020a60003504630924120081146101d05780630a16697a146101dd5780630fd1f94e146101e6578063137c638b1461023a57806321835af61461024757806324032866146102605780632f95b833146102e05780633017fe24146102ef5780633233c686146102f9578063349501b71461030457806337f4c00e1461031d5780634500054f146103285780634e417a98146103995780634e71d92d146104025780634f059a43146104145780636146195414610470578063625cc4651461048057806367ce940d146104895780637d298ee314610496578063830953ab14610516578063938b5f321461052157806395ee122114610533578063974654f414610547578063a06db7dc14610552578063a9d2293d1461055e578063ae45850b146105b2578063b0f07e44146105c4578063c19d93fb146105e6578063c6502da814610647578063c680362214610650578063ca94692d14610664578063cc3471af1461068d578063d379be23146106e1578063d62457f6146106fb578063ea8a1af014610706578063f556275314610808578063f6b4dfb414610867575b61087b60008054819033600160a060020a0390811691161461088f57600091506109a4565b61087b600b5460ff165b90565b6109a8600d5481565b6109a8600073__CallLib_______________________________630fd1f94e6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a85b62012cc86101da565b61087b60043560008160001415610aa957506001610ba9565b61087b600435602435600073__CallLib_______________________________630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f415610002575050604051519150505b92915050565b6109ba60085461ffff166101da565b6109a860026101da565b6109a8600a546101da565b61087b60043560008160001415610b3057506001610ba9565b6109a86006546101da565b61087b600073__CallLib_______________________________63a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109d160408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610bd95780601f10610bae57610100808354040283529160200191610bd9565b61087b60006000600180610be56105ea565b6109a8600073__CallLib_______________________________63f5562753436040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a3f6000600480610cfe6105ea565b6109a860025481565b6109a85b620186a06101da565b61087b6004356024355b600073__CallLib_______________________________63a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506102da9050565b6109a86009546101da565b610a41600c54600160a060020a031681565b61087b600b5462010000900460ff166101da565b6109a86007546101da565b610a5e600e5460ff1681565b6109a8600073__CallLib_______________________________63a9d2293d6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600054600160a060020a031681565b61087b600080548190600160a060020a039081163390911614610e25576109a4565b6109a85b600073__CallLib_______________________________635054d98a60036000506040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515191506101da9050565b6109a860015481565b61087b600b5460ff610100909104166101da565b610a7460035474010000000000000000000000000000000000000000900460e060020a026101da565b6109a8600073__CallLib_______________________________63cc3471af6040518160e060020a0281526004018090506020604051808303818660325a03f4156100025750506040515191506101da9050565b610a41600854620100009004600160a060020a03166101da565b6109a86005546101da565b610a3f604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________9163a094315491604480830192602092919082900301818660325a03f4156100025750506040515115905061080657604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a03166024820152905173__CallLib_______________________________91637e92656291604482810192600092919082900301818660325a03f415610002575050505b565b6109a8600435600073__CallLib_______________________________63f5562753836040518260e060020a028152600401808281526020019150506020604051808303818660325a03f415610002575050604051519150610ba99050565b610a41600354600160a060020a03166101da565b604080519115158252519081900360200190f35b60045460006002600019600184161561010002019092169190910411156108b957600091506109a4565b6108c16105ea565b9050600081141580156108d5575060018114155b80156108e2575060028114155b156108f057600091506109a4565b6004805460008281527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6020601f6002600186161561010002600019019095169490940484010481019236929083901061096d5782800160ff198235161785555b5061099d9291505b808211156109a45760008155600101610959565b82800160010185558215610951579182015b8281111561095157823582600050559160200191906001019061097f565b5050600191505b5090565b60408051918252519081900360200190f35b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f2925050501515610ba957610002565b604080517f5f5f6469672875696e74323536290000000000000000000000000000000000008152815190819003600e01812060e060020a90819004908102825260001985016004830152915130600160a060020a031692916102bc86029160248281019260009291908290030181838887f19450505050505b919050565b820191906000526020600020905b815481529060010190602001808311610bbc57829003601f168201915b505050505090506101da565b1415610ceb57604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a031660248301523460448301526064820152905173__CallLib_______________________________91630fee183d91608480830192602092919082900301818660325a03f41561000257505060405151925050811515610cf05773__AccountingLib_________________________6312c82bcc33346040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303818660325a03f4156100025750506040515115159050610cf057610002565b505090565b819250506109a4565b505b50565b1415610cf9575a9150610d1133836104a0565b1515610d1d5750610cfb565b73__CallLib_______________________________63da46be0a60038433610d4361048d565b610d4b61023e565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a03168152602001838152602001828152602001955050505050506000604051808303818660325a03f41561000257505050610cf933604080516000547fc17e6817000000000000000000000000000000000000000000000000000000008252600160a060020a0390811660048301523016316024820152905173__CallLib_______________________________9163c17e681791604480830192602092919082900301818660325a03f4156100025750505050565b6004546000600260018316156101000260001901909216919091041115610e4f57600091506109a4565b610e576105ea565b905060008114158015610e6b575060018114155b8015610e78575060028114155b15610e8657600091506109a4565b604080517f7c0278fc00000000000000000000000000000000000000000000000000000000815260036004820181815260248301938452366044840181905273__CallLib_______________________________94637c0278fc94600093919060640184848082843782019150509450505050506000604051808303818660325a03f41561000257505050509056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'TokenCallContract': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'schedulerAddress', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x606060405260428060106000396000f3606060405260e060020a6000350463ae45850b8114601a575b005b603860005473ffffffffffffffffffffffffffffffffffffffff1681565b6060908152602090f3', - 'code_runtime': '0x606060405260e060020a6000350463ae45850b8114601a575b005b603860005473ffffffffffffffffffffffffffffffffffffffff1681565b6060908152602090f3', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'TokenScheduler': { - 'abi': [ - { - 'constant': False, - 'inputs': [ - { - 'name': 'callAddress', - 'type': 'address', - }, - ], - 'name': 'isKnownCall', - 'outputs': [ - { - 'name': '', - 'type': 'bool', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [ - { - 'name': 'abiSignature', - 'type': 'bytes4', - }, - { - 'name': 'targetBlock', - 'type': 'uint256', - }, - ], - 'name': 'scheduleCall', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - ], - 'code': '0x', - 'code_runtime': '0x', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'TrustFund': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'beneficiary', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': True, - 'inputs': [], - 'name': 'releaseBlock', - 'outputs': [ - { - 'name': '', - 'type': 'uint256', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'releaseFunds', - 'outputs': [], - 'type': 'function', - }, - { - 'inputs': [ - { - 'name': '_beneficiary', - 'type': 'address', - }, - { - 'name': '_releaseBlock', - 'type': 'uint256', - }, - { - 'name': 'alarmScheduler', - 'type': 'address', - }, - ], - 'type': 'constructor', - }, - ], - 'code': '0x606060405260405160608061015f83395060c06040525160805160a05160008054600160a060020a0319168417815560018390557f112e39a80000000000000000000000000000000000000000000000000000000060c090815260c4849052600160a060020a0383169163112e39a89160e4919060248183876161da5a03f15050505050505060cd806100926000396000f36060604052361560315760e060020a600035046338af3eed811460395780634c77a10f14604a57806369d89575146052575b607560736055565b6077600054600160a060020a031681565b609460015481565b60755b30600160a060020a03163160001480606e575060015443105b1560a6575b565b005b60408051600160a060020a03929092168252519081900360200190f35b60408051918252519081900360200190f35b60008054604051600160a060020a0391821692913016319082818181858883f1505050505056', - 'code_runtime': '0x6060604052361560315760e060020a600035046338af3eed811460395780634c77a10f14604a57806369d89575146052575b607560736055565b6077600054600160a060020a031681565b609460015481565b60755b30600160a060020a03163160001480606e575060015443105b1560a6575b565b005b60408051600160a060020a03929092168252519081900360200190f35b60408051918252519081900360200190f35b60008054604051600160a060020a0391821692913016319082818181858883f1505050505056', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - 'owned': { - 'abi': [ - { - 'constant': True, - 'inputs': [], - 'name': 'owner', - 'outputs': [ - { - 'name': '', - 'type': 'address', - }, - ], - 'type': 'function', - }, - { - 'constant': False, - 'inputs': [], - 'name': 'Owned', - 'outputs': [], - 'type': 'function', - }, - ], - 'code': '0x6060604052606f8060106000396000f3606060405260e060020a60003504638da5cb5b81146024578063b303dcbd146042575b005b606560005473ffffffffffffffffffffffffffffffffffffffff1681565b60226000805473ffffffffffffffffffffffffffffffffffffffff191633179055565b6060908152602090f3', - 'code_runtime': '0x606060405260e060020a60003504638da5cb5b81146024578063b303dcbd146042575b005b606560005473ffffffffffffffffffffffffffffffffffffffff1681565b60226000805473ffffffffffffffffffffffffffffffffffffffff191633179055565b6060908152602090f3', - 'meta': { - 'compilerVersion': '0.3.6-0', - 'language': 'Solidity', - 'languageVersion': '0', - }, - 'source': None, - }, - } diff --git a/tests/transaction-request/test_request_factory.py b/tests/transaction-request/test_request_factory.py new file mode 100644 index 000000000..752ba270f --- /dev/null +++ b/tests/transaction-request/test_request_factory.py @@ -0,0 +1,60 @@ +def test_request_factory(chain, web3, denoms): + factory = chain.get_contract('RequestFactory') + Request = chain.get_contract_factory('TransactionRequest') + RequestLib = chain.get_contract_factory('RequestLib') + + chain_code = web3.eth.getCode(factory.address) + assert len(chain_code) > 10 + + window_start = web3.eth.blockNumber + 20 + + create_txn_hash = factory.transact({ + 'value': 10 * denoms.ether, + }).createRequest( + addressArgs=[ + '0xd3cda913deb6f67967b99d67acdfa1712c293601', + web3.eth.coinbase, + ], + uintArgs=[ + 255, # claimWindowSize + 12345, # donation + 54321, # payment + 10, # freezePeriod + 16, # reservedWindowSize + 1, # temporalUnit (blocks) + window_start, # windowStart + 255, # windowSize + 1000000, # callGas + 123456789, # callValue + 0, # requiredStackDepth + ], + callData='', + ) + create_txn_receipt = chain.wait.for_receipt(create_txn_hash) + + request_created_filter = factory.pastEvents('RequestCreated') + request_created_logs = request_created_filter.get() + assert len(request_created_logs) == 1 + + log_data = request_created_logs[0] + + request_address = log_data['args']['request'] + request = Request(address=request_address) + + chain.wait.for_block(window_start) + + #request_data = request.call().requestData() + #request_call_data = request.call().callData() + + execute_txn_hash = request.transact({'gas': 3000000}).execute() + execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) + + execute_filter = RequestLib.pastEvents('Executed', { + 'address': request.address, + }) + execute_logs = execute_filter.get() + assert len(execute_logs) == 1 + execute_data = execute_logs[0] + + benefactor_balance = web3.eth.getBalance('0xd3cda913deb6f67967b99d67acdfa1712c293601') + assert False From 91338b8e2bdcecbae811ec28801641d128108885 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Fri, 16 Sep 2016 20:58:56 -0600 Subject: [PATCH 05/25] dirty dirty dirty --- conftest.py | 254 ----------- contracts/ClaimLib.sol | 43 +- contracts/GasLib.sol | 17 +- contracts/MathLib.sol | 65 +++ contracts/PaymentLib.sol | 85 ++-- contracts/RequestFactory.sol | 54 ++- contracts/RequestFactoryInterface.sol | 2 +- contracts/RequestLib.sol | 393 ++++++++++++------ contracts/RequestMetaLib.sol | 6 + ...ScheduleLib.sol => RequestScheduleLib.sol} | 88 +++- contracts/RequestTracker.sol | 64 +++ contracts/RequestTrackerInterface.sol | 12 + contracts/SafeSendLib.sol | 46 ++ contracts/TransactionRequest.sol | 115 ++++- contracts/TransactionRequestInterface.sol | 22 + docs/changelog.rst | 14 + tests/accounting/test_call_donation.py | 41 -- tests/accounting/test_call_gas_scalar.py | 48 --- tests/accounting/test_call_payout.py | 43 -- ...est_early_claim_reduces_default_payment.py | 41 -- ..._extra_payment_when_claimer_doesnt_call.py | 58 --- .../test_gas_accounting_for_exceptions.py | 33 -- .../test_gas_accounting_for_infinite_loops.py | 33 -- .../test_gas_accounting_for_normal_calls.py | 33 -- ...st_late_claim_increases_default_payment.py | 41 -- ..._claim_leaves_default_payment_unchanged.py | 39 -- ..._scheduler_is_reimbursed_whatevers_left.py | 51 --- tests/accounting/test_sending_ether.py | 18 - ...ed_call_does_not_change_default_payment.py | 26 -- tests/call-state/test_call_states.py | 140 ------- .../test_auto_returns_funds_when_exhausted.py | 42 -- tests/canary/test_can_only_initialize_once.py | 19 - tests/canary/test_cancelling_canary.py | 28 -- ..._cannot_revive_once_heartbeat_is_missed.py | 38 -- tests/canary/test_initial_scheduling_setup.py | 37 -- .../test_is_alive_when_first_deployed.py | 4 - ...est_anyone_can_cancel_after_call_window.py | 27 -- tests/cancelling/test_cancelling_a_call.py | 56 --- .../test_cannot_cancel_during_bid_window.py | 23 - .../test_cannot_cancel_if_already_called.py | 30 -- ...test_cannot_cancel_if_already_cancelled.py | 25 -- .../test_is_cancellable_property.py | 83 ---- ...eduler_can_cancel_prior_to_target_block.py | 18 - .../test_cannot_claim_after_window.py | 22 - .../test_cannot_claim_before_window.py | 21 - .../test_cannot_claim_during_call_window.py | 21 - .../test_cannot_claim_during_freeze.py | 21 - tests/claiming/test_claim_values.py | 29 -- .../test_claiming_during_growth_window.py | 25 -- .../test_claiming_during_max_window.py | 26 -- tests/conftest.py | 388 +++++++++++++++++ .../test_data_registry_via_call_contract.py | 57 --- .../test_data_registry_via_fallback.py | 47 --- .../test_data_registry_via_scheduling.py | 51 --- ...wed_to_execute_if_claimer_does_not_call.py | 34 -- tests/execution/test_basic_call_execution.py | 103 ----- .../test_call_that_throws_exception.py | 23 - .../execution/test_call_with_infinite_loop.py | 23 - .../test_cannot_execute_after_call_window.py | 13 - ...test_cannot_execute_before_target_block.py | 14 - .../test_cannot_execute_cancelled_call.py | 22 - .../test_cannot_execute_if_claimed.py | 27 -- .../test_different_call_data_modes.py | 75 ---- tests/execution/test_minimum_call_gas_cost.py | 45 -- tests/execution/test_stack_depth_attack.py | 38 -- tests/execution/test_stack_depth_limits.py | 66 --- tests/request-factory/test_request_factory.py | 58 +++ tests/request-tracker/test_request_tracker.py | 49 +++ tests/scheduling/test_basic_scheduling.py | 51 --- .../test_cannot_schedule_too_soon.py | 16 - .../scheduling/test_endowment_enforcement.py | 113 ----- tests/scheduling/test_gas_limits_enforced.py | 95 ----- .../test_minimum_grace_period_enforced.py | 44 -- tests/scheduling/test_scheduling_cost.py | 43 -- .../test_stack_check_limits_enforced.py | 111 ----- tests/transaction-request/test_donation.py | 32 ++ .../test_request_factory.py | 60 --- 77 files changed, 1327 insertions(+), 2891 deletions(-) delete mode 100644 conftest.py create mode 100644 contracts/MathLib.sol rename contracts/{ScheduleLib.sol => RequestScheduleLib.sol} (50%) create mode 100644 contracts/RequestTracker.sol create mode 100644 contracts/RequestTrackerInterface.sol create mode 100644 contracts/SafeSendLib.sol delete mode 100644 tests/accounting/test_call_donation.py delete mode 100644 tests/accounting/test_call_gas_scalar.py delete mode 100644 tests/accounting/test_call_payout.py delete mode 100644 tests/accounting/test_early_claim_reduces_default_payment.py delete mode 100644 tests/accounting/test_extra_payment_when_claimer_doesnt_call.py delete mode 100644 tests/accounting/test_gas_accounting_for_exceptions.py delete mode 100644 tests/accounting/test_gas_accounting_for_infinite_loops.py delete mode 100644 tests/accounting/test_gas_accounting_for_normal_calls.py delete mode 100644 tests/accounting/test_late_claim_increases_default_payment.py delete mode 100644 tests/accounting/test_middle_third_claim_leaves_default_payment_unchanged.py delete mode 100644 tests/accounting/test_scheduler_is_reimbursed_whatevers_left.py delete mode 100644 tests/accounting/test_sending_ether.py delete mode 100644 tests/accounting/test_unclaimed_call_does_not_change_default_payment.py delete mode 100644 tests/call-state/test_call_states.py delete mode 100644 tests/canary/test_auto_returns_funds_when_exhausted.py delete mode 100644 tests/canary/test_can_only_initialize_once.py delete mode 100644 tests/canary/test_cancelling_canary.py delete mode 100644 tests/canary/test_cannot_revive_once_heartbeat_is_missed.py delete mode 100644 tests/canary/test_initial_scheduling_setup.py delete mode 100644 tests/canary/test_is_alive_when_first_deployed.py delete mode 100644 tests/cancelling/test_anyone_can_cancel_after_call_window.py delete mode 100644 tests/cancelling/test_cancelling_a_call.py delete mode 100644 tests/cancelling/test_cannot_cancel_during_bid_window.py delete mode 100644 tests/cancelling/test_cannot_cancel_if_already_called.py delete mode 100644 tests/cancelling/test_cannot_cancel_if_already_cancelled.py delete mode 100644 tests/cancelling/test_is_cancellable_property.py delete mode 100644 tests/cancelling/test_only_scheduler_can_cancel_prior_to_target_block.py delete mode 100644 tests/claiming/test_cannot_claim_after_window.py delete mode 100644 tests/claiming/test_cannot_claim_before_window.py delete mode 100644 tests/claiming/test_cannot_claim_during_call_window.py delete mode 100644 tests/claiming/test_cannot_claim_during_freeze.py delete mode 100644 tests/claiming/test_claim_values.py delete mode 100644 tests/claiming/test_claiming_during_growth_window.py delete mode 100644 tests/claiming/test_claiming_during_max_window.py create mode 100644 tests/conftest.py delete mode 100644 tests/data-registry/test_data_registry_via_call_contract.py delete mode 100644 tests/data-registry/test_data_registry_via_fallback.py delete mode 100644 tests/data-registry/test_data_registry_via_scheduling.py delete mode 100644 tests/execution/test_allowed_to_execute_if_claimer_does_not_call.py delete mode 100644 tests/execution/test_basic_call_execution.py delete mode 100644 tests/execution/test_call_that_throws_exception.py delete mode 100644 tests/execution/test_call_with_infinite_loop.py delete mode 100644 tests/execution/test_cannot_execute_after_call_window.py delete mode 100644 tests/execution/test_cannot_execute_before_target_block.py delete mode 100644 tests/execution/test_cannot_execute_cancelled_call.py delete mode 100644 tests/execution/test_cannot_execute_if_claimed.py delete mode 100644 tests/execution/test_different_call_data_modes.py delete mode 100644 tests/execution/test_minimum_call_gas_cost.py delete mode 100644 tests/execution/test_stack_depth_attack.py delete mode 100644 tests/execution/test_stack_depth_limits.py create mode 100644 tests/request-factory/test_request_factory.py create mode 100644 tests/request-tracker/test_request_tracker.py delete mode 100644 tests/scheduling/test_basic_scheduling.py delete mode 100644 tests/scheduling/test_cannot_schedule_too_soon.py delete mode 100644 tests/scheduling/test_endowment_enforcement.py delete mode 100644 tests/scheduling/test_gas_limits_enforced.py delete mode 100644 tests/scheduling/test_minimum_grace_period_enforced.py delete mode 100644 tests/scheduling/test_scheduling_cost.py delete mode 100644 tests/scheduling/test_stack_check_limits_enforced.py create mode 100644 tests/transaction-request/test_donation.py delete mode 100644 tests/transaction-request/test_request_factory.py diff --git a/conftest.py b/conftest.py deleted file mode 100644 index 537131d5d..000000000 --- a/conftest.py +++ /dev/null @@ -1,254 +0,0 @@ -import pytest - -from web3.utils.encoding import ( - decode_hex, -) - - -@pytest.fixture -def FutureBlockCall(chain): - return chain.get_contract_factory('FutureBlockCall') - - -@pytest.fixture -def CallLib(chain): - return chain.get_contract_factory('CallLib') - - -@pytest.fixture -def SchedulerLib(chain): - return chain.get_contract_factory('SchedulerLib') - - -def get_block_gas_limit(web3): - latest_block = web3.eth.getBlock(web3.eth.blockNumber) - return latest_block['gasLimit'] - - -@pytest.fixture -def deploy_fbc(unmigrated_chain, web3, FutureBlockCall): - chain = unmigrated_chain - - def _deploy_fbc(contract=None, - method_name=None, - abi_signature=None, - arguments=None, - scheduler_address=None, - target_block=None, - grace_period=255, - required_gas=1000000, - payment=1, - donation=1, - endowment=None, - call_data=None, - require_depth=0, - call_value=0): - if arguments is not None and call_data: - raise ValueError("Cannot specify both arguments and call_data") - elif arguments is not None and not method_name: - raise ValueError("Method name must be provided if providing arguments") - - if endowment is None: - endowment = ( - get_block_gas_limit(web3) * - web3.eth.gasPrice + - payment + - donation + - call_value - ) - - if target_block is None: - target_block = web3.eth.blockNumber - - if scheduler_address is None: - scheduler_address = web3.eth.coinbase - - if contract is None: - contract_address = web3.eth.coinbase - else: - contract_address = contract.address - - if method_name is not None: - if call_data is None and abi_signature is None: - fn_abi, fn_selector, _ = contract._get_function_info(method_name, arguments) - abi_signature = decode_hex(fn_selector) - - if call_data is None and arguments: - hex_call_data = contract.encodeABI(method_name, arguments) - call_data = decode_hex(hex_call_data) - - if abi_signature is None: - abi_signature = "" - - if call_data is None: - call_data = "" - - deploy_txn_hash = FutureBlockCall.deploy( - {'value': endowment}, - [ - scheduler_address, - target_block, - grace_period, - contract_address, - abi_signature, - call_data, - call_value, - required_gas, - require_depth, - payment, - donation, - ], - ) - - contract_address = chain.wait.for_contract_address(deploy_txn_hash) - fbc = FutureBlockCall(address=contract_address) - return fbc - return _deploy_fbc - - -@pytest.fixture -def Canary(unmigrated_chain): - return unmigrated_chain.get_contract_factory('Canary') - - -@pytest.fixture() -def deploy_canary(chain, web3, denoms, Canary): - def _deploy_canary(endowment=None, - scheduler_address=None, - frequency=480, - deploy_from=None): - if scheduler_address is None: - scheduler = chain.get_contract('Scheduler') - scheduler_address = scheduler.address - - if endowment is None: - endowment = 5 * denoms.ether - - transaction = {'value': endowment} - - if deploy_from is not None: - transaction['from'] = deploy_from - - deploy_txn_hash = Canary.deploy( - transaction=transaction, - args=(scheduler_address, frequency), - ) - canary_address = chain.wait.for_contract_address(deploy_txn_hash) - - canary = Canary(address=canary_address) - return canary - return _deploy_canary - - -#@pytest.fixture() -#def canary(deploy_canary_contract): -# return deploy_canary_contract() -# -# -#@pytest.fixture(scope="module") -#def get_call(SchedulerLib, FutureBlockCall, deploy_client): -# def _get_call(txn_hash): -# call_scheduled_logs = SchedulerLib.CallScheduled.get_transaction_logs(txn_hash) -# if not len(call_scheduled_logs): -# call_rejected_logs = SchedulerLib.CallRejected.get_transaction_logs(txn_hash) -# if len(call_rejected_logs): -# reject_data = SchedulerLib.CallRejected.get_log_data(call_rejected_logs[0]) -# raise ValueError("CallRejected: {0}".format(reject_data)) -# raise ValueError("No scheduled call found") -# call_scheduled_data = SchedulerLib.CallScheduled.get_log_data(call_scheduled_logs[0]) -# -# call_address = call_scheduled_data['call_address'] -# call = FutureBlockCall(call_address, deploy_client) -# return call -# return _get_call -# -# -#@pytest.fixture(scope="module") -#def get_call_rejection_data(SchedulerLib): -# def _get_rejection_data(txn_hash): -# rejection_logs = SchedulerLib.CallRejected.get_transaction_logs(txn_hash) -# assert len(rejection_logs) == 1 -# rejection_data = SchedulerLib.CallRejected.get_log_data(rejection_logs[0]) -# -# return rejection_data -# return _get_rejection_data -# -# -#@pytest.fixture(scope="module") -#def get_execution_data(CallLib): -# def _get_execution_data(txn_hash): -# execution_logs = CallLib.CallExecuted.get_transaction_logs(txn_hash) -# assert len(execution_logs) == 1 -# execution_data = CallLib.CallExecuted.get_log_data(execution_logs[0]) -# -# return execution_data -# return _get_execution_data - -@pytest.fixture() -def denoms(): - from web3.utils.currency import units - int_units = { - key: int(value) - for key, value in units.items() - } - return type('denoms', (object,), int_units) - - -@pytest.fixture() -def get_scheduled_fbc(chain, web3): - scheduler = chain.get_contract('Scheduler') - SchedulerLib = chain.get_contract_factory('SchedulerLib') - FutureBlockCall = chain.get_contract_factory('FutureBlockCall') - - def _get_scheduled_fbc(scheduling_txn_hash): - schedule_receipt = chain.wait.for_receipt(scheduling_txn_hash) - - schedule_filter = SchedulerLib.on( - 'CallScheduled', - { - 'address': scheduler.address, - 'fromBlock': schedule_receipt['blockNumber'], - 'toBlock': schedule_receipt['blockNumber'], - }, - ) - schedule_events = schedule_filter.get() - assert len(schedule_events) == 1 - schedule_event_data = schedule_events[0] - fbc_address = schedule_event_data['args']['call_address'] - - chain_bytecode = web3.eth.getCode(fbc_address) - assert chain_bytecode == FutureBlockCall.code_runtime - - fbc = FutureBlockCall(address=fbc_address) - return fbc - return _get_scheduled_fbc - - -@pytest.fixture() -def get_4byte_selector(): - from web3.utils.encoding import ( - decode_hex, - ) - from web3.utils.abi import ( - function_abi_to_4byte_selector, - ) - - def _get_4byte_selector(contract, fn_name, args=None, kwargs=None): - fn_abi = contract._find_matching_fn_abi(fn_name, args=args, kwargs=kwargs) - fn_4byte_selector = decode_hex(function_abi_to_4byte_selector(fn_abi)) - return fn_4byte_selector - return _get_4byte_selector - - -@pytest.fixture() -def CallStates(): - class States(object): - Pending = 0 - Unclaimed = 1 - Claimed = 2 - Frozen = 3 - Callable = 4 - Executed = 5 - Cancelled = 6 - Missed = 7 - return States diff --git a/contracts/ClaimLib.sol b/contracts/ClaimLib.sol index 2271ad8ca..c28d74ba0 100644 --- a/contracts/ClaimLib.sol +++ b/contracts/ClaimLib.sol @@ -1,7 +1,13 @@ //pragma solidity 0.4.1; +import {SafeSendLib} from "contracts/SafeSendLib.sol"; +import {MathLib} from "contracts/MathLib.sol"; + library ClaimLib { + using SafeSendLib for address; + using MathLib for uint; + struct ClaimData { // The address that has claimed this request address claimedBy; @@ -12,10 +18,15 @@ library ClaimLib { // An integer constrained between 0-100 that will be applied to the // request payment as a percentage. uint8 paymentModifier; + } - // The number of temporal units that prior to the call freeze window - // during which the request will be claimable. - uint claimWindowSize; + /* + * Mark the request as being claimed + */ + function claim(ClaimData storage self, uint8 paymentModifier) returns (bool) { + self.claimedBy = msg.sender; + self.claimDeposit = msg.value; + self.paymentModifier = paymentModifier; } /* @@ -24,4 +35,30 @@ library ClaimLib { function isClaimed(ClaimData storage self) returns (bool) { return self.claimedBy != 0x0; } + + /* + * Amount that must be supplied as a deposit to claim. This is set to the + * maximum possible payment value that could be paid out by this request. + */ + function minimumDeposit(uint payment) returns (uint) { + return payment.safeMultiply(2); + } + + /* + * Refund the claimer deposit. + */ + function refundDeposit(ClaimData storage self) returns (bool) { + return refundDeposit(self, SafeSendLib.DEFAULT_SEND_GAS()); + } + + function refundDeposit(ClaimData storage self, uint sendGas) returns (bool) { + uint depositAmount; + + depositAmount = self.claimDeposit; + // re-entrance protection. + self.claimDeposit = 0; + self.claimDeposit = depositAmount.flooredSub(self.claimedBy.safeSend(depositAmount, sendGas)); + + return true; + } } diff --git a/contracts/GasLib.sol b/contracts/GasLib.sol index 75a41405a..606f5ba9e 100644 --- a/contracts/GasLib.sol +++ b/contracts/GasLib.sol @@ -1,16 +1,27 @@ +//pragma solidity 0.4.1; + +import {MathLib} from "contracts/MathLib.sol"; + + library GasLib { + using MathLib for uint; + /* * Returns a gas value that leaves at least reserveAmount leftover. This * may return 0 if msg.gas < reserveAmount. The BUFFER value is present * to prevent underflow in cases where msg.gas >= reserveAmount but the * act of comparison drops msg.gas < reserveAmount. */ - uint constant BUFFER = 10000; + uint constant _BUFFER = 10000; + + function BUFFER() returns (uint) { + return _BUFFER; + } function getGas(uint reserveAmount) returns (uint) { - if (msg.gas < reserveAmount + BUFFER) { + if (msg.gas < reserveAmount.safeAdd(_BUFFER)) { return 0; } - return msg.gas - reserveAmount; + return msg.gas.flooredSub(reserveAmount); } } diff --git a/contracts/MathLib.sol b/contracts/MathLib.sol new file mode 100644 index 000000000..14325b985 --- /dev/null +++ b/contracts/MathLib.sol @@ -0,0 +1,65 @@ +//pragma solidity 0.4.1; + + +library MathLib { + uint constant INT_MAX = 57896044618658097711785492504343953926634992332820282019728792003956564819967; // 2**255 - 1 + /* + * Subtracts b from a in a manner such that zero is returned when an + * underflow condition is met. + */ + function flooredSub(uint a, uint b) returns (uint) { + if (b > a) { + return 0; + } else { + return a - b; + } + } + + /* + * Adds b to a in a manner that throws an exception when overflow + * conditions are met. + */ + function safeAdd(uint a, uint b) returns (uint) { + if (a + b >= a) { + return a + b; + } else { + throw; + } + } + + /* + * Multiplies a by b in a manner that throws an exception when overflow + * conditions are met. + */ + function safeMultiply(uint a, uint b) returns (uint) { + var result = a * b; + if (b == 0 || result / b == a) { + return a * b; + } else { + throw; + } + } + + /* + * Return the larger of a or b. Returns a if a == b. + */ + function max(uint a, uint b) returns (uint) { + if (a >= b) { + return a; + } else { + return b; + } + } + + /* + * Returns a represented as a signed integer in a manner that throw an + * exception if casting to signed integer would result in a negative + * number. + */ + function safeCastSigned(uint a) returns (int) { + if (a > INT_MAX) { + throw; + } + return int(a); + } +} diff --git a/contracts/PaymentLib.sol b/contracts/PaymentLib.sol index d19db827b..5a4fdd643 100644 --- a/contracts/PaymentLib.sol +++ b/contracts/PaymentLib.sol @@ -1,7 +1,13 @@ //pragma solidity 0.4.1; +import {SafeSendLib} from "contracts/SafeSendLib.sol"; +import {MathLib} from "contracts/MathLib.sol"; + library PaymentLib { + using SafeSendLib for address; + using MathLib for uint; + struct PaymentData { // The gas price that was used during creation of this request. uint anchorGasPrice; @@ -10,11 +16,20 @@ library PaymentLib { // this request. uint payment; + // The address that the payment should be sent to. + address paymentBenefactor; + + // The amount that is owed to the payment benefactor. + uint paymentOwed; + // The amount in wei that will be payed to the donationBenefactor address. uint donation; - // The address that the donation amount will be paid to. + // The address that the donation should be sent to. address donationBenefactor; + + // The amount that is owed to the donation benefactor. + uint donationOwed; } /* @@ -41,10 +56,13 @@ library PaymentLib { */ function getMultiplier(PaymentData storage self) returns (uint) { if (tx.gasprice > self.anchorGasPrice) { - return 100 * self.anchorGasPrice / tx.gasprice; + return self.anchorGasPrice.safeMultiply(100) / tx.gasprice; } else { - return 200 - 100 * self.anchorGasPrice / (2 * self.anchorGasPrice - tx.gasprice); + return 200 - ( + self.anchorGasPrice.safeMultiply(100) / + self.anchorGasPrice.safeMultiply(2).flooredSub(tx.gasprice) + ).max(200); } } @@ -67,46 +85,40 @@ library PaymentLib { * with an additional modifier. This is used when the call was claimed. */ function getPaymentWithModifier(PaymentData storage self, - uint8 paymentModifier)returns (uint) { - return getPayment(self) * 100 / paymentModifier; - } - - event SendFailed(address to, uint value); - - uint constant _DEFAULT_SEND_GAS = 90000; - - function DEFAULT_SEND_GAS() returns (uint) { - return _DEFAULT_SEND_GAS; + uint8 paymentModifier) returns (uint) { + return getPayment(self).safeMultiply(100) / paymentModifier; } /* - * Send ether to an address. - * On failure log the `SendFailed` event. - * Returns the amount of wei that was sent (which will be 0 on failure). + * Send the donationOwed amount to the donationBenefactor */ - function safeSend(address to, uint value) internal returns (uint) { - return safeSend(to, value, _DEFAULT_SEND_GAS); + function sendDonation(PaymentData storage self) returns (bool) { + return sendDonation(self, SafeSendLib.DEFAULT_SEND_GAS()); + } + + function sendDonation(PaymentData storage self, uint sendGas) returns (bool) { + uint donationAmount = self.donationOwed; + // re-entrance protection. + self.donationOwed = 0; + self.donationOwed = donationAmount.flooredSub(self.donationBenefactor.safeSend(donationAmount, + sendGas)); + return true; } /* - * Same as `safeSend` but allows specifying the gas to be included with the - * send. + * Send the paymentOwed amount to the paymentBenefactor */ - function safeSend(address to, uint value, uint sendGas) internal returns (uint) { - if (value > this.balance) { - value = this.balance; - } - - if (value == 0) { - return 0; - } - - if (!to.call.value(value).gas(sendGas)()) { - SendFailed(to, value); - return 0; - } + function sendPayment(PaymentData storage self) returns (bool) { + return sendPayment(self, SafeSendLib.DEFAULT_SEND_GAS()); + } - return value; + function sendPayment(PaymentData storage self, uint sendGas) returns (bool) { + uint paymentAmount = self.paymentOwed; + // re-entrance protection. + self.paymentOwed = 0; + self.paymentOwed = paymentAmount.flooredSub(self.paymentBenefactor.safeSend(paymentAmount, + sendGas)); + return true; } /* @@ -121,6 +133,9 @@ library PaymentLib { uint donation, uint callGas, uint callValue) returns (bool) { - return endowment >= 2 * (payment + donation) + callGas * tx.gasprice + callValue; + return endowment >= payment.safeAdd(donation) + .safeMultiply(2) + .safeAdd(callGas.safeMultiply(tx.gasprice)) + .safeAdd(callValue); } } diff --git a/contracts/RequestFactory.sol b/contracts/RequestFactory.sol index 69f3841a0..1a15e8f7e 100644 --- a/contracts/RequestFactory.sol +++ b/contracts/RequestFactory.sol @@ -4,11 +4,18 @@ import {RequestFactoryInterface} from "contracts/RequestFactoryInterface.sol"; import {TransactionRequest} from "contracts/TransactionRequest.sol"; import {RequestLib} from "contracts/RequestLib.sol"; import {IterTools} from "contracts/IterTools.sol"; +import {RequestTrackerInterface} from "contracts/RequestTrackerInterface.sol"; contract RequestFactory is RequestFactoryInterface { using IterTools for bool[7]; + RequestTrackerInterface tracker; + + function RequestFactory(address trackerAddress) { + tracker = RequestTrackerInterface(trackerAddress); + } + /* * ValidationError */ @@ -27,29 +34,29 @@ contract RequestFactory is RequestFactoryInterface { /* * The lowest level interface for creating a transaction request. * - * addressArgs[0]: paymentData.donationBenefactor - * addressArgs[1]: txnData.toAddress - * uintArgs[0], claimData.claimWindowSize - * uintArgs[1], paymentData.donation - * uintArgs[2], paymentData.payment - * uintArgs[3], schedule.freezePeriod - * uintArgs[4], schedule.reservedWindowSize - * uintArgs[5], schedule.temporalUnit - * uintArgs[6], schedule.windowStart - * uintArgs[7], schedule.windowSize - * uintArgs[8], txnData.callGas - * uintArgs[9], txnData.callValue - * uintArgs[10] txnData.requiredStackDepth + * addressArgs[0] - paymentData.donationBenefactor + * addressArgs[1] - txnData.toAddress + * uintArgs[0] - paymentData.donation + * uintArgs[1] - paymentData.payment + * uintArgs[2] - schedule.claimWindowSize + * uintArgs[3] - schedule.freezePeriod + * uintArgs[4] - schedule.reservedWindowSize + * uintArgs[5] - schedule.temporalUnit + * uintArgs[6] - schedule.windowStart + * uintArgs[7] - schedule.windowSize + * uintArgs[8] - txnData.callGas + * uintArgs[9] - txnData.callValue + * uintArgs[10] - txnData.requiredStackDepth */ - function createRequest(address[2] addressArgs, + function createRequest(address[3] addressArgs, uint[11] uintArgs, bytes callData) returns (address) { var errors = RequestLib.validate( [ - address(this), // meta.createdBy - msg.sender, // meta.owner - addressArgs[0], // paymentData.donationBenefactor - addressArgs[1] // txnData.toAddress + msg.sender, // meta.createdBy + addressArgs[0], // meta.owner + addressArgs[1], // paymentData.donationBenefactor + addressArgs[2] // txnData.toAddress ], uintArgs, callData, @@ -68,17 +75,20 @@ contract RequestFactory is RequestFactoryInterface { var request = (new TransactionRequest).value(msg.value)( [ - msg.sender, // meta.owner - addressArgs[0], // paymentData.donationBenefactor - addressArgs[1] // txnData.toAddress + msg.sender, + addressArgs[0], // meta.owner + addressArgs[1], // paymentData.donationBenefactor + addressArgs[2] // txnData.toAddress ], uintArgs, callData ); + // Log the creation. RequestCreated(address(request)); - // TODO: register with tracker + // Register with tracker + tracker.addRequest(address(request), uintArgs[6]); return request; } diff --git a/contracts/RequestFactoryInterface.sol b/contracts/RequestFactoryInterface.sol index d8c7fa937..e34fefb99 100644 --- a/contracts/RequestFactoryInterface.sol +++ b/contracts/RequestFactoryInterface.sol @@ -4,7 +4,7 @@ contract RequestFactoryInterface { event RequestCreated(address request); - function createRequest(address[2] addressArgs, + function createRequest(address[3] addressArgs, uint[11] uintArgs, bytes callData) returns (address); function receiveExecutionNotification() returns (bool); diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index de7e863ba..904b62cac 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -1,34 +1,29 @@ //pragma solidity 0.4.1; import {ExecutionLib} from "contracts/ExecutionLib.sol"; -import {ScheduleLib} from "contracts/ScheduleLib.sol"; +import {RequestScheduleLib} from "contracts/RequestScheduleLib.sol"; import {ClaimLib} from "contracts/ClaimLib.sol"; import {RequestMetaLib} from "contracts/RequestMetaLib.sol"; import {PaymentLib} from "contracts/PaymentLib.sol"; +import {SafeSendLib} from "contracts/SafeSendLib.sol"; +import {MathLib} from "contracts/MathLib.sol"; library RequestLib { using ExecutionLib for ExecutionLib.ExecutionData; - using ScheduleLib for ScheduleLib.Schedule; + using RequestScheduleLib for RequestScheduleLib.ExecutionWindow; using ClaimLib for ClaimLib.ClaimData; using RequestMetaLib for RequestMetaLib.RequestMeta; using PaymentLib for PaymentLib.PaymentData; - - struct Result { - bool wasCalled; - bool wasSuccessful; - uint gasConsumption; - uint paymentOwed; - uint donationOwed; - } + using SafeSendLib for address; + using MathLib for uint; struct Request { ExecutionLib.ExecutionData txnData; - Result result; RequestMetaLib.RequestMeta meta; PaymentLib.PaymentData paymentData; ClaimLib.ClaimData claimData; - ScheduleLib.Schedule schedule; + RequestScheduleLib.ExecutionWindow schedule; } enum Reason { @@ -42,7 +37,52 @@ library RequestLib { } event Aborted(Reason reason); - event Executed(uint payment, uint donation); + event Executed(uint payment, uint donation, uint measuredGasConsumption); + + /* + * Initialize a new Request. + */ + function initialize(Request storage self, + address[4] addressArgs, + uint[11] uintArgs, + bytes callData) returns (bool) { + address[6] memory addressValues = [ + 0x0, // self.claimData.claimedBy + addressArgs[0], // self.meta.createdBy + addressArgs[1], // self.meta.owner + addressArgs[2], // self.paymentData.donationBenefactor + 0x0, // self.paymentData.paymentBenefactor + addressArgs[3] // self.txnData.toAddress + ]; + + bool[3] memory boolValues = [false, false, false]; + + uint[15] memory uintValues = [ + 0, // self.claimData.claimDeposit + tx.gasprice, // self.paymentData.anchorGasPrice + uintArgs[0], // self.paymentData.donation + 0, // self.paymentData.donationOwed + uintArgs[1], // self.paymentData.payment + 0, // self.paymentData.paymentOwed + uintArgs[2], // self.schedule.claimWindowSize + uintArgs[3], // self.schedule.freezePeriod + uintArgs[4], // self.schedule.reservedWindowSize + uintArgs[5], // self.schedule.temporalUnit + uintArgs[6], // self.schedule.windowStart + uintArgs[7], // self.schedule.windowSize + uintArgs[8], // self.txnData.callGas + uintArgs[9], // self.txnData.callValue + uintArgs[10] // self.txnData.requiredStackDepth + ]; + + uint8[1] memory uint8Values = [ + 0 + ]; + + deserialize(self, addressValues, boolValues, uintValues, uint8Values, callData); + + return true; + } /* * Returns the entire data structure of the Request in a *serialized* @@ -50,40 +90,42 @@ library RequestLib { * separately * * Parameter order is alphabetical by type, then namespace, then name + * + * TODO: figure out why this fails. */ - function serialize(Request storage self) returns (address[5] addressValues, + function serialize(Request storage self) returns (address[6] addressValues, bool[3] boolValues, - uint[16] uintValues, + uint[15] uintValues, uint8[1] uint8Values) { // Address values addressValues[0] = self.claimData.claimedBy; addressValues[1] = self.meta.createdBy; addressValues[2] = self.meta.owner; addressValues[3] = self.paymentData.donationBenefactor; - addressValues[4] = self.txnData.toAddress; + addressValues[4] = self.paymentData.paymentBenefactor; + addressValues[5] = self.txnData.toAddress; // Boolean values boolValues[0] = self.meta.isCancelled; - boolValues[1] = self.result.wasCalled; - boolValues[2] = self.result.wasSuccessful; + boolValues[1] = self.meta.wasCalled; + boolValues[2] = self.meta.wasSuccessful; // UInt256 values uintValues[0] = self.claimData.claimDeposit; - uintValues[1] = self.claimData.claimWindowSize; - uintValues[2] = self.paymentData.anchorGasPrice; - uintValues[3] = self.paymentData.donation; - uintValues[4] = self.paymentData.payment; - uintValues[5] = self.result.donationOwed; - uintValues[6] = self.result.gasConsumption; - uintValues[7] = self.result.paymentOwed; - uintValues[8] = self.schedule.freezePeriod; - uintValues[9] = self.schedule.reservedWindowSize; - uintValues[10] = uint(self.schedule.temporalUnit); - uintValues[11] = self.schedule.windowStart; - uintValues[12] = self.schedule.windowSize; - uintValues[13] = self.txnData.callGas; - uintValues[14] = self.txnData.callValue; - uintValues[15] = self.txnData.requiredStackDepth; + uintValues[1] = self.paymentData.anchorGasPrice; + uintValues[2] = self.paymentData.donation; + uintValues[3] = self.paymentData.payment; + uintValues[4] = self.paymentData.donationOwed; + uintValues[5] = self.paymentData.paymentOwed; + uintValues[6] = self.schedule.claimWindowSize; + uintValues[7] = self.schedule.freezePeriod; + uintValues[8] = self.schedule.reservedWindowSize; + uintValues[9] = uint(self.schedule.temporalUnit); + uintValues[10] = self.schedule.windowStart; + uintValues[11] = self.schedule.windowSize; + uintValues[12] = self.txnData.callGas; + uintValues[13] = self.txnData.callValue; + uintValues[14] = self.txnData.requiredStackDepth; // Uint8 values uint8Values[0] = self.claimData.paymentModifier; @@ -102,9 +144,9 @@ library RequestLib { * Parameter order is alphabetical by type, then namespace, then name. */ function deserialize(Request storage self, - address[5] addressValues, + address[6] addressValues, bool[3] boolValues, - uint[16] uintValues, + uint[15] uintValues, uint8[1] uint8Values, bytes callData) returns (bool) { // callData is special. @@ -115,77 +157,35 @@ library RequestLib { self.meta.createdBy = addressValues[1]; self.meta.owner = addressValues[2]; self.paymentData.donationBenefactor = addressValues[3]; - self.txnData.toAddress = addressValues[4]; + self.paymentData.paymentBenefactor = addressValues[4]; + self.txnData.toAddress = addressValues[5]; // Boolean values self.meta.isCancelled = boolValues[0]; - self.result.wasCalled = boolValues[1]; - self.result.wasSuccessful = boolValues[2]; + self.meta.wasCalled = boolValues[1]; + self.meta.wasSuccessful = boolValues[2]; // UInt values self.claimData.claimDeposit = uintValues[0]; - self.claimData.claimWindowSize = uintValues[1]; - self.paymentData.anchorGasPrice = uintValues[2]; - self.paymentData.donation = uintValues[3]; - self.paymentData.payment = uintValues[4]; - self.result.donationOwed = uintValues[5]; - self.result.gasConsumption = uintValues[6]; - self.result.paymentOwed = uintValues[7]; - self.schedule.freezePeriod = uintValues[8]; - self.schedule.reservedWindowSize = uintValues[9]; - self.schedule.temporalUnit = ScheduleLib.TemporalUnit(uintValues[10]); - self.schedule.windowStart = uintValues[11]; - self.schedule.windowSize = uintValues[12]; - self.txnData.callGas = uintValues[13]; - self.txnData.callValue = uintValues[14]; - self.txnData.requiredStackDepth = uintValues[15]; + self.paymentData.anchorGasPrice = uintValues[1]; + self.paymentData.donation = uintValues[2]; + self.paymentData.payment = uintValues[3]; + self.paymentData.donationOwed = uintValues[4]; + self.paymentData.paymentOwed = uintValues[5]; + self.schedule.claimWindowSize = uintValues[6]; + self.schedule.freezePeriod = uintValues[7]; + self.schedule.reservedWindowSize = uintValues[8]; + self.schedule.temporalUnit = RequestScheduleLib.TemporalUnit(uintValues[9]); + self.schedule.windowStart = uintValues[10]; + self.schedule.windowSize = uintValues[11]; + self.txnData.callGas = uintValues[12]; + self.txnData.callValue = uintValues[13]; + self.txnData.requiredStackDepth = uintValues[14]; // Uint8 values self.claimData.paymentModifier = uint8Values[0]; } - function initialize(Request storage self, - address[4] addressArgs, - uint[11] uintArgs, - bytes callData) returns (bool) { - address[5] memory addressValues = [ - 0x0, // self.claimData.claimedBy - addressArgs[0], // self.meta.createdBy - addressArgs[1], // self.meta.owner - addressArgs[2], // self.paymentData.donationBenefactor - addressArgs[3] // self.txnData.toAddress - ]; - - bool[3] memory boolValues = [false, false, false]; - - uint[16] memory uintValues = [ - 0, // self.claimData.claimDeposit - uintArgs[0], // self.claimData.claimWindowSize - tx.gasprice, // self.paymentData.anchorGasPrice - uintArgs[1], // self.paymentData.donation - uintArgs[2], // self.paymentData.payment - 0, // self.result.donationOwed - 0, // self.result.gasConsumption - 0, // self.result.paymentOwed - uintArgs[3], // self.schedule.freezePeriod - uintArgs[4], // self.schedule.reservedWindowSize - uintArgs[5], // self.schedule.temporalUnit - uintArgs[6], // self.schedule.windowStart - uintArgs[7], // self.schedule.windowSize - uintArgs[8], // self.txnData.callGas - uintArgs[9], // self.txnData.callValue - uintArgs[10] // self.txnData.requiredStackDepth - ]; - - uint8[1] memory uint8Values = [ - 0 - ]; - - deserialize(self, addressValues, boolValues, uintValues, uint8Values, callData); - - return true; - } - function validate(address[4] addressValues, uint[11] uintValues, bytes callData, @@ -200,25 +200,25 @@ library RequestLib { request.meta.createdBy = addressValues[0]; request.meta.owner = addressValues[1]; request.paymentData.donationBenefactor = addressValues[2]; + request.paymentData.donationBenefactor = 0x0; request.txnData.toAddress = addressValues[3]; // Boolean values request.meta.isCancelled = false; - request.result.wasCalled = false; - request.result.wasSuccessful = false; + request.meta.wasCalled = false; + request.meta.wasSuccessful = false; // UInt values request.claimData.claimDeposit = 0; - request.claimData.claimWindowSize = uintValues[0]; request.paymentData.anchorGasPrice = tx.gasprice; - request.paymentData.donation = uintValues[1]; - request.paymentData.payment = uintValues[2]; - request.result.donationOwed = 0; - request.result.gasConsumption = 0; - request.result.paymentOwed = 0; + request.paymentData.donation = uintValues[0]; + request.paymentData.payment = uintValues[1]; + request.paymentData.donationOwed = 0; + request.paymentData.paymentOwed = 0; + request.schedule.claimWindowSize = uintValues[2]; request.schedule.freezePeriod = uintValues[3]; request.schedule.reservedWindowSize = uintValues[4]; - request.schedule.temporalUnit = ScheduleLib.TemporalUnit(uintValues[5]); + request.schedule.temporalUnit = RequestScheduleLib.TemporalUnit(uintValues[5]); request.schedule.windowStart = uintValues[6]; request.schedule.windowSize = uintValues[7]; request.txnData.callGas = uintValues[8]; @@ -228,19 +228,19 @@ library RequestLib { // Uint8 values request.claimData.paymentModifier = 0; - // These errors must be in the same order as the RequestFactory.Errors - // enum. + // The order of these errors matters as it determines which + // ValidationError event codes are logged when validation fails. errors[0] = PaymentLib.validateEndowment(endowment, request.paymentData.payment, request.paymentData.donation, request.txnData.callGas, request.txnData.callValue); - errors[1] = ScheduleLib.validateReservedWindowSize(request.schedule.reservedWindowSize, - request.schedule.windowSize); - errors[2] = ScheduleLib.validateTemporalUnit(uintValues[5]); - errors[3] = ScheduleLib.validateWindowStart(request.schedule.temporalUnit, - request.schedule.freezePeriod, - request.schedule.windowStart); + errors[1] = RequestScheduleLib.validateReservedWindowSize(request.schedule.reservedWindowSize, + request.schedule.windowSize); + errors[2] = RequestScheduleLib.validateTemporalUnit(uintValues[5]); + errors[3] = RequestScheduleLib.validateWindowStart(request.schedule.temporalUnit, + request.schedule.freezePeriod, + request.schedule.windowStart); errors[4] = ExecutionLib.validateRequiredStackDepth(request.txnData.requiredStackDepth); errors[5] = ExecutionLib.validateCallGas(request.txnData.callGas, _EXTRA_GAS); errors[6] = ExecutionLib.validateToAddress(request.txnData.toAddress); @@ -275,7 +275,7 @@ library RequestLib { if (msg.gas < requiredExecutionGas(self)) { Aborted(Reason.InsufficientGas); return false; - } else if (self.result.wasCalled) { + } else if (self.meta.wasCalled) { Aborted(Reason.AlreadyCalled); return false; } else if (self.meta.isCancelled) { @@ -299,62 +299,66 @@ library RequestLib { // Ensure the request is marked as having been called before sending // the transaction to prevent re-entrance. - self.result.wasCalled = true; + self.meta.wasCalled = true; // Send the transaction - self.result.wasSuccessful = self.txnData.sendTransaction(); + self.meta.wasSuccessful = self.txnData.sendTransaction(); // Report execution back to the origin address. self.meta.reportExecution(_GAS_TO_COMPLETE_EXECUTION); - uint paymentOwed; - uint donationOwed; - // Compute the donation amount if (self.paymentData.hasBenefactor()) { - donationOwed += self.paymentData.getDonation(); + self.paymentData.donationOwed = self.paymentData.getDonation() + .safeAdd(self.paymentData.donationOwed); } - // Compute the payment amount + // Compute the payment amount and who it should be sent do. + self.paymentData.paymentBenefactor = msg.sender; if (self.claimData.isClaimed()) { - paymentOwed += self.claimData.claimDeposit; - paymentOwed += self.paymentData.getPaymentWithModifier(self.claimData.paymentModifier); + self.paymentData.paymentOwed = self.claimData.claimDeposit.safeAdd(self.paymentData.paymentOwed); + // need to zero out the claim deposit since it is now accounted for + // in the paymentOwed value. + self.claimData.claimDeposit = 0; + self.paymentData.paymentOwed = self.paymentData.getPaymentWithModifier(self.claimData.paymentModifier).safeAdd(self.paymentData.paymentOwed); } else { - paymentOwed += self.paymentData.getPayment(); + self.paymentData.paymentOwed = self.paymentData.getPayment().safeAdd(self.paymentData.paymentOwed); } // Record the amount of gas used by execution. - self.result.gasConsumption = (startGas - msg.gas) + EXTRA_GAS(); + uint measuredGasConsumption = startGas.flooredSub(msg.gas).safeAdd(EXTRA_GAS()); + // // NOTE: All code after this must be accounted for by EXTRA_GAS + // // Add the gas reimbursment amount to the payment. - paymentOwed += self.result.gasConsumption * tx.gasprice; + self.paymentData.paymentOwed = measuredGasConsumption.safeMultiply(tx.gasprice) + .safeAdd(self.paymentData.paymentOwed); // Log the two payment amounts. Otherwise it is non-trivial to figure // out how much was payed. - Executed(paymentOwed, donationOwed); + Executed(self.paymentData.paymentOwed, + self.paymentData.donationOwed, + measuredGasConsumption); // Send the donation. This will be a noop if there is no benefactor or // if the donation amount is 0. - donationOwed -= PaymentLib.safeSend(self.paymentData.donationBenefactor, donationOwed); + self.paymentData.sendDonation(); // Send the payment. - paymentOwed -= PaymentLib.safeSend(msg.sender, paymentOwed); + self.paymentData.sendDonation(); - // These need to be set after the send so that there is not opportunity - // for re-entrance. - self.result.donationOwed = donationOwed; - self.result.paymentOwed = paymentOwed; + // Send all extra ether back to the owner. + sendOwnerEther(self); return true; } function requiredExecutionGas(Request storage self) returns (uint) { - return self.txnData.callGas + - _GAS_TO_COMPLETE_EXECUTION + - _GAS_TO_AUTHORIZE_EXECUTION + - 2 * PaymentLib.DEFAULT_SEND_GAS(); + return self.txnData.callGas.safeAdd(_GAS_TO_AUTHORIZE_EXECUTION) + .safeAdd(_GAS_TO_COMPLETE_EXECUTION) + .safeAdd(SafeSendLib.DEFAULT_SEND_GAS().safeMultiply(3)); } // TODO: compute this @@ -388,4 +392,121 @@ library RequestLib { function EXTRA_GAS() returns (uint) { return _EXTRA_GAS; } + + /* + * Return boolean whether the call can be cancelled. Must satisfy the + * following conditions. + * + * 1. Not Cancelled + * 2. either: + * * not wasCalled && afterExecutionWindow + * * not claimed && beforeFreezeWindow && msg.sender == owner + */ + function isCancellable(Request storage self) returns (bool) { + if (self.meta.isCancelled) { + return false; + } else if (!self.meta.wasCalled && self.schedule.isAfterWindow()) { + return true; + } else if (!self.claimData.isClaimed() && self.schedule.isBeforeFreeze() && msg.sender == self.meta.owner) { + return true; + } else { + return false; + } + } + + /* + * Cancel the transaction request, attempting to send all appropriate + * refunds. + */ + function cancel(Request storage self) returns (bool) { + if (!isCancellable(self)) { + return false; + } + + // set this here to prevent re-entrance attacks. + self.meta.isCancelled = true; + + // refund any claim deposit. + self.claimData.refundDeposit(); + + // send the remaining ether to the owner. + sendOwnerEther(self); + + return true; + } + + /* + * Return boolean as to whether the request may be claimed. + */ + function isClaimable(Request storage self) returns (bool) { + if (self.claimData.isClaimed()) { + return false; + } else if (self.meta.isCancelled) { + return false; + } else if (!self.schedule.inClaimWindow()) { + return false; + } else if (msg.value < ClaimLib.minimumDeposit(self.paymentData.payment)) { + return false; + } else { + return true; + } + } + + /* + * Claim the request + */ + function claim(Request storage self) returns (bool) { + if (!isClaimable(self)) { + return false; + } + self.claimData.claim(self.schedule.computePaymentModifier()); + } + + /* + * Refund claimer deposit. + */ + function refundClaimDeposit(Request storage self) returns (bool) { + if (self.meta.isCancelled || self.meta.wasCalled) { + return self.claimData.refundDeposit(msg.gas); + } + return false; + } + + /* + * Send donation + */ + function sendDonation(Request storage self) returns (bool) { + if (self.meta.wasCalled) { + return self.paymentData.sendDonation(msg.gas); + } + return false; + } + + /* + * Send payment + */ + function sendPayment(Request storage self) returns (bool) { + if (self.meta.wasCalled) { + return self.paymentData.sendPayment(msg.gas); + } + return false; + } + + /* + * Send all extra ether in the request contract back to the owner. + */ + function sendOwnerEther(Request storage self) returns (bool) { + return sendOwnerEther(self, SafeSendLib.DEFAULT_SEND_GAS()); + } + + function sendOwnerEther(Request storage self, uint sendGas) returns (bool) { + if (self.meta.isCancelled || self.meta.wasCalled) { + self.meta.owner.safeSend(this.balance.flooredSub(self.claimData.claimDeposit) + .flooredSub(self.paymentData.paymentOwed) + .flooredSub(self.paymentData.donationOwed), + sendGas); + return true; + } + return false; + } } diff --git a/contracts/RequestMetaLib.sol b/contracts/RequestMetaLib.sol index 5919c54e1..3cdbe4565 100644 --- a/contracts/RequestMetaLib.sol +++ b/contracts/RequestMetaLib.sol @@ -14,6 +14,12 @@ library RequestMetaLib { // Was the request cancelled. bool isCancelled; + + // Was the request called. + bool wasCalled; + + // Was the return value from the call successful. + bool wasSuccessful; } function reportExecution(RequestMeta storage self, uint gasReserve) returns (bool) { diff --git a/contracts/ScheduleLib.sol b/contracts/RequestScheduleLib.sol similarity index 50% rename from contracts/ScheduleLib.sol rename to contracts/RequestScheduleLib.sol index 55a6fb648..443b99d13 100644 --- a/contracts/ScheduleLib.sol +++ b/contracts/RequestScheduleLib.sol @@ -1,13 +1,17 @@ //pragma solidity 0.4.1; +import {MathLib} from "contracts/MathLib.sol"; + + +library RequestScheduleLib { + using MathLib for uint; -library ScheduleLib { enum TemporalUnit { Seconds, Blocks } - struct Schedule { + struct ExecutionWindow { // The type of unit used to measure time. TemporalUnit temporalUnit; @@ -25,6 +29,10 @@ library ScheduleLib { // The number of temporal units after the windowStart during which only // the address that claimed the request may execute the request. uint reservedWindowSize; + + // The number of temporal units that prior to the call freeze window + // during which the request will be claimable. + uint claimWindowSize; } /* @@ -32,7 +40,7 @@ library ScheduleLib { * Currently supports block based times, and timestamp (seconds) based * times. */ - function getNow(Schedule storage self) returns (uint) { + function getNow(ExecutionWindow storage self) returns (uint) { return getNow(self.temporalUnit); } @@ -47,48 +55,98 @@ library ScheduleLib { } } + /* + * The modifier that will be applied to the payment value for a claimed call. + */ + function computePaymentModifier(ExecutionWindow storage self) returns (uint8) { + if (!inClaimWindow(self)) { + throw; + } + uint paymentModifier = getNow(self).flooredSub(firstClaimBlock(self)) + .safeMultiply(100) / self.claimWindowSize; + if (paymentModifier > 100) { + throw; + } + return uint8(paymentModifier); + } + /* * Helper: computes the end of the execution window. */ - function windowEnd(Schedule storage self) returns (uint) { - return self.windowStart + self.windowSize; + function windowEnd(ExecutionWindow storage self) returns (uint) { + return self.windowStart.safeAdd(self.windowSize); } /* * Helper: computes the end of the reserved portion of the execution * window. */ - function reservedWindowEnd(Schedule storage self) returns (uint) { - return self.windowStart + self.reservedWindowSize; + function reservedWindowEnd(ExecutionWindow storage self) returns (uint) { + return self.windowStart.safeAdd(self.reservedWindowSize); + } + + /* + * Helper: computes the time when the request will be frozen until execution. + */ + function freezeStart(ExecutionWindow storage self) returns (uint) { + return self.windowStart.flooredSub(self.freezePeriod); + } + + /* + * Helper: computes the time when the request will be frozen until execution. + */ + function firstClaimBlock(ExecutionWindow storage self) returns (uint) { + return freezeStart(self).flooredSub(self.claimWindowSize); } /* * Helper: Returns boolean if we are before the execution window. */ - function isBeforeWindow(Schedule storage self) returns (bool) { + function isBeforeWindow(ExecutionWindow storage self) returns (bool) { return getNow(self) < self.windowStart; } /* * Helper: Returns boolean if we are after the execution window. */ - function isAfterWindow(Schedule storage self) returns (bool) { - return getNow(self) > self.windowStart; + function isAfterWindow(ExecutionWindow storage self) returns (bool) { + return getNow(self) >= windowEnd(self); } /* * Helper: Returns boolean if we are inside the execution window. */ - function inWindow(Schedule storage self) returns (bool) { - return self.windowStart <= getNow(self) && getNow(self) <= windowEnd(self); + function inWindow(ExecutionWindow storage self) returns (bool) { + return self.windowStart <= getNow(self) && getNow(self) < windowEnd(self); } /* * Helper: Returns boolean if we are inside the reserved portion of the * execution window. */ - function inReservedWindow(Schedule storage self) returns (bool) { - return self.windowStart <= getNow(self) && getNow(self) <= reservedWindowEnd(self); + function inReservedWindow(ExecutionWindow storage self) returns (bool) { + return self.windowStart <= getNow(self) && getNow(self) < reservedWindowEnd(self); + } + + /* + * Helper: Returns boolean if we are inside the claim window. + */ + function inClaimWindow(ExecutionWindow storage self) returns (bool) { + return firstClaimBlock(self) <= getNow(self) && getNow(self) < freezeStart(self); + } + + /* + * Helper: Returns boolean if we are before the freeze period. + */ + function isBeforeFreeze(ExecutionWindow storage self) returns (bool) { + return getNow(self) < freezeStart(self); + } + + /* + * Helper: Returns boolean if we are before the freeze period. + */ + function isBeforeClaimWindow(ExecutionWindow storage self) returns (bool) { + return getNow(self) < firstClaimBlock(self); } /* @@ -105,7 +163,7 @@ library ScheduleLib { function validateWindowStart(TemporalUnit temporalUnit, uint freezePeriod, uint windowStart) returns (bool) { - return getNow(temporalUnit) + freezePeriod <= windowStart; + return getNow(temporalUnit).safeAdd(freezePeriod) <= windowStart; } /* diff --git a/contracts/RequestTracker.sol b/contracts/RequestTracker.sol new file mode 100644 index 000000000..e360f3804 --- /dev/null +++ b/contracts/RequestTracker.sol @@ -0,0 +1,64 @@ +//pragma solidity 0.4.1; + +import {GroveLib} from "contracts/GroveLib.sol"; +import {MathLib} from "contracts/MathLib.sol"; + + +contract RequestTracker { + using GroveLib for GroveLib.Index; + using MathLib for uint; + + mapping (address => GroveLib.Index) requestsByAddress; + + /* + * Returns the windowStart value for the given request. + */ + function getWindowStart(address factory, address request) constant returns (uint) { + return uint(requestsByAddress[factory].getNodeValue(bytes32(request))); + } + + /* + * Returns the request which comes directly before the given request. + */ + function getPreviousRequest(address factory, address request) constant returns (address) { + return address(requestsByAddress[factory].getPreviousNode(bytes32(request))); + } + + /* + * Returns the request which comes directly after the given request. + */ + function getNextRequest(address factory, address request) constant returns (address) { + return address(requestsByAddress[factory].getNextNode(bytes32(request))); + } + + /* + * Add the given request. + */ + function addRequest(address request, uint startWindow) returns (bool) { + requestsByAddress[msg.sender].insert(bytes32(request), startWindow.safeCastSigned()); + return true; + } + + /* + * Remove the given address from the index. + */ + function removeRequest(address request) constant returns (bool) { + requestsByAddress[msg.sender].remove(bytes32(request)); + return true; + } + + /* + * Return boolean as to whether the given address is present for the given + * factory. + */ + function isKnownRequest(address factory, address request) constant returns (bool) { + return requestsByAddress[factory].exists(bytes32(request)); + } + + /* + * Query the index for the given factory. + */ + function query(address factory, bytes2 operator, uint value) constant returns (address) { + return address(requestsByAddress[factory].query(operator, value.safeCastSigned())); + } +} diff --git a/contracts/RequestTrackerInterface.sol b/contracts/RequestTrackerInterface.sol new file mode 100644 index 000000000..0a2a1166d --- /dev/null +++ b/contracts/RequestTrackerInterface.sol @@ -0,0 +1,12 @@ +//pragma solidity 0.4.1; + + +contract RequestTrackerInterface { + function getWindowStart(address factory, address request) constant returns (uint); + function getPreviousRequest(address factory, address request) constant returns (address); + function getNextRequest(address factory, address request) constant returns (address); + function addRequest(address request, uint startWindow) constant returns (bool); + function removeRequest(address request) constant returns (bool); + function isKnownRequest(address factory, address request) constant returns (bool); + function query(address factory, bytes2 operator, uint value) constant returns (address); +} diff --git a/contracts/SafeSendLib.sol b/contracts/SafeSendLib.sol new file mode 100644 index 000000000..8d35eb9d9 --- /dev/null +++ b/contracts/SafeSendLib.sol @@ -0,0 +1,46 @@ +//pragma solidity 0.4.1; + + +library SafeSendLib { + event SendFailed(address to, uint value); + + uint constant _DEFAULT_SEND_GAS = 90000; + + function DEFAULT_SEND_GAS() returns (uint) { + return _DEFAULT_SEND_GAS; + } + + /* + * Send ether to an address. + * On failure log the `SendFailed` event. + * Returns the amount of wei that was sent (which will be 0 on failure). + */ + function safeSend(address to, uint value) returns (uint) { + return safeSend(to, value, _DEFAULT_SEND_GAS); + } + + /* + * Same as `safeSend` but allows specifying the gas to be included with the + * send. + */ + function safeSend(address to, uint value, uint sendGas) returns (uint) { + if (to == 0x0) { + throw; + } + + if (value > this.balance) { + value = this.balance; + } + + if (value == 0) { + return 0; + } + + if (!to.call.value(value).gas(sendGas)()) { + SendFailed(to, value); + return 0; + } + + return value; + } +} diff --git a/contracts/TransactionRequest.sol b/contracts/TransactionRequest.sol index 7fad03646..e7a58780f 100644 --- a/contracts/TransactionRequest.sol +++ b/contracts/TransactionRequest.sol @@ -7,32 +7,125 @@ import {Digger} from "contracts/Digger.sol"; contract TransactionRequest is Digger { using RequestLib for RequestLib.Request; - function TransactionRequest(address[3] addressArgs, + /* + * addressArgs[0] - meta.owner + * addressArgs[1] - paymentData.donationBenefactor + * addressArgs[2] - txnData.toAddress + * + * uintArgs[0] - paymentData.donation + * uintArgs[1] - paymentData.payment + * uintArgs[2] - schedule.claimWindowSize + * uintArgs[3] - schedule.freezePeriod + * uintArgs[4] - schedule.reservedWindowSize + * uintArgs[5] - schedule.temporalUnit + * uintArgs[6] - schedule.windowStart + * uintArgs[7] - schedule.windowSize + * uintArgs[8] - txnData.callGas + * uintArgs[9] - txnData.callValue + * uintArgs[10] - txnData.requiredStackDepth + */ + function TransactionRequest(address[4] addressArgs, uint[11] uintArgs, bytes callData) { - address[4] memory addressValues = [ - msg.sender, // meta.createdBy - addressArgs[0], // meta.owner - addressArgs[1], // paymentData.donationBenefactor - addressArgs[2] // txnData.toAddress - ]; - txnRequest.initialize(addressValues, uintArgs, callData); + txnRequest.initialize(addressArgs, uintArgs, callData); } RequestLib.Request txnRequest; + /* + * Actions + */ function execute() public returns (bool) { return txnRequest.execute(); } - function requestData() constant returns (address[5], + function cancel() public returns (bool) { + return txnRequest.cancel(); + } + + function claim() public returns (bool) { + return txnRequest.claim(); + } + + /* + * Data accessor functions. + */ + // + // TODO: figure out why returning RequestLib.serialize() isn't working. + // + function requestData() constant returns (address[6], bool[3], - uint[16], + uint[15], uint8[1]) { - return txnRequest.serialize(); + // Address values + address[6] memory addressValues = [ + txnRequest.claimData.claimedBy, + txnRequest.meta.createdBy, + txnRequest.meta.owner, + txnRequest.paymentData.donationBenefactor, + txnRequest.paymentData.paymentBenefactor, + txnRequest.txnData.toAddress + ]; + + // Boolean values + bool[3] memory boolValues = [ + txnRequest.meta.isCancelled, + txnRequest.meta.wasCalled, + txnRequest.meta.wasSuccessful + ]; + + // UInt256 values + uint[15] memory uintValues = [ + txnRequest.claimData.claimDeposit, + txnRequest.paymentData.anchorGasPrice, + txnRequest.paymentData.donation, + txnRequest.paymentData.donationOwed, + txnRequest.paymentData.payment, + txnRequest.paymentData.paymentOwed, + txnRequest.schedule.claimWindowSize, + txnRequest.schedule.freezePeriod, + txnRequest.schedule.reservedWindowSize, + uint(txnRequest.schedule.temporalUnit), + txnRequest.schedule.windowStart, + txnRequest.schedule.windowSize, + txnRequest.txnData.callGas, + txnRequest.txnData.callValue, + txnRequest.txnData.requiredStackDepth + ]; + + // Uint8 values + uint8[1] memory uint8Values = [ + txnRequest.claimData.paymentModifier + ]; + + return ( + addressValues, + boolValues, + uintValues, + uint8Values + ); } function callData() constant returns (bytes) { return txnRequest.txnData.callData; } + + /* + * Pull based payment functions. + */ + function refundClaimDeposit() public returns (bool) { + return txnRequest.refundClaimDeposit(); + } + + function sendDonation() public returns (bool) { + return txnRequest.sendDonation(); + } + + function sendPayment() public returns (bool) { + return txnRequest.sendPayment(); + } + + function sendOwnerEther() public returns (bool) { + return txnRequest.sendOwnerEther(); + } } diff --git a/contracts/TransactionRequestInterface.sol b/contracts/TransactionRequestInterface.sol index c38247089..0c2ac8f80 100644 --- a/contracts/TransactionRequestInterface.sol +++ b/contracts/TransactionRequestInterface.sol @@ -2,5 +2,27 @@ contract TransactionRequestInterface { + /* + * Primary actions + */ function execute() public returns (bool); + function cancel() public returns (bool); + function claim() public returns (bool); + + /* + * Data accessors + */ + function requestData() constant returns (address[5], + bool[3], + uint[16], + uint8[1]); + function callData() constant returns (bytes); + + /* + * Pull mechanisms for payments. + */ + function refundClaimDeposit() public returns (bool); + function sendDonation() public returns (bool); + function sendPayment() public returns (bool); + function sendOwnerEther() public returns (bool); } diff --git a/docs/changelog.rst b/docs/changelog.rst index db83811aa..137f25f81 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,20 @@ Changelog ========= +1.0.0 (unreleased) +----- + +- Full rewrite of all contracts. +- Support for both time and block based scheduling. +- New permissionless call tracker now used to track scheduled calls. +- Donation address can now be configured. +- Request execution window size is now configurable. +- Reserved claim window size is now configurable. +- Freeze period is now configurable. +- Claim window size is now configurable. +- All payments now support pull mechanism for retrieving payments. + + 0.7.0 ----- diff --git a/tests/accounting/test_call_donation.py b/tests/accounting/test_call_donation.py deleted file mode 100644 index 56a6143b2..000000000 --- a/tests/accounting/test_call_donation.py +++ /dev/null @@ -1,41 +0,0 @@ -def test_execution_donation(unmigrated_chain, web3, FutureBlockCall, CallLib, - deploy_fbc): - chain = unmigrated_chain - client_contract = chain.get_contract('TestCallExecution') - - call = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=web3.eth.blockNumber + 20, - payment=12345, - donation=54321, - ) - - while web3.eth.blockNumber < call.call().targetBlock(): - web3._requestManager.request_blocking("evm_mine", []) - - assert web3.eth.getBalance(client_contract.address) == 0 - - assert client_contract.call().v_bool() is False - assert client_contract.call().wasSuccessful() == 0 - - # sanity check - assert web3.eth.getBalance('0xd3cda913deb6f67967b99d67acdfa1712c293601') == 0 - - call_txn_hash = client_contract.transact().doExecution(call.address) - call_txn_receipt = chain.wait.for_receipt(call_txn_hash) - - assert client_contract.call().wasSuccessful() == 1 - assert client_contract.call().v_bool() is True - - log_entries = call_txn_receipt['logs'] - assert log_entries - - filter = CallLib().pastEvents('CallExecuted') - events = filter.get() - - assert len(events) == 1 - event = events[0] - - assert event['args']['donation'] == 54321 - assert web3.eth.getBalance('0xd3cda913deb6f67967b99d67acdfa1712c293601') == 54321 diff --git a/tests/accounting/test_call_gas_scalar.py b/tests/accounting/test_call_gas_scalar.py deleted file mode 100644 index 050950052..000000000 --- a/tests/accounting/test_call_gas_scalar.py +++ /dev/null @@ -1,48 +0,0 @@ -import pytest -import itertools - - -@pytest.mark.parametrize( - 'base_gas_price,gas_price_and_expected', - itertools.chain( - itertools.product( - [20], - [ - (4, 145), - (8, 138), - (12, 129), - (16, 117), - (20, 100), - (24, 83), - (28, 71), - (32, 62), - (36, 55), - ], - ), - itertools.product( - [500], - [ - (50, 148), - (125, 143), - (275, 132), - (400, 117), - (475, 105), - (500, 100), - (525, 95), - (600, 83), - (700, 71), - (900, 55), - (1200, 41), - ], - ), - ), -) -def test_gas_scalar_values(unmigrated_chain, base_gas_price, gas_price_and_expected): - gas_price, expected_gas_scalar = gas_price_and_expected - - chain = unmigrated_chain - - call_lib = chain.get_contract('CallLib') - - actual_gas_scalar = call_lib.call().getGasScalar(base_gas_price, gas_price) - assert actual_gas_scalar == expected_gas_scalar diff --git a/tests/accounting/test_call_payout.py b/tests/accounting/test_call_payout.py deleted file mode 100644 index 2329d3d07..000000000 --- a/tests/accounting/test_call_payout.py +++ /dev/null @@ -1,43 +0,0 @@ -def test_execution_payment(chain, web3, FutureBlockCall, CallLib, - deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 20 - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=target_block, - payment=12345, - donation=54321, - ) - - chain.wait.for_block(target_block) - - assert web3.eth.getBalance(client_contract.address) == 0 - - assert client_contract.call().v_bool() is False - assert client_contract.call().wasSuccessful() == 0 - - assert fbc.call().wasCalled() is False - - call_txn_hash = client_contract.transact().doExecution(fbc.address) - chain.wait.for_receipt(call_txn_hash) - - assert fbc.call().wasCalled() is True - assert fbc.call().wasSuccessful() is True - - assert client_contract.call().wasSuccessful() == 1 - assert client_contract.call().v_bool() is True - - filter = CallLib().pastEvents('CallExecuted', {'address': fbc.address}) - events = filter.get() - - assert len(events) == 1 - event = events[0] - - assert 'gasCost' in event['args'] - expected_payout = 12345 + event['args']['gasCost'] - - assert event['args']['payment'] == expected_payout - assert web3.eth.getBalance(client_contract.address) == event['args']['payment'] diff --git a/tests/accounting/test_early_claim_reduces_default_payment.py b/tests/accounting/test_early_claim_reduces_default_payment.py deleted file mode 100644 index efd799424..000000000 --- a/tests/accounting/test_early_claim_reduces_default_payment.py +++ /dev/null @@ -1,41 +0,0 @@ -def test_early_claim_decreases_default_payment(chain, web3, denoms, - get_scheduled_fbc, - get_4byte_selector): - scheduler = chain.get_contract('Scheduler') - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - - noop_4byte_selector = get_4byte_selector(client_contract, 'noop') - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - contractAddress=client_contract.address, - abiSignature=noop_4byte_selector, - targetBlock=target_block, - ) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - - chain.wait.for_block(fbc.call().firstClaimBlock()) - - claim_txn_hash = fbc.transact({'value': 10 * denoms.ether}).claim() - chain.wait.for_receipt(claim_txn_hash) - - assert fbc.call().claimer() == web3.eth.coinbase - - chain.wait.for_block(target_block) - - default_payment_before = scheduler.call().defaultPayment() - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().wasCalled() - - expected = default_payment_before * 9999 // 10000 - actual = scheduler.call().defaultPayment() - - assert actual < default_payment_before - assert actual == expected diff --git a/tests/accounting/test_extra_payment_when_claimer_doesnt_call.py b/tests/accounting/test_extra_payment_when_claimer_doesnt_call.py deleted file mode 100644 index 43842788a..000000000 --- a/tests/accounting/test_extra_payment_when_claimer_doesnt_call.py +++ /dev/null @@ -1,58 +0,0 @@ -def test_claim_deposit_goes_to_caller(chain, web3, denoms, deploy_fbc): - scheduler = chain.get_contract('Scheduler') - client_contract = chain.get_contract('TestCallExecution') - CallLib = chain.get_contract_factory('CallLib') - - target_block = web3.eth.blockNumber + 300 - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=target_block, - payment=12345, - donation=54321, - endowment=denoms.ether * 100, - ) - - chain.wait.for_block(target_block - 10 - 255) - - # claim it - deposit_amount = 2 * fbc.call().basePayment() - claim_txn_h = fbc.transact({'value': deposit_amount}).claim() - chain.wait.for_receipt(claim_txn_h) - - chain.wait.for_block( - fbc.call().targetBlock() + scheduler.call().getCallWindowSize() + 1 - ) - executor_addr = web3.eth.accounts[1] - before_balance = web3.eth.getBalance(executor_addr) - - assert fbc.call().wasCalled() is False - assert fbc.call().claimer() == web3.eth.coinbase - assert fbc.call().claimerDeposit() == deposit_amount - - ffa_txn_h = fbc.transact({'from': executor_addr}).execute() - ffa_txn_r = chain.wait.for_receipt(ffa_txn_h) - - assert fbc.call().wasCalled() is True - assert fbc.call().claimer() == web3.eth.coinbase - assert fbc.call().claimerDeposit() == 0 - - execute_filter = CallLib.pastEvents('CallExecuted', {'address': fbc.address}) - execute_logs = execute_filter.get() - - assert len(execute_logs) == 1 - execute_log_data = execute_logs[0] - - assert executor_addr == execute_log_data['args']['executor'] - - after_balance = web3.eth.getBalance(executor_addr) - expected_payout = deposit_amount + fbc.call().basePayment() + execute_log_data['args']['gasCost'] - - assert abs(execute_log_data['args']['payment'] - expected_payout) < 100 - - computed_payout = after_balance - before_balance - actual_gas = ffa_txn_r['gasUsed'] - gas_diff = execute_log_data['args']['gasCost'] - actual_gas - - assert computed_payout == deposit_amount + 12345 + gas_diff diff --git a/tests/accounting/test_gas_accounting_for_exceptions.py b/tests/accounting/test_gas_accounting_for_exceptions.py deleted file mode 100644 index c25d1aa3c..000000000 --- a/tests/accounting/test_gas_accounting_for_exceptions.py +++ /dev/null @@ -1,33 +0,0 @@ -def test_gas_accounting_for_call_exception(unmigrated_chain, web3, deploy_fbc): - chain = unmigrated_chain - client_contract = chain.get_contract('TestErrors') - CallLib = chain.get_contract_factory('CallLib') - - fbc = deploy_fbc( - contract=client_contract, - method_name='doFail', - target_block=web3.eth.blockNumber + 10, - payment=12345, - donation=54321, - ) - - chain.wait.for_block(fbc.call().targetBlock()) - - execute_txn_hash = fbc.transact().execute() - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - execute_txn = web3.eth.getTransaction(execute_txn_hash) - - execute_filter = CallLib.pastEvents('CallExecuted', {'address': fbc.address}) - execute_logs = execute_filter.get() - assert len(execute_logs) == 1 - execute_log_data = execute_logs[0] - - assert execute_log_data['args']['success'] is False - - gas_used = execute_txn_receipt['gasUsed'] - gas_price = execute_txn['gasPrice'] - expected_gas_cost = gas_used * gas_price - recorded_gas_cost = execute_log_data['args']['gasCost'] - - assert expected_gas_cost <= recorded_gas_cost - assert abs(recorded_gas_cost - expected_gas_cost) < 1000 diff --git a/tests/accounting/test_gas_accounting_for_infinite_loops.py b/tests/accounting/test_gas_accounting_for_infinite_loops.py deleted file mode 100644 index 41f885be1..000000000 --- a/tests/accounting/test_gas_accounting_for_infinite_loops.py +++ /dev/null @@ -1,33 +0,0 @@ -def test_gas_accounting_for_infinite_loop(unmigrated_chain, web3, deploy_fbc): - chain = unmigrated_chain - client_contract = chain.get_contract('TestErrors') - CallLib = chain.get_contract_factory('CallLib') - - fbc = deploy_fbc( - contract=client_contract, - method_name='doInfinite', - target_block=web3.eth.blockNumber + 10, - payment=12345, - donation=54321, - ) - - chain.wait.for_block(fbc.call().targetBlock()) - - execute_txn_hash = fbc.transact().execute() - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - execute_txn = web3.eth.getTransaction(execute_txn_hash) - - execute_filter = CallLib.pastEvents('CallExecuted', {'address': fbc.address}) - execute_logs = execute_filter.get() - assert len(execute_logs) == 1 - execute_log_data = execute_logs[0] - - assert execute_log_data['args']['success'] is False - - gas_used = execute_txn_receipt['gasUsed'] - gas_price = execute_txn['gasPrice'] - expected_gas_cost = gas_used * gas_price - recorded_gas_cost = execute_log_data['args']['gasCost'] - - assert expected_gas_cost <= recorded_gas_cost - assert abs(expected_gas_cost - recorded_gas_cost) < 1000 diff --git a/tests/accounting/test_gas_accounting_for_normal_calls.py b/tests/accounting/test_gas_accounting_for_normal_calls.py deleted file mode 100644 index 2e9108be0..000000000 --- a/tests/accounting/test_gas_accounting_for_normal_calls.py +++ /dev/null @@ -1,33 +0,0 @@ -def test_gas_accounting_for_successful_call(unmigrated_chain, web3, deploy_fbc): - chain = unmigrated_chain - client_contract = chain.get_contract('TestCallExecution') - CallLib = chain.get_contract_factory('CallLib') - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=web3.eth.blockNumber + 10, - payment=12345, - donation=54321, - ) - - chain.wait.for_block(fbc.call().targetBlock()) - - execute_txn_hash = fbc.transact().execute() - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - execute_txn = web3.eth.getTransaction(execute_txn_hash) - - execute_filter = CallLib.pastEvents('CallExecuted', {'address': fbc.address}) - execute_logs = execute_filter.get() - assert len(execute_logs) == 1 - execute_log_data = execute_logs[0] - - assert execute_log_data['args']['success'] is True - - gas_used = execute_txn_receipt['gasUsed'] - gas_price = execute_txn['gasPrice'] - expected_gas_cost = gas_used * gas_price - recorded_gas_cost = execute_log_data['args']['gasCost'] - - assert expected_gas_cost <= recorded_gas_cost - assert abs(recorded_gas_cost - expected_gas_cost) < 1000 diff --git a/tests/accounting/test_late_claim_increases_default_payment.py b/tests/accounting/test_late_claim_increases_default_payment.py deleted file mode 100644 index 01fd35533..000000000 --- a/tests/accounting/test_late_claim_increases_default_payment.py +++ /dev/null @@ -1,41 +0,0 @@ -def test_late_claim_decreases_default_payment(chain, web3, denoms, - get_scheduled_fbc, - get_4byte_selector): - scheduler = chain.get_contract('Scheduler') - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - - noop_4byte_selector = get_4byte_selector(client_contract, 'noop') - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - contractAddress=client_contract.address, - abiSignature=noop_4byte_selector, - targetBlock=target_block, - ) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - - chain.wait.for_block(fbc.call().maxClaimBlock()) - - claim_txn_hash = fbc.transact({'value': 10 * denoms.ether}).claim() - chain.wait.for_receipt(claim_txn_hash) - - assert fbc.call().claimer() == web3.eth.coinbase - - chain.wait.for_block(target_block) - - default_payment_before = scheduler.call().defaultPayment() - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().wasCalled() - - expected = default_payment_before * 10001 // 10000 - actual = scheduler.call().defaultPayment() - - assert actual > default_payment_before - assert actual == expected diff --git a/tests/accounting/test_middle_third_claim_leaves_default_payment_unchanged.py b/tests/accounting/test_middle_third_claim_leaves_default_payment_unchanged.py deleted file mode 100644 index f95544ab9..000000000 --- a/tests/accounting/test_middle_third_claim_leaves_default_payment_unchanged.py +++ /dev/null @@ -1,39 +0,0 @@ -def test_middle_third_claim_results_in_no_change(chain, web3, denoms, - get_scheduled_fbc, - get_4byte_selector): - scheduler = chain.get_contract('Scheduler') - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - - noop_4byte_selector = get_4byte_selector(client_contract, 'noop') - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - contractAddress=client_contract.address, - abiSignature=noop_4byte_selector, - targetBlock=target_block, - ) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - - chain.wait.for_block(fbc.call().firstClaimBlock() + 128) - - claim_txn_hash = fbc.transact({'value': 10 * denoms.ether}).claim() - chain.wait.for_receipt(claim_txn_hash) - - assert fbc.call().claimer() == web3.eth.coinbase - - chain.wait.for_block(target_block) - - default_payment_before = scheduler.call().defaultPayment() - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().wasCalled() - - actual = scheduler.call().defaultPayment() - - assert actual == default_payment_before diff --git a/tests/accounting/test_scheduler_is_reimbursed_whatevers_left.py b/tests/accounting/test_scheduler_is_reimbursed_whatevers_left.py deleted file mode 100644 index d73c838b4..000000000 --- a/tests/accounting/test_scheduler_is_reimbursed_whatevers_left.py +++ /dev/null @@ -1,51 +0,0 @@ -def test_scheduler_gets_what_is_leftover(unmigrated_chain, web3, denoms, - deploy_fbc): - chain = unmigrated_chain - client_contract = chain.get_contract('TestCallExecution') - CallLib = chain.get_contract_factory('CallLib') - - scheduler_address = web3.eth.accounts[1] - web3.eth.sendTransaction({'to': scheduler_address, 'value': 20 * denoms.ether}) - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=web3.eth.blockNumber + 10, - payment=12345, - donation=54321, - endowment=10 * denoms.ether, - scheduler_address=scheduler_address, - ) - - chain.wait.for_block(fbc.call().targetBlock()) - - before_balance = web3.eth.getBalance(scheduler_address) - before_call_balance = web3.eth.getBalance(fbc.address) - - assert fbc.call().wasCalled() is False - assert before_call_balance == 10 * denoms.ether - - execute_txn_h = fbc.transact({ - 'from': web3.eth.coinbase, - }).execute() - chain.wait.for_receipt(execute_txn_h) - - assert fbc.call().wasCalled() is True - assert web3.eth.getBalance(fbc.address) == 0 - - execute_filter = CallLib.pastEvents( - 'CallExecuted', - {'address': fbc.address}, - ) - execute_logs = execute_filter.get() - assert len(execute_logs) == 1 - execute_log_data = execute_logs[0] - - after_balance = web3.eth.getBalance(scheduler_address) - payout = execute_log_data['args']['payment'] - donation = execute_log_data['args']['donation'] - - computed_reimbursement = after_balance - before_balance - expected_reimbursement = before_call_balance - payout - donation - - assert computed_reimbursement == expected_reimbursement diff --git a/tests/accounting/test_sending_ether.py b/tests/accounting/test_sending_ether.py deleted file mode 100644 index 465e1f76e..000000000 --- a/tests/accounting/test_sending_ether.py +++ /dev/null @@ -1,18 +0,0 @@ -def test_middle_third_claim_results_in_no_change(unmigrated_chain, web3, denoms, - deploy_fbc): - chain = unmigrated_chain - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - call_value=5 * denoms.ether, - ) - chain.wait.for_block(fbc.call().targetBlock()) - - assert web3.eth.getBalance(client_contract.address) == 0 - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert web3.eth.getBalance(client_contract.address) == 5 * denoms.ether diff --git a/tests/accounting/test_unclaimed_call_does_not_change_default_payment.py b/tests/accounting/test_unclaimed_call_does_not_change_default_payment.py deleted file mode 100644 index ea3b138c4..000000000 --- a/tests/accounting/test_unclaimed_call_does_not_change_default_payment.py +++ /dev/null @@ -1,26 +0,0 @@ -def test_unclaimed_call_does_not_change_default_payment(chain, web3, denoms, - get_scheduled_fbc, - get_4byte_selector): - scheduler = chain.get_contract('Scheduler') - client_contract = chain.get_contract('TestCallExecution') - - noop_4byte_selector = get_4byte_selector(client_contract, 'noop') - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - contractAddress=client_contract.address, - abiSignature=noop_4byte_selector, - ) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - - chain.wait.for_block(fbc.call().targetBlock()) - - default_payment_before = scheduler.call().defaultPayment() - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().wasCalled() - assert scheduler.call().defaultPayment() == default_payment_before diff --git a/tests/call-state/test_call_states.py b/tests/call-state/test_call_states.py deleted file mode 100644 index ed2807e36..000000000 --- a/tests/call-state/test_call_states.py +++ /dev/null @@ -1,140 +0,0 @@ -def test_call_cancellation_states_before_call_window(unmigrated_chain, web3, - deploy_fbc, CallStates): - chain = unmigrated_chain - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=web3.eth.blockNumber + 300 - ) - - assert fbc.call().state() == CallStates.Pending - - cancel_txn_hash = fbc.transact().cancel() - chain.wait.for_receipt(cancel_txn_hash) - - assert fbc.call().state() == CallStates.Cancelled - - -def test_states_when_claimed(unmigrated_chain, web3, denoms, deploy_fbc, - CallStates): - chain = unmigrated_chain - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=web3.eth.blockNumber + 300 - ) - - assert fbc.call().state() == CallStates.Pending - - # wait until middle of claim window - chain.wait.for_block(fbc.call().targetBlock() - 10 - 100) - - assert fbc.call().state() == CallStates.Unclaimed - - claim_txn_hash = fbc.transact({ - 'value': 2 * denoms.ether, - }).claim() - chain.wait.for_receipt(claim_txn_hash) - - assert fbc.call().state() == CallStates.Claimed - - chain.wait.for_block(fbc.call().targetBlock() - 9) - - assert fbc.call().state() == CallStates.Frozen - - chain.wait.for_block(fbc.call().targetBlock()) - - assert fbc.call().state() == CallStates.Callable - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().state() == CallStates.Executed - - -def test_states_when_unclaimed(unmigrated_chain, web3, denoms, deploy_fbc, - CallStates): - chain = unmigrated_chain - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=web3.eth.blockNumber + 300 - ) - - assert fbc.call().state() == CallStates.Pending - - chain.wait.for_block(fbc.call().targetBlock() - 9) - - assert fbc.call().state() == CallStates.Frozen - - chain.wait.for_block(fbc.call().targetBlock()) - - assert fbc.call().state() == CallStates.Callable - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().state() == CallStates.Executed - - -def test_missed_state_when_claimed(unmigrated_chain, web3, denoms, deploy_fbc, - CallStates): - chain = unmigrated_chain - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=web3.eth.blockNumber + 300 - ) - - assert fbc.call().state() == CallStates.Pending - - chain.wait.for_block(fbc.call().targetBlock() - 10 - 100) - - assert fbc.call().state() == CallStates.Unclaimed - - claim_txn_hash = fbc.transact({'value': 2 * denoms.ether}).claim() - chain.wait.for_receipt(claim_txn_hash) - - assert fbc.call().state() == CallStates.Claimed - - chain.wait.for_block(fbc.call().targetBlock()) - - assert fbc.call().state() == CallStates.Callable - - chain.wait.for_block(fbc.call().targetBlock() + fbc.call().gracePeriod()) - - assert fbc.call().state() == CallStates.Missed - - -def test_missed_state_when_not_claimed(unmigrated_chain, web3, denoms, - deploy_fbc, CallStates): - chain = unmigrated_chain - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=web3.eth.blockNumber + 300 - ) - - assert fbc.call().state() == CallStates.Pending - - chain.wait.for_block(fbc.call().targetBlock() - 10 - 100) - - assert fbc.call().state() == CallStates.Unclaimed - - chain.wait.for_block(fbc.call().targetBlock()) - - assert fbc.call().state() == CallStates.Callable - - chain.wait.for_block(fbc.call().targetBlock() + fbc.call().gracePeriod()) - - assert fbc.call().state() == CallStates.Missed diff --git a/tests/canary/test_auto_returns_funds_when_exhausted.py b/tests/canary/test_auto_returns_funds_when_exhausted.py deleted file mode 100644 index f3b5d83aa..000000000 --- a/tests/canary/test_auto_returns_funds_when_exhausted.py +++ /dev/null @@ -1,42 +0,0 @@ -import gevent - - -def test_canary_returns_funds_when_exhausted(chain, web3, denoms, - deploy_canary, FutureBlockCall): - endowment = web3.toWei('4.003', 'ether') - - scheduler = chain.get_contract('Scheduler') - canary = deploy_canary(endowment=endowment, deploy_from=web3.eth.accounts[1]) - - initial_balance = web3.eth.getBalance(canary.address) - assert initial_balance == endowment - - assert canary.call().isAlive() is False - - init_txn_h = canary.transact().initialize() - chain.wait.for_receipt(init_txn_h) - - assert canary.call().isAlive() is True - - initial_owner_balance = web3.eth.getBalance(web3.eth.accounts[1]) - - with gevent.Timeout(180): - while web3.eth.getBalance(canary.address) > 0 or canary.call().isAlive(): - fbc_address = canary.call().callContractAddress() - - assert scheduler.call().isKnownCall(fbc_address) is True - - fbc = FutureBlockCall(address=fbc_address) - chain.wait.for_block(fbc.call().targetBlock()) - - exec_txn_h = fbc.transact().execute() - chain.wait.for_receipt(exec_txn_h) - - assert fbc.call().wasCalled() - - assert canary.call().isAlive() is False - assert web3.eth.getBalance(canary.address) == 0 - - after_owner_balance = web3.eth.getBalance(web3.eth.accounts[1]) - - assert after_owner_balance > initial_owner_balance diff --git a/tests/canary/test_can_only_initialize_once.py b/tests/canary/test_can_only_initialize_once.py deleted file mode 100644 index 80cbdc4cf..000000000 --- a/tests/canary/test_can_only_initialize_once.py +++ /dev/null @@ -1,19 +0,0 @@ -def test_canary_cannot_be_double_initialized(chain, deploy_canary): - canary = deploy_canary() - - assert canary.call().isAlive() is False - - first_init_txn_hash = canary.transact().initialize() - chain.wait.for_receipt(first_init_txn_hash) - - assert canary.call().isAlive() is True - - fbc_address = canary.call().callContractAddress() - assert fbc_address != "0x0000000000000000000000000000000000000000" - - second_init_txn_hash = canary.transact().initialize() - chain.wait.for_receipt(second_init_txn_hash) - - assert canary.call().isAlive() is True - # assert that the address hasn't changed - assert fbc_address == canary.call().callContractAddress() diff --git a/tests/canary/test_cancelling_canary.py b/tests/canary/test_cancelling_canary.py deleted file mode 100644 index 7e9d21889..000000000 --- a/tests/canary/test_cancelling_canary.py +++ /dev/null @@ -1,28 +0,0 @@ -def test_canary_cancellation(chain, web3, deploy_canary, FutureBlockCall, denoms): - scheduler = chain.get_contract('Scheduler') - canary = deploy_canary() - - init_txn_h = canary.transact().initialize() - chain.wait.for_receipt(init_txn_h) - - fbc_address = canary.call().callContractAddress() - - # check that the call was scheduled - assert fbc_address != "0x0000000000000000000000000000000000000000" - assert scheduler.call().isKnownCall(fbc_address) is True - - # check that the heartbeat went up - assert canary.call().heartbeatCount() == 0 - - fbc = FutureBlockCall(address=fbc_address) - - # check that it has enough funds to successfully heartbeat - assert web3.eth.getBalance(canary.address) >= 2 * denoms.ether - assert fbc.call().isCancelled() is False - - cancel_txn_h = canary.transact().cancel() - chain.wait.for_receipt(cancel_txn_h) - - assert web3.eth.getBalance(canary.address) == 0 - # ensure it also cancells the pending call contract - assert fbc.call().isCancelled() is True diff --git a/tests/canary/test_cannot_revive_once_heartbeat_is_missed.py b/tests/canary/test_cannot_revive_once_heartbeat_is_missed.py deleted file mode 100644 index 8cc084072..000000000 --- a/tests/canary/test_cannot_revive_once_heartbeat_is_missed.py +++ /dev/null @@ -1,38 +0,0 @@ -def test_cannary_cannot_be_revived(chain, web3, deploy_canary, denoms, - FutureBlockCall): - scheduler = chain.get_contract('Scheduler') - canary = deploy_canary() - - init_txn_h = canary.transact().initialize() - chain.wait.for_receipt(init_txn_h) - - fbc_address = canary.call().callContractAddress() - - # check that the call was scheduled - assert fbc_address != "0x0000000000000000000000000000000000000000" - assert scheduler.call().isKnownCall(fbc_address) is True - - # check that the heartbeat went up - assert canary.call().heartbeatCount() == 0 - - # check that it has enough funds to successfully heartbeat - assert web3.eth.getBalance(canary.address) >= 2 * denoms.ether - - fbc = FutureBlockCall(address=fbc_address) - - assert canary.call().isAlive() is True - - # Wait till after the call - chain.wait.for_block( - fbc.call().targetBlock() + fbc.call().gracePeriod() + 1 - ) - - assert canary.call().isAlive() is False - - revive_txn_h = canary.transact().heartbeat() - chain.wait.for_receipt(revive_txn_h) - - # shouldn't be alive. stats shouldn't have changed - assert canary.call().isAlive() is False - assert canary.call().heartbeatCount() == 0 - assert canary.call().callContractAddress() == fbc_address diff --git a/tests/canary/test_initial_scheduling_setup.py b/tests/canary/test_initial_scheduling_setup.py deleted file mode 100644 index 1b25a5ac3..000000000 --- a/tests/canary/test_initial_scheduling_setup.py +++ /dev/null @@ -1,37 +0,0 @@ -def test_canary_initialization(chain, web3, deploy_canary, denoms, - FutureBlockCall): - scheduler = chain.get_contract('Scheduler') - canary = deploy_canary() - - init_txn_h = canary.transact().initialize() - chain.wait.for_receipt(init_txn_h) - - fbc_address = canary.call().callContractAddress() - - # check that the call was scheduled - assert fbc_address != "0x0000000000000000000000000000000000000000" - assert scheduler.call().isKnownCall(fbc_address) is True - - # check that the heartbeat went up - assert canary.call().heartbeatCount() == 0 - - # check that it has enough funds to successfully heartbeat - assert web3.eth.getBalance(canary.address) >= 2 * denoms.ether - - fbc = FutureBlockCall(address=fbc_address) - - assert canary.call().isAlive() is True - - chain.wait.for_block(fbc.call().targetBlock()) - - exec_txn_h = fbc.transact().execute() - chain.wait.for_receipt(exec_txn_h) - - assert fbc.call().wasCalled() - assert fbc.call().wasSuccessful() - - next_fbc_address = canary.call().callContractAddress() - assert next_fbc_address != fbc_address - assert scheduler.call().isKnownCall(fbc_address) - - assert canary.call().heartbeatCount() == 1 diff --git a/tests/canary/test_is_alive_when_first_deployed.py b/tests/canary/test_is_alive_when_first_deployed.py deleted file mode 100644 index c1c5476d8..000000000 --- a/tests/canary/test_is_alive_when_first_deployed.py +++ /dev/null @@ -1,4 +0,0 @@ -def test_canary_is_alive_on_initial_deploy(deploy_canary): - canary = deploy_canary() - assert canary.call().callContractAddress() == "0x0000000000000000000000000000000000000000" - assert canary.call().isAlive() is False diff --git a/tests/cancelling/test_anyone_can_cancel_after_call_window.py b/tests/cancelling/test_anyone_can_cancel_after_call_window.py deleted file mode 100644 index 46d776d11..000000000 --- a/tests/cancelling/test_anyone_can_cancel_after_call_window.py +++ /dev/null @@ -1,27 +0,0 @@ -def test_anyone_can_cancel_after_call_window(chain, web3, deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=target_block, - ) - - chain.wait.for_block(target_block + fbc.call().gracePeriod() + 1) - - assert fbc.call().isCancelled() is False - - cancel_txn_h = fbc.transact({'from': web3.eth.accounts[1]}).cancel() - chain.wait.for_receipt(cancel_txn_h) - - cancel_txn = web3.eth.getTransaction(cancel_txn_h) - - scheduler_address = fbc.call().schedulerAddress() - - # sanity - assert cancel_txn['from'] != scheduler_address - assert cancel_txn['from'] == web3.eth.accounts[1] - - assert fbc.call().isCancelled() is True diff --git a/tests/cancelling/test_cancelling_a_call.py b/tests/cancelling/test_cancelling_a_call.py deleted file mode 100644 index 555633c31..000000000 --- a/tests/cancelling/test_cancelling_a_call.py +++ /dev/null @@ -1,56 +0,0 @@ -def test_cancelling_a_call_before_bid_window(chain, web3, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=target_block, - ) - - first_bid_block = target_block - 240 - 15 - 10 - - chain.wait.for_block(first_bid_block - 1) - - assert fbc.call().isCancelled() is False - - cancel_txn_h = fbc.transact().cancel() - cancel_txn_r = chain.wait.for_receipt(cancel_txn_h) - - assert cancel_txn_r['blockNumber'] == first_bid_block - 1 - - assert fbc.call().isCancelled() is True - - cancel_filter = CallLib.pastEvents('Cancelled', {'address': fbc.address}) - cancel_logs = cancel_filter.get() - assert len(cancel_logs) == 1 - - cancel_log_data = cancel_logs[0] - assert cancel_log_data['args']['cancelled_by'] == web3.eth.coinbase - - -def test_cancelling_a_call_after_call_window(chain, web3, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 20 - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=target_block, - ) - - chain.wait.for_block(target_block + 256) - - assert fbc.call().isCancelled() is False - - cancel_txn_hash = fbc.transact().cancel() - chain.wait.for_receipt(cancel_txn_hash) - - cancel_filter = CallLib.pastEvents('Cancelled', {'address': fbc.address}) - cancel_logs = cancel_filter.get() - assert len(cancel_logs) == 1 - - cancel_log_data = cancel_logs[0] - assert cancel_log_data['args']['cancelled_by'] == web3.eth.coinbase - - assert fbc.call().isCancelled() is True diff --git a/tests/cancelling/test_cannot_cancel_during_bid_window.py b/tests/cancelling/test_cannot_cancel_during_bid_window.py deleted file mode 100644 index fba2ded53..000000000 --- a/tests/cancelling/test_cannot_cancel_during_bid_window.py +++ /dev/null @@ -1,23 +0,0 @@ -def test_cancelling_a_call_during_bid_window(chain, web3, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=target_block, - ) - - first_bid_block = target_block - 240 - 15 - 10 - chain.wait.for_block(first_bid_block) - - assert fbc.call().isCancelled() is False - - cancel_txn = fbc.transact().cancel() - chain.wait.for_receipt(cancel_txn) - - cancel_filter = CallLib.pastEvents('Cancelled', {'address': fbc.address}) - cancel_logs = cancel_filter.get() - assert not cancel_logs - - assert fbc.call().isCancelled() is False diff --git a/tests/cancelling/test_cannot_cancel_if_already_called.py b/tests/cancelling/test_cannot_cancel_if_already_called.py deleted file mode 100644 index 43a0d98e8..000000000 --- a/tests/cancelling/test_cannot_cancel_if_already_called.py +++ /dev/null @@ -1,30 +0,0 @@ -def test_cannot_cancel_if_already_called(chain, web3, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=target_block, - ) - - chain.wait.for_block(target_block) - - assert fbc.call().isCancelled() is False - assert fbc.call().wasCalled() is False - - execute_txn_h = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_h) - - assert fbc.call().wasCalled() is True - assert fbc.call().isCancelled() is False - - cancel_txn = fbc.transact().cancel() - chain.wait.for_receipt(cancel_txn) - - assert fbc.call().wasCalled() is True - assert fbc.call().isCancelled() is False - - cancel_filter = CallLib.pastEvents('Cancelled', {'address': fbc.address}) - cancel_logs = cancel_filter.get() - assert not cancel_logs diff --git a/tests/cancelling/test_cannot_cancel_if_already_cancelled.py b/tests/cancelling/test_cannot_cancel_if_already_cancelled.py deleted file mode 100644 index 4b9fc2b5f..000000000 --- a/tests/cancelling/test_cannot_cancel_if_already_cancelled.py +++ /dev/null @@ -1,25 +0,0 @@ -def test_cannot_cancel_if_already_cancelled(chain, web3, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - contract=client_contract, - method_name='setBool', - target_block=target_block, - ) - - assert fbc.call().isCancelled() is False - - cancel_txn_h = fbc.transact().cancel() - chain.wait.for_receipt(cancel_txn_h) - - assert fbc.call().isCancelled() is True - - duplicate_cancel_txn_h = fbc.transact().cancel() - chain.wait.for_receipt(duplicate_cancel_txn_h) - - cancel_filter = CallLib.pastEvents('Cancelled', {'address': fbc.address}) - cancel_logs = cancel_filter.get() - assert len(cancel_logs) == 1 - cancel_log_data = cancel_logs[0] - assert cancel_log_data['transactionHash'] == cancel_txn_h diff --git a/tests/cancelling/test_is_cancellable_property.py b/tests/cancelling/test_is_cancellable_property.py deleted file mode 100644 index fb970ffb2..000000000 --- a/tests/cancelling/test_is_cancellable_property.py +++ /dev/null @@ -1,83 +0,0 @@ -class State(object): - Pending = 0 - Unclaimed = 1 - Claimed = 2 - Frozen = 3 - Callable = 4 - Executed = 5 - Cancelled = 6 - Missed = 7 - - -def test_is_cancellable_before_call_window(chain, web3, deploy_fbc): - fbc = deploy_fbc(target_block=web3.eth.blockNumber + 300) - - assert fbc.call().isCancellable() is True - - # false for non-scheduler account - assert fbc.call({'from': web3.eth.accounts[1]}).isCancellable() is False - - cancel_txn_hash = fbc.transact().cancel() - chain.wait.for_receipt(cancel_txn_hash) - - assert fbc.call().isCancellable() is False - assert fbc.call({'from': web3.eth.accounts[1]}).isCancellable() is False - - -def test_not_cancellable_during_claim_window_and_call_window(chain, - web3, - denoms, - deploy_fbc): - fbc = deploy_fbc(target_block=web3.eth.blockNumber + 300) - - assert fbc.call().state() == State.Pending - assert fbc.call().isCancellable() is True - - # false for non-scheduler account - assert fbc.call({'from': web3.eth.accounts[1]}).isCancellable() is False - - chain.wait.for_block(fbc.call().firstClaimBlock()) - - assert fbc.call().isCancellable() is False - - claim_txn_hash = fbc.transact({'value': 2 * denoms.ether}).claim() - chain.wait.for_receipt(claim_txn_hash) - - assert fbc.call().state() == State.Claimed - assert fbc.call().isCancellable() is False - - chain.wait.for_block(fbc.call().targetBlock() - 9) - - assert fbc.call().state() == State.Frozen - assert fbc.call().isCancellable() is False - - chain.wait.for_block(fbc.call().targetBlock()) - - assert fbc.call().state() == State.Callable - assert fbc.call().isCancellable() is False - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().state() == State.Executed - assert fbc.call().isCancellable() is False - - -def test_cancellable_after_call_window_if_missed(chain, web3, deploy_fbc): - fbc = deploy_fbc(target_block=web3.eth.blockNumber + 300) - - assert fbc.call().state() == State.Pending - - chain.wait.for_block(fbc.call().targetBlock() + fbc.call().gracePeriod()) - - assert fbc.call().state() == State.Missed - - assert fbc.call().isCancellable() is True - # true for non-scheduler account - assert fbc.call({'from': web3.eth.accounts[1]}).isCancellable() is True - - cancel_txn_hash = fbc.transact().cancel() - chain.wait.for_receipt(cancel_txn_hash) - - assert fbc.call().isCancellable() is False - assert fbc.call({'from': web3.eth.accounts[1]}).isCancellable() is False diff --git a/tests/cancelling/test_only_scheduler_can_cancel_prior_to_target_block.py b/tests/cancelling/test_only_scheduler_can_cancel_prior_to_target_block.py deleted file mode 100644 index 310b826b7..000000000 --- a/tests/cancelling/test_only_scheduler_can_cancel_prior_to_target_block.py +++ /dev/null @@ -1,18 +0,0 @@ -def test_only_scheduler_can_cancel_prior_to_target_block(chain, - web3, - deploy_fbc, - CallLib): - target_block = web3.eth.blockNumber + 300 - - fbc = deploy_fbc(target_block=target_block) - - assert fbc.call().isCancelled() is False - - cancel_txn_hash = fbc.transact({'from': web3.eth.accounts[1]}).cancel() - chain.wait.for_receipt(cancel_txn_hash) - - assert fbc.call().isCancelled() is False - - cancel_filter = CallLib.pastEvents('Cancelled', {'address': fbc.address}) - cancel_logs = cancel_filter.get() - assert len(cancel_logs) == 0 diff --git a/tests/claiming/test_cannot_claim_after_window.py b/tests/claiming/test_cannot_claim_after_window.py deleted file mode 100644 index 70f60a60b..000000000 --- a/tests/claiming/test_cannot_claim_after_window.py +++ /dev/null @@ -1,22 +0,0 @@ -def test_cannot_claim_after_window(chain, web3, deploy_fbc, denoms): - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - target_block=target_block, - payment=1 * denoms.ether, - ) - - target_block = fbc.call().targetBlock() - base_payment = fbc.call().basePayment() - - last_claim_block = target_block - 10 - - chain.wait.for_block(last_claim_block + 1) - - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" - - txn_h = fbc.transact({'value': 2 * base_payment}).claim() - txn_r = chain.wait.for_receipt(txn_h) - - assert txn_r['blockNumber'] == last_claim_block + 1 - - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" diff --git a/tests/claiming/test_cannot_claim_before_window.py b/tests/claiming/test_cannot_claim_before_window.py deleted file mode 100644 index 88ee2856b..000000000 --- a/tests/claiming/test_cannot_claim_before_window.py +++ /dev/null @@ -1,21 +0,0 @@ -def test_cannot_claim_before_window(chain, web3, deploy_fbc, denoms): - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - target_block=target_block, - payment=1 * denoms.ether, - ) - - target_block = fbc.call().targetBlock() - base_payment = fbc.call().basePayment() - - first_claim_block = target_block - 255 - 10 - chain.wait.for_block(first_claim_block - 2) - - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" - - txn_h = fbc.transact({'value': 2 * base_payment}).claim() - txn_r = chain.wait.for_receipt(txn_h) - - assert txn_r['blockNumber'] == first_claim_block - 2 - - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" diff --git a/tests/claiming/test_cannot_claim_during_call_window.py b/tests/claiming/test_cannot_claim_during_call_window.py deleted file mode 100644 index 99d23505f..000000000 --- a/tests/claiming/test_cannot_claim_during_call_window.py +++ /dev/null @@ -1,21 +0,0 @@ -def test_cannot_claim_during_call_window(chain, web3, deploy_fbc, denoms): - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - target_block=target_block, - payment=1 * denoms.ether, - ) - - target_block = fbc.call().targetBlock() - base_payment = fbc.call().basePayment() - - chain.wait.for_block(target_block) - assert web3.eth.blockNumber == target_block - - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" - - txn_h = fbc.transact({'value': 2 * base_payment}).claim() - txn_r = chain.wait.for_receipt(txn_h) - - # this really should be `target_block + 1` very confused as to why it isn't - assert txn_r['blockNumber'] == target_block - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" diff --git a/tests/claiming/test_cannot_claim_during_freeze.py b/tests/claiming/test_cannot_claim_during_freeze.py deleted file mode 100644 index 2da985ea5..000000000 --- a/tests/claiming/test_cannot_claim_during_freeze.py +++ /dev/null @@ -1,21 +0,0 @@ -def test_cannot_claim_during_freeze_window(chain, web3, deploy_fbc, denoms, - CallStates): - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - target_block=target_block, - payment=1 * denoms.ether, - ) - - target_block = fbc.call().targetBlock() - base_payment = fbc.call().basePayment() - - chain.wait.for_block(target_block - 10) - assert fbc.call().state() == CallStates.Frozen - - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" - - txn_h = fbc.transact({'value': 2 * base_payment}).claim() - txn_r = chain.wait.for_receipt(txn_h) - - assert txn_r['blockNumber'] == target_block - 10 - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" diff --git a/tests/claiming/test_claim_values.py b/tests/claiming/test_claim_values.py deleted file mode 100644 index 4c4ef3b29..000000000 --- a/tests/claiming/test_claim_values.py +++ /dev/null @@ -1,29 +0,0 @@ -def test_claim_block_values(chain, web3, deploy_fbc, denoms): - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - target_block=target_block, - payment=1 * denoms.ether, - ) - - base_payment = fbc.call().basePayment() - - first_claim_block = target_block - 255 - 10 - peak_claim_block = target_block - 10 - 15 - last_claim_block = target_block - 10 - - assert fbc.call().getClaimAmountForBlock(first_claim_block) == 0 - - for i in range(240): - actual_claim_amount = fbc.call().getClaimAmountForBlock(first_claim_block + i) - expected_claim_amount = base_payment * i // 240 - assert actual_claim_amount == expected_claim_amount - - peak_amount = fbc.call().getClaimAmountForBlock(peak_claim_block) - assert peak_amount == base_payment - - for i in range(15): - actual_claim_amount = fbc.call().getClaimAmountForBlock(peak_claim_block + i) - assert actual_claim_amount == base_payment - - last_amount = fbc.call().getClaimAmountForBlock(last_claim_block) - assert last_amount == base_payment diff --git a/tests/claiming/test_claiming_during_growth_window.py b/tests/claiming/test_claiming_during_growth_window.py deleted file mode 100644 index b6685e460..000000000 --- a/tests/claiming/test_claiming_during_growth_window.py +++ /dev/null @@ -1,25 +0,0 @@ -def test_claiming_during_growth_window(chain, web3, deploy_fbc, denoms): - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc( - target_block=target_block, - payment=1 * denoms.ether, - ) - - base_payment = fbc.call().basePayment() - - first_claim_block = target_block - 255 - 10 - - claim_at_block = first_claim_block + 42 - - chain.wait.for_block(claim_at_block) - - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" - - txn_h = fbc.transact({'value': 2 * base_payment}).claim() - txn_r = chain.wait.for_receipt(txn_h) - - assert txn_r['blockNumber'] == claim_at_block - - assert fbc.call().claimer() == web3.eth.coinbase - assert fbc.call().claimerDeposit() == 2 * base_payment - assert fbc.call().claimAmount() == 42 * base_payment / 240 diff --git a/tests/claiming/test_claiming_during_max_window.py b/tests/claiming/test_claiming_during_max_window.py deleted file mode 100644 index 26f9fb2cc..000000000 --- a/tests/claiming/test_claiming_during_max_window.py +++ /dev/null @@ -1,26 +0,0 @@ -def test_claiming_during_max_window(chain, web3, deploy_fbc, denoms): - target_block = web3.eth.blockNumber + 300 - - fbc = deploy_fbc( - target_block=target_block, - payment=denoms.ether, - ) - - base_payment = fbc.call().basePayment() - - peak_claim_block = target_block - 10 - 15 - - claim_at_block = peak_claim_block + 7 - - chain.wait.for_block(claim_at_block) - - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" - - txn_h = fbc.transact({'value': 2 * base_payment}).claim() - txn_r = chain.wait.for_receipt(txn_h) - - assert txn_r['blockNumber'] == claim_at_block - - assert fbc.call().claimer() == web3.eth.coinbase - assert fbc.call().claimerDeposit() == 2 * base_payment - assert fbc.call().claimAmount() == base_payment diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..571b1f4a6 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,388 @@ +import pytest +import os +import json + +from web3.utils.string import ( + force_obj_to_text, + force_obj_to_bytes, +) + + +NULL_ADDRESS = '0x0000000000000000000000000000000000000000' + + +@pytest.fixture(scope="session") +def saved_state(project): + filename = 'tmp/saved-state-{hash}.json'.format(hash=project.get_source_file_hash()) + if os.path.exists(filename): + print("Loading state from:", filename) + with open(filename) as f: + state = {key: force_obj_to_bytes(value) for key, value in json.load(f).items()} + state['loaded_from'] = filename + return state + else: + return { + 'saved_blocks': [], + 'registrar_address': None, + } + + +@pytest.fixture() +def load_chain_state(saved_state, chain): + import rlp + from ethereum.blocks import Block + from testrpc import testrpc + + saved_blocks = saved_state['saved_blocks'] + + if saved_blocks: + evm = testrpc.tester_client.evm + evm.blocks = [] + + for block_idx, block_data in enumerate(saved_blocks[:-1]): + print("Loading: ", block_idx, "/", len(saved_blocks)) + block = rlp.decode(block_data, Block, env=evm.env) + evm.blocks.append(block) + evm.db.put(block.hash, block_data) + + evm.revert(saved_blocks[-2]) + print("Done loading") + evm.mine() + print("Done mining") + + registrar_address = saved_state['registrar_address'] + + if registrar_address: + chain.registrar = chain.RegistrarFactory(address=registrar_address) + + +@pytest.fixture() +def request_tracker(unmigrated_chain, web3, load_chain_state): + chain = unmigrated_chain + tracker = chain.get_contract('RequestTracker') + return tracker + + +@pytest.fixture() +def request_factory(chain, web3, request_tracker, load_chain_state): + import time + start_at = time.time() + print("Start:", start_at) + factory = chain.get_contract('RequestFactory', deploy_args=[request_tracker.address]) + + chain_code = web3.eth.getCode(factory.address) + assert len(chain_code) > 10 + print("End:", time.time(), "Elapsed:", time.time() - start_at) + + return factory + + +@pytest.fixture() +def RequestLib(chain, load_chain_state): + return type(chain.get_contract('RequestLib')) + + +@pytest.fixture() +def TransactionRequest(chain, load_chain_state): + # force lazy deployment of the dependencies for the TransactionRequest + # contract. + chain.get_contract('RequestLib') + TransactionRequest = chain.get_contract_factory('TransactionRequest') + return TransactionRequest + + +@pytest.fixture() +def RequestFactory(chain, request_factory, load_chain_state): + return type(request_factory) + + +@pytest.fixture() +def save_chain_snapshot(project, + chain, + saved_state, + RequestFactory, + TransactionRequest, + RequestLib, + request_factory, + request_tracker): + import rlp + from testrpc import testrpc + + saved_blocks = saved_state['saved_blocks'] + + if not saved_blocks: + evm = testrpc.tester_client.evm + evm.mine() + saved_state['saved_blocks'] = [rlp.encode(block) for block in evm.blocks[:-1]] + + registrar_address = saved_state['registrar_address'] + + if not registrar_address: + saved_state['registrar_address'] = chain.registrar.address + + filename = 'tmp/saved-state-{hash}.json'.format(hash=project.get_source_file_hash()) + + if saved_state.get('loaded_from') != filename: + print("Saving state to:", filename) + with open(filename, 'w') as f: + return json.dump(force_obj_to_text(saved_state), f) + + +@pytest.fixture() +def denoms(): + from web3.utils.currency import units + int_units = { + key: int(value) + for key, value in units.items() + } + return type('denoms', (object,), int_units) + + +@pytest.fixture() +def RequestData(chain, + web3, + request_factory, + get_txn_request, + denoms, + TransactionRequest, + save_chain_snapshot): + class _RequestData(object): + def __init__(self, + # claim + claimedBy=NULL_ADDRESS, + claimDeposit=0, + paymentModifier=0, + # meta + createdBy=web3.eth.coinbase, + owner=web3.eth.coinbase, + isCancelled=False, + wasCalled=False, + wasSuccessful=False, + # payment + anchorGasPrice=web3.eth.gasPrice, + donation=12345, + donationBenefactor='0xd3cda913deb6f67967b99d67acdfa1712c293601', + donationOwed=0, + payment=54321, + paymentBenefactor=NULL_ADDRESS, + paymentOwed=0, + # txnData + callData="", + toAddress=NULL_ADDRESS, + callGas=1000000, + callValue=0, + requiredStackDepth=0, + # schedule + claimWindowSize=255, + freezePeriod=None, + windowStart=None, + windowSize=None, + reservedWindowSize=None, + temporalUnit=1): + + if freezePeriod is None: + if temporalUnit == 0: + freezePeriod = 10 * 17 + else: + freezePeriod = 10 + + if windowSize is None: + if temporalUnit == 0: + windowSize = 255 * 17 + else: + windowSize = 255 + + if windowStart is None: + if temporalUnit == 0: + windowStart = web3.eth.getBlock('latest')['timestamp'] + freezePeriod + else: + windowStart = web3.eth.blockNumber + freezePeriod + + if reservedWindowSize is None: + if temporalUnit == 0: + reservedWindowSize = 16 * 17 + else: + reservedWindowSize = 16 + + self.claimData = type('claimData', (object,), { + 'claimedBy': claimedBy, + 'claimDeposit': claimDeposit, + 'paymentModifier': paymentModifier, + }) + self.meta = type('meta', (object,), { + 'createdBy': createdBy, + 'owner': owner, + 'isCancelled': isCancelled, + 'wasCalled': wasCalled, + 'wasSuccessful': wasSuccessful, + }) + self.paymentData = type('paymentData', (object,), { + 'anchorGasPrice': anchorGasPrice, + 'donation': donation, + 'donationBenefactor': donationBenefactor, + 'donationOwed': donationOwed, + 'payment': payment, + 'paymentBenefactor': paymentBenefactor, + 'paymentOwed': paymentOwed, + }) + self.txnData = type('txnData', (object,), { + 'callData': callData, + 'toAddress': toAddress, + 'callGas': callGas, + 'callValue': callValue, + 'requiredStackDepth': requiredStackDepth, + }) + self.schedule = type('schedule', (object,), { + 'claimWindowSize': claimWindowSize, + 'freezePeriod': freezePeriod, + 'reservedWindowSize': reservedWindowSize, + 'temporalUnit': temporalUnit, + 'windowStart': windowStart, + 'windowSize': windowSize, + }) + + def to_factory_kwargs(self): + return { + 'addressArgs': [ + self.meta.owner, + self.paymentData.donationBenefactor, + self.txnData.toAddress, + ], + 'uintArgs': [ + self.paymentData.donation, + self.paymentData.payment, + self.schedule.claimWindowSize, + self.schedule.freezePeriod, + self.schedule.reservedWindowSize, + self.schedule.temporalUnit, + self.schedule.windowStart, + self.schedule.windowSize, + self.txnData.callGas, + self.txnData.callValue, + self.txnData.requiredStackDepth, + ], + 'callData': self.txnData.callData, + } + + def deploy_via_factory(self, deploy_txn=None): + if deploy_txn is None: + deploy_txn = {'value': 10 * denoms.ether} + create_txn_hash = request_factory.transact( + deploy_txn, + ).createRequest( + **self.to_factory_kwargs() + ) + txn_request = get_txn_request(create_txn_hash) + return txn_request + + def to_init_kwargs(self): + return { + 'addressArgs': [ + self.meta.createdBy, + self.meta.owner, + self.paymentData.donationBenefactor, + self.txnData.toAddress, + ], + 'uintArgs': [ + self.paymentData.donation, + self.paymentData.payment, + self.schedule.claimWindowSize, + self.schedule.freezePeriod, + self.schedule.reservedWindowSize, + self.schedule.temporalUnit, + self.schedule.windowStart, + self.schedule.windowSize, + self.txnData.callGas, + self.txnData.callValue, + self.txnData.requiredStackDepth, + ], + 'callData': self.txnData.callData, + } + + def direct_deploy(self, deploy_txn=None): + if deploy_txn is None: + deploy_txn = {'value': 10 * denoms.ether} + deploy_txn_hash = TransactionRequest.deploy( + transaction=deploy_txn, + kwargs=self.to_init_kwargs(), + ) + txn_request_address = chain.wait.for_contract_address(deploy_txn_hash) + return TransactionRequest(address=txn_request_address) + + @classmethod + def from_contract(cls, txn_request): + address_args, bool_args, uint_args, uint8_args = txn_request.call().requestData() + call_data = txn_request.call().callData() + return cls.from_deserialize( + address_args, bool_args, uint_args, uint8_args, call_data, + ) + + @classmethod + def from_deserialize(cls, address_args, bool_args, uint_args, uint8_args, call_data): + init_kwargs = { + 'claimedBy': address_args[0], + 'createdBy': address_args[1], + 'owner': address_args[2], + 'donationBenefactor': address_args[3], + 'paymentBenefactor': address_args[4], + 'toAddress': address_args[5], + 'wasCalled': bool_args[1], + 'wasSuccessful': bool_args[2], + 'isCancelled': bool_args[0], + 'paymentModifier': uint8_args[0], + 'claimDeposit': uint_args[0], + 'anchorGasPrice': uint_args[1], + 'donation': uint_args[2], + 'payment': uint_args[3], + 'donationOwed': uint_args[4], + 'paymentOwed': uint_args[5], + 'claimWindowSize': uint_args[6], + 'freezePeriod': uint_args[7], + 'reservedWindowSize': uint_args[8], + 'temporalUnit': uint_args[9], + 'windowStart': uint_args[10], + 'windowSize': uint_args[11], + 'callGas': uint_args[12], + 'callValue': uint_args[13], + 'requiredStackDepth': uint_args[14], + 'callData': call_data, + } + return cls(**init_kwargs) + return _RequestData + + +@pytest.fixture() +def get_txn_request(chain, web3, request_factory, RequestFactory, TransactionRequest): + def _get_txn_request(txn_hash): + txn_receipt = chain.wait.for_receipt(txn_hash) + request_created_filter = RequestFactory.pastEvents('RequestCreated', { + 'fromBlock': txn_receipt['blockNumber'], + 'toBlock': txn_receipt['blockNumber'], + 'address': request_factory.address, + }) + request_created_logs = request_created_filter.get() + assert len(request_created_logs) == 1 + + log_data = request_created_logs[0] + + request_address = log_data['args']['request'] + txn_request = TransactionRequest(address=request_address) + return txn_request + return _get_txn_request + + +@pytest.fixture() +def get_execute_data(chain, web3, RequestLib): + def _get_execute_data(execute_txn_hash): + execute_txn = web3.eth.getTransaction(execute_txn_hash) + execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) + execute_filter = RequestLib.pastEvents('Executed', { + 'fromBlock': execute_txn_receipt['blockNumber'], + 'toBlock': execute_txn_receipt['blockNumber'], + 'address': execute_txn['to'], + }) + execute_logs = execute_filter.get() + assert len(execute_logs) == 1 + execute_data = execute_logs[0] + return execute_data + return _get_execute_data diff --git a/tests/data-registry/test_data_registry_via_call_contract.py b/tests/data-registry/test_data_registry_via_call_contract.py deleted file mode 100644 index f1abc2040..000000000 --- a/tests/data-registry/test_data_registry_via_call_contract.py +++ /dev/null @@ -1,57 +0,0 @@ -import pytest - -from web3.utils.encoding import ( - decode_hex, - encode_hex, -) - - -@pytest.mark.parametrize( - 'fn_name,fn_args', - ( - ('setInt', [-1234567890]), - ('setUInt', [1234567890123456789012345678901234567890]), - ('setAddress', ['0xd3cda913deb6f67967b99d67acdfa1712c293601']), - ('setBytes32', ['this is a bytes32 string']), - ('setBytes', ['this is a byte string that is longer than 32 bytes']), - ( - 'setMany', - ( - 1234567890, - -1234567890, - 987654321, - '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13', - '0xd3cda913deb6f67967b99d67acdfa1712c293601', - 'abcdef', - ), - ), - ) -) -def test_data_registry_via_register_data(chain, - web3, - deploy_fbc, - fn_name, - fn_args): - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc( - client_contract, - target_block=web3.eth.blockNumber + 300, - ) - - call_data = client_contract._encode_transaction_data(fn_name, fn_args) - _, sig, _ = fbc._get_function_info('registerData') - - register_call_data_txn_hash = encode_hex( - decode_hex(sig) + decode_hex(call_data) - ) - - assert fbc.call().callData() == "" - - register_txn_hash = web3.eth.sendTransaction({ - 'to': fbc.address, - 'data': register_call_data_txn_hash, - }) - chain.wait.for_receipt(register_txn_hash) - - assert encode_hex(fbc.call().callData()) == call_data diff --git a/tests/data-registry/test_data_registry_via_fallback.py b/tests/data-registry/test_data_registry_via_fallback.py deleted file mode 100644 index c9a61acae..000000000 --- a/tests/data-registry/test_data_registry_via_fallback.py +++ /dev/null @@ -1,47 +0,0 @@ -import pytest - -from web3.utils.encoding import ( - encode_hex, -) - - -@pytest.mark.parametrize( - 'fn_name,fn_args', - ( - ('setInt', [-1234567890]), - ('setUInt', [1234567890123456789012345678901234567890]), - ('setAddress', ['0xd3cda913deb6f67967b99d67acdfa1712c293601']), - ('setBytes32', ['this is a bytes32 string']), - ('setBytes', ['this is a byte string that is longer than 32 bytes']), - ( - 'setMany', - ( - 1234567890, - -1234567890, - 987654321, - '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13', - '0xd3cda913deb6f67967b99d67acdfa1712c293601', - 'abcdef', - ), - ), - ) -) -def test_data_registry_via_fallback(chain, web3, deploy_fbc, fn_name, fn_args): - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc( - client_contract, - method_name=fn_name, - call_data="", - target_block=web3.eth.blockNumber + 300, - ) - - call_data = client_contract._encode_transaction_data(fn_name, fn_args) - - web3.eth.sendTransaction({ - 'to': fbc.address, - 'data': call_data, - }) - - # FROM: abi.encode_single(abi.process_type('int256'), value) - assert encode_hex(fbc.call().callData()) == call_data diff --git a/tests/data-registry/test_data_registry_via_scheduling.py b/tests/data-registry/test_data_registry_via_scheduling.py deleted file mode 100644 index 8bd152ffe..000000000 --- a/tests/data-registry/test_data_registry_via_scheduling.py +++ /dev/null @@ -1,51 +0,0 @@ -import pytest - -from web3.utils.encoding import ( - encode_hex, - decode_hex, -) - - -@pytest.mark.parametrize( - 'fn_name,fn_args', - ( - ('setInt', [-1234567890]), - ('setUInt', [2**255 - 1]), - ('setAddress', ['0xd3cda913deb6f67967b99d67acdfa1712c293601']), - ('setBytes32', ['this is a bytes32 string']), - ('setBytes', ['this is a byte string that is longer than 32 bytes']), - ( - 'setMany', - ( - 1234567890, - -1234567890, - 987654321, - '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13', - '0xd3cda913deb6f67967b99d67acdfa1712c293601', - 'abcdef', - ), - ), - ), -) -def test_data_registry_via_scheduling(chain, - web3, - get_scheduled_fbc, - denoms, - fn_name, - fn_args): - scheduler = chain.get_contract('Scheduler') - client_contract = chain.get_contract('TestCallExecution') - - _, sig, _ = client_contract._get_function_info(fn_name, fn_args) - call_data = client_contract.encodeABI(fn_name, fn_args) - - scheduling_txn_hash = scheduler.transact({ - 'value': 2 * denoms.ether, - }).scheduleCall( - abiSignature=decode_hex(sig), - callData=decode_hex(call_data), - ) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - - assert encode_hex(fbc.call().callData()) == call_data diff --git a/tests/execution/test_allowed_to_execute_if_claimer_does_not_call.py b/tests/execution/test_allowed_to_execute_if_claimer_does_not_call.py deleted file mode 100644 index 65370c5d4..000000000 --- a/tests/execution/test_allowed_to_execute_if_claimer_does_not_call.py +++ /dev/null @@ -1,34 +0,0 @@ -def test_cannot_execute_if_claimed_by_other(chain, web3, deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - - fbc = deploy_fbc( - client_contract, - method_name='setBool', - target_block=target_block, - ) - - chain.wait.for_block(target_block - 10 - 255) - - # claim it - claim_txn_h = fbc.transact({'value': 2 * fbc.call().basePayment()}).claim() - chain.wait.for_receipt(claim_txn_h) - - assert fbc.call().claimer() == web3.eth.coinbase - - chain.wait.for_block(target_block) - - assert fbc.call().wasCalled() is False - - not_allowed_txn_h = fbc.transact({'from': web3.eth.accounts[1]}).execute() - chain.wait.for_receipt(not_allowed_txn_h) - - assert fbc.call().wasCalled() is False - - chain.wait.for_block(target_block + 64) - - ffa_txn_h = fbc.transact({'from': web3.eth.accounts[1]}).execute() - chain.wait.for_receipt(ffa_txn_h) - - assert fbc.call().wasCalled() is True diff --git a/tests/execution/test_basic_call_execution.py b/tests/execution/test_basic_call_execution.py deleted file mode 100644 index 364509587..000000000 --- a/tests/execution/test_basic_call_execution.py +++ /dev/null @@ -1,103 +0,0 @@ -import pytest - -from web3.utils.string import force_text -from web3.utils.encoding import decode_hex - - -def test_execution_of_call_with_single_bool(chain, deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc(client_contract, method_name='setBool') - chain.wait.for_block(fbc.call().targetBlock()) - - assert client_contract.call().v_bool() is False - - call_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(call_txn_hash) - - assert client_contract.call().v_bool() is True - - -@pytest.mark.parametrize( - 'fn_name,fn_args,init_value,lookup_fn', - ( - ('setInt', [-1234567890], 0, 'v_int'), - ('setUInt', [1234567890], 0, 'v_uint'), - ( - 'setAddress', - ['0xd3cda913deb6f67967b99d67acdfa1712c293601'], - '0x0000000000000000000000000000000000000000', - 'v_address', - ), - ( - 'setBytes32', - [force_text(decode_hex('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'))], - force_text(decode_hex('00' * 32)), - 'v_bytes32', - ), - ( - 'setBytes', - ['abcdefg'], - '', - 'v_bytes', - ), - ), -) -def test_execution_of_call_with_args(chain, - deploy_fbc, - fn_name, - fn_args, - init_value, - lookup_fn): - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc( - client_contract, - method_name=fn_name, - arguments=fn_args, - ) - chain.wait.for_block(fbc.call().targetBlock()) - - assert getattr(client_contract.call(), lookup_fn)() == init_value - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert getattr(client_contract.call(), lookup_fn)() == fn_args[0] - - -def test_execution_of_call_with_many_values(chain, deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - values = ( - 1234567890, - -1234567890, - 987654321, - force_text(decode_hex('000102030405060708090a0b0c0d0e0f10111213')), - 'd3cda913deb6f67967b99d67acdfa1712c293601', - 'abcdefg', - ) - - fbc = deploy_fbc( - client_contract, - method_name='setMany', - arguments=values, - ) - chain.wait.for_block(fbc.call().targetBlock()) - - assert client_contract.call().vm_a() == 0 - assert client_contract.call().vm_b() == 0 - assert client_contract.call().vm_c() == 0 - assert client_contract.call().vm_d() == force_text(decode_hex('00' * 20)) - assert client_contract.call().vm_e() == '0x0000000000000000000000000000000000000000' - assert client_contract.call().vm_f() == '' - - call_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(call_txn_hash) - - assert client_contract.call().vm_a() == values[0] - assert client_contract.call().vm_b() == values[1] - assert client_contract.call().vm_c() == values[2] - assert client_contract.call().vm_d() == values[3] - assert client_contract.call().vm_e() == '0xd3cda913deb6f67967b99d67acdfa1712c293601' - assert client_contract.call().vm_f() == values[5] diff --git a/tests/execution/test_call_that_throws_exception.py b/tests/execution/test_call_that_throws_exception.py deleted file mode 100644 index cc72c7171..000000000 --- a/tests/execution/test_call_that_throws_exception.py +++ /dev/null @@ -1,23 +0,0 @@ -def test_execution_of_call_that_throws_exception(chain, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestErrors') - - fbc = deploy_fbc(client_contract, method_name='doFail') - - chain.wait.for_block(fbc.call().targetBlock()) - - assert client_contract.call().value() is False - - execute_txn_hash = fbc.transact().execute() - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - - assert client_contract.call().value() is False - - execute_filter = CallLib.pastEvents('CallExecuted', { - 'address': fbc.address, - 'fromBlock': execute_txn_receipt['blockNumber'], - 'toBlock': execute_txn_receipt['blockNumber'], - }) - execute_logs = execute_filter.get() - assert len(execute_logs) == 1 - execute_log_data = execute_logs[0] - assert execute_log_data['args']['success'] is False diff --git a/tests/execution/test_call_with_infinite_loop.py b/tests/execution/test_call_with_infinite_loop.py deleted file mode 100644 index d536a167e..000000000 --- a/tests/execution/test_call_with_infinite_loop.py +++ /dev/null @@ -1,23 +0,0 @@ -def test_execution_of_call_that_contains_infinite_loop(chain, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestErrors') - - fbc = deploy_fbc(client_contract, method_name='doInfinite') - - chain.wait.for_block(fbc.call().targetBlock()) - - assert client_contract.call().value() is False - - execute_txn_hash = fbc.transact().execute() - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - - assert client_contract.call().value() is False - - execute_filter = CallLib.pastEvents('CallExecuted', { - 'address': fbc.address, - 'fromBlock': execute_txn_receipt['blockNumber'], - 'toBlock': execute_txn_receipt['blockNumber'], - }) - execute_logs = execute_filter.get() - assert len(execute_logs) == 1 - execute_log_data = execute_logs[0] - assert execute_log_data['args']['success'] is False diff --git a/tests/execution/test_cannot_execute_after_call_window.py b/tests/execution/test_cannot_execute_after_call_window.py deleted file mode 100644 index 4aedb87d5..000000000 --- a/tests/execution/test_cannot_execute_after_call_window.py +++ /dev/null @@ -1,13 +0,0 @@ -def test_cannot_execute_after_call_window(chain, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc(client_contract, method_name='setBool') - - chain.wait.for_block(fbc.call().targetBlock() + fbc.call().gracePeriod() + 1) - - assert fbc.call().wasCalled() is False - - txn_h = fbc.transact({'gas': 2000000}).execute() - chain.wait.for_receipt(txn_h) - - assert fbc.call().wasCalled() is False diff --git a/tests/execution/test_cannot_execute_before_target_block.py b/tests/execution/test_cannot_execute_before_target_block.py deleted file mode 100644 index e8bea1d55..000000000 --- a/tests/execution/test_cannot_execute_before_target_block.py +++ /dev/null @@ -1,14 +0,0 @@ -def test_cannot_execute_before_target_block(chain, web3, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 20 - fbc = deploy_fbc(client_contract, target_block=target_block) - - chain.wait.for_block(target_block - 4) - - assert fbc.call().wasCalled() is False - - txn_h = fbc.transact().execute() - chain.wait.for_receipt(txn_h) - - assert fbc.call().wasCalled() is False diff --git a/tests/execution/test_cannot_execute_cancelled_call.py b/tests/execution/test_cannot_execute_cancelled_call.py deleted file mode 100644 index e794c339d..000000000 --- a/tests/execution/test_cannot_execute_cancelled_call.py +++ /dev/null @@ -1,22 +0,0 @@ -def test_cannot_execute_cancelled_call(chain, web3, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc(client_contract, target_block=target_block) - - assert fbc.call().isCancellable() is True - - # cancel it - cancel_txn_h = fbc.transact().cancel() - chain.wait.for_receipt(cancel_txn_h) - - assert fbc.call().isCancelled() is True - - chain.wait.for_block(target_block) - - assert fbc.call().wasCalled() is False - - txn_h = fbc.transact().execute() - chain.wait.for_receipt(txn_h) - - assert fbc.call().wasCalled() is False diff --git a/tests/execution/test_cannot_execute_if_claimed.py b/tests/execution/test_cannot_execute_if_claimed.py deleted file mode 100644 index 78ad81258..000000000 --- a/tests/execution/test_cannot_execute_if_claimed.py +++ /dev/null @@ -1,27 +0,0 @@ -def test_cannot_execute_if_claimed_by_other(chain, web3, deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 300 - fbc = deploy_fbc(client_contract, target_block=target_block) - - chain.wait.for_block(target_block - 10 - 255) - - # claim it - claim_txn_h = fbc.transact({'value': 2 * fbc.call().basePayment()}).claim() - chain.wait.for_receipt(claim_txn_h) - - assert fbc.call().claimer() == web3.eth.coinbase - - chain.wait.for_block(target_block) - - assert fbc.call().wasCalled() is False - - not_allowed_txn_h = fbc.transact({'from': web3.eth.accounts[1]}).execute() - chain.wait.for_receipt(not_allowed_txn_h) - - assert fbc.call().wasCalled() is False - - execute_txn_h = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_h) - - assert fbc.call().wasCalled() is True diff --git a/tests/execution/test_different_call_data_modes.py b/tests/execution/test_different_call_data_modes.py deleted file mode 100644 index 3928ffaba..000000000 --- a/tests/execution/test_different_call_data_modes.py +++ /dev/null @@ -1,75 +0,0 @@ -from web3.utils.encoding import decode_hex - - -def test_no_signature_or_calldata(chain, web3, deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - fbc = deploy_fbc(client_contract) - chain.wait.for_block(fbc.call().targetBlock()) - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().wasCalled() is True - assert fbc.call().wasSuccessful() is True - - -def test_only_signature(chain, deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - _, sig, _ = client_contract._get_function_info('setBool') - - fbc = deploy_fbc( - client_contract, - abi_signature=decode_hex(sig), - ) - chain.wait.for_block(fbc.call().targetBlock()) - - assert client_contract.call().v_bool() is False - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert client_contract.call().v_bool() is True - assert fbc.call().wasCalled() is True - assert fbc.call().wasSuccessful() is True - - -def test_only_call_data(chain, deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - call_data = client_contract._encode_transaction_data('setUInt', [12345]) - - fbc = deploy_fbc( - client_contract, - call_data=decode_hex(call_data), - ) - chain.wait.for_block(fbc.call().targetBlock()) - - assert client_contract.call().v_uint() == 0 - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert client_contract.call().v_uint() == 12345 - - -def test_both_signature_and_call_data(chain, deploy_fbc): - client_contract = chain.get_contract('TestCallExecution') - - _, sig, _ = client_contract._get_function_info('setUInt', [12345]) - call_data = client_contract.encodeABI('setUInt', [12345]) - - fbc = deploy_fbc( - client_contract, - call_data=decode_hex(call_data), - abi_signature=decode_hex(sig), - ) - chain.wait.for_block(fbc.call().targetBlock()) - - assert client_contract.call().v_uint() == 0 - - execute_txn_hash = fbc.transact().execute() - chain.wait.for_receipt(execute_txn_hash) - - assert client_contract.call().v_uint() == 12345 diff --git a/tests/execution/test_minimum_call_gas_cost.py b/tests/execution/test_minimum_call_gas_cost.py deleted file mode 100644 index b86275da6..000000000 --- a/tests/execution/test_minimum_call_gas_cost.py +++ /dev/null @@ -1,45 +0,0 @@ -from web3.utils.encoding import decode_hex - - -MEASURED_VALUE = 95000 - - -def test_minimum_call_gas(chain, web3, denoms, get_scheduled_fbc): - client_contract = chain.get_contract('TestCallExecution') - scheduler = chain.get_contract('Scheduler') - - target_block = web3.eth.blockNumber + 300 - - _, sig, _ = client_contract._get_function_info('setBool') - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - contractAddress=client_contract.address, - abiSignature=decode_hex(sig), - targetBlock=target_block, - ) - chain.wait.for_receipt(scheduling_txn_hash) - fbc = get_scheduled_fbc(scheduling_txn_hash) - - chain.wait.for_block(fbc.call().firstClaimBlock() + 250) - - claim_txn_hash = fbc.transact({'value': 10 * denoms.ether}).claim() - chain.wait.for_receipt(claim_txn_hash) - - chain.wait.for_block(fbc.call().targetBlock()) - - assert fbc.call().claimer() == web3.eth.coinbase - assert client_contract.call().v_bool() is False - - execute_txn_hash = fbc.transact().execute() - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().wasCalled() is True - assert fbc.call().wasSuccessful() is True - - actual = execute_txn_receipt['gasUsed'] - - assert actual < MEASURED_VALUE - assert MEASURED_VALUE - actual < 10000 - assert actual * 2 < scheduler.call().getMinimumCallGas() diff --git a/tests/execution/test_stack_depth_attack.py b/tests/execution/test_stack_depth_attack.py deleted file mode 100644 index 90d7d0305..000000000 --- a/tests/execution/test_stack_depth_attack.py +++ /dev/null @@ -1,38 +0,0 @@ -def test_stack_depth_does_not_call_if_cannot_reach_depth(chain, web3, deploy_fbc, CallLib): - client_contract = chain.get_contract('TestErrors') - - fbc = deploy_fbc( - client_contract, - method_name='doStackExtension', - arguments=[340], - require_depth=1000, - ) - assert fbc.call().requiredStackDepth() == 1000 - - set_txn_hash = client_contract.transact().setCallAddress(fbc.address) - chain.wait.for_receipt(set_txn_hash) - - chain.wait.for_block(fbc.call().targetBlock()) - - assert client_contract.call().value() is False - - # Call such that the stack has been "significantly" extended prior to - # executing the call. - bad_call_txn_hash = client_contract.transact().proxyCall(1000) - chain.wait.for_receipt(bad_call_txn_hash) - - assert fbc.call().wasCalled() is False - assert client_contract.call().value() is False - - abort_filter = CallLib.pastEvents('CallAborted', {'address': fbc.address}) - abort_logs = abort_filter.get() - assert len(abort_logs) == 1 - abort_log_data = abort_logs[0] - reason = abort_log_data['args']['reason'].replace('\x00', '') - assert reason == 'STACK_TOO_DEEP' - - execute_txn_hash = client_contract.transact().proxyCall(0) - chain.wait.for_receipt(execute_txn_hash) - - assert fbc.call().wasCalled() is True - assert client_contract.call().value() is True diff --git a/tests/execution/test_stack_depth_limits.py b/tests/execution/test_stack_depth_limits.py deleted file mode 100644 index aa6f3dc2e..000000000 --- a/tests/execution/test_stack_depth_limits.py +++ /dev/null @@ -1,66 +0,0 @@ -MAX_DEPTH = 2048 - -OUTER_MAX = 1021 -CHECK_MAX = 1021 -INNER_MAX = 1021 - - -def test_stack_depth_checking(chain, web3, deploy_fbc, CallLib): - """ - This function is useful for finding out what the limits are for stack depth - protection. - """ - client_contract = chain.get_contract('TestErrors') - - def deploy_call(depth_check, depth_inner): - _fbc = deploy_fbc( - client_contract, - method_name='doStackExtension', - arguments=[depth_inner], - require_depth=depth_check, - ) - chain.wait.for_receipt(client_contract.transact().reset()) - chain.wait.for_receipt(client_contract.transact().setCallAddress(_fbc.address)) - chain.wait.for_block(_fbc.call().targetBlock()) - return _fbc - - def check(_fbc, depth_outer): - assert client_contract.call().value() is False - - call_txn_hash = client_contract.transact().proxyCall(depth_outer) - chain.wait.for_receipt(call_txn_hash) - - is_successful = _fbc.call().wasCalled() and client_contract.call().value() is True - return is_successful - - def find_maxima(attr, **defaults): - left = 0 - right = MAX_DEPTH - - while left < right: - depth = (left + right) // 2 - defaults[attr] = depth - fbc = deploy_call(defaults['depth_check'], defaults['depth_inner']) - - if check(fbc, defaults['depth_outer']): - if left == depth: - break - left = depth - else: - if right == depth: - break - right = depth - - assert depth != 0 and depth != MAX_DEPTH - return depth - - outer_max = find_maxima('depth_outer', depth_check=0, depth_inner=0) - print("outer max", outer_max) - check_max = find_maxima('depth_check', depth_outer=0, depth_inner=0) - print("check max", check_max) - inner_max = find_maxima('depth_inner', depth_outer=0, depth_check=0) - print("inner max", inner_max) - - assert outer_max == OUTER_MAX - assert check_max == CHECK_MAX - assert inner_max == INNER_MAX diff --git a/tests/request-factory/test_request_factory.py b/tests/request-factory/test_request_factory.py new file mode 100644 index 000000000..1c1bf4ab8 --- /dev/null +++ b/tests/request-factory/test_request_factory.py @@ -0,0 +1,58 @@ +def test_request_factory_creates_request_with_provided_properties(chain, + web3, + denoms, + request_factory, + RequestData, + get_txn_request): + import time + start_at = time.time() + print("In Test") + window_start = web3.eth.blockNumber + 20 + + expected_request_data = RequestData( + claimWindowSize=255, + donation=12345, + payment=54321, + freezePeriod=10, + windowStart=window_start, + windowSize=255, + reservedWindowSize=16, + temporalUnit=1, + callValue=123456789, + callGas=1000000, + requiredStackDepth=0 + ) + txn_request = expected_request_data.deploy_via_factory() + + actual_request_data = RequestData.from_contract(txn_request) + + assert actual_request_data.meta.owner == web3.eth.coinbase + assert actual_request_data.meta.createdBy == web3.eth.coinbase + assert actual_request_data.meta.isCancelled is False + assert actual_request_data.meta.wasCalled is False + assert actual_request_data.meta.wasSuccessful is False + + assert actual_request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' + assert actual_request_data.claimData.claimDeposit == 0 + assert actual_request_data.claimData.paymentModifier == 0 + + assert actual_request_data.paymentData.donation == 12345 + assert actual_request_data.paymentData.donationBenefactor == '0xd3cda913deb6f67967b99d67acdfa1712c293601' + assert actual_request_data.paymentData.donationOwed == 0 + assert actual_request_data.paymentData.payment == 54321 + assert actual_request_data.paymentData.paymentBenefactor == '0x0000000000000000000000000000000000000000' + assert actual_request_data.paymentData.paymentOwed == 0 + + assert actual_request_data.schedule.claimWindowSize == 255 + assert actual_request_data.schedule.freezePeriod == 10 + assert actual_request_data.schedule.windowStart == window_start + assert actual_request_data.schedule.windowSize == 255 + assert actual_request_data.schedule.reservedWindowSize == 16 + assert actual_request_data.schedule.temporalUnit == 1 + + assert actual_request_data.txnData.callData == '' + assert actual_request_data.txnData.callValue == 123456789 + assert actual_request_data.txnData.callGas == 1000000 + assert actual_request_data.txnData.requiredStackDepth == 0 + + print("End test:", time.time() - start_at) diff --git a/tests/request-tracker/test_request_tracker.py b/tests/request-tracker/test_request_tracker.py new file mode 100644 index 000000000..f0ad58d7e --- /dev/null +++ b/tests/request-tracker/test_request_tracker.py @@ -0,0 +1,49 @@ +def test_request_tracker(chain, web3, request_tracker): + factory_address = web3.eth.coinbase + + values = [ + ('0x0000000000000000000000000000000000000001', 2), + ('0x0000000000000000000000000000000000000002', 1), + ('0x0000000000000000000000000000000000000003', 4), + ('0x0000000000000000000000000000000000000004', 10), + ('0x0000000000000000000000000000000000000005', 10), + ('0x0000000000000000000000000000000000000006', 3), + ('0x0000000000000000000000000000000000000007', 2), + ('0x0000000000000000000000000000000000000008', 8), + ('0x0000000000000000000000000000000000000009', 3), + ('0x0000000000000000000000000000000000000010', 4), + ('0x0000000000000000000000000000000000000011', 0), + ('0x0000000000000000000000000000000000000012', 2), + ] + window_start_lookup = dict(values) + + expected_order = [ + '0x0000000000000000000000000000000000000011', + '0x0000000000000000000000000000000000000002', + '0x0000000000000000000000000000000000000001', + '0x0000000000000000000000000000000000000007', + '0x0000000000000000000000000000000000000012', + '0x0000000000000000000000000000000000000006', + '0x0000000000000000000000000000000000000009', + '0x0000000000000000000000000000000000000003', + '0x0000000000000000000000000000000000000010', + '0x0000000000000000000000000000000000000008', + '0x0000000000000000000000000000000000000004', + '0x0000000000000000000000000000000000000005', + ] + + for request_address, window_start in values: + add_txn_hash = request_tracker.transact().addRequest(request_address, window_start) + chain.wait.for_receipt(add_txn_hash) + + assert request_tracker.call().query(factory_address, '>=', 0) == expected_order[0] + assert request_tracker.call().query(factory_address, '<=', 20) == expected_order[-1] + + for idx, request_address in enumerate(expected_order): + assert request_tracker.call().isKnownRequest(factory_address, request_address) is True + assert request_tracker.call().getWindowStart(factory_address, request_address) == window_start_lookup[request_address] + + if idx > 0: + assert request_tracker.call().getPreviousRequest(factory_address, request_address) == expected_order[idx - 1] + if idx < len(expected_order) - 1: + assert request_tracker.call().getNextRequest(factory_address, request_address) == expected_order[idx + 1] diff --git a/tests/scheduling/test_basic_scheduling.py b/tests/scheduling/test_basic_scheduling.py deleted file mode 100644 index 4c289367e..000000000 --- a/tests/scheduling/test_basic_scheduling.py +++ /dev/null @@ -1,51 +0,0 @@ -from web3.utils.string import ( - force_text, -) -from web3.utils.encoding import ( - decode_hex, -) - - -def test_basic_call_scheduling(chain, web3, get_scheduled_fbc, denoms): - scheduler = chain.get_contract('Scheduler') - client_contract = chain.get_contract('TestCallExecution') - - target_block = web3.eth.blockNumber + 255 + 10 + 40 - - _, sig, _ = client_contract._get_function_info('setBytes', ['some-byte-string']) - call_data = client_contract.encodeABI('setBytes', ['some-byte-string']) - - base_payment = scheduler.call().defaultPayment() - default_payment = scheduler.call().defaultPayment() // 100 - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - contractAddress=client_contract.address, - abiSignature=decode_hex(sig), - callData=decode_hex(call_data), - targetBlock=target_block, - ) - scheduling_txn = web3.eth.getTransaction(scheduling_txn_hash) - chain.wait.for_receipt(scheduling_txn_hash) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - - # Sanity check for all of the queriable call values. - assert fbc.call().targetBlock() == target_block - assert fbc.call().gracePeriod() == 255 - assert fbc.call().requiredGas() == 200000 - assert fbc.call().callValue() == 0 - assert fbc.call().basePayment() == base_payment - assert fbc.call().baseDonation() == default_payment - assert fbc.call().schedulerAddress() == web3.eth.coinbase - assert fbc.call().contractAddress() == client_contract.address - assert fbc.call().abiSignature() == force_text(decode_hex(sig)) - assert fbc.call().callData() == force_text(decode_hex(call_data)) - assert fbc.call().anchorGasPrice() == scheduling_txn['gasPrice'] - assert fbc.call().claimer() == "0x0000000000000000000000000000000000000000" - assert fbc.call().claimAmount() == 0 - assert fbc.call().claimerDeposit() == 0 - assert fbc.call().wasSuccessful() is False - assert fbc.call().wasCalled() is False - assert fbc.call().isCancelled() is False diff --git a/tests/scheduling/test_cannot_schedule_too_soon.py b/tests/scheduling/test_cannot_schedule_too_soon.py deleted file mode 100644 index af478fcc9..000000000 --- a/tests/scheduling/test_cannot_schedule_too_soon.py +++ /dev/null @@ -1,16 +0,0 @@ -def test_cannot_schedule_too_soon(chain, denoms, SchedulerLib): - scheduler = chain.get_contract('Scheduler') - - scheduler_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - targetBlock=scheduler.call().getFirstSchedulableBlock() - 1, - ) - chain.wait.for_receipt(scheduler_txn_hash) - - schedule_filter = SchedulerLib.pastEvents('CallRejected', {'address': scheduler.address}) - schedule_logs = schedule_filter.get() - assert len(schedule_logs) == 1 - schedule_log_data = schedule_logs[0] - reason = schedule_log_data['args']['reason'].replace('\x00', '') - assert reason == 'TOO_SOON' diff --git a/tests/scheduling/test_endowment_enforcement.py b/tests/scheduling/test_endowment_enforcement.py deleted file mode 100644 index 72406b102..000000000 --- a/tests/scheduling/test_endowment_enforcement.py +++ /dev/null @@ -1,113 +0,0 @@ -def test_call_rejected_for_insufficient_endowment(chain, web3, denoms, SchedulerLib): - scheduler = chain.get_contract('Scheduler') - - target_block = web3.eth.blockNumber + 300 - - payment = scheduler.call().defaultPayment() - donation = scheduler.call().getDefaultDonation() - - required_gas = 1234567 - - call_value = 5 * denoms.ether - - # 1 wei short - endowment = ( - call_value + - 2 * (payment + donation) + - required_gas * web3.eth.gasPrice - ) - 1 - required_endowment = scheduler.call().getMinimumEndowment( - basePayment=payment, - baseDonation=donation, - callValue=call_value, - requiredGas=required_gas, - ) - - assert endowment == required_endowment - 1 - - failed_scheduling_txn_hash = scheduler.transact({ - 'value': endowment, - }).scheduleCall( - abiSignature="1234", - callData="", - requiredStackDepth=10, - gracePeriod=255, - callValue=call_value, - targetBlock=target_block, - requiredGas=required_gas, - basePayment=payment, - baseDonation=donation, - ) - failed_scheduling_txn_receipt = chain.wait.for_receipt(failed_scheduling_txn_hash) - - schedule_filter = SchedulerLib.pastEvents('CallRejected', { - 'address': scheduler.address, - 'fromBlock': failed_scheduling_txn_receipt['blockNumber'], - 'toBlock': failed_scheduling_txn_receipt['blockNumber'], - }) - schedule_logs = schedule_filter.get() - assert len(schedule_logs) == 1 - schedule_log_data = schedule_logs[0] - reason = schedule_log_data['args']['reason'].replace('\x00', '') - assert reason == 'INSUFFICIENT_FUNDS' - - -def test_call_accepted_for_sufficient_endowment(chain, - web3, - denoms, - SchedulerLib, - get_scheduled_fbc): - scheduler = chain.get_contract('Scheduler') - - target_block = web3.eth.blockNumber + 300 - - payment = scheduler.call().defaultPayment() - donation = scheduler.call().getDefaultDonation() - - required_gas = 1234567 - - call_value = 5 * denoms.ether - - # 1 wei short - endowment = ( - call_value + - 2 * (payment + donation) + - required_gas * web3.eth.gasPrice - ) - required_endowment = scheduler.call().getMinimumEndowment( - basePayment=payment, - baseDonation=donation, - callValue=call_value, - requiredGas=required_gas, - ) - - assert endowment == required_endowment - - scheduling_txn_hash = scheduler.transact({ - 'value': endowment, - }).scheduleCall( - abiSignature="1234", - callData="", - requiredStackDepth=10, - gracePeriod=255, - callValue=call_value, - targetBlock=target_block, - requiredGas=required_gas, - basePayment=payment, - baseDonation=donation, - ) - scheduling_txn_receipt = chain.wait.for_receipt(scheduling_txn_hash) - - schedule_filter = SchedulerLib.pastEvents('CallRejected', { - 'address': scheduler.address, - 'fromBlock': scheduling_txn_receipt['blockNumber'], - 'toBlock': scheduling_txn_receipt['blockNumber'], - }) - schedule_logs = schedule_filter.get() - assert len(schedule_logs) == 0 - - fbc = get_scheduled_fbc(scheduling_txn_hash) - assert fbc.call().callValue() == call_value - assert fbc.call().basePayment() == payment - assert fbc.call().baseDonation() == donation - assert fbc.call().requiredGas() == required_gas diff --git a/tests/scheduling/test_gas_limits_enforced.py b/tests/scheduling/test_gas_limits_enforced.py deleted file mode 100644 index 4f345cda7..000000000 --- a/tests/scheduling/test_gas_limits_enforced.py +++ /dev/null @@ -1,95 +0,0 @@ -def test_call_accepted_with_minimum_gas_value(chain, denoms, web3, - SchedulerLib, get_scheduled_fbc): - scheduler = chain.get_contract('Scheduler') - - target_block = web3.eth.blockNumber + 300 - - minimum_gas = scheduler.call().getMinimumCallGas() - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - targetBlock=target_block, - requiredGas=minimum_gas, - ) - chain.wait.for_receipt(scheduling_txn_hash) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - assert fbc.call().requiredGas() == minimum_gas - - -def test_call_rejected_below_minimum_gas_value(chain, denoms, web3, SchedulerLib): - scheduler = chain.get_contract('Scheduler') - - target_block = web3.eth.blockNumber + 300 - - minimum_gas = scheduler.call().getMinimumCallGas() - - failed_scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - targetBlock=target_block, - requiredGas=minimum_gas - 1, - ) - failed_scheduling_txn_receipt = chain.wait.for_receipt(failed_scheduling_txn_hash) - - schedule_filter = SchedulerLib.pastEvents('CallRejected', { - 'address': scheduler.address, - 'fromBlock': failed_scheduling_txn_receipt['blockNumber'], - 'toBlock': failed_scheduling_txn_receipt['blockNumber'], - }) - schedule_logs = schedule_filter.get() - assert len(schedule_logs) == 1 - schedule_log_data = schedule_logs[0] - reason = schedule_log_data['args']['reason'].replace('\x00', '') - assert reason == 'REQUIRED_GAS_OUT_OF_RANGE' - - -def test_call_accepted_at_maximum_gas(chain, denoms, web3, SchedulerLib, get_scheduled_fbc): - scheduler = chain.get_contract('Scheduler') - - target_block = web3.eth.blockNumber + 300 - - max_allowed_gas = scheduler.call().getMaximumCallGas() - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - targetBlock=target_block, - requiredGas=max_allowed_gas, - ) - chain.wait.for_receipt(scheduling_txn_hash) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - assert fbc.call().requiredGas() == max_allowed_gas - - -def test_call_rejected_above_maximum_gas(chain, denoms, web3, SchedulerLib): - scheduler = chain.get_contract('Scheduler') - - target_block = web3.eth.blockNumber + 300 - - max_allowed_gas = scheduler.call().getMaximumCallGas() - - failed_scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - targetBlock=target_block, - requiredGas=max_allowed_gas + 1, - ) - failed_scheduling_txn_receipt = chain.wait.for_receipt(failed_scheduling_txn_hash) - - schedule_filter = SchedulerLib.pastEvents('CallRejected', { - 'address': scheduler.address, - 'fromBlock': failed_scheduling_txn_receipt['blockNumber'], - 'toBlock': failed_scheduling_txn_receipt['blockNumber'], - }) - schedule_logs = schedule_filter.get() - assert len(schedule_logs) == 1 - schedule_log_data = schedule_logs[0] - reason = schedule_log_data['args']['reason'].replace('\x00', '') - assert reason == 'REQUIRED_GAS_OUT_OF_RANGE' diff --git a/tests/scheduling/test_minimum_grace_period_enforced.py b/tests/scheduling/test_minimum_grace_period_enforced.py deleted file mode 100644 index 48b5ac0bc..000000000 --- a/tests/scheduling/test_minimum_grace_period_enforced.py +++ /dev/null @@ -1,44 +0,0 @@ -def test_cannot_schedule_with_too_small_grace_perioud(chain, web3, denoms, SchedulerLib): - scheduler = chain.get_contract('Scheduler') - - minimum_grace_period = scheduler.call().getMinimumGracePeriod() - - failed_scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - targetBlock=web3.eth.blockNumber + 300, - requiredGas=1000000, - gracePeriod=minimum_grace_period - 1, - ) - failed_scheduling_txn_receipt = chain.wait.for_receipt(failed_scheduling_txn_hash) - - schedule_filter = SchedulerLib.pastEvents('CallRejected', { - 'address': scheduler.address, - 'fromBlock': failed_scheduling_txn_receipt['blockNumber'], - 'toBlock': failed_scheduling_txn_receipt['blockNumber'], - }) - schedule_logs = schedule_filter.get() - assert len(schedule_logs) == 1 - schedule_log_data = schedule_logs[0] - reason = schedule_log_data['args']['reason'].replace('\x00', '') - assert reason == 'GRACE_TOO_SHORT' - - -def test_schedule_accepted_with_minimum_grace_period(chain, web3, denoms, get_scheduled_fbc): - scheduler = chain.get_contract('Scheduler') - - minimum_grace_period = scheduler.call().getMinimumGracePeriod() - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - targetBlock=web3.eth.blockNumber + 300, - requiredGas=1000000, - gracePeriod=minimum_grace_period, - ) - chain.wait.for_receipt(scheduling_txn_hash) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - assert fbc.call().gracePeriod() == minimum_grace_period diff --git a/tests/scheduling/test_scheduling_cost.py b/tests/scheduling/test_scheduling_cost.py deleted file mode 100644 index b1a8c89a9..000000000 --- a/tests/scheduling/test_scheduling_cost.py +++ /dev/null @@ -1,43 +0,0 @@ -SCHEDULING_COSTS_MIN = 1160000 -SCHEDULING_COSTS_MAX = 1160000 - -DELTA = 10000 - - -def test_cost_of_scheduling_no_args(chain, denoms, get_scheduled_fbc): - scheduler = chain.get_contract('Scheduler') - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall() - scheduling_txn_receipt = chain.wait.for_receipt(scheduling_txn_hash) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - assert fbc.address - - gas_actual = scheduling_txn_receipt['gasUsed'] - assert abs(gas_actual - SCHEDULING_COSTS_MIN) < DELTA - - -def test_cost_of_scheduling_all_args(chain, web3, denoms, get_scheduled_fbc): - scheduler = chain.get_contract('Scheduler') - - target_block = web3.eth.blockNumber + 300 - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - contractAddress=web3.eth.coinbase, - abiSignature='1234', - callData="", - requiredStackDepth=1000, - gracePeriod=255, - args=[0, target_block, 300000, 12345, 54321], - ) - scheduling_txn_receipt = chain.wait.for_receipt(scheduling_txn_hash) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - assert fbc.address - - gas_actual = scheduling_txn_receipt['gasUsed'] - assert abs(gas_actual - SCHEDULING_COSTS_MAX) < DELTA diff --git a/tests/scheduling/test_stack_check_limits_enforced.py b/tests/scheduling/test_stack_check_limits_enforced.py deleted file mode 100644 index c0ffbb93f..000000000 --- a/tests/scheduling/test_stack_check_limits_enforced.py +++ /dev/null @@ -1,111 +0,0 @@ -def test_call_rejected_for_too_low_stack_depth_check(chain, web3, denoms, SchedulerLib): - scheduler = chain.get_contract('Scheduler') - - minimum_allowed_stack_depth = scheduler.call().getMinimumStackCheck() - - failed_scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - callData='', - requiredStackDepth=minimum_allowed_stack_depth - 1, - gracePeriod=255, - callValue=0, - targetBlock=web3.eth.blockNumber + 300, - requiredGas=1000000, - basePayment=12345, - baseDonation=54321, - ) - failed_scheduling_txn_receipt = chain.wait.for_receipt(failed_scheduling_txn_hash) - - schedule_filter = SchedulerLib.pastEvents('CallRejected', { - 'address': scheduler.address, - 'fromBlock': failed_scheduling_txn_receipt['blockNumber'], - 'toBlock': failed_scheduling_txn_receipt['blockNumber'], - }) - schedule_logs = schedule_filter.get() - assert len(schedule_logs) == 1 - schedule_log_data = schedule_logs[0] - reason = schedule_log_data['args']['reason'].replace('\x00', '') - assert reason == 'STACK_CHECK_OUT_OF_RANGE' - - -def test_call_accepted_for_at_minimum_stack_depth_check(chain, web3, denoms, - get_scheduled_fbc): - scheduler = chain.get_contract('Scheduler') - - minimum_allowed_stack_depth = scheduler.call().getMinimumStackCheck() - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - callData='', - requiredStackDepth=minimum_allowed_stack_depth, - gracePeriod=255, - callValue=0, - targetBlock=web3.eth.blockNumber + 300, - requiredGas=1000000, - basePayment=12345, - baseDonation=54321, - ) - chain.wait.for_receipt(scheduling_txn_hash) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - assert fbc.call().requiredStackDepth() == minimum_allowed_stack_depth - - -def test_call_rejected_for_too_high_stack_depth_check(chain, web3, denoms, SchedulerLib): - scheduler = chain.get_contract('Scheduler') - - maximum_allowed_stack_depth = scheduler.call().getMaximumStackCheck() - - failed_scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - callData='', - requiredStackDepth=maximum_allowed_stack_depth + 1, - gracePeriod=255, - callValue=0, - targetBlock=web3.eth.blockNumber + 300, - requiredGas=1000000, - basePayment=12345, - baseDonation=54321, - ) - failed_scheduling_txn_receipt = chain.wait.for_receipt(failed_scheduling_txn_hash) - - schedule_filter = SchedulerLib.pastEvents('CallRejected', { - 'address': scheduler.address, - 'fromBlock': failed_scheduling_txn_receipt['blockNumber'], - 'toBlock': failed_scheduling_txn_receipt['blockNumber'], - }) - schedule_logs = schedule_filter.get() - assert len(schedule_logs) == 1 - schedule_log_data = schedule_logs[0] - reason = schedule_log_data['args']['reason'].replace('\x00', '') - assert reason == 'STACK_CHECK_OUT_OF_RANGE' - - -def test_call_accepted_for_maximum_stack_depth_check(chain, web3, denoms, get_scheduled_fbc): - scheduler = chain.get_contract('Scheduler') - - maximum_allowed_stack_depth = scheduler.call().getMaximumStackCheck() - - scheduling_txn_hash = scheduler.transact({ - 'value': 10 * denoms.ether, - }).scheduleCall( - abiSignature='1234', - callData='', - requiredStackDepth=maximum_allowed_stack_depth, - gracePeriod=255, - callValue=0, - targetBlock=web3.eth.blockNumber + 300, - requiredGas=1000000, - basePayment=12345, - baseDonation=54321, - ) - chain.wait.for_receipt(scheduling_txn_hash) - - fbc = get_scheduled_fbc(scheduling_txn_hash) - assert fbc.call().requiredStackDepth() == maximum_allowed_stack_depth diff --git a/tests/transaction-request/test_donation.py b/tests/transaction-request/test_donation.py new file mode 100644 index 000000000..75dcd98d1 --- /dev/null +++ b/tests/transaction-request/test_donation.py @@ -0,0 +1,32 @@ +def test_txn_request_payments(chain, + web3, + get_execute_data, + RequestData): + txn_request = RequestData(donation=12345).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + before_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) + + chain.wait.for_block(request_data.schedule.windowStart) + + execute_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).execute() + execute_txn = web3.eth.getTransaction(execute_txn_hash) + execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) + + execute_data = get_execute_data(execute_txn_hash) + + after_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) + + donation = execute_data['args']['donation'] + assert donation == 12345 + assert after_donation_balance - before_donation_balance == donation + + payment = execute_data['args']['payment'] + + gas_price = execute_txn['gasPrice'] + gas_used = execute_txn_receipt['gasUsed'] + gas_cost = gas_used * gas_price + + expected_payment = gas_cost + request_data.paymentData.payment + + assert payment >= expected_payment diff --git a/tests/transaction-request/test_request_factory.py b/tests/transaction-request/test_request_factory.py deleted file mode 100644 index 752ba270f..000000000 --- a/tests/transaction-request/test_request_factory.py +++ /dev/null @@ -1,60 +0,0 @@ -def test_request_factory(chain, web3, denoms): - factory = chain.get_contract('RequestFactory') - Request = chain.get_contract_factory('TransactionRequest') - RequestLib = chain.get_contract_factory('RequestLib') - - chain_code = web3.eth.getCode(factory.address) - assert len(chain_code) > 10 - - window_start = web3.eth.blockNumber + 20 - - create_txn_hash = factory.transact({ - 'value': 10 * denoms.ether, - }).createRequest( - addressArgs=[ - '0xd3cda913deb6f67967b99d67acdfa1712c293601', - web3.eth.coinbase, - ], - uintArgs=[ - 255, # claimWindowSize - 12345, # donation - 54321, # payment - 10, # freezePeriod - 16, # reservedWindowSize - 1, # temporalUnit (blocks) - window_start, # windowStart - 255, # windowSize - 1000000, # callGas - 123456789, # callValue - 0, # requiredStackDepth - ], - callData='', - ) - create_txn_receipt = chain.wait.for_receipt(create_txn_hash) - - request_created_filter = factory.pastEvents('RequestCreated') - request_created_logs = request_created_filter.get() - assert len(request_created_logs) == 1 - - log_data = request_created_logs[0] - - request_address = log_data['args']['request'] - request = Request(address=request_address) - - chain.wait.for_block(window_start) - - #request_data = request.call().requestData() - #request_call_data = request.call().callData() - - execute_txn_hash = request.transact({'gas': 3000000}).execute() - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - - execute_filter = RequestLib.pastEvents('Executed', { - 'address': request.address, - }) - execute_logs = execute_filter.get() - assert len(execute_logs) == 1 - execute_data = execute_logs[0] - - benefactor_balance = web3.eth.getBalance('0xd3cda913deb6f67967b99d67acdfa1712c293601') - assert False From b9310c73e921ea36efe8b6cf715be0e46f1011c0 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Fri, 16 Sep 2016 23:01:45 -0600 Subject: [PATCH 06/25] dirty --- contracts/MathLib.sol | 11 ++ contracts/PaymentLib.sol | 17 +- contracts/RequestLib.sol | 58 ++++--- contracts/SafeSendLib.sol | 2 +- tests/TestErrors.sol | 19 +++ tests/conftest.py | 155 +++++++----------- tests/request-factory/test_request_factory.py | 5 - tests/transaction-request/test_accounting.py | 32 ++++ tests/transaction-request/test_donation.py | 6 + tests/transaction-request/test_exceptions.py | 69 ++++++++ 10 files changed, 242 insertions(+), 132 deletions(-) create mode 100644 tests/TestErrors.sol create mode 100644 tests/transaction-request/test_accounting.py create mode 100644 tests/transaction-request/test_exceptions.py diff --git a/contracts/MathLib.sol b/contracts/MathLib.sol index 14325b985..f19b04358 100644 --- a/contracts/MathLib.sol +++ b/contracts/MathLib.sol @@ -51,6 +51,17 @@ library MathLib { } } + /* + * Return the larger of a or b. Returns a if a == b. + */ + function min(uint a, uint b) returns (uint) { + if (a <= b) { + return a; + } else { + return b; + } + } + /* * Returns a represented as a signed integer in a manner that throw an * exception if casting to signed integer would result in a negative diff --git a/contracts/PaymentLib.sol b/contracts/PaymentLib.sol index 5a4fdd643..ba478cd49 100644 --- a/contracts/PaymentLib.sol +++ b/contracts/PaymentLib.sol @@ -55,14 +55,20 @@ library PaymentLib { * caller. */ function getMultiplier(PaymentData storage self) returns (uint) { + //if (gas_price > base_gas_price) { + // return 100 * base_gas_price / gas_price; + //} + //else { + // return 200 - 100 * base_gas_price / (2 * base_gas_price - gas_price); + //} + if (tx.gasprice > self.anchorGasPrice) { return self.anchorGasPrice.safeMultiply(100) / tx.gasprice; } else { - return 200 - ( - self.anchorGasPrice.safeMultiply(100) / + return 200 - (self.anchorGasPrice.safeMultiply(100) / self.anchorGasPrice.safeMultiply(2).flooredSub(tx.gasprice) - ).max(200); + ).min(200); } } @@ -70,14 +76,15 @@ library PaymentLib { * Computes the amount to send to the donationBenefactor */ function getDonation(PaymentData storage self) returns (uint) { - return self.donation * getMultiplier(self) / 100; + if (getMultiplier(self) == 0) throw; + return self.donation.safeMultiply(getMultiplier(self)) / 100; } /* * Computes the amount to send to the address that fulfilled the request */ function getPayment(PaymentData storage self) returns (uint) { - return self.payment * getMultiplier(self) / 100; + return self.payment.safeMultiply(getMultiplier(self)) / 100; } /* diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index 904b62cac..d16bdd7b5 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -26,19 +26,6 @@ library RequestLib { RequestScheduleLib.ExecutionWindow schedule; } - enum Reason { - WasCancelled, - AlreadyCalled, - BeforeCallWindow, - AfterCallWindow, - ReservedForClaimer, - StackTooDeep, - InsufficientGas - } - - event Aborted(Reason reason); - event Executed(uint payment, uint donation, uint measuredGasConsumption); - /* * Initialize a new Request. */ @@ -169,8 +156,8 @@ library RequestLib { self.claimData.claimDeposit = uintValues[0]; self.paymentData.anchorGasPrice = uintValues[1]; self.paymentData.donation = uintValues[2]; - self.paymentData.payment = uintValues[3]; - self.paymentData.donationOwed = uintValues[4]; + self.paymentData.donationOwed = uintValues[3]; + self.paymentData.payment = uintValues[4]; self.paymentData.paymentOwed = uintValues[5]; self.schedule.claimWindowSize = uintValues[6]; self.schedule.freezePeriod = uintValues[7]; @@ -248,6 +235,19 @@ library RequestLib { return errors; } + enum Reason { + WasCancelled, + AlreadyCalled, + BeforeCallWindow, + AfterCallWindow, + ReservedForClaimer, + StackTooDeep, + InsufficientGas + } + + event Aborted(Reason reason); + event Executed(uint payment, uint donation, uint measuredGasConsumption); + function execute(Request storage self) returns (bool) { /* * Send the requested transaction. @@ -304,8 +304,7 @@ library RequestLib { // Send the transaction self.meta.wasSuccessful = self.txnData.sendTransaction(); - // Report execution back to the origin address. - self.meta.reportExecution(_GAS_TO_COMPLETE_EXECUTION); + if (self.paymentData.getDonation() == 0) throw; // Compute the donation amount if (self.paymentData.hasBenefactor()) { @@ -320,13 +319,21 @@ library RequestLib { // need to zero out the claim deposit since it is now accounted for // in the paymentOwed value. self.claimData.claimDeposit = 0; - self.paymentData.paymentOwed = self.paymentData.getPaymentWithModifier(self.claimData.paymentModifier).safeAdd(self.paymentData.paymentOwed); + self.paymentData.paymentOwed = self.paymentData.getPaymentWithModifier(self.claimData.paymentModifier) + .safeAdd(self.paymentData.paymentOwed); } else { - self.paymentData.paymentOwed = self.paymentData.getPayment().safeAdd(self.paymentData.paymentOwed); + self.paymentData.paymentOwed = self.paymentData.getPayment() + .safeAdd(self.paymentData.paymentOwed); } + // Report execution back to the origin address. This is located as far + // down in the function as possible as to minimize the amount of code + // that must be accounted for with the _GAS_TO_COMPLETE_EXECUTION + // value. + self.meta.reportExecution(_GAS_TO_COMPLETE_EXECUTION); + // Record the amount of gas used by execution. - uint measuredGasConsumption = startGas.flooredSub(msg.gas).safeAdd(EXTRA_GAS()); + uint measuredGasConsumption = startGas.safeAdd(_EXTRA_GAS).flooredSub(msg.gas); // // NOTE: All code after this must be accounted for by EXTRA_GAS @@ -347,7 +354,7 @@ library RequestLib { self.paymentData.sendDonation(); // Send the payment. - self.paymentData.sendDonation(); + self.paymentData.sendPayment(); // Send all extra ether back to the owner. sendOwnerEther(self); @@ -357,12 +364,11 @@ library RequestLib { function requiredExecutionGas(Request storage self) returns (uint) { return self.txnData.callGas.safeAdd(_GAS_TO_AUTHORIZE_EXECUTION) - .safeAdd(_GAS_TO_COMPLETE_EXECUTION) - .safeAdd(SafeSendLib.DEFAULT_SEND_GAS().safeMultiply(3)); + .safeAdd(_GAS_TO_COMPLETE_EXECUTION); } // TODO: compute this - uint constant _GAS_TO_AUTHORIZE_EXECUTION = 200000; + uint constant _GAS_TO_AUTHORIZE_EXECUTION = 0; /* * The amount of gas needed to do all of the pre execution checks. @@ -372,7 +378,7 @@ library RequestLib { } // TODO: compute this - uint constant _GAS_TO_COMPLETE_EXECUTION = 200000; + uint constant _GAS_TO_COMPLETE_EXECUTION = 190000; /* * The amount of gas needed to complete the execute method after @@ -383,7 +389,7 @@ library RequestLib { } // TODO: compute this - uint constant _EXTRA_GAS = 0; + uint constant _EXTRA_GAS = 185000; /* * The amount of gas used by the portion of the `execute` function diff --git a/contracts/SafeSendLib.sol b/contracts/SafeSendLib.sol index 8d35eb9d9..a6cbb4d18 100644 --- a/contracts/SafeSendLib.sol +++ b/contracts/SafeSendLib.sol @@ -4,7 +4,7 @@ library SafeSendLib { event SendFailed(address to, uint value); - uint constant _DEFAULT_SEND_GAS = 90000; + uint constant _DEFAULT_SEND_GAS = 30000; function DEFAULT_SEND_GAS() returns (uint) { return _DEFAULT_SEND_GAS; diff --git a/tests/TestErrors.sol b/tests/TestErrors.sol new file mode 100644 index 000000000..3a424278a --- /dev/null +++ b/tests/TestErrors.sol @@ -0,0 +1,19 @@ +contract ErrorGenerator { + function doThrow() { + doThrow(true); + } + + function doThrow(bool shouldThrow) { + if (shouldThrow) { + throw; + } + } + + function() { + throw; + } + + function __proxy(address to, bytes callData) returns (bool) { + return to.call(callData); + } +} diff --git a/tests/conftest.py b/tests/conftest.py index 571b1f4a6..0b0ae06f7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,70 +1,20 @@ -import pytest import os -import json -from web3.utils.string import ( - force_obj_to_text, - force_obj_to_bytes, -) +import pytest NULL_ADDRESS = '0x0000000000000000000000000000000000000000' -@pytest.fixture(scope="session") -def saved_state(project): - filename = 'tmp/saved-state-{hash}.json'.format(hash=project.get_source_file_hash()) - if os.path.exists(filename): - print("Loading state from:", filename) - with open(filename) as f: - state = {key: force_obj_to_bytes(value) for key, value in json.load(f).items()} - state['loaded_from'] = filename - return state - else: - return { - 'saved_blocks': [], - 'registrar_address': None, - } - - @pytest.fixture() -def load_chain_state(saved_state, chain): - import rlp - from ethereum.blocks import Block - from testrpc import testrpc - - saved_blocks = saved_state['saved_blocks'] - - if saved_blocks: - evm = testrpc.tester_client.evm - evm.blocks = [] - - for block_idx, block_data in enumerate(saved_blocks[:-1]): - print("Loading: ", block_idx, "/", len(saved_blocks)) - block = rlp.decode(block_data, Block, env=evm.env) - evm.blocks.append(block) - evm.db.put(block.hash, block_data) - - evm.revert(saved_blocks[-2]) - print("Done loading") - evm.mine() - print("Done mining") - - registrar_address = saved_state['registrar_address'] - - if registrar_address: - chain.registrar = chain.RegistrarFactory(address=registrar_address) - - -@pytest.fixture() -def request_tracker(unmigrated_chain, web3, load_chain_state): +def request_tracker(unmigrated_chain, web3): chain = unmigrated_chain tracker = chain.get_contract('RequestTracker') return tracker @pytest.fixture() -def request_factory(chain, web3, request_tracker, load_chain_state): +def request_factory(chain, web3, request_tracker): import time start_at = time.time() print("Start:", start_at) @@ -78,12 +28,12 @@ def request_factory(chain, web3, request_tracker, load_chain_state): @pytest.fixture() -def RequestLib(chain, load_chain_state): +def RequestLib(chain): return type(chain.get_contract('RequestLib')) @pytest.fixture() -def TransactionRequest(chain, load_chain_state): +def TransactionRequest(chain): # force lazy deployment of the dependencies for the TransactionRequest # contract. chain.get_contract('RequestLib') @@ -92,42 +42,10 @@ def TransactionRequest(chain, load_chain_state): @pytest.fixture() -def RequestFactory(chain, request_factory, load_chain_state): +def RequestFactory(chain, request_factory): return type(request_factory) -@pytest.fixture() -def save_chain_snapshot(project, - chain, - saved_state, - RequestFactory, - TransactionRequest, - RequestLib, - request_factory, - request_tracker): - import rlp - from testrpc import testrpc - - saved_blocks = saved_state['saved_blocks'] - - if not saved_blocks: - evm = testrpc.tester_client.evm - evm.mine() - saved_state['saved_blocks'] = [rlp.encode(block) for block in evm.blocks[:-1]] - - registrar_address = saved_state['registrar_address'] - - if not registrar_address: - saved_state['registrar_address'] = chain.registrar.address - - filename = 'tmp/saved-state-{hash}.json'.format(hash=project.get_source_file_hash()) - - if saved_state.get('loaded_from') != filename: - print("Saving state to:", filename) - with open(filename, 'w') as f: - return json.dump(force_obj_to_text(saved_state), f) - - @pytest.fixture() def denoms(): from web3.utils.currency import units @@ -144,8 +62,7 @@ def RequestData(chain, request_factory, get_txn_request, denoms, - TransactionRequest, - save_chain_snapshot): + TransactionRequest): class _RequestData(object): def __init__(self, # claim @@ -333,8 +250,8 @@ def from_deserialize(cls, address_args, bool_args, uint_args, uint8_args, call_d 'claimDeposit': uint_args[0], 'anchorGasPrice': uint_args[1], 'donation': uint_args[2], - 'payment': uint_args[3], - 'donationOwed': uint_args[4], + 'donationOwed': uint_args[3], + 'payment': uint_args[4], 'paymentOwed': uint_args[5], 'claimWindowSize': uint_args[6], 'freezePeriod': uint_args[7], @@ -372,17 +289,65 @@ def _get_txn_request(txn_hash): @pytest.fixture() -def get_execute_data(chain, web3, RequestLib): +def AbortReasons(): + return ( + 'WasCancelled', + 'AlreadyCalled', + 'BeforeCallWindow', + 'AfterCallWindow', + 'ReservedForClaimer', + 'StackTooDeep', + 'InsufficientGas', + ) + + +@pytest.fixture() +def get_execute_data(chain, web3, RequestLib, AbortReasons): def _get_execute_data(execute_txn_hash): - execute_txn = web3.eth.getTransaction(execute_txn_hash) execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) execute_filter = RequestLib.pastEvents('Executed', { 'fromBlock': execute_txn_receipt['blockNumber'], 'toBlock': execute_txn_receipt['blockNumber'], - 'address': execute_txn['to'], }) execute_logs = execute_filter.get() + if len(execute_logs) == 0: + abort_filter = RequestLib.pastEvents('Aborted', { + 'fromBlock': execute_txn_receipt['blockNumber'], + 'toBlock': execute_txn_receipt['blockNumber'], + }) + abort_logs = abort_filter.get() + if abort_logs: + errors = [AbortReasons[entry['args']['reason']] for entry in abort_logs] + raise AssertionError("Execution Failed: {0}".format(', '.join(errors))) assert len(execute_logs) == 1 execute_data = execute_logs[0] return execute_data return _get_execute_data + + +@pytest.fixture() +def test_contract_factories(web3): + from solc import compile_files + from populus.utils.filesystem import recursive_find_files + from populus.utils.contracts import ( + package_contracts, + construct_contract_factories, + ) + + base_tests_dir = os.path.dirname(__file__) + + solidity_source_files = recursive_find_files(base_tests_dir, '*.sol') + compiled_contracts = compile_files(solidity_source_files) + test_contract_factories = construct_contract_factories(web3, compiled_contracts) + return package_contracts(test_contract_factories) + + +@pytest.fixture() +def ErrorGenerator(test_contract_factories): + return test_contract_factories.ErrorGenerator + + +@pytest.fixture() +def error_generator(chain, ErrorGenerator): + chain.contract_factories['ErrorGenerator'] = ErrorGenerator + return chain.get_contract('ErrorGenerator') diff --git a/tests/request-factory/test_request_factory.py b/tests/request-factory/test_request_factory.py index 1c1bf4ab8..d52c1c08b 100644 --- a/tests/request-factory/test_request_factory.py +++ b/tests/request-factory/test_request_factory.py @@ -4,9 +4,6 @@ def test_request_factory_creates_request_with_provided_properties(chain, request_factory, RequestData, get_txn_request): - import time - start_at = time.time() - print("In Test") window_start = web3.eth.blockNumber + 20 expected_request_data = RequestData( @@ -54,5 +51,3 @@ def test_request_factory_creates_request_with_provided_properties(chain, assert actual_request_data.txnData.callValue == 123456789 assert actual_request_data.txnData.callGas == 1000000 assert actual_request_data.txnData.requiredStackDepth == 0 - - print("End test:", time.time() - start_at) diff --git a/tests/transaction-request/test_accounting.py b/tests/transaction-request/test_accounting.py new file mode 100644 index 000000000..75dcd98d1 --- /dev/null +++ b/tests/transaction-request/test_accounting.py @@ -0,0 +1,32 @@ +def test_txn_request_payments(chain, + web3, + get_execute_data, + RequestData): + txn_request = RequestData(donation=12345).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + before_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) + + chain.wait.for_block(request_data.schedule.windowStart) + + execute_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).execute() + execute_txn = web3.eth.getTransaction(execute_txn_hash) + execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) + + execute_data = get_execute_data(execute_txn_hash) + + after_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) + + donation = execute_data['args']['donation'] + assert donation == 12345 + assert after_donation_balance - before_donation_balance == donation + + payment = execute_data['args']['payment'] + + gas_price = execute_txn['gasPrice'] + gas_used = execute_txn_receipt['gasUsed'] + gas_cost = gas_used * gas_price + + expected_payment = gas_cost + request_data.paymentData.payment + + assert payment >= expected_payment diff --git a/tests/transaction-request/test_donation.py b/tests/transaction-request/test_donation.py index 75dcd98d1..1f2463d94 100644 --- a/tests/transaction-request/test_donation.py +++ b/tests/transaction-request/test_donation.py @@ -4,11 +4,14 @@ def test_txn_request_payments(chain, RequestData): txn_request = RequestData(donation=12345).direct_deploy() request_data = RequestData.from_contract(txn_request) + assert request_data.paymentData.donation == 12345 before_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) chain.wait.for_block(request_data.schedule.windowStart) + data_start = txn_request.call().requestData() + execute_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).execute() execute_txn = web3.eth.getTransaction(execute_txn_hash) execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) @@ -17,6 +20,8 @@ def test_txn_request_payments(chain, after_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) + data_after = txn_request.call().requestData() + donation = execute_data['args']['donation'] assert donation == 12345 assert after_donation_balance - before_donation_balance == donation @@ -30,3 +35,4 @@ def test_txn_request_payments(chain, expected_payment = gas_cost + request_data.paymentData.payment assert payment >= expected_payment + assert payment - expected_payment < 50000 * gas_price diff --git a/tests/transaction-request/test_exceptions.py b/tests/transaction-request/test_exceptions.py new file mode 100644 index 000000000..352b125b9 --- /dev/null +++ b/tests/transaction-request/test_exceptions.py @@ -0,0 +1,69 @@ +from web3.utils.encoding import decode_hex + + +def test_txn_request_for_txn_that_throw_exception(chain, + web3, + get_execute_data, + RequestData, + error_generator): + txn_request = RequestData( + createdBy=error_generator.address, + donation=12345, + toAddress=error_generator.address, + callData=decode_hex(error_generator._encode_transaction_data('doThrow')) + ).direct_deploy() + + request_data = RequestData.from_contract(txn_request) + chain.wait.for_block(request_data.schedule.windowStart) + + execute_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).execute() + execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) + + execute_data = get_execute_data(execute_txn_hash) + request_data = RequestData.from_contract(txn_request) + + assert request_data.meta.wasCalled is True + assert request_data.meta.wasSuccessful is False + + gas_used = execute_txn_receipt['gasUsed'] + measured_gas_consumption = execute_data['args']['measuredGasConsumption'] + + assert measured_gas_consumption > gas_used + assert measured_gas_consumption - gas_used < 50000 + + +def test_txn_request_when_everything_throws(chain, + web3, + get_execute_data, + RequestData, + error_generator): + txn_request = RequestData( + createdBy=error_generator.address, + owner=error_generator.address, + donationBenefactor=error_generator.address, + toAddress=error_generator.address, + callData=decode_hex(error_generator._encode_transaction_data('doThrow')) + ).direct_deploy() + + request_data = RequestData.from_contract(txn_request) + chain.wait.for_block(request_data.schedule.windowStart) + + proxy_call_data = decode_hex(txn_request._encode_transaction_data('execute')) + + execute_txn_hash = error_generator.transact({'from': web3.eth.accounts[1]}).__proxy( + to=txn_request.address, + callData=proxy_call_data, + ) + execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) + + execute_data = get_execute_data(execute_txn_hash) + request_data = RequestData.from_contract(txn_request) + + assert request_data.meta.wasCalled is True + assert request_data.meta.wasSuccessful is False + + gas_used = execute_txn_receipt['gasUsed'] + measured_gas_consumption = execute_data['args']['measuredGasConsumption'] + + assert measured_gas_consumption > gas_used + assert measured_gas_consumption - gas_used < 50000 From 999c648168e0707989a2e9115693b88a7f536d75 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 00:13:55 -0600 Subject: [PATCH 07/25] dirty --- contracts/BlockSchedulerLib.sol | 99 ++++++++++++++++++++ contracts/GasLib.sol | 27 ------ contracts/PaymentLib.sol | 22 +++-- contracts/RequestFactory.sol | 16 +--- contracts/RequestLib.sol | 17 +--- contracts/RequestMetaLib.sol | 9 -- contracts/Scheduler.sol | 31 ++++++ tests/conftest.py | 8 +- tests/transaction-request/test_accounting.py | 6 ++ tests/transaction-request/test_donation.py | 38 -------- 10 files changed, 162 insertions(+), 111 deletions(-) create mode 100644 contracts/BlockSchedulerLib.sol delete mode 100644 contracts/GasLib.sol create mode 100644 contracts/Scheduler.sol delete mode 100644 tests/transaction-request/test_donation.py diff --git a/contracts/BlockSchedulerLib.sol b/contracts/BlockSchedulerLib.sol new file mode 100644 index 000000000..d683df9a8 --- /dev/null +++ b/contracts/BlockSchedulerLib.sol @@ -0,0 +1,99 @@ +//pragma solidity 0.4.1; + +import {RequestFactoryInterface} from "contracts/RequestFactoryInterface.sol"; +import {RequestTrackerInterface} from "contracts/RequestTrackerInterface.sol"; +import {PaymentLib} from "contracts/PaymentLib.sol"; + + +library FutureBlockTransactionLib { + address constant DONATION_BENEFACTOR = 0xd3cda913deb6f67967b99d67acdfa1712c293601; + + struct FutureBlockTransaction { + uint donation; + uint payment; + + uint8 gracePeriod; + + uint callGas; + uint callValue; + bytes callData; + address toAddress; + uint requiredStackDepth; + } + + /* + * Set default values. + */ + function initialize(FutureBlockTransaction memory self) { + self.donation = 12345; + self.payment = 54321; + self.gracePeriod = 255; + self.targetBlock = block.number + 10; + self.callGas = 100000; + self.callData = ""; + self.toAddress = msg.sender; + self.requiredStackDepth = 0; + } + + /* + * Schedule t + */ + /* + * The lowest level interface for creating a transaction request. + * + * addressArgs[1] - meta.owner + * addressArgs[1] - paymentData.donationBenefactor + * addressArgs[2] - txnData.toAddress + * uintArgs[0] - paymentData.donation + * uintArgs[1] - paymentData.payment + * uintArgs[2] - schedule.claimWindowSize + * uintArgs[3] - schedule.freezePeriod + * uintArgs[4] - schedule.reservedWindowSize + * uintArgs[5] - schedule.temporalUnit + * uintArgs[6] - schedule.windowStart + * uintArgs[7] - schedule.windowSize + * uintArgs[8] - txnData.callGas + * uintArgs[9] - txnData.callValue + * uintArgs[10] - txnData.requiredStackDepth + */ + function schedule(FutureBlockTransaction storage self, + address factoryAddress, + address trackerAddress) public returns (address) { + factory = RequestFactoryInterface(factoryAddress); + newRequestAddress = factory.createRequest.value(PaymentLib.computeEndowment( + self.payment, + self.donation, + self.callGas, + self.callValue, + ))( + [ + msg.sender, // meta.owner + DONATION_BENEFACTOR, // paymentData.donationBenefactor + self.toAddress // txnData.toAddress + ], + [ + self.donation, // paymentData.donation + self.payment, // paymentData.payment + 255, // scheduler.claimWindowSize + 10, // scheduler.freezePeriod + 16, // scheduler.reservedWindowSize + 1, // scheduler.temporalUnit (block) + self.targetBlock, // scheduler.windowStart + 255, // scheduler.windowSize + self.callGas, // txnData.callGas + self.callValue, // txnData.callValue + self.requiredStackDepth // txnData.requiredStackDepth + ] + ); + + if (newRequestAddress == 0x0) { + // something went wrong.... + return 0x0; + } + + tracker = RequestTrackerInterface(trackerAddress); + tracker.addRequest(newRequestAddress, targetBlock); + + return newRequestAddress; + } +} diff --git a/contracts/GasLib.sol b/contracts/GasLib.sol deleted file mode 100644 index 606f5ba9e..000000000 --- a/contracts/GasLib.sol +++ /dev/null @@ -1,27 +0,0 @@ -//pragma solidity 0.4.1; - -import {MathLib} from "contracts/MathLib.sol"; - - -library GasLib { - using MathLib for uint; - - /* - * Returns a gas value that leaves at least reserveAmount leftover. This - * may return 0 if msg.gas < reserveAmount. The BUFFER value is present - * to prevent underflow in cases where msg.gas >= reserveAmount but the - * act of comparison drops msg.gas < reserveAmount. - */ - uint constant _BUFFER = 10000; - - function BUFFER() returns (uint) { - return _BUFFER; - } - - function getGas(uint reserveAmount) returns (uint) { - if (msg.gas < reserveAmount.safeAdd(_BUFFER)) { - return 0; - } - return msg.gas.flooredSub(reserveAmount); - } -} diff --git a/contracts/PaymentLib.sol b/contracts/PaymentLib.sol index ba478cd49..224fddab7 100644 --- a/contracts/PaymentLib.sol +++ b/contracts/PaymentLib.sol @@ -55,13 +55,6 @@ library PaymentLib { * caller. */ function getMultiplier(PaymentData storage self) returns (uint) { - //if (gas_price > base_gas_price) { - // return 100 * base_gas_price / gas_price; - //} - //else { - // return 200 - 100 * base_gas_price / (2 * base_gas_price - gas_price); - //} - if (tx.gasprice > self.anchorGasPrice) { return self.anchorGasPrice.safeMultiply(100) / tx.gasprice; } @@ -128,6 +121,21 @@ library PaymentLib { return true; } + + /* + * Compute the required endowment value for the given TransactionRequest + * parameters. + */ + function computeEndowment(uint payment, + uint donation, + uint callGas, + uint callValue) returns (uint) { + return payment.safeAdd(donation) + .safeMultiply(2) + .safeAdd(callGas.safeMultiply(tx.gasprice)) + .safeAdd(callValue); + } + /* * Validation: ensure that the request endowment is sufficient to cover. * - payment * maxMultiplier diff --git a/contracts/RequestFactory.sol b/contracts/RequestFactory.sol index 1a15e8f7e..9fb7a646f 100644 --- a/contracts/RequestFactory.sol +++ b/contracts/RequestFactory.sol @@ -4,18 +4,11 @@ import {RequestFactoryInterface} from "contracts/RequestFactoryInterface.sol"; import {TransactionRequest} from "contracts/TransactionRequest.sol"; import {RequestLib} from "contracts/RequestLib.sol"; import {IterTools} from "contracts/IterTools.sol"; -import {RequestTrackerInterface} from "contracts/RequestTrackerInterface.sol"; contract RequestFactory is RequestFactoryInterface { using IterTools for bool[7]; - RequestTrackerInterface tracker; - - function RequestFactory(address trackerAddress) { - tracker = RequestTrackerInterface(trackerAddress); - } - /* * ValidationError */ @@ -34,8 +27,9 @@ contract RequestFactory is RequestFactoryInterface { /* * The lowest level interface for creating a transaction request. * - * addressArgs[0] - paymentData.donationBenefactor - * addressArgs[1] - txnData.toAddress + * addressArgs[1] - meta.owner + * addressArgs[1] - paymentData.donationBenefactor + * addressArgs[2] - txnData.toAddress * uintArgs[0] - paymentData.donation * uintArgs[1] - paymentData.payment * uintArgs[2] - schedule.claimWindowSize @@ -71,6 +65,7 @@ contract RequestFactory is RequestFactoryInterface { if (errors[4]) ValidationError(Errors.InvalidRequiredStackDepth); if (errors[5]) ValidationError(Errors.CallGasTooHigh); if (errors[6]) ValidationError(Errors.EmptyToAddress); + return 0x0; } var request = (new TransactionRequest).value(msg.value)( @@ -87,9 +82,6 @@ contract RequestFactory is RequestFactoryInterface { // Log the creation. RequestCreated(address(request)); - // Register with tracker - tracker.addRequest(address(request), uintArgs[6]); - return request; } diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index d16bdd7b5..c6061fa7f 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -326,18 +326,12 @@ library RequestLib { .safeAdd(self.paymentData.paymentOwed); } - // Report execution back to the origin address. This is located as far - // down in the function as possible as to minimize the amount of code - // that must be accounted for with the _GAS_TO_COMPLETE_EXECUTION - // value. - self.meta.reportExecution(_GAS_TO_COMPLETE_EXECUTION); - // Record the amount of gas used by execution. - uint measuredGasConsumption = startGas.safeAdd(_EXTRA_GAS).flooredSub(msg.gas); + uint measuredGasConsumption = startGas.flooredSub(msg.gas).safeAdd(_EXTRA_GAS); - // - // NOTE: All code after this must be accounted for by EXTRA_GAS - // + // +--------------------------------------------------------------+ + // | NOTE: All code after this must be accounted for by EXTRA_GAS | + // +--------------------------------------------------------------+ // Add the gas reimbursment amount to the payment. self.paymentData.paymentOwed = measuredGasConsumption.safeMultiply(tx.gasprice) @@ -349,8 +343,7 @@ library RequestLib { self.paymentData.donationOwed, measuredGasConsumption); - // Send the donation. This will be a noop if there is no benefactor or - // if the donation amount is 0. + // Send the donation. self.paymentData.sendDonation(); // Send the payment. diff --git a/contracts/RequestMetaLib.sol b/contracts/RequestMetaLib.sol index 3cdbe4565..a9ea2981e 100644 --- a/contracts/RequestMetaLib.sol +++ b/contracts/RequestMetaLib.sol @@ -1,8 +1,5 @@ //pragma solidity 0.4.1; -import {GasLib} from "contracts/GasLib.sol"; - - library RequestMetaLib { struct RequestMeta { @@ -21,10 +18,4 @@ library RequestMetaLib { // Was the return value from the call successful. bool wasSuccessful; } - - function reportExecution(RequestMeta storage self, uint gasReserve) returns (bool) { - return self.createdBy.call. - gas(GasLib.getGas(gasReserve)) - (bytes4(sha3("receiveExecutionNotification()"))); - } } diff --git a/contracts/Scheduler.sol b/contracts/Scheduler.sol new file mode 100644 index 000000000..e751f5bf8 --- /dev/null +++ b/contracts/Scheduler.sol @@ -0,0 +1,31 @@ +//pragma solidity 0.4.1; + + +import {FutureBlockTransactionLib} from "contracts/FutureBlockTransactionLib.sol"; + + +contract BaseScheduler { + address trackerAddress; + address factoryAddress; + + function BaseScheduler(address _trackerAddress, address _factoryAddress) { + trackerAddress = _trackerAddress; + factoryAddress = _factoryAddress; + } +} + + +contract BlockScheduler is BaseScheduler { + using FutureBlockTransactionLib for FutureBlockTransactionLib.FutureBlockTransaction; + + /* + * Local storage variable used to hold + */ + FutureBlockTransactionLib.FutureBlockTransaction __futureBlockTransaction; + + function scheduleTransaction() public returns (address) { + } +} + + + diff --git a/tests/conftest.py b/tests/conftest.py index 0b0ae06f7..23f749830 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,15 +14,11 @@ def request_tracker(unmigrated_chain, web3): @pytest.fixture() -def request_factory(chain, web3, request_tracker): - import time - start_at = time.time() - print("Start:", start_at) - factory = chain.get_contract('RequestFactory', deploy_args=[request_tracker.address]) +def request_factory(chain, web3): + factory = chain.get_contract('RequestFactory') chain_code = web3.eth.getCode(factory.address) assert len(chain_code) > 10 - print("End:", time.time(), "Elapsed:", time.time() - start_at) return factory diff --git a/tests/transaction-request/test_accounting.py b/tests/transaction-request/test_accounting.py index 75dcd98d1..c9aab77bd 100644 --- a/tests/transaction-request/test_accounting.py +++ b/tests/transaction-request/test_accounting.py @@ -4,8 +4,10 @@ def test_txn_request_payments(chain, RequestData): txn_request = RequestData(donation=12345).direct_deploy() request_data = RequestData.from_contract(txn_request) + assert request_data.paymentData.donation == 12345 before_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) + before_payment_balance = web3.eth.getBalance(web3.eth.accounts[1]) chain.wait.for_block(request_data.schedule.windowStart) @@ -16,6 +18,7 @@ def test_txn_request_payments(chain, execute_data = get_execute_data(execute_txn_hash) after_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) + after_payment_balance = web3.eth.getBalance(web3.eth.accounts[1]) donation = execute_data['args']['donation'] assert donation == 12345 @@ -30,3 +33,6 @@ def test_txn_request_payments(chain, expected_payment = gas_cost + request_data.paymentData.payment assert payment >= expected_payment + assert payment - expected_payment < 120000 * gas_price + + assert after_payment_balance - before_payment_balance == payment - gas_cost diff --git a/tests/transaction-request/test_donation.py b/tests/transaction-request/test_donation.py deleted file mode 100644 index 1f2463d94..000000000 --- a/tests/transaction-request/test_donation.py +++ /dev/null @@ -1,38 +0,0 @@ -def test_txn_request_payments(chain, - web3, - get_execute_data, - RequestData): - txn_request = RequestData(donation=12345).direct_deploy() - request_data = RequestData.from_contract(txn_request) - assert request_data.paymentData.donation == 12345 - - before_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) - - chain.wait.for_block(request_data.schedule.windowStart) - - data_start = txn_request.call().requestData() - - execute_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).execute() - execute_txn = web3.eth.getTransaction(execute_txn_hash) - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - - execute_data = get_execute_data(execute_txn_hash) - - after_donation_balance = web3.eth.getBalance(request_data.paymentData.donationBenefactor) - - data_after = txn_request.call().requestData() - - donation = execute_data['args']['donation'] - assert donation == 12345 - assert after_donation_balance - before_donation_balance == donation - - payment = execute_data['args']['payment'] - - gas_price = execute_txn['gasPrice'] - gas_used = execute_txn_receipt['gasUsed'] - gas_cost = gas_used * gas_price - - expected_payment = gas_cost + request_data.paymentData.payment - - assert payment >= expected_payment - assert payment - expected_payment < 50000 * gas_price From 95a168c6865c80c39a334e3b586f6648445dbb83 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 10:22:15 -0600 Subject: [PATCH 08/25] flesh out tests for validation errors through request factory --- contracts/BlockSchedulerLib.sol | 18 +- contracts/IterTools.sol | 8 +- contracts/RequestFactory.sol | 18 +- contracts/RequestLib.sol | 200 +++++++-------- contracts/Scheduler.sol | 12 +- contracts/TransactionRequest.sol | 109 +++++---- tests/TransactionRecorder.sol | 13 + tests/conftest.py | 98 +++++++- tests/request-factory/test_request_factory.py | 231 +++++++++++++++++- 9 files changed, 526 insertions(+), 181 deletions(-) create mode 100644 tests/TransactionRecorder.sol diff --git a/contracts/BlockSchedulerLib.sol b/contracts/BlockSchedulerLib.sol index d683df9a8..dc0440093 100644 --- a/contracts/BlockSchedulerLib.sol +++ b/contracts/BlockSchedulerLib.sol @@ -14,6 +14,7 @@ library FutureBlockTransactionLib { uint8 gracePeriod; + uint targetBlock; uint callGas; uint callValue; bytes callData; @@ -24,14 +25,14 @@ library FutureBlockTransactionLib { /* * Set default values. */ - function initialize(FutureBlockTransaction memory self) { + function initialize(FutureBlockTransaction storage self) { self.donation = 12345; self.payment = 54321; self.gracePeriod = 255; self.targetBlock = block.number + 10; + self.toAddress = msg.sender; self.callGas = 100000; self.callData = ""; - self.toAddress = msg.sender; self.requiredStackDepth = 0; } @@ -59,12 +60,12 @@ library FutureBlockTransactionLib { function schedule(FutureBlockTransaction storage self, address factoryAddress, address trackerAddress) public returns (address) { - factory = RequestFactoryInterface(factoryAddress); - newRequestAddress = factory.createRequest.value(PaymentLib.computeEndowment( + var factory = RequestFactoryInterface(factoryAddress); + address newRequestAddress = factory.createRequest.value(PaymentLib.computeEndowment( self.payment, self.donation, self.callGas, - self.callValue, + self.callValue ))( [ msg.sender, // meta.owner @@ -83,7 +84,8 @@ library FutureBlockTransactionLib { self.callGas, // txnData.callGas self.callValue, // txnData.callValue self.requiredStackDepth // txnData.requiredStackDepth - ] + ], + self.callData ); if (newRequestAddress == 0x0) { @@ -91,8 +93,8 @@ library FutureBlockTransactionLib { return 0x0; } - tracker = RequestTrackerInterface(trackerAddress); - tracker.addRequest(newRequestAddress, targetBlock); + var tracker = RequestTrackerInterface(trackerAddress); + tracker.addRequest(newRequestAddress, self.targetBlock); return newRequestAddress; } diff --git a/contracts/IterTools.sol b/contracts/IterTools.sol index 5df5ed185..91c068417 100644 --- a/contracts/IterTools.sol +++ b/contracts/IterTools.sol @@ -2,12 +2,12 @@ library IterTools { /* * Return true if any of the values in the boolean array are true */ - function any(bool[7] values) returns (bool) { + function all(bool[7] values) returns (bool) { for (uint i = 0; i < values.length; i++) { - if (values[i]) { - return true; + if (!values[i]) { + return false; } } - return false; + return true; } } diff --git a/contracts/RequestFactory.sol b/contracts/RequestFactory.sol index 9fb7a646f..4e9078cbf 100644 --- a/contracts/RequestFactory.sol +++ b/contracts/RequestFactory.sol @@ -45,7 +45,7 @@ contract RequestFactory is RequestFactoryInterface { function createRequest(address[3] addressArgs, uint[11] uintArgs, bytes callData) returns (address) { - var errors = RequestLib.validate( + var is_valid = RequestLib.validate( [ msg.sender, // meta.createdBy addressArgs[0], // meta.owner @@ -57,14 +57,14 @@ contract RequestFactory is RequestFactoryInterface { msg.value ); - if (errors.any()) { - if (errors[0]) ValidationError(Errors.InsufficientEndowment); - if (errors[1]) ValidationError(Errors.ReservedWindowBiggerThanExecutionWindow); - if (errors[2]) ValidationError(Errors.InvalidTemporalUnit); - if (errors[3]) ValidationError(Errors.ExecutionWindowTooSoon); - if (errors[4]) ValidationError(Errors.InvalidRequiredStackDepth); - if (errors[5]) ValidationError(Errors.CallGasTooHigh); - if (errors[6]) ValidationError(Errors.EmptyToAddress); + if (!is_valid.all()) { + if (!is_valid[0]) ValidationError(Errors.InsufficientEndowment); + if (!is_valid[1]) ValidationError(Errors.ReservedWindowBiggerThanExecutionWindow); + if (!is_valid[2]) ValidationError(Errors.InvalidTemporalUnit); + if (!is_valid[3]) ValidationError(Errors.ExecutionWindowTooSoon); + if (!is_valid[4]) ValidationError(Errors.InvalidRequiredStackDepth); + if (!is_valid[5]) ValidationError(Errors.CallGasTooHigh); + if (!is_valid[6]) ValidationError(Errors.EmptyToAddress); return 0x0; } diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index c6061fa7f..7dc077e5b 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -18,12 +18,86 @@ library RequestLib { using SafeSendLib for address; using MathLib for uint; + struct SerializedRequest { + address[6] addressValues; + bool[3] boolValues; + uint[15] uintValues; + uint8[1] uint8Values; + } + struct Request { ExecutionLib.ExecutionData txnData; RequestMetaLib.RequestMeta meta; PaymentLib.PaymentData paymentData; ClaimLib.ClaimData claimData; RequestScheduleLib.ExecutionWindow schedule; + SerializedRequest serializedValues; + } + + /* + * Validate the initialization parameters for a transaction request. + */ + function validate(address[4] addressArgs, + uint[11] uintArgs, + bytes callData, + uint endowment) returns (bool[7] is_valid) { + Request memory request; + + // callData is special. + request.txnData.callData = callData; + + // Address values + request.claimData.claimedBy = 0x0; + request.meta.createdBy = addressArgs[0]; + request.meta.owner = addressArgs[1]; + request.paymentData.donationBenefactor = addressArgs[2]; + request.paymentData.donationBenefactor = 0x0; + request.txnData.toAddress = addressArgs[3]; + + // Boolean values + request.meta.isCancelled = false; + request.meta.wasCalled = false; + request.meta.wasSuccessful = false; + + // UInt values + request.claimData.claimDeposit = 0; + request.paymentData.anchorGasPrice = tx.gasprice; + request.paymentData.donation = uintArgs[0]; + request.paymentData.payment = uintArgs[1]; + request.paymentData.donationOwed = 0; + request.paymentData.paymentOwed = 0; + request.schedule.claimWindowSize = uintArgs[2]; + request.schedule.freezePeriod = uintArgs[3]; + request.schedule.reservedWindowSize = uintArgs[4]; + // This must be capped at 1 or it throws an exception. + request.schedule.temporalUnit = RequestScheduleLib.TemporalUnit(uintArgs[5].min(1)); + request.schedule.windowStart = uintArgs[6]; + request.schedule.windowSize = uintArgs[7]; + request.txnData.callGas = uintArgs[8]; + request.txnData.callValue = uintArgs[9]; + request.txnData.requiredStackDepth = uintArgs[10]; + + // Uint8 values + request.claimData.paymentModifier = 0; + + // The order of these errors matters as it determines which + // ValidationError event codes are logged when validation fails. + is_valid[0] = PaymentLib.validateEndowment(endowment, + request.paymentData.payment, + request.paymentData.donation, + request.txnData.callGas, + request.txnData.callValue); + is_valid[1] = RequestScheduleLib.validateReservedWindowSize(request.schedule.reservedWindowSize, + request.schedule.windowSize); + is_valid[2] = RequestScheduleLib.validateTemporalUnit(uintArgs[5]); + is_valid[3] = RequestScheduleLib.validateWindowStart(request.schedule.temporalUnit, + request.schedule.freezePeriod, + request.schedule.windowStart); + is_valid[4] = ExecutionLib.validateRequiredStackDepth(request.txnData.requiredStackDepth); + is_valid[5] = ExecutionLib.validateCallGas(request.txnData.callGas, _EXTRA_GAS); + is_valid[6] = ExecutionLib.validateToAddress(request.txnData.toAddress); + + return is_valid; } /* @@ -80,49 +154,41 @@ library RequestLib { * * TODO: figure out why this fails. */ - function serialize(Request storage self) returns (address[6] addressValues, - bool[3] boolValues, - uint[15] uintValues, - uint8[1] uint8Values) { + function serialize(Request storage self) returns (bool) { // Address values - addressValues[0] = self.claimData.claimedBy; - addressValues[1] = self.meta.createdBy; - addressValues[2] = self.meta.owner; - addressValues[3] = self.paymentData.donationBenefactor; - addressValues[4] = self.paymentData.paymentBenefactor; - addressValues[5] = self.txnData.toAddress; + self.serializedValues.addressValues[0] = self.claimData.claimedBy; + self.serializedValues.addressValues[1] = self.meta.createdBy; + self.serializedValues.addressValues[2] = self.meta.owner; + self.serializedValues.addressValues[3] = self.paymentData.donationBenefactor; + self.serializedValues.addressValues[4] = self.paymentData.paymentBenefactor; + self.serializedValues.addressValues[5] = self.txnData.toAddress; // Boolean values - boolValues[0] = self.meta.isCancelled; - boolValues[1] = self.meta.wasCalled; - boolValues[2] = self.meta.wasSuccessful; + self.serializedValues.boolValues[0] = self.meta.isCancelled; + self.serializedValues.boolValues[1] = self.meta.wasCalled; + self.serializedValues.boolValues[2] = self.meta.wasSuccessful; // UInt256 values - uintValues[0] = self.claimData.claimDeposit; - uintValues[1] = self.paymentData.anchorGasPrice; - uintValues[2] = self.paymentData.donation; - uintValues[3] = self.paymentData.payment; - uintValues[4] = self.paymentData.donationOwed; - uintValues[5] = self.paymentData.paymentOwed; - uintValues[6] = self.schedule.claimWindowSize; - uintValues[7] = self.schedule.freezePeriod; - uintValues[8] = self.schedule.reservedWindowSize; - uintValues[9] = uint(self.schedule.temporalUnit); - uintValues[10] = self.schedule.windowStart; - uintValues[11] = self.schedule.windowSize; - uintValues[12] = self.txnData.callGas; - uintValues[13] = self.txnData.callValue; - uintValues[14] = self.txnData.requiredStackDepth; + self.serializedValues.uintValues[0] = self.claimData.claimDeposit; + self.serializedValues.uintValues[1] = self.paymentData.anchorGasPrice; + self.serializedValues.uintValues[2] = self.paymentData.donation; + self.serializedValues.uintValues[3] = self.paymentData.donationOwed; + self.serializedValues.uintValues[4] = self.paymentData.payment; + self.serializedValues.uintValues[5] = self.paymentData.paymentOwed; + self.serializedValues.uintValues[6] = self.schedule.claimWindowSize; + self.serializedValues.uintValues[7] = self.schedule.freezePeriod; + self.serializedValues.uintValues[8] = self.schedule.reservedWindowSize; + self.serializedValues.uintValues[9] = uint(self.schedule.temporalUnit); + self.serializedValues.uintValues[10] = self.schedule.windowStart; + self.serializedValues.uintValues[11] = self.schedule.windowSize; + self.serializedValues.uintValues[12] = self.txnData.callGas; + self.serializedValues.uintValues[13] = self.txnData.callValue; + self.serializedValues.uintValues[14] = self.txnData.requiredStackDepth; // Uint8 values - uint8Values[0] = self.claimData.paymentModifier; - - return ( - addressValues, - boolValues, - uintValues, - uint8Values - ); + self.serializedValues.uint8Values[0] = self.claimData.paymentModifier; + + return true; } /* @@ -173,68 +239,6 @@ library RequestLib { self.claimData.paymentModifier = uint8Values[0]; } - function validate(address[4] addressValues, - uint[11] uintValues, - bytes callData, - uint endowment) returns (bool[7] errors) { - Request memory request; - - // callData is special. - request.txnData.callData = callData; - - // Address values - request.claimData.claimedBy = 0x0; - request.meta.createdBy = addressValues[0]; - request.meta.owner = addressValues[1]; - request.paymentData.donationBenefactor = addressValues[2]; - request.paymentData.donationBenefactor = 0x0; - request.txnData.toAddress = addressValues[3]; - - // Boolean values - request.meta.isCancelled = false; - request.meta.wasCalled = false; - request.meta.wasSuccessful = false; - - // UInt values - request.claimData.claimDeposit = 0; - request.paymentData.anchorGasPrice = tx.gasprice; - request.paymentData.donation = uintValues[0]; - request.paymentData.payment = uintValues[1]; - request.paymentData.donationOwed = 0; - request.paymentData.paymentOwed = 0; - request.schedule.claimWindowSize = uintValues[2]; - request.schedule.freezePeriod = uintValues[3]; - request.schedule.reservedWindowSize = uintValues[4]; - request.schedule.temporalUnit = RequestScheduleLib.TemporalUnit(uintValues[5]); - request.schedule.windowStart = uintValues[6]; - request.schedule.windowSize = uintValues[7]; - request.txnData.callGas = uintValues[8]; - request.txnData.callValue = uintValues[9]; - request.txnData.requiredStackDepth = uintValues[10]; - - // Uint8 values - request.claimData.paymentModifier = 0; - - // The order of these errors matters as it determines which - // ValidationError event codes are logged when validation fails. - errors[0] = PaymentLib.validateEndowment(endowment, - request.paymentData.payment, - request.paymentData.donation, - request.txnData.callGas, - request.txnData.callValue); - errors[1] = RequestScheduleLib.validateReservedWindowSize(request.schedule.reservedWindowSize, - request.schedule.windowSize); - errors[2] = RequestScheduleLib.validateTemporalUnit(uintValues[5]); - errors[3] = RequestScheduleLib.validateWindowStart(request.schedule.temporalUnit, - request.schedule.freezePeriod, - request.schedule.windowStart); - errors[4] = ExecutionLib.validateRequiredStackDepth(request.txnData.requiredStackDepth); - errors[5] = ExecutionLib.validateCallGas(request.txnData.callGas, _EXTRA_GAS); - errors[6] = ExecutionLib.validateToAddress(request.txnData.toAddress); - - return errors; - } - enum Reason { WasCancelled, AlreadyCalled, diff --git a/contracts/Scheduler.sol b/contracts/Scheduler.sol index e751f5bf8..5b64bcfa0 100644 --- a/contracts/Scheduler.sol +++ b/contracts/Scheduler.sol @@ -1,7 +1,7 @@ //pragma solidity 0.4.1; -import {FutureBlockTransactionLib} from "contracts/FutureBlockTransactionLib.sol"; +import {FutureBlockTransactionLib} from "contracts/BlockSchedulerLib.sol"; contract BaseScheduler { @@ -21,11 +21,11 @@ contract BlockScheduler is BaseScheduler { /* * Local storage variable used to hold */ - FutureBlockTransactionLib.FutureBlockTransaction __futureBlockTransaction; + FutureBlockTransactionLib.FutureBlockTransaction futureBlockTransaction; - function scheduleTransaction() public returns (address) { + function scheduleAtBlock(uint targetBlock) public returns (address) { + futureBlockTransaction.initialize(); + futureBlockTransaction.targetBlock = targetBlock; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); } } - - - diff --git a/contracts/TransactionRequest.sol b/contracts/TransactionRequest.sol index e7a58780f..72ea3a55b 100644 --- a/contracts/TransactionRequest.sol +++ b/contracts/TransactionRequest.sol @@ -57,54 +57,69 @@ contract TransactionRequest is Digger { bool[3], uint[15], uint8[1]) { - // Address values - address[6] memory addressValues = [ - txnRequest.claimData.claimedBy, - txnRequest.meta.createdBy, - txnRequest.meta.owner, - txnRequest.paymentData.donationBenefactor, - txnRequest.paymentData.paymentBenefactor, - txnRequest.txnData.toAddress - ]; - - // Boolean values - bool[3] memory boolValues = [ - txnRequest.meta.isCancelled, - txnRequest.meta.wasCalled, - txnRequest.meta.wasSuccessful - ]; - - // UInt256 values - uint[15] memory uintValues = [ - txnRequest.claimData.claimDeposit, - txnRequest.paymentData.anchorGasPrice, - txnRequest.paymentData.donation, - txnRequest.paymentData.donationOwed, - txnRequest.paymentData.payment, - txnRequest.paymentData.paymentOwed, - txnRequest.schedule.claimWindowSize, - txnRequest.schedule.freezePeriod, - txnRequest.schedule.reservedWindowSize, - uint(txnRequest.schedule.temporalUnit), - txnRequest.schedule.windowStart, - txnRequest.schedule.windowSize, - txnRequest.txnData.callGas, - txnRequest.txnData.callValue, - txnRequest.txnData.requiredStackDepth - ]; - - // Uint8 values - uint8[1] memory uint8Values = [ - txnRequest.claimData.paymentModifier - ]; - - return ( - addressValues, - boolValues, - uintValues, - uint8Values - ); + if (txnRequest.serialize()) { + return ( + txnRequest.serializedValues.addressValues, + txnRequest.serializedValues.boolValues, + txnRequest.serializedValues.uintValues, + txnRequest.serializedValues.uint8Values + ); + } else { + throw; + } } + //function requestData() constant returns (address[6], + // bool[3], + // uint[15], + // uint8[1]) { + // // Address values + // address[6] memory addressValues = [ + // txnRequest.claimData.claimedBy, + // txnRequest.meta.createdBy, + // txnRequest.meta.owner, + // txnRequest.paymentData.donationBenefactor, + // txnRequest.paymentData.paymentBenefactor, + // txnRequest.txnData.toAddress + // ]; + + // // Boolean values + // bool[3] memory boolValues = [ + // txnRequest.meta.isCancelled, + // txnRequest.meta.wasCalled, + // txnRequest.meta.wasSuccessful + // ]; + + // // UInt256 values + // uint[15] memory uintValues = [ + // txnRequest.claimData.claimDeposit, + // txnRequest.paymentData.anchorGasPrice, + // txnRequest.paymentData.donation, + // txnRequest.paymentData.donationOwed, + // txnRequest.paymentData.payment, + // txnRequest.paymentData.paymentOwed, + // txnRequest.schedule.claimWindowSize, + // txnRequest.schedule.freezePeriod, + // txnRequest.schedule.reservedWindowSize, + // uint(txnRequest.schedule.temporalUnit), + // txnRequest.schedule.windowStart, + // txnRequest.schedule.windowSize, + // txnRequest.txnData.callGas, + // txnRequest.txnData.callValue, + // txnRequest.txnData.requiredStackDepth + // ]; + + // // Uint8 values + // uint8[1] memory uint8Values = [ + // txnRequest.claimData.paymentModifier + // ]; + + // return ( + // addressValues, + // boolValues, + // uintValues, + // uint8Values + // ); + //} function callData() constant returns (bytes) { return txnRequest.txnData.callData; diff --git a/tests/TransactionRecorder.sol b/tests/TransactionRecorder.sol new file mode 100644 index 000000000..ff003d9f7 --- /dev/null +++ b/tests/TransactionRecorder.sol @@ -0,0 +1,13 @@ +contract TransactionRecorder { + uint public lastCallValue; + address public lastCaller; + bytes public lastCallData; + uint public lastCallGas; + + function () { + lastCallGas = msg.gas; + lastCallData = msg.data; + lastCaller = msg.sender; + lastCallValue = msg.value; + } +} diff --git a/tests/conftest.py b/tests/conftest.py index 23f749830..cdc9f44d5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -58,6 +58,7 @@ def RequestData(chain, request_factory, get_txn_request, denoms, + txn_recorder, TransactionRequest): class _RequestData(object): def __init__(self, @@ -81,7 +82,7 @@ def __init__(self, paymentOwed=0, # txnData callData="", - toAddress=NULL_ADDRESS, + toAddress=txn_recorder.address, callGas=1000000, callValue=0, requiredStackDepth=0, @@ -265,16 +266,51 @@ def from_deserialize(cls, address_args, bool_args, uint_args, uint8_args, call_d @pytest.fixture() -def get_txn_request(chain, web3, request_factory, RequestFactory, TransactionRequest): +def ValidationErrors(): + return ( + 'InsufficientEndowment', + 'ReservedWindowBiggerThanExecutionWindow', + 'InvalidTemporalUnit', + 'ExecutionWindowTooSoon', + 'InvalidRequiredStackDepth', + 'CallGasTooHigh', + 'EmptyToAddress', + ) + + +@pytest.fixture() +def get_txn_request(chain, + web3, + request_factory, + RequestFactory, + TransactionRequest, + ValidationErrors, + logs_to_event_data, + TopicMap): def _get_txn_request(txn_hash): txn_receipt = chain.wait.for_receipt(txn_hash) request_created_filter = RequestFactory.pastEvents('RequestCreated', { 'fromBlock': txn_receipt['blockNumber'], 'toBlock': txn_receipt['blockNumber'], - 'address': request_factory.address, }) request_created_logs = request_created_filter.get() - assert len(request_created_logs) == 1 + if len(request_created_logs) == 0: + error_filter = RequestFactory.pastEvents('ValidationError', { + 'fromBlock': txn_receipt['blockNumber'], + 'toBlock': txn_receipt['blockNumber'], + }) + error_logs = error_filter.get() + if error_logs: + errors = [ValidationErrors[entry['args']['reason']] for entry in error_logs] + raise AssertionError("ValidationError: {0}".format(', '.join(errors))) + decoded_events = logs_to_event_data(txn_receipt['logs']) + if decoded_events: + raise AssertionError( + "Something went wrong. The following events were found in" + "the logs for the given transaction hash:\n" + "{0}".format('\n'.join(decoded_events)) + ) + raise AssertionError("Something went wrong. No 'RequestCreated' log entries found") log_data = request_created_logs[0] @@ -298,7 +334,7 @@ def AbortReasons(): @pytest.fixture() -def get_execute_data(chain, web3, RequestLib, AbortReasons): +def get_execute_data(chain, web3, RequestLib, AbortReasons, logs_to_event_data): def _get_execute_data(execute_txn_hash): execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) execute_filter = RequestLib.pastEvents('Executed', { @@ -315,12 +351,51 @@ def _get_execute_data(execute_txn_hash): if abort_logs: errors = [AbortReasons[entry['args']['reason']] for entry in abort_logs] raise AssertionError("Execution Failed: {0}".format(', '.join(errors))) - assert len(execute_logs) == 1 + decoded_events = logs_to_event_data(execute_txn_receipt['logs']) + if decoded_events: + raise AssertionError( + "Something went wrong. The following events were found in" + "the logs for the given transaction hash:\n" + "{0}".format('\n'.join(decoded_events)) + ) + raise AssertionError("Something went wrong. No 'Executed' log entries found") execute_data = execute_logs[0] return execute_data return _get_execute_data +@pytest.fixture() +def logs_to_event_data(TopicMap): + from web3.utils.events import ( + get_event_data, + ) + + def _logs_to_event_data(log_entries): + return [ + get_event_data(TopicMap[log_entry['topics'][0]], log_entry) + for log_entry in log_entries + if log_entry['topics'] and log_entry['topics'][0] in TopicMap + ] + return _logs_to_event_data + + +@pytest.fixture() +def TopicMap(project): + import itertools + from web3.utils.abi import ( + filter_by_type, + event_abi_to_log_topic, + ) + all_events_abi = filter_by_type('event', itertools.chain.from_iterable( + contract['abi'] for contract in project.compiled_contracts.values() + )) + topic_to_abi = { + event_abi_to_log_topic(abi): abi + for abi in all_events_abi + } + return topic_to_abi + + @pytest.fixture() def test_contract_factories(web3): from solc import compile_files @@ -347,3 +422,14 @@ def ErrorGenerator(test_contract_factories): def error_generator(chain, ErrorGenerator): chain.contract_factories['ErrorGenerator'] = ErrorGenerator return chain.get_contract('ErrorGenerator') + + +@pytest.fixture() +def TransactionRecorder(test_contract_factories): + return test_contract_factories.TransactionRecorder + + +@pytest.fixture() +def txn_recorder(chain, TransactionRecorder): + chain.contract_factories['TransactionRecorder'] = TransactionRecorder + return chain.get_contract('TransactionRecorder') diff --git a/tests/request-factory/test_request_factory.py b/tests/request-factory/test_request_factory.py index d52c1c08b..972318e6e 100644 --- a/tests/request-factory/test_request_factory.py +++ b/tests/request-factory/test_request_factory.py @@ -1,9 +1,9 @@ def test_request_factory_creates_request_with_provided_properties(chain, web3, denoms, - request_factory, - RequestData, - get_txn_request): + txn_recorder, + RequestData): + request_lib = chain.get_contract('RequestLib') window_start = web3.eth.blockNumber + 20 expected_request_data = RequestData( @@ -19,6 +19,12 @@ def test_request_factory_creates_request_with_provided_properties(chain, callGas=1000000, requiredStackDepth=0 ) + is_valid = request_lib.call().validate( + endowment=10 * denoms.ether, + **expected_request_data.to_init_kwargs() + ) + assert all(is_valid) + txn_request = expected_request_data.deploy_via_factory() actual_request_data = RequestData.from_contract(txn_request) @@ -47,7 +53,226 @@ def test_request_factory_creates_request_with_provided_properties(chain, assert actual_request_data.schedule.reservedWindowSize == 16 assert actual_request_data.schedule.temporalUnit == 1 + assert actual_request_data.txnData.toAddress == txn_recorder.address assert actual_request_data.txnData.callData == '' assert actual_request_data.txnData.callValue == 123456789 assert actual_request_data.txnData.callGas == 1000000 assert actual_request_data.txnData.requiredStackDepth == 0 + + +def test_request_factory_insufficient_endowment_validation_error(chain, + web3, + denoms, + txn_recorder, + RequestData): + request_lib = chain.get_contract('RequestLib') + window_start = web3.eth.blockNumber + 20 + + expected_request_data = RequestData( + claimWindowSize=255, + donation=12345, + payment=54321, + freezePeriod=10, + windowStart=window_start, + windowSize=255, + reservedWindowSize=16, + temporalUnit=1, + callValue=123456789, + callGas=1000000, + requiredStackDepth=0 + ) + is_valid = request_lib.call().validate( + endowment=123456789, # too small of an endowment. + **expected_request_data.to_init_kwargs() + ) + assert not all(is_valid) + assert is_valid[0] is False + assert all(is_valid[1:]) + + +def test_request_factory_too_large_reserved_window_validation_error(chain, + web3, + denoms, + txn_recorder, + RequestData): + request_lib = chain.get_contract('RequestLib') + window_start = web3.eth.blockNumber + 20 + + expected_request_data = RequestData( + claimWindowSize=255, + donation=12345, + payment=54321, + freezePeriod=10, + windowStart=window_start, + windowSize=255, + reservedWindowSize=255 + 1, # 1 more than the window size. + temporalUnit=1, + callValue=123456789, + callGas=1000000, + requiredStackDepth=0 + ) + is_valid = request_lib.call().validate( + endowment=10 * denoms.ether, + **expected_request_data.to_init_kwargs() + ) + assert not all(is_valid) + assert is_valid[1] is False + assert all(is_valid[:1]) + assert all(is_valid[2:]) + + +def test_request_factory_invalid_temporal_unit_validation_error(chain, + web3, + denoms, + txn_recorder, + RequestData): + request_lib = chain.get_contract('RequestLib') + window_start = web3.eth.blockNumber + 20 + + expected_request_data = RequestData( + claimWindowSize=255, + donation=12345, + payment=54321, + freezePeriod=10, + windowStart=window_start, + windowSize=255, + reservedWindowSize=16, + temporalUnit=2, # Only 0, and 1 are supported. + callValue=123456789, + callGas=1000000, + requiredStackDepth=0 + ) + is_valid = request_lib.call().validate( + endowment=10 * denoms.ether, + **expected_request_data.to_init_kwargs() + ) + assert not all(is_valid) + assert is_valid[2] is False + assert all(is_valid[:2]) + assert all(is_valid[3:]) + + +def test_request_factory_too_soon_execution_window_validation_error(chain, + web3, + denoms, + txn_recorder, + RequestData): + request_lib = chain.get_contract('RequestLib') + window_start = web3.eth.blockNumber + 10 + + expected_request_data = RequestData( + claimWindowSize=255, + donation=12345, + payment=54321, + freezePeriod=11, # more than the number of blocks between now and the windowStart. + windowStart=window_start, + windowSize=255, + reservedWindowSize=255, + temporalUnit=1, + callValue=123456789, + callGas=1000000, + requiredStackDepth=0 + ) + is_valid = request_lib.call().validate( + endowment=10 * denoms.ether, + **expected_request_data.to_init_kwargs() + ) + assert not all(is_valid) + assert is_valid[3] is False + assert all(is_valid[:3]) + assert all(is_valid[4:]) + + +def test_request_factory_invalid_required_stack_depth_validation_error(chain, + web3, + denoms, + txn_recorder, + RequestData): + request_lib = chain.get_contract('RequestLib') + window_start = web3.eth.blockNumber + 20 + + expected_request_data = RequestData( + claimWindowSize=255, + donation=12345, + payment=54321, + freezePeriod=10, + windowStart=window_start, + windowSize=255, + reservedWindowSize=255, + temporalUnit=1, + callValue=123456789, + callGas=1000000, + requiredStackDepth=1025, + ) + is_valid = request_lib.call().validate( + endowment=10 * denoms.ether, + **expected_request_data.to_init_kwargs() + ) + assert not all(is_valid) + assert is_valid[4] is False + assert all(is_valid[:4]) + assert all(is_valid[5:]) + + +def test_request_factory_too_high_call_gas_validation_error(chain, + web3, + denoms, + txn_recorder, + RequestData): + last_block = web3.eth.getBlock('latest') + + request_lib = chain.get_contract('RequestLib') + window_start = web3.eth.blockNumber + 20 + + expected_request_data = RequestData( + claimWindowSize=255, + donation=12345, + payment=54321, + freezePeriod=10, + windowStart=window_start, + windowSize=255, + reservedWindowSize=255, + temporalUnit=1, + callValue=123456789, + callGas=last_block['gasLimit'], # cannot be at gas limit. + requiredStackDepth=0, + ) + is_valid = request_lib.call().validate( + endowment=10 * denoms.ether, + **expected_request_data.to_init_kwargs() + ) + assert not all(is_valid) + assert is_valid[5] is False + assert all(is_valid[:5]) + assert all(is_valid[6:]) + + +def test_request_factory_to_address_as_null_validation_error(chain, + web3, + denoms, + txn_recorder, + RequestData): + request_lib = chain.get_contract('RequestLib') + window_start = web3.eth.blockNumber + 20 + + expected_request_data = RequestData( + toAddress='0x0000000000000000000000000000000000000000', # cannot send to 0x0 + claimWindowSize=255, + donation=12345, + payment=54321, + freezePeriod=10, + windowStart=window_start, + windowSize=255, + reservedWindowSize=255, + temporalUnit=1, + callValue=123456789, + callGas=1000000, + requiredStackDepth=0, + ) + is_valid = request_lib.call().validate( + endowment=10 * denoms.ether, + **expected_request_data.to_init_kwargs() + ) + assert not all(is_valid) + assert is_valid[6] is False + assert all(is_valid[:6]) From 580d71e7936c73c85a6b2c3704dc4bc7811aead6 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 10:24:19 -0600 Subject: [PATCH 09/25] fix --- tests/request-factory/test_request_factory.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/request-factory/test_request_factory.py b/tests/request-factory/test_request_factory.py index 972318e6e..bce3db47d 100644 --- a/tests/request-factory/test_request_factory.py +++ b/tests/request-factory/test_request_factory.py @@ -167,7 +167,7 @@ def test_request_factory_too_soon_execution_window_validation_error(chain, freezePeriod=11, # more than the number of blocks between now and the windowStart. windowStart=window_start, windowSize=255, - reservedWindowSize=255, + reservedWindowSize=16, temporalUnit=1, callValue=123456789, callGas=1000000, @@ -198,7 +198,7 @@ def test_request_factory_invalid_required_stack_depth_validation_error(chain, freezePeriod=10, windowStart=window_start, windowSize=255, - reservedWindowSize=255, + reservedWindowSize=16, temporalUnit=1, callValue=123456789, callGas=1000000, @@ -231,7 +231,7 @@ def test_request_factory_too_high_call_gas_validation_error(chain, freezePeriod=10, windowStart=window_start, windowSize=255, - reservedWindowSize=255, + reservedWindowSize=16, temporalUnit=1, callValue=123456789, callGas=last_block['gasLimit'], # cannot be at gas limit. @@ -263,7 +263,7 @@ def test_request_factory_to_address_as_null_validation_error(chain, freezePeriod=10, windowStart=window_start, windowSize=255, - reservedWindowSize=255, + reservedWindowSize=16, temporalUnit=1, callValue=123456789, callGas=1000000, From 899128a3e533bc7f2ee38ed1b98e87975c079316 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 10:30:34 -0600 Subject: [PATCH 10/25] remove commented code --- contracts/TransactionRequest.sol | 52 -------------------------------- 1 file changed, 52 deletions(-) diff --git a/contracts/TransactionRequest.sol b/contracts/TransactionRequest.sol index 72ea3a55b..620df4c64 100644 --- a/contracts/TransactionRequest.sol +++ b/contracts/TransactionRequest.sol @@ -68,58 +68,6 @@ contract TransactionRequest is Digger { throw; } } - //function requestData() constant returns (address[6], - // bool[3], - // uint[15], - // uint8[1]) { - // // Address values - // address[6] memory addressValues = [ - // txnRequest.claimData.claimedBy, - // txnRequest.meta.createdBy, - // txnRequest.meta.owner, - // txnRequest.paymentData.donationBenefactor, - // txnRequest.paymentData.paymentBenefactor, - // txnRequest.txnData.toAddress - // ]; - - // // Boolean values - // bool[3] memory boolValues = [ - // txnRequest.meta.isCancelled, - // txnRequest.meta.wasCalled, - // txnRequest.meta.wasSuccessful - // ]; - - // // UInt256 values - // uint[15] memory uintValues = [ - // txnRequest.claimData.claimDeposit, - // txnRequest.paymentData.anchorGasPrice, - // txnRequest.paymentData.donation, - // txnRequest.paymentData.donationOwed, - // txnRequest.paymentData.payment, - // txnRequest.paymentData.paymentOwed, - // txnRequest.schedule.claimWindowSize, - // txnRequest.schedule.freezePeriod, - // txnRequest.schedule.reservedWindowSize, - // uint(txnRequest.schedule.temporalUnit), - // txnRequest.schedule.windowStart, - // txnRequest.schedule.windowSize, - // txnRequest.txnData.callGas, - // txnRequest.txnData.callValue, - // txnRequest.txnData.requiredStackDepth - // ]; - - // // Uint8 values - // uint8[1] memory uint8Values = [ - // txnRequest.claimData.paymentModifier - // ]; - - // return ( - // addressValues, - // boolValues, - // uintValues, - // uint8Values - // ); - //} function callData() constant returns (bytes) { return txnRequest.txnData.callData; From 7236b137c7c77c17f1e2505878abb761a1a5df66 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 13:47:50 -0700 Subject: [PATCH 11/25] block scheduler --- contracts/BlockSchedulerLib.sol | 24 +- contracts/Scheduler.sol | 356 +++++++++++++++++++++- tests/block-scheduling/test_scheduling.py | 43 +++ 3 files changed, 400 insertions(+), 23 deletions(-) create mode 100644 tests/block-scheduling/test_scheduling.py diff --git a/contracts/BlockSchedulerLib.sol b/contracts/BlockSchedulerLib.sol index dc0440093..784b4c81c 100644 --- a/contracts/BlockSchedulerLib.sol +++ b/contracts/BlockSchedulerLib.sol @@ -25,37 +25,19 @@ library FutureBlockTransactionLib { /* * Set default values. */ - function initialize(FutureBlockTransaction storage self) { + function reset(FutureBlockTransaction storage self) { self.donation = 12345; self.payment = 54321; self.gracePeriod = 255; self.targetBlock = block.number + 10; self.toAddress = msg.sender; - self.callGas = 100000; + self.callGas = 90000; self.callData = ""; self.requiredStackDepth = 0; } /* - * Schedule t - */ - /* - * The lowest level interface for creating a transaction request. - * - * addressArgs[1] - meta.owner - * addressArgs[1] - paymentData.donationBenefactor - * addressArgs[2] - txnData.toAddress - * uintArgs[0] - paymentData.donation - * uintArgs[1] - paymentData.payment - * uintArgs[2] - schedule.claimWindowSize - * uintArgs[3] - schedule.freezePeriod - * uintArgs[4] - schedule.reservedWindowSize - * uintArgs[5] - schedule.temporalUnit - * uintArgs[6] - schedule.windowStart - * uintArgs[7] - schedule.windowSize - * uintArgs[8] - txnData.callGas - * uintArgs[9] - txnData.callValue - * uintArgs[10] - txnData.requiredStackDepth + * The low level interface for creating a transaction request. */ function schedule(FutureBlockTransaction storage self, address factoryAddress, diff --git a/contracts/Scheduler.sol b/contracts/Scheduler.sol index 5b64bcfa0..ae785359d 100644 --- a/contracts/Scheduler.sol +++ b/contracts/Scheduler.sol @@ -18,14 +18,366 @@ contract BaseScheduler { contract BlockScheduler is BaseScheduler { using FutureBlockTransactionLib for FutureBlockTransactionLib.FutureBlockTransaction; + function BlockScheduler(address _trackerAddress, address _factoryAddress) + BaseScheduler(_trackerAddress, _factoryAddress) { + } + /* * Local storage variable used to hold */ FutureBlockTransactionLib.FutureBlockTransaction futureBlockTransaction; - function scheduleAtBlock(uint targetBlock) public returns (address) { - futureBlockTransaction.initialize(); + modifier doReset { + futureBlockTransaction.reset(); + _ + } + + /* + * +----------------+ + * | Scheduling API | + * +----------------+ + * + * Attempt to expose as many common ways of scheduling a transaction + * request as possible. + * + * uint donation; + * uint payment; + * uint8 gracePeriod; + * uint targetBlock; + * uint callGas; + * uint callValue; + * bytes callData; + * address toAddress; + * uint requiredStackDepth; + */ + function scheduleTransaction() doReset public returns (address) { + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + /* + * +----------------------------+ + * | Common Scheduling Patterns | + * +----------------------------+ + */ + + /* + * - without targetBlock + */ + function scheduleTransaction(address toAddress) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(uint callValue, + address toAddress) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callValue = callValue; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(address toAddress, + bytes callData) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(address toAddress, + bytes callData, + uint callValue) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + /* + * - with targetBlock + */ + function scheduleTransaction(uint targetBlock, + address toAddress, + uint callValue) doReset public returns (address) { + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callValue = callValue; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(uint targetBlock, + address toAddress, + bytes callData) doReset public returns (address) { + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(uint targetBlock, + address toAddress, + bytes callData, + uint callValue) doReset public returns (address) { + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + + /* + * +---------------------------------------------------------+ + * | Transactions which will use msg.sender as the toAddress | + * +---------------------------------------------------------+ + */ + + /* + * - without callData + */ + function scheduleTransaction(uint targetBlock) doReset public returns (address) { + futureBlockTransaction.targetBlock = targetBlock; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(uint targetBlock, + uint callValue) doReset public returns (address) { + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callValue = callValue; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(uint targetBlock, + uint callValue, + uint callGas) doReset public returns (address) { + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callValue = callValue; + futureBlockTransaction.callGas = callGas; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + + /* + * - with callData + */ + function scheduleTransaction(uint targetBlock, + bytes callData) doReset public returns (address) { + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(uint targetBlock, + uint callValue, + bytes callData) doReset public returns (address) { + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callValue = callValue; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(uint targetBlock, + uint callValue, + uint callGas, + bytes callData) doReset public returns (address) { + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callValue = callValue; + futureBlockTransaction.callGas = callGas; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + /* + * +--------------------------------------------+ + * | Transactions which specify the `toAddress` | + * +--------------------------------------------+ + */ + + /* + * - without callData + */ + function scheduleTransaction(address toAddress, + uint targetBlock) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.targetBlock = targetBlock; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(address toAddress, + uint targetBlock, + uint callValue) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callValue = callValue; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(address toAddress, + uint targetBlock, + uint callValue, + uint callGas) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callValue = callValue; + futureBlockTransaction.callGas = callGas; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + + /* + * - with callData + */ + function scheduleTransaction(address toAddress, + uint targetBlock, + bytes callData) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(address toAddress, + uint targetBlock, + uint callValue, + bytes callData) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callValue = callValue; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + function scheduleTransaction(address toAddress, + uint targetBlock, + uint callValue, + uint callGas, + bytes callData) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.targetBlock = targetBlock; + futureBlockTransaction.callValue = callValue; + futureBlockTransaction.callGas = callGas; + futureBlockTransaction.callData = callData; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + /* + * All fields except `requiredStackDepth` and `gracePeriod` and `donation` and `payment` + * + * uintArgs[0] callGas + * uintArgs[1] callValue + * uintArgs[2] targetBlock + * uint8 gracePeriod; + * bytes callData; + * address toAddress; + */ + function scheduleTransaction(address toAddress, + bytes callData, + uint[3] uintArgs) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callData = callData; + futureBlockTransaction.callGas = uintArgs[0]; + futureBlockTransaction.callValue = uintArgs[1]; + futureBlockTransaction.targetBlock = uintArgs[2]; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + /* + * All fields except `requiredStackDepth` and `gracePeriod` and `donation` + * + * uintArgs[0] callGas + * uintArgs[1] callValue + * uintArgs[2] payment + * uintArgs[3] targetBlock + * uint8 gracePeriod; + * bytes callData; + * address toAddress; + */ + function scheduleTransaction(address toAddress, + bytes callData, + uint[4] uintArgs) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callData = callData; + futureBlockTransaction.callGas = uintArgs[0]; + futureBlockTransaction.callValue = uintArgs[1]; + futureBlockTransaction.payment = uintArgs[2]; + futureBlockTransaction.targetBlock = uintArgs[3]; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + /* + * All fields except `requiredStackDepth` and `gracePeriod` + * + * uintArgs[0] callGas + * uintArgs[1] callValue + * uintArgs[2] donation + * uintArgs[3] payment + * uintArgs[4] targetBlock + * uint8 gracePeriod; + * bytes callData; + * address toAddress; + */ + function scheduleTransaction(address toAddress, + bytes callData, + uint[5] uintArgs) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callData = callData; + futureBlockTransaction.callGas = uintArgs[0]; + futureBlockTransaction.callValue = uintArgs[1]; + futureBlockTransaction.donation = uintArgs[2]; + futureBlockTransaction.payment = uintArgs[3]; + futureBlockTransaction.targetBlock = uintArgs[4]; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + /* + * All fields except `requiredStackDepth` + * + * uintArgs[0] callGas + * uintArgs[1] callValue + * uintArgs[2] donation + * uintArgs[3] payment + * uintArgs[4] targetBlock + * uint8 gracePeriod; + * bytes callData; + * address toAddress; + */ + function scheduleTransaction(address toAddress, + bytes callData, + uint8 gracePeriod, + uint[5] uintArgs) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callData = callData; + futureBlockTransaction.gracePeriod = gracePeriod; + futureBlockTransaction.callGas = uintArgs[0]; + futureBlockTransaction.callValue = uintArgs[1]; + futureBlockTransaction.donation = uintArgs[2]; + futureBlockTransaction.payment = uintArgs[3]; + futureBlockTransaction.targetBlock = uintArgs[4]; + return futureBlockTransaction.schedule(factoryAddress, trackerAddress); + } + + /* + * Full scheduling API exposing all fields. + * + * uintArgs[0] callGas + * uintArgs[1] callValue + * uintArgs[2] donation + * uintArgs[3] payment + * uintArgs[4] targetBlock + * uintArgs[5] requiredStackDepth + * uint8 gracePeriod; + * bytes callData; + * address toAddress; + */ + function scheduleTransaction(address toAddress, + bytes callData, + uint8 gracePeriod, + uint[6] uintArgs) doReset public returns (address) { + futureBlockTransaction.toAddress = toAddress; + futureBlockTransaction.callData = callData; + futureBlockTransaction.gracePeriod = gracePeriod; + futureBlockTransaction.callGas = uintArgs[0]; + futureBlockTransaction.callValue = uintArgs[1]; + futureBlockTransaction.donation = uintArgs[2]; + futureBlockTransaction.payment = uintArgs[3]; + futureBlockTransaction.targetBlock = uintArgs[4]; + futureBlockTransaction.requiredStackDepth = uintArgs[5]; return futureBlockTransaction.schedule(factoryAddress, trackerAddress); } } diff --git a/tests/block-scheduling/test_scheduling.py b/tests/block-scheduling/test_scheduling.py new file mode 100644 index 000000000..18cb0e915 --- /dev/null +++ b/tests/block-scheduling/test_scheduling.py @@ -0,0 +1,43 @@ +import pytest + + +@pytest.fixture() +def scheduler(chain, request_tracker, request_factory): + block_scheduler = chain.get_contract('BlockScheduler', deploy_args=[ + request_tracker.address, + request_factory.address, + ]) + return block_scheduler + + +def test_scheduling_with_no_args(chain, web3, denoms, scheduler, RequestData, get_txn_request): + schedule_txn_hash = scheduler.transact({ + 'value': 10 * denoms.ether, + }).scheduleTransaction() + schedule_txn_receipt = web3.eth.getTransactionReceipt(schedule_txn_hash) + + txn_request = get_txn_request(schedule_txn_hash) + request_data = RequestData.from_contract(txn_request) + + assert request_data.txnData.toAddress == web3.eth.coinbase + assert request_data.schedule.windowStart == schedule_txn_receipt['blockNumber'] + 10 + + +def test_scheduling_with_specified_block(chain, + web3, + denoms, + scheduler, + RequestData, + get_txn_request): + target_block = web3.eth.blockNumber + 100 + schedule_txn_hash = scheduler.transact({ + 'value': 10 * denoms.ether, + }).scheduleTransaction( + targetBlock=target_block, + ) + + txn_request = get_txn_request(schedule_txn_hash) + request_data = RequestData.from_contract(txn_request) + + assert request_data.txnData.toAddress == web3.eth.coinbase + assert request_data.schedule.windowStart == target_block From f326f61d13d544776beda8f4b723ee0c7a5d6a87 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 18:17:41 -0700 Subject: [PATCH 12/25] call scheduling API --- contracts/BlockSchedulerLib.sol | 12 +- contracts/Scheduler.sol | 323 +--------------------- tests/block-scheduling/test_scheduling.py | 57 +++- 3 files changed, 66 insertions(+), 326 deletions(-) diff --git a/contracts/BlockSchedulerLib.sol b/contracts/BlockSchedulerLib.sol index 784b4c81c..321e7a34d 100644 --- a/contracts/BlockSchedulerLib.sol +++ b/contracts/BlockSchedulerLib.sol @@ -12,9 +12,9 @@ library FutureBlockTransactionLib { uint donation; uint payment; - uint8 gracePeriod; + uint8 windowSize; - uint targetBlock; + uint windowStart; uint callGas; uint callValue; bytes callData; @@ -28,8 +28,8 @@ library FutureBlockTransactionLib { function reset(FutureBlockTransaction storage self) { self.donation = 12345; self.payment = 54321; - self.gracePeriod = 255; - self.targetBlock = block.number + 10; + self.windowSize = 255; + self.windowStart = block.number + 10; self.toAddress = msg.sender; self.callGas = 90000; self.callData = ""; @@ -61,7 +61,7 @@ library FutureBlockTransactionLib { 10, // scheduler.freezePeriod 16, // scheduler.reservedWindowSize 1, // scheduler.temporalUnit (block) - self.targetBlock, // scheduler.windowStart + self.windowStart, // scheduler.windowStart 255, // scheduler.windowSize self.callGas, // txnData.callGas self.callValue, // txnData.callValue @@ -76,7 +76,7 @@ library FutureBlockTransactionLib { } var tracker = RequestTrackerInterface(trackerAddress); - tracker.addRequest(newRequestAddress, self.targetBlock); + tracker.addRequest(newRequestAddress, self.windowStart); return newRequestAddress; } diff --git a/contracts/Scheduler.sol b/contracts/Scheduler.sol index ae785359d..16e201e5e 100644 --- a/contracts/Scheduler.sol +++ b/contracts/Scheduler.sol @@ -33,322 +33,25 @@ contract BlockScheduler is BaseScheduler { } /* - * +----------------+ - * | Scheduling API | - * +----------------+ - * - * Attempt to expose as many common ways of scheduling a transaction - * request as possible. - * - * uint donation; - * uint payment; - * uint8 gracePeriod; - * uint targetBlock; - * uint callGas; - * uint callValue; - * bytes callData; - * address toAddress; - * uint requiredStackDepth; - */ - function scheduleTransaction() doReset public returns (address) { - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - /* - * +----------------------------+ - * | Common Scheduling Patterns | - * +----------------------------+ - */ - - /* - * - without targetBlock - */ - function scheduleTransaction(address toAddress) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(uint callValue, - address toAddress) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.callValue = callValue; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(address toAddress, - bytes callData) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(address toAddress, - bytes callData, - uint callValue) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - /* - * - with targetBlock - */ - function scheduleTransaction(uint targetBlock, - address toAddress, - uint callValue) doReset public returns (address) { - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.callValue = callValue; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(uint targetBlock, - address toAddress, - bytes callData) doReset public returns (address) { - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(uint targetBlock, - address toAddress, - bytes callData, - uint callValue) doReset public returns (address) { - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - - /* - * +---------------------------------------------------------+ - * | Transactions which will use msg.sender as the toAddress | - * +---------------------------------------------------------+ - */ - - /* - * - without callData - */ - function scheduleTransaction(uint targetBlock) doReset public returns (address) { - futureBlockTransaction.targetBlock = targetBlock; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(uint targetBlock, - uint callValue) doReset public returns (address) { - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callValue = callValue; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(uint targetBlock, - uint callValue, - uint callGas) doReset public returns (address) { - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callValue = callValue; - futureBlockTransaction.callGas = callGas; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - - /* - * - with callData - */ - function scheduleTransaction(uint targetBlock, - bytes callData) doReset public returns (address) { - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(uint targetBlock, - uint callValue, - bytes callData) doReset public returns (address) { - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callValue = callValue; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(uint targetBlock, - uint callValue, - uint callGas, - bytes callData) doReset public returns (address) { - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callValue = callValue; - futureBlockTransaction.callGas = callGas; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - /* - * +--------------------------------------------+ - * | Transactions which specify the `toAddress` | - * +--------------------------------------------+ - */ - - /* - * - without callData - */ - function scheduleTransaction(address toAddress, - uint targetBlock) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.targetBlock = targetBlock; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(address toAddress, - uint targetBlock, - uint callValue) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callValue = callValue; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(address toAddress, - uint targetBlock, - uint callValue, - uint callGas) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callValue = callValue; - futureBlockTransaction.callGas = callGas; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - - /* - * - with callData - */ - function scheduleTransaction(address toAddress, - uint targetBlock, - bytes callData) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(address toAddress, - uint targetBlock, - uint callValue, - bytes callData) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callValue = callValue; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - function scheduleTransaction(address toAddress, - uint targetBlock, - uint callValue, - uint callGas, - bytes callData) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.targetBlock = targetBlock; - futureBlockTransaction.callValue = callValue; - futureBlockTransaction.callGas = callGas; - futureBlockTransaction.callData = callData; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - /* - * All fields except `requiredStackDepth` and `gracePeriod` and `donation` and `payment` + * Full scheduling API exposing all fields. * * uintArgs[0] callGas * uintArgs[1] callValue - * uintArgs[2] targetBlock - * uint8 gracePeriod; + * uintArgs[2] windowStart + * uint8 windowSize; * bytes callData; * address toAddress; */ function scheduleTransaction(address toAddress, bytes callData, + uint8 windowSize, uint[3] uintArgs) doReset public returns (address) { futureBlockTransaction.toAddress = toAddress; futureBlockTransaction.callData = callData; + futureBlockTransaction.windowSize = windowSize; futureBlockTransaction.callGas = uintArgs[0]; futureBlockTransaction.callValue = uintArgs[1]; - futureBlockTransaction.targetBlock = uintArgs[2]; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - /* - * All fields except `requiredStackDepth` and `gracePeriod` and `donation` - * - * uintArgs[0] callGas - * uintArgs[1] callValue - * uintArgs[2] payment - * uintArgs[3] targetBlock - * uint8 gracePeriod; - * bytes callData; - * address toAddress; - */ - function scheduleTransaction(address toAddress, - bytes callData, - uint[4] uintArgs) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.callData = callData; - futureBlockTransaction.callGas = uintArgs[0]; - futureBlockTransaction.callValue = uintArgs[1]; - futureBlockTransaction.payment = uintArgs[2]; - futureBlockTransaction.targetBlock = uintArgs[3]; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - /* - * All fields except `requiredStackDepth` and `gracePeriod` - * - * uintArgs[0] callGas - * uintArgs[1] callValue - * uintArgs[2] donation - * uintArgs[3] payment - * uintArgs[4] targetBlock - * uint8 gracePeriod; - * bytes callData; - * address toAddress; - */ - function scheduleTransaction(address toAddress, - bytes callData, - uint[5] uintArgs) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.callData = callData; - futureBlockTransaction.callGas = uintArgs[0]; - futureBlockTransaction.callValue = uintArgs[1]; - futureBlockTransaction.donation = uintArgs[2]; - futureBlockTransaction.payment = uintArgs[3]; - futureBlockTransaction.targetBlock = uintArgs[4]; - return futureBlockTransaction.schedule(factoryAddress, trackerAddress); - } - - /* - * All fields except `requiredStackDepth` - * - * uintArgs[0] callGas - * uintArgs[1] callValue - * uintArgs[2] donation - * uintArgs[3] payment - * uintArgs[4] targetBlock - * uint8 gracePeriod; - * bytes callData; - * address toAddress; - */ - function scheduleTransaction(address toAddress, - bytes callData, - uint8 gracePeriod, - uint[5] uintArgs) doReset public returns (address) { - futureBlockTransaction.toAddress = toAddress; - futureBlockTransaction.callData = callData; - futureBlockTransaction.gracePeriod = gracePeriod; - futureBlockTransaction.callGas = uintArgs[0]; - futureBlockTransaction.callValue = uintArgs[1]; - futureBlockTransaction.donation = uintArgs[2]; - futureBlockTransaction.payment = uintArgs[3]; - futureBlockTransaction.targetBlock = uintArgs[4]; + futureBlockTransaction.windowStart = uintArgs[2]; return futureBlockTransaction.schedule(factoryAddress, trackerAddress); } @@ -359,25 +62,25 @@ contract BlockScheduler is BaseScheduler { * uintArgs[1] callValue * uintArgs[2] donation * uintArgs[3] payment - * uintArgs[4] targetBlock - * uintArgs[5] requiredStackDepth - * uint8 gracePeriod; + * uintArgs[4] requiredStackDepth + * uintArgs[5] windowStart + * uint8 windowSize; * bytes callData; * address toAddress; */ function scheduleTransaction(address toAddress, bytes callData, - uint8 gracePeriod, + uint8 windowSize, uint[6] uintArgs) doReset public returns (address) { futureBlockTransaction.toAddress = toAddress; futureBlockTransaction.callData = callData; - futureBlockTransaction.gracePeriod = gracePeriod; + futureBlockTransaction.windowSize = windowSize; futureBlockTransaction.callGas = uintArgs[0]; futureBlockTransaction.callValue = uintArgs[1]; futureBlockTransaction.donation = uintArgs[2]; futureBlockTransaction.payment = uintArgs[3]; - futureBlockTransaction.targetBlock = uintArgs[4]; - futureBlockTransaction.requiredStackDepth = uintArgs[5]; + futureBlockTransaction.requiredStackDepth = uintArgs[4]; + futureBlockTransaction.windowStart = uintArgs[5]; return futureBlockTransaction.schedule(factoryAddress, trackerAddress); } } diff --git a/tests/block-scheduling/test_scheduling.py b/tests/block-scheduling/test_scheduling.py index 18cb0e915..cd03d18b0 100644 --- a/tests/block-scheduling/test_scheduling.py +++ b/tests/block-scheduling/test_scheduling.py @@ -10,34 +10,71 @@ def scheduler(chain, request_tracker, request_factory): return block_scheduler -def test_scheduling_with_no_args(chain, web3, denoms, scheduler, RequestData, get_txn_request): +def test_scheduling_with_full_args(chain, + web3, + denoms, + txn_recorder, + scheduler, + RequestData, + get_txn_request): + window_start = web3.eth.blockNumber + 20 schedule_txn_hash = scheduler.transact({ 'value': 10 * denoms.ether, - }).scheduleTransaction() - schedule_txn_receipt = web3.eth.getTransactionReceipt(schedule_txn_hash) + }).scheduleTransaction( + txn_recorder.address, + 'this-is-the-call-data', + 255, # windowSize + [ + 1212121, # callGas + 123454321, # callValue + 98765, # donation + 80008, # payment + 123, # requiredStackDepth + window_start, # windowStart + ], + ) + web3.eth.getTransactionReceipt(schedule_txn_hash) txn_request = get_txn_request(schedule_txn_hash) request_data = RequestData.from_contract(txn_request) - assert request_data.txnData.toAddress == web3.eth.coinbase - assert request_data.schedule.windowStart == schedule_txn_receipt['blockNumber'] + 10 + assert request_data.txnData.toAddress == txn_recorder.address + assert request_data.txnData.callData == 'this-is-the-call-data' + assert request_data.schedule.windowSize == 255 + assert request_data.txnData.callGas == 1212121 + assert request_data.paymentData.donation == 98765 + assert request_data.paymentData.payment == 80008 + assert request_data.txnData.requiredStackDepth == 123 + assert request_data.schedule.windowStart == window_start -def test_scheduling_with_specified_block(chain, +def test_scheduling_with_simplified_args(chain, web3, denoms, + txn_recorder, scheduler, RequestData, get_txn_request): - target_block = web3.eth.blockNumber + 100 + window_start = web3.eth.blockNumber + 20 schedule_txn_hash = scheduler.transact({ 'value': 10 * denoms.ether, }).scheduleTransaction( - targetBlock=target_block, + txn_recorder.address, + 'this-is-the-call-data', + 255, # windowSize + [ + 1212121, # callGas + 123454321, # callValue + window_start, # windowStart + ], ) + web3.eth.getTransactionReceipt(schedule_txn_hash) txn_request = get_txn_request(schedule_txn_hash) request_data = RequestData.from_contract(txn_request) - assert request_data.txnData.toAddress == web3.eth.coinbase - assert request_data.schedule.windowStart == target_block + assert request_data.txnData.toAddress == txn_recorder.address + assert request_data.txnData.callData == 'this-is-the-call-data' + assert request_data.schedule.windowSize == 255 + assert request_data.txnData.callGas == 1212121 + assert request_data.schedule.windowStart == window_start From 59a757d42e4839e959e3d167f7ce0704340a999b Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 19:01:37 -0700 Subject: [PATCH 13/25] some cancellation tests --- contracts/ClaimLib.sol | 9 +- contracts/PaymentLib.sol | 20 +-- contracts/RequestLib.sol | 5 +- contracts/SafeSendLib.sol | 19 ++- tests/transaction-request/test_cancelling.py | 88 ++++++++++++ tests/transaction-request/test_claiming.py | 137 +++++++++++++++++++ 6 files changed, 262 insertions(+), 16 deletions(-) create mode 100644 tests/transaction-request/test_cancelling.py create mode 100644 tests/transaction-request/test_claiming.py diff --git a/contracts/ClaimLib.sol b/contracts/ClaimLib.sol index c28d74ba0..4a61e90ef 100644 --- a/contracts/ClaimLib.sol +++ b/contracts/ClaimLib.sol @@ -55,9 +55,12 @@ library ClaimLib { uint depositAmount; depositAmount = self.claimDeposit; - // re-entrance protection. - self.claimDeposit = 0; - self.claimDeposit = depositAmount.flooredSub(self.claimedBy.safeSend(depositAmount, sendGas)); + if (depositAmount > 0) { + // re-entrance protection. + self.claimDeposit = 0; + self.claimDeposit = depositAmount.flooredSub(self.claimedBy.safeSend(depositAmount, + sendGas)); + } return true; } diff --git a/contracts/PaymentLib.sol b/contracts/PaymentLib.sol index 224fddab7..d8b5aae79 100644 --- a/contracts/PaymentLib.sol +++ b/contracts/PaymentLib.sol @@ -98,10 +98,12 @@ library PaymentLib { function sendDonation(PaymentData storage self, uint sendGas) returns (bool) { uint donationAmount = self.donationOwed; - // re-entrance protection. - self.donationOwed = 0; - self.donationOwed = donationAmount.flooredSub(self.donationBenefactor.safeSend(donationAmount, - sendGas)); + if (donationAmount > 0) { + // re-entrance protection. + self.donationOwed = 0; + self.donationOwed = donationAmount.flooredSub(self.donationBenefactor.safeSend(donationAmount, + sendGas)); + } return true; } @@ -114,10 +116,12 @@ library PaymentLib { function sendPayment(PaymentData storage self, uint sendGas) returns (bool) { uint paymentAmount = self.paymentOwed; - // re-entrance protection. - self.paymentOwed = 0; - self.paymentOwed = paymentAmount.flooredSub(self.paymentBenefactor.safeSend(paymentAmount, - sendGas)); + if (paymentAmount > 0) { + // re-entrance protection. + self.paymentOwed = 0; + self.paymentOwed = paymentAmount.flooredSub(self.paymentBenefactor.safeSend(paymentAmount, + sendGas)); + } return true; } diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index 7dc077e5b..fc5b24478 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -460,7 +460,10 @@ library RequestLib { */ function claim(Request storage self) returns (bool) { if (!isClaimable(self)) { - return false; + if (msg.sender.sendOrThrow(msg.value)) { + return false; + } + throw; } self.claimData.claim(self.schedule.computePaymentModifier()); } diff --git a/contracts/SafeSendLib.sol b/contracts/SafeSendLib.sol index a6cbb4d18..33374a25b 100644 --- a/contracts/SafeSendLib.sol +++ b/contracts/SafeSendLib.sol @@ -24,10 +24,6 @@ library SafeSendLib { * send. */ function safeSend(address to, uint value, uint sendGas) returns (uint) { - if (to == 0x0) { - throw; - } - if (value > this.balance) { value = this.balance; } @@ -36,6 +32,10 @@ library SafeSendLib { return 0; } + if (to == 0x0) { + throw; + } + if (!to.call.value(value).gas(sendGas)()) { SendFailed(to, value); return 0; @@ -43,4 +43,15 @@ library SafeSendLib { return value; } + + /* + * Try to send to the account. If the send fails, then throw. + */ + function sendOrThrow(address to, uint value) returns (bool) { + uint remainder = safeSend(to, value, msg.gas); + if (remainder > 0) { + throw; + } + return true; + } } diff --git a/tests/transaction-request/test_cancelling.py b/tests/transaction-request/test_cancelling.py new file mode 100644 index 000000000..c4432e263 --- /dev/null +++ b/tests/transaction-request/test_cancelling.py @@ -0,0 +1,88 @@ +def test_cancelling_before_claim_window(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - request_data.schedule.claimWindowSize - 3 + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.coinbase + assert request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at) + + cancel_txn_hash = txn_request.transact().cancel() + chain.wait.for_receipt(cancel_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is True + + +def test_non_owner_cannot_cancel_before_claim_window(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - request_data.schedule.claimWindowSize - 3 + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.coinbase + assert request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at) + + cancel_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).cancel() + chain.wait.for_receipt(cancel_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is False + + +def test_cancelling_during_claim_window_when_unclaimed(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - 20 + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.coinbase + assert request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at) + + cancel_txn_hash = txn_request.transact().cancel() + chain.wait.for_receipt(cancel_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is True + + +def test_not_cancellable_once_claimed(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - 20 + claim_at = cancel_at - 5 + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.coinbase + assert request_data.meta.isCancelled is False + + chain.wait.for_block(claim_at) + + claim_txn_hash = txn_request.transact({ + 'value': 2 * request_data.paymentData.payment, + 'from': web3.eth.accounts[1], + }).claim() + chain.wait.for_receipt(claim_txn_hash) + + claimed_request_data = RequestData.from_contract(txn_request) + assert claimed_request_data.claimData.claimedBy == web3.eth.coinbase + + cancel_txn_hash = txn_request.transact().cancel() + chain.wait.for_receipt(cancel_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is False diff --git a/tests/transaction-request/test_claiming.py b/tests/transaction-request/test_claiming.py new file mode 100644 index 000000000..eaf95916a --- /dev/null +++ b/tests/transaction-request/test_claiming.py @@ -0,0 +1,137 @@ +import pytest + + +def test_cannot_claim_before_first_claim_block(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + first_claim_block = request_data.schedule.windowStart - request_data.schedule.freezePeriod - request_data.schedule.claimWindowSize + + # sanity + assert first_claim_block > web3.eth.blockNumber + + chain.wait.for_block(first_claim_block - 1) + + claim_txn_hash = txn_request.transact({'value': 2 * request_data.paymentData.payment}).claim() + chain.wait.for_receipt(claim_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' + + +def test_can_claim_at_first_claim_block(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + first_claim_block = request_data.schedule.windowStart - request_data.schedule.freezePeriod - request_data.schedule.claimWindowSize + + # sanity + assert first_claim_block > web3.eth.blockNumber + + chain.wait.for_block(first_claim_block) + + claim_txn_hash = txn_request.transact({'value': 2 * request_data.paymentData.payment}).claim() + chain.wait.for_receipt(claim_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.claimData.claimedBy == web3.eth.coinbase + + +def test_can_claim_at_last_claim_block(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + last_claim_block = request_data.schedule.windowStart - request_data.schedule.freezePeriod - 1 + + # sanity + assert last_claim_block > web3.eth.blockNumber + + chain.wait.for_block(last_claim_block) + + claim_txn_hash = txn_request.transact({'value': 2 * request_data.paymentData.payment}).claim() + chain.wait.for_receipt(claim_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.claimData.claimedBy == web3.eth.coinbase + + +def test_cannot_claim_after_last_claim_block(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + last_claim_block = request_data.schedule.windowStart - request_data.schedule.freezePeriod + + # sanity + assert last_claim_block > web3.eth.blockNumber + + chain.wait.for_block(last_claim_block) + + claim_txn_hash = txn_request.transact({'value': 2 * request_data.paymentData.payment}).claim() + chain.wait.for_receipt(claim_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' + + +def test_deposit_held_by_contract_on_claim(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + claim_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - 10 + + # sanity + assert claim_at > web3.eth.blockNumber + + chain.wait.for_block(claim_at) + + deposit_amount = 2 * request_data.paymentData.payment + + before_contract_balance = web3.eth.getBalance(txn_request.address) + before_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) + + claim_txn_hash = txn_request.transact({ + 'value': deposit_amount, + 'from': web3.eth.accounts[1], + }).claim() + claim_txn_receipt = chain.wait.for_receipt(claim_txn_hash) + + after_contract_balance = web3.eth.getBalance(txn_request.address) + after_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) + + assert after_contract_balance - before_contract_balance == deposit_amount + assert before_account_balance - after_account_balance == deposit_amount + web3.eth.gasPrice * claim_txn_receipt['gasUsed'] + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.claimData.claimedBy == web3.eth.accounts[1] + + +def test_deposit_returned_if_claim_rejected(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + try_claim_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - request_data.schedule.claimWindowSize - 3 + + # sanity + assert try_claim_at > web3.eth.blockNumber + + chain.wait.for_block(try_claim_at) + + deposit_amount = 2 * request_data.paymentData.payment + + before_contract_balance = web3.eth.getBalance(txn_request.address) + before_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) + + with pytest.raises(ValueError): + txn_request.transact({ + 'value': deposit_amount, + 'from': web3.eth.accounts[1], + }).claim() + + after_contract_balance = web3.eth.getBalance(txn_request.address) + after_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) + + assert after_contract_balance == before_contract_balance + assert after_account_balance == before_account_balance + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' From babaf23ef2aa62b95b697d664c3f5a96397ac1b7 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 19:03:26 -0700 Subject: [PATCH 14/25] fix test --- tests/transaction-request/test_cancelling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/transaction-request/test_cancelling.py b/tests/transaction-request/test_cancelling.py index c4432e263..b60c7574f 100644 --- a/tests/transaction-request/test_cancelling.py +++ b/tests/transaction-request/test_cancelling.py @@ -79,7 +79,7 @@ def test_not_cancellable_once_claimed(chain, web3, RequestData): chain.wait.for_receipt(claim_txn_hash) claimed_request_data = RequestData.from_contract(txn_request) - assert claimed_request_data.claimData.claimedBy == web3.eth.coinbase + assert claimed_request_data.claimData.claimedBy == web3.eth.accounts[1] cancel_txn_hash = txn_request.transact().cancel() chain.wait.for_receipt(cancel_txn_hash) From 7331184ed88d30d73c400483caa27ec352a5523f Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 20:35:57 -0700 Subject: [PATCH 15/25] attempt to send back scheduling ether --- contracts/BlockSchedulerLib.sol | 11 ++- contracts/RequestFactory.sol | 10 +- contracts/RequestLib.sol | 71 ++++++++++---- contracts/SafeSendLib.sol | 4 +- contracts/Scheduler.sol | 7 ++ tests/block-scheduling/test_scheduling.py | 34 +++++++ tests/conftest.py | 46 ++++++++++ tests/transaction-request/test_cancelling.py | 97 ++++++++++++++++++++ 8 files changed, 257 insertions(+), 23 deletions(-) diff --git a/contracts/BlockSchedulerLib.sol b/contracts/BlockSchedulerLib.sol index 321e7a34d..9e48f5af5 100644 --- a/contracts/BlockSchedulerLib.sol +++ b/contracts/BlockSchedulerLib.sol @@ -3,9 +3,12 @@ import {RequestFactoryInterface} from "contracts/RequestFactoryInterface.sol"; import {RequestTrackerInterface} from "contracts/RequestTrackerInterface.sol"; import {PaymentLib} from "contracts/PaymentLib.sol"; +import {SafeSendLib} from "contracts/SafeSendLib.sol"; library FutureBlockTransactionLib { + using SafeSendLib for address; + address constant DONATION_BENEFACTOR = 0xd3cda913deb6f67967b99d67acdfa1712c293601; struct FutureBlockTransaction { @@ -71,8 +74,14 @@ library FutureBlockTransactionLib { ); if (newRequestAddress == 0x0) { - // something went wrong.... + // Something went wrong during creation (likely a ValidationError). + // Try to return the ether that was sent. If this fails then + // resort to throwing an exception to force reversion. return 0x0; + if (msg.sender.sendOrThrow(msg.value)) { + return 0x0; + } + throw; } var tracker = RequestTrackerInterface(trackerAddress); diff --git a/contracts/RequestFactory.sol b/contracts/RequestFactory.sol index 4e9078cbf..a30f7a12a 100644 --- a/contracts/RequestFactory.sol +++ b/contracts/RequestFactory.sol @@ -3,11 +3,13 @@ import {RequestFactoryInterface} from "contracts/RequestFactoryInterface.sol"; import {TransactionRequest} from "contracts/TransactionRequest.sol"; import {RequestLib} from "contracts/RequestLib.sol"; +import {SafeSendLib} from "contracts/SafeSendLib.sol"; import {IterTools} from "contracts/IterTools.sol"; contract RequestFactory is RequestFactoryInterface { using IterTools for bool[7]; + using SafeSendLib for address; /* * ValidationError @@ -65,7 +67,13 @@ contract RequestFactory is RequestFactoryInterface { if (!is_valid[4]) ValidationError(Errors.InvalidRequiredStackDepth); if (!is_valid[5]) ValidationError(Errors.CallGasTooHigh); if (!is_valid[6]) ValidationError(Errors.EmptyToAddress); - return 0x0; + + // Try to return the ether sent with the message. If this failed + // then throw to force it to be returned. + if (msg.sender.sendOrThrow(msg.value)) { + return 0x0; + } + throw; } var request = (new TransactionRequest).value(msg.value)( diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index fc5b24478..2b5d66117 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -94,7 +94,7 @@ library RequestLib { request.schedule.freezePeriod, request.schedule.windowStart); is_valid[4] = ExecutionLib.validateRequiredStackDepth(request.txnData.requiredStackDepth); - is_valid[5] = ExecutionLib.validateCallGas(request.txnData.callGas, _EXTRA_GAS); + is_valid[5] = ExecutionLib.validateCallGas(request.txnData.callGas, _EXECUTE_EXTRA_GAS); is_valid[6] = ExecutionLib.validateToAddress(request.txnData.toAddress); return is_valid; @@ -249,6 +249,9 @@ library RequestLib { InsufficientGas } + // TODO: maybe cancel reward. + event Cancelled(uint rewardPayment, uint measuredGasConsumption); + event Claimed(); event Aborted(Reason reason); event Executed(uint payment, uint donation, uint measuredGasConsumption); @@ -308,8 +311,6 @@ library RequestLib { // Send the transaction self.meta.wasSuccessful = self.txnData.sendTransaction(); - if (self.paymentData.getDonation() == 0) throw; - // Compute the donation amount if (self.paymentData.hasBenefactor()) { self.paymentData.donationOwed = self.paymentData.getDonation() @@ -331,11 +332,11 @@ library RequestLib { } // Record the amount of gas used by execution. - uint measuredGasConsumption = startGas.flooredSub(msg.gas).safeAdd(_EXTRA_GAS); + uint measuredGasConsumption = startGas.flooredSub(msg.gas).safeAdd(_EXECUTE_EXTRA_GAS); - // +--------------------------------------------------------------+ - // | NOTE: All code after this must be accounted for by EXTRA_GAS | - // +--------------------------------------------------------------+ + // +----------------------------------------------------------------------+ + // | NOTE: All code after this must be accounted for by EXECUTE_EXTRA_GAS | + // +----------------------------------------------------------------------+ // Add the gas reimbursment amount to the payment. self.paymentData.paymentOwed = measuredGasConsumption.safeMultiply(tx.gasprice) @@ -364,36 +365,35 @@ library RequestLib { .safeAdd(_GAS_TO_COMPLETE_EXECUTION); } - // TODO: compute this - uint constant _GAS_TO_AUTHORIZE_EXECUTION = 0; - /* * The amount of gas needed to do all of the pre execution checks. */ + // TODO: measure this. + uint constant _GAS_TO_AUTHORIZE_EXECUTION = 0; + function GAS_TO_AUTHORIZE_EXECUTION() returns (uint) { return _GAS_TO_AUTHORIZE_EXECUTION; } - // TODO: compute this - uint constant _GAS_TO_COMPLETE_EXECUTION = 190000; - /* * The amount of gas needed to complete the execute method after * the transaction has been sent. */ + uint constant _GAS_TO_COMPLETE_EXECUTION = 190000; + function GAS_TO_COMPLETE_EXECUTION() returns (uint) { return _GAS_TO_COMPLETE_EXECUTION; } - // TODO: compute this - uint constant _EXTRA_GAS = 185000; - + /* * The amount of gas used by the portion of the `execute` function * that cannot be accounted for via gas tracking. */ - function EXTRA_GAS() returns (uint) { - return _EXTRA_GAS; + uint constant _EXECUTE_EXTRA_GAS = 185000; + + function EXECUTE_EXTRA_GAS() returns (uint) { + return _EXECUTE_EXTRA_GAS; } /* @@ -417,11 +417,27 @@ library RequestLib { } } + /* + * Constant value to account for the gas usage that cannot be accounted + * for using gas-tracking within the `cancel` function. + */ + uint constant _CANCEL_EXTRA_GAS = 0; + + function CANCEL_EXTRA_GAS() returns (uint) { + return _CANCEL_EXTRA_GAS; + } + /* * Cancel the transaction request, attempting to send all appropriate - * refunds. + * refunds. To incentivise cancellation by other parties, a small reward + * payment is issued to the party that cancels the request if they are not + * the owner. */ function cancel(Request storage self) returns (bool) { + uint startGas = msg.gas; + uint rewardPayment; + uint measuredGasConsumption; + if (!isCancellable(self)) { return false; } @@ -432,6 +448,21 @@ library RequestLib { // refund any claim deposit. self.claimData.refundDeposit(); + // send a reward to the canceller if it isn't the owner. This also + // guarantees that it is being cancelled after the call window since + // the `isCancellable()` function checks this. + if (msg.sender != self.meta.owner) { + rewardPayment = self.paymentData.payment.safeMultiply(self.paymentData.getMultiplier()); + measuredGasConsumption = startGas.flooredSub(msg.gas) + .safeAdd(_CANCEL_EXTRA_GAS); + rewardPayment = measuredGasConsumption.safeMultiply(tx.gasprice) + .safeAdd(rewardPayment); + msg.sender.safeSend(rewardPayment); + } + + // Log the event + Cancelled(rewardPayment, measuredGasConsumption); + // send the remaining ether to the owner. sendOwnerEther(self); @@ -466,6 +497,8 @@ library RequestLib { throw; } self.claimData.claim(self.schedule.computePaymentModifier()); + Claimed(); + return true; } /* diff --git a/contracts/SafeSendLib.sol b/contracts/SafeSendLib.sol index 33374a25b..60531bb67 100644 --- a/contracts/SafeSendLib.sol +++ b/contracts/SafeSendLib.sol @@ -33,7 +33,7 @@ library SafeSendLib { } if (to == 0x0) { - throw; + //throw; } if (!to.call.value(value).gas(sendGas)()) { @@ -50,7 +50,7 @@ library SafeSendLib { function sendOrThrow(address to, uint value) returns (bool) { uint remainder = safeSend(to, value, msg.gas); if (remainder > 0) { - throw; + //throw; } return true; } diff --git a/contracts/Scheduler.sol b/contracts/Scheduler.sol index 16e201e5e..2947643a9 100644 --- a/contracts/Scheduler.sol +++ b/contracts/Scheduler.sol @@ -32,6 +32,13 @@ contract BlockScheduler is BaseScheduler { _ } + /* + * Fallback function to be able to receive ether. This can occur + * legidimately when scheduling fails due to a validation error. + */ + function() { + } + /* * Full scheduling API exposing all fields. * diff --git a/tests/block-scheduling/test_scheduling.py b/tests/block-scheduling/test_scheduling.py index cd03d18b0..471994929 100644 --- a/tests/block-scheduling/test_scheduling.py +++ b/tests/block-scheduling/test_scheduling.py @@ -78,3 +78,37 @@ def test_scheduling_with_simplified_args(chain, assert request_data.schedule.windowSize == 255 assert request_data.txnData.callGas == 1212121 assert request_data.schedule.windowStart == window_start + + +def test_invalid_schedule_returns_ether(chain, + web3, + denoms, + txn_recorder, + scheduler, + RequestData, + get_txn_request): + latest_block = web3.eth.getBlock('latest') + window_start = web3.eth.blockNumber + 20 + + before_balance = web3.eth.getBalance(web3.eth.accounts[1]) + + schedule_txn_hash = scheduler.transact({ + 'value': 10 * denoms.ether, + 'from': web3.eth.accounts[1], + }).scheduleTransaction( + txn_recorder.address, + 'this-is-the-call-data', + 0, # windowSize + [ + latest_block['gasLimit'], # callGas - too high a value. + 123454321, # callValue + window_start, # windowStart + ], + ) + schedule_txn_receipt = web3.eth.getTransactionReceipt(schedule_txn_hash) + + after_balance = web3.eth.getBalance(web3.eth.accounts[1]) + assert before_balance - after_balance == schedule_txn_receipt['gasUsed'] * web3.eth.gasPrice + + with pytest.raises(AssertionError): + get_txn_request(schedule_txn_hash) diff --git a/tests/conftest.py b/tests/conftest.py index cdc9f44d5..d5449887c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -364,6 +364,52 @@ def _get_execute_data(execute_txn_hash): return _get_execute_data +@pytest.fixture() +def get_claim_data(chain, web3, RequestLib, logs_to_event_data): + def _get_claim_data(claim_txn_hash): + claim_txn_receipt = chain.wait.for_receipt(claim_txn_hash) + claim_filter = RequestLib.pastEvents('Claimed', { + 'fromBlock': claim_txn_receipt['blockNumber'], + 'toBlock': claim_txn_receipt['blockNumber'], + }) + claim_logs = claim_filter.get() + if len(claim_logs) == 0: + decoded_events = logs_to_event_data(claim_txn_receipt['logs']) + if decoded_events: + raise AssertionError( + "Something went wrong. The following events were found in" + "the logs for the given transaction hash:\n" + "{0}".format('\n'.join(decoded_events)) + ) + raise AssertionError("Something went wrong. No 'Claimed' log entries found") + claim_data = claim_logs[0] + return claim_data + return _get_claim_data + + +@pytest.fixture() +def get_cancel_data(chain, web3, RequestLib, logs_to_event_data): + def _get_cancel_data(cancel_txn_hash): + cancel_txn_receipt = chain.wait.for_receipt(cancel_txn_hash) + cancel_filter = RequestLib.pastEvents('Cancelled', { + 'fromBlock': cancel_txn_receipt['blockNumber'], + 'toBlock': cancel_txn_receipt['blockNumber'], + }) + cancel_logs = cancel_filter.get() + if len(cancel_logs) == 0: + decoded_events = logs_to_event_data(cancel_txn_receipt['logs']) + if decoded_events: + raise AssertionError( + "Something went wrong. The following events were found in" + "the logs for the given transaction hash:\n" + "{0}".format('\n'.join(decoded_events)) + ) + raise AssertionError("Something went wrong. No 'Cancelled' log entries found") + cancel_data = cancel_logs[0] + return cancel_data + return _get_cancel_data + + @pytest.fixture() def logs_to_event_data(TopicMap): from web3.utils.events import ( diff --git a/tests/transaction-request/test_cancelling.py b/tests/transaction-request/test_cancelling.py index b60c7574f..c1dd6cbae 100644 --- a/tests/transaction-request/test_cancelling.py +++ b/tests/transaction-request/test_cancelling.py @@ -86,3 +86,100 @@ def test_not_cancellable_once_claimed(chain, web3, RequestData): updated_request_data = RequestData.from_contract(txn_request) assert updated_request_data.meta.isCancelled is False + + +def test_not_cancellable_during_freeze_window(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.coinbase + assert request_data.meta.isCancelled is False + + cancel_txn_hash = txn_request.transact().cancel() + chain.wait.for_receipt(cancel_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is False + + +def test_not_cancellable_during_execution_window(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.coinbase + assert request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at) + + cancel_txn_hash = txn_request.transact().cancel() + chain.wait.for_receipt(cancel_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is False + + +def test_not_cancellable_if_was_called(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + execute_at = request_data.schedule.windowStart + cancel_at_first = request_data.schedule.windowStart + 10 + cancel_at_second = request_data.schedule.windowStart + request_data.schedule.windowSize + 5 + + # sanity + assert execute_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.coinbase + assert request_data.meta.isCancelled is False + + chain.wait.for_block(execute_at) + + execute_txn_hash = txn_request.transact().execute() + chain.wait.for_receipt(execute_txn_hash) + + after_execute_request_data = RequestData.from_contract(txn_request) + assert after_execute_request_data.meta.wasCalled is True + assert after_execute_request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at_first) + + first_cancel_txn_hash = txn_request.transact().cancel() + chain.wait.for_receipt(first_cancel_txn_hash) + + after_first_cancel_request_data = RequestData.from_contract(txn_request) + assert after_first_cancel_request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at_second) + + second_cancel_txn_hash = txn_request.transact().cancel() + chain.wait.for_receipt(second_cancel_txn_hash) + + after_second_cancel_request_data = RequestData.from_contract(txn_request) + assert after_second_cancel_request_data.meta.isCancelled is False + + +def test_cancellable_if_call_is_missed(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart + request_data.schedule.windowSize + 10 + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.coinbase + assert request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at) + + cancel_txn_hash = txn_request.transact().cancel() + chain.wait.for_receipt(cancel_txn_hash) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is True From 27c28bf824cec29ec040814f6f8ab7a56c42b90d Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 17 Sep 2016 23:59:28 -0700 Subject: [PATCH 16/25] more cancel tests --- contracts/BlockSchedulerLib.sol | 1 - contracts/RequestLib.sol | 52 +++---- contracts/SafeSendLib.sol | 20 ++- tests/transaction-request/test_cancelling.py | 136 +++++++++++++++++++ 4 files changed, 178 insertions(+), 31 deletions(-) diff --git a/contracts/BlockSchedulerLib.sol b/contracts/BlockSchedulerLib.sol index 9e48f5af5..a9190face 100644 --- a/contracts/BlockSchedulerLib.sol +++ b/contracts/BlockSchedulerLib.sol @@ -77,7 +77,6 @@ library FutureBlockTransactionLib { // Something went wrong during creation (likely a ValidationError). // Try to return the ether that was sent. If this fails then // resort to throwing an exception to force reversion. - return 0x0; if (msg.sender.sendOrThrow(msg.value)) { return 0x0; } diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index 2b5d66117..19aa5b086 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -34,6 +34,22 @@ library RequestLib { SerializedRequest serializedValues; } + enum AbortReason { + WasCancelled, + AlreadyCalled, + BeforeCallWindow, + AfterCallWindow, + ReservedForClaimer, + StackTooDeep, + InsufficientGas + } + + // TODO: maybe cancel reward. + event Cancelled(uint rewardPayment, uint measuredGasConsumption); + event Claimed(); + event Aborted(AbortReason reason); + event Executed(uint payment, uint donation, uint measuredGasConsumption); + /* * Validate the initialization parameters for a transaction request. */ @@ -239,22 +255,6 @@ library RequestLib { self.claimData.paymentModifier = uint8Values[0]; } - enum Reason { - WasCancelled, - AlreadyCalled, - BeforeCallWindow, - AfterCallWindow, - ReservedForClaimer, - StackTooDeep, - InsufficientGas - } - - // TODO: maybe cancel reward. - event Cancelled(uint rewardPayment, uint measuredGasConsumption); - event Claimed(); - event Aborted(Reason reason); - event Executed(uint payment, uint donation, uint measuredGasConsumption); - function execute(Request storage self) returns (bool) { /* * Send the requested transaction. @@ -280,27 +280,27 @@ library RequestLib { var startGas = msg.gas; if (msg.gas < requiredExecutionGas(self)) { - Aborted(Reason.InsufficientGas); + Aborted(AbortReason.InsufficientGas); return false; } else if (self.meta.wasCalled) { - Aborted(Reason.AlreadyCalled); + Aborted(AbortReason.AlreadyCalled); return false; } else if (self.meta.isCancelled) { - Aborted(Reason.WasCancelled); + Aborted(AbortReason.WasCancelled); return false; } else if (self.schedule.isBeforeWindow()) { - Aborted(Reason.BeforeCallWindow); + Aborted(AbortReason.BeforeCallWindow); return false; } else if (self.schedule.isAfterWindow()) { - Aborted(Reason.AfterCallWindow); + Aborted(AbortReason.AfterCallWindow); return false; } else if (self.claimData.isClaimed() && msg.sender != self.claimData.claimedBy && self.schedule.inReservedWindow()) { - Aborted(Reason.ReservedForClaimer); + Aborted(AbortReason.ReservedForClaimer); return false; } else if (msg.sender != tx.origin && !self.txnData.stackCanBeExtended()) { - Aborted(Reason.StackTooDeep); + Aborted(AbortReason.StackTooDeep); return false; } @@ -421,7 +421,7 @@ library RequestLib { * Constant value to account for the gas usage that cannot be accounted * for using gas-tracking within the `cancel` function. */ - uint constant _CANCEL_EXTRA_GAS = 0; + uint constant _CANCEL_EXTRA_GAS = 85000; function CANCEL_EXTRA_GAS() returns (uint) { return _CANCEL_EXTRA_GAS; @@ -452,9 +452,9 @@ library RequestLib { // guarantees that it is being cancelled after the call window since // the `isCancellable()` function checks this. if (msg.sender != self.meta.owner) { - rewardPayment = self.paymentData.payment.safeMultiply(self.paymentData.getMultiplier()); + rewardPayment = self.paymentData.payment.safeMultiply(self.paymentData.getMultiplier()) / 100 / 100; measuredGasConsumption = startGas.flooredSub(msg.gas) - .safeAdd(_CANCEL_EXTRA_GAS); + .safeAdd(_CANCEL_EXTRA_GAS); rewardPayment = measuredGasConsumption.safeMultiply(tx.gasprice) .safeAdd(rewardPayment); msg.sender.safeSend(rewardPayment); diff --git a/contracts/SafeSendLib.sol b/contracts/SafeSendLib.sol index 60531bb67..6d33d51c8 100644 --- a/contracts/SafeSendLib.sol +++ b/contracts/SafeSendLib.sol @@ -33,7 +33,7 @@ library SafeSendLib { } if (to == 0x0) { - //throw; + throw; } if (!to.call.value(value).gas(sendGas)()) { @@ -48,10 +48,22 @@ library SafeSendLib { * Try to send to the account. If the send fails, then throw. */ function sendOrThrow(address to, uint value) returns (bool) { - uint remainder = safeSend(to, value, msg.gas); - if (remainder > 0) { - //throw; + if (value > this.balance) { + throw; + } + + if (value == 0) { + return true; + } + + if (to == 0x0) { + throw; } + + if (!to.call.value(value)()) { + throw; + } + return true; } } diff --git a/tests/transaction-request/test_cancelling.py b/tests/transaction-request/test_cancelling.py index c1dd6cbae..db752a66e 100644 --- a/tests/transaction-request/test_cancelling.py +++ b/tests/transaction-request/test_cancelling.py @@ -183,3 +183,139 @@ def test_cancellable_if_call_is_missed(chain, web3, RequestData): updated_request_data = RequestData.from_contract(txn_request) assert updated_request_data.meta.isCancelled is True + + +def test_accounting_for_pre_execution_cancellation(chain, + web3, + denoms, + RequestData, + get_cancel_data): + txn_request = RequestData( + windowStart=web3.eth.blockNumber + 255 + 10 + 5, + owner=web3.eth.accounts[1], + ).direct_deploy({ + 'from': web3.eth.accounts[1], + 'value': 10 * denoms.ether, + }) + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - 5 + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.accounts[1] + assert request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at) + + before_cancel_balance = web3.eth.getBalance(web3.eth.accounts[1]) + before_contract_balance = web3.eth.getBalance(txn_request.address) + + cancel_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).cancel() + cancel_txn_receipt = chain.wait.for_receipt(cancel_txn_hash) + + after_cancel_balance = web3.eth.getBalance(web3.eth.accounts[1]) + after_contract_balance = web3.eth.getBalance(txn_request.address) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is True + + cancel_data = get_cancel_data(cancel_txn_hash) + # since this was cancelled by the owner. + assert cancel_data['args']['rewardPayment'] == 0 + assert cancel_data['args']['measuredGasConsumption'] == 0 + + assert before_contract_balance == 10 * denoms.ether + assert after_contract_balance == 0 + + assert after_cancel_balance - before_cancel_balance == 10 * denoms.ether - cancel_txn_receipt['gasUsed'] * web3.eth.gasPrice + + +def test_accounting_for_missed_execution_cancellation_by_owner(chain, + web3, + denoms, + RequestData, + get_cancel_data): + txn_request = RequestData( + windowStart=web3.eth.blockNumber + 255 + 10 + 5, + owner=web3.eth.accounts[1], + ).direct_deploy({ + 'from': web3.eth.accounts[1], + 'value': 10 * denoms.ether, + }) + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart + request_data.schedule.windowSize + 1 + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.accounts[1] + assert request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at) + + before_cancel_balance = web3.eth.getBalance(web3.eth.accounts[1]) + before_contract_balance = web3.eth.getBalance(txn_request.address) + + cancel_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).cancel() + cancel_txn_receipt = chain.wait.for_receipt(cancel_txn_hash) + + after_cancel_balance = web3.eth.getBalance(web3.eth.accounts[1]) + after_contract_balance = web3.eth.getBalance(txn_request.address) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is True + + cancel_data = get_cancel_data(cancel_txn_hash) + # since this was cancelled by the owner. + assert cancel_data['args']['rewardPayment'] == 0 + assert cancel_data['args']['measuredGasConsumption'] == 0 + + assert before_contract_balance == 10 * denoms.ether + assert after_contract_balance == 0 + + assert after_cancel_balance - before_cancel_balance == 10 * denoms.ether - cancel_txn_receipt['gasUsed'] * web3.eth.gasPrice + + +def test_accounting_for_missed_execution_cancellation_not_by_owner(chain, + web3, + denoms, + RequestData, + get_cancel_data): + txn_request = RequestData( + windowStart=web3.eth.blockNumber + 255 + 10 + 5, + owner=web3.eth.coinbase, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + cancel_at = request_data.schedule.windowStart + request_data.schedule.windowSize + 1 + + # sanity + assert cancel_at > web3.eth.blockNumber + assert request_data.meta.owner == web3.eth.coinbase + assert request_data.meta.isCancelled is False + + chain.wait.for_block(cancel_at) + + before_cancel_balance = web3.eth.getBalance(web3.eth.accounts[1]) + before_contract_balance = web3.eth.getBalance(txn_request.address) + + cancel_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).cancel() + cancel_txn_receipt = chain.wait.for_receipt(cancel_txn_hash) + + after_cancel_balance = web3.eth.getBalance(web3.eth.accounts[1]) + after_contract_balance = web3.eth.getBalance(txn_request.address) + + updated_request_data = RequestData.from_contract(txn_request) + assert updated_request_data.meta.isCancelled is True + + cancel_data = get_cancel_data(cancel_txn_hash) + measured_gas_consumption = cancel_data['args']['measuredGasConsumption'] + assert measured_gas_consumption >= cancel_txn_receipt['gasUsed'] + + assert cancel_data['args']['rewardPayment'] == measured_gas_consumption * web3.eth.gasPrice + updated_request_data.paymentData.payment // 100 + + assert before_contract_balance == 10 * denoms.ether + assert after_contract_balance == 0 + + assert after_cancel_balance - before_cancel_balance == cancel_data['args']['rewardPayment'] - cancel_txn_receipt['gasUsed'] * web3.eth.gasPrice From c9b7572d26cde028d953ebed6bf8555eb988fa9a Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sun, 18 Sep 2016 02:07:20 -0700 Subject: [PATCH 17/25] tests for execution authorization --- contracts/RequestLib.sol | 68 +++++-- tests/Proxy.sol | 13 ++ tests/TestErrors.sol | 9 +- tests/TransactionRecorder.sol | 16 +- tests/conftest.py | 79 +++++-- .../transaction-request/test_authorization.py | 192 ++++++++++++++++++ tests/transaction-request/test_execution.py | 28 +++ 7 files changed, 368 insertions(+), 37 deletions(-) create mode 100644 tests/Proxy.sol create mode 100644 tests/transaction-request/test_authorization.py create mode 100644 tests/transaction-request/test_execution.py diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index 19aa5b086..eb3af15cb 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -44,10 +44,12 @@ library RequestLib { InsufficientGas } - // TODO: maybe cancel reward. event Cancelled(uint rewardPayment, uint measuredGasConsumption); event Claimed(); - event Aborted(AbortReason reason); + // TODO: Figure out how log topics are constructed for events that use + // Enums as args. + //event Aborted(AbortReason reason); + event Aborted(uint8 reason); event Executed(uint payment, uint donation, uint measuredGasConsumption); /* @@ -257,7 +259,11 @@ library RequestLib { function execute(Request storage self) returns (bool) { /* - * Send the requested transaction. + * Execute the TransactionRequest + * + * +---------------------+ + * | Phase 1: Accounting | + * +---------------------+ * * Must pass all of the following checks: * @@ -276,41 +282,75 @@ library RequestLib { * 6. if (msg.sender != tx.origin): * - Verify stack can be increased by requiredStackDepth * 7. msg.gas >= callGas + * + * +--------------------+ + * | Phase 2: Execution | + * +--------------------+ + * + * 1. Mark as called (must be before actual execution to prevent + * re-entrance. + * 2. Send Transaction and record success or failure. + * + * +---------------------+ + * | Phase 3: Accounting | + * +---------------------+ + * + * 1. Calculate and send donation amount. + * 2. Calculate and send payment amount. + * 3. Send remaining ether back to owner. + * */ var startGas = msg.gas; + // +----------------------+ + // | Begin: Authorization | + // +----------------------+ + if (msg.gas < requiredExecutionGas(self)) { - Aborted(AbortReason.InsufficientGas); + Aborted(uint8(AbortReason.InsufficientGas)); return false; } else if (self.meta.wasCalled) { - Aborted(AbortReason.AlreadyCalled); + Aborted(uint8(AbortReason.AlreadyCalled)); return false; } else if (self.meta.isCancelled) { - Aborted(AbortReason.WasCancelled); + Aborted(uint8(AbortReason.WasCancelled)); return false; } else if (self.schedule.isBeforeWindow()) { - Aborted(AbortReason.BeforeCallWindow); + Aborted(uint8(AbortReason.BeforeCallWindow)); return false; } else if (self.schedule.isAfterWindow()) { - Aborted(AbortReason.AfterCallWindow); + Aborted(uint8(AbortReason.AfterCallWindow)); return false; } else if (self.claimData.isClaimed() && msg.sender != self.claimData.claimedBy && self.schedule.inReservedWindow()) { - Aborted(AbortReason.ReservedForClaimer); + Aborted(uint8(AbortReason.ReservedForClaimer)); return false; } else if (msg.sender != tx.origin && !self.txnData.stackCanBeExtended()) { - Aborted(AbortReason.StackTooDeep); + Aborted(uint8(AbortReason.StackTooDeep)); return false; } - // Ensure the request is marked as having been called before sending - // the transaction to prevent re-entrance. + // +--------------------+ + // | End: Authorization | + // +--------------------+ + // +------------------+ + // | Begin: Execution | + // +------------------+ + + // Mark as being called before sending transaction to prevent re-entrance self.meta.wasCalled = true; // Send the transaction self.meta.wasSuccessful = self.txnData.sendTransaction(); + // +----------------+ + // | End: Execution | + // +----------------+ + // +-------------------+ + // | Begin: Accounting | + // +-------------------+ + // Compute the donation amount if (self.paymentData.hasBenefactor()) { self.paymentData.donationOwed = self.paymentData.getDonation() @@ -357,6 +397,10 @@ library RequestLib { // Send all extra ether back to the owner. sendOwnerEther(self); + // +-----------------+ + // | End: Accounting | + // +-----------------+ + return true; } diff --git a/tests/Proxy.sol b/tests/Proxy.sol new file mode 100644 index 000000000..ae8643e4d --- /dev/null +++ b/tests/Proxy.sol @@ -0,0 +1,13 @@ +contract Proxy { + function __proxy(address to) returns (bool) { + return to.call.value(msg.value)(); + } + + function __proxy(address to, bytes callData) returns (bool) { + return to.call.value(msg.value)(callData); + } + + function __proxy(address to, bytes callData, uint callGas) returns (bool) { + return to.call.value(msg.value).gas(callGas)(callData); + } +} diff --git a/tests/TestErrors.sol b/tests/TestErrors.sol index 3a424278a..381226809 100644 --- a/tests/TestErrors.sol +++ b/tests/TestErrors.sol @@ -1,4 +1,7 @@ -contract ErrorGenerator { +import {Proxy} from "tests/Proxy.sol"; + + +contract ErrorGenerator is Proxy { function doThrow() { doThrow(true); } @@ -12,8 +15,4 @@ contract ErrorGenerator { function() { throw; } - - function __proxy(address to, bytes callData) returns (bool) { - return to.call(callData); - } } diff --git a/tests/TransactionRecorder.sol b/tests/TransactionRecorder.sol index ff003d9f7..2a30417e8 100644 --- a/tests/TransactionRecorder.sol +++ b/tests/TransactionRecorder.sol @@ -1,4 +1,9 @@ -contract TransactionRecorder { +import {Proxy} from "tests/Proxy.sol"; + + +contract TransactionRecorder is Proxy { + bool public wasCalled; + uint public lastCallValue; address public lastCaller; bytes public lastCallData; @@ -9,5 +14,14 @@ contract TransactionRecorder { lastCallData = msg.data; lastCaller = msg.sender; lastCallValue = msg.value; + wasCalled = true; + } + + function __reset__() public { + lastCallGas = 0; + lastCallData = ''; + lastCaller = 0x0; + lastCallValue = 0; + wasCalled = false; } } diff --git a/tests/conftest.py b/tests/conftest.py index d5449887c..f964d858e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -24,8 +24,13 @@ def request_factory(chain, web3): @pytest.fixture() -def RequestLib(chain): - return type(chain.get_contract('RequestLib')) +def request_lib(chain): + return chain.get_contract('RequestLib') + + +@pytest.fixture() +def RequestLib(request_lib): + return type(request_lib) @pytest.fixture() @@ -61,6 +66,8 @@ def RequestData(chain, txn_recorder, TransactionRequest): class _RequestData(object): + _contract = None + def __init__(self, # claim claimedBy=NULL_ADDRESS, @@ -223,13 +230,20 @@ def direct_deploy(self, deploy_txn=None): txn_request_address = chain.wait.for_contract_address(deploy_txn_hash) return TransactionRequest(address=txn_request_address) + def refresh(self): + if not self._contract: + raise ValueError("No contract set") + self.__dict__.update(self.from_contract(self._contract).__dict__) + @classmethod def from_contract(cls, txn_request): address_args, bool_args, uint_args, uint8_args = txn_request.call().requestData() call_data = txn_request.call().callData() - return cls.from_deserialize( + instance = cls.from_deserialize( address_args, bool_args, uint_args, uint8_args, call_data, ) + instance._contract = txn_request + return instance @classmethod def from_deserialize(cls, address_args, bool_args, uint_args, uint8_args, call_data): @@ -320,8 +334,8 @@ def _get_txn_request(txn_hash): return _get_txn_request -@pytest.fixture() -def AbortReasons(): +@pytest.fixture +def ABORT_REASONS_ENUM_KEYS(): return ( 'WasCancelled', 'AlreadyCalled', @@ -334,23 +348,22 @@ def AbortReasons(): @pytest.fixture() -def get_execute_data(chain, web3, RequestLib, AbortReasons, logs_to_event_data): - def _get_execute_data(execute_txn_hash): +def AbortReasons(ABORT_REASONS_ENUM_KEYS): + return type('AbortReasons', (object,), { + name: idx for idx, name in enumerate(ABORT_REASONS_ENUM_KEYS) + }) + + +@pytest.fixture() +def get_abort_data(chain, web3, RequestLib, logs_to_event_data): + def _get_abort_data(execute_txn_hash): execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - execute_filter = RequestLib.pastEvents('Executed', { + abort_filter = RequestLib.pastEvents('Aborted', { 'fromBlock': execute_txn_receipt['blockNumber'], 'toBlock': execute_txn_receipt['blockNumber'], }) - execute_logs = execute_filter.get() - if len(execute_logs) == 0: - abort_filter = RequestLib.pastEvents('Aborted', { - 'fromBlock': execute_txn_receipt['blockNumber'], - 'toBlock': execute_txn_receipt['blockNumber'], - }) - abort_logs = abort_filter.get() - if abort_logs: - errors = [AbortReasons[entry['args']['reason']] for entry in abort_logs] - raise AssertionError("Execution Failed: {0}".format(', '.join(errors))) + abort_logs = abort_filter.get() + if len(abort_logs) == 0: decoded_events = logs_to_event_data(execute_txn_receipt['logs']) if decoded_events: raise AssertionError( @@ -358,7 +371,24 @@ def _get_execute_data(execute_txn_hash): "the logs for the given transaction hash:\n" "{0}".format('\n'.join(decoded_events)) ) - raise AssertionError("Something went wrong. No 'Executed' log entries found") + raise AssertionError("Something went wrong. No 'Aborted' log entries found") + return abort_logs + return _get_abort_data + + +@pytest.fixture() +def get_execute_data(chain, web3, RequestLib, ABORT_REASONS_ENUM_KEYS, get_abort_data): + def _get_execute_data(execute_txn_hash): + execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) + execute_filter = RequestLib.pastEvents('Executed', { + 'fromBlock': execute_txn_receipt['blockNumber'], + 'toBlock': execute_txn_receipt['blockNumber'], + }) + execute_logs = execute_filter.get() + if len(execute_logs) == 0: + abort_logs = get_abort_data(execute_txn_hash) + errors = [ABORT_REASONS_ENUM_KEYS[entry['args']['reason']] for entry in abort_logs] + raise AssertionError("Execution Failed: {0}".format(', '.join(errors))) execute_data = execute_logs[0] return execute_data return _get_execute_data @@ -479,3 +509,14 @@ def TransactionRecorder(test_contract_factories): def txn_recorder(chain, TransactionRecorder): chain.contract_factories['TransactionRecorder'] = TransactionRecorder return chain.get_contract('TransactionRecorder') + + +@pytest.fixture() +def Proxy(test_contract_factories): + return test_contract_factories.Proxy + + +@pytest.fixture() +def proxy(chain, Proxy): + chain.contract_factories['Proxy'] = Proxy + return chain.get_contract('Proxy') diff --git a/tests/transaction-request/test_authorization.py b/tests/transaction-request/test_authorization.py new file mode 100644 index 000000000..e3a74158b --- /dev/null +++ b/tests/transaction-request/test_authorization.py @@ -0,0 +1,192 @@ +import pytest +from web3.utils.encoding import decode_hex + + +def test_execution_rejected_for_insufficient_gas(chain, + RequestData, + proxy, + txn_recorder, + request_lib, + get_execute_data, + get_abort_data, + AbortReasons): + txn_request = RequestData( + toAddress=txn_recorder.address, + callGas=100000, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + assert txn_recorder.call().wasCalled() is False + + chain.wait.for_block(request_data.schedule.windowStart) + + minimum_call_gas = request_data.txnData.callGas + request_lib.call().GAS_TO_AUTHORIZE_EXECUTION() + request_lib.call().GAS_TO_COMPLETE_EXECUTION() + + call_data_hex = txn_request._encode_transaction_data('execute') + execute_txn_hash = proxy.transact().__proxy( + to=txn_request.address, + callData=decode_hex(call_data_hex), + callGas=minimum_call_gas - 1, + ) + chain.wait.for_receipt(execute_txn_hash) + + with pytest.raises(AssertionError): + get_execute_data(execute_txn_hash) + + abort_data = get_abort_data(execute_txn_hash) + reasons = {entry['args']['reason'] for entry in abort_data} + assert AbortReasons.InsufficientGas in reasons + + +def test_execution_rejected_if_already_executed(chain, + RequestData, + txn_recorder, + get_execute_data, + get_abort_data, + AbortReasons): + txn_request = RequestData( + toAddress=txn_recorder.address, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + + chain.wait.for_block(request_data.schedule.windowStart) + + execute_txn_hash = txn_request.transact().execute() + chain.wait.for_receipt(execute_txn_hash) + + assert txn_recorder.call().wasCalled() is True + request_data.refresh() + assert request_data.meta.wasCalled is True + + duplicate_execute_txn_hash = txn_request.transact().execute() + chain.wait.for_receipt(duplicate_execute_txn_hash) + + with pytest.raises(AssertionError): + get_execute_data(duplicate_execute_txn_hash) + + abort_data = get_abort_data(duplicate_execute_txn_hash) + reasons = {entry['args']['reason'] for entry in abort_data} + assert AbortReasons.AlreadyCalled in reasons + + +def test_execution_rejected_if_cancelled(chain, + web3, + RequestData, + txn_recorder, + get_execute_data, + get_abort_data, + AbortReasons): + txn_request = RequestData( + toAddress=txn_recorder.address, + windowStart=web3.eth.blockNumber + 20, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + assert request_data.meta.isCancelled is False + + cancel_txn_hash = txn_request.transact().cancel() + chain.wait.for_receipt(cancel_txn_hash) + + request_data.refresh() + assert request_data.meta.isCancelled is True + + chain.wait.for_block(request_data.schedule.windowStart) + + execute_txn_hash = txn_request.transact().execute() + chain.wait.for_receipt(execute_txn_hash) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + + with pytest.raises(AssertionError): + get_execute_data(execute_txn_hash) + + abort_data = get_abort_data(execute_txn_hash) + reasons = {entry['args']['reason'] for entry in abort_data} + assert AbortReasons.WasCancelled in reasons + + +def test_execution_rejected_if_before_call_window(chain, + web3, + RequestData, + txn_recorder, + get_execute_data, + get_abort_data, + AbortReasons): + txn_request = RequestData( + toAddress=txn_recorder.address, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + assert web3.eth.blockNumber < request_data.schedule.windowStart + + execute_txn_hash = txn_request.transact().execute() + chain.wait.for_receipt(execute_txn_hash) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + + with pytest.raises(AssertionError): + get_execute_data(execute_txn_hash) + + abort_data = get_abort_data(execute_txn_hash) + reasons = {entry['args']['reason'] for entry in abort_data} + assert AbortReasons.BeforeCallWindow in reasons + + +def test_execution_rejected_if_after_call_window(chain, + web3, + RequestData, + txn_recorder, + get_execute_data, + get_abort_data, + AbortReasons): + txn_request = RequestData( + toAddress=txn_recorder.address, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + + chain.wait.for_block(request_data.schedule.windowStart + request_data.schedule.windowSize + 1) + + execute_txn_hash = txn_request.transact().execute() + chain.wait.for_receipt(execute_txn_hash) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + + with pytest.raises(AssertionError): + get_execute_data(execute_txn_hash) + + abort_data = get_abort_data(execute_txn_hash) + reasons = {entry['args']['reason'] for entry in abort_data} + assert AbortReasons.AfterCallWindow in reasons + + +def test_execution_rejected_if_claimed_by_other(chain, + web3, + RequestData, + txn_recorder, + get_execute_data, + get_abort_data, + AbortReasons): + assert False + + +def test_execution_rejected_if_stack_too_deep(chain, + web3, + RequestData, + txn_recorder, + get_execute_data, + get_abort_data, + AbortReasons): + assert False diff --git a/tests/transaction-request/test_execution.py b/tests/transaction-request/test_execution.py new file mode 100644 index 000000000..2031ec18f --- /dev/null +++ b/tests/transaction-request/test_execution.py @@ -0,0 +1,28 @@ +def test_transaction_parameters(chain, RequestData, txn_recorder): + txn_request = RequestData( + toAddress=txn_recorder.address, + callData='this-is-the-call-data', + callGas=123456, + callValue=121212, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + assert txn_recorder.call().wasCalled() is False + assert txn_recorder.call().lastCaller() == '0x0000000000000000000000000000000000000000' + assert txn_recorder.call().lastCallValue() == 0 + assert txn_recorder.call().lastCallGas() == 0 + assert txn_recorder.call().lastCallData() == '' + + chain.wait.for_block(request_data.schedule.windowStart) + + execute_txn_hash = txn_request.transact().execute() + chain.wait.for_receipt(execute_txn_hash) + + assert txn_recorder.call().wasCalled() is True + assert txn_recorder.call().lastCaller() == txn_request.address + assert txn_recorder.call().lastCallValue() == 121212 + assert txn_recorder.call().lastCallData().startswith('this-is-the-call-data') + assert len(txn_recorder.call().lastCallData()) == 32 + + call_gas_delta = abs(txn_recorder.call().lastCallGas() - 123456) + assert call_gas_delta < 10000 From 2be26ce47aba1ae8a82a332ab5bb331a72417630 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sun, 18 Sep 2016 03:35:11 -0700 Subject: [PATCH 18/25] stack depth test --- contracts/ExecutionLib.sol | 2 +- tests/StackDigger.sol | 23 +++++++ tests/conftest.py | 11 +++ tests/test_digger_proxy.py | 15 ++++ .../transaction-request/test_authorization.py | 68 ++++++++++++++++++- 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 tests/StackDigger.sol create mode 100644 tests/test_digger_proxy.py diff --git a/contracts/ExecutionLib.sol b/contracts/ExecutionLib.sol index eaf773391..c45fa3fe0 100644 --- a/contracts/ExecutionLib.sol +++ b/contracts/ExecutionLib.sol @@ -39,7 +39,7 @@ library ExecutionLib { */ function stackCanBeExtended(ExecutionData storage self) returns (bool) { if (self.requiredStackDepth == 0) return true; - return address(this).call + return address(this).callcode .gas(_GAS_PER_DEPTH * self.requiredStackDepth) ( bytes4(sha3("__dig(uint256)")), diff --git a/tests/StackDigger.sol b/tests/StackDigger.sol new file mode 100644 index 000000000..0ecd10a05 --- /dev/null +++ b/tests/StackDigger.sol @@ -0,0 +1,23 @@ +import {Proxy} from "tests/Proxy.sol"; + + +contract DiggerProxy is Proxy { + address public to; + bytes public callData; + + function __dig_then_proxy(uint n, address _to, bytes _callData) public { + to = _to; + callData = _callData; + __dig_then_proxy(n); + } + + bool public result; + + function __dig_then_proxy(uint n) public { + if (n == 0) { + result = __proxy(to, callData); + } else { + if (!address(this).callcode(bytes4(sha3("__dig_then_proxy(uint256)")), n - 1)) throw; + } + } +} diff --git a/tests/conftest.py b/tests/conftest.py index f964d858e..e3dd0f3bf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -520,3 +520,14 @@ def Proxy(test_contract_factories): def proxy(chain, Proxy): chain.contract_factories['Proxy'] = Proxy return chain.get_contract('Proxy') + + +@pytest.fixture() +def DiggerProxy(test_contract_factories): + return test_contract_factories.DiggerProxy + + +@pytest.fixture() +def digger_proxy(chain, DiggerProxy): + chain.contract_factories['DiggerProxy'] = DiggerProxy + return chain.get_contract('DiggerProxy') diff --git a/tests/test_digger_proxy.py b/tests/test_digger_proxy.py new file mode 100644 index 000000000..7d3155795 --- /dev/null +++ b/tests/test_digger_proxy.py @@ -0,0 +1,15 @@ +def test_execution_rejected_if_stack_too_deep(chain, + web3, + txn_recorder, + digger_proxy): + assert txn_recorder.call().wasCalled() is False + + dig_txn_hash = digger_proxy.transact().__dig_then_proxy( + 1023, + txn_recorder.address, + 'the-call-data', + ) + chain.wait.for_receipt(dig_txn_hash) + + assert txn_recorder.call().wasCalled() is True + assert txn_recorder.call().lastCallData().startswith('the-call-data') diff --git a/tests/transaction-request/test_authorization.py b/tests/transaction-request/test_authorization.py index e3a74158b..e03b39341 100644 --- a/tests/transaction-request/test_authorization.py +++ b/tests/transaction-request/test_authorization.py @@ -179,14 +179,78 @@ def test_execution_rejected_if_claimed_by_other(chain, get_execute_data, get_abort_data, AbortReasons): - assert False + txn_request = RequestData( + windowStart=web3.eth.blockNumber + 255 + 10 + 5, + toAddress=txn_recorder.address, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + claim_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - 10 + chain.wait.for_block(claim_at) + + txn_request.transact({ + 'from': web3.eth.accounts[1], + 'value': 2 * request_data.paymentData.payment, + }).claim() + + request_data.refresh() + assert request_data.claimData.claimedBy == web3.eth.accounts[1] + + chain.wait.for_block(request_data.schedule.windowStart) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + + execute_txn_hash = txn_request.transact().execute() + chain.wait.for_receipt(execute_txn_hash) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + + with pytest.raises(AssertionError): + get_execute_data(execute_txn_hash) + + abort_data = get_abort_data(execute_txn_hash) + reasons = {entry['args']['reason'] for entry in abort_data} + assert AbortReasons.ReservedForClaimer in reasons def test_execution_rejected_if_stack_too_deep(chain, web3, RequestData, txn_recorder, + digger_proxy, get_execute_data, get_abort_data, AbortReasons): - assert False + txn_request = RequestData( + toAddress=txn_recorder.address, + requiredStackDepth=1000, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + assert request_data.txnData.requiredStackDepth == 1000 + + chain.wait.for_block(request_data.schedule.windowStart) + + execute_call_data = decode_hex(txn_request._encode_transaction_data('execute')) + + execute_txn_hash = digger_proxy.transact().__dig_then_proxy( + 24, + txn_request.address, + execute_call_data, + ) + chain.wait.for_receipt(execute_txn_hash) + + assert digger_proxy.call().result() is True + assert txn_recorder.call().wasCalled() is False + assert request_data.meta.wasCalled is False + + with pytest.raises(AssertionError): + get_execute_data(execute_txn_hash) + + abort_data = get_abort_data(execute_txn_hash) + reasons = {entry['args']['reason'] for entry in abort_data} + assert AbortReasons.StackTooDeep in reasons From 3ded5d2970019216ff8e983dedc980f773fcea43 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sun, 18 Sep 2016 03:38:55 -0700 Subject: [PATCH 19/25] add stub tests --- tests/transaction-request/test_claiming.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/transaction-request/test_claiming.py b/tests/transaction-request/test_claiming.py index eaf95916a..23041d380 100644 --- a/tests/transaction-request/test_claiming.py +++ b/tests/transaction-request/test_claiming.py @@ -135,3 +135,15 @@ def test_deposit_returned_if_claim_rejected(chain, web3, RequestData): updated_request_data = RequestData.from_contract(txn_request) assert updated_request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' + + +def test_executing_own_claimed_call(): + assert False + + +def test_executing_other_claimed_call_after_reserved_window(): + assert False + + +def test_claim_block_determines_payment_amount(): + assert False From 391dcc0e47865ff8618a6d07cbcfb348a8bbf539 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Thu, 22 Sep 2016 20:38:30 +0800 Subject: [PATCH 20/25] travis ci config --- .travis.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index ecfc6458d..2b6209a61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,14 +7,10 @@ env: global: - SOLC_BINARY="$TRAVIS_BUILD_DIR/solc-versions/solc-0.3.6/solc" matrix: - - TEST_DIR=accounting - - TEST_DIR=call-state - - TEST_DIR=canary - - TEST_DIR=cancelling - - TEST_DIR=claiming - - TEST_DIR=data-registry - - TEST_DIR=execution - - TEST_DIR=scheduling + - TEST_DIR=block-scheduling + - TEST_DIR=request-factory + - TEST_DIR=request-tracker + - TEST_DIR=transaction-request cache: - pip: true - directories: From 57c6f18f533517fe858bac02961380b17d42152c Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Thu, 22 Sep 2016 20:56:41 +0800 Subject: [PATCH 21/25] conftest updates and cleanup --- tests/conftest.py | 160 +++++++++++++++++----------------------------- 1 file changed, 59 insertions(+), 101 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index e3dd0f3bf..9d66937a9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,6 @@ import os +import functools +import itertools import pytest @@ -293,30 +295,16 @@ def ValidationErrors(): @pytest.fixture() -def get_txn_request(chain, - web3, - request_factory, - RequestFactory, - TransactionRequest, - ValidationErrors, - logs_to_event_data, - TopicMap): - def _get_txn_request(txn_hash): +def extract_event_logs(chain, web3, logs_to_event_data): + def _extract_event_logs(event_name, contract, txn_hash): txn_receipt = chain.wait.for_receipt(txn_hash) - request_created_filter = RequestFactory.pastEvents('RequestCreated', { + filter = contract.pastEvents(event_name, { 'fromBlock': txn_receipt['blockNumber'], 'toBlock': txn_receipt['blockNumber'], }) - request_created_logs = request_created_filter.get() - if len(request_created_logs) == 0: - error_filter = RequestFactory.pastEvents('ValidationError', { - 'fromBlock': txn_receipt['blockNumber'], - 'toBlock': txn_receipt['blockNumber'], - }) - error_logs = error_filter.get() - if error_logs: - errors = [ValidationErrors[entry['args']['reason']] for entry in error_logs] - raise AssertionError("ValidationError: {0}".format(', '.join(errors))) + log_entries = filter.get() + + if len(log_entries) == 0: decoded_events = logs_to_event_data(txn_receipt['logs']) if decoded_events: raise AssertionError( @@ -324,11 +312,36 @@ def _get_txn_request(txn_hash): "the logs for the given transaction hash:\n" "{0}".format('\n'.join(decoded_events)) ) - raise AssertionError("Something went wrong. No 'RequestCreated' log entries found") + raise AssertionError( + "Something went wrong. No '{0}' log entries found".format(event_name) + ) + event_data = log_entries[0] + return event_data + return _extract_event_logs + - log_data = request_created_logs[0] +@pytest.fixture() +def get_txn_request(chain, + web3, + extract_event_logs, + RequestFactory, + TransactionRequest, + ValidationErrors): + def _get_txn_request(txn_hash): + try: + request_created_data = extract_event_logs('RequestCreated', RequestFactory, txn_hash) + except AssertionError: + validation_error_data = extract_event_logs('ValidationError', RequestFactory, txn_hash) + if validation_error_data: + errors = [ + ValidationErrors[entry['args']['error']] + for entry in validation_error_data + ] + raise AssertionError("ValidationError: {0}".format(', '.join(errors))) + raise + + request_address = request_created_data['args']['request'] - request_address = log_data['args']['request'] txn_request = TransactionRequest(address=request_address) return txn_request return _get_txn_request @@ -355,109 +368,54 @@ def AbortReasons(ABORT_REASONS_ENUM_KEYS): @pytest.fixture() -def get_abort_data(chain, web3, RequestLib, logs_to_event_data): - def _get_abort_data(execute_txn_hash): - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - abort_filter = RequestLib.pastEvents('Aborted', { - 'fromBlock': execute_txn_receipt['blockNumber'], - 'toBlock': execute_txn_receipt['blockNumber'], - }) - abort_logs = abort_filter.get() - if len(abort_logs) == 0: - decoded_events = logs_to_event_data(execute_txn_receipt['logs']) - if decoded_events: - raise AssertionError( - "Something went wrong. The following events were found in" - "the logs for the given transaction hash:\n" - "{0}".format('\n'.join(decoded_events)) - ) - raise AssertionError("Something went wrong. No 'Aborted' log entries found") - return abort_logs - return _get_abort_data +def get_abort_data(chain, web3, RequestLib): + return functools.partial(extract_event_logs, 'Aborted', RequestLib) @pytest.fixture() -def get_execute_data(chain, web3, RequestLib, ABORT_REASONS_ENUM_KEYS, get_abort_data): - def _get_execute_data(execute_txn_hash): - execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) - execute_filter = RequestLib.pastEvents('Executed', { - 'fromBlock': execute_txn_receipt['blockNumber'], - 'toBlock': execute_txn_receipt['blockNumber'], - }) - execute_logs = execute_filter.get() - if len(execute_logs) == 0: - abort_logs = get_abort_data(execute_txn_hash) - errors = [ABORT_REASONS_ENUM_KEYS[entry['args']['reason']] for entry in abort_logs] - raise AssertionError("Execution Failed: {0}".format(', '.join(errors))) - execute_data = execute_logs[0] - return execute_data +def get_execute_data(chain, web3, RequestLib, get_abort_data): + def _get_execute_data(txn_hash): + try: + return extract_event_logs('Executed', RequestFactory, txn_hash) + except AssertionError: + abort_data = get_abort_data(txn_hash) + if abort_data: + errors = [ + ABORT_REASONS_ENUM_KEYS[entry['args']['reason']] + for entry in abort_data + ] + raise AssertionError("Aborted: {0}".format(', '.join(errors))) + raise return _get_execute_data @pytest.fixture() def get_claim_data(chain, web3, RequestLib, logs_to_event_data): - def _get_claim_data(claim_txn_hash): - claim_txn_receipt = chain.wait.for_receipt(claim_txn_hash) - claim_filter = RequestLib.pastEvents('Claimed', { - 'fromBlock': claim_txn_receipt['blockNumber'], - 'toBlock': claim_txn_receipt['blockNumber'], - }) - claim_logs = claim_filter.get() - if len(claim_logs) == 0: - decoded_events = logs_to_event_data(claim_txn_receipt['logs']) - if decoded_events: - raise AssertionError( - "Something went wrong. The following events were found in" - "the logs for the given transaction hash:\n" - "{0}".format('\n'.join(decoded_events)) - ) - raise AssertionError("Something went wrong. No 'Claimed' log entries found") - claim_data = claim_logs[0] - return claim_data - return _get_claim_data + return functools.partial(extract_event_logs, 'Claimed', RequestLib) @pytest.fixture() def get_cancel_data(chain, web3, RequestLib, logs_to_event_data): - def _get_cancel_data(cancel_txn_hash): - cancel_txn_receipt = chain.wait.for_receipt(cancel_txn_hash) - cancel_filter = RequestLib.pastEvents('Cancelled', { - 'fromBlock': cancel_txn_receipt['blockNumber'], - 'toBlock': cancel_txn_receipt['blockNumber'], - }) - cancel_logs = cancel_filter.get() - if len(cancel_logs) == 0: - decoded_events = logs_to_event_data(cancel_txn_receipt['logs']) - if decoded_events: - raise AssertionError( - "Something went wrong. The following events were found in" - "the logs for the given transaction hash:\n" - "{0}".format('\n'.join(decoded_events)) - ) - raise AssertionError("Something went wrong. No 'Cancelled' log entries found") - cancel_data = cancel_logs[0] - return cancel_data - return _get_cancel_data + return functools.partial(extract_event_logs, 'Cancelled', RequestLib) @pytest.fixture() -def logs_to_event_data(TopicMap): +def logs_to_event_data(topics_to_abi): from web3.utils.events import ( get_event_data, ) def _logs_to_event_data(log_entries): return [ - get_event_data(TopicMap[log_entry['topics'][0]], log_entry) + get_event_data(topics_to_abi[log_entry['topics'][0]], log_entry) for log_entry in log_entries - if log_entry['topics'] and log_entry['topics'][0] in TopicMap + if log_entry['topics'] and log_entry['topics'][0] in topics_to_abi ] return _logs_to_event_data @pytest.fixture() -def TopicMap(project): - import itertools +def topics_to_abi(project): from web3.utils.abi import ( filter_by_type, event_abi_to_log_topic, @@ -465,11 +423,11 @@ def TopicMap(project): all_events_abi = filter_by_type('event', itertools.chain.from_iterable( contract['abi'] for contract in project.compiled_contracts.values() )) - topic_to_abi = { + _topic_to_abi = { event_abi_to_log_topic(abi): abi for abi in all_events_abi } - return topic_to_abi + return _topic_to_abi @pytest.fixture() From 8cf99b6de37e2d0cc1c11e52b6eef3f4bec8e0a5 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Thu, 22 Sep 2016 23:17:50 +0800 Subject: [PATCH 22/25] test cleanup --- contracts/RequestLib.sol | 13 +- tests/conftest.py | 51 ++++--- tests/transaction-request/test_cancelling.py | 6 +- tests/transaction-request/test_claiming.py | 132 ++++++++++++++---- .../test_digger_proxy.py | 0 tests/transaction-request/test_exceptions.py | 2 +- 6 files changed, 153 insertions(+), 51 deletions(-) rename tests/{ => transaction-request}/test_digger_proxy.py (100%) diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index eb3af15cb..49c6e059d 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -357,6 +357,12 @@ library RequestLib { .safeAdd(self.paymentData.donationOwed); } + // record this so that we can log it later. + var totalDonationPayment = self.paymentData.donationOwed; + + // Send the donation. + self.paymentData.sendDonation(); + // Compute the payment amount and who it should be sent do. self.paymentData.paymentBenefactor = msg.sender; if (self.claimData.isClaimed()) { @@ -385,12 +391,9 @@ library RequestLib { // Log the two payment amounts. Otherwise it is non-trivial to figure // out how much was payed. Executed(self.paymentData.paymentOwed, - self.paymentData.donationOwed, + totalDonationPayment, measuredGasConsumption); - // Send the donation. - self.paymentData.sendDonation(); - // Send the payment. self.paymentData.sendPayment(); @@ -434,7 +437,7 @@ library RequestLib { * The amount of gas used by the portion of the `execute` function * that cannot be accounted for via gas tracking. */ - uint constant _EXECUTE_EXTRA_GAS = 185000; + uint constant _EXECUTE_EXTRA_GAS = 145000; function EXECUTE_EXTRA_GAS() returns (uint) { return _EXECUTE_EXTRA_GAS; diff --git a/tests/conftest.py b/tests/conftest.py index 9d66937a9..d85cd3eec 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -295,8 +295,8 @@ def ValidationErrors(): @pytest.fixture() -def extract_event_logs(chain, web3, logs_to_event_data): - def _extract_event_logs(event_name, contract, txn_hash): +def extract_event_logs(chain, web3, get_all_event_data): + def _extract_event_logs(event_name, contract, txn_hash, return_single=True): txn_receipt = chain.wait.for_receipt(txn_hash) filter = contract.pastEvents(event_name, { 'fromBlock': txn_receipt['blockNumber'], @@ -305,18 +305,23 @@ def _extract_event_logs(event_name, contract, txn_hash): log_entries = filter.get() if len(log_entries) == 0: - decoded_events = logs_to_event_data(txn_receipt['logs']) - if decoded_events: + all_event_logs = get_all_event_data(txn_receipt['logs']) + if all_event_logs: raise AssertionError( "Something went wrong. The following events were found in" "the logs for the given transaction hash:\n" - "{0}".format('\n'.join(decoded_events)) + "{0}".format('\n'.join([ + event_log['event'] for event_log in all_event_logs + ])) ) raise AssertionError( "Something went wrong. No '{0}' log entries found".format(event_name) ) - event_data = log_entries[0] - return event_data + if return_single: + event_data = log_entries[0] + return event_data + else: + return log_entries return _extract_event_logs @@ -331,7 +336,7 @@ def _get_txn_request(txn_hash): try: request_created_data = extract_event_logs('RequestCreated', RequestFactory, txn_hash) except AssertionError: - validation_error_data = extract_event_logs('ValidationError', RequestFactory, txn_hash) + validation_error_data = extract_event_logs('ValidationError', RequestFactory, txn_hash, return_single=False) if validation_error_data: errors = [ ValidationErrors[entry['args']['error']] @@ -368,17 +373,24 @@ def AbortReasons(ABORT_REASONS_ENUM_KEYS): @pytest.fixture() -def get_abort_data(chain, web3, RequestLib): - return functools.partial(extract_event_logs, 'Aborted', RequestLib) +def get_abort_data(chain, web3, RequestLib, extract_event_logs): + def _get_abort_data(txn_hash, return_single=False): + return extract_event_logs('Aborted', RequestLib, txn_hash, return_single=return_single) + return _get_abort_data @pytest.fixture() -def get_execute_data(chain, web3, RequestLib, get_abort_data): +def get_execute_data(chain, + web3, + RequestLib, + extract_event_logs, + get_abort_data, + ABORT_REASONS_ENUM_KEYS): def _get_execute_data(txn_hash): try: - return extract_event_logs('Executed', RequestFactory, txn_hash) + return extract_event_logs('Executed', RequestLib, txn_hash) except AssertionError: - abort_data = get_abort_data(txn_hash) + abort_data = get_abort_data(txn_hash, return_single=False) if abort_data: errors = [ ABORT_REASONS_ENUM_KEYS[entry['args']['reason']] @@ -390,28 +402,29 @@ def _get_execute_data(txn_hash): @pytest.fixture() -def get_claim_data(chain, web3, RequestLib, logs_to_event_data): +def get_claim_data(chain, web3, RequestLib, extract_event_logs): return functools.partial(extract_event_logs, 'Claimed', RequestLib) @pytest.fixture() -def get_cancel_data(chain, web3, RequestLib, logs_to_event_data): +def get_cancel_data(chain, web3, RequestLib, extract_event_logs): return functools.partial(extract_event_logs, 'Cancelled', RequestLib) @pytest.fixture() -def logs_to_event_data(topics_to_abi): +def get_all_event_data(topics_to_abi): from web3.utils.events import ( get_event_data, ) - def _logs_to_event_data(log_entries): - return [ + def _get_all_event_data(log_entries): + all_event_data = [ get_event_data(topics_to_abi[log_entry['topics'][0]], log_entry) for log_entry in log_entries if log_entry['topics'] and log_entry['topics'][0] in topics_to_abi ] - return _logs_to_event_data + return all_event_data + return _get_all_event_data @pytest.fixture() diff --git a/tests/transaction-request/test_cancelling.py b/tests/transaction-request/test_cancelling.py index db752a66e..d7d3eb3cb 100644 --- a/tests/transaction-request/test_cancelling.py +++ b/tests/transaction-request/test_cancelling.py @@ -99,11 +99,13 @@ def test_not_cancellable_during_freeze_window(chain, web3, RequestData): assert request_data.meta.owner == web3.eth.coinbase assert request_data.meta.isCancelled is False + chain.wait.for_block(cancel_at) + cancel_txn_hash = txn_request.transact().cancel() chain.wait.for_receipt(cancel_txn_hash) - updated_request_data = RequestData.from_contract(txn_request) - assert updated_request_data.meta.isCancelled is False + request_data.refresh() + assert request_data.meta.isCancelled is False def test_not_cancellable_during_execution_window(chain, web3, RequestData): diff --git a/tests/transaction-request/test_claiming.py b/tests/transaction-request/test_claiming.py index 23041d380..d60858d06 100644 --- a/tests/transaction-request/test_claiming.py +++ b/tests/transaction-request/test_claiming.py @@ -1,7 +1,7 @@ import pytest -def test_cannot_claim_before_first_claim_block(chain, web3, RequestData): +def test_cannot_claim_before_first_claim_block(chain, web3, RequestData, get_claim_data): txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() request_data = RequestData.from_contract(txn_request) @@ -12,14 +12,19 @@ def test_cannot_claim_before_first_claim_block(chain, web3, RequestData): chain.wait.for_block(first_claim_block - 1) - claim_txn_hash = txn_request.transact({'value': 2 * request_data.paymentData.payment}).claim() + claim_txn_hash = txn_request.transact({ + 'value': 2 * request_data.paymentData.payment, + }).claim() chain.wait.for_receipt(claim_txn_hash) - updated_request_data = RequestData.from_contract(txn_request) - assert updated_request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' + with pytest.raises(AssertionError): + get_claim_data(claim_txn_hash) + request_data.refresh() + assert request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' -def test_can_claim_at_first_claim_block(chain, web3, RequestData): + +def test_can_claim_at_first_claim_block(chain, web3, RequestData, get_claim_data): txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() request_data = RequestData.from_contract(txn_request) @@ -30,11 +35,16 @@ def test_can_claim_at_first_claim_block(chain, web3, RequestData): chain.wait.for_block(first_claim_block) - claim_txn_hash = txn_request.transact({'value': 2 * request_data.paymentData.payment}).claim() + claim_txn_hash = txn_request.transact({ + 'value': 2 * request_data.paymentData.payment, + }).claim() chain.wait.for_receipt(claim_txn_hash) - updated_request_data = RequestData.from_contract(txn_request) - assert updated_request_data.claimData.claimedBy == web3.eth.coinbase + claim_data = get_claim_data(claim_txn_hash) + assert claim_data + + request_data.refresh() + assert request_data.claimData.claimedBy == web3.eth.coinbase def test_can_claim_at_last_claim_block(chain, web3, RequestData): @@ -48,11 +58,13 @@ def test_can_claim_at_last_claim_block(chain, web3, RequestData): chain.wait.for_block(last_claim_block) - claim_txn_hash = txn_request.transact({'value': 2 * request_data.paymentData.payment}).claim() + claim_txn_hash = txn_request.transact({ + 'value': 2 * request_data.paymentData.payment, + }).claim() chain.wait.for_receipt(claim_txn_hash) - updated_request_data = RequestData.from_contract(txn_request) - assert updated_request_data.claimData.claimedBy == web3.eth.coinbase + request_data.refresh() + assert request_data.claimData.claimedBy == web3.eth.coinbase def test_cannot_claim_after_last_claim_block(chain, web3, RequestData): @@ -66,11 +78,16 @@ def test_cannot_claim_after_last_claim_block(chain, web3, RequestData): chain.wait.for_block(last_claim_block) - claim_txn_hash = txn_request.transact({'value': 2 * request_data.paymentData.payment}).claim() + claim_txn_hash = txn_request.transact({ + 'value': 2 * request_data.paymentData.payment, + }).claim() chain.wait.for_receipt(claim_txn_hash) - updated_request_data = RequestData.from_contract(txn_request) - assert updated_request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' + with pytest.raises(AssertionError): + get_claim_data(claim_txn_hash) + + request_data.refresh() + assert request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' def test_deposit_held_by_contract_on_claim(chain, web3, RequestData): @@ -101,11 +118,46 @@ def test_deposit_held_by_contract_on_claim(chain, web3, RequestData): assert after_contract_balance - before_contract_balance == deposit_amount assert before_account_balance - after_account_balance == deposit_amount + web3.eth.gasPrice * claim_txn_receipt['gasUsed'] - updated_request_data = RequestData.from_contract(txn_request) - assert updated_request_data.claimData.claimedBy == web3.eth.accounts[1] + request_data.refresh() + assert request_data.claimData.claimedBy == web3.eth.accounts[1] + + +def test_deposit_returned_if_claim_rejected(chain, web3, RequestData, get_claim_data): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + try_claim_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - request_data.schedule.claimWindowSize - 3 + + # sanity + assert try_claim_at > web3.eth.blockNumber + + chain.wait.for_block(try_claim_at) + + deposit_amount = 2 * request_data.paymentData.payment + + before_contract_balance = web3.eth.getBalance(txn_request.address) + before_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) + + claim_txn_hash = txn_request.transact({ + 'value': deposit_amount, + 'from': web3.eth.accounts[1], + }).claim() + chain.wait.for_receipt(claim_txn_hash) + + after_contract_balance = web3.eth.getBalance(txn_request.address) + after_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) + + assert after_contract_balance == before_contract_balance + assert after_account_balance == before_account_balance + + with pytest.raises(AssertionError): + get_claim_data(claim_txn_hash) + request_data.refresh() + assert request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' -def test_deposit_returned_if_claim_rejected(chain, web3, RequestData): + +def test_deposit_returned_even_if_returning_it_throws(chain, web3, RequestData, get_claim_data, proxy): txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() request_data = RequestData.from_contract(txn_request) @@ -121,11 +173,12 @@ def test_deposit_returned_if_claim_rejected(chain, web3, RequestData): before_contract_balance = web3.eth.getBalance(txn_request.address) before_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) + claim_call_data = txn_request._encode_transaction_data('claim') + with pytest.raises(ValueError): - txn_request.transact({ + proxy.transact({ 'value': deposit_amount, - 'from': web3.eth.accounts[1], - }).claim() + }).__proxy(txn_request.address, claim_call_data) after_contract_balance = web3.eth.getBalance(txn_request.address) after_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) @@ -133,12 +186,43 @@ def test_deposit_returned_if_claim_rejected(chain, web3, RequestData): assert after_contract_balance == before_contract_balance assert after_account_balance == before_account_balance - updated_request_data = RequestData.from_contract(txn_request) - assert updated_request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' + request_data.refresh() + assert request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' -def test_executing_own_claimed_call(): - assert False +def test_executing_own_claimed_call(chain, web3, RequestData, get_execute_data, get_claim_data): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + first_claim_block = request_data.schedule.windowStart - request_data.schedule.freezePeriod - request_data.schedule.claimWindowSize + + # sanity + assert first_claim_block > web3.eth.blockNumber + + chain.wait.for_block(first_claim_block) + + claim_txn_hash = txn_request.transact({ + 'value': 2 * request_data.paymentData.payment, + 'from': web3.eth.accounts[1], + }).claim() + chain.wait.for_receipt(claim_txn_hash) + + request_data = request_data.refresh() + assert request_data.claimData.claimedBy == web3.eth.accounts[1] + + assert get_claim_data(claim_txn_hash) + + chain.wait.for_block(request_data.schedule.windowStart) + + execute_txn_hash = txn_request.transact({ + 'from': web3.eth.accounts[1], + }).execute() + chain.wait.for_receipt(execute_txn_hash) + + request_data = request_data.refresh() + assert request_data.meta.wasCalled is True + + assert get_execute_data(execute_txn_hash) def test_executing_other_claimed_call_after_reserved_window(): diff --git a/tests/test_digger_proxy.py b/tests/transaction-request/test_digger_proxy.py similarity index 100% rename from tests/test_digger_proxy.py rename to tests/transaction-request/test_digger_proxy.py diff --git a/tests/transaction-request/test_exceptions.py b/tests/transaction-request/test_exceptions.py index 352b125b9..b2ede94c2 100644 --- a/tests/transaction-request/test_exceptions.py +++ b/tests/transaction-request/test_exceptions.py @@ -29,7 +29,7 @@ def test_txn_request_for_txn_that_throw_exception(chain, measured_gas_consumption = execute_data['args']['measuredGasConsumption'] assert measured_gas_consumption > gas_used - assert measured_gas_consumption - gas_used < 50000 + assert measured_gas_consumption - gas_used < 120000 def test_txn_request_when_everything_throws(chain, From d792b24a02f4bd77cb65dec40b61a92eb7df0374 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Thu, 22 Sep 2016 23:24:24 +0800 Subject: [PATCH 23/25] dirty --- alarm_client/__init__.py | 0 alarm_client/transaction_request.py | 214 ++++++++++++++++++++++++++++ setup.py | 41 ++++++ 3 files changed, 255 insertions(+) create mode 100644 alarm_client/__init__.py create mode 100644 alarm_client/transaction_request.py create mode 100644 setup.py diff --git a/alarm_client/__init__.py b/alarm_client/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/alarm_client/transaction_request.py b/alarm_client/transaction_request.py new file mode 100644 index 000000000..f03f33fb3 --- /dev/null +++ b/alarm_client/transaction_request.py @@ -0,0 +1,214 @@ +NULL_ADDRESS = '0x0000000000000000000000000000000000000000' + + +class RequestData(object): + _contract = None + + def __init__(self, + # claim + claimedBy, + claimDeposit, + paymentModifier, + # meta + createdBy, + owner, + isCancelled, + wasCalled, + wasSuccessful, + # payment + anchorGasPrice, + donation, + donationBenefactor, + donationOwed, + payment, + paymentBenefactor, + paymentOwed, + # txnData + callData, + toAddress, + callGas, + callValue, + requiredStackDepth, + # schedule + claimWindowSize, + freezePeriod, + windowStart, + windowSize, + reservedWindowSize, + temporalUnit): + + if freezePeriod is None: + if temporalUnit == 0: + freezePeriod = 10 * 17 + else: + freezePeriod = 10 + + if windowSize is None: + if temporalUnit == 0: + windowSize = 255 * 17 + else: + windowSize = 255 + + if windowStart is None: + if temporalUnit == 0: + windowStart = web3.eth.getBlock('latest')['timestamp'] + freezePeriod + else: + windowStart = web3.eth.blockNumber + freezePeriod + + if reservedWindowSize is None: + if temporalUnit == 0: + reservedWindowSize = 16 * 17 + else: + reservedWindowSize = 16 + + self.claimData = type('claimData', (object,), { + 'claimedBy': claimedBy, + 'claimDeposit': claimDeposit, + 'paymentModifier': paymentModifier, + }) + self.meta = type('meta', (object,), { + 'createdBy': createdBy, + 'owner': owner, + 'isCancelled': isCancelled, + 'wasCalled': wasCalled, + 'wasSuccessful': wasSuccessful, + }) + self.paymentData = type('paymentData', (object,), { + 'anchorGasPrice': anchorGasPrice, + 'donation': donation, + 'donationBenefactor': donationBenefactor, + 'donationOwed': donationOwed, + 'payment': payment, + 'paymentBenefactor': paymentBenefactor, + 'paymentOwed': paymentOwed, + }) + self.txnData = type('txnData', (object,), { + 'callData': callData, + 'toAddress': toAddress, + 'callGas': callGas, + 'callValue': callValue, + 'requiredStackDepth': requiredStackDepth, + }) + self.schedule = type('schedule', (object,), { + 'claimWindowSize': claimWindowSize, + 'freezePeriod': freezePeriod, + 'reservedWindowSize': reservedWindowSize, + 'temporalUnit': temporalUnit, + 'windowStart': windowStart, + 'windowSize': windowSize, + }) + + def to_factory_kwargs(self): + return { + 'addressArgs': [ + self.meta.owner, + self.paymentData.donationBenefactor, + self.txnData.toAddress, + ], + 'uintArgs': [ + self.paymentData.donation, + self.paymentData.payment, + self.schedule.claimWindowSize, + self.schedule.freezePeriod, + self.schedule.reservedWindowSize, + self.schedule.temporalUnit, + self.schedule.windowStart, + self.schedule.windowSize, + self.txnData.callGas, + self.txnData.callValue, + self.txnData.requiredStackDepth, + ], + 'callData': self.txnData.callData, + } + + def deploy_via_factory(self, deploy_txn=None): + if deploy_txn is None: + deploy_txn = {'value': 10 * denoms.ether} + create_txn_hash = request_factory.transact( + deploy_txn, + ).createRequest( + **self.to_factory_kwargs() + ) + txn_request = get_txn_request(create_txn_hash) + return txn_request + + def to_init_kwargs(self): + return { + 'addressArgs': [ + self.meta.createdBy, + self.meta.owner, + self.paymentData.donationBenefactor, + self.txnData.toAddress, + ], + 'uintArgs': [ + self.paymentData.donation, + self.paymentData.payment, + self.schedule.claimWindowSize, + self.schedule.freezePeriod, + self.schedule.reservedWindowSize, + self.schedule.temporalUnit, + self.schedule.windowStart, + self.schedule.windowSize, + self.txnData.callGas, + self.txnData.callValue, + self.txnData.requiredStackDepth, + ], + 'callData': self.txnData.callData, + } + + def direct_deploy(self, deploy_txn=None): + if deploy_txn is None: + deploy_txn = {'value': 10 * denoms.ether} + deploy_txn_hash = TransactionRequest.deploy( + transaction=deploy_txn, + kwargs=self.to_init_kwargs(), + ) + txn_request_address = chain.wait.for_contract_address(deploy_txn_hash) + return TransactionRequest(address=txn_request_address) + + def refresh(self): + if not self._contract: + raise ValueError("No contract set") + self.__dict__.update(self.from_contract(self._contract).__dict__) + + @classmethod + def from_contract(cls, txn_request): + address_args, bool_args, uint_args, uint8_args = txn_request.call().requestData() + call_data = txn_request.call().callData() + instance = cls.from_deserialize( + address_args, bool_args, uint_args, uint8_args, call_data, + ) + instance._contract = txn_request + return instance + + @classmethod + def from_deserialize(cls, address_args, bool_args, uint_args, uint8_args, call_data): + init_kwargs = { + 'claimedBy': address_args[0], + 'createdBy': address_args[1], + 'owner': address_args[2], + 'donationBenefactor': address_args[3], + 'paymentBenefactor': address_args[4], + 'toAddress': address_args[5], + 'wasCalled': bool_args[1], + 'wasSuccessful': bool_args[2], + 'isCancelled': bool_args[0], + 'paymentModifier': uint8_args[0], + 'claimDeposit': uint_args[0], + 'anchorGasPrice': uint_args[1], + 'donation': uint_args[2], + 'donationOwed': uint_args[3], + 'payment': uint_args[4], + 'paymentOwed': uint_args[5], + 'claimWindowSize': uint_args[6], + 'freezePeriod': uint_args[7], + 'reservedWindowSize': uint_args[8], + 'temporalUnit': uint_args[9], + 'windowStart': uint_args[10], + 'windowSize': uint_args[11], + 'callGas': uint_args[12], + 'callValue': uint_args[13], + 'requiredStackDepth': uint_args[14], + 'callData': call_data, + } + return cls(**init_kwargs) diff --git a/setup.py b/setup.py new file mode 100644 index 000000000..d7a4f3796 --- /dev/null +++ b/setup.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import os + +from setuptools import setup, find_packages + + +DIR = os.path.dirname(os.path.abspath(__file__)) + + +version = '7.0.0' + +setup( + name='ethereum-alarm-clock', + version=version, + description="""Ethereum Alarm Clock""", + long_description="Ethereum Alarm Clock service", + author='Piper Merriam', + author_email='pipermerriam@gmail.com', + url='http://www.ethereum-alarm-clock.com', + include_package_data=True, + py_modules=['eth_alarm_client'], + install_requires=[ + "populus>=1.0.0", + ], + license="MIT", + zip_safe=False, + keywords='ethereum', + packages=find_packages(exclude=["tests", "tests.*"]), + entry_points={ + #'console_scripts': ["eth_alarm=eth_alarm_client.cli:main"], + }, + classifiers=[ + 'Development Status :: 2 - Pre-Alpha', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Natural Language :: English', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + ], +) From 86a08e0c4b06681b10b9a310173022d0ef6d0e25 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Fri, 23 Sep 2016 08:11:58 +0800 Subject: [PATCH 24/25] make more tests pass --- alarm_client/transaction_request.py | 251 ++++--------------- tests/block-scheduling/test_scheduling.py | 4 +- tests/transaction-request/test_accounting.py | 4 + tests/transaction-request/test_claiming.py | 70 ++++-- 4 files changed, 113 insertions(+), 216 deletions(-) diff --git a/alarm_client/transaction_request.py b/alarm_client/transaction_request.py index f03f33fb3..7987e95d2 100644 --- a/alarm_client/transaction_request.py +++ b/alarm_client/transaction_request.py @@ -1,214 +1,65 @@ -NULL_ADDRESS = '0x0000000000000000000000000000000000000000' - +from populus.contract import Contract as ContractFactory -class RequestData(object): - _contract = None - def __init__(self, - # claim - claimedBy, - claimDeposit, - paymentModifier, - # meta - createdBy, - owner, - isCancelled, - wasCalled, - wasSuccessful, - # payment - anchorGasPrice, - donation, - donationBenefactor, - donationOwed, - payment, - paymentBenefactor, - paymentOwed, - # txnData - callData, - toAddress, - callGas, - callValue, - requiredStackDepth, - # schedule - claimWindowSize, - freezePeriod, - windowStart, - windowSize, - reservedWindowSize, - temporalUnit): +NULL_ADDRESS = '0x0000000000000000000000000000000000000000' - if freezePeriod is None: - if temporalUnit == 0: - freezePeriod = 10 * 17 - else: - freezePeriod = 10 - if windowSize is None: - if temporalUnit == 0: - windowSize = 255 * 17 - else: - windowSize = 255 +class TxnData(object): + """ + callData="", + toAddress=txn_recorder.address, + callGas=1000000, + callValue=0, + requiredStackDepth=0, + """ + def __init__(self, to_address, call_data, call_gas, call_value, required_stack_depth): + self.to_address = to_ad + pass - if windowStart is None: - if temporalUnit == 0: - windowStart = web3.eth.getBlock('latest')['timestamp'] + freezePeriod - else: - windowStart = web3.eth.blockNumber + freezePeriod - if reservedWindowSize is None: - if temporalUnit == 0: - reservedWindowSize = 16 * 17 - else: - reservedWindowSize = 16 +class Schedule(object): + """ + claimWindowSize=255, + freezePeriod=None, + windowStart=None, + windowSize=None, + reservedWindowSize=None, + temporalUnit=1): + """ + pass - self.claimData = type('claimData', (object,), { - 'claimedBy': claimedBy, - 'claimDeposit': claimDeposit, - 'paymentModifier': paymentModifier, - }) - self.meta = type('meta', (object,), { - 'createdBy': createdBy, - 'owner': owner, - 'isCancelled': isCancelled, - 'wasCalled': wasCalled, - 'wasSuccessful': wasSuccessful, - }) - self.paymentData = type('paymentData', (object,), { - 'anchorGasPrice': anchorGasPrice, - 'donation': donation, - 'donationBenefactor': donationBenefactor, - 'donationOwed': donationOwed, - 'payment': payment, - 'paymentBenefactor': paymentBenefactor, - 'paymentOwed': paymentOwed, - }) - self.txnData = type('txnData', (object,), { - 'callData': callData, - 'toAddress': toAddress, - 'callGas': callGas, - 'callValue': callValue, - 'requiredStackDepth': requiredStackDepth, - }) - self.schedule = type('schedule', (object,), { - 'claimWindowSize': claimWindowSize, - 'freezePeriod': freezePeriod, - 'reservedWindowSize': reservedWindowSize, - 'temporalUnit': temporalUnit, - 'windowStart': windowStart, - 'windowSize': windowSize, - }) - def to_factory_kwargs(self): - return { - 'addressArgs': [ - self.meta.owner, - self.paymentData.donationBenefactor, - self.txnData.toAddress, - ], - 'uintArgs': [ - self.paymentData.donation, - self.paymentData.payment, - self.schedule.claimWindowSize, - self.schedule.freezePeriod, - self.schedule.reservedWindowSize, - self.schedule.temporalUnit, - self.schedule.windowStart, - self.schedule.windowSize, - self.txnData.callGas, - self.txnData.callValue, - self.txnData.requiredStackDepth, - ], - 'callData': self.txnData.callData, - } +class ClaimData(object): + """ + claimedBy=NULL_ADDRESS, + claimDeposit=0, + paymentModifier=0, + """ + pass - def deploy_via_factory(self, deploy_txn=None): - if deploy_txn is None: - deploy_txn = {'value': 10 * denoms.ether} - create_txn_hash = request_factory.transact( - deploy_txn, - ).createRequest( - **self.to_factory_kwargs() - ) - txn_request = get_txn_request(create_txn_hash) - return txn_request - def to_init_kwargs(self): - return { - 'addressArgs': [ - self.meta.createdBy, - self.meta.owner, - self.paymentData.donationBenefactor, - self.txnData.toAddress, - ], - 'uintArgs': [ - self.paymentData.donation, - self.paymentData.payment, - self.schedule.claimWindowSize, - self.schedule.freezePeriod, - self.schedule.reservedWindowSize, - self.schedule.temporalUnit, - self.schedule.windowStart, - self.schedule.windowSize, - self.txnData.callGas, - self.txnData.callValue, - self.txnData.requiredStackDepth, - ], - 'callData': self.txnData.callData, - } +class PaymentData(object): + """ + anchorGasPrice=web3.eth.gasPrice, + donation=12345, + donationBenefactor='0xd3cda913deb6f67967b99d67acdfa1712c293601', + donationOwed=0, + payment=54321, + paymentBenefactor=NULL_ADDRESS, + paymentOwed=0, + """ + pass - def direct_deploy(self, deploy_txn=None): - if deploy_txn is None: - deploy_txn = {'value': 10 * denoms.ether} - deploy_txn_hash = TransactionRequest.deploy( - transaction=deploy_txn, - kwargs=self.to_init_kwargs(), - ) - txn_request_address = chain.wait.for_contract_address(deploy_txn_hash) - return TransactionRequest(address=txn_request_address) - def refresh(self): - if not self._contract: - raise ValueError("No contract set") - self.__dict__.update(self.from_contract(self._contract).__dict__) +class Meta(object): + """ + createdBy=web3.eth.coinbase, + owner=web3.eth.coinbase, + isCancelled=False, + wasCalled=False, + wasSuccessful=False, + """ + pass - @classmethod - def from_contract(cls, txn_request): - address_args, bool_args, uint_args, uint8_args = txn_request.call().requestData() - call_data = txn_request.call().callData() - instance = cls.from_deserialize( - address_args, bool_args, uint_args, uint8_args, call_data, - ) - instance._contract = txn_request - return instance - @classmethod - def from_deserialize(cls, address_args, bool_args, uint_args, uint8_args, call_data): - init_kwargs = { - 'claimedBy': address_args[0], - 'createdBy': address_args[1], - 'owner': address_args[2], - 'donationBenefactor': address_args[3], - 'paymentBenefactor': address_args[4], - 'toAddress': address_args[5], - 'wasCalled': bool_args[1], - 'wasSuccessful': bool_args[2], - 'isCancelled': bool_args[0], - 'paymentModifier': uint8_args[0], - 'claimDeposit': uint_args[0], - 'anchorGasPrice': uint_args[1], - 'donation': uint_args[2], - 'donationOwed': uint_args[3], - 'payment': uint_args[4], - 'paymentOwed': uint_args[5], - 'claimWindowSize': uint_args[6], - 'freezePeriod': uint_args[7], - 'reservedWindowSize': uint_args[8], - 'temporalUnit': uint_args[9], - 'windowStart': uint_args[10], - 'windowSize': uint_args[11], - 'callGas': uint_args[12], - 'callValue': uint_args[13], - 'requiredStackDepth': uint_args[14], - 'callData': call_data, - } - return cls(**init_kwargs) +class BaseTransactionRequestFactory(ContractFactory): diff --git a/tests/block-scheduling/test_scheduling.py b/tests/block-scheduling/test_scheduling.py index 471994929..d7e41caf2 100644 --- a/tests/block-scheduling/test_scheduling.py +++ b/tests/block-scheduling/test_scheduling.py @@ -33,7 +33,9 @@ def test_scheduling_with_full_args(chain, window_start, # windowStart ], ) - web3.eth.getTransactionReceipt(schedule_txn_hash) + schedule_txn_receipt = web3.eth.getTransactionReceipt(schedule_txn_hash) + + assert schedule_txn_receipt['gasUsed'] < 1200000 txn_request = get_txn_request(schedule_txn_hash) request_data = RequestData.from_contract(txn_request) diff --git a/tests/transaction-request/test_accounting.py b/tests/transaction-request/test_accounting.py index c9aab77bd..c86a70957 100644 --- a/tests/transaction-request/test_accounting.py +++ b/tests/transaction-request/test_accounting.py @@ -36,3 +36,7 @@ def test_txn_request_payments(chain, assert payment - expected_payment < 120000 * gas_price assert after_payment_balance - before_payment_balance == payment - gas_cost + + +def test_txn_request_payments_when_claimed(chain, web3, get_execute_data, RequestData): + assert False diff --git a/tests/transaction-request/test_claiming.py b/tests/transaction-request/test_claiming.py index d60858d06..3b8219b72 100644 --- a/tests/transaction-request/test_claiming.py +++ b/tests/transaction-request/test_claiming.py @@ -1,5 +1,9 @@ import pytest +from web3.utils.encoding import ( + decode_hex, +) + def test_cannot_claim_before_first_claim_block(chain, web3, RequestData, get_claim_data): txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() @@ -67,7 +71,7 @@ def test_can_claim_at_last_claim_block(chain, web3, RequestData): assert request_data.claimData.claimedBy == web3.eth.coinbase -def test_cannot_claim_after_last_claim_block(chain, web3, RequestData): +def test_cannot_claim_after_last_claim_block(chain, web3, RequestData, get_claim_data): txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() request_data = RequestData.from_contract(txn_request) @@ -142,13 +146,14 @@ def test_deposit_returned_if_claim_rejected(chain, web3, RequestData, get_claim_ 'value': deposit_amount, 'from': web3.eth.accounts[1], }).claim() - chain.wait.for_receipt(claim_txn_hash) + claim_txn = web3.eth.getTransaction(claim_txn_hash) + claim_txn_receipt = chain.wait.for_receipt(claim_txn_hash) after_contract_balance = web3.eth.getBalance(txn_request.address) after_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) assert after_contract_balance == before_contract_balance - assert after_account_balance == before_account_balance + assert after_account_balance == before_account_balance - claim_txn['gasPrice'] * claim_txn_receipt['gasUsed'] with pytest.raises(AssertionError): get_claim_data(claim_txn_hash) @@ -171,20 +176,22 @@ def test_deposit_returned_even_if_returning_it_throws(chain, web3, RequestData, deposit_amount = 2 * request_data.paymentData.payment before_contract_balance = web3.eth.getBalance(txn_request.address) - before_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) + before_account_balance = web3.eth.getBalance(proxy.address) + + assert before_account_balance == 0 - claim_call_data = txn_request._encode_transaction_data('claim') + claim_call_data = decode_hex(txn_request._encode_transaction_data('claim')) - with pytest.raises(ValueError): - proxy.transact({ - 'value': deposit_amount, - }).__proxy(txn_request.address, claim_call_data) + claim_txn_hash = proxy.transact({ + 'value': deposit_amount, + }).__proxy(txn_request.address, claim_call_data, ) + chain.wait.for_receipt(claim_txn_hash) after_contract_balance = web3.eth.getBalance(txn_request.address) - after_account_balance = web3.eth.getBalance(web3.eth.accounts[1]) + after_account_balance = web3.eth.getBalance(proxy.address) assert after_contract_balance == before_contract_balance - assert after_account_balance == before_account_balance + assert after_account_balance == deposit_amount request_data.refresh() assert request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' @@ -207,7 +214,7 @@ def test_executing_own_claimed_call(chain, web3, RequestData, get_execute_data, }).claim() chain.wait.for_receipt(claim_txn_hash) - request_data = request_data.refresh() + request_data.refresh() assert request_data.claimData.claimedBy == web3.eth.accounts[1] assert get_claim_data(claim_txn_hash) @@ -219,14 +226,47 @@ def test_executing_own_claimed_call(chain, web3, RequestData, get_execute_data, }).execute() chain.wait.for_receipt(execute_txn_hash) - request_data = request_data.refresh() + request_data.refresh() assert request_data.meta.wasCalled is True assert get_execute_data(execute_txn_hash) -def test_executing_other_claimed_call_after_reserved_window(): - assert False +def test_executing_other_claimed_call_after_reserved_window(chain, + web3, + RequestData, + get_claim_data, + get_execute_data): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + first_claim_block = request_data.schedule.windowStart - request_data.schedule.freezePeriod - request_data.schedule.claimWindowSize + + # sanity + assert first_claim_block > web3.eth.blockNumber + + chain.wait.for_block(first_claim_block) + + claim_txn_hash = txn_request.transact({ + 'value': 2 * request_data.paymentData.payment, + 'from': web3.eth.accounts[1], + }).claim() + chain.wait.for_receipt(claim_txn_hash) + + request_data.refresh() + assert request_data.claimData.claimedBy == web3.eth.accounts[1] + + assert get_claim_data(claim_txn_hash) + + chain.wait.for_block(request_data.schedule.windowStart + request_data.schedule.reservedWindowSize) + + execute_txn_hash = txn_request.transact().execute() + chain.wait.for_receipt(execute_txn_hash) + + request_data.refresh() + assert request_data.meta.wasCalled is True + + assert get_execute_data(execute_txn_hash) def test_claim_block_determines_payment_amount(): From 158f12fba6e620668fa5c1274c5ef97e4eafca4e Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Fri, 23 Sep 2016 11:40:44 +0800 Subject: [PATCH 25/25] fix sending back payments --- contracts/PaymentLib.sol | 2 +- contracts/RequestLib.sol | 6 +- contracts/SafeSendLib.sol | 15 +- contracts/TransactionRequest.sol | 2 +- tests/TestErrors.sol | 20 ++- tests/transaction-request/test_accounting.py | 151 ++++++++++++++++++- tests/transaction-request/test_claiming.py | 35 ++++- 7 files changed, 212 insertions(+), 19 deletions(-) diff --git a/contracts/PaymentLib.sol b/contracts/PaymentLib.sol index d8b5aae79..37f7d1d72 100644 --- a/contracts/PaymentLib.sol +++ b/contracts/PaymentLib.sol @@ -86,7 +86,7 @@ library PaymentLib { */ function getPaymentWithModifier(PaymentData storage self, uint8 paymentModifier) returns (uint) { - return getPayment(self).safeMultiply(100) / paymentModifier; + return getPayment(self).safeMultiply(paymentModifier) / 100; } /* diff --git a/contracts/RequestLib.sol b/contracts/RequestLib.sol index 49c6e059d..65e2b634f 100644 --- a/contracts/RequestLib.sol +++ b/contracts/RequestLib.sol @@ -553,7 +553,7 @@ library RequestLib { */ function refundClaimDeposit(Request storage self) returns (bool) { if (self.meta.isCancelled || self.meta.wasCalled) { - return self.claimData.refundDeposit(msg.gas); + return self.claimData.refundDeposit(0); } return false; } @@ -563,7 +563,7 @@ library RequestLib { */ function sendDonation(Request storage self) returns (bool) { if (self.meta.wasCalled) { - return self.paymentData.sendDonation(msg.gas); + return self.paymentData.sendDonation(0); } return false; } @@ -573,7 +573,7 @@ library RequestLib { */ function sendPayment(Request storage self) returns (bool) { if (self.meta.wasCalled) { - return self.paymentData.sendPayment(msg.gas); + return self.paymentData.sendPayment(0); } return false; } diff --git a/contracts/SafeSendLib.sol b/contracts/SafeSendLib.sol index 6d33d51c8..3e35abbb1 100644 --- a/contracts/SafeSendLib.sol +++ b/contracts/SafeSendLib.sol @@ -36,11 +36,20 @@ library SafeSendLib { throw; } - if (!to.call.value(value).gas(sendGas)()) { - SendFailed(to, value); - return 0; + if (sendGas > 0) { + // 0 send gas indicates sending all send gas. + if (!to.call.value(value).gas(sendGas)()) { + SendFailed(to, value); + return 0; + } + } else { + if (!to.call.value(value)()) { + SendFailed(to, value); + return 0; + } } + return value; } diff --git a/contracts/TransactionRequest.sol b/contracts/TransactionRequest.sol index 620df4c64..12d8e20ac 100644 --- a/contracts/TransactionRequest.sol +++ b/contracts/TransactionRequest.sol @@ -89,6 +89,6 @@ contract TransactionRequest is Digger { } function sendOwnerEther() public returns (bool) { - return txnRequest.sendOwnerEther(); + return txnRequest.sendOwnerEther(0); } } diff --git a/tests/TestErrors.sol b/tests/TestErrors.sol index 381226809..581ef8360 100644 --- a/tests/TestErrors.sol +++ b/tests/TestErrors.sol @@ -2,17 +2,29 @@ import {Proxy} from "tests/Proxy.sol"; contract ErrorGenerator is Proxy { + bool public shouldThrow; + + function ErrorGenerator() { + shouldThrow = true; + } + + function toggle() { + shouldThrow = !shouldThrow; + } + function doThrow() { - doThrow(true); + doThrow(shouldThrow); } - function doThrow(bool shouldThrow) { - if (shouldThrow) { + function doThrow(bool _shouldThrow) { + if (_shouldThrow) { throw; } } function() { - throw; + if (shouldThrow) { + throw; + } } } diff --git a/tests/transaction-request/test_accounting.py b/tests/transaction-request/test_accounting.py index c86a70957..5189cd00d 100644 --- a/tests/transaction-request/test_accounting.py +++ b/tests/transaction-request/test_accounting.py @@ -1,3 +1,6 @@ +from web3.utils.encoding import decode_hex + + def test_txn_request_payments(chain, web3, get_execute_data, @@ -39,4 +42,150 @@ def test_txn_request_payments(chain, def test_txn_request_payments_when_claimed(chain, web3, get_execute_data, RequestData): - assert False + txn_request = RequestData(donation=12345, windowStart=web3.eth.blockNumber + 10 + 255 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + before_payment_balance = web3.eth.getBalance(web3.eth.accounts[1]) + + claim_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - 5 + + assert claim_at > web3.eth.blockNumber + + chain.wait.for_block(claim_at) + + claim_deposit = 2 * request_data.paymentData.payment + assert claim_deposit > 0 + + claim_txn_hash = txn_request.transact({ + 'value': claim_deposit, + 'from': web3.eth.accounts[1], + }).claim() + claim_txn = web3.eth.getTransaction(claim_txn_hash) + claim_txn_receipt = chain.wait.for_receipt(claim_txn_hash) + claim_gas_cost = claim_txn['gasPrice'] * claim_txn_receipt['gasUsed'] + + after_claim_balance = web3.eth.getBalance(web3.eth.accounts[1]) + assert before_payment_balance - after_claim_balance == claim_deposit + claim_gas_cost + + request_data.refresh() + + assert request_data.claimData.claimedBy == web3.eth.accounts[1] + + chain.wait.for_block(request_data.schedule.windowStart) + + execute_txn_hash = txn_request.transact({'from': web3.eth.accounts[1]}).execute() + execute_txn = web3.eth.getTransaction(execute_txn_hash) + execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) + + request_data.refresh() + + execute_data = get_execute_data(execute_txn_hash) + + after_payment_balance = web3.eth.getBalance(web3.eth.accounts[1]) + + payment = execute_data['args']['payment'] + + gas_price = execute_txn['gasPrice'] + gas_used = execute_txn_receipt['gasUsed'] + gas_cost = gas_used * gas_price + + expected_payment = claim_deposit + gas_cost + request_data.claimData.paymentModifier * request_data.paymentData.payment // 100 + + assert payment >= expected_payment + assert payment - expected_payment < 150000 * gas_price + + assert after_payment_balance - before_payment_balance == payment - claim_deposit - gas_cost - claim_gas_cost + + +def test_accounting_when_everything_throws(chain, + web3, + get_execute_data, + RequestData, + error_generator): + txn_request = RequestData( + createdBy=error_generator.address, + owner=error_generator.address, + donationBenefactor=error_generator.address, + toAddress=error_generator.address, + callData=decode_hex(error_generator._encode_transaction_data('doThrow')), + windowStart=web3.eth.blockNumber + 10 + 255 + 5, + ).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + claim_at = request_data.schedule.windowStart - 10 - 5 + deposit_amount = request_data.paymentData.payment * 2 + + assert claim_at > web3.eth.blockNumber + + chain.wait.for_block(claim_at) + + claim_call_data = decode_hex(txn_request._encode_transaction_data('claim')) + claim_txn_hash = error_generator.transact({ + 'value': deposit_amount, + }).__proxy(txn_request.address, claim_call_data, ) + chain.wait.for_receipt(claim_txn_hash) + + chain.wait.for_block(request_data.schedule.windowStart) + + execute_call_data = decode_hex(txn_request._encode_transaction_data('execute')) + + execute_txn_hash = error_generator.transact({'from': web3.eth.accounts[1]}).__proxy( + to=txn_request.address, + callData=execute_call_data, + ) + execute_txn_receipt = chain.wait.for_receipt(execute_txn_hash) + + execute_data = get_execute_data(execute_txn_hash) + request_data.refresh() + + assert request_data.meta.wasCalled is True + assert request_data.meta.wasSuccessful is False + + gas_used = execute_txn_receipt['gasUsed'] + measured_gas_consumption = execute_data['args']['measuredGasConsumption'] + + assert measured_gas_consumption > gas_used + assert measured_gas_consumption - gas_used < 50000 + + payment_owed = request_data.paymentData.paymentOwed + donation_owed = request_data.paymentData.donationOwed + + assert payment_owed > 0 + assert payment_owed == execute_data['args']['payment'] + assert donation_owed > 0 + assert donation_owed == execute_data['args']['donation'] + + # make the contract stop throwing now. + chain.wait.for_receipt(error_generator.transact().toggle()) + assert error_generator.call().shouldThrow() is False + + before_payments_contract_balance = web3.eth.getBalance(txn_request.address) + + before_owner_refund_balance = web3.eth.getBalance(error_generator.address) + + issue_owner_refund_txn_hash = txn_request.transact().sendOwnerEther() + chain.wait.for_receipt(issue_owner_refund_txn_hash) + + after_owner_refund_balance = web3.eth.getBalance(error_generator.address) + owner_refund = after_owner_refund_balance - before_owner_refund_balance + assert owner_refund > 0 + + before_payment_balance = web3.eth.getBalance(error_generator.address) + + issue_payment_txn_hash = txn_request.transact().sendPayment() + chain.wait.for_receipt(issue_payment_txn_hash) + request_data.refresh() + + after_payment_balance = web3.eth.getBalance(error_generator.address) + assert after_payment_balance - before_payment_balance == payment_owed + + before_donation_balance = web3.eth.getBalance(error_generator.address) + + issue_donation_txn_hash = txn_request.transact().sendDonation() + chain.wait.for_receipt(issue_donation_txn_hash) + request_data.refresh() + + after_donation_balance = web3.eth.getBalance(error_generator.address) + assert after_donation_balance - before_donation_balance == donation_owed + + assert owner_refund + payment_owed + donation_owed == before_payments_contract_balance diff --git a/tests/transaction-request/test_claiming.py b/tests/transaction-request/test_claiming.py index 3b8219b72..0ac497f39 100644 --- a/tests/transaction-request/test_claiming.py +++ b/tests/transaction-request/test_claiming.py @@ -162,7 +162,11 @@ def test_deposit_returned_if_claim_rejected(chain, web3, RequestData, get_claim_ assert request_data.claimData.claimedBy == '0x0000000000000000000000000000000000000000' -def test_deposit_returned_even_if_returning_it_throws(chain, web3, RequestData, get_claim_data, proxy): +def test_deposit_returned_even_if_returning_it_throws(chain, + web3, + RequestData, + get_claim_data, + error_generator): txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() request_data = RequestData.from_contract(txn_request) @@ -176,19 +180,19 @@ def test_deposit_returned_even_if_returning_it_throws(chain, web3, RequestData, deposit_amount = 2 * request_data.paymentData.payment before_contract_balance = web3.eth.getBalance(txn_request.address) - before_account_balance = web3.eth.getBalance(proxy.address) + before_account_balance = web3.eth.getBalance(error_generator.address) assert before_account_balance == 0 claim_call_data = decode_hex(txn_request._encode_transaction_data('claim')) - claim_txn_hash = proxy.transact({ + claim_txn_hash = error_generator.transact({ 'value': deposit_amount, }).__proxy(txn_request.address, claim_call_data, ) chain.wait.for_receipt(claim_txn_hash) after_contract_balance = web3.eth.getBalance(txn_request.address) - after_account_balance = web3.eth.getBalance(proxy.address) + after_account_balance = web3.eth.getBalance(error_generator.address) assert after_contract_balance == before_contract_balance assert after_account_balance == deposit_amount @@ -269,5 +273,24 @@ def test_executing_other_claimed_call_after_reserved_window(chain, assert get_execute_data(execute_txn_hash) -def test_claim_block_determines_payment_amount(): - assert False +def test_claim_block_determines_payment_amount(chain, web3, RequestData): + txn_request = RequestData(windowStart=web3.eth.blockNumber + 255 + 10 + 5).direct_deploy() + request_data = RequestData.from_contract(txn_request) + + claim_at = request_data.schedule.windowStart - request_data.schedule.freezePeriod - request_data.schedule.claimWindowSize + request_data.schedule.claimWindowSize * 2 // 3 + + expected_payment_modifier = 100 * 2 // 3 + + # sanity + assert request_data.claimData.paymentModifier == 0 + assert claim_at > web3.eth.blockNumber + + chain.wait.for_block(claim_at) + + claim_txn_hash = txn_request.transact({ + 'value': 2 * request_data.paymentData.payment, + }).claim() + chain.wait.for_receipt(claim_txn_hash) + + request_data.refresh() + assert request_data.claimData.paymentModifier == expected_payment_modifier