示例#1
0
class StakeTracker:

    REFRESH_RATE = 60

    tracking_addresses = set()

    __stakes = dict()  # type: Dict[str: List[Stake]]
    __actions = list()  # type: List[Tuple[Callable, tuple]]

    def __init__(self,
                 checksum_addresses: List[str],
                 refresh_rate: int = None,
                 start_now: bool = False,
                 *args,
                 **kwargs):

        super().__init__(*args, **kwargs)

        self.log = Logger('stake-tracker')
        self.staking_agent = StakingEscrowAgent()

        self._refresh_rate = refresh_rate or self.REFRESH_RATE
        self._tracking_task = task.LoopingCall(self.__update)

        self.__current_period = None
        self.__stakes = dict()
        self.__start_time = NOT_STAKING
        self.__uptime_period = NOT_STAKING
        self.__terminal_period = NOT_STAKING
        self._abort_on_stake_tracking_error = True

        # "load-in":  Read on-chain stakes
        for checksum_address in checksum_addresses:
            if not is_checksum_address(checksum_address):
                raise ValueError(
                    f'{checksum_address} is not a valid EIP-55 checksum address'
                )
            self.tracking_addresses.add(checksum_address)

        if start_now:
            self.start()  # deamonize
        else:
            self.refresh(checksum_addresses=checksum_addresses)  # read-once

    @validate_checksum_address
    def __getitem__(self, checksum_address: str):
        stakes = self.stakes(checksum_address=checksum_address)
        return stakes

    def add_action(self, func: Callable, args=()) -> None:
        self.__actions.append((func, args))

    def clear_actions(self) -> None:
        self.__actions.clear()

    @property
    def current_period(self):
        return self.__current_period

    @validate_checksum_address
    def stakes(self, checksum_address: str) -> List[Stake]:
        """Return all cached stake instances from the blockchain."""
        try:
            return self.__stakes[checksum_address]
        except KeyError:
            return NO_STAKES.bool_value(False)
        except TypeError:
            if self.__stakes in (UNKNOWN_STAKES, NO_STAKES):
                return NO_STAKES.bool_value(False)
            raise

    @validate_checksum_address
    def refresh(self, checksum_addresses: List[str] = None) -> None:
        """Public staking cache invalidation method"""
        return self.__read_stakes(checksum_addresses=checksum_addresses)

    def stop(self) -> None:
        self._tracking_task.stop()
        self.log.info(f"STOPPED STAKE TRACKING")

    def start(self, force: bool = False) -> None:
        """
        High-level stake tracking initialization, this function aims
        to be safely called at any time - For example, it is okay to call
        this function multiple times within the same period.
        """
        if self._tracking_task.running and not force:
            return

        # Record the start time and period
        self.__start_time = maya.now()
        self.__uptime_period = self.staking_agent.get_current_period()
        self.__current_period = self.__uptime_period

        d = self._tracking_task.start(interval=self._refresh_rate)
        d.addErrback(self.handle_tracking_errors)
        self.log.info(
            f"STARTED STAKE TRACKING for {len(self.tracking_addresses)} addresses"
        )

    def _crash_gracefully(self, failure=None) -> None:
        """
        A facility for crashing more gracefully in the event that
        an exception is unhandled in a different thread.
        """
        self._crashed = failure
        failure.raiseException()

    def handle_tracking_errors(self, *args, **kwargs) -> None:
        failure = args[0]
        if self._abort_on_stake_tracking_error:
            self.log.critical(
                f"Unhandled error during node stake tracking. {failure}")
            reactor.callFromThread(self._crash_gracefully, failure=failure)
        else:
            self.log.warn(
                f"Unhandled error during stake tracking: {failure.getTraceback()}"
            )

    def __update(self) -> None:
        self.log.info(
            f"Checking for new period. Current period is {self.__current_period}"
        )
        onchain_period = self.staking_agent.get_current_period(
        )  # < -- Read from contract
        if self.__current_period != onchain_period:
            self.__current_period = onchain_period
            self.__read_stakes()
            for action, args in self.__actions:
                action(*args)

    @validate_checksum_address
    def __read_stakes(self, checksum_addresses: List[str] = None) -> None:
        """Rewrite the local staking cache by reading on-chain stakes"""

        if not checksum_addresses:
            checksum_addresses = self.tracking_addresses

        for checksum_address in checksum_addresses:

            if not is_checksum_address(checksum_address):
                if self._abort_on_stake_tracking_error:
                    raise ValueError(
                        f'{checksum_address} is not a valid EIP-55 checksum address'
                    )
                self.tracking_addresses.remove(checksum_address)  # Prune

            existing_records = len(
                self.stakes(checksum_address=checksum_address))

            # Candidate replacement cache values
            onchain_stakes, terminal_period = list(), 0

            # Read from blockchain
            stakes_reader = self.staking_agent.get_all_stakes(
                staker_address=checksum_address)
            for onchain_index, stake_info in enumerate(stakes_reader):

                if not stake_info:
                    onchain_stake = EMPTY_STAKING_SLOT

                else:
                    onchain_stake = Stake.from_stake_info(
                        checksum_address=checksum_address,
                        stake_info=stake_info,
                        index=onchain_index)

                    # rack the latest terminal period
                    if onchain_stake.end_period > terminal_period:
                        terminal_period = onchain_stake.end_period

                # Store the replacement stake
                onchain_stakes.append(onchain_stake)

            # Commit the new stake and terminal values to the cache
            if not onchain_stakes:
                self.__stakes[checksum_address] = NO_STAKES.bool_value(False)
            else:
                self.__terminal_period = terminal_period
                self.__stakes[checksum_address] = onchain_stakes
                new_records = existing_records - len(
                    self.__stakes[checksum_address])
                self.log.debug(
                    f"Updated local staking cache ({new_records} new stakes).")

            # Record most recent cache update
            self.__updated = maya.now()
示例#2
0
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 analyzer is None:
        analyzer = AnalyzeGas()

    log = Logger(AnalyzeGas.LOG_NAME)
    os.environ[
        'GAS_ESTIMATOR_BACKEND_FUNC'] = 'eth.estimators.gas.binary_gas_search_exact'

    # Blockchain
    economics = StandardTokenEconomics(base_penalty=MIN_ALLOWED_LOCKED - 1,
                                       penalty_history_coefficient=0,
                                       percentage_penalty_coefficient=2,
                                       reward_coefficient=2)
    testerchain, registry = TesterBlockchain.bootstrap_network(
        economics=economics)
    web3 = testerchain.w3

    print("\n********* SIZE OF MAIN CONTRACTS *********")
    MAX_SIZE = 24576
    rows = list()
    for contract_name in NUCYPHER_CONTRACT_NAMES:
        compiled_contract = testerchain._raw_contract_cache[contract_name]

        version = list(compiled_contract).pop()
        bin_runtime = compiled_contract[version]['bin-runtime']
        bin_length_in_bytes = len(bin_runtime) // 2
        percentage = int(100 * bin_length_in_bytes / MAX_SIZE)
        bar = ('*' * (percentage // 2)).ljust(50)
        rows.append(
            (contract_name, bin_length_in_bytes, f'{bar} {percentage}%'))

    headers = ('Contract', 'Size (B)',
               f'% of max allowed contract size ({MAX_SIZE} B)')
    print(tabulate.tabulate(rows, headers=headers, tablefmt="simple"),
          end="\n\n")

    # Accounts
    origin, staker1, staker2, staker3, staker4, alice1, alice2, *everyone_else = testerchain.client.accounts

    ursula_with_stamp = mock_ursula(testerchain, staker1)

    # Contracts
    token_agent = NucypherTokenAgent(registry=registry)
    staking_agent = StakingEscrowAgent(registry=registry)
    policy_agent = PolicyManagerAgent(registry=registry)
    adjudicator_agent = AdjudicatorAgent(registry=registry)

    # Contract Callers
    token_functions = token_agent.contract.functions
    staker_functions = staking_agent.contract.functions
    policy_functions = policy_agent.contract.functions
    adjudicator_functions = adjudicator_agent.contract.functions

    analyzer.start_collection()
    print("********* Estimating Gas *********")

    def transact_and_log(label, function, transaction):
        estimates = function.estimateGas(transaction)
        transaction.update(gas=estimates)
        tx = function.transact(transaction)
        receipt = testerchain.wait_for_receipt(tx)
        log.info(f"{label} = {estimates} | {receipt['gasUsed']}")

    def transact(function, transaction):
        transaction.update(gas=1000000)
        tx = function.transact(transaction)
        testerchain.wait_for_receipt(tx)

    #
    # Give Ursula and Alice some coins
    #
    transact_and_log(
        "Transfer tokens",
        token_functions.transfer(staker1, MIN_ALLOWED_LOCKED * 10),
        {'from': origin})
    transact(token_functions.transfer(staker2, MIN_ALLOWED_LOCKED * 10),
             {'from': origin})
    transact(token_functions.transfer(staker3, MIN_ALLOWED_LOCKED * 10),
             {'from': origin})

    #
    # Ursula and Alice give Escrow rights to transfer
    #
    transact_and_log(
        "Approving transfer",
        token_functions.approve(staking_agent.contract_address,
                                MIN_ALLOWED_LOCKED * 7), {'from': staker1})
    transact(
        token_functions.approve(staking_agent.contract_address,
                                MIN_ALLOWED_LOCKED * 6), {'from': staker2})
    transact(
        token_functions.approve(staking_agent.contract_address,
                                MIN_ALLOWED_LOCKED * 6), {'from': staker3})

    #
    # Batch deposit tokens
    #
    current_period = staking_agent.get_current_period()
    transact(
        token_functions.approve(staking_agent.contract_address,
                                MIN_ALLOWED_LOCKED * 10), {'from': origin})
    transact_and_log(
        "Batch deposit tokens for 5 owners x 2 sub-stakes",
        staker_functions.batchDeposit(everyone_else[0:5], [2] * 5,
                                      [MIN_ALLOWED_LOCKED] * 10,
                                      [MIN_LOCKED_PERIODS] * 10),
        {'from': origin})

    transact(
        token_functions.approve(staking_agent.contract_address,
                                MIN_ALLOWED_LOCKED * 24), {'from': origin})
    transact_and_log(
        "Batch deposit tokens for 1 owners x 24 sub-stakes",
        staker_functions.batchDeposit([everyone_else[6]], [24],
                                      [MIN_ALLOWED_LOCKED] * 24,
                                      [MIN_LOCKED_PERIODS] * 24),
        {'from': origin})

    transact(
        token_functions.approve(staking_agent.contract_address,
                                MIN_ALLOWED_LOCKED * 24 * 5), {'from': origin})
    transact_and_log(
        "Batch deposit tokens for 5 owners x 24 sub-stakes",
        staker_functions.batchDeposit(everyone_else[7:12], [24] * 5,
                                      [MIN_ALLOWED_LOCKED] * (24 * 5),
                                      [MIN_LOCKED_PERIODS] * (24 * 5)),
        {'from': origin})

    #
    # Ursula and Alice transfer some tokens to the escrow and lock them
    #
    transact_and_log(
        "Initial deposit tokens, first",
        staker_functions.deposit(staker1, MIN_ALLOWED_LOCKED * 3,
                                 MIN_LOCKED_PERIODS), {'from': staker1})
    transact_and_log(
        "Initial deposit tokens, other",
        staker_functions.deposit(staker2, MIN_ALLOWED_LOCKED * 3,
                                 MIN_LOCKED_PERIODS), {'from': staker2})
    transact(
        staker_functions.deposit(staker3, MIN_ALLOWED_LOCKED * 3,
                                 MIN_LOCKED_PERIODS), {'from': staker3})

    transact(staker_functions.bondWorker(staker1), {'from': staker1})
    transact(staker_functions.bondWorker(staker2), {'from': staker2})
    transact(staker_functions.bondWorker(staker3), {'from': staker3})
    transact(staker_functions.setReStake(False), {'from': staker1})
    transact(staker_functions.setReStake(False), {'from': staker2})
    transact(staker_functions.setWindDown(True), {'from': staker1})
    transact(staker_functions.setWindDown(True), {'from': staker2})
    transact(staker_functions.commitToNextPeriod(), {'from': staker1})
    transact(staker_functions.commitToNextPeriod(), {'from': staker2})

    #
    # Wait 1 period and make a commitment
    #
    testerchain.time_travel(periods=1)
    transact_and_log("Make a commitment, first",
                     staker_functions.commitToNextPeriod(), {'from': staker1})
    transact_and_log("Make a commitment, other",
                     staker_functions.commitToNextPeriod(), {'from': staker2})

    #
    # Wait 1 period and mint tokens
    #
    testerchain.time_travel(periods=1)
    transact_and_log("Minting (1 stake), first", staker_functions.mint(),
                     {'from': staker1})
    transact_and_log("Minting (1 stake), other", staker_functions.mint(),
                     {'from': staker2})
    transact_and_log("Make a commitment again, first",
                     staker_functions.commitToNextPeriod(), {'from': staker1})
    transact_and_log("Make a commitment again, other",
                     staker_functions.commitToNextPeriod(), {'from': staker2})
    transact(staker_functions.commitToNextPeriod(), {'from': staker3})

    #
    # Commit again
    #
    testerchain.time_travel(periods=1)
    transact_and_log("Make a commitment + mint, first",
                     staker_functions.commitToNextPeriod(), {'from': staker1})
    transact_and_log("Make a commitment + mint, other",
                     staker_functions.commitToNextPeriod(), {'from': staker2})

    #
    # Create policy
    #
    policy_id_1 = os.urandom(int(Policy.POLICY_ID_LENGTH))
    policy_id_2 = os.urandom(int(Policy.POLICY_ID_LENGTH))
    number_of_periods = 10
    rate = 100
    one_period = economics.hours_per_period * 60 * 60
    value = number_of_periods * rate
    current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
    end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
    transact_and_log(
        "Creating policy (1 node, 10 periods, pre-committed), first",
        policy_functions.createPolicy(policy_id_1, alice1, end_timestamp,
                                      [staker1]), {
                                          'from': alice1,
                                          'value': value
                                      })
    transact_and_log(
        "Creating policy (1 node, 10 periods, pre-committed), other",
        policy_functions.createPolicy(policy_id_2, alice1, end_timestamp,
                                      [staker1]), {
                                          'from': alice1,
                                          'value': value
                                      })

    #
    # Get locked tokens
    #
    transact_and_log("Getting locked tokens",
                     staker_functions.getLockedTokens(staker1, 0), {})

    #
    # Wait 1 period and withdraw tokens
    #
    testerchain.time_travel(periods=1)
    transact_and_log("Withdraw", staker_functions.withdraw(1),
                     {'from': staker1})

    #
    # Make a commitment with re-stake
    #
    transact(staker_functions.setReStake(True), {'from': staker1})
    transact(staker_functions.setReStake(True), {'from': staker2})

    # Used to remove spending for first call in a day for mint and commitToNextPeriod
    transact(staker_functions.commitToNextPeriod(), {'from': staker3})

    transact_and_log("Make a commitment + mint + re-stake",
                     staker_functions.commitToNextPeriod(), {'from': staker2})
    transact_and_log(
        "Make a commitment + mint + re-stake + first fee + first fee rate",
        staker_functions.commitToNextPeriod(), {'from': staker1})

    transact(staker_functions.setReStake(False), {'from': staker1})
    transact(staker_functions.setReStake(False), {'from': staker2})

    #
    # Wait 2 periods and make a commitment after downtime
    #
    testerchain.time_travel(periods=2)
    transact(staker_functions.commitToNextPeriod(), {'from': staker3})
    transact_and_log("Make a commitment after downtime",
                     staker_functions.commitToNextPeriod(), {'from': staker2})
    transact_and_log("Make a commitment after downtime + updating fee",
                     staker_functions.commitToNextPeriod(), {'from': staker1})

    #
    # Ursula and Alice deposit some tokens to the escrow again
    #
    transact_and_log(
        "Deposit tokens after making a commitment",
        staker_functions.deposit(staker1, MIN_ALLOWED_LOCKED * 2,
                                 MIN_LOCKED_PERIODS), {'from': staker1})
    transact(
        staker_functions.deposit(staker2, MIN_ALLOWED_LOCKED * 2,
                                 MIN_LOCKED_PERIODS), {'from': staker2})

    #
    # Revoke policy
    #
    transact_and_log("Revoking policy",
                     policy_functions.revokePolicy(policy_id_1),
                     {'from': alice1})

    #
    # Wait 1 period
    #
    testerchain.time_travel(periods=1)

    #
    # Create policy with multiple pre-committed nodes
    #
    policy_id_1 = os.urandom(int(Policy.POLICY_ID_LENGTH))
    policy_id_2 = os.urandom(int(Policy.POLICY_ID_LENGTH))
    policy_id_3 = os.urandom(int(Policy.POLICY_ID_LENGTH))
    number_of_periods = 100
    value = 3 * number_of_periods * rate
    current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
    end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
    transact_and_log(
        "Creating policy (3 nodes, 100 periods, pre-committed), first",
        policy_functions.createPolicy(policy_id_1, alice1, end_timestamp,
                                      [staker1, staker2, staker3]), {
                                          'from': alice1,
                                          'value': value
                                      })
    transact_and_log(
        "Creating policy (3 nodes, 100 periods, pre-committed), other",
        policy_functions.createPolicy(policy_id_2, alice1, end_timestamp,
                                      [staker1, staker2, staker3]), {
                                          'from': alice1,
                                          'value': value
                                      })
    value = 2 * number_of_periods * rate
    transact_and_log(
        "Creating policy (2 nodes, 100 periods, pre-committed), other",
        policy_functions.createPolicy(policy_id_3, alice1, end_timestamp,
                                      [staker1, staker2]), {
                                          'from': alice1,
                                          'value': value
                                      })

    #
    # Wait 1 period and mint tokens
    #
    testerchain.time_travel(periods=1)
    transact(staker_functions.mint(), {'from': staker3})
    transact_and_log("Last minting + updating fee + updating fee rate",
                     staker_functions.mint(), {'from': staker1})
    transact_and_log("Last minting + first fee + first fee rate",
                     staker_functions.mint(), {'from': staker2})

    #
    # Create policy again without pre-committed nodes
    #
    policy_id_1 = os.urandom(int(Policy.POLICY_ID_LENGTH))
    policy_id_2 = os.urandom(int(Policy.POLICY_ID_LENGTH))
    policy_id_3 = os.urandom(int(Policy.POLICY_ID_LENGTH))
    number_of_periods = 100
    value = number_of_periods * rate
    current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
    end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
    transact_and_log(
        "Creating policy (1 node, 100 periods)",
        policy_functions.createPolicy(policy_id_1, alice2, end_timestamp,
                                      [staker2]), {
                                          'from': alice1,
                                          'value': value
                                      })
    testerchain.time_travel(periods=1)
    current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
    end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
    transact_and_log(
        "Creating policy (1 node, 100 periods), next period",
        policy_functions.createPolicy(policy_id_2, alice2, end_timestamp,
                                      [staker2]), {
                                          'from': alice1,
                                          'value': value
                                      })
    transact_and_log(
        "Creating policy (1 node, 100 periods), another node",
        policy_functions.createPolicy(policy_id_3, alice2, end_timestamp,
                                      [staker1]), {
                                          'from': alice1,
                                          'value': value
                                      })

    #
    # Mint and revoke policy
    #
    testerchain.time_travel(periods=10)
    transact(staker_functions.commitToNextPeriod(), {'from': staker1})
    transact(staker_functions.commitToNextPeriod(), {'from': staker3})

    testerchain.time_travel(periods=2)
    transact(staker_functions.mint(), {'from': staker3})
    transact_and_log("Last minting after downtime + updating fee",
                     staker_functions.mint(), {'from': staker1})

    testerchain.time_travel(periods=10)
    transact_and_log("Revoking policy after downtime, 1st policy",
                     policy_functions.revokePolicy(policy_id_1),
                     {'from': alice2})
    transact_and_log("Revoking policy after downtime, 2nd policy",
                     policy_functions.revokePolicy(policy_id_2),
                     {'from': alice2})
    transact_and_log("Revoking policy after downtime, 3rd policy",
                     policy_functions.revokePolicy(policy_id_3),
                     {'from': alice2})

    for index in range(5):
        transact(staker_functions.commitToNextPeriod(), {'from': staker1})
        testerchain.time_travel(periods=1)
    transact(staker_functions.mint(), {'from': staker1})

    #
    # Check regular deposit
    #
    transact_and_log(
        "Deposit tokens to new sub-stake",
        staker_functions.deposit(staker1, MIN_ALLOWED_LOCKED,
                                 MIN_LOCKED_PERIODS), {'from': staker1})
    transact_and_log(
        "Deposit tokens using existing sub-stake",
        staker_functions.depositAndIncrease(0, MIN_ALLOWED_LOCKED),
        {'from': staker1})

    #
    # ApproveAndCall
    #
    testerchain.time_travel(periods=1)
    transact(staker_functions.mint(), {'from': staker1})

    transact_and_log(
        "ApproveAndCall",
        token_functions.approveAndCall(staking_agent.contract_address,
                                       MIN_ALLOWED_LOCKED * 2,
                                       web3.toBytes(MIN_LOCKED_PERIODS)),
        {'from': staker1})

    #
    # Locking tokens
    #
    testerchain.time_travel(periods=1)
    transact(staker_functions.commitToNextPeriod(), {'from': staker1})
    transact_and_log(
        "Locking tokens and creating new sub-stake",
        staker_functions.lockAndCreate(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS),
        {'from': staker1})
    transact_and_log("Locking tokens using existing sub-stake",
                     staker_functions.lockAndIncrease(0, MIN_ALLOWED_LOCKED),
                     {'from': staker1})

    #
    # Divide stake
    #
    transact_and_log("Divide stake",
                     staker_functions.divideStake(1, MIN_ALLOWED_LOCKED, 2),
                     {'from': staker1})
    transact(staker_functions.divideStake(3, MIN_ALLOWED_LOCKED, 2),
             {'from': staker1})

    #
    # Divide almost finished stake
    #
    testerchain.time_travel(periods=1)
    transact(staker_functions.commitToNextPeriod(), {'from': staker1})
    testerchain.time_travel(periods=1)
    transact(staker_functions.commitToNextPeriod(), {'from': staker1})

    #
    # Slashing tests
    #
    transact(staker_functions.commitToNextPeriod(), {'from': staker1})
    testerchain.time_travel(periods=1)

    #
    # Slashing
    #
    slashing_args = generate_args_for_slashing(ursula_with_stamp)
    transact_and_log("Slash just value",
                     adjudicator_functions.evaluateCFrag(*slashing_args),
                     {'from': alice1})

    deposit = staker_functions.stakerInfo(staker1).call()[0]
    unlocked = deposit - staker_functions.getLockedTokens(staker1, 0).call()
    transact(staker_functions.withdraw(unlocked), {'from': staker1})

    sub_stakes_length = str(
        staker_functions.getSubStakesLength(staker1).call())
    slashing_args = generate_args_for_slashing(ursula_with_stamp)
    transact_and_log(
        "Slashing one sub stake and saving old one (" +
        sub_stakes_length + " sub stakes), 1st",
        adjudicator_functions.evaluateCFrag(*slashing_args), {'from': alice1})

    sub_stakes_length = str(
        staker_functions.getSubStakesLength(staker1).call())
    slashing_args = generate_args_for_slashing(ursula_with_stamp)
    transact_and_log(
        "Slashing one sub stake and saving old one (" +
        sub_stakes_length + " sub stakes), 2nd",
        adjudicator_functions.evaluateCFrag(*slashing_args), {'from': alice1})

    sub_stakes_length = str(
        staker_functions.getSubStakesLength(staker1).call())
    slashing_args = generate_args_for_slashing(ursula_with_stamp)
    transact_and_log(
        "Slashing one sub stake and saving old one (" +
        sub_stakes_length + " sub stakes), 3rd",
        adjudicator_functions.evaluateCFrag(*slashing_args), {'from': alice1})

    sub_stakes_length = str(
        staker_functions.getSubStakesLength(staker1).call())
    slashing_args = generate_args_for_slashing(ursula_with_stamp)
    transact_and_log(
        "Slashing two sub stakes and saving old one (" +
        sub_stakes_length + " sub stakes)",
        adjudicator_functions.evaluateCFrag(*slashing_args), {'from': alice1})

    for index in range(18):
        transact(staker_functions.commitToNextPeriod(), {'from': staker1})
        testerchain.time_travel(periods=1)

    transact(
        staker_functions.lockAndCreate(MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS),
        {'from': staker1})
    deposit = staker_functions.stakerInfo(staker1).call()[0]
    unlocked = deposit - staker_functions.getLockedTokens(staker1, 1).call()
    transact(staker_functions.withdraw(unlocked), {'from': staker1})

    sub_stakes_length = str(
        staker_functions.getSubStakesLength(staker1).call())
    slashing_args = generate_args_for_slashing(ursula_with_stamp)
    transact_and_log(
        "Slashing two sub stakes, shortest and new one (" +
        sub_stakes_length + " sub stakes)",
        adjudicator_functions.evaluateCFrag(*slashing_args), {'from': alice1})

    sub_stakes_length = str(
        staker_functions.getSubStakesLength(staker1).call())
    slashing_args = generate_args_for_slashing(ursula_with_stamp)
    transact_and_log(
        "Slashing three sub stakes, two shortest and new one (" +
        sub_stakes_length + " sub stakes)",
        adjudicator_functions.evaluateCFrag(*slashing_args), {'from': alice1})

    slashing_args = generate_args_for_slashing(ursula_with_stamp,
                                               corrupt_cfrag=False)
    transact_and_log("Evaluating correct CFrag",
                     adjudicator_functions.evaluateCFrag(*slashing_args),
                     {'from': alice1})

    transact_and_log("Prolong stake", staker_functions.prolongStake(0, 20),
                     {'from': staker1})
    transact_and_log("Merge sub-stakes", staker_functions.mergeStake(2, 3),
                     {'from': staker1})

    # Large number of sub-stakes
    number_of_sub_stakes = 24
    transact(
        token_functions.approve(staking_agent.contract_address,
                                MIN_ALLOWED_LOCKED * number_of_sub_stakes),
        {'from': origin})
    transact(
        staker_functions.batchDeposit(
            [staker4], [number_of_sub_stakes],
            [MIN_ALLOWED_LOCKED] * number_of_sub_stakes,
            [MIN_LOCKED_PERIODS] * number_of_sub_stakes), {'from': origin})
    transact(staker_functions.bondWorker(staker4), {'from': staker4})
    transact(staker_functions.setWindDown(True), {'from': staker4})

    # Used to remove spending for first call in a day for mint and commitToNextPeriod
    transact(staker_functions.commitToNextPeriod(), {'from': staker1})

    transact_and_log(f"Make a commitment ({number_of_sub_stakes} sub-stakes)",
                     staker_functions.commitToNextPeriod(), {'from': staker4})

    testerchain.time_travel(periods=1)
    transact(staker_functions.commitToNextPeriod(), {'from': staker4})
    testerchain.time_travel(periods=1)

    # Used to remove spending for first call in a day for mint and commitToNextPeriod
    transact(staker_functions.commitToNextPeriod(), {'from': staker1})

    transact_and_log(
        f"Make a commitment + mint + re-stake ({number_of_sub_stakes} sub-stakes)",
        staker_functions.commitToNextPeriod(), {'from': staker4})

    print("********* All Done! *********")
示例#3
0
def test_nucypher_deploy_contracts(click_runner,
                                   mock_primary_registry_filepath,
                                   mock_allocation_infile, token_economics):

    Agency.clear()

    #
    # Setup
    #

    # We start with a blockchain node, and nothing else...
    if os.path.isfile(mock_primary_registry_filepath):
        os.remove(mock_primary_registry_filepath)
    assert not os.path.isfile(mock_primary_registry_filepath)

    #
    # Main
    #

    command = [
        'contracts', '--registry-outfile', mock_primary_registry_filepath,
        '--provider-uri', TEST_PROVIDER_URI, '--poa'
    ]

    user_input = '0\n' + 'Y\n' + (f'{INSECURE_SECRETS[1]}\n' * 8) + 'DEPLOY'
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Ensure there is a report on each contract
    for registry_name in Deployer.contract_names:
        assert registry_name in result.output

    # Check that the primary contract registry was written
    # and peek at some of the registered entries
    assert os.path.isfile(mock_primary_registry_filepath)
    with open(mock_primary_registry_filepath, 'r') as file:

        # Ensure every contract's name was written to the file, somehow
        raw_registry_data = file.read()
        for registry_name in Deployer.contract_names:
            assert registry_name in raw_registry_data

        # Ensure the Registry is JSON deserializable
        registry_data = json.loads(raw_registry_data)

        # and that is has the correct number of entries
        assert len(registry_data) == 9

        # Read several records
        token_record, escrow_record, dispatcher_record, *other_records = registry_data
        registered_name, registered_address, registered_abi = token_record

    #
    # Agency
    #

    token_agent = NucypherTokenAgent()
    assert token_agent.contract_name == registered_name
    assert token_agent.registry_contract_name == registered_name
    assert token_agent.contract_address == registered_address

    # Now show that we can use contract Agency and read from the blockchain
    assert token_agent.get_balance() == 0
    staking_agent = StakingEscrowAgent()
    assert staking_agent.get_current_period()

    # and at least the others can be instantiated
    assert PolicyAgent()