Beispiel #1
0
def test_transacting_power_sign_transaction(testerchain):

    eth_address = testerchain.unassigned_accounts[2]
    power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD,
                             signer=Web3Signer(testerchain.client),
                             account=eth_address)

    transaction_dict = {
        'nonce': testerchain.client.w3.eth.getTransactionCount(eth_address),
        'gasPrice': testerchain.client.w3.eth.gasPrice,
        'gas': 100000,
        'from': eth_address,
        'to': testerchain.unassigned_accounts[1],
        'value': 1,
        'data': b''
    }

    # Sign
    power.activate()
    signed_transaction = power.sign_transaction(
        transaction_dict=transaction_dict)

    # Demonstrate that the transaction is valid RLP encoded.
    from eth_account._utils.transactions import Transaction
    restored_transaction = Transaction.from_bytes(
        serialized_bytes=signed_transaction)
    restored_dict = restored_transaction.as_dict()
    assert to_checksum_address(restored_dict['to']) == transaction_dict['to']

    # Try signing with missing transaction fields
    del transaction_dict['gas']
    del transaction_dict['nonce']
    with pytest.raises(TypeError):
        power.sign_transaction(transaction_dict=transaction_dict)
Beispiel #2
0
def test_transacting_power_sign_agent_transaction(testerchain, agency,
                                                  test_registry):

    token_agent = NucypherTokenAgent(registry=test_registry)
    contract_function = token_agent.contract.functions.approve(
        testerchain.etherbase_account, 100)

    payload = {
        'chainId':
        int(testerchain.client.chain_id),
        'nonce':
        testerchain.client.w3.eth.getTransactionCount(
            testerchain.etherbase_account),
        'from':
        testerchain.etherbase_account,
        'gasPrice':
        testerchain.client.gas_price
    }

    unsigned_transaction = contract_function.buildTransaction(payload)

    # Sign with Transacting Power
    transacting_power = TransactingPower(
        password=INSECURE_DEVELOPMENT_PASSWORD,
        signer=Web3Signer(testerchain.client),
        account=testerchain.etherbase_account)
    signed_raw_transaction = transacting_power.sign_transaction(
        unsigned_transaction)

    # Demonstrate that the transaction is valid RLP encoded.
    restored_transaction = Transaction.from_bytes(
        serialized_bytes=signed_raw_transaction)
    restored_dict = restored_transaction.as_dict()
    assert to_checksum_address(
        restored_dict['to']) == unsigned_transaction['to']
Beispiel #3
0
def test_transacting_power_sign_transaction(testerchain):

    eth_address = testerchain.unassigned_accounts[2]
    power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD,
                             signer=Web3Signer(testerchain.client),
                             account=eth_address)

    assert power.is_active is False
    assert power.is_unlocked is False

    transaction_dict = {
        'nonce': testerchain.client.w3.eth.getTransactionCount(eth_address),
        'gasPrice': testerchain.client.w3.eth.gasPrice,
        'gas': 100000,
        'from': eth_address,
        'to': testerchain.unassigned_accounts[1],
        'value': 1,
        'data': b''
    }

    # The default state of the account is locked.
    assert not power.is_unlocked

    # Test a signature without unlocking the account
    with pytest.raises(power.AccountLocked):
        power.sign_transaction(transaction_dict=transaction_dict)

    # Sign
    power.activate()
    assert power.is_unlocked is True
    signed_transaction = power.sign_transaction(
        transaction_dict=transaction_dict)

    # Demonstrate that the transaction is valid RLP encoded.
    from eth_account._utils.transactions import Transaction
    restored_transaction = Transaction.from_bytes(
        serialized_bytes=signed_transaction)
    restored_dict = restored_transaction.as_dict()
    assert to_checksum_address(restored_dict['to']) == transaction_dict['to']

    # Try signing with missing transaction fields
    del transaction_dict['gas']
    del transaction_dict['nonce']
    with pytest.raises(TypeError):
        power.sign_transaction(transaction_dict=transaction_dict)

    # Try signing with a re-locked account.
    power.lock_account()
    with pytest.raises(power.AccountLocked):
        power.sign_transaction(transaction_dict=transaction_dict)

    power.unlock_account(password=INSECURE_DEVELOPMENT_PASSWORD)
    assert power.is_unlocked is True

    # Tear-Down Test
    power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD,
                             signer=Web3Signer(testerchain.client),
                             account=testerchain.etherbase_account)
    power.activate(password=INSECURE_DEVELOPMENT_PASSWORD)
Beispiel #4
0
    def sign_and_broadcast_transaction(
            self,
            transacting_power: TransactingPower,
            transaction_dict: TransactionDict,
            transaction_name: str = "",
            confirmations: int = 0,
            fire_and_forget: bool = False) -> Union[TxReceipt, HexBytes]:
        """
        Takes a transaction dictionary, signs it with the configured signer, then broadcasts the signed
        transaction using the ethereum provider's eth_sendRawTransaction RPC endpoint.
        Optionally blocks for receipt and confirmation with 'confirmations', and 'fire_and_forget' flags.

        If 'fire and forget' is True this method returns the transaction hash only, without waiting for a receipt -
        otherwise return the transaction receipt.

        """
        #
        # Setup
        #

        # TODO # 1754 - Move this to singleton - I do not approve... nor does Bogdan?
        if GlobalLoggerSettings._json_ipc:
            emitter = JSONRPCStdoutEmitter()
        else:
            emitter = StdoutEmitter()

        #
        # Sign
        #

        # TODO: Show the USD Price:  https://api.coinmarketcap.com/v1/ticker/ethereum/
        price = transaction_dict['gasPrice']
        price_gwei = Web3.fromWei(price, 'gwei')
        cost_wei = price * transaction_dict['gas']
        cost = Web3.fromWei(cost_wei, 'ether')

        if transacting_power.is_device:
            emitter.message(
                f'Confirm transaction {transaction_name} on hardware wallet... '
                f'({cost} ETH @ {price_gwei} gwei)',
                color='yellow')
        signed_raw_transaction = transacting_power.sign_transaction(
            transaction_dict)

        #
        # Broadcast
        #
        emitter.message(
            f'Broadcasting {transaction_name} Transaction ({cost} ETH @ {price_gwei} gwei)',
            color='yellow')
        try:
            txhash = self.client.send_raw_transaction(
                signed_raw_transaction)  # <--- BROADCAST
            emitter.message(f'TXHASH {txhash.hex()}', color='yellow')
        except (TestTransactionFailed, ValueError):
            raise  # TODO: Unify with Transaction failed handling -- Entry point for _handle_failed_transaction
        else:
            if fire_and_forget:
                return txhash

        #
        # Receipt
        #

        try:  # TODO: Handle block confirmation exceptions
            waiting_for = 'receipt'
            if confirmations:
                waiting_for = f'{confirmations} confirmations'
            emitter.message(
                f'Waiting {self.TIMEOUT} seconds for {waiting_for}',
                color='yellow')
            receipt = self.client.wait_for_receipt(txhash,
                                                   timeout=self.TIMEOUT,
                                                   confirmations=confirmations)
        except TimeExhausted:
            # TODO: #1504 - Handle transaction timeout
            raise
        else:
            self.log.debug(
                f"[RECEIPT-{transaction_name}] | txhash: {receipt['transactionHash'].hex()}"
            )

        #
        # Confirmations
        #

        # Primary check
        transaction_status = receipt.get('status', UNKNOWN_TX_STATUS)
        if transaction_status == 0:
            failure = f"Transaction transmitted, but receipt returned status code 0. " \
                      f"Full receipt: \n {pprint.pformat(receipt, indent=2)}"
            raise self.InterfaceError(failure)

        if transaction_status is UNKNOWN_TX_STATUS:
            self.log.info(
                f"Unknown transaction status for {txhash} (receipt did not contain a status field)"
            )

            # Secondary check
            tx = self.client.get_transaction(txhash)
            if tx["gas"] == receipt["gasUsed"]:
                raise self.InterfaceError(
                    f"Transaction consumed 100% of transaction gas."
                    f"Full receipt: \n {pprint.pformat(receipt, indent=2)}")

        return receipt