def verifyTxOutputDuplicateInPool(self, transaction): for txIn in transaction.inputs: outpoint = txIn.outpoint for txId in MemoryPool.getMemoryPool(): tx = MemoryPool.getTransactionById(txId) for i in tx.inputs: if outpoint == i.outpoint: return False return True
def onSuccess(self, callback=None): message = MessageFactory.getInstance(MessageType.GETDATA) message.addrRecv = self.addrFrom for inventory in self.inventory: if inventory.invType == InventoryType.BLOCK: if self.chain.getBlockByHash(inventory.getInvHash()) == None: message.inventory.append(inventory) elif inventory.invType == InventoryType.TRANSACTION: if MemoryPool.getTransactionById( inventory.getInvHash()) == None: message.inventory.append(inventory) if len(message.inventory) > 0: message.send()
def validate(self, transaction): if transaction == None: return False ''' The transaction’s syntax and data structure must be correct ''' if transaction.version == None or transaction.version != Config.getIntValue( 'TRANSACTION_VERSION'): return False if not self.verifyInputOutputNonEmpty(transaction): return False for txIn in transaction.inputs: ''' Check outpoint ''' if txIn.outpoint == None: return False outpoint = txIn.outpoint if outpoint.txId == None or len( outpoint.txId) != Config.getIntValue('HASH_LEN'): return False if outpoint.outputIndex == None or outpoint.outputIndex < 0: return False ''' Check Output Value ''' for txOut in transaction.outputs: if txOut.value == None: return False if txOut.hasExtScript(): if not txOut.value >= 0: return False elif not txOut.value > 0: return False ''' Check tx gas price and gas limit ''' if transaction.gasPrice == None or transaction.gasPrice < 0: return False if transaction.gasLimit == None or transaction.gasLimit < 0: return False ''' Internal Outputs are created from the result of a smart contract. Only the RVM should create them. ''' if len(transaction.internalOutputs) > 0: return False if not self.verifyAddress(transaction): return False if not self.verifyExtraData(transaction): return False if not self.verifyScript(transaction): return False if not self.verifyWitness(transaction): return False if not self.verifyTransactionSizeLimit(transaction): return False ''' Check for duplicate outpoints. ''' outpoints = set() for txIn in transaction.inputs: if txIn.outpoint in outpoints: return False outpoints.add(txIn.outpoint) if not self.verifyAllowedOutputValueRange(transaction): return False if not self.verifyInputsNonCoinbase(transaction): return False if not self.verifyTransactionRequiredSize(transaction): return False if not self.verifyTransactionDuplicateInPool(transaction): return False ''' or txId in a block in the main branch ''' txId = transaction.hash() try: UXTOStorage.uxto.open() with UXTOStorage.uxto.db.begin() as uxto: cursor = uxto.cursor(db=UXTOStorage.uxto.subDb) while cursor.next(): outpointBytes = cursor.key() outpoint = Outpoint() outpoint.deserialize(outpointBytes) if txId == outpoint.txId: return False except IOError: Log.error( 'Unable to determine if txId is in a block in the main branch.' ) finally: UXTOStorage.uxto.close() if not self.verifyTxOutputDuplicateInPool(transaction): return False ''' For each input, look in the main branch and the transaction pool to find the referenced output transaction. If the output transaction is missing for any input, this will be an orphan transaction. Add to the orphan transactions, if a matching transaction is not in there already. ''' for txIn in transaction.inputs: outpoint = txIn.outpoint if not UXTO.hasUnspentTransactionCoin(outpoint): tx = MemoryPool.getTransactionById(outpoint.txId) if tx == None or len(tx.outputs) - 1 < outpoint.outputIndex: OrphanManager.addTransaction(transaction) return False if not self.verifyCoinbaseMaturity(transaction): return False if not self.verifyUxtoReferencedOutput(transaction): return False if not self.verifyAllowedInputValueRange(transaction): return False if not self.verifySumInputOutputValues(transaction): return False if not self.verifyUnlockingScripts(transaction): return False ''' 7) Note that when the transaction is accepted into the memory pool, an additional check is made to ensure that the coinbase value does not exceed the transaction fees plus the expected BTC value (25BTC as of this writing). ''' if transaction.isCoinbase(): txOut = transaction.outputs blockRewards = Config.getDecimalValue("BLOCK_REWARDS") blockRewards = Units.toUnits(blockRewards) if txOut.value > blockRewards: return False return True