Example #1
0
 def to_dict(self):
     return {
         'type':
         self.__class__.__name__,
         'message_identifier':
         self.message_identifier,
         'payment_identifier':
         self.payment_identifier,
         'nonce':
         self.nonce,
         'token_network_address':
         to_normalized_address(self.token_network_address),
         'token':
         to_normalized_address(self.token),
         'channel':
         to_normalized_address(self.channel),
         'transferred_amount':
         self.transferred_amount,
         'locked_amount':
         self.locked_amount,
         'recipient':
         to_normalized_address(self.recipient),
         'locksroot':
         data_encoder(self.locksroot),
         'signature':
         data_encoder(self.signature),
     }
Example #2
0
 def to_dict(self):
     return {
         'type': self.__class__.__name__,
         'message_identifier': self.message_identifier,
         'secret': data_encoder(self.secret),
         'signature': data_encoder(self.signature)
     }
Example #3
0
def format_data_for_call(sender='',
                         to='',
                         value=0,
                         data='',
                         startgas=GAS_PRICE,
                         gasprice=GAS_PRICE):
    """ Helper to format the transaction data. """

    json_data = {}

    if sender is not None:
        json_data['from'] = address_encoder(sender)

    if to is not None:
        json_data['to'] = data_encoder(to)

    if value is not None:
        json_data['value'] = quantity_encoder(value)

    if gasprice is not None:
        json_data['gasPrice'] = quantity_encoder(gasprice)

    if startgas is not None:
        json_data['gas'] = quantity_encoder(startgas)

    if data is not None:
        json_data['data'] = data_encoder(data)

    return json_data
Example #4
0
 def to_dict(self):
     return {
         'type': self.__class__.__name__,
         'message_identifier': self.message_identifier,
         'payment_identifier': self.payment_identifier,
         'secrethash': data_encoder(self.secrethash),
         'amount': self.amount,
         'signature': data_encoder(self.signature)
     }
Example #5
0
    def eth_sendTransaction(
            self,
            nonce=None,
            sender='',
            to='',
            value=0,
            data='',
            gasPrice=GAS_PRICE,
            gas=GAS_PRICE):
        """ Creates new message call transaction or a contract creation, if the
        data field contains code.

        Args:
            sender (address): The 20 bytes address the transaction is sent from.
            to (address): DATA, 20 Bytes - (optional when creating new
                contract) The address the transaction is directed to.
            gas (int): Gas provided for the transaction execution. It will
                return unused gas.
            gasPrice (int): gasPrice used for each unit of gas paid.
            value (int): Value sent with this transaction.
            data (bin): The compiled code of a contract OR the hash of the
                invoked method signature and encoded parameters.
            nonce (int): This allows to overwrite your own pending transactions
                that use the same nonce.
        """

        if to == '' and data.isalnum():
            warnings.warn(
                'Verify that the data parameter is _not_ hex encoded, if this is the case '
                'the data will be double encoded and result in unexpected '
                'behavior.'
            )

        if to == '0' * 40:
            warnings.warn('For contract creation the empty string must be used.')

        if sender is None:
            raise ValueError('sender needs to be provided.')

        json_data = {
            'to': data_encoder(normalize_address(to, allow_blank=True)),
            'value': quantity_encoder(value),
            'gasPrice': quantity_encoder(gasPrice),
            'gas': quantity_encoder(gas),
            'data': data_encoder(data),
            'from': address_encoder(sender),
        }

        if nonce is not None:
            json_data['nonce'] = quantity_encoder(nonce)

        res = self.call('eth_sendTransaction', json_data)

        return data_decoder(res)
Example #6
0
 def to_dict(self):
     return {
         'type': self.__class__.__name__,
         'message_identifier': self.message_identifier,
         'payment_identifier': self.payment_identifier,
         'secret': data_encoder(self.secret),
         'nonce': self.nonce,
         'channel': address_encoder(self.channel),
         'transferred_amount': self.transferred_amount,
         'locked_amount': self.locked_amount,
         'locksroot': data_encoder(self.locksroot),
         'signature': data_encoder(self.signature),
     }
Example #7
0
def test_api_open_close_and_settle_channel(
    api_backend,
    token_addresses,
    reveal_timeout,
):
    # let's create a new channel
    partner_address = '0x61C808D82A3Ac53231750daDc13c777b59310bD9'
    token_address = token_addresses[0]
    settle_timeout = 1650
    channel_data_obj = {
        'partner_address': partner_address,
        'token_address': to_checksum_address(token_address),
        'settle_timeout': settle_timeout,
    }
    request = grequests.put(
        api_url_for(
            api_backend,
            'channelsresource',
        ),
        json=channel_data_obj,
    )
    response = request.send().response

    balance = 0
    assert_proper_response(response, status_code=HTTPStatus.CREATED)
    response = response.json()
    expected_response = channel_data_obj
    expected_response['balance'] = balance
    expected_response['state'] = CHANNEL_STATE_OPENED
    expected_response['reveal_timeout'] = reveal_timeout
    channel_identifier = data_encoder(
        calculate_channel_identifier(
            api_backend[1].raiden_api.raiden.address,
            to_canonical_address(partner_address),
        ))
    expected_response['channel_identifier'] = channel_identifier
    assert response == expected_response

    # let's close the channel
    request = grequests.patch(
        api_url_for(
            api_backend,
            'channelsresourcebytokenandpartneraddress',
            token_address=token_address,
            partner_address=partner_address,
        ),
        json={'state': CHANNEL_STATE_CLOSED},
    )
    response = request.send().response
    assert_proper_response(response)
    expected_response = {
        'channel_identifier': channel_identifier,
        'partner_address': partner_address,
        'token_address': to_checksum_address(token_address),
        'settle_timeout': settle_timeout,
        'reveal_timeout': reveal_timeout,
        'state': CHANNEL_STATE_CLOSED,
        'balance': balance,
    }
    assert response.json() == expected_response
Example #8
0
 def to_dict(self):
     return {
         'type': self.__class__.__name__,
         'sender': to_normalized_address(self.sender),
         'message_identifier': self.message_identifier,
         'signature': data_encoder(self.signature),
     }
Example #9
0
    def send_transaction(self,
                         sender: address,
                         to: address,
                         value: int = 0,
                         data: bytes = b'',
                         startgas: int = None,
                         nonce: int = None):
        """ Helper to send signed messages.

        This method will use the `privkey` provided in the constructor to
        locally sign the transaction. This requires an extended server
        implementation that accepts the variables v, r, and s.
        """

        if not self.privkey and not sender:
            raise ValueError('Either privkey or sender needs to be supplied.')

        if self.privkey:
            privkey_address = privatekey_to_address(self.privkey)
            sender = sender or privkey_address

            if sender != privkey_address:
                raise ValueError('sender for a different privkey.')

            if nonce is None:
                nonce = self.nonce(sender)
        else:
            if nonce is None:
                nonce = 0

        startgas = self.check_startgas(startgas)

        tx = Transaction(nonce,
                         self.gasprice(),
                         startgas,
                         to=to,
                         value=value,
                         data=data)

        if self.privkey:
            tx.sign(self.privkey)
            result = self.call(
                'eth_sendRawTransaction',
                data_encoder(rlp.encode(tx)),
            )
            return result[2 if result.startswith('0x') else 0:]

        else:

            # rename the fields to match the eth_sendTransaction signature
            tx_dict = tx.to_dict()
            tx_dict.pop('hash')
            tx_dict['sender'] = sender
            tx_dict['gasPrice'] = tx_dict.pop('gasprice')
            tx_dict['gas'] = tx_dict.pop('startgas')

            res = self.eth_sendTransaction(**tx_dict)

        assert len(res) in (20, 32)
        return hexlify(res)
Example #10
0
 def to_dict(self):
     return {
         'type': self.__class__.__name__,
         'amount': self.amount,
         'expiration': self.expiration,
         'secrethash': data_encoder(self.secrethash),
     }
Example #11
0
def format_data_for_call(sender: address = b'',
                         to: address = b'',
                         value: int = 0,
                         data: bytes = b'',
                         startgas: int = GAS_LIMIT,
                         gasprice: int = GAS_PRICE):
    """ Helper to format the transaction data. """

    return {
        'from': address_encoder(sender),
        'to': data_encoder(to),
        'value': quantity_encoder(value),
        'gasPrice': quantity_encoder(gasprice),
        'gas': quantity_encoder(startgas),
        'data': data_encoder(data)
    }
Example #12
0
    def _login_or_register(self):
        # password is signed server address
        password = data_encoder(self._sign(self._server_url.encode()))
        seed = int.from_bytes(self._sign(b'seed')[-32:], 'big')
        rand = Random()  # deterministic, random secret for username suffixes
        rand.seed(seed)
        # try login and register on first 5 possible accounts
        for i in range(5):
            base_username = to_normalized_address(self._raiden_service.address)
            username = base_username
            if i:
                username = f'{username}.{rand.randint(0, 0xffffffff):08x}'

            try:
                self._client.login_with_password(username, password)
                self.log.info(
                    'LOGIN',
                    homeserver=self._server_url,
                    username=username,
                )
                break
            except MatrixRequestError as ex:
                if ex.code != 403:
                    raise
                self.log.debug(
                    'Could not login. Trying register',
                    homeserver=self._server_url,
                    username=username,
                )
                try:
                    self._client.register_with_password(username, password)
                    self.log.info(
                        'REGISTER',
                        homeserver=self._server_url,
                        username=username,
                    )
                    break
                except MatrixRequestError as ex:
                    if ex.code != 400:
                        raise
                    self.log.debug('Username taken. Continuing')
                    continue
        else:
            raise ValueError('Could not register or login!')
        # TODO: persist access_token, to avoid generating a new login every time
        name = data_encoder(self._sign(self._client.user_id.encode()))
        self._client.get_user(self._client.user_id).set_display_name(name)
def format_data_for_call(
        sender: address = b'',
        to: address = b'',
        value: int = 0,
        data: bytes = b'',
        startgas: int = GAS_PRICE,
        gasprice: int = GAS_PRICE):
    """ Helper to format the transaction data. """

    return {
        'from': address_encoder(sender),
        'to': data_encoder(to),
        'value': quantity_encoder(value),
        'gasPrice': quantity_encoder(gasprice),
        'gas': quantity_encoder(startgas),
        'data': data_encoder(data)
    }
    def send_transaction(
            self,
            sender: address,
            to: address,
            value: int = 0,
            data: bytes = b'',
            startgas: int = 0,
            gasprice: int = GAS_PRICE,
            nonce: Optional[int] = None):
        """ Helper to send signed messages.

        This method will use the `privkey` provided in the constructor to
        locally sign the transaction. This requires an extended server
        implementation that accepts the variables v, r, and s.
        """

        if not self.privkey and not sender:
            raise ValueError('Either privkey or sender needs to be supplied.')

        if self.privkey:
            privkey_address = privatekey_to_address(self.privkey)
            sender = sender or privkey_address

            if sender != privkey_address:
                raise ValueError('sender for a different privkey.')

            if nonce is None:
                nonce = self.nonce(sender)
        else:
            if nonce is None:
                nonce = 0

        if not startgas:
            startgas = self.gaslimit() - 1

        tx = Transaction(nonce, gasprice, startgas, to=to, value=value, data=data)

        if self.privkey:
            tx.sign(self.privkey)
            result = self.call(
                'eth_sendRawTransaction',
                data_encoder(rlp.encode(tx)),
            )
            return result[2 if result.startswith('0x') else 0:]

        else:

            # rename the fields to match the eth_sendTransaction signature
            tx_dict = tx.to_dict()
            tx_dict.pop('hash')
            tx_dict['sender'] = sender
            tx_dict['gasPrice'] = tx_dict.pop('gasprice')
            tx_dict['gas'] = tx_dict.pop('startgas')

            res = self.eth_sendTransaction(**tx_dict)

        assert len(res) in (20, 32)
        return hexlify(res)
Example #15
0
    def poll(self, transaction_hash: bytes, confirmations: int = None):
        """ Wait until the `transaction_hash` is applied or rejected.

        Args:
            transaction_hash: Transaction hash that we are waiting for.
            confirmations: Number of block confirmations that we will
                wait for.
        """
        if transaction_hash.startswith(b'0x'):
            warnings.warn(
                'transaction_hash seems to be already encoded, this will'
                ' result in unexpected behavior',
            )

        if len(transaction_hash) != 32:
            raise ValueError(
                'transaction_hash length must be 32 (it might be hex encoded)',
            )

        transaction_hash = data_encoder(transaction_hash)

        # used to check if the transaction was removed, this could happen
        # if gas price is too low:
        #
        # > Transaction (acbca3d6) below gas price (tx=1 Wei ask=18
        # > Shannon). All sequential txs from this address(7d0eae79)
        # > will be ignored
        #
        last_result = None

        while True:
            # Could return None for a short period of time, until the
            # transaction is added to the pool
            transaction = self.web3.eth.getTransaction(transaction_hash)

            # if the transaction was added to the pool and then removed
            if transaction is None and last_result is not None:
                raise Exception('invalid transaction, check gas price')

            # the transaction was added to the pool and mined
            if transaction and transaction['blockNumber'] is not None:
                break

            last_result = transaction

            gevent.sleep(.5)

        if confirmations:
            # this will wait for both APPLIED and REVERTED transactions
            transaction_block = transaction['blockNumber']
            confirmation_block = transaction_block + confirmations

            block_number = self.block_number()

            while block_number < confirmation_block:
                gevent.sleep(.5)
                block_number = self.block_number()
Example #16
0
 def to_dict(self):
     return {
         'type': self.__class__.__name__,
         'message_identifier': self.message_identifier,
         'payment_identifier': self.payment_identifier,
         'nonce': self.nonce,
         'registry_address': address_encoder(self.registry_address),
         'token': address_encoder(self.token),
         'channel': address_encoder(self.channel),
         'transferred_amount': self.transferred_amount,
         'locked_amount': self.locked_amount,
         'recipient': address_encoder(self.recipient),
         'locksroot': data_encoder(self.locksroot),
         'lock': self.lock.to_dict(),
         'target': address_encoder(self.target),
         'initiator': address_encoder(self.initiator),
         'fee': self.fee,
         'signature': data_encoder(self.signature),
     }
Example #17
0
    def eth_getTransactionByHash(self, transaction_hash):
        """ Returns the information about a transaction requested by
        transaction hash.
        """

        if transaction_hash.startswith('0x'):
            warnings.warn(
                'transaction_hash seems to be already encoded, this will'
                ' result in unexpected behavior')

        if len(transaction_hash) != 32:
            raise ValueError(
                'transaction_hash length must be 32 (it might be hex encoded)')

        transaction_hash = data_encoder(transaction_hash)
        return self.call('eth_getTransactionByHash', transaction_hash)
Example #18
0
def check_transaction_threw(client, transaction_hash):
    """Check if the transaction threw/reverted or if it executed properly
       Returns None in case of success and the transaction receipt if the
       transaction's status indicator is 0x0.
    """
    encoded_transaction = data_encoder(unhexlify(transaction_hash))
    receipt = client.call('eth_getTransactionReceipt', encoded_transaction)

    if 'status' not in receipt:
        raise ValueError(
            'Transaction receipt does not contain a status field. Upgrade your client'
        )

    if receipt['status'] == '0x0':
        return receipt

    return None
def check_transaction_threw(client, transaction_hash):
    """Check if the transaction threw/reverted or if it executed properly
       Returns None in case of success and the transaction receipt if the
       transaction's status indicator is 0x0.
    """
    encoded_transaction = data_encoder(unhexlify(transaction_hash))
    receipt = client.call('eth_getTransactionReceipt', encoded_transaction)

    if 'status' not in receipt:
        raise ValueError(
            'Transaction receipt does not contain a status field. Upgrade your client'
        )

    if receipt['status'] == '0x0':
        return receipt

    return None
    def eth_getTransactionByHash(self, transaction_hash: bytes):
        """ Returns the information about a transaction requested by
        transaction hash.
        """

        if transaction_hash.startswith(b'0x'):
            warnings.warn(
                'transaction_hash seems to be already encoded, this will'
                ' result in unexpected behavior'
            )

        if len(transaction_hash) != 32:
            raise ValueError(
                'transaction_hash length must be 32 (it might be hex encoded)'
            )

        transaction_hash = data_encoder(transaction_hash)
        return self.call('eth_getTransactionByHash', transaction_hash)
Example #21
0
    def send_transaction(
        self,
        to: Address,
        value: int = 0,
        data: bytes = b'',
        startgas: int = None,
    ):
        """ Helper to send signed messages.

        This method will use the `privkey` provided in the constructor to
        locally sign the transaction. This requires an extended server
        implementation that accepts the variables v, r, and s.
        """

        if to == b'' and data.isalnum():
            warnings.warn(
                'Verify that the data parameter is _not_ hex encoded, if this is the case '
                'the data will be double encoded and result in unexpected '
                'behavior.')

        if to == b'0' * 40:
            warnings.warn(
                'For contract creation the empty string must be used.')

        nonce = self.nonce()
        startgas = self.check_startgas(startgas)

        tx = Transaction(
            nonce,
            self.gasprice(),
            startgas,
            to=to,
            value=value,
            data=data,
        )

        tx.sign(self.privkey)
        result = self.rpccall_with_retry(
            'eth_sendRawTransaction',
            data_encoder(rlp.encode(tx)),
        )
        return result[2 if result.startswith('0x') else 0:]
Example #22
0
    def eth_getTransactionReceipt(self, transaction_hash):
        """ Returns the receipt of a transaction by transaction hash.

        Args:
            transaction_hash: Hash of a transaction.

        Returns:
            A dict representing the transaction receipt object, or null when no
            receipt was found.
        """
        if transaction_hash.startswith('0x'):
            warnings.warn(
                'transaction_hash seems to be already encoded, this will'
                ' result in unexpected behavior')

        if len(transaction_hash) != 32:
            raise ValueError(
                'transaction_hash length must be 32 (it might be hex encoded)')

        transaction_hash = data_encoder(transaction_hash)
        return self.call('eth_getTransactionReceipt', transaction_hash)
    def eth_getTransactionReceipt(self, transaction_hash: bytes) -> Dict:
        """ Returns the receipt of a transaction by transaction hash.

        Args:
            transaction_hash: Hash of a transaction.

        Returns:
            A dict representing the transaction receipt object, or null when no
            receipt was found.
        """
        if transaction_hash.startswith(b'0x'):
            warnings.warn(
                'transaction_hash seems to be already encoded, this will'
                ' result in unexpected behavior'
            )

        if len(transaction_hash) != 32:
            raise ValueError(
                'transaction_hash length must be 32 (it might be hex encoded)'
            )

        transaction_hash = data_encoder(transaction_hash)
        return self.call('eth_getTransactionReceipt', transaction_hash)
Example #24
0
def test_api_deposit_limit(
    api_backend,
    token_addresses,
    reveal_timeout,
):
    # let's create a new channel and deposit exactly the limit amount
    first_partner_address = '0x61C808D82A3Ac53231750daDc13c777b59310bD9'
    token_address = token_addresses[0]
    settle_timeout = 1650
    balance_working = MAX_TOKENS_DEPLOY * (10**2)  # token has two digits
    channel_data_obj = {
        'partner_address': first_partner_address,
        'token_address': to_checksum_address(token_address),
        'settle_timeout': settle_timeout,
        'reveal_timeout': reveal_timeout,
        'balance': balance_working,
    }

    request = grequests.put(
        api_url_for(
            api_backend,
            'channelsresource',
        ),
        json=channel_data_obj,
    )
    response = request.send().response

    assert_proper_response(response, HTTPStatus.CREATED)
    response = response.json()
    expected_response = channel_data_obj
    expected_response['balance'] = balance_working
    expected_response['state'] = CHANNEL_STATE_OPENED
    first_channel_identifier = data_encoder(
        calculate_channel_identifier(
            api_backend[1].raiden_api.raiden.address,
            to_canonical_address(first_partner_address),
        ))
    expected_response['channel_identifier'] = first_channel_identifier
    assert response == expected_response

    # now let's open a channel and deposit a bit more than the limit
    second_partner_address = '0x29FA6cf0Cce24582a9B20DB94Be4B6E017896038'
    balance_failing = balance_working + 1  # token has two digits
    channel_data_obj = {
        'partner_address': second_partner_address,
        'token_address': to_checksum_address(token_address),
        'settle_timeout': settle_timeout,
        'reveal_timeout': reveal_timeout,
        'balance': balance_failing,
    }
    request = grequests.put(
        api_url_for(
            api_backend,
            'channelsresource',
        ),
        json=channel_data_obj,
    )
    response = request.send().response

    assert_proper_response(response, HTTPStatus.EXPECTATION_FAILED)
    response = response.json()
    assert response[
        'errors'] == 'The deposit of 10001 is bigger than the current limit of 10000'
 def _serialize(self, value, attr, obj):
     return data_encoder(value)
Example #26
0
def test_api_open_and_deposit_channel(
    api_backend,
    token_addresses,
    reveal_timeout,
):
    # let's create a new channel
    first_partner_address = '0x61C808D82A3Ac53231750daDc13c777b59310bD9'
    token_address = token_addresses[0]
    settle_timeout = 1650
    channel_data_obj = {
        'partner_address': first_partner_address,
        'token_address': to_checksum_address(token_address),
        'settle_timeout': settle_timeout,
        'reveal_timeout': reveal_timeout,
    }

    request = grequests.put(
        api_url_for(
            api_backend,
            'channelsresource',
        ),
        json=channel_data_obj,
    )
    response = request.send().response

    assert_proper_response(response, HTTPStatus.CREATED)
    response = response.json()
    expected_response = channel_data_obj
    expected_response['balance'] = 0
    expected_response['state'] = CHANNEL_STATE_OPENED
    first_channel_identifier = data_encoder(
        calculate_channel_identifier(
            api_backend[1].raiden_api.raiden.address,
            to_canonical_address(first_partner_address),
        ))
    expected_response['channel_identifier'] = first_channel_identifier
    assert response == expected_response

    # now let's open a channel and make a deposit too
    second_partner_address = '0x29FA6cf0Cce24582a9B20DB94Be4B6E017896038'
    balance = 100
    channel_data_obj = {
        'partner_address': second_partner_address,
        'token_address': to_checksum_address(token_address),
        'settle_timeout': settle_timeout,
        'reveal_timeout': reveal_timeout,
        'balance': balance,
    }
    request = grequests.put(
        api_url_for(
            api_backend,
            'channelsresource',
        ),
        json=channel_data_obj,
    )
    response = request.send().response

    assert_proper_response(response, HTTPStatus.CREATED)
    response = response.json()
    expected_response = channel_data_obj
    expected_response['balance'] = balance
    expected_response['state'] = CHANNEL_STATE_OPENED
    second_channel_identifier = data_encoder(
        calculate_channel_identifier(
            api_backend[1].raiden_api.raiden.address,
            to_canonical_address(second_partner_address),
        ))
    expected_response['channel_identifier'] = second_channel_identifier
    assert response == expected_response

    # let's deposit on the first channel
    request = grequests.patch(
        api_url_for(
            api_backend,
            'channelsresourcebytokenandpartneraddress',
            token_address=token_address,
            partner_address=first_partner_address,
        ),
        json={'total_deposit': balance},
    )
    response = request.send().response
    assert_proper_response(response)
    response = response.json()
    expected_response = {
        'channel_identifier': first_channel_identifier,
        'partner_address': first_partner_address,
        'token_address': to_checksum_address(token_address),
        'settle_timeout': settle_timeout,
        'reveal_timeout': reveal_timeout,
        'state': CHANNEL_STATE_OPENED,
        'balance': balance,
    }
    assert response == expected_response

    # finally let's try querying for the second channel
    request = grequests.get(
        api_url_for(
            api_backend,
            'channelsresourcebytokenandpartneraddress',
            token_address=token_address,
            partner_address=second_partner_address,
        ), )

    response = request.send().response
    assert_proper_response(response)
    response = response.json()
    expected_response = {
        'channel_identifier': second_channel_identifier,
        'partner_address': second_partner_address,
        'token_address': to_checksum_address(token_address),
        'settle_timeout': settle_timeout,
        'reveal_timeout': reveal_timeout,
        'state': CHANNEL_STATE_OPENED,
        'balance': balance,
    }
    assert response == expected_response
Example #27
0
    def poll(self, transaction_hash, confirmations=None, timeout=None):
        """ Wait until the `transaction_hash` is applied or rejected.
        If timeout is None, this could wait indefinitely!

        Args:
            transaction_hash (hash): Transaction hash that we are waiting for.
            confirmations (int): Number of block confirmations that we will
                wait for.
            timeout (float): Timeout in seconds, raise an Excpetion on
                timeout.
        """
        if transaction_hash.startswith('0x'):
            warnings.warn(
                'transaction_hash seems to be already encoded, this will'
                ' result in unexpected behavior')

        if len(transaction_hash) != 32:
            raise ValueError(
                'transaction_hash length must be 32 (it might be hex encoded)')

        transaction_hash = data_encoder(transaction_hash)

        deadline = None
        if timeout:
            deadline = gevent.Timeout(timeout)
            deadline.start()

        try:
            # used to check if the transaction was removed, this could happen
            # if gas price is too low:
            #
            # > Transaction (acbca3d6) below gas price (tx=1 Wei ask=18
            # > Shannon). All sequential txs from this address(7d0eae79)
            # > will be ignored
            #
            last_result = None

            while True:
                # Could return None for a short period of time, until the
                # transaction is added to the pool
                transaction = self.call('eth_getTransactionByHash',
                                        transaction_hash)

                # if the transaction was added to the pool and then removed
                if transaction is None and last_result is not None:
                    raise Exception('invalid transaction, check gas price')

                # the transaction was added to the pool and mined
                if transaction and transaction['blockNumber'] is not None:
                    break

                last_result = transaction

                gevent.sleep(.5)

            if confirmations:
                # this will wait for both APPLIED and REVERTED transactions
                transaction_block = quantity_decoder(
                    transaction['blockNumber'])
                confirmation_block = transaction_block + confirmations

                block_number = self.blocknumber()

                while block_number < confirmation_block:
                    gevent.sleep(.5)
                    block_number = self.blocknumber()

        except gevent.Timeout:
            raise Exception('timeout when polling for transaction')

        finally:
            if deadline:
                deadline.cancel()
    def poll(
            self,
            transaction_hash: bytes,
            confirmations: Optional[int] = None,
            timeout: Optional[float] = None):
        """ Wait until the `transaction_hash` is applied or rejected.
        If timeout is None, this could wait indefinitely!

        Args:
            transaction_hash: Transaction hash that we are waiting for.
            confirmations: Number of block confirmations that we will
                wait for.
            timeout: Timeout in seconds, raise an Excpetion on timeout.
        """
        if transaction_hash.startswith(b'0x'):
            warnings.warn(
                'transaction_hash seems to be already encoded, this will'
                ' result in unexpected behavior'
            )

        if len(transaction_hash) != 32:
            raise ValueError(
                'transaction_hash length must be 32 (it might be hex encoded)'
            )

        transaction_hash = data_encoder(transaction_hash)

        deadline = None
        if timeout:
            deadline = gevent.Timeout(timeout)
            deadline.start()

        try:
            # used to check if the transaction was removed, this could happen
            # if gas price is too low:
            #
            # > Transaction (acbca3d6) below gas price (tx=1 Wei ask=18
            # > Shannon). All sequential txs from this address(7d0eae79)
            # > will be ignored
            #
            last_result = None

            while True:
                # Could return None for a short period of time, until the
                # transaction is added to the pool
                transaction = self.call('eth_getTransactionByHash', transaction_hash)

                # if the transaction was added to the pool and then removed
                if transaction is None and last_result is not None:
                    raise Exception('invalid transaction, check gas price')

                # the transaction was added to the pool and mined
                if transaction and transaction['blockNumber'] is not None:
                    break

                last_result = transaction

                gevent.sleep(.5)

            if confirmations:
                # this will wait for both APPLIED and REVERTED transactions
                transaction_block = quantity_decoder(transaction['blockNumber'])
                confirmation_block = transaction_block + confirmations

                block_number = self.block_number()

                while block_number < confirmation_block:
                    gevent.sleep(.5)
                    block_number = self.block_number()

        except gevent.Timeout:
            raise Exception('timeout when polling for transaction')

        finally:
            if deadline:
                deadline.cancel()
Example #29
0
 def _serialize(value, attr, obj):  # pylint: disable=unused-argument
     return data_encoder(value)
Example #30
0
 def to_dict(self):
     return {
         'type': self.__class__.__name__,
         'delivered_message_identifier': self.delivered_message_identifier,
         'signature': data_encoder(self.signature)
     }
Example #31
0
 def _serialize(self, value, attr, obj):
     return data_encoder(value)
Example #32
0
 def _serialize(self, value, attr, obj):  # pylint: disable=no-self-use
     return data_encoder(value)