Exemple #1
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()
Exemple #2
0
 async def syncing(self):
     # Check our current syncing stage. If not sync stage 4, then we are syncing
     current_sync_stage_response = await self._event_bus.request(
         CurrentSyncStageRequest())
     if current_sync_stage_response.sync_stage < FULLY_SYNCED_STAGE_ID:
         return True
     else:
         return False
Exemple #3
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)
Exemple #4
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.")


        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
Exemple #5
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)
Exemple #6
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
Exemple #7
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