def validate(self, data): # Check for extra data extra_data = self.context['request'].data.get('extra_data') if not data.get('extra_data') and extra_data: data['extra_data'] = b64decode(extra_data) # Build the transaction tx = UnconfirmedTransaction(**data) # Verify the hash tx.hash = tx.calculate_hash() if tx.hash != data['hash']: raise serializers.ValidationError('Invalid hash') # Verify the signature if not verify(tx.hash, tx.from_account, tx.signature): raise serializers.ValidationError('Bad signature') data['transaction'] = tx # Validate the transaction active_block = Block.get_active_block() if not validate_transaction( active_block.get_balances(), tx, prev_block=active_block, ): raise serializers.ValidationError('Transaction was not accepted.') return data
def mine_block(): logger.debug('Checking for sync locks...') if SyncLock.objects.count(): logger.debug("Looks like we're syncing, canceling mine_block call.") return logger.debug('Mining new block...') broadcast = None with transaction.atomic(): # Get the active block active_block = Block.get_active_block() logger.debug(f'{active_block.id} is the active block.') # Collect the unconfirmed transactions unconfirmed = UnconfirmedTransaction.objects.all() logger.debug(f'{len(unconfirmed)} unconfirmed transactions found.') # Prune invalid transactions transactions = prune_invalid_transactions(active_block, unconfirmed) logger.debug(f'{len(transactions)} transactions after pruning.') # Convert the unconfirmed transactions and add the block reward transactions = [u.to_transaction() for u in transactions] transactions.insert(0, Transaction.create_block_reward()) # Set up the block block = Block( previous_block=active_block, depth=active_block.depth + 1, miner=settings.MINER_PUBLIC_KEY, extra_data=settings.BLOCK_EXTRA_DATA, time=now(), ) block.set_merkle_root(transactions) block.set_balances( apply_transactions_to_balances( transactions, active_block.get_balances(), )) block.set_hash() block.sign() # Validate the block and transactions if validate_block(block, transactions): # Save the block block.save(transactions) UnconfirmedTransaction.objects.all().delete() broadcast = block logger.info(f'Block {block.id} successfully mined.') else: logger.info('Failed to mine block - validation error!') if broadcast: from boocoin.p2p import broadcast_block broadcast_block(broadcast)
def is_time_to_mine(): """ Returns whether or not there are either at least 10 unconfirmed transactions, or it has been at least 10 minutes since the last block was mined. """ active_block = Block.get_active_block() minutes_passed = (now() - active_block.time).total_seconds() / 60 if UnconfirmedTransaction.objects.count() >= 10 or minutes_passed > 10: return True return False
def check_for_block(): # Get the active block active_block = Block.get_active_block() # Calculate how many minutes it has been since that block minutes_passed = (now() - active_block.time).total_seconds() / 60 logger.debug(f'Minutes passed since last block: {minutes_passed}') # Mine a new block if it has been 10 minutes if minutes_passed >= 10: logger.info('10 minutes passed, mining new block...') mine_block()
def get(self, request): before = request.GET.get('before') if before: from_block = get_object_or_404(Block, id=before) else: from_block = Block.get_active_block() ids = [] for i in range(100): ids.append(from_block.id) if from_block.previous_block: from_block = from_block.previous_block else: break return Response(ids)
def get(self, request): return Response(Block.get_active_block().depth + 1)