Makes Testerchain a subclass of BlockchainDeployer

pull/1029/head
Kieran Prasch 2019-06-17 14:09:42 -07:00 committed by David Núñez
parent 47d221a9f9
commit 1886527a1c
2 changed files with 40 additions and 45 deletions

View File

@ -20,16 +20,13 @@ import os
from typing import List, Tuple, Dict
import maya
from constant_sorrow.constants import NO_BLOCKCHAIN_AVAILABLE, TEST_PROVIDER_ON_MAIN_PROCESS
from twisted.logger import Logger
from web3 import Web3
from web3.middleware import geth_poa_middleware
from nucypher.blockchain.economics import TokenEconomics
from nucypher.blockchain.eth.actors import Deployer
from nucypher.blockchain.eth.agents import EthereumContractAgent
from nucypher.blockchain.eth.chains import Blockchain
from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface
from nucypher.blockchain.eth.interfaces import BlockchainDeployer
from nucypher.blockchain.eth.registry import InMemoryEthereumContractRegistry
from nucypher.blockchain.eth.sol.compile import SolidityCompiler
from nucypher.blockchain.eth.token import NU
@ -51,7 +48,7 @@ def token_airdrop(token_agent, amount: NU, origin: str, addresses: List[str]):
"""Airdrops tokens from creator address to all other addresses!"""
def txs():
args = {'from': origin, 'gasPrice': token_agent.blockchain.interface.w3.eth.gasPrice}
args = {'from': origin, 'gasPrice': token_agent.blockchain.w3.eth.gasPrice}
for address in addresses:
txhash = token_agent.contract.functions.transfer(address, int(amount)).transact(args)
yield txhash
@ -63,13 +60,12 @@ def token_airdrop(token_agent, amount: NU, origin: str, addresses: List[str]):
return receipts
class TesterBlockchain(Blockchain):
class TesterBlockchain(BlockchainDeployer):
"""
Blockchain subclass with additional test utility methods and options.
"""
_PROVIDER_URI = 'tester://pyevm'
_instance = NO_BLOCKCHAIN_AVAILABLE
_test_account_cache = list()
_default_test_accounts = NUMBER_OF_ETH_TEST_ACCOUNTS
@ -90,20 +86,19 @@ class TesterBlockchain(Blockchain):
free_transactions=False,
*args, **kwargs):
if test_accounts is None:
if not test_accounts:
test_accounts = self._default_test_accounts
super().__init__(provider_process=TEST_PROVIDER_ON_MAIN_PROCESS, *args, **kwargs)
self.free_transactions = free_transactions
super().__init__(provider_process=None, poa=poa, *args, **kwargs)
self.log = Logger("test-blockchain")
self.attach_middleware(w3=self.interface.w3, poa=poa, free_transactions=free_transactions)
# Generate additional ethereum accounts for testing
population = test_accounts
enough_accounts = len(self.interface.w3.eth.accounts) >= population
enough_accounts = len(self.w3.eth.accounts) >= population
if not enough_accounts:
accounts_to_make = population - len(self.interface.w3.eth.accounts)
accounts_to_make = population - len(self.w3.eth.accounts)
self.__generate_insecure_unlocked_accounts(quantity=accounts_to_make)
assert test_accounts == len(self.interface.w3.eth.accounts)
assert test_accounts == len(self.w3.eth.accounts)
if eth_airdrop is True: # ETH for everyone!
self.ether_airdrop(amount=DEVELOPMENT_ETH_AIRDROP_AMOUNT)
@ -112,20 +107,10 @@ class TesterBlockchain(Blockchain):
def free_gas_price_strategy(w3, transaction_params=None):
return 0
def attach_middleware(self, w3, poa: bool = True, free_transactions: bool = False):
# For use with Proof-Of-Authority test-blockchains
if poa:
w3 = self.interface.w3
w3.middleware_onion.inject(geth_poa_middleware, layer=0)
# Free transaction gas!!
if free_transactions:
w3.eth.setGasPriceStrategy(self.free_gas_price_strategy)
@classmethod
def sever_connection(self) -> None:
Blockchain._instance = NO_BLOCKCHAIN_AVAILABLE
def attach_middleware(self):
super().attach_middleware()
if self.free_transactions:
self.w3.eth.setGasPriceStrategy(self.free_gas_price_strategy)
def __generate_insecure_unlocked_accounts(self, quantity: int) -> List[str]:
@ -134,7 +119,7 @@ class TesterBlockchain(Blockchain):
#
# Detect provider platform
client_version = self.interface.w3.clientVersion
client_version = self.w3.clientVersion
if 'Geth' in client_version:
raise RuntimeError("WARNING: Geth providers are not implemented.")
@ -143,7 +128,7 @@ class TesterBlockchain(Blockchain):
addresses = list()
for _ in range(quantity):
address = self.interface.provider.ethereum_tester.add_account('0x' + os.urandom(32).hex())
address = self.provider.ethereum_tester.add_account('0x' + os.urandom(32).hex())
addresses.append(address)
self._test_account_cache.append(address)
self.log.info('Generated new insecure account {}'.format(address))
@ -152,7 +137,7 @@ class TesterBlockchain(Blockchain):
def ether_airdrop(self, amount: int) -> List[str]:
"""Airdrops ether from creator address to all other addresses!"""
coinbase, *addresses = self.interface.w3.eth.accounts
coinbase, *addresses = self.w3.eth.accounts
tx_hashes = list()
for address in addresses:
@ -161,7 +146,7 @@ class TesterBlockchain(Blockchain):
'from': coinbase,
'value': amount}
txhash = self.interface.w3.eth.sendTransaction(tx)
txhash = self.w3.eth.sendTransaction(tx)
_receipt = self.wait_for_receipt(txhash)
tx_hashes.append(txhash)
@ -192,11 +177,11 @@ class TesterBlockchain(Blockchain):
else:
raise ValueError("Specify either hours, seconds, or lock_periods.")
now = self.interface.w3.eth.getBlock(block_identifier='latest').timestamp
now = self.w3.eth.getBlock(block_identifier='latest').timestamp
end_timestamp = ((now+duration)//base) * base
self.interface.w3.eth.web3.testing.timeTravel(timestamp=end_timestamp)
self.interface.w3.eth.web3.testing.mine(1)
self.w3.eth.web3.testing.timeTravel(timestamp=end_timestamp)
self.w3.eth.web3.testing.mine(1)
delta = maya.timedelta(seconds=end_timestamp-now)
self.log.info(f"Time traveled {delta} "
@ -208,9 +193,9 @@ class TesterBlockchain(Blockchain):
@classmethod
def connect(cls, *args, **kwargs) -> 'TesterBlockchain':
interface = BlockchainDeployerInterface(provider_uri=cls._PROVIDER_URI,
compiler=SolidityCompiler(test_contract_dir=CONTRACT_ROOT),
registry=InMemoryEthereumContractRegistry())
interface = BlockchainDeployer(provider_uri=cls._PROVIDER_URI,
compiler=SolidityCompiler(test_contract_dir=CONTRACT_ROOT),
registry=InMemoryEthereumContractRegistry())
testerchain = TesterBlockchain(interface=interface, *args, **kwargs)
return testerchain
@ -219,7 +204,7 @@ class TesterBlockchain(Blockchain):
def bootstrap_network(cls) -> Tuple['TesterBlockchain', Dict[str, EthereumContractAgent]]:
testerchain = cls.connect()
origin = testerchain.interface.w3.eth.accounts[0]
origin = testerchain.w3.eth.accounts[0]
deployer = Deployer(blockchain=testerchain, deployer_address=origin, bare=True)
_txhashes, agents = deployer.deploy_network_contracts(staker_secret=STAKING_ESCROW_DEPLOYMENT_SECRET,
@ -230,25 +215,25 @@ class TesterBlockchain(Blockchain):
@property
def etherbase_account(self):
return self.interface.w3.eth.accounts[self._ETHERBASE]
return self.w3.eth.accounts[self._ETHERBASE]
@property
def alice_account(self):
return self.interface.w3.eth.accounts[self._ALICE]
return self.w3.eth.accounts[self._ALICE]
@property
def bob_account(self):
return self.interface.w3.eth.accounts[self._BOB]
return self.w3.eth.accounts[self._BOB]
def ursula_account(self, index):
if index not in self._ursulas_range:
raise ValueError(f"Ursula index must be lower than {NUMBER_OF_URSULAS_IN_BLOCKCHAIN_TESTS}")
return self.interface.w3.eth.accounts[index + self._FIRST_URSULA]
return self.w3.eth.accounts[index + self._FIRST_URSULA]
def staker_account(self, index):
if index not in self._stakers_range:
raise ValueError(f"Staker index must be lower than {NUMBER_OF_STAKERS_IN_BLOCKCHAIN_TESTS}")
return self.interface.w3.eth.accounts[index + self._FIRST_STAKER]
return self.w3.eth.accounts[index + self._FIRST_STAKER]
@property
def ursulas_accounts(self):
@ -262,5 +247,12 @@ class TesterBlockchain(Blockchain):
def unassigned_accounts(self):
special_accounts = [self.etherbase_account, self.alice_account, self.bob_account]
assigned_accounts = set(self.stakers_accounts + self.ursulas_accounts + special_accounts)
accounts = set(self.interface.w3.eth.accounts)
accounts = set(self.w3.eth.accounts)
return list(accounts.difference(assigned_accounts))
def wait_for_receipt(self, txhash: bytes, timeout: int = None) -> dict:
"""Wait for a transaction receipt and return it"""
timeout = timeout or self.TIMEOUT
result = self.w3.eth.waitForTransactionReceipt(txhash, timeout=timeout)
return result

View File

@ -20,6 +20,7 @@ import random
from cryptography.x509 import Certificate
from typing import Set, List, Iterable
from nucypher.blockchain.eth.interfaces import Blockchain
from nucypher.blockchain.eth.token import StakeTracker
from nucypher.characters.lawful import Ursula
from nucypher.config.characters import UrsulaConfiguration
@ -65,6 +66,7 @@ def make_federated_ursulas(ursula_config: UrsulaConfiguration,
def make_decentralized_ursulas(ursula_config: UrsulaConfiguration,
blockchain: Blockchain,
stakers_addresses: Iterable[str],
workers_addresses: Iterable[str],
confirm_activity: bool = False,
@ -83,6 +85,7 @@ def make_decentralized_ursulas(ursula_config: UrsulaConfiguration,
ursula = ursula_config.produce(checksum_address=staker_address,
worker_address=worker_address,
blockchain=blockchain,
db_filepath=MOCK_URSULA_DB_FILEPATH,
rest_port=port + 100,
stake_tracker=stake_tracker,