def scheduler(address): """ Run the call scheduler. """ Alarm = get_contract('Alarm') alarm = Alarm(address, rpc_client) block_sage = BlockSage(rpc_client) pool_manager = PoolManager(alarm, block_sage=block_sage) pool_manager.monitor_async() scheduler = Scheduler(alarm, pool_manager, block_sage=block_sage) scheduler.monitor_async() try: while scheduler._thread.is_alive(): time.sleep(1) except KeyboardInterrupt: scheduler.stop() scheduler.block_sage.stop() scheduler.pool_manager.stop() for scheduled_call in scheduler.active_calls.values(): scheduled_call.stop() scheduler._thread.join(5)
def test_scheduler(geth_node, geth_node_config, deploy_client, deployed_contracts, contracts): block_sage = BlockSage(deploy_client) alarm = deployed_contracts.Alarm client_contract = deployed_contracts.SpecifyBlock deposit_amount = get_max_gas( deploy_client) * deploy_client.get_gas_price() * 20 alarm.deposit.sendTransaction(client_contract._meta.address, value=deposit_amount) anchor_block = deploy_client.get_block_number() blocks = (1, 4, 4, 8, 30, 40, 50, 60) call_keys = [] for n in blocks: wait_for_transaction( deploy_client, client_contract.scheduleIt.sendTransaction(alarm._meta.address, anchor_block + 100 + n)) last_call_key = alarm.getLastCallKey() assert last_call_key is not None call_keys.append(last_call_key) pool_manager = PoolManager(alarm, block_sage) scheduler = Scheduler(alarm, pool_manager, block_sage=block_sage) scheduler.monitor_async() final_block = anchor_block + 100 + 70 wait_for_block( deploy_client, final_block, 2 * block_sage.estimated_time_to_block(final_block), ) scheduler.stop() block_sage.stop() results = [alarm.checkIfCalled(k) for k in call_keys] assert all(results)
def test_scheduler(geth_node, geth_node_config, deploy_client, deployed_contracts, contracts, get_call, denoms): block_sage = BlockSage(deploy_client) scheduler = deployed_contracts.Scheduler client_contract = deployed_contracts.TestCallExecution anchor_block = deploy_client.get_block_number() blocks = (1, 4, 4, 8, 30, 40, 50, 60) calls = [] for n in blocks: scheduling_txn = scheduler.scheduleCall( client_contract._meta.address, client_contract.setBool.encoded_abi_signature, anchor_block + 100 + n, 1000000, value=10 * denoms.ether, gas=3000000, ) scheduling_receipt = deploy_client.wait_for_transaction(scheduling_txn) call = get_call(scheduling_txn) calls.append(call) pool_manager = PoolManager(scheduler, block_sage) scheduler = Scheduler(scheduler, pool_manager, block_sage=block_sage) scheduler.monitor_async() final_block = anchor_block + 100 + 80 deploy_client.wait_for_block( final_block, 2 * block_sage.estimated_time_to_block(final_block), ) scheduler.stop() block_sage.stop() did_suicide = [len(deploy_client.get_code(call._meta.address)) <= 2 for call in calls] assert all(did_suicide)
def test_scheduler(geth_node, deployed_contracts, deploy_client, scheduled_calls): block_sage = BlockSage(deploy_client) scheduler = Scheduler(deployed_contracts.Scheduler, block_sage=block_sage) scheduler.monitor_async() last_call = scheduled_calls[-1] final_block = last_call.targetBlock() + last_call.gracePeriod() + 1 for call in scheduled_calls: wait_til = call.targetBlock() - 5 deploy_client.wait_for_block( wait_til, block_sage.estimated_time_to_block(wait_til) * 2, ) time.sleep(2) wait_til = scheduled_calls[-1].targetBlock() + 50 deploy_client.wait_for_block( wait_til, block_sage.estimated_time_to_block(wait_til) * 2, ) scheduler.stop() block_sage.stop() was_called = [call.wasCalled() for call in scheduled_calls] assert all(was_called)
def test_scheduler(geth_node, geth_node_config, deploy_client, deployed_contracts, contracts): block_sage = BlockSage(deploy_client) alarm = deployed_contracts.Alarm client_contract = deployed_contracts.SpecifyBlock deposit_amount = get_max_gas(deploy_client) * deploy_client.get_gas_price() * 20 alarm.deposit.sendTransaction(client_contract._meta.address, value=deposit_amount) anchor_block = deploy_client.get_block_number() blocks = (1, 4, 4, 8, 30, 40, 50, 60) call_keys = [] for n in blocks: wait_for_transaction(deploy_client, client_contract.scheduleIt.sendTransaction(alarm._meta.address, anchor_block + 100 + n)) last_call_key = alarm.getLastCallKey() assert last_call_key is not None call_keys.append(last_call_key) pool_manager = PoolManager(alarm, block_sage) scheduler = Scheduler(alarm, pool_manager, block_sage=block_sage) scheduler.monitor_async() final_block = anchor_block + 100 + 70 wait_for_block( deploy_client, final_block, 2 * block_sage.estimated_time_to_block(final_block), ) scheduler.stop() block_sage.stop() results = [alarm.checkIfCalled(k) for k in call_keys] assert all(results)
def scheduler(address, client, rpchost, rpcport, ipcpath): """ Run the call scheduler. """ if client == 'ipc': blockchain_client = IPCClient(ipc_path=ipcpath) elif client == 'rpc': blockchain_client = RPCClient(host=rpchost, port=rpcport) SchedulerContract = get_contract('Scheduler') scheduler_contract = SchedulerContract(address, blockchain_client) try: api_version = scheduler_contract.callAPIVersion() if api_version != 7: raise click.ClickException( "The scheduling contract address does not appear to have a compatable API" ) except EmptyDataError: raise click.ClickException( "The scheduler address seems to not be correct. Using {0}. You " "may need to specify the address using `--address` if you are " "running the client against a test network".format(address)) block_sage = BlockSage(blockchain_client) scheduler = Scheduler(scheduler_contract, block_sage=block_sage) scheduler.monitor_async() try: while scheduler._thread.is_alive(): time.sleep(1) except KeyboardInterrupt: scheduler.stop() scheduler.block_sage.stop() for scheduled_call in scheduler.active_calls.values(): scheduled_call.stop() scheduler._thread.join(5)
def test_scheduled_call_execution_with_pool(geth_node, geth_coinbase, geth_node_config, deploy_client, deployed_contracts, contracts): alarm = deployed_contracts.Alarm joiner = deployed_contracts.JoinsPool client_contract = deployed_contracts.SpecifyBlock coinbase = geth_coinbase block_sage = BlockSage(deploy_client) # Put in our deposit with the alarm contract. deposit_amount = get_max_gas( deploy_client) * deploy_client.get_gas_price() * 20 alarm.deposit.sendTransaction(client_contract._meta.address, value=deposit_amount) wait_for_transaction( deploy_client, joiner.setCallerPool.sendTransaction(alarm._meta.address)) assert alarm.getBondBalance(coinbase) == 0 bond_amount = alarm.getMinimumBond() * 10 # Put in our bond wait_for_transaction(deploy_client, alarm.depositBond.sendTransaction(value=bond_amount)) # Put the contract's bond in wait_for_transaction( deploy_client, deploy_client.send_transaction(to=joiner._meta.address, value=bond_amount)) wait_for_transaction(deploy_client, joiner.deposit.sendTransaction(bond_amount)) # Both join the pool wait_for_transaction(deploy_client, joiner.enter.sendTransaction()) wait_for_transaction(deploy_client, alarm.enterPool.sendTransaction()) # New pool is formed but not active first_generation_id = alarm.getNextGenerationId() assert first_generation_id > 0 # Go ahead and schedule the call. generation_start_at = alarm.getGenerationStartAt(first_generation_id) target_block = generation_start_at + 5 txn_hash = client_contract.scheduleIt.sendTransaction( alarm._meta.address, target_block) wait_for_transaction(deploy_client, txn_hash) # Wait for the pool to become active wait_for_block( deploy_client, generation_start_at, 2 * block_sage.estimated_time_to_block(generation_start_at), ) # We should both be in the pool assert alarm.getCurrentGenerationId() == first_generation_id assert alarm.isInGeneration(joiner._meta.address, first_generation_id) is True assert alarm.isInGeneration(coinbase, first_generation_id) is True call_key = alarm.getLastCallKey() assert call_key is not None scheduled_call = ScheduledCall(alarm, call_key, block_sage=block_sage) pool_manager = PoolManager(alarm, block_sage=block_sage) scheduled_call.execute_async() wait_for_block( deploy_client, scheduled_call.target_block, 2 * block_sage.estimated_time_to_block(scheduled_call.target_block), ) for i in range(alarm.getCallWindowSize() * 2): if scheduled_call.txn_hash: break time.sleep(block_sage.block_time) assert scheduled_call.txn_hash assert scheduled_call.txn_receipt assert scheduled_call.txn assert scheduled_call.was_called assert alarm.checkIfCalled(scheduled_call.call_key) assert scheduled_call.target_block <= scheduled_call.called_at_block assert scheduled_call.called_at_block <= scheduled_call.target_block + scheduled_call.grace_period
def test_scheduled_call_execution_with_pool(geth_node, geth_node_config, deploy_client, deployed_contracts, contracts, deploy_coinbase, get_call, denoms, get_execution_data): scheduler = deployed_contracts.Scheduler joiner = deployed_contracts.JoinsPool client_contract = deployed_contracts.TestCallExecution block_sage = BlockSage(deploy_client) # Let the block sage spin up. time.sleep(4) join_txn_hash = joiner.setCallerPool(scheduler._meta.address) deploy_client.wait_for_transaction(join_txn_hash) assert scheduler.getBondBalance(deploy_coinbase) == 0 bond_amount = scheduler.getMinimumBond() * 10 # Put in our bond deploy_client.wait_for_transaction( scheduler.depositBond(value=bond_amount) ) # Put the contract's bond in deploy_client.wait_for_transaction( deploy_client.send_transaction(to=joiner._meta.address, value=bond_amount) ) deploy_client.wait_for_transaction( joiner.deposit(bond_amount) ) # Both join the pool deploy_client.wait_for_transaction(joiner.enter()) deploy_client.wait_for_transaction(scheduler.enterPool()) # New pool is formed but not active first_generation_id = scheduler.getNextGenerationId() assert first_generation_id > 0 # Go ahead and schedule the call. generation_start_at = scheduler.getGenerationStartAt(first_generation_id) target_block = generation_start_at + 5 scheduling_txn = scheduler.scheduleCall( client_contract._meta.address, client_contract.setBool.encoded_abi_signature, target_block, 1000000, value=10 * denoms.ether, gas=3000000, ) scheduling_receipt = deploy_client.wait_for_transaction(scheduling_txn) call = get_call(scheduling_txn) call_address = call._meta.address # Wait for the pool to become active deploy_client.wait_for_block( generation_start_at, 2 * block_sage.estimated_time_to_block(generation_start_at), ) # We should both be in the pool assert scheduler.getCurrentGenerationId() == first_generation_id assert scheduler.isInGeneration(joiner._meta.address, first_generation_id) is True assert scheduler.isInGeneration(deploy_coinbase, first_generation_id) is True scheduled_call = ScheduledCall(scheduler, call_address, block_sage=block_sage) pool_manager = PoolManager(scheduler, block_sage=block_sage) scheduled_call.execute_async() assert scheduled_call.has_been_suicided is False deploy_client.wait_for_block( scheduled_call.target_block, 2 * block_sage.estimated_time_to_block(scheduled_call.target_block), ) for i in range(scheduler.getCallWindowSize() * 2): if scheduled_call.txn_hash: break time.sleep(block_sage.block_time) assert scheduled_call.txn_hash assert scheduled_call.txn_receipt assert scheduled_call.txn execute_data = get_execution_data(scheduled_call.txn_hash) assert execute_data['success'] is True assert scheduled_call.has_been_suicided is True
def test_scheduled_call_execution_with_pool(geth_node, geth_coinbase, geth_node_config, deploy_client, deployed_contracts, contracts): alarm = deployed_contracts.Alarm joiner = deployed_contracts.JoinsPool client_contract = deployed_contracts.SpecifyBlock coinbase = geth_coinbase block_sage = BlockSage(deploy_client) # Put in our deposit with the alarm contract. deposit_amount = get_max_gas(deploy_client) * deploy_client.get_gas_price() * 20 alarm.deposit.sendTransaction(client_contract._meta.address, value=deposit_amount) wait_for_transaction(deploy_client, joiner.setCallerPool.sendTransaction(alarm._meta.address)) assert alarm.getBondBalance(coinbase) == 0 bond_amount = alarm.getMinimumBond() * 10 # Put in our bond wait_for_transaction( deploy_client, alarm.depositBond.sendTransaction(value=bond_amount) ) # Put the contract's bond in wait_for_transaction( deploy_client, deploy_client.send_transaction(to=joiner._meta.address, value=bond_amount) ) wait_for_transaction( deploy_client, joiner.deposit.sendTransaction(bond_amount) ) # Both join the pool wait_for_transaction(deploy_client, joiner.enter.sendTransaction()) wait_for_transaction(deploy_client, alarm.enterPool.sendTransaction()) # New pool is formed but not active first_generation_id = alarm.getNextGenerationId() assert first_generation_id > 0 # Go ahead and schedule the call. generation_start_at = alarm.getGenerationStartAt(first_generation_id) target_block = generation_start_at + 5 txn_hash = client_contract.scheduleIt.sendTransaction(alarm._meta.address, target_block) wait_for_transaction(deploy_client, txn_hash) # Wait for the pool to become active wait_for_block( deploy_client, generation_start_at, 2 * block_sage.estimated_time_to_block(generation_start_at), ) # We should both be in the pool assert alarm.getCurrentGenerationId() == first_generation_id assert alarm.isInGeneration(joiner._meta.address, first_generation_id) is True assert alarm.isInGeneration(coinbase, first_generation_id) is True call_key = alarm.getLastCallKey() assert call_key is not None scheduled_call = ScheduledCall(alarm, call_key, block_sage=block_sage) pool_manager = PoolManager(alarm, block_sage=block_sage) scheduled_call.execute_async() wait_for_block( deploy_client, scheduled_call.target_block, 2 * block_sage.estimated_time_to_block(scheduled_call.target_block), ) for i in range(alarm.getCallWindowSize() * 2): if scheduled_call.txn_hash: break time.sleep(block_sage.block_time) assert scheduled_call.txn_hash assert scheduled_call.txn_receipt assert scheduled_call.txn assert scheduled_call.was_called assert alarm.checkIfCalled(scheduled_call.call_key) assert scheduled_call.target_block <= scheduled_call.called_at_block assert scheduled_call.called_at_block <= scheduled_call.target_block + scheduled_call.grace_period