mirror of https://github.com/nucypher/nucypher.git
Makes Testerchain a subclass of BlockchainDeployer
parent
47d221a9f9
commit
1886527a1c
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue