diff --git a/.circleci/config.yml b/.circleci/config.yml index 5658503bc..23d621b0e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -126,6 +126,16 @@ workflows: - deployers - config - character + - estimate_gas: + context: "NuCypher Tests" + filters: + tags: + only: /.*/ + requires: + - actors + - deployers + - config + - character # # TODO: Initial Publication Automation @@ -421,6 +431,19 @@ jobs: - store_artifacts: path: ./mypy_reports + estimate_gas: + <<: *python_36_base + steps: + - checkout + - attach_workspace: + at: ~/.local/share/virtualenvs/ + - run: + name: Estimate Gas + command: | + pipenv run python tests/metrics/estimate_gas.py + - store_artifacts: + path: tests/metrics/results/ + test_build: <<: *python_36_base steps: diff --git a/Pipfile b/Pipfile index 70672d802..c7ce1e6ea 100644 --- a/Pipfile +++ b/Pipfile @@ -65,6 +65,7 @@ pytest-mock = "*" [scripts] install-solc = "./scripts/install_solc.sh" +estimate-gas = "python3 tests/metrics/estimate_gas.py" nucypher = "python3 nucypher/cli.py" [pipenv] diff --git a/nucypher/blockchain/eth/scripts/estimate_gas_tester.py b/nucypher/blockchain/eth/scripts/estimate_gas_tester.py deleted file mode 100755 index ccccfb716..000000000 --- a/nucypher/blockchain/eth/scripts/estimate_gas_tester.py +++ /dev/null @@ -1,518 +0,0 @@ -#!/usr/bin/env python3 -""" -This file is part of nucypher. - -nucypher is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -nucypher is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with nucypher. If not, see . -""" - -""" -Deploy contracts in tester. -A simple Python script to deploy contracts and then estimate gas for different methods. -""" - -import os -import sys - - -sys.path.append(os.path.abspath(os.getcwd())) - -from os.path import dirname, abspath - -from eth_tester import EthereumTester -from web3 import EthereumTesterProvider -from constant_sorrow import constants - -from nucypher.blockchain.eth.chains import TesterBlockchain -from nucypher.blockchain.eth.deployers import NucypherTokenDeployer, MinerEscrowDeployer, PolicyManagerDeployer -from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface -from nucypher.blockchain.eth.sol.compile import SolidityCompiler - -from nucypher.blockchain.eth import sol - -CONTRACTS_DIR = os.path.join(dirname(abspath(sol.__file__)), 'source', 'contracts') - - -def estimate_gas(): - solidity_compiler = SolidityCompiler(test_contract_dir=CONTRACTS_DIR) - - # create a temporary registrar for the tester blockchain - temporary_registry = TemporaryEthereumContractRegistry() - - # Configure a custom provider - overrides = {'gas_limit': 4626271} - pyevm_backend = OverridablePyEVMBackend(genesis_overrides=overrides) - - eth_tester = EthereumTester(backend=pyevm_backend, auto_mine_transactions=True) - pyevm_provider = EthereumTesterProvider(ethereum_tester=eth_tester) - - # Use the the custom provider and registrar to init an interface - circumflex = BlockchainDeployerInterface(compiler=solidity_compiler, # freshly recompile - registry=temporary_registry, # use temporary registrar - providers=(pyevm_provider,)) # use custom test provider - - # Create the blockchain - testerchain = TesterBlockchain(interface=circumflex, test_accounts=10) - origin, ursula1, ursula2, ursula3, alice1, *everyone_else = testerchain.interface.w3.eth.accounts - circumflex.deployer_address = origin # Set the deployer address from a freshly created test account - - token_deployer = NucypherTokenDeployer(blockchain=testerchain, deployer_address=origin) - - token_deployer.deploy() - token_agent = token_deployer.make_agent() - - miners_escrow_secret = os.urandom(constants.DISPATCHER_SECRET_LENGTH) - miner_escrow_deployer = MinerEscrowDeployer( - token_agent=token_agent, - deployer_address=origin, - secret_hash=testerchain.interface.w3.sha3(miners_escrow_secret)) - - miner_escrow_deployer.deploy() - miner_agent = miner_escrow_deployer.make_agent() - - policy_manager_secret = os.urandom(constants.DISPATCHER_SECRET_LENGTH) - policy_manager_deployer = PolicyManagerDeployer( - miner_agent=miner_agent, - deployer_address=origin, - secret_hash=testerchain.interface.w3.sha3(policy_manager_secret)) - - policy_manager_deployer.deploy() - policy_agent = policy_manager_deployer.make_agent() - - web3 = testerchain.interface.w3 - - print("Estimate gas:") - # Pre deposit tokens - tx = token_agent.contract.functions.approve(miner_agent.contract_address, constants.MIN_ALLOWED_LOCKED * 5)\ - .transact({'from': origin}) - testerchain.wait_for_receipt(tx) - print("Pre-deposit tokens for 5 owners = " + - str(miner_agent.contract.functions - .preDeposit(everyone_else[0:5], - [int(constants.MIN_ALLOWED_LOCKED)] * 5, - [int(constants.MIN_LOCKED_PERIODS)] * 5) - .estimateGas({'from': origin}))) - - # Give Ursula and Alice some coins - print("Transfer tokens = " + - str(token_agent.contract.functions.transfer(ursula1, constants.MIN_ALLOWED_LOCKED * 10) - .estimateGas({'from': origin}))) - tx = token_agent.contract.functions.transfer(ursula1, constants.MIN_ALLOWED_LOCKED * 10).transact({'from': origin}) - testerchain.wait_for_receipt(tx) - tx = token_agent.contract.functions.transfer(ursula2, constants.MIN_ALLOWED_LOCKED * 10).transact({'from': origin}) - testerchain.wait_for_receipt(tx) - tx = token_agent.contract.functions.transfer(ursula3, constants.MIN_ALLOWED_LOCKED * 10).transact({'from': origin}) - testerchain.wait_for_receipt(tx) - - # Ursula and Alice give Escrow rights to transfer - print("Approving transfer = " + - str(token_agent.contract.functions.approve(miner_agent.contract_address, constants.MIN_ALLOWED_LOCKED * 6) - .estimateGas({'from': ursula1}))) - tx = token_agent.contract.functions.approve(miner_agent.contract_address, constants.MIN_ALLOWED_LOCKED * 6)\ - .transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - tx = token_agent.contract.functions.approve(miner_agent.contract_address, constants.MIN_ALLOWED_LOCKED * 6)\ - .transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - tx = token_agent.contract.functions.approve(miner_agent.contract_address, constants.MIN_ALLOWED_LOCKED * 6)\ - .transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Ursula and Alice transfer some tokens to the escrow and lock them - print("First initial deposit tokens = " + - str(miner_agent.contract.functions - .deposit(constants.MIN_ALLOWED_LOCKED * 3, int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.deposit(constants.MIN_ALLOWED_LOCKED * 3, int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second initial deposit tokens = " + - str(miner_agent.contract.functions - .deposit(constants.MIN_ALLOWED_LOCKED * 3, int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.deposit(constants.MIN_ALLOWED_LOCKED * 3, int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third initial deposit tokens = " + - str(miner_agent.contract.functions - .deposit(constants.MIN_ALLOWED_LOCKED * 3, int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.deposit(constants.MIN_ALLOWED_LOCKED * 3, int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Wait 1 period and confirm activity - testerchain.time_travel(periods=1) - print("First confirm activity = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second confirm activity = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third confirm activity = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Wait 1 period and mint tokens - testerchain.time_travel(periods=1) - print("First mining (1 stake) = " + str(miner_agent.contract.functions.mint().estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.mint().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second mining (1 stake) = " + str(miner_agent.contract.functions.mint().estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.mint().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third/last mining (1 stake) = " + str(miner_agent.contract.functions.mint().estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.mint().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - print("First confirm activity again = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second confirm activity again = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third confirm activity again = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Confirm again - testerchain.time_travel(periods=1) - print("First confirm activity + mint = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second confirm activity + mint = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third confirm activity + mint = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Get locked tokens - print("Getting locked tokens = " + str(miner_agent.contract.functions.getLockedTokens(ursula1).estimateGas())) - - # Wait 1 period and withdraw tokens - testerchain.time_travel(periods=1) - print("First withdraw = " + str(miner_agent.contract.functions.withdraw(1).estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.withdraw(1).transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second withdraw = " + str(miner_agent.contract.functions.withdraw(1).estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.withdraw(1).transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third withdraw = " + str(miner_agent.contract.functions.withdraw(1).estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.withdraw(1).transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Wait 1 period and confirm activity - testerchain.time_travel(periods=1) - print("First confirm activity after downtime = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second confirm activity after downtime = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third confirm activity after downtime = " + - str(miner_agent.contract.functions.confirmActivity().estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Ursula and Alice deposit some tokens to the escrow again - print("First deposit tokens again = " + - str(miner_agent.contract.functions.deposit(constants.MIN_ALLOWED_LOCKED * 2, int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.deposit(constants.MIN_ALLOWED_LOCKED * 2, int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second deposit tokens again = " + - str(miner_agent.contract.functions.deposit(constants.MIN_ALLOWED_LOCKED * 2, int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.deposit(constants.MIN_ALLOWED_LOCKED * 2, int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third deposit tokens again = " + - str(miner_agent.contract.functions.deposit(constants.MIN_ALLOWED_LOCKED * 2, int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.deposit(constants.MIN_ALLOWED_LOCKED * 2, int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Wait 1 period and mint tokens - testerchain.time_travel(periods=1) - print("First mining again = " + str(miner_agent.contract.functions.mint().estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.mint().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second mining again = " + str(miner_agent.contract.functions.mint().estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.mint().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third/last mining again = " + str(miner_agent.contract.functions.mint().estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.mint().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Create policy - policy_id_1 = os.urandom(int(constants.POLICY_ID_LENGTH)) - policy_id_2 = os.urandom(int(constants.POLICY_ID_LENGTH)) - number_of_periods = 10 - print("First creating policy (1 node, 10 periods) = " + - str(policy_agent.contract.functions.createPolicy(policy_id_1, number_of_periods, 0, [ursula1]) - .estimateGas({'from': alice1, 'value': 10000}))) - tx = policy_agent.contract.functions.createPolicy(policy_id_1, number_of_periods, 0, [ursula1])\ - .transact({'from': alice1, 'value': 10000}) - testerchain.wait_for_receipt(tx) - print("Second creating policy (1 node, 10 periods) = " + - str(policy_agent.contract.functions.createPolicy(policy_id_2, number_of_periods, 0, [ursula1]) - .estimateGas({'from': alice1, 'value': 10000}))) - tx = policy_agent.contract.functions.createPolicy(policy_id_2, number_of_periods, 0, [ursula1])\ - .transact({'from': alice1, 'value': 10000}) - testerchain.wait_for_receipt(tx) - - # Revoke policy - print("Revoking policy = " + - str(policy_agent.contract.functions.revokePolicy(policy_id_1).estimateGas({'from': alice1}))) - tx = policy_agent.contract.functions.revokePolicy(policy_id_1).transact({'from': alice1}) - testerchain.wait_for_receipt(tx) - tx = policy_agent.contract.functions.revokePolicy(policy_id_2).transact({'from': alice1}) - testerchain.wait_for_receipt(tx) - - # Create policy with more periods - policy_id_1 = os.urandom(int(constants.POLICY_ID_LENGTH)) - policy_id_2 = os.urandom(int(constants.POLICY_ID_LENGTH)) - policy_id_3 = os.urandom(int(constants.POLICY_ID_LENGTH)) - number_of_periods = 100 - print("First creating policy (1 node, " + str(number_of_periods) + " periods, first reward) = " + - str(policy_agent.contract.functions.createPolicy(policy_id_1, number_of_periods, 50, [ursula2]) - .estimateGas({'from': alice1, 'value': 10050}))) - tx = policy_agent.contract.functions.createPolicy(policy_id_1, number_of_periods, 50, [ursula2])\ - .transact({'from': alice1, 'value': 10050}) - testerchain.wait_for_receipt(tx) - testerchain.time_travel(periods=1) - print("Second creating policy (1 node, " + str(number_of_periods) + " periods, first reward) = " + - str(policy_agent.contract.functions.createPolicy(policy_id_2, number_of_periods, 50, [ursula2]) - .estimateGas({'from': alice1, 'value': 10050}))) - tx = policy_agent.contract.functions.createPolicy(policy_id_2, number_of_periods, 50, [ursula2])\ - .transact({'from': alice1, 'value': 10050}) - testerchain.wait_for_receipt(tx) - print("Third creating policy (1 node, " + str(number_of_periods) + " periods, first reward) = " + - str(policy_agent.contract.functions.createPolicy(policy_id_3, number_of_periods, 50, [ursula1]) - .estimateGas({'from': alice1, 'value': 10050}))) - tx = policy_agent.contract.functions.createPolicy(policy_id_3, number_of_periods, 50, [ursula1])\ - .transact({'from': alice1, 'value': 10050}) - testerchain.wait_for_receipt(tx) - - # Mine and revoke policy - testerchain.time_travel(periods=10) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - - testerchain.time_travel(periods=1) - print("First mining after downtime = " + str(miner_agent.contract.functions.mint().estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.mint().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second mining after downtime = " + str(miner_agent.contract.functions.mint().estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.mint().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - - testerchain.time_travel(periods=10) - print("First revoking policy after downtime = " + - str(policy_agent.contract.functions.revokePolicy(policy_id_1).estimateGas({'from': alice1}))) - tx = policy_agent.contract.functions.revokePolicy(policy_id_1).transact({'from': alice1}) - testerchain.wait_for_receipt(tx) - print("Second revoking policy after downtime = " + - str(policy_agent.contract.functions.revokePolicy(policy_id_2).estimateGas({'from': alice1}))) - tx = policy_agent.contract.functions.revokePolicy(policy_id_2).transact({'from': alice1}) - testerchain.wait_for_receipt(tx) - print("Second revoking policy after downtime = " + - str(policy_agent.contract.functions.revokePolicy(policy_id_3).estimateGas({'from': alice1}))) - tx = policy_agent.contract.functions.revokePolicy(policy_id_3).transact({'from': alice1}) - testerchain.wait_for_receipt(tx) - - # Create policy with multiple nodes - policy_id_1 = os.urandom(int(constants.POLICY_ID_LENGTH)) - policy_id_2 = os.urandom(int(constants.POLICY_ID_LENGTH)) - policy_id_3 = os.urandom(int(constants.POLICY_ID_LENGTH)) - number_of_periods = 100 - print("First creating policy (3 nodes, 100 periods, first reward) = " + - str(policy_agent.contract.functions - .createPolicy(policy_id_1, number_of_periods, 50, [ursula1, ursula2, ursula3]) - .estimateGas({'from': alice1, 'value': 30150}))) - tx = policy_agent.contract.functions.createPolicy(policy_id_1, number_of_periods, 50, [ursula1, ursula2, ursula3])\ - .transact({'from': alice1, 'value': 30150}) - testerchain.wait_for_receipt(tx) - print("Second creating policy (3 nodes, 100 periods, first reward) = " + - str(policy_agent.contract.functions - .createPolicy(policy_id_2, number_of_periods, 50, [ursula1, ursula2, ursula3]) - .estimateGas({'from': alice1, 'value': 30150}))) - tx = policy_agent.contract.functions.createPolicy(policy_id_2, number_of_periods, 50, [ursula1, ursula2, ursula3])\ - .transact({'from': alice1, 'value': 30150}) - testerchain.wait_for_receipt(tx) - print("Third creating policy (2 nodes, 100 periods, first reward) = " + - str(policy_agent.contract.functions.createPolicy(policy_id_3, number_of_periods, 50, [ursula1, ursula2]) - .estimateGas({'from': alice1, 'value': 20100}))) - tx = policy_agent.contract.functions.createPolicy(policy_id_3, number_of_periods, 50, [ursula1, ursula2])\ - .transact({'from': alice1, 'value': 20100}) - testerchain.wait_for_receipt(tx) - - for index in range(5): - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - testerchain.time_travel(periods=1) - - tx = miner_agent.contract.functions.mint().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - tx = miner_agent.contract.functions.mint().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - tx = miner_agent.contract.functions.mint().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Check regular deposit - print("First deposit tokens = " + - str(miner_agent.contract.functions.deposit(int(constants.MIN_ALLOWED_LOCKED), int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.deposit(int(constants.MIN_ALLOWED_LOCKED), int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second deposit tokens = " + - str(miner_agent.contract.functions.deposit(int(constants.MIN_ALLOWED_LOCKED), int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.deposit(int(constants.MIN_ALLOWED_LOCKED), int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third deposit tokens = " + - str(miner_agent.contract.functions.deposit(int(constants.MIN_ALLOWED_LOCKED), int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.deposit(int(constants.MIN_ALLOWED_LOCKED), int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # ApproveAndCall - testerchain.time_travel(periods=1) - - tx = miner_agent.contract.functions.mint().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - tx = miner_agent.contract.functions.mint().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - tx = miner_agent.contract.functions.mint().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - print("First approveAndCall = " + - str(token_agent.contract.functions.approveAndCall(miner_agent.contract_address, - int(constants.MIN_ALLOWED_LOCKED) * 2, - web3.toBytes(int(constants.MIN_LOCKED_PERIODS))) - .estimateGas({'from': ursula1}))) - tx = token_agent.contract.functions.approveAndCall(miner_agent.contract_address, - int(constants.MIN_ALLOWED_LOCKED) * 2, - web3.toBytes(int(constants.MIN_LOCKED_PERIODS)))\ - .transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second approveAndCall = " + - str(token_agent.contract.functions.approveAndCall(miner_agent.contract_address, - int(constants.MIN_ALLOWED_LOCKED) * 2, - web3.toBytes(int(constants.MIN_LOCKED_PERIODS))) - .estimateGas({'from': ursula2}))) - tx = token_agent.contract.functions.approveAndCall(miner_agent.contract_address, - int(constants.MIN_ALLOWED_LOCKED) * 2, - web3.toBytes(int(constants.MIN_LOCKED_PERIODS)))\ - .transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third approveAndCall = " + - str(token_agent.contract.functions.approveAndCall(miner_agent.contract_address, - int(constants.MIN_ALLOWED_LOCKED) * 2, - web3.toBytes(int(constants.MIN_LOCKED_PERIODS))) - .estimateGas({'from': ursula3}))) - tx = token_agent.contract.functions.approveAndCall(miner_agent.contract_address, - int(constants.MIN_ALLOWED_LOCKED) * 2, - web3.toBytes(int(constants.MIN_LOCKED_PERIODS)))\ - .transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Locking tokens - testerchain.time_travel(periods=1) - - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - print("First locking tokens = " + - str(miner_agent.contract.functions.lock(int(constants.MIN_ALLOWED_LOCKED), - int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.lock(int(constants.MIN_ALLOWED_LOCKED), - int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second locking tokens = " + - str(miner_agent.contract.functions.lock(int(constants.MIN_ALLOWED_LOCKED), - int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula2}))) - tx = miner_agent.contract.functions.lock(int(constants.MIN_ALLOWED_LOCKED), - int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula2}) - testerchain.wait_for_receipt(tx) - print("Third locking tokens = " + - str(miner_agent.contract.functions.lock(int(constants.MIN_ALLOWED_LOCKED), - int(constants.MIN_LOCKED_PERIODS)) - .estimateGas({'from': ursula3}))) - tx = miner_agent.contract.functions.lock(int(constants.MIN_ALLOWED_LOCKED), - int(constants.MIN_LOCKED_PERIODS))\ - .transact({'from': ursula3}) - testerchain.wait_for_receipt(tx) - - # Divide stake - print("First divide stake = " + - str(miner_agent.contract.functions.divideStake(1, int(constants.MIN_ALLOWED_LOCKED), 2) - .estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.divideStake(1, int(constants.MIN_ALLOWED_LOCKED), 2).transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Second divide stake = " + - str(miner_agent.contract.functions.divideStake(3, int(constants.MIN_ALLOWED_LOCKED), 2) - .estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.divideStake(3, int(constants.MIN_ALLOWED_LOCKED), 2).transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - - # Divide almost finished stake - testerchain.time_travel(periods=1) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - testerchain.time_travel(periods=1) - print("Divide stake (next period is not confirmed) = " + - str(miner_agent.contract.functions.divideStake(0, int(constants.MIN_ALLOWED_LOCKED), 2) - .estimateGas({'from': ursula1}))) - tx = miner_agent.contract.functions.confirmActivity().transact({'from': ursula1}) - testerchain.wait_for_receipt(tx) - print("Divide stake (next period is confirmed) = " + - str(miner_agent.contract.functions.divideStake(0, int(constants.MIN_ALLOWED_LOCKED), 2) - .estimateGas({'from': ursula1}))) - - print("All done!") - - -if __name__ == "__main__": - estimate_gas() diff --git a/nucypher/config/constants.py b/nucypher/config/constants.py index 06b5c18ed..d537fe3c6 100644 --- a/nucypher/config/constants.py +++ b/nucypher/config/constants.py @@ -16,17 +16,19 @@ along with nucypher. If not, see . """ +import os from collections import namedtuple from os.path import abspath, dirname from appdirs import AppDirs import nucypher - +from nucypher.blockchain.eth import sol # Base Filepaths BASE_DIR = abspath(dirname(dirname(nucypher.__file__))) PROJECT_ROOT = abspath(dirname(nucypher.__file__)) +CONTRACT_ROOT = os.path.join(abspath(dirname(sol.__file__)), 'source', 'contracts') # User Application Filepaths APP_DIR = AppDirs(nucypher.__title__, nucypher.__author__) diff --git a/nucypher/utilities/logging.py b/nucypher/utilities/logging.py index a798defa9..8e2f3ca3a 100644 --- a/nucypher/utilities/logging.py +++ b/nucypher/utilities/logging.py @@ -62,16 +62,16 @@ def _get_or_create_user_log_dir(): return pathlib.Path(USER_LOG_DIR).mkdir(parents=True, exist_ok=True) -def getJsonFileObserver(): +def getJsonFileObserver(name="ursula.log.json", path=USER_LOG_DIR): # TODO: More configurable naming here? _get_or_create_user_log_dir() - logfile = DailyLogFile("ursula.log.json", USER_LOG_DIR) + logfile = DailyLogFile(name, path) observer = jsonFileLogObserver(outFile=logfile) return observer -def getTextFileObserver(): +def getTextFileObserver(name="ursula.log", path=USER_LOG_DIR): _get_or_create_user_log_dir() - logfile = DailyLogFile("ursula.log", USER_LOG_DIR) + logfile = DailyLogFile(name, path) observer = FileLogObserver(formatEvent=formatUrsulaLogEvent, outFile=logfile) return observer diff --git a/tests/metrics/estimate_gas.py b/tests/metrics/estimate_gas.py new file mode 100755 index 000000000..8343c2a75 --- /dev/null +++ b/tests/metrics/estimate_gas.py @@ -0,0 +1,585 @@ +#!/usr/bin/env python3 + + +""" +This file is part of nucypher. + +nucypher is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +nucypher is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with nucypher. If not, see . +""" + + +import json +import os +from typing import List, Tuple + +import time +from os.path import abspath, dirname + +import io +import re +from twisted.logger import globalLogPublisher, Logger, jsonFileLogObserver, ILogObserver +from zope.interface import provider + +from nucypher.blockchain.eth.actors import Deployer +from nucypher.blockchain.eth.agents import NucypherTokenAgent, MinerAgent, PolicyAgent +from nucypher.blockchain.eth.constants import ( + DISPATCHER_SECRET_LENGTH, + MIN_ALLOWED_LOCKED, + MIN_LOCKED_PERIODS, + POLICY_ID_LENGTH +) +from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface +from nucypher.blockchain.eth.registry import InMemoryEthereumContractRegistry +from nucypher.blockchain.eth.sol.compile import SolidityCompiler +from nucypher.config.constants import CONTRACT_ROOT +from nucypher.utilities.sandbox.blockchain import TesterBlockchain + + +class AnalyzeGas: + """ + Callable twisted log observer with built-in record-keeping for gas estimation runs. + """ + + # Logging + LOG_NAME = 'estimate-gas' + LOG_FILENAME = '{}.log.json'.format(LOG_NAME) + OUTPUT_DIR = os.path.join(abspath(dirname(__file__)), 'results') + JSON_OUTPUT_FILENAME = '{}.json'.format(LOG_NAME) + + # Tweaks + CONTRACT_DIR = CONTRACT_ROOT + PROVIDER_URI = "tester://pyevm" + TEST_ACCOUNTS = 10 + + _PATTERN = re.compile(r''' + ^ # Anchor at the start of a string + (.+) # Any character sequence longer than 1; Captured + \s=\s # Space-Equal-Space + (\d+) # A sequence of digits; Captured + $ # Anchor at the end of the string + ''', re.VERBOSE) + + def __init__(self) -> None: + + self.log = Logger(self.__class__.__name__) + self.gas_estimations = dict() + + if not os.path.isdir(self.OUTPUT_DIR): + os.mkdir(self.OUTPUT_DIR) + + @provider(ILogObserver) + def __call__(self, event, *args, **kwargs) -> None: + + if event.get('log_namespace') == self.LOG_NAME: + message = event.get("log_format") + + matches = self._PATTERN.match(message) + if not matches: + self.log.debug("No match for {} with pattern {}".format(message, self._PATTERN)) + return + + label, gas = matches.groups() + self.paint_line(label, gas) + self.gas_estimations[label] = int(gas) + + @staticmethod + def paint_line(label: str, gas: str) -> None: + print('{label} {gas:,}'.format(label=label.ljust(65, '.'), gas=int(gas))) + + def to_json_file(self) -> None: + print('Saving JSON Output...') + + epoch_time = str(int(time.time())) + timestamped_filename = '{}-{}'.format(epoch_time, self.JSON_OUTPUT_FILENAME) + filepath = os.path.join(self.OUTPUT_DIR, timestamped_filename) + with open(filepath, 'w') as file: + file.write(json.dumps(self.gas_estimations, indent=4)) + + def start_collection(self) -> None: + print("Starting Data Collection...") + + json_filepath = os.path.join(self.OUTPUT_DIR, AnalyzeGas.LOG_FILENAME) + json_io = io.open(json_filepath, "w") + json_observer = jsonFileLogObserver(json_io) + globalLogPublisher.addObserver(json_observer) + globalLogPublisher.addObserver(self) + + def connect_to_blockchain(self) -> TesterBlockchain: + print("Deploying Blockchain...") + + solidity_compiler = SolidityCompiler(test_contract_dir=self.CONTRACT_DIR) + memory_registry = InMemoryEthereumContractRegistry() + interface = BlockchainDeployerInterface(provider_uri=self.PROVIDER_URI, compiler=solidity_compiler, + registry=memory_registry) + + testerchain = TesterBlockchain(interface=interface, test_accounts=self.TEST_ACCOUNTS, airdrop=False) + return testerchain + + @staticmethod + def deploy_contracts(testerchain: TesterBlockchain) -> None: + print("Deploying Contracts...") + + origin = testerchain.interface.w3.eth.accounts[0] + deployer = Deployer(blockchain=testerchain, deployer_address=origin, bare=True) + _txhashes, _agents = deployer.deploy_network_contracts(miner_secret=os.urandom(DISPATCHER_SECRET_LENGTH), + policy_secret=os.urandom(DISPATCHER_SECRET_LENGTH)) + + @staticmethod + def connect_to_contracts(testerchain: TesterBlockchain) -> Tuple[NucypherTokenAgent, MinerAgent, PolicyAgent]: + print("Connecting...") + + token_agent = NucypherTokenAgent(blockchain=testerchain) + miner_agent = MinerAgent(blockchain=testerchain) + policy_agent = PolicyAgent(blockchain=testerchain) + + return token_agent, miner_agent, policy_agent + + def bootstrap_network(self) -> Tuple[TesterBlockchain, List[str]]: + print("Bootstrapping testing network...") + + testerchain = self.connect_to_blockchain() + self.deploy_contracts(testerchain=testerchain) + return testerchain, testerchain.interface.w3.eth.accounts + + +def estimate_gas(analyzer: AnalyzeGas = None) -> None: + """ + Execute a linear sequence of NyCypher transactions mimicking + post-deployment usage on a local PyEVM blockchain; + Record the resulting estimated transaction gas expenditure. + + Note: The function calls below are *order dependant* + """ + + # + # Setup + # + if AnalyzeGas is None: + analyzer = AnalyzeGas() + + # Logger + log = Logger(AnalyzeGas.LOG_NAME) + + # Blockchain + testerchain, accounts = analyzer.bootstrap_network() + web3 = testerchain.interface.w3 + + # Contracts + token_agent, miner_agent, policy_agent = analyzer.connect_to_contracts(testerchain=testerchain) + token_functions = token_agent.contract.functions + miner_functions = miner_agent.contract.functions + policy_functions = policy_agent.contract.functions + + # Accounts + origin, ursula1, ursula2, ursula3, alice1, *everyone_else = testerchain.interface.w3.eth.accounts + + analyzer.start_collection() + print("********* Estimating Gas *********") + + # + # Pre deposit tokens + # + tx = token_functions.approve(miner_agent.contract_address, MIN_ALLOWED_LOCKED * 5).transact({'from': origin}) + testerchain.wait_for_receipt(tx) + log.info("Pre-deposit tokens for 5 owners = " + str(miner_functions.preDeposit(everyone_else[0:5], + [MIN_ALLOWED_LOCKED] * 5, + [MIN_LOCKED_PERIODS] * 5) + .estimateGas({'from': origin}))) + + # + # Give Ursula and Alice some coins + # + log.info("Transfer tokens = " + str(token_functions.transfer(ursula1, MIN_ALLOWED_LOCKED * 10).estimateGas({'from': origin}))) + tx = token_functions.transfer(ursula1, MIN_ALLOWED_LOCKED * 10).transact({'from': origin}) + testerchain.wait_for_receipt(tx) + tx = token_functions.transfer(ursula2, MIN_ALLOWED_LOCKED * 10).transact({'from': origin}) + testerchain.wait_for_receipt(tx) + tx = token_functions.transfer(ursula3, MIN_ALLOWED_LOCKED * 10).transact({'from': origin}) + testerchain.wait_for_receipt(tx) + + # + # Ursula and Alice give Escrow rights to transfer + # + log.info("Approving transfer = " + + str(token_functions.approve(miner_agent.contract_address, MIN_ALLOWED_LOCKED * 6).estimateGas({'from': ursula1}))) + tx = token_functions.approve(miner_agent.contract_address, MIN_ALLOWED_LOCKED * 6).transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + tx = token_functions.approve(miner_agent.contract_address, MIN_ALLOWED_LOCKED * 6).transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + tx = token_functions.approve(miner_agent.contract_address, MIN_ALLOWED_LOCKED * 6).transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Ursula and Alice transfer some tokens to the escrow and lock them + # + log.info("First initial deposit tokens = " + + str(miner_functions.deposit(MIN_ALLOWED_LOCKED * 3, MIN_LOCKED_PERIODS).estimateGas({'from': ursula1}))) + tx = miner_functions.deposit(MIN_ALLOWED_LOCKED * 3, MIN_LOCKED_PERIODS).transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second initial deposit tokens = " + + str(miner_functions.deposit(MIN_ALLOWED_LOCKED * 3, MIN_LOCKED_PERIODS).estimateGas({'from': ursula2}))) + tx = miner_functions.deposit(MIN_ALLOWED_LOCKED * 3, MIN_LOCKED_PERIODS).transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third initial deposit tokens = " + + str(miner_functions.deposit(MIN_ALLOWED_LOCKED * 3, MIN_LOCKED_PERIODS).estimateGas({'from': ursula3}))) + tx = miner_functions.deposit(MIN_ALLOWED_LOCKED * 3, MIN_LOCKED_PERIODS).transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Wait 1 period and confirm activity + # + testerchain.time_travel(periods=1) + log.info("First confirm activity = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula1}))) + tx = miner_functions.confirmActivity().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second confirm activity = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula2}))) + tx = miner_functions.confirmActivity().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third confirm activity = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula3}))) + tx = miner_functions.confirmActivity().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Wait 1 period and mint tokens + # + testerchain.time_travel(periods=1) + log.info("First mining (1 stake) = " + str(miner_functions.mint().estimateGas({'from': ursula1}))) + tx = miner_functions.mint().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second mining (1 stake) = " + str(miner_functions.mint().estimateGas({'from': ursula2}))) + tx = miner_functions.mint().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third/last mining (1 stake) = " + str(miner_functions.mint().estimateGas({'from': ursula3}))) + tx = miner_functions.mint().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + log.info("First confirm activity again = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula1}))) + tx = miner_functions.confirmActivity().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second confirm activity again = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula2}))) + tx = miner_functions.confirmActivity().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third confirm activity again = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula3}))) + tx = miner_functions.confirmActivity().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Confirm again + # + testerchain.time_travel(periods=1) + log.info("First confirm activity + mint = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula1}))) + tx = miner_functions.confirmActivity().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second confirm activity + mint = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula2}))) + tx = miner_functions.confirmActivity().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third confirm activity + mint = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula3}))) + tx = miner_functions.confirmActivity().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Get locked tokens + # + log.info("Getting locked tokens = " + str(miner_functions.getLockedTokens(ursula1).estimateGas())) + + # + # Wait 1 period and withdraw tokens + # + testerchain.time_travel(periods=1) + log.info("First withdraw = " + str(miner_functions.withdraw(1).estimateGas({'from': ursula1}))) + tx = miner_functions.withdraw(1).transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second withdraw = " + str(miner_functions.withdraw(1).estimateGas({'from': ursula2}))) + tx = miner_functions.withdraw(1).transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third withdraw = " + str(miner_functions.withdraw(1).estimateGas({'from': ursula3}))) + tx = miner_functions.withdraw(1).transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Wait 1 period and confirm activity + # + testerchain.time_travel(periods=1) + log.info("First confirm activity after downtime = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula1}))) + tx = miner_functions.confirmActivity().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second confirm activity after downtime = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula2}))) + tx = miner_functions.confirmActivity().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third confirm activity after downtime = " + + str(miner_functions.confirmActivity().estimateGas({'from': ursula3}))) + tx = miner_functions.confirmActivity().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Ursula and Alice deposit some tokens to the escrow again + # + log.info("First deposit tokens again = " + + str(miner_functions.deposit(MIN_ALLOWED_LOCKED * 2, MIN_LOCKED_PERIODS).estimateGas({'from': ursula1}))) + tx = miner_functions.deposit(MIN_ALLOWED_LOCKED * 2, MIN_LOCKED_PERIODS).transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second deposit tokens again = " + + str(miner_functions.deposit(MIN_ALLOWED_LOCKED * 2, MIN_LOCKED_PERIODS).estimateGas({'from': ursula2}))) + tx = miner_functions.deposit(MIN_ALLOWED_LOCKED * 2, MIN_LOCKED_PERIODS).transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third deposit tokens again = " + + str(miner_functions.deposit(MIN_ALLOWED_LOCKED * 2, MIN_LOCKED_PERIODS).estimateGas({'from': ursula3}))) + tx = miner_functions.deposit(MIN_ALLOWED_LOCKED * 2, MIN_LOCKED_PERIODS).transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Wait 1 period and mint tokens + # + testerchain.time_travel(periods=1) + log.info("First mining again = " + str(miner_functions.mint().estimateGas({'from': ursula1}))) + tx = miner_functions.mint().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second mining again = " + str(miner_functions.mint().estimateGas({'from': ursula2}))) + tx = miner_functions.mint().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third/last mining again = " + str(miner_functions.mint().estimateGas({'from': ursula3}))) + tx = miner_functions.mint().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Create policy + # + policy_id_1 = os.urandom(int(POLICY_ID_LENGTH)) + policy_id_2 = os.urandom(int(POLICY_ID_LENGTH)) + number_of_periods = 10 + log.info("First creating policy (1 node, 10 periods) = " + + str(policy_functions.createPolicy(policy_id_1, number_of_periods, 0, [ursula1]).estimateGas({'from': alice1, 'value': 10000}))) + tx = policy_functions.createPolicy(policy_id_1, number_of_periods, 0, [ursula1]).transact({'from': alice1, 'value': 10000}) + testerchain.wait_for_receipt(tx) + log.info("Second creating policy (1 node, 10 periods) = " + + str(policy_functions.createPolicy(policy_id_2, number_of_periods, 0, [ursula1]).estimateGas({'from': alice1, 'value': 10000}))) + tx = policy_functions.createPolicy(policy_id_2, number_of_periods, 0, [ursula1]).transact({'from': alice1, 'value': 10000}) + testerchain.wait_for_receipt(tx) + + # + # Revoke policy + # + log.info("Revoking policy = " + str(policy_functions.revokePolicy(policy_id_1).estimateGas({'from': alice1}))) + tx = policy_functions.revokePolicy(policy_id_1).transact({'from': alice1}) + testerchain.wait_for_receipt(tx) + tx = policy_functions.revokePolicy(policy_id_2).transact({'from': alice1}) + testerchain.wait_for_receipt(tx) + + # + # Create policy with more periods + # + policy_id_1 = os.urandom(int(POLICY_ID_LENGTH)) + policy_id_2 = os.urandom(int(POLICY_ID_LENGTH)) + policy_id_3 = os.urandom(int(POLICY_ID_LENGTH)) + number_of_periods = 100 + log.info("First creating policy (1 node, " + str(number_of_periods) + " periods, first reward) = " + + str(policy_functions.createPolicy(policy_id_1, number_of_periods, 50, [ursula2]).estimateGas({'from': alice1, 'value': 10050}))) + tx = policy_functions.createPolicy(policy_id_1, number_of_periods, 50, [ursula2]).transact({'from': alice1, 'value': 10050}) + testerchain.wait_for_receipt(tx) + testerchain.time_travel(periods=1) + log.info("Second creating policy (1 node, " + str(number_of_periods) + " periods, first reward) = " + + str(policy_functions.createPolicy(policy_id_2, number_of_periods, 50, [ursula2]).estimateGas({'from': alice1, 'value': 10050}))) + tx = policy_functions.createPolicy(policy_id_2, number_of_periods, 50, [ursula2]).transact({'from': alice1, 'value': 10050}) + testerchain.wait_for_receipt(tx) + log.info("Third creating policy (1 node, " + str(number_of_periods) + " periods, first reward) = " + + str(policy_functions.createPolicy(policy_id_3, number_of_periods, 50, [ursula1]).estimateGas({'from': alice1, 'value': 10050}))) + tx = policy_functions.createPolicy(policy_id_3, number_of_periods, 50, [ursula1]).transact({'from': alice1, 'value': 10050}) + testerchain.wait_for_receipt(tx) + + # + # Mine and revoke policy + # + testerchain.time_travel(periods=10) + tx = miner_functions.confirmActivity().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + tx = miner_functions.confirmActivity().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + + testerchain.time_travel(periods=1) + log.info("First mining after downtime = " + str(miner_functions.mint().estimateGas({'from': ursula1}))) + tx = miner_functions.mint().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second mining after downtime = " + str(miner_functions.mint().estimateGas({'from': ursula2}))) + tx = miner_functions.mint().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + + testerchain.time_travel(periods=10) + log.info("First revoking policy after downtime = " + + str(policy_functions.revokePolicy(policy_id_1).estimateGas({'from': alice1}))) + tx = policy_functions.revokePolicy(policy_id_1).transact({'from': alice1}) + testerchain.wait_for_receipt(tx) + log.info("Second revoking policy after downtime = " + + str(policy_functions.revokePolicy(policy_id_2).estimateGas({'from': alice1}))) + tx = policy_functions.revokePolicy(policy_id_2).transact({'from': alice1}) + testerchain.wait_for_receipt(tx) + log.info("Second revoking policy after downtime = " + + str(policy_functions.revokePolicy(policy_id_3).estimateGas({'from': alice1}))) + tx = policy_functions.revokePolicy(policy_id_3).transact({'from': alice1}) + testerchain.wait_for_receipt(tx) + + # + # Create policy with multiple nodes + # + policy_id_1 = os.urandom(int(POLICY_ID_LENGTH)) + policy_id_2 = os.urandom(int(POLICY_ID_LENGTH)) + policy_id_3 = os.urandom(int(POLICY_ID_LENGTH)) + number_of_periods = 100 + log.info("First creating policy (3 nodes, 100 periods, first reward) = " + + str(policy_functions + .createPolicy(policy_id_1, number_of_periods, 50, [ursula1, ursula2, ursula3]) + .estimateGas({'from': alice1, 'value': 30150}))) + tx = policy_functions.createPolicy(policy_id_1, number_of_periods, 50, [ursula1, ursula2, ursula3]).transact({'from': alice1, 'value': 30150}) + testerchain.wait_for_receipt(tx) + log.info("Second creating policy (3 nodes, 100 periods, first reward) = " + + str(policy_functions + .createPolicy(policy_id_2, number_of_periods, 50, [ursula1, ursula2, ursula3]) + .estimateGas({'from': alice1, 'value': 30150}))) + tx = policy_functions.createPolicy(policy_id_2, number_of_periods, 50, [ursula1, ursula2, ursula3]).transact({'from': alice1, 'value': 30150}) + testerchain.wait_for_receipt(tx) + log.info("Third creating policy (2 nodes, 100 periods, first reward) = " + + str(policy_functions.createPolicy(policy_id_3, number_of_periods, 50, [ursula1, ursula2]).estimateGas({'from': alice1, 'value': 20100}))) + tx = policy_functions.createPolicy(policy_id_3, number_of_periods, 50, [ursula1, ursula2]).transact({'from': alice1, 'value': 20100}) + testerchain.wait_for_receipt(tx) + + for index in range(5): + tx = miner_functions.confirmActivity().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + tx = miner_functions.confirmActivity().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + tx = miner_functions.confirmActivity().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + testerchain.time_travel(periods=1) + + tx = miner_functions.mint().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + tx = miner_functions.mint().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + tx = miner_functions.mint().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Check regular deposit + # + log.info("First deposit tokens = " + str(miner_functions.deposit(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).estimateGas({'from': ursula1}))) + tx = miner_functions.deposit(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second deposit tokens = " + str(miner_functions.deposit(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).estimateGas({'from': ursula2}))) + tx = miner_functions.deposit(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third deposit tokens = " + str(miner_functions.deposit(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).estimateGas({'from': ursula3}))) + tx = miner_functions.deposit(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # ApproveAndCall + # + testerchain.time_travel(periods=1) + + tx = miner_functions.mint().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + tx = miner_functions.mint().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + tx = miner_functions.mint().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + log.info("First approveAndCall = " + + str(token_functions.approveAndCall(miner_agent.contract_address, + MIN_ALLOWED_LOCKED * 2, + web3.toBytes(MIN_LOCKED_PERIODS)).estimateGas({'from': ursula1}))) + tx = token_functions.approveAndCall(miner_agent.contract_address, + MIN_ALLOWED_LOCKED * 2, + web3.toBytes(MIN_LOCKED_PERIODS)).transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second approveAndCall = " + + str(token_functions.approveAndCall(miner_agent.contract_address, MIN_ALLOWED_LOCKED * 2, + web3.toBytes(MIN_LOCKED_PERIODS)).estimateGas({'from': ursula2}))) + tx = token_functions.approveAndCall(miner_agent.contract_address, + MIN_ALLOWED_LOCKED * 2, + web3.toBytes(MIN_LOCKED_PERIODS)).transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third approveAndCall = " + + str(token_functions.approveAndCall(miner_agent.contract_address, + MIN_ALLOWED_LOCKED * 2, + web3.toBytes(MIN_LOCKED_PERIODS)).estimateGas({'from': ursula3}))) + tx = token_functions.approveAndCall(miner_agent.contract_address, + MIN_ALLOWED_LOCKED * 2, + web3.toBytes(MIN_LOCKED_PERIODS)).transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Locking tokens + # + testerchain.time_travel(periods=1) + + tx = miner_functions.confirmActivity().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + tx = miner_functions.confirmActivity().transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + tx = miner_functions.confirmActivity().transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + log.info("First locking tokens = " + + str(miner_functions.lock(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).estimateGas({'from': ursula1}))) + tx = miner_functions.lock(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second locking tokens = " + + str(miner_functions.lock(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).estimateGas({'from': ursula2}))) + tx = miner_functions.lock(MIN_ALLOWED_LOCKED,MIN_LOCKED_PERIODS).transact({'from': ursula2}) + testerchain.wait_for_receipt(tx) + log.info("Third locking tokens = " + + str(miner_functions.lock(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).estimateGas({'from': ursula3}))) + tx = miner_functions.lock(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS).transact({'from': ursula3}) + testerchain.wait_for_receipt(tx) + + # + # Divide stake + # + log.info("First divide stake = " + str(miner_functions.divideStake(1, MIN_ALLOWED_LOCKED, 2).estimateGas({'from': ursula1}))) + tx = miner_functions.divideStake(1, MIN_ALLOWED_LOCKED, 2).transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Second divide stake = " + str(miner_functions.divideStake(3, MIN_ALLOWED_LOCKED, 2).estimateGas({'from': ursula1}))) + tx = miner_functions.divideStake(3, MIN_ALLOWED_LOCKED, 2).transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + + # + # Divide almost finished stake + # + testerchain.time_travel(periods=1) + tx = miner_functions.confirmActivity().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + testerchain.time_travel(periods=1) + log.info("Divide stake (next period is not confirmed) = " + str(miner_functions.divideStake(0, MIN_ALLOWED_LOCKED, 2).estimateGas({'from': ursula1}))) + tx = miner_functions.confirmActivity().transact({'from': ursula1}) + testerchain.wait_for_receipt(tx) + log.info("Divide stake (next period is confirmed) = " + str(miner_functions.divideStake(0, MIN_ALLOWED_LOCKED, 2).estimateGas({'from': ursula1}))) + + print("********* All Done! *********") + + +if __name__ == "__main__": + print("Starting Up...") + analyzer = AnalyzeGas() + estimate_gas(analyzer=analyzer) + analyzer.to_json_file()