async def generate(cls, config, transactions, public_key, private_key, force_version=None, index=None, force_time=None): try: mongo = config.mongo app_log = getLogger("tornado.application") if force_version is None: version = CHAIN.get_version_for_height(index) else: version = force_version if force_time: xtime = str(int(force_time)) else: xtime = str(int(time.time())) index = int(index) if index == 0: prev_hash = '' else: prev_hash = config.BU.get_latest_block()['hash'] transaction_objs = [] fee_sum = 0.0 used_sigs = [] for txn in transactions: try: if isinstance(txn, FastGraph): transaction_obj = txn else: transaction_obj = FastGraph.from_dict(index, txn) if transaction_obj.transaction_signature in used_sigs: print('duplicate transaction found and removed') continue if not transaction_obj.verify(): raise InvalidTransactionException( "invalid transactions") used_sigs.append(transaction_obj.transaction_signature) except: try: if isinstance(txn, Transaction): transaction_obj = txn else: transaction_obj = Transaction.from_dict(index, txn) if transaction_obj.transaction_signature in used_sigs: print('duplicate transaction found and removed') continue transaction_obj.verify() used_sigs.append(transaction_obj.transaction_signature) except: raise InvalidTransactionException( "invalid transactions") try: if int(index) > CHAIN.CHECK_TIME_FROM and ( int(transaction_obj.time) > int(xtime) + CHAIN.TIME_TOLERANCE): app_log.debug("Block embeds txn too far in the future") continue transaction_objs.append(transaction_obj) fee_sum += float(transaction_obj.fee) except Exception as e: await mongo.async_db.miner_transactions.delete_many( {'id': transaction_obj.transaction_signature}) if config.debug: app_log.debug('Exception {}'.format(e)) else: continue block_reward = CHAIN.get_block_reward(index) coinbase_txn_fctry = TransactionFactory( index, public_key=public_key, private_key=private_key, outputs=[{ 'value': block_reward + float(fee_sum), 'to': str( P2PKHBitcoinAddress.from_pubkey( bytes.fromhex(public_key))) }], coinbase=True) coinbase_txn = coinbase_txn_fctry.generate_transaction() transaction_objs.append(coinbase_txn) transactions = transaction_objs block_factory = cls() block = Block(version=version, block_time=xtime, block_index=index, prev_hash=prev_hash, transactions=transactions, public_key=public_key) txn_hashes = block.get_transaction_hashes() block.set_merkle_root(txn_hashes) block.merkle_root = block.verify_merkle_root block_factory.block = block return block_factory except Exception as e: import sys, os print("Exception {} BlockFactory".format(e)) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] print(exc_type, fname, exc_tb.tb_lineno) raise
""" Temp. test for block reward function precision """ import sys import random sys.path.append('../') from yadacoin.chain import CHAIN if __name__ == "__main__": for i in range(1000): index = random.randint(1, 6930000+21000) value1 = CHAIN.get_block_reward_deprecated(index) value2 = CHAIN.get_block_reward(index) if value1 != value2: print("Error", index, value1, value2) # boundary tests test2 = (2519999, 2520000, 2520001, 2729999, 2730000, 2730001) for index in test2: value1 = CHAIN.get_block_reward_deprecated(index) value2 = CHAIN.get_block_reward(index) if value1 != value2: print("Error2", index, value1, value2)
def verify(self): try: getcontext().prec = 8 if int(self.version) != int( CHAIN.get_version_for_height(self.index)): raise Exception("Wrong version for block height", self.version, CHAIN.get_version_for_height(self.index)) txns = self.get_transaction_hashes() self.set_merkle_root(txns) if self.verify_merkle_root != self.merkle_root: raise Exception("Invalid block merkle root") header = BlockFactory.generate_header(self) hashtest = BlockFactory.generate_hash_from_header( header, str(self.nonce)) # print("header", header, "nonce", self.nonce, "hashtest", hashtest) if self.hash != hashtest: getLogger("tornado.application").warning( "Verify error hashtest {} header {} nonce {}".format( hashtest, header, self.nonce)) raise Exception('Invalid block hash') address = P2PKHBitcoinAddress.from_pubkey( bytes.fromhex(self.public_key)) try: # print("address", address, "sig", self.signature, "pubkey", self.public_key) result = verify_signature(base64.b64decode(self.signature), self.hash.encode('utf-8'), bytes.fromhex(self.public_key)) if not result: raise Exception("block signature1 is invalid") except: try: result = VerifyMessage( address, BitcoinMessage(self.hash.encode('utf-8'), magic=''), self.signature) if not result: raise except: raise Exception("block signature2 is invalid") # verify reward coinbase_sum = 0 for txn in self.transactions: if int(self.index) > CHAIN.CHECK_TIME_FROM and (int( txn.time) > int(self.time) + CHAIN.TIME_TOLERANCE): raise Exception("Block embeds txn too far in the future") if txn.coinbase: for output in txn.outputs: coinbase_sum += float(output.value) fee_sum = 0.0 for txn in self.transactions: if not txn.coinbase: fee_sum += float(txn.fee) reward = CHAIN.get_block_reward(self.index) #if Decimal(str(fee_sum)[:10]) != Decimal(str(coinbase_sum)[:10]) - Decimal(str(reward)[:10]): """ KO for block 13949 0.02099999 50.021 50.0 Integrate block error 1 ('Coinbase output total does not equal block reward + transaction fees', 0.020999999999999998, 0.021000000000000796) """ if quantize_eight(fee_sum) != quantize_eight(coinbase_sum - reward): print(fee_sum, coinbase_sum, reward) raise Exception( "Coinbase output total does not equal block reward + transaction fees", fee_sum, (coinbase_sum - reward)) except Exception as e: exc_type, exc_obj, exc_tb = exc_info() fname = path.split(exc_tb.tb_frame.f_code.co_filename)[1] getLogger("tornado.application").warning("verify {} {} {}".format( exc_type, fname, exc_tb.tb_lineno)) raise