Beispiel #1
0
    async def sendRawBlock(self, encoded_micro_block):

        chain = self.get_new_chain()

        encoded_micro_block = decode_hex(encoded_micro_block)

        micro_block = rlp.decode(encoded_micro_block, sedes=chain.get_vm().micro_block_class)

        block_class = self._chain_class.get_vm_class_for_block_timestamp(timestamp = micro_block.header.timestamp).get_block_class()

        full_block = block_class.from_micro_block(micro_block)

        min_time_between_blocks = chain.get_vm(header=full_block.header).min_time_between_blocks

        # Validate the block here
        if(full_block.header.timestamp < (int(time.time()) - MAX_ALLOWED_AGE_OF_NEW_RPC_BLOCK)):
            raise BaseRPCError("The block timestamp is to old. We can only import new blocks over RPC.")

        try:
            canonical_head = chain.chaindb.get_canonical_head(full_block.header.chain_address)
            if canonical_head.block_number >= full_block.header.block_number:
                raise BaseRPCError("You are attempting to replace an existing block. This is not allowed.")

            if full_block.header.timestamp < (canonical_head.timestamp + min_time_between_blocks):
                raise BaseRPCError("Not enough time has passed for you to add a new block yet. New blocks can only be added to your chain every {} seconds".format(min_time_between_blocks))

        except CanonicalHeadNotFound:
            pass

        if((full_block.header.block_number != 0) and
            (not chain.chaindb.is_in_canonical_chain(full_block.header.parent_hash))):
            raise BaseRPCError("Parent block not found on canonical chain.")

        #Check our current syncing stage. Must be sync stage 4.
        current_sync_stage_response = await self._event_bus.request(
            CurrentSyncStageRequest()
        )
        if current_sync_stage_response.sync_stage < FULLY_SYNCED_STAGE_ID:
            raise BaseRPCError("This node is still syncing with the network. Please wait until this node has synced.")


        if not does_block_meet_min_gas_price(full_block, chain):
            required_min_gas_price = self._chain.chaindb.get_required_block_min_gas_price()
            raise Exception("Block transactions don't meet the minimum gas price requirement of {}".format(required_min_gas_price))

        self._event_bus.broadcast(
            NewBlockEvent(block=cast(P2PBlock, full_block), from_rpc=True)
        )

        return True
Beispiel #2
0
    async def filterAddressesWithReceivableTransactions(
            self, chain_addresses, after_timestamp=0):
        #
        # Checks all of the given chain_addresses for receivable transactions, and returns a list of chain addresses that have any.
        #

        if len(chain_addresses) < 1:
            raise BaseRPCError(
                "Must provide at least one chain address when calling getAddressesWithReceivableTransactions"
            )

        earliest_chronological_timestamp = int(
            int(time.time()) -
            TIME_BETWEEN_HEAD_HASH_SAVE * NUMBER_OF_HEAD_HASH_TO_SAVE * 0.95)

        # create new chain for all requests
        chain = self.get_new_chain()
        chain_addresses = [Address(decode_hex(x)) for x in chain_addresses]

        if isinstance(
                after_timestamp,
                int) and after_timestamp > earliest_chronological_timestamp:
            # cycle through all chronological windows
            _, addresses_with_receivable_transactions = await chain.coro_get_receivable_transaction_hashes_from_chronological(
                after_timestamp, chain_addresses)
        else:
            addresses_with_receivable_transactions = await chain.coro_filter_accounts_with_receivable_transactions(
                chain_addresses)

        addresses_with_receivable_transactions = [
            to_checksum_address(x)
            for x in addresses_with_receivable_transactions
        ]

        return addresses_with_receivable_transactions
Beispiel #3
0
 async def getBlockTransactionCountByHash(self, block_hash):
     chain = self.get_new_chain()
     try:
         tx_count = chain.chaindb.get_number_of_total_tx_in_block(block_hash)
     except HeaderNotFound:
         raise BaseRPCError('No block found with the given block hash')
     return hex(tx_count)
Beispiel #4
0
    async def getFaucet(self, chain_address):
        current_sync_stage_response = await self._event_bus.request(
            CurrentSyncStageRequest())
        if current_sync_stage_response.sync_stage < FULLY_SYNCED_STAGE_ID:
            raise BaseRPCError(
                "This node is still syncing with the network. Please wait until this node has synced."
            )

        chain_object = self.get_new_chain(
            self._chain_class.faucet_private_key.public_key.
            to_canonical_address(),
            private_key=self._chain_class.faucet_private_key)
        receivable_transactions, _ = chain_object.get_receivable_transactions(
            chain_address)
        total_receivable = 0
        for tx in receivable_transactions:
            total_receivable += tx.value

        if (chain_object.get_vm().state.account_db.get_balance(chain_address) +
                total_receivable) < 5 * 10**18:
            gas_price = int(
                to_wei(
                    int(chain_object.chaindb.get_required_block_min_gas_price(
                    ) + 5), 'gwei'))
            chain_object.create_and_sign_transaction_for_queue_block(
                gas_price=gas_price,
                gas=0x0c3500,
                to=chain_address,
                value=int(1 * 10**18),
                data=b"",
                v=0,
                r=0,
                s=0)

            chain_object.import_current_queue_block()
Beispiel #5
0
    async def getBlockTransactionCountByNumber(self, at_block, chain_address):
        chain = self.get_new_chain()
        try:
            block_hash = chain.chaindb.get_canonical_block_hash(chain_address=chain_address, block_number=at_block)
            tx_count = chain.chaindb.get_number_of_total_tx_in_block(block_hash)
        except HeaderNotFound:
            raise BaseRPCError('No block found with the given wallet address and block number')

        return hex(tx_count)
Beispiel #6
0
 async def getTransactionByHash(self, tx_hash):
     chain = self.get_new_chain()
     try:
         tx = chain.get_canonical_transaction(tx_hash)
     except TransactionNotFound:
         raise BaseRPCError("Transaction with hash {} not found on canonical chain.".format(encode_hex(tx_hash)))
     if isinstance(tx, BaseReceiveTransaction):
         return receive_transaction_to_dict(tx, chain)
     else:
         return transaction_to_dict(tx, chain)
Beispiel #7
0
 async def _get_unlocked_account_or_unlock_now(self, wallet_address: bytes, password: str = None):
     normalized_wallet_address = to_normalized_address(wallet_address)
     if password is None or password == '':
         try:
             account = self._unlocked_accounts[normalized_wallet_address]
         except KeyError:
             raise BaseRPCError("No unlocked account found with wallet address {}".format(normalized_wallet_address))
     else:
         account = await self._unlock_account(wallet_address, password)
     return account
Beispiel #8
0
 async def getReceiveTransactionOfSendTransaction(self, tx_hash):
     '''
     Gets the receive transaction corresponding to a given send transaction, if it exists
     '''
     chain = self.get_new_chain()
     receive_tx = chain.get_receive_tx_from_send_tx(tx_hash)
     if receive_tx is not None:
         receive_tx_dict = receive_transaction_to_dict(receive_tx, chain)
         return receive_tx_dict
     else:
         raise BaseRPCError("No receive transaction found for the given send transaction hash")
Beispiel #9
0
 async def getTransactionByBlockHashAndIndex(self, block_hash, index):
     try:
         tx = self._chain.get_transaction_by_block_hash_and_index(block_hash, index)
     except HeaderNotFound:
         raise BaseRPCError('No block found with the given block hash')
     if isinstance(tx, BaseReceiveTransaction):
         # receive tx
         return receive_transaction_to_dict(tx, self._chain)
     else:
         # send tx
         return transaction_to_dict(tx, self._chain)
Beispiel #10
0
    async def receiveTransactions(self, wallet_address: bytes, password: str = None):
        # Check our current syncing stage. Must be sync stage 4.
        current_sync_stage_response = await self._event_bus.request(
            CurrentSyncStageRequest()
        )
        if current_sync_stage_response.sync_stage < FULLY_SYNCED_STAGE_ID:
            raise BaseRPCError("This node is still syncing with the network. Please wait until this node has synced.")

        wallet_address_hex = encode_hex(wallet_address)

        account = await self._get_unlocked_account_or_unlock_now(wallet_address_hex, password)
        return await self._send_transactions([], account)
Beispiel #11
0
 async def getTransactionByBlockNumberAndIndex(self, at_block, index, chain_address):
     try:
         block_hash = self._chain.chaindb.get_canonical_block_hash(chain_address=chain_address,
                                                                   block_number=at_block)
     except HeaderNotFound:
         raise BaseRPCError('No block found with the given chain address and block number')
     tx = self._chain.get_transaction_by_block_hash_and_index(block_hash, index)
     if isinstance(tx, BaseReceiveTransaction):
         # receive tx
         return receive_transaction_to_dict(tx, self._chain)
     else:
         # send tx
         return transaction_to_dict(tx, self._chain)
Beispiel #12
0
    def _save_account(self, account, password):
        if not self._account_address_cache_ready.is_set():
            raise BaseRPCError("Account cache is still building. Please wait and try again in a moment.")

        w3 = Web3()
        new_account_json_encrypted = w3.hls.account.encrypt(account.privateKey, password)
        keyfile_name = "HLS_account_{}".format(account.address)
        keyfile_path = self._rpc_context.keystore_dir / keyfile_name

        f = open(str(keyfile_path), "w")
        f.write(json.dumps(new_account_json_encrypted))
        f.close()

        self._account_address_cache.add(account.address)
Beispiel #13
0
    def _get_keystore_for_address(self, wallet_address):
        normalized_wallet_address = to_normalized_address(wallet_address)
        file_glob = self.rpc_context.keystore_dir.glob('**/*')
        files = [x for x in file_glob if x.is_file()]
        for json_keystore in files:
            try:
                with open(str(json_keystore)) as json_file:
                    keystore = json.load(json_file)
                    if 'address' in keystore:
                        if normalized_wallet_address == to_normalized_address(keystore['address']):
                            return keystore
            except Exception as e:
                # Not a json file
                pass

        raise BaseRPCError("No saved keystore for wallet address {}".format(normalized_wallet_address))
Beispiel #14
0
    async def sendTransactions(self, txs, password: str = None):
        '''

        :param tx: {'from', 'to', 'value', 'gas', 'gasPrice', 'data', 'nonce'}
        :param password:
        :return:
        '''

        # Check our current syncing stage. Must be sync stage 4.
        current_sync_stage_response = await self._event_bus.request(
            CurrentSyncStageRequest()
        )
        if current_sync_stage_response.sync_stage < FULLY_SYNCED_STAGE_ID:
            raise BaseRPCError("This node is still syncing with the network. Please wait until this node has synced.")

        wallet_address_hex = txs[0]['from']

        account = await self._get_unlocked_account_or_unlock_now(wallet_address_hex, password)
        return await self._send_transactions(txs, account)
Beispiel #15
0
    async def _send_transactions(self, transactions, account, include_receive: bool = True):
        async with self._importing_block_lock:
            print("Importing block")
            normalized_wallet_address = to_normalized_address(account.address)

            wallet_address_hex = account.address

            wallet_address = decode_hex(wallet_address_hex)

            chain = self.get_new_chain(Address(wallet_address), account._key_obj)

            allowed_time_of_next_block = chain.get_allowed_time_of_next_block()
            now = int(time.time())

            if now < allowed_time_of_next_block:
                raise BaseRPCError("The minimum time between blocks has not passed. You must wait until {} to send the next block. "
                                   "Use personal_sendTrasactions to send multiple transactions at once.".format(allowed_time_of_next_block))

            # make the chain read only for creating the block. We don't want to actually import it here.
            chain.enable_read_only_db()

            if include_receive:
                chain.populate_queue_block_with_receive_tx()

            signed_transactions = []
            min_gas_price = to_wei(chain.chaindb.get_required_block_min_gas_price(), 'gwei')
            safe_min_gas_price = to_wei(chain.chaindb.get_required_block_min_gas_price()+5, 'gwei')
            for i in range(len(transactions)):
                tx = transactions[i]
                if to_normalized_address(tx['from']) != normalized_wallet_address:
                    raise BaseRPCError("When sending multiple transactions at once, they must all be from the same address")

                if 'gasPrice' in tx:
                    gas_price = to_int_if_hex(tx['gasPrice'])
                else:
                    gas_price = safe_min_gas_price

                if 'gas' in tx:
                    gas = to_int_if_hex(tx['gas'])
                else:
                    gas = GAS_TX

                if 'data' in tx:
                    data = tx['data']
                else:
                    data = b''

                if 'nonce' in tx:
                    nonce = to_int_if_hex(tx['nonce'])
                else:
                    nonce = None

                transactions[i]['nonce'] = nonce
                signed_tx = chain.create_and_sign_transaction_for_queue_block(
                    gas_price=gas_price,
                    gas=gas,
                    to=decode_hex(tx['to']),
                    value=to_int_if_hex(tx['value']),
                    data=data,
                    nonce=nonce,
                    v=0,
                    r=0,
                    s=0
                )
                signed_transactions.append(signed_tx)


            block = chain.import_current_queue_block()

            if not does_block_meet_min_gas_price(block, chain):
                raise Exception("The average gas price of all transactions in your block does not meet the required minimum gas price. Your average block gas price: {}. Min gas price: {}".format(
                    get_block_average_transaction_gas_price(block),
                    min_gas_price))

            if len(signed_transactions) == 0 and len(block.receive_transactions) == 0:
                raise BaseRPCError("Cannot send block if it has no send or receive transactions.")

            self._event_bus.broadcast(
                NewBlockEvent(block=cast(P2PBlock, block), from_rpc=True)
            )

            send_transaction_hashes = [encode_hex(tx.hash) for tx in signed_transactions]
            receive_transaction_hashes = [encode_hex(tx.hash) for tx in block.receive_transactions]
            all_transaction_hashes = send_transaction_hashes
            all_transaction_hashes.extend(receive_transaction_hashes)

            if not include_receive:
                return all_transaction_hashes[0]
            else:
                return all_transaction_hashes
Beispiel #16
0
    async def _send_transactions(self,
                                 transactions,
                                 account,
                                 include_receive: bool = True):
        async with self._importing_block_lock:
            print("Importing block")

            # Check our current syncing stage. Must be sync stage 4.
            current_sync_stage_response = await self._event_bus.request(
                CurrentSyncStageRequest())
            if current_sync_stage_response.sync_stage < FULLY_SYNCED_STAGE_ID:
                raise BaseRPCError(
                    "This node is still syncing with the network. Please wait until this node has synced."
                )

            # Check that our block import queue is not deep. It could cause min gas to increase before this block makes it there.
            current_block_import_queue_length = await self._event_bus.request(
                BlockImportQueueLengthRequest())
            if current_block_import_queue_length.queue_length > MAX_ALLOWED_LENGTH_BLOCK_IMPORT_QUEUE:
                raise BaseRPCError(
                    "This node is currently at it's maximum capacity of new blocks. Please wait a moment while we process them, and try again."
                )

            normalized_wallet_address = to_normalized_address(account.address)

            wallet_address_hex = account.address

            wallet_address = decode_hex(wallet_address_hex)

            chain = self.get_new_chain(Address(wallet_address),
                                       account._key_obj)

            allowed_time_of_next_block = chain.get_allowed_time_of_next_block()
            now = int(time.time())

            if now < allowed_time_of_next_block:
                raise BaseRPCError(
                    "The minimum time between blocks has not passed. You must wait until {} to send the next block. "
                    "Use personal_sendTrasactions to send multiple transactions at once."
                    .format(allowed_time_of_next_block))

            # make the chain read only for creating the block. We don't want to actually import it here.
            chain.enable_read_only_db()

            if include_receive:
                chain.populate_queue_block_with_receive_tx()

            signed_transactions = []

            # Make sure it meets the average min gas price of the network. If it doesnt, then it won't reach consensus.
            current_network_min_gas_price_response = await self._event_bus.request(
                AverageNetworkMinGasPriceRequest())

            network_min_gas_price = current_network_min_gas_price_response.min_gas_price
            local_min_gas_price = chain.min_gas_db.get_required_block_min_gas_price(
            )
            actual_min_gas_price = max(
                [network_min_gas_price, local_min_gas_price])

            min_gas_price = to_wei(actual_min_gas_price, 'gwei')
            safe_min_gas_price = to_wei(actual_min_gas_price + 5, 'gwei')
            for i in range(len(transactions)):
                tx = transactions[i]
                if to_normalized_address(
                        tx['from']) != normalized_wallet_address:
                    raise BaseRPCError(
                        "When sending multiple transactions at once, they must all be from the same address"
                    )

                if 'gasPrice' in tx:
                    gas_price = to_int_if_hex(tx['gasPrice'])
                else:
                    gas_price = safe_min_gas_price

                if 'gas' in tx:
                    gas = to_int_if_hex(tx['gas'])
                else:
                    gas = GAS_TX

                if 'data' in tx:
                    data = tx['data']
                else:
                    data = b''

                if 'nonce' in tx:
                    nonce = to_int_if_hex(tx['nonce'])
                else:
                    nonce = None

                transactions[i]['nonce'] = nonce
                signed_tx = chain.create_and_sign_transaction_for_queue_block(
                    gas_price=gas_price,
                    gas=gas,
                    to=decode_hex(tx['to']),
                    value=to_int_if_hex(tx['value']),
                    data=data,
                    nonce=nonce,
                    v=0,
                    r=0,
                    s=0)
                signed_transactions.append(signed_tx)

            block = chain.import_current_queue_block()

            average_block_gas_price = get_block_average_transaction_gas_price(
                block)

            if average_block_gas_price < min_gas_price:
                raise Exception(
                    "The average gas price of all transactions in your block does not meet the required minimum gas price. Your average block gas price: {}. Min gas price: {}"
                    .format(average_block_gas_price, min_gas_price))

            if len(signed_transactions) == 0 and len(
                    block.receive_transactions) == 0:
                raise BaseRPCError(
                    "Cannot send block if it has no send or receive transactions."
                )

            self._event_bus.broadcast(
                NewBlockEvent(block=cast(P2PBlock, block), from_rpc=True))

            send_transaction_hashes = [
                encode_hex(tx.hash) for tx in signed_transactions
            ]
            receive_transaction_hashes = [
                encode_hex(tx.hash) for tx in block.receive_transactions
            ]
            all_transaction_hashes = send_transaction_hashes
            all_transaction_hashes.extend(receive_transaction_hashes)

            if not include_receive:
                return all_transaction_hashes[0]
            else:
                return all_transaction_hashes
Beispiel #17
0
    async def _send_transactions(self, transactions, account):
        async with self._importing_block_lock:
            print("Importing block")
            normalized_wallet_address = to_normalized_address(account.address)

            wallet_address_hex = account.address

            wallet_address = decode_hex(wallet_address_hex)

            chain = self.get_new_chain(Address(wallet_address), account._key_obj)

            # make the chain read only for creating the block. We don't want to actually import it here.
            chain.enable_read_only_db()

            signed_transactions = []
            for i in range(len(transactions)):
                tx = transactions[i]
                if to_normalized_address(tx['from']) != normalized_wallet_address:
                    raise BaseRPCError("When sending multiple transactions at once, they must all be from the same address")

                if 'gasPrice' in tx:
                    gas_price = tx['gasPrice']
                else:
                    gas_price = to_wei(chain.chaindb.get_required_block_min_gas_price()+1, 'gwei')

                if 'gas' in tx:
                    gas = tx['gas']
                else:
                    gas = GAS_TX

                if 'data' in tx:
                    data = tx['data']
                else:
                    data = b''

                if 'nonce' in tx:
                    nonce = tx['nonce']
                else:
                    if normalized_wallet_address in self._current_tx_nonce:
                        nonce_from_state = chain.get_vm().state.account_db.get_nonce(wallet_address)

                    nonce = chain.get_vm().state.account_db.get_nonce(wallet_address)

                transactions[i]['nonce'] = nonce
                signed_tx = chain.create_and_sign_transaction_for_queue_block(
                    gas_price=gas_price,
                    gas=GAS_TX,
                    to=decode_hex(tx['to']),
                    value=to_int_if_hex(tx['value']),
                    data=data,
                    v=0,
                    r=0,
                    s=0
                )
                signed_transactions.append(signed_tx)

            # We put this part down here because we have to return the hashes of all the transactions.
            # Check when the next block can be. If we are early, queue up the tx.
            allowed_time_of_next_block = chain.get_allowed_time_of_next_block()
            min_time_between_blocks = chain.min_time_between_blocks
            now = int(time.time())

            # Or, we may have just sent a block and it hasn't been imported yet. Lets check. Then send to queue if that is the case.
            if normalized_wallet_address in self._newest_block_times_sent_to_event_bus:
                if self._newest_block_times_sent_to_event_bus[normalized_wallet_address] >= allowed_time_of_next_block:
                    allowed_time_of_next_block = self._newest_block_times_sent_to_event_bus[normalized_wallet_address] + min_time_between_blocks

            if now < allowed_time_of_next_block:
                for tx in transactions:
                    await self._add_transaction_to_queue(tx)

                asyncio.ensure_future(self._import_delayed_block_with_queue(account, allowed_time_of_next_block-now, min_time_between_blocks))
            else:
                block = chain.import_current_queue_block()

                self._event_bus.broadcast(
                    NewBlockEvent(block=cast(P2PBlock, block), from_rpc=True)
                )

                self._newest_block_times_sent_to_event_bus[normalized_wallet_address] = block.header.timestamp

            if len(signed_transactions) == 1:
                return encode_hex(signed_transactions[0].hash)
            else:
                return [encode_hex(tx.hash) for tx in signed_transactions]
Beispiel #18
0
 async def _get_all_account_addresses_set_from_cache(self):
     if not self._account_address_cache_ready.is_set():
         raise BaseRPCError("Account cache is still building. Please wait and try again in a moment.")
     return self._account_address_cache
Beispiel #19
0
    async def sendRawBlock(self, encoded_micro_block):

        chain = self.get_new_chain()

        encoded_micro_block = decode_hex(encoded_micro_block)

        micro_block = rlp.decode(encoded_micro_block,
                                 sedes=chain.get_vm().micro_block_class)

        block_class = self._chain_class.get_vm_class_for_block_timestamp(
            timestamp=micro_block.header.timestamp).get_block_class()

        full_block = block_class.from_micro_block(micro_block)

        min_time_between_blocks = chain.get_vm(
            header=full_block.header).min_time_between_blocks

        # Validate the block here
        if (full_block.header.timestamp <
            (int(time.time()) - MAX_ALLOWED_AGE_OF_NEW_RPC_BLOCK)):
            raise BaseRPCError(
                "The block timestamp is to old. We can only import new blocks over RPC."
            )

        if (full_block.header.timestamp >
                int(time.time() + BLOCK_TIMESTAMP_FUTURE_ALLOWANCE)):
            raise BaseRPCError(
                "The block timestamp is in the future and cannot be accepted. You should check your computer clock."
            )

        try:
            canonical_head = chain.chaindb.get_canonical_head(
                full_block.header.chain_address)
            if canonical_head.block_number >= full_block.header.block_number:
                raise BaseRPCError(
                    "You are attempting to replace an existing block. This is not allowed."
                )

            if full_block.header.timestamp < (canonical_head.timestamp +
                                              min_time_between_blocks):
                raise BaseRPCError(
                    "Not enough time has passed for you to add a new block yet. New blocks can only be added to your chain every {} seconds"
                    .format(min_time_between_blocks))

        except CanonicalHeadNotFound:
            pass

        if ((full_block.header.block_number != 0)
                and (not chain.chaindb.is_in_canonical_chain(
                    full_block.header.parent_hash))):
            raise BaseRPCError("Parent block not found on canonical chain.")

        # Check our current syncing stage. Must be sync stage 4.
        current_sync_stage_response = await self._event_bus.request(
            CurrentSyncStageRequest())
        if current_sync_stage_response.sync_stage < FULLY_SYNCED_STAGE_ID:
            raise BaseRPCError(
                "This node is still syncing with the network. Please wait until this node has synced and try again."
            )

        # Check that our block import queue is not deep. It could cause min gas to increase before this block makes it there.
        current_block_import_queue_length = await self._event_bus.request(
            BlockImportQueueLengthRequest())
        if current_block_import_queue_length.queue_length > MAX_ALLOWED_LENGTH_BLOCK_IMPORT_QUEUE:
            raise BaseRPCError(
                "This node's block import queue is saturated. Please wait a moment and try again."
            )

        # Make sure it meets the local min gas price
        if not does_block_meet_min_gas_price(full_block, chain):
            required_min_gas_price = self._chain.min_gas_db.get_required_block_min_gas_price(
            )
            raise Exception(
                "Block transactions don't meet the minimum gas price requirement of {}"
                .format(required_min_gas_price))

        # Make sure it meets the average min gas price of the network. If it doesnt, then it won't reach consensus.
        current_network_min_gas_price_response = await self._event_bus.request(
            AverageNetworkMinGasPriceRequest())
        network_min_gas_price_wei = to_wei(
            current_network_min_gas_price_response.min_gas_price, 'gwei')
        if network_min_gas_price_wei > get_block_average_transaction_gas_price(
                full_block):
            raise BaseRPCError(
                "This block doesn't meet the minimum gas requirements to reach consensus on the network. It must have at least {} average gas price on all transactions."
                .format(current_network_min_gas_price_response.min_gas_price))

        self._event_bus.broadcast(
            NewBlockEvent(block=cast(P2PBlock, full_block), from_rpc=True))

        return True
Beispiel #20
0
    async def _send_transactions(self, transactions, account):
        async with self._importing_block_lock:
            print("Importing block")
            normalized_wallet_address = to_normalized_address(account.address)

            wallet_address_hex = account.address

            wallet_address = decode_hex(wallet_address_hex)

            chain = self.get_new_chain(Address(wallet_address),
                                       account._key_obj)

            allowed_time_of_next_block = chain.get_allowed_time_of_next_block()
            now = int(time.time())

            if now < allowed_time_of_next_block:
                raise BaseRPCError(
                    "The minimum time between blocks has not passed. You must wait until {} to send the next block. "
                    "Use personal_sendTrasactions to send multiple transactions at once."
                    .format(allowed_time_of_next_block))

            # make the chain read only for creating the block. We don't want to actually import it here.
            chain.enable_read_only_db()

            signed_transactions = []
            for i in range(len(transactions)):
                tx = transactions[i]
                if to_normalized_address(
                        tx['from']) != normalized_wallet_address:
                    raise BaseRPCError(
                        "When sending multiple transactions at once, they must all be from the same address"
                    )

                if 'gasPrice' in tx:
                    gas_price = tx['gasPrice']
                else:
                    gas_price = to_wei(
                        chain.chaindb.get_required_block_min_gas_price() + 1,
                        'gwei')

                if 'gas' in tx:
                    gas = tx['gas']
                else:
                    gas = GAS_TX

                if 'data' in tx:
                    data = tx['data']
                else:
                    data = b''

                if 'nonce' in tx:
                    nonce = tx['nonce']
                else:
                    nonce = None

                transactions[i]['nonce'] = nonce
                signed_tx = chain.create_and_sign_transaction_for_queue_block(
                    gas_price=gas_price,
                    gas=GAS_TX,
                    to=decode_hex(tx['to']),
                    value=to_int_if_hex(tx['value']),
                    data=data,
                    nonce=nonce,
                    v=0,
                    r=0,
                    s=0)
                signed_transactions.append(signed_tx)

            block = chain.import_current_queue_block()

            self._event_bus.broadcast(
                NewBlockEvent(block=cast(P2PBlock, block), from_rpc=True))

            if len(signed_transactions) == 1:
                return encode_hex(signed_transactions[0].hash)
            else:
                return [encode_hex(tx.hash) for tx in signed_transactions]