def init(self):
        if self.getIndexBlockByHash(self.CHAIN_HEAD_INDEX) == None:
            genesisBlockGasLimit = Config.getIntValue("GENESIS_BLOCK_GAS_LIMIT")
            genesisBlockGasUsed = Config.getIntValue("GENESIS_BLOCK_GAS_USED")
            genesisBlockGasPrice = Config.getIntValue("GENESIS_BLOCK_GAS_PRICE")

            genesisBlock = Block()
            genesisBlock.previousHash = Config.getBytesValue("GENESIS_BLOCK_PREVIOUS_HASH", False)
            genesisBlock.gasLimit = genesisBlockGasLimit
            genesisBlock.gasUsed = genesisBlockGasUsed
            genesisBlock.nonce = Config.getIntValue("GENESIS_BLOCK_NONCE")
            genesisBlock.bits = Config.getIntValue("GENESIS_BLOCK_DIFFICULTY_BITS", 16)
            genesisBlock.timestamp = Config.getIntValue("GENESIS_BLOCK_TIMESTAMP")
            
            transaction = Transaction(genesisBlockGasLimit, genesisBlockGasPrice)
            coinbaseData = []
            coinbaseData.append(Config.getValue("GENESIS_BLOCK_COINBASE_DATA"))
            transaction.addCoinbaseInput(coinbaseData)
            genesisBlockRewards = Config.getDecimalValue("GENESIS_BLOCK_REWARDS")
            genesisBlockRewards = Units.toUnits(genesisBlockRewards)
            genesisBlockPublicAddress = Config.getValue("GENESIS_BLOCK_PUBLIC_ADDRESS")
            genesisBlockPublicAddress = Address.toAddressBytes(genesisBlockPublicAddress)
            genesisBlockScript = Script.verifySignature()
            transaction.addOutput(genesisBlockPublicAddress, genesisBlockScript, genesisBlockRewards)
            transaction.hash()
            
            genesisBlock.transactions.append(transaction) 
            genesisBlock.merkleRoot = MerkleTree.getMerkleRoot(genesisBlock.transactions, False)
            genesisBlock.witnessRoot = MerkleTree.getMerkleRoot(genesisBlock.transactions, True)
            
            self.addBlock(genesisBlock)
 def verifyCoinbaseValue(self, block):
     coinbaseValue = 0.0
     blkCreationTxFees = Config.getDecimalValue("BLOCK_REWARDS")
     blkCreationTxFees = Units.toUnits(blkCreationTxFees)
     for transaction in block.transactions:
         if transaction.isCoinbase():
             output = transaction.outputs[0]
             coinbaseValue = output.value
         else:
             blkCreationTxFees += transaction.calculateTxFee()
     if coinbaseValue > blkCreationTxFees:
         return False
     return True
    def getNewBlock(self, address, previousHash, bits, extraNonce):
        previousIndexBlock = self.getIndexBlockByHash(previousHash)
        block = Block()

        gasLimit = Config.getIntValue("BLOCK_REWARDS_GAS_LIMIT")
        gasPrice = Config.getIntValue("BLOCK_REWARDS_GAS_PRICE")
        transaction = Transaction(gasLimit, gasPrice)

        height = previousIndexBlock.height + 1
        coinbaseData = [
            DataType.asString(height), 
            DataType.asString(bits), 
            DataType.asString(extraNonce)
        ]
        transaction.addCoinbaseInput(coinbaseData)
        block.transactions.append(transaction) 
        txFees = 0
        totalTxGasUsed = 0
        unconfirmedTransactions = MemoryPool.getMemoryPool()
        for txId in unconfirmedTransactions:
            unconfirmedTransaction = unconfirmedTransactions[txId]
            block.transactions.append(unconfirmedTransaction)  
            txFees += unconfirmedTransaction.calculateTxFee()
            totalTxGasUsed += unconfirmedTransaction.calculateTxGasUsed()
        blockRewards = Config.getDecimalValue("BLOCK_REWARDS")
        blockRewards = Units.toUnits(blockRewards)
        coinbaseValue = blockRewards + txFees
        script = Script.verifySignature()

        transaction.addOutput(address, script, coinbaseValue)
        transaction.hash()

        #Include coinbase tx gas used
        totalTxGasUsed += transaction.calculateTxGasUsed()

        block.merkleRoot = MerkleTree.getMerkleRoot(block.transactions, False)
        block.witnessRoot = MerkleTree.getMerkleRoot(block.transactions, True)

        blockGasLimit = previousIndexBlock.gasLimit + (previousIndexBlock.gasLimit * (1 / 1024))
        blockGasLimit = math.ceil(blockGasLimit)

        block.gasLimit = blockGasLimit
        block.gasUsed = totalTxGasUsed
        block.nonce = 0
        block.bits = bits
        block.previousHash = previousHash
        return block
def toValue(units):
    return units * Config.getDecimalValue('TRANSACTION_MIN_VALUE')
Exemple #5
0
    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