Ejemplo n.º 1
0
    def signHash(self, message_hash, private_key):
        '''
        Sign the hash provided.

        .. WARNING:: *Never* sign a hash that you didn't generate,
            it can be an arbitrary transaction. For example, it might
            send all of your account's ether to an attacker.

        If you would like compatibility with
        :meth:`w3.eth.sign() <web3.eth.Eth.sign>`
        you can use :meth:`~eth_account.messages.defunct_hash_message`.

        Several other message standards are proposed, but none have a clear
        consensus. You'll need to manually comply with any of those message standards manually.

        :param message_hash: the 32-byte message hash to be signed
        :type message_hash: hex str, bytes or int
        :param private_key: the key to sign the message with
        :type private_key: hex str, bytes or int
        :returns: Various details about the signature - most
          importantly the fields: v, r, and s
        :rtype: ~eth_account.datastructures.AttributeDict

        .. code-block:: python

            >>> msg = "I♥SF"
            >>> from eth_account.messages import defunct_hash_message
            >>> msghash = defunct_hash_message(text=msg)
            HexBytes('0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750')
            >>> key = "0xb25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364"
            >>> Account.signHash(msghash, key)
            {'messageHash': HexBytes('0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750'),  # noqa: E501
             'r': 104389933075820307925104709181714897380569894203213074526835978196648170704563,
             's': 28205917190874851400050446352651915501321657673772411533993420917949420456142,
             'signature': HexBytes('0xe6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb33e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce1c'),  # noqa: E501
             'v': 28}

            # these are equivalent:
            >>> Account.signHash(
                0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750,
                key
            )
            >>> Account.signHash(
                "0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750",
                key
            )
        '''
        msg_hash_bytes = HexBytes(message_hash)
        if len(msg_hash_bytes) != 32:
            raise ValueError("The message hash must be exactly 32-bytes")
        key_bytes = HexBytes(private_key)
        key = self._keys.PrivateKey(key_bytes)
        (v, r, s, eth_signature_bytes) = sign_message_hash(key, msg_hash_bytes)
        return AttributeDict({
            'messageHash': msg_hash_bytes,
            'r': r,
            's': s,
            'v': v,
            'signature': HexBytes(eth_signature_bytes),
        })
Ejemplo n.º 2
0
 def get_account(self, key_name):
     return AttributeDict({
         'address':
         ADDRESS,
         'public_key':
         'ab00000000000000000000000000000000000000',
     })
Ejemplo n.º 3
0
def sign_transaction(account, transaction_dict):
    if not isinstance(transaction_dict, Mapping):
        raise TypeError("transaction_dict must be dict-like, got %r" %
                        transaction_dict)

    # allow from field, *only* if it matches the private key
    if 'from' in transaction_dict:
        if transaction_dict['from'] == account.address:
            sanitized_transaction = dissoc(transaction_dict, 'from')
        else:
            raise TypeError("from field must match key's %s, but it was %s" % (
                account.address,
                transaction_dict['from'],
            ))
    else:
        sanitized_transaction = transaction_dict

    # sign transaction
    (
        v,
        r,
        s,
        rlp_encoded,
    ) = sign_transaction_dict(account._key_obj, sanitized_transaction)

    transaction_hash = keccak(rlp_encoded)

    return AttributeDict({
        'rawTransaction': HexBytes(rlp_encoded),
        'hash': HexBytes(transaction_hash),
        'r': r,
        's': s,
        'v': v,
    })
Ejemplo n.º 4
0
    def signTransaction(self, transaction_dict, private_key):
        '''
        Sign a transaction using a local private key. Produces signature details
        and the hex-encoded transaction suitable for broadcast using
        :meth:`w3.eth.sendRawTransaction() <web3.eth.Eth.sendRawTransaction>`.

        Create the transaction dict for a contract method with
        `my_contract.functions.my_function().buildTransaction()
        <http://web3py.readthedocs.io/en/latest/contracts.html#methods>`_

        :param dict transaction_dict: the transaction with keys:
          nonce, chainId, to, data, value, gas, and gasPrice.
        :param private_key: the private key to sign the data with
        :type private_key: hex str, bytes or int
        :returns: Various details about the signature - most
          importantly the fields: v, r, and s
        :rtype: AttributeDict

        .. code-block:: python

            >>> transaction = {
                    'to': '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
                    'value': 1000000000,
                    'gas': 2000000,
                    'gasPrice': 234567897654321,
                    'nonce': 0,
                    'chainId': 1
                }
            >>> key = '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318'
            >>> signed = Account.signTransaction(transaction, key)
            {'hash': HexBytes('0x6893a6ee8df79b0f5d64a180cd1ef35d030f3e296a5361cf04d02ce720d32ec5'),
             'r': 4487286261793418179817841024889747115779324305375823110249149479905075174044,
             'rawTransaction': HexBytes('0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428'),  # noqa: E501
             's': 30785525769477805655994251009256770582792548537338581640010273753578382951464,
             'v': 37}
            >>> w3.eth.sendRawTransaction(signed.rawTransaction)
        '''
        if not isinstance(transaction_dict, Mapping):
            raise TypeError("transaction_dict must be dict-like, got %r" %
                            transaction_dict)

        account = self.privateKeyToAccount(private_key)

        # sign transaction
        (
            v,
            r,
            s,
            rlp_encoded,
        ) = sign_transaction_dict(account._key_obj, transaction_dict)

        transaction_hash = keccak(rlp_encoded)

        return AttributeDict({
            'rawTransaction': HexBytes(rlp_encoded),
            'hash': HexBytes(transaction_hash),
            'r': r,
            's': s,
            'v': v,
        })
Ejemplo n.º 5
0
 def sign(self, transaction_dict, key_name):
     return AttributeDict({
         'rawTransaction': HexBytes('0x000000000000'),
         'hash': HexBytes('0x000000000000'),
         'r': 100000000000,
         's': 100000000000,
         'v': 37,
     })
Ejemplo n.º 6
0
 def get_account(self, key_name):
     key = self.sgx_server.get_public_key(key_name)
     key = add_0x_prefix(key)
     address = public_key_to_address(key)
     return AttributeDict({
         'address': address,
         'public_key': key,
     })
Ejemplo n.º 7
0
 def generate_key(self):
     return AttributeDict({
         'name':
         'NEK:aaabbb',
         'address':
         ADDRESS,
         'public_key':
         'ab00000000000000000000000000000000000000',
     })
Ejemplo n.º 8
0
    def sign(self, message=None, private_key=None, message_hexstr=None, message_text=None):
        '''
        Sign the message provided. This is equivalent to
        :meth:`w3.eth.sign() <web3.eth.Eth.sign>`
        but with a local private key instead of an account in a connected client.

        Caller must supply exactly one of the message types:
        in bytes, a hex string, or a unicode string. The message will automatically
        be prepended with the text indicating that it is a message (preventing it
        from being used to sign a transaction). The prefix is:
        ``b'\\x19Ethereum Signed Message:\\n'``
        concatenated with the number of bytes in the message.

        :param message: the message message to be signed
        :type message: bytes or int
        :param private_key: the key to sign the message with
        :type private_key: hex str, bytes or int
        :param str message_hexstr: the message encoded as hex
        :param str message_text: the message as a series of unicode characters (a normal Py3 str)
        :returns: Various details about the signature - most
          importantly the fields: v, r, and s
        :rtype: ~eth_account.datastructures.AttributeDict

        .. code-block:: python

            >>> msg = "I♥SF"
            >>> key = "0xb25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364"
            >>> Account.sign(message_text=msg, private_key=key)
            {'message': b'I\\xe2\\x99\\xa5SF',
             'messageHash': HexBytes('0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750'),  # noqa: E501
             'r': 104389933075820307925104709181714897380569894203213074526835978196648170704563,
             's': 28205917190874851400050446352651915501321657673772411533993420917949420456142,
             'signature': HexBytes('0xe6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb33e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce1c'),  # noqa: E501
             'v': 28}

            # these are all equivalent:
            >>> Account.sign(w3.toBytes(text=msg), key)
            >>> Account.sign(bytes(msg, encoding='utf-8'), key)

            >>> Web3.toHex(text=msg)
            '0x49e299a55346'
            >>> Account.sign(message_hexstr='0x49e299a55346', private_key=key)
            >>> Account.sign(0x49e299a55346, key)
        '''
        msg_bytes = to_bytes(message, hexstr=message_hexstr, text=message_text)
        msg_hash = self.hashMessage(msg_bytes)
        key_bytes = HexBytes(private_key)
        key = self._keys.PrivateKey(key_bytes)
        (v, r, s, eth_signature_bytes) = sign_message_hash(key, msg_hash)
        return AttributeDict({
            'message': HexBytes(msg_bytes),
            'messageHash': msg_hash,
            'r': r,
            's': s,
            'v': v,
            'signature': HexBytes(eth_signature_bytes),
        })
Ejemplo n.º 9
0
 def generate_key(self):
     key_name, public_key = self.sgx_server.generate_key()
     public_key = add_0x_prefix(public_key)
     address = public_key_to_address(public_key)
     return AttributeDict({
         'name': key_name,
         'address': address,
         'public_key': public_key,
     })
Ejemplo n.º 10
0
 def complaint_response(self, poly_name, idx):
     share, dh_key, verification_vector_mult = self.sgx_server.complaint_response(
         poly_name, self.n, self.t, idx)
     return AttributeDict({
         'share':
         share,
         'dh_key':
         dh_key,
         'verification_vector_mult':
         verification_vector_mult
     })
Ejemplo n.º 11
0
    def signed_tx(cls, sutx, v, r, s):
        enctx = encode_transaction(sutx, (v, r, s))
        transaction_hash = keccak(enctx)

        attr_dict = AttributeDict({
            'rawTransaction': HexBytes(enctx),
            'hash': HexBytes(transaction_hash),
            'r': r,
            's': s,
            'v': v,
        })

        return attr_dict
Ejemplo n.º 12
0
    def test_validate_ethereum_transaction(self):
        seller = EthereumCrypto()
        client = EthereumCrypto()
        ledger_apis = LedgerApis(
            {ETHEREUM: DEFAULT_ETHEREUM_CONFIG, FETCHAI: DEFAULT_FETCHAI_CONFIG},
            FETCHAI,
        )
        tx_nonce = ledger_apis.generate_tx_nonce(
            ETHEREUM, seller.address, client.address
        )

        tx_digest = "0xbefa7768c313ff49bf274eefed001042a0ff9e3cfbe75ff1a9c2baf18001cec4"
        result = AttributeDict(
            {
                "blockHash": HexBytes(
                    "0x0bfc237d2a17f719a3300a4822779391ec6e3a74832fe1b05b8c477902b0b59e"
                ),
                "blockNumber": 7161932,
                "from": client.address,
                "gas": 200000,
                "gasPrice": 50000000000,
                "hash": HexBytes(
                    "0xbefa7768c313ff49bf274eefed001042a0ff9e3cfbe75ff1a9c2baf18001cec4"
                ),
                "input": tx_nonce,
                "nonce": 4,
                "r": HexBytes(
                    "0xb54ce8b9fa1d1be7be316c068af59a125d511e8dd51202b1a7e3002dee432b52"
                ),
                "s": HexBytes(
                    "0x4f44702b3812d3b4e4b76da0fd5b554b3ae76d1717db5b6b5faebd7b85ae0303"
                ),
                "to": seller.address,
                "transactionIndex": 0,
                "v": 42,
                "value": 2,
            }
        )
        with mock.patch.object(
            ledger_apis.apis.get(ETHEREUM).api.eth,
            "getTransaction",
            return_value=result,
        ):
            assert ledger_apis.is_tx_valid(
                identifier=ETHEREUM,
                tx_digest=tx_digest,
                seller=seller.address,
                client=client.address,
                tx_nonce=tx_nonce,
                amount=2,
            )
Ejemplo n.º 13
0
    def sign_hash(self, message, key_name, chain_id):
        msg_hash_bytes = HexBytes(message)
        if len(msg_hash_bytes) != 32:
            raise ValueError("The message hash must be exactly 32-bytes")

        (v, r, s) = self._sign_hash(key_name, msg_hash_bytes, chain_id)
        signature_bytes = signing.to_bytes32(r) + signing.to_bytes32(
            s) + signing.to_bytes(v)
        return AttributeDict({
            'messageHash': msg_hash_bytes,
            'r': r,
            's': s,
            'v': v,
            'signature': HexBytes(signature_bytes),
        })
Ejemplo n.º 14
0
    def _sign_hash(self, message_hash, private_key):
        msg_hash_bytes = HexBytes(message_hash)
        if len(msg_hash_bytes) != 32:
            raise ValueError("The message hash must be exactly 32-bytes")

        key = self._parsePrivateKey(private_key)

        (v, r, s, eth_signature_bytes) = sign_message_hash(key, msg_hash_bytes)
        return AttributeDict({
            'messageHash': msg_hash_bytes,
            'r': r,
            's': s,
            'v': v,
            'signature': HexBytes(eth_signature_bytes),
        })
Ejemplo n.º 15
0
    def parse_sign_result(cls, tx, exchange_result):
        sign_v = exchange_result[0]
        sign_r = int((exchange_result[1:1 + 32]).hex(), 16)
        sign_s = int((exchange_result[1 + 32:1 + 32 + 32]).hex(), 16)
        enctx = encode_transaction(tx, (sign_v, sign_r, sign_s))
        transaction_hash = keccak(enctx)

        signed_txn = AttributeDict({
            'rawTransaction': HexBytes(enctx),
            'hash': HexBytes(transaction_hash),
            'v': sign_v,
            'r': sign_r,
            's': sign_s,
        })
        return signed_txn
Ejemplo n.º 16
0
    def default_address(self, address: str) -> None:
        """Sets the address used with all Tron API.
        Will not sign any transactions.

        Args:
             address (str) Tron Address

        """

        if not self.isAddress(address):
            raise InvalidTronError('Invalid address provided')

        _hex = self.address.to_hex(address)
        _base58 = self.address.from_hex(address)
        _private_base58 = self.address.from_private_key(
            self._private_key).base58

        # check the addresses
        if self._private_key and _private_base58 != _base58:
            self._private_key = None

        self._default_address = AttributeDict({'hex': _hex, 'base58': _base58})
Ejemplo n.º 17
0
    def address(self):
        public_key = self._key.public_key
        address = '41' + public_key.to_address()[2:]
        to_base58 = base58.b58encode_check(bytes.fromhex(address))

        return AttributeDict({'hex': address, 'base58': to_base58.decode()})
Ejemplo n.º 18
0
class Tron:
    # Providers
    HTTPProvider = HttpProvider

    _default_block = None
    _private_key = None
    _default_address = AttributeDict({})

    # Encoding and Decoding
    toBytes = staticmethod(to_bytes)
    toInt = staticmethod(to_int)
    toHex = staticmethod(to_hex)
    toText = staticmethod(to_text)
    toJSON = staticmethod(to_json)

    # Currency Utility
    toSun = staticmethod(to_sun)
    fromSun = staticmethod(from_sun)

    # Validate address
    isAddress = staticmethod(is_address)

    def __init__(self, **kwargs):
        """Connect to the Tron network.

        Args:
            kwargs (Any): We fill the most necessary parameters
            for working with blockchain Tron

        """

        # We check the obtained nodes, if the necessary parameters
        # are not specified, then we take the default
        kwargs.setdefault('full_node', constants.DEFAULT_NODES['full_node'])
        kwargs.setdefault('solidity_node',
                          constants.DEFAULT_NODES['solidity_node'])
        kwargs.setdefault('event_server',
                          constants.DEFAULT_NODES['event_server'])

        # The node manager allows you to automatically determine the node
        # on the router or manually refer to a specific node.
        # solidity_node, full_node or event_server
        self.manager = TronManager(
            self,
            dict(full_node=kwargs.get('full_node'),
                 solidity_node=kwargs.get('solidity_node'),
                 event_server=kwargs.get('event_server')))

        # If the parameter of the private key is not empty,
        # then write to the variable
        if 'private_key' in kwargs:
            self.private_key = kwargs.get('private_key')

        # We check whether the default wallet address is set when
        # defining the class, and then written to the variable
        if 'default_address' in kwargs:
            self.default_address = kwargs.get('default_address')

        # If custom methods are not declared,
        # we take the default from the list
        modules = kwargs.setdefault('modules', DEFAULT_MODULES)
        for module_name, module_class in modules.items():
            module_class.attach(self, module_name)

        self.transaction_builder = TransactionBuilder(self)

    @property
    def default_block(self):
        return self._default_block

    @default_block.setter
    def default_block(self, block_id):
        """Sets the default block used as a reference for all future calls."""
        if block_id in ('latest', 'earliest', 0):
            self._default_block = block_id
            return

        if not is_integer(block_id) or not block_id:
            raise ValueError('Invalid block ID provided')

        self._default_block = abs(block_id)

    @property
    def providers(self):
        """List providers"""
        return self.manager.providers

    @property
    def private_key(self):
        """Get a private key"""
        return self._private_key

    @private_key.setter
    def private_key(self, value: str) -> None:
        """Set a private key used with the TronAPI instance,
        used for obtaining the address, signing transactions etc...

        Args:
            value (str): Private key
        """
        try:
            private_key = PrivateKey(value)
        except ValueError:
            raise TronError('Invalid private key provided')

        self._private_key = str(private_key).lower()

    @property
    def default_address(self) -> AttributeDict:
        """Get a TRON Address"""
        return self._default_address

    @default_address.setter
    def default_address(self, address: str) -> None:
        """Sets the address used with all Tron API.
        Will not sign any transactions.

        Args:
             address (str) Tron Address

        """

        if not self.isAddress(address):
            raise InvalidTronError('Invalid address provided')

        _hex = self.address.to_hex(address)
        _base58 = self.address.from_hex(address)
        _private_base58 = self.address.from_private_key(
            self._private_key).base58

        # check the addresses
        if self._private_key and _private_base58 != _base58:
            self._private_key = None

        self._default_address = AttributeDict({'hex': _hex, 'base58': _base58})

    def get_event_result(self, **kwargs):
        """Will return all events matching the filters.

        Args:
            kwargs (any): List parameters
        """

        # Check the most necessary parameters
        since_timestamp = kwargs.setdefault('since_timestamp', 0)
        event_name = kwargs.setdefault('event_name', 'Notify')
        block_number = kwargs.setdefault('block_number', '')
        size = kwargs.setdefault('size', 20)
        page = kwargs.setdefault('page', 1)
        only_confirmed = kwargs.setdefault('only_confirmed', None)
        only_unconfirmed = kwargs.setdefault('only_unconfirmed', None)
        previous_last = kwargs.setdefault('previous_last_event_fingerprint',
                                          None)
        contract_address = kwargs.setdefault('contract_address',
                                             self.default_address.hex)

        if not self.isAddress(contract_address):
            raise InvalidTronError('Invalid contract address provided')

        if event_name and not contract_address:
            raise TronError(
                'Usage of event name filtering requires a contract address')

        if block_number and event_name is None:
            raise TronError(
                'Usage of block number filtering requires an event name')

        if not is_integer(page):
            raise ValueError('Invalid size provided')

        if not is_integer(since_timestamp):
            raise ValueError('Invalid sinceTimestamp provided')

        # If the size exceeds 200, displays an error
        if size > 200:
            raise ValueError('Defaulting to maximum accepted size: 200')

        # We collect all parameters in one array
        route_params = []
        if contract_address:
            route_params.append(contract_address)
        if event_name:
            route_params.append(event_name)
        if block_number:
            route_params.append(block_number)

        route = '/'.join(route_params)

        qs = {'since': since_timestamp, 'page': page, 'size': size}

        if only_confirmed is not None:
            qs.update({'onlyConfirmed': only_confirmed})

        if only_unconfirmed is not None and not only_confirmed:
            qs.update({'onlyUnconfirmed': only_unconfirmed})

        if previous_last is not None:
            qs.update({'previousLastEventFingerprint': previous_last})

        return self.manager.request("/event/contract/{0}?{1}".format(
            route, urlencode(qs)),
                                    method='get')

    def get_event_transaction_id(self, tx_id):
        """Will return all events within a transactionID.

        Args:
            tx_id (str): TransactionID to query for events.
        """
        response = self.manager.request('/event/transaction/' + tx_id,
                                        method='get')
        return response

    @property
    def address(self) -> Address:
        """Helper object that allows you to convert
        between hex/base58 and private key representations of a TRON address.

        Note:
            If you wish to convert generic data to hexadecimal strings,
            please use the function tron.to_hex.

        """
        return Address()

    @property
    def create_account(self) -> PrivateKey:
        """Create account

        Warning: Please control risks when using this API.
        To ensure environmental security, please do not invoke APIs
        provided by other or invoke this very API on a public network.

        """
        return Account.create()

    @staticmethod
    def is_valid_provider(provider) -> bool:
        """Check connected provider

        Args:
            provider(HttpProvider): Provider
        """
        return isinstance(provider, HttpProvider)

    def solidity_sha3(self, abi_types, values):
        """
            Executes keccak256 exactly as Solidity does.
            Takes list of abi_types as inputs -- `[uint24, int8[], bool]`
            and list of corresponding values  -- `[20, [-1, 5, 0], True]`

            Args:
                abi_types (any): types abi
                values (any): values

            Examples:
                >>> tron = Tron()
                >>> sol = tron.solidity_sha3(['uint8[]'], [[1, 2, 3, 4, 5]])
                >>> assert sol.hex() == '0x5917e5a395fb9b454434de59651d36822a9e29c5ec57474df3e67937b969460c'

        """
        if len(abi_types) != len(values):
            raise ValueError(
                "Length mismatch between provided abi types and values.  Got "
                "{0} types and {1} values.".format(len(abi_types),
                                                   len(values)))

        normalized_values = map_abi_data([abi_resolver()], abi_types, values)

        hex_string = add_0x_prefix(''.join(
            remove_0x_prefix(hex_encode_abi_type(abi_type, value))
            for abi_type, value in zip(abi_types, normalized_values)))
        return self.keccak(hexstr=hex_string)

    @staticmethod
    @apply_to_return_value(HexBytes)
    def keccak(primitive=None, text=None, hexstr=None):
        if isinstance(primitive, (bytes, int, type(None))):
            input_bytes = to_bytes(primitive, hexstr=hexstr, text=text)
            return tron_keccak(input_bytes)

        raise TypeError(
            "You called keccak with first arg %r and keywords %r. You must call it with one of "
            "these approaches: keccak(text='txt'), keccak(hexstr='0x747874'), "
            "keccak(b'\\x74\\x78\\x74'), or keccak(0x747874)." %
            (primitive, {
                'text': text,
                'hexstr': hexstr
            }))

    def is_connected(self):
        """List of available providers"""
        return self.manager.is_connected()
Ejemplo n.º 19
0
 def complaint_response(self, poly_name, idx):
     share, dh_key = self.sgx_server.complaint_response(poly_name, self.n, self.t, idx)
     return AttributeDict({'share': share, 'dh_key': dh_key})
Ejemplo n.º 20
0
    def signBlock(self,
                  header_dict: dict,
                  private_key: str,
                  send_transaction_dicts: List[dict] = [],
                  receive_transaction_dicts: List[dict] = []) -> AttributeDict:
        '''

        transaction = {
                    # Note that the address must be in checksum format:
                    'to': '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
                    'value': 1000000000,
                    'gas': 2000000,
                    'gasPrice': 234567897654321,
                    'nonce': 0,
                    'chainId': 1
                }

         receive_transaction = {
                'senderBlockHash',
                'sendTransactionHash',
                'isRefund',
                'remainingRefund'
            }

        header = {
                'parentHash',
                'blockNumber',
                'extraData',
            }

        :param send_transaction_dicts:
        :param receive_transaction_dicts:
        :param reward_bundle:
        :param private_key:
        :return:
        '''

        timestamp = int(time.time())

        if not is_bytes(header_dict['parentHash']):
            header_dict['parentHash'] = to_bytes(
                hexstr=header_dict['parentHash'])

        if "extraData" in header_dict:
            if not is_bytes(header_dict['extraData']):
                extra_data = to_bytes(hexstr=header_dict['extraData'])
            else:
                extra_data = header_dict['extraData']
        else:
            extra_data = b''

        if "chainId" in header_dict:
            chain_id = header_dict['chainId']
        else:
            if len(send_transaction_dicts) > 0:
                if 'chainId' in send_transaction_dicts[0]:
                    chain_id = send_transaction_dicts[0]['chainId']
                else:
                    chain_id = 1
            else:
                chain_id = 1

        photon_timestamp = get_photon_timestamp(chain_id)
        if timestamp < photon_timestamp:
            fork_id = 0
        else:
            fork_id = 1

        account = self.privateKeyToAccount(private_key)

        send_transactions = []
        for transaction_dict in send_transaction_dicts:
            if 'data' in transaction_dict:
                if not is_bytes(transaction_dict['data']):
                    data = to_bytes(hexstr=transaction_dict['data'])
                else:
                    data = transaction_dict['data']
            else:
                data = b''

            if not is_bytes(transaction_dict['to']):
                to = to_bytes(hexstr=transaction_dict['to'])
            else:
                to = transaction_dict['to']

            if fork_id == 0:
                tx = BosonTransaction(nonce=transaction_dict['nonce'],
                                      gas_price=transaction_dict['gasPrice'],
                                      gas=transaction_dict['gas'],
                                      to=to,
                                      value=transaction_dict['value'],
                                      data=data,
                                      v=0,
                                      r=0,
                                      s=0)
                signed_tx = tx.get_signed(account._key_obj, chain_id)
            elif fork_id == 1:
                if 'codeAddress' in transaction_dict:
                    if not is_bytes(transaction_dict['codeAddress']):
                        code_address = to_bytes(
                            hexstr=transaction_dict['codeAddress'])
                    else:
                        code_address = transaction_dict['codeAddress']
                else:
                    code_address = b''

                if 'executeOnSend' in transaction_dict:
                    execute_on_send = bool(transaction_dict['executeOnSend'])
                else:
                    execute_on_send = False

                tx = PhotonTransaction(nonce=transaction_dict['nonce'],
                                       gas_price=transaction_dict['gasPrice'],
                                       gas=transaction_dict['gas'],
                                       to=to,
                                       value=transaction_dict['value'],
                                       data=data,
                                       code_address=code_address,
                                       execute_on_send=execute_on_send,
                                       v=0,
                                       r=0,
                                       s=0)
                signed_tx = tx.get_signed(account._key_obj, chain_id)
            else:
                raise Exception("Unknown fork id")

            send_transactions.append(signed_tx)

        receive_transactions = []
        for receive_transaction_dict in receive_transaction_dicts:

            if not is_bytes(receive_transaction_dict['senderBlockHash']):
                receive_transaction_dict['senderBlockHash'] = to_bytes(
                    hexstr=receive_transaction_dict['senderBlockHash'])

            if not is_bytes(receive_transaction_dict['sendTransactionHash']):
                receive_transaction_dict['sendTransactionHash'] = to_bytes(
                    hexstr=receive_transaction_dict['sendTransactionHash'])

            if not is_boolean(receive_transaction_dict['isRefund']):
                receive_transaction_dict['isRefund'] = False if to_int(
                    hexstr=receive_transaction_dict['isRefund']) == 0 else True

            # We renamed the fourth parameter in the new photon fork
            fourth_parameter = 0
            if 'remainingRefund' in receive_transaction_dict:
                if not is_integer(receive_transaction_dict['remainingRefund']):
                    fourth_parameter = to_int(
                        hexstr=receive_transaction_dict['remainingRefund'])
                else:
                    fourth_parameter = receive_transaction_dict[
                        'remainingRefund']
            elif 'refundAmount' in receive_transaction_dict:
                if not is_integer(receive_transaction_dict['refundAmount']):
                    fourth_parameter = to_int(
                        hexstr=receive_transaction_dict['refundAmount'])
                else:
                    fourth_parameter = receive_transaction_dict['refundAmount']

            if fork_id == 0:
                receive_transaction_class = BosonReceiveTransaction
            elif fork_id == 1:
                receive_transaction_class = PhotonReceiveTransaction
            else:
                raise Exception("Unknown fork id")

            tx = receive_transaction_class(
                receive_transaction_dict['senderBlockHash'],
                receive_transaction_dict['sendTransactionHash'],
                receive_transaction_dict['isRefund'], fourth_parameter)

            receive_transactions.append(tx)

        send_tx_root_hash, _ = make_trie_root_and_nodes(send_transactions)
        receive_tx_root_hash, _ = make_trie_root_and_nodes(
            receive_transactions)

        chain_address = account.address

        reward_bundle = StakeRewardBundle()

        header = BlockHeader(chain_address=decode_hex(chain_address),
                             parent_hash=header_dict['parentHash'],
                             transaction_root=send_tx_root_hash,
                             receive_transaction_root=receive_tx_root_hash,
                             block_number=header_dict['blockNumber'],
                             timestamp=timestamp,
                             extra_data=extra_data,
                             reward_hash=reward_bundle.hash)

        signed_header = header.get_signed(account._key_obj, chain_id)
        signed_micro_header = signed_header.to_micro_header()

        if fork_id == 0:
            micro_block = BosonMicroBlock(
                header=signed_micro_header,
                transactions=send_transactions,
                receive_transactions=receive_transactions,
                reward_bundle=reward_bundle)
            rlp_encoded_micro_block = rlp.encode(micro_block,
                                                 sedes=BosonMicroBlock)
        elif fork_id == 1:
            micro_block = PhotonMicroBlock(
                header=signed_micro_header,
                transactions=send_transactions,
                receive_transactions=receive_transactions,
                reward_bundle=reward_bundle)
            rlp_encoded_micro_block = rlp.encode(micro_block,
                                                 sedes=PhotonMicroBlock)
        else:
            raise Exception("Unknown fork id")

        return AttributeDict({
            'rawBlock':
            encode_hex(rlp_encoded_micro_block),
            'send_tx_hashes': [tx.hash for tx in send_transactions],
            'receive_tx_hashes': [tx.hash for tx in receive_transactions],
            'r':
            signed_header.r,
            's':
            signed_header.s,
            'v':
            signed_header.v,
        })