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()
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
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)
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
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)
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
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