Include worker address sync in Stake; Blockchain to/from dict payload, Geth tranction formatting and signging.

pull/1124/head
Kieran Prasch 2019-06-26 17:31:20 -07:00
parent 7d3c80ae2b
commit 3bc659b66f
No known key found for this signature in database
GPG Key ID: 199AB839D4125A62
6 changed files with 81 additions and 36 deletions

View File

@ -145,8 +145,6 @@ class Deployer(NucypherTokenActor):
def __init__(self,
blockchain: BlockchainDeployerInterface,
client_password: str = None,
device = NO_STAKING_DEVICE,
deployer_address: str = None,
client_password: str = None,
bare: bool = True
@ -174,7 +172,6 @@ class Deployer(NucypherTokenActor):
# TODO: Does this class want to be a Character implementing PowerUp consumption?
self.transacting_power = TransactingPower(blockchain=blockchain,
device=device,
password=client_password,
account=deployer_address)
self.transacting_power.activate()

View File

@ -31,6 +31,9 @@ from nucypher.crypto.api import sha256_digest
class Agency(type):
__agents = dict()
class NoAgency(Exception):
pass
def __call__(cls, *args, **kwargs):
if cls not in cls.__agents:
cls.__agents[cls] = super().__call__(*args, **kwargs)
@ -44,6 +47,13 @@ class Agency(type):
def agents(cls):
return cls.__agents
@classmethod
def get_agent(mcs, cls):
try:
return mcs.__agents[cls]
except KeyError:
raise mcs.NoAgency
class EthereumContractAgent:
"""

View File

@ -197,20 +197,20 @@ class Web3Client:
return self.w3.eth.coinbase
def wait_for_receipt(self, transaction_hash: str, timeout: int) -> dict:
receipt = self.w3.eth.waitForTransactionReceipt(transaction_hash, timeout=timeout)
receipt = self.w3.eth.waitForTransactionReceipt(transaction_hash=transaction_hash, timeout=timeout)
return receipt
def sign_transaction(self, transaction: dict):
raise NotImplementedError
def get_transaction(self, transaction_hash) -> str:
return self.w3.eth.getTransaction(transaction_hash)
return self.w3.eth.getTransaction(transaction_hash=transaction_hash)
def send_transaction(self, transaction: dict) -> str:
return self.w3.eth.sendTransaction(transaction)
return self.w3.eth.sendTransaction(transaction=transaction)
def send_raw_transaction(self, transaction: bytes) -> str:
return self.w3.eth.sendRawTransaction(transaction)
return self.w3.eth.sendRawTransaction(raw_transaction=transaction)
def sync(self,
timeout: int = 120,
@ -258,6 +258,9 @@ class Web3Client:
"""
return self.w3.eth.sign(account, data=message)
def sign_transaction(self, transaction: dict) -> bytes:
raise NotImplementedError
class GethClient(Web3Client):
@ -270,6 +273,8 @@ class GethClient(Web3Client):
return self.w3.geth.admin.peers()
def unlock_account(self, address, password):
# if self.is_local:
# return True
return self.w3.geth.personal.unlockAccount(address, password)
def sign_transaction(self, transaction: dict) -> bytes:
@ -323,6 +328,10 @@ class EthereumTesterClient(Web3Client):
def sync(self, *args, **kwargs):
return True
def new_account(self, password: str):
insecure_account = self.w3.provider.ethereum_tester.add_account(os.urandom(32).hex(), password=password)
return insecure_account
def sign_transaction(self, transaction: dict):
# Get signing key of test account
address = to_canonical_address(transaction['from'])
@ -410,17 +419,20 @@ class NuCypherGethDevProcess(NuCypherGethProcess):
self.data_dir = get_chain_data_dir(base_dir=base_dir, name=self._CHAIN_NAME)
ipc_path = os.path.join(self.data_dir, 'geth.ipc')
self.geth_kwargs = {'ipc_path': ipc_path}
super().__init__(geth_kwargs=self.geth_kwargs, *args, **kwargs)
self.geth_kwargs.update({'dev': True})
self.geth_kwargs = {'ipc_path': ipc_path,
'data_dir': self.data_dir}
super().__init__(geth_kwargs=self.geth_kwargs, *args, **kwargs)
self.command = [*self.command, '--dev']
def start(self, timeout: int = 30, extra_delay: int = 1):
self.LOG.info("STARTING GETH DEV NOW")
BaseGethProcess.start(self) # <--- START GETH
time.sleep(extra_delay) # give it a second
self.wait_for_ipc(timeout=timeout)
if not self.is_running:
self.LOG.info("STARTING GETH DEV PROCESS NOW")
BaseGethProcess.start(self) # <--- START GETH
time.sleep(extra_delay) # give it a second
self.wait_for_ipc(timeout=timeout)
else:
self.LOG.info("RECONNECTING TO GETH DEV PROCESS")
class NuCypherGethDevnetProcess(NuCypherGethProcess):

View File

@ -164,9 +164,8 @@ class NucypherTokenDeployer(ContractDeployer):
"""
self.check_deployment_readiness()
_contract, deployment_txhash = self.blockchain.deploy_contract(
self.contract_name,
self.__economics.erc20_total_supply)
_contract, deployment_txhash = self.blockchain.deploy_contract(self.contract_name,
self.__economics.erc20_total_supply)
self._contract = _contract
return {'txhash': deployment_txhash}

View File

@ -34,9 +34,10 @@ from eth_tester import EthereumTester
from eth_utils import to_checksum_address, to_canonical_address
from twisted.logger import Logger
from web3 import Web3, WebsocketProvider, HTTPProvider, IPCProvider
from web3.contract import ConciseContract
from web3.contract import Contract, ContractFunction, ContractConstructor
from web3.exceptions import TimeExhausted, ValidationError
from web3.contract import Contract, ContractFunction
from web3.contract import ContractConstructor
from web3.exceptions import TimeExhausted
from web3.exceptions import ValidationError
from web3.middleware import geth_poa_middleware
from nucypher.blockchain.eth.clients import Web3Client, NuCypherGethProcess
@ -65,11 +66,11 @@ class BlockchainInterface:
TIMEOUT = 180 # seconds
NULL_ADDRESS = '0x' + '0' * 40
_instance = NO_BLOCKCHAIN_CONNECTION
_instance = NO_BLOCKCHAIN_CONNECTION.bool_value(False)
process = NO_PROVIDER_PROCESS.bool_value(False)
Web3 = Web3
_contract_factory = ConciseContract
_contract_factory = Contract
class InterfaceError(Exception):
pass
@ -163,20 +164,33 @@ class BlockchainInterface:
self.client = NO_BLOCKCHAIN_CONNECTION
self.transacting_power = transacting_power
self.registry = registry
BlockchainInterface._instance = self
def __repr__(self):
r = '{name}({uri})'.format(name=self.__class__.__name__, uri=self.provider_uri)
return r
def _configure_registry(self, fetch_registry: bool = True):
@classmethod
def from_dict(cls, payload: dict) -> 'BlockchainInterface':
registry = EthereumContractRegistry(registry_filepath=payload['registry_filepath'])
blockchain = cls(provider_uri=payload['provider_uri'],
registry=registry)
return blockchain
def to_dict(self) -> dict:
payload = dict(provider_uri=self.provider_uri,
poa=self.poa,
registry_filepath=self.registry.filepath)
return payload
def _configure_registry(self, fetch_registry: bool = True) -> None:
RegistryClass = EthereumContractRegistry._get_registry_class(local=self.client.is_local)
if fetch_registry:
registry = RegistryClass.from_latest_publication()
else:
registry = RegistryClass()
self.registry = registry
self.log.info("Using contract registry {}".format(self.registry.filepath))
@property
def is_connected(self) -> bool:
@ -187,7 +201,7 @@ class BlockchainInterface:
return False
return self.client.is_connected
def disconnect(self):
def disconnect(self) -> None:
if self._provider_process:
self._provider_process.stop()
self._provider_process = NO_PROVIDER_PROCESS
@ -232,14 +246,14 @@ class BlockchainInterface:
else:
self.attach_middleware()
# Establish contact with NuCypher contracts
if not self.registry:
self._configure_registry(fetch_registry=fetch_registry)
# Wait for chaindata sync
if sync_now:
self.client.sync()
# Establish contact with NuCypher contracts
if not self.registry:
self._configure_registry()
return self.is_connected
@property
@ -304,7 +318,9 @@ class BlockchainInterface:
payload.update({'chainId': int(self.client.chain_id),
'nonce': nonce,
'from': sender_address,
'gasPrice': self.client.w3.eth.gasPrice})
'gasPrice': self.client.w3.eth.gasPrice,
# 'gas': 0, # TODO: Gas Management
})
# Get interface name
try:
@ -461,8 +477,6 @@ class BlockchainDeployerInterface(BlockchainInterface):
self.__recompile = recompile
self.__sol_compiler = compiler
self.log.info("Using contract registry {}".format(self.registry.filepath))
if self.__recompile is True:
# Execute the compilation if we're recompiling
# Otherwise read compiled contract data from the registry

View File

@ -2,7 +2,15 @@ from _pydecimal import Decimal
from typing import Union, Tuple, Callable, List
import maya
from constant_sorrow.constants import NEW_STAKE, NO_STAKING_RECEIPT, NOT_STAKING, UNKNOWN_STAKES, NO_STAKES, EMPTY_STAKING_SLOT
from constant_sorrow.constants import (
NEW_STAKE,
NO_STAKING_RECEIPT,
NOT_STAKING,
UNKNOWN_STAKES,
NO_STAKES,
EMPTY_STAKING_SLOT,
UNKNOWN_WORKER_STATUS
)
from eth_utils import currency, is_checksum_address
from twisted.internet import task, reactor
from twisted.logger import Logger
@ -149,6 +157,7 @@ class Stake:
# Stake Metadata
self.owner_address = checksum_address
self.worker_address = UNKNOWN_WORKER_STATUS
self.index = index
self.value = value
self.start_period = start_period
@ -161,7 +170,7 @@ class Stake:
# Agency
self.staking_agent = None
self.token_agent = NucypherTokenAgent()
self.token_agent = NucypherTokenAgent() # TODO: Use Agency
self.blockchain = self.token_agent.blockchain
# Economics
@ -215,6 +224,9 @@ class Stake:
start_period=start_period,
end_period=end_period,
value=NU(value, 'NuNit'))
agent = StakingEscrowAgent()
instance.worker_address = agent.get_worker_from_staker(staker_address=checksum_address)
return instance
def to_stake_info(self) -> Tuple[int, int, int]:
@ -304,9 +316,9 @@ class Stake:
"""Update this stakes attributes with on-chain values."""
if not self.staking_agent:
self.staking_agent = StakingEscrowAgent()
self.staking_agent = StakingEscrowAgent(blockchain=self.blockchain)
if not self.token_agent:
self.token_agent = NucypherTokenAgent()
self.token_agent = NucypherTokenAgent(blockchain=self.blockchain)
# Read from blockchain
stake_info = self.staking_agent.get_substake_info(staker_address=self.owner_address,
@ -320,6 +332,7 @@ class Stake:
# Mutate the instance with the on-chain values
self.end_period = last_period
self.value = NU.from_nunits(locked_value)
self.worker_address = self.staking_agent.get_worker_from_staker(staker_address=self.owner_address)
@classmethod
def __deposit(cls, staker, amount: int, lock_periods: int) -> Tuple[str, str]: