Beispiel #1
0
 def call(self, isLocal, callback):
     result = None
     fromAccount = Accounts.getAccountByAddress(self.fromAddress)
     if fromAccount != None:
         if isLocal:
             _output = PersistentStorage.get(self.script, True)
             if _output == None:
                 unspentTransactionScript = UXTO.getUnspentTransactionScript(
                     self.script)
                 if unspentTransactionScript != None:
                     _output = unspentTransactionScript.output
             if _output != None:
                 result = self.handleLocalScript(fromAccount, _output,
                                                 False)
         else:
             result = MemoryPool.addUnconfirmedTransaction(
                 fromAccount, self.script, self.value, self.gasLimit,
                 self.gasPrice, None, self.parameters)
             try:
                 result = DataType.toHex(result)
             except:
                 pass
     if result != None:
         callback(JSONRPC.createResultObject(result, self.id))
     else:
         self.onFailure(callback)
Beispiel #2
0
 def verifyUnlockingScripts(self, transaction):
     for txIn in transaction.inputs:
         coin = UXTO.getUnspentTransactionCoin(txIn.outpoint)
         txOut = coin.output
         #Standard transactions and contract call
         if not RVM.run(transaction, txIn, txOut):
             return False
     for txOut in transaction.outputs:
         if txOut.hasExtScript():
             #Deploy contract
             if not RVM.run(transaction, None, txOut, deploy=True):
                 return False
         elif UXTO.getUnspentTransactionScript(txOut.address) != None:
             #Send value to contract
             if not RVM.run(transaction, None, txOut, deploy=True):
                 return False
     return True
    def sign(self):
        signatures = {}

        for txIn in self.inputs:
            unspentTransactionCoin = UXTO.getUnspentTransactionCoin(
                txIn.outpoint)
            unspentTransactionOutput = unspentTransactionCoin.output

            outputHash = self.hashOutput(txIn, unspentTransactionOutput)

            account = None
            if unspentTransactionOutput.hasExtScript():
                account = Accounts.getAccountByAddress(txIn.witness[0])
            else:
                account = Accounts.getAccountByAddress(
                    unspentTransactionOutput.address)
            if account.isMultiSig():
                _signatures = []
                for public in account.public:
                    _account = Accounts.getAccountByPublic(public)
                    signature = _account.sign(outputHash)
                    _signatures.append(signature)
                signatures[txIn.outpoint] = _signatures
            else:
                signature = account.sign(outputHash)
                signatures[txIn.outpoint] = signature

        for txIn in self.inputs:
            unspentTransactionCoin = UXTO.getUnspentTransactionCoin(
                txIn.outpoint)

            unspentTransactionOutput = unspentTransactionCoin.output

            account = None
            if unspentTransactionOutput.hasExtScript():
                account = Accounts.getAccountByAddress(txIn.witness[0])
            else:
                account = Accounts.getAccountByAddress(
                    unspentTransactionOutput.address)
            if account.isMultiSig():
                signatures = signatures[txIn.outpoint]
                for signature, public in zip(signatures, account.public):
                    txIn.initWitness(signature, public)
            else:
                signature = signatures[txIn.outpoint]
                txIn.initWitness(signature, account.public)
Beispiel #4
0
    def extcodehash(self):
        address = self.pop()

        unspentTransactionScript = UXTO.getUnspentTransactionScript(address)
        txOut = unspentTransactionScript.output
        script = txOut.script

        _hash = 0 if script == None else Crypto.generateHash(script, Config.getValue('SHA3_HASHING_ALGORITHM'))
        self.stack.append(_hash)
Beispiel #5
0
 def verifyCoinbaseMaturity(self, transaction):
     for txIn in transaction.inputs:
         coin = UXTO.getUnspentTransactionCoin(txIn.outpoint)
         if coin.isCoinbase():
             chainHeadIndexBlock = Chain.getChain().getChainHeadIndexBlock()
             if Config.getIntValue(
                     'COINBASE_MATURITY'
             ) > chainHeadIndexBlock.height - coin.height:
                 return False
     return True
Beispiel #6
0
    def extcodecopy(self):
        address = self.pop()
        destOffset = self.popAsInt()
        offset = self.popAsInt()
        length = self.popAsInt()

        unspentTransactionScript = UXTO.getUnspentTransactionScript(address)
        txOut = unspentTransactionScript.output

        self.memory[destOffset:destOffset + length] = txOut.script[offset:offset + length]
Beispiel #7
0
 def get(self, callback=None):
     contracts = []
     for contract in Contracts.getContracts():
         confirmedBalance = 0
         unspentTransactionScript = UXTO.getUnspentTransactionScript(
             contract.address)
         if unspentTransactionScript != None:
             txOut = unspentTransactionScript.output
             confirmedBalance = txOut.value
         confirmedBalance = Units.toValue(confirmedBalance)
         confirmedBalance = DataType.asFloat(confirmedBalance)
         address = Address.to0xAddress(contract.address)
         contracts.append({'address': address, 'balance': confirmedBalance})
     callback(JSONRPC.createResultObject(contracts, self.id))
Beispiel #8
0
 def verifySumInputOutputValues(self, transaction):
     inputValueTotal = 0
     for txIn in transaction.inputs:
         coin = UXTO.getUnspentTransactionCoin(txIn.outpoint)
         txOut = coin.output
         inputValueTotal += txOut.value
     outputValueTotal = 0
     for txOut in transaction.outputs:
         outputValueTotal += txOut.value
     if inputValueTotal < outputValueTotal:
         return False
     if inputValueTotal - outputValueTotal <= 0:
         return False
     return True
Beispiel #9
0
    def verifyWitness(self, transaction):
        for txIn in transaction.inputs:
            witness = txIn.witness
            if witness == None or len(witness) == 0:
                return False
            unspentTransactionCoin = UXTO.getUnspentTransactionCoin(
                txIn.outpoint)
            txOut = unspentTransactionCoin.output
            if txOut.hasExtScript():
                if len(witness) < Config.getIntValue(
                        'EXTENSION_INPUT_WITNESS_LEN'):
                    return False
            if txOut.isMultiSig() or txOut.isAtomicSwap(
            ) or txOut.isAtomicLock():
                if len(witness) % 2 == 0:
                    publicKeys = witness[::2]
                    signatures = witness[1::2]
                    for publicKey, signature in zip(publicKeys, signatures):
                        '''
                            The unlocking script (witness) can only push numbers on the stack
                        '''
                        if signature == None or len(
                                signature) != Config.getIntValue(
                                    'SIGNATURE_LEN'):
                            return False
                        if publicKey == None or len(
                                publicKey) != Config.getIntValue('PUBLIC_LEN'):
                            return False
                else:
                    return False
            else:
                if len(witness) != Config.getIntValue('INPUT_WITNESS_LEN'):
                    return False
                '''
                    The unlocking script (witness) can only push numbers on the stack
                '''
                if witness[0] == None or len(
                        witness[0]) != Config.getIntValue('SIGNATURE_LEN'):
                    return False
                if witness[1] == None or len(
                        witness[1]) != Config.getIntValue('PUBLIC_LEN'):
                    return False

            if txOut.hasExtScript():
                address = txOut.address
                if address == None or len(address) != Config.getIntValue(
                        'ADDRESS_LEN'):
                    return False
        return True
 def calculateTxFee(self):
     txInFee = 0
     for txIn in self.inputs:
         prevCoin = UXTO.getUnspentTransactionCoin(txIn.outpoint)
         if prevCoin != None:
             prevTxOut = prevCoin.output
             txInFee += prevTxOut.value
     txOutFee = 0
     for txOut in self.outputs:
         txOutFee += txOut.value
     txFee = txInFee - txOutFee
     if txFee < 0:
         return 0
     else:
         return txFee
Beispiel #11
0
 def verifyNonCoinbaseTransactions(self, block):
     for transaction in block.transactions:
         if not transaction.isCoinbase():
             '''     
                 For each input, look in the main branch to find the referenced output transaction. Reject if the output transaction is missing for any input.
                 For each input, if the referenced output has already been spent by a transaction in the main branch, reject
             '''
             if not self.txValidator.verifyUxtoReferencedOutput(transaction):
                 return False
             
             '''
                 For each input, if we are using the nth output of the earlier transaction, but it has fewer than n+1 outputs, reject.
             '''
             for txIn in transaction.inputs:
                 outpoint = txIn.outpoint
                 unspentTransactionCoin = UXTO.getUnspentTransactionCoin(outpoint)
                 if unspentTransactionCoin.txOutputSize <= outpoint.outputIndex:
                     return False
             
             '''
                 For each input, if the referenced output transaction is coinbase (i.e. only 1 input, with hash=0, n=-1), 
                 it must have at least COINBASE_MATURITY (100) confirmations; else reject.
             '''
             if not self.txValidator.verifyCoinbaseMaturity(transaction):
                 return False
                                  
             '''
                 Verify crypto signatures for each input; reject if any are bad
             '''
             if not self.txValidator.verifyUnlockingScripts(transaction):
                 return False
             
             '''
                 Using the referenced output transactions to get input values, check that each input value, as well as the sum, are in legal money range
             '''
             if not self.txValidator.verifyAllowedInputValueRange(transaction):
                 return False
                
             '''         
                 Reject if the sum of input values < sum of output values
             '''
             if not self.txValidator.verifySumInputOutputValues(transaction):
                 return False
     return True
Beispiel #12
0
    def verifyAddress(self, transaction):
        for txOut in transaction.outputs:
            address = txOut.address
            if address == None or len(address) != Config.getIntValue(
                    'ADDRESS_LEN'):
                return False
            if txOut.hasExtScript():
                if UXTO.getUnspentTransactionScript(address) == None:
                    outpointBytes = bytearray()
                    for inputs in transaction.inputs:
                        outpoint = inputs.outpoint
                        outpointBytes.extend(outpoint.serialize())

                    if address != Crypto.generateAddress(outpointBytes):
                        return False
                else:
                    #contract exists and address is not available
                    return False
        return True
Beispiel #13
0
 def verifyAllowedInputValueRange(self, transaction):
     inputValueTotal = 0
     for txIn in transaction.inputs:
         coin = UXTO.getUnspentTransactionCoin(txIn.outpoint)
         txOut = coin.output
         if txOut.hasExtScript():
             if txOut.value < 0:
                 return False
         elif txOut.value <= 0:
             return False
         inputValueTotal += txOut.value
     '''
         Check coin supply limit
     '''
     coinSupplyLimit = Config.getIntValue('COIN_SUPPLY_LIMIT')
     if coinSupplyLimit > 0:
         if inputValueTotal > coinSupplyLimit:
             return False
     return True
Beispiel #14
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
Beispiel #15
0
 def extcodesize(self):
     address = self.pop()
     unspentTransactionScript = UXTO.getUnspentTransactionScript(address)
     txOut = unspentTransactionScript.output
     size = len(txOut.script)
     self.stack.append(size)
Beispiel #16
0
 def balance(self):
     address = self.pop()
     address = DataType.serialize(address)
     print('balance', address)
     unspentTransactionScript = UXTO.getUnspentTransactionScript(address)
     self.stack.append(unspentTransactionScript.output.value)
Beispiel #17
0
 def _merge(self):
     unspentTransactionScript = UXTO.getUnspentTransactionScript(self.output.address)
     txOut = unspentTransactionScript.output
     self.overrideScript = txOut.script
     self.overrideValue = txOut.value + self.output.value
     self.merge = True
    def addBlock(self, block):
        if self.blkValidator.validate(block):
            try:
                self.acquireBlockLock()
            
                blockHash = block.hash()
                blockHashBytes = DataType.serialize(blockHash)
                
                if self.index.get(blockHashBytes) == None:
                    if not OrphanManager.hasBlock(blockHash):
                        bits = block.bits
                        previousChainWork = None
                        previousHash = block.previousHash
                        blockGasLimit = block.gasLimit
                        blockHeight = 0
                        
                        chainHeadBlock = self.getChainHeadBlock()
                        chainHeadIndexBlock = self.getIndexBlockByHash(self.CHAIN_HEAD_INDEX)
                        previousIndexBlock = self.getIndexBlockByHash(previousHash)
                        
                        if chainHeadIndexBlock == None:
                            chainHeadIndexBlock = IndexBlock()
                        if previousIndexBlock != None:
                            blockHeight = previousIndexBlock.height + 1
                            previousChainWork = previousIndexBlock.chainWork
                            
                        if blockHash == Config.getBytesValue('GENESIS_BLOCK_HASH'):
                            previousChainWork = Config.getIntValue('GENESIS_BLOCK_CHAIN_WORK', 16)
                        
                        '''        
                            For case 1, adding to main branch:
                        '''
                        if previousHash == chainHeadIndexBlock.previousHash or blockHash == Config.getBytesValue('GENESIS_BLOCK_HASH'):                
                            '''
                                For all but the coinbase transaction, apply the following:
                            '''
                            if not self.blkValidator.verifyNonCoinbaseTransactions(block):
                                return False
                                 
                            '''
                                Reject if coinbase value > sum of block creation fee and transaction fees
                            '''   
                            if not self.blkValidator.verifyCoinbaseValue(block):
                                return False
                                    
                            for transaction in block.transactions:
                                for txIn in transaction.inputs:
                                    UXTO.removeUnspentTransactionCoin(txIn.outpoint)
                                uxtoOutputs = []
                                uxtoOutputs.extend(transaction.outputs)
                                uxtoOutputs.extend(transaction.internalOutputs)
                                txOutputSize = 0
                                for txOut in uxtoOutputs:
                                    if txOut.store:
                                        txOutputSize += 1
                                outputIndex = 0
                                for txOut in uxtoOutputs:
                                    UXTO.removeStaleUnspentTransactionScript(txOut)
                                    if txOut.store:
                                        coin = Coin()
                                        coin.output = txOut
                                        coin.txOutputSize = txOutputSize
                                        coin.height = blockHeight
                                        coin.coinbase = transaction.isCoinbase()
                                        UXTO.addUnspentTransactionCoin(Outpoint(transaction.hash(), outputIndex), coin)
                                        outputIndex += 1
                                        '''
                                            For each transaction, "Add to wallet if mine"
                                        '''

                                '''
                                    For each transaction in the block, delete any matching transaction from the transaction pool
                                '''
                                MemoryPool.removeTransaction(transaction)
                                
                            chainHeadIndexBlock.chainWork = Bits.getChainworkFromBits(previousChainWork, bits)
                            chainHeadIndexBlock.previousHash = blockHash
                            chainHeadIndexBlock.gasLimit = blockGasLimit
                            chainHeadIndexBlock.height = blockHeight
                            self.index.set(self.CHAIN_HEAD_INDEX, chainHeadIndexBlock.serialize())
                        else:
                            blockChainWork = Bits.getChainworkFromBits(previousChainWork, bits)
                            chainHeadWork = chainHeadIndexBlock.chainWork
                            
                            hasNewMainChain = blockChainWork > chainHeadWork
                            
                            if hasNewMainChain:
                                '''
                                    For case 3, a side branch becoming the main branch:
                                '''
                            else:
                                '''
                                    For case 2, adding to a side branch, we don't do anything.
                                '''
                
                            if hasNewMainChain:
                                '''
                                    Find the fork block on the main branch which this side branch forks off of
                                '''
                                forkBlockHash = self.searchForkBlockHash(previousIndexBlock, chainHeadIndexBlock)
                                
                                '''
                                    Redefine the main branch to only go up to this fork block
                                    
                                    We will set new main chain head below
                                '''
                                
                                isNewMainChainValid = True
                                
                                '''
                                    For each block on the side branch, from the child of the fork block to the leaf, add to the main branch:
                                '''
                                prevBlock = self.getBlockByHash(block.previousHash)
                                while prevBlock.hash() != forkBlockHash:
                                    '''
                                        Do "branch" checks 3-11
                                    '''
                                    '''
                                        3) Transaction list must be non-empty
                                    '''
                                    if not self.blkValidator.verifyTransactionsNonEmpty(prevBlock):
                                        isNewMainChainValid = False
                                    
                                    '''
                                        4) Block hash must satisfy claimed nBits proof of work
                                    '''
                                    if not self.blkValidator.validateBlockBits(prevBlock.serializeHeader(), prevBlock.bits):
                                        isNewMainChainValid = False
                                    
                                    '''
                                        5) Block timestamp must not be more than two hours in the future
                                    '''
                                    if not self.blkValidator.verifyFutureTimestamp(prevBlock):
                                        isNewMainChainValid = False
                                        
                                    '''
                                        6) First transaction must be coinbase (i.e. only 1 input, with hash=0, n=-1), the rest must not be
                                    '''
                                    if not self.blkValidator.verifyInitialCoinbaseTransaction(prevBlock):
                                        isNewMainChainValid = False
                                        
                                    '''
                                        7) For each transaction, apply "tx" checks 2-4
                                            2) Make sure neither in or out lists are empty
                                            3) Size in bytes <= TRANSACTION_SIZE_LIMIT
                                            4) Each output value, as well as the total, must be in legal money range
                                    '''
                                    for transaction in prevBlock.transactions:
                                        if not self.txValidator.verifyInputOutputNonEmpty(transaction):
                                            isNewMainChainValid = False
                                        if not self.txValidator.verifyTransactionSizeLimit(transaction):
                                            isNewMainChainValid = False
                                        if not self.txValidator.verifyAllowedOutputValueRange(transaction):
                                            isNewMainChainValid = False
                                        
                                        '''
                                            8) For the coinbase (first) transaction, scriptSig length must be 2-100
                                        '''
                                        if not self.blkValidator.verifyCoinbaseWitnessLength(transaction):
                                            isNewMainChainValid = False
                                        
                                        '''
                                            9) Reject if sum of transaction sig opcounts > MAX_BLOCK_SIGOPS
                                        '''
                                        if not self.blkValidator.verifyMaxBlockSigOps(transaction):
                                            isNewMainChainValid = False
                                        
                                    '''
                                        10) Verify Merkle hash
                                    '''
                                    if not self.blkValidator.verifyMerkleHash(prevBlock):
                                        isNewMainChainValid = False
                                        
                                    '''
                                        Verify Witness hash
                                    '''
                                    if not self.blkValidator.verifyWitnessHash(prevBlock):
                                        isNewMainChainValid = False
                                        
                                    '''
                                        11) Check if prev block (matching prev hash) is in main branch or side branches. If not, add this to orphan blocks, 
                                        then query peer we got this from for 1st missing orphan block in prev chain; done with block
                                    '''
                                    if blockHash != Config.getBytesValue('GENESIS_BLOCK_HASH') and self.getBlockByHash(prevBlock.previousHash) == None:
                                        OrphanManager.addBlock(prevBlock)
                                        isNewMainChainValid = False
                                
                                    '''
                                        For all but the coinbase transaction, apply the following:
                                    '''
                                    if not self.blkValidator.verifyNonCoinbaseTransactions(prevBlock):
                                        isNewMainChainValid = False
                                    
                                    '''
                                        Reject if coinbase value > sum of block creation fee and transaction fees
                                    '''   
                                    if not self.blkValidator.verifyCoinbaseValue(prevBlock):
                                        isNewMainChainValid = False
                                    
                                    '''
                                        (If we have not rejected):
                                    '''
                                    if not isNewMainChainValid:
                                        break
                                    
                                    '''         
                                        For each transaction, "Add to wallet if mine"
                                    '''
                                        
                                    prevBlock = self.getBlockByHash(prevBlock.previousHash)
                                
                                '''
                                    If we reject at any point, leave the main branch as what it was originally, done with block
                                '''
                                if isNewMainChainValid:
                                    chainHeadIndexBlock.chainWork = blockChainWork
                                    chainHeadIndexBlock.previousHash = blockHash 
                                    chainHeadIndexBlock.gasLimit = blockGasLimit
                                    chainHeadIndexBlock.height = blockHeight
                                    self.index.set(self.CHAIN_HEAD_INDEX, chainHeadIndexBlock.serialize())
                                    
                                    '''
                                        For each block in the old main branch, from the leaf down to the child of the fork block:
                                    '''
                                    oldBlock = chainHeadBlock
                                    while oldBlock.hash() != forkBlockHash:
                                        '''
                                            For each non-coinbase transaction in the block:
                                        '''
                                        for transaction in oldBlock.transactions:
                                            if not transaction.isCoinbase():
                                                '''
                                                    Apply "tx" checks 2-9
                                                '''
                                                isTxValid = True
                                                
                                                '''
                                                    2) Make sure neither in or out lists are empty
                                                '''
                                                if not self.txValidator.verifyInputOutputNonEmpty(transaction):
                                                    isTxValid = False
                                                
                                                '''
                                                    3) Size in bytes <= TRANSACTION_SIZE_LIMIT
                                                '''
                                                if not self.txValidator.verifyTransactionSizeLimit(transaction):
                                                    isTxValid = False
                                                
                                                '''
                                                    4) Each output value, as well as the total, must be in legal money range
                                                '''
                                                if not self.txValidator.verifyAllowedOutputValueRange(transaction):
                                                    isTxValid = False
                                                
                                                '''
                                                    5) Make sure none of the inputs have hash=0, n=-1 (coinbase transactions)
                                                '''
                                                if not self.txValidator.verifyInputsNonCoinbase(transaction):
                                                    isTxValid = False
                                                
                                                '''
                                                    6) size in bytes >= 100[2]
                                                '''
                                                if not self.txValidator.verifyTransactionRequiredSize(transaction):
                                                    isTxValid = False
                                                
                                                '''
                                                    sig opcount <= 2[3]
                                                    3) The number of signature operands in the signature (no, that is not redundant) for standard transactions will never exceed two
                                                    7) Reject "nonstandard" transactions: scriptSig doing anything other than pushing numbers on the stack, 
                                                    or script not matching the two usual forms[4]
                                                '''
                                                if not self.txValidator.verifyAddress(transaction):
                                                    isTxValid = False
                                                if not self.txValidator.verifyExtraData(transaction):
                                                    isTxValid = False
                                                if not self.txValidator.verifyScript(transaction):
                                                    isTxValid = False
                                                if not self.txValidator.verifyWitness(transaction):
                                                    isTxValid = False
                                                
                                                '''
                                                    8) Reject if we already have matching tx in the pool,
                                                    except in step 8, only look in the transaction pool for duplicates, not the main branch
                                                '''
                                                if not self.txValidator.verifyTransactionDuplicateInPool(transaction):
                                                    isTxValid = False
                                                
                                                '''
                                                    9) For each input, if the referenced output exists in any other tx in the pool, reject this transaction
                                                '''
                                                if not self.txValidator.verifyTxOutputDuplicateInPool(transaction):
                                                    isTxValid = False
                                                
                                                '''
                                                    Add to transaction pool if accepted, else go on to next transaction
                                                '''
                                                if isTxValid:
                                                    MemoryPool.addSignedTransaction(transaction)

                                            outputIndex = 0
                                            for txOut in transaction.outputs:
                                                UXTO.removeUnspentTransactionCoin(Outpoint(transaction.hash(), outputIndex))
                                                outputIndex += 1

                                        oldBlock = self.getBlockByHash(oldBlock.previousHash)
                                    
                                    '''
                                        For each block in the new main branch, from the child of the fork node to the leaf:
                                    '''
                                    newMainBranchBlocks = []
                                        
                                    prevBlock = block
                                    while prevBlock.hash() != forkBlockHash:
                                        newMainBranchBlocks.insert(0, prevBlock)
                                        prevBlock = self.getBlockByHash(prevBlock.previousHash)
                                        
                                    for newMainBranchBlock in newMainBranchBlocks:
                                        newMainBranchBlockHash = newMainBranchBlock.hash()
                                        newMainBranchIndexBlock = None
                                        if newMainBranchBlockHash == blockHash:
                                            newMainBranchIndexBlock = chainHeadIndexBlock
                                        else:
                                            newMainBranchIndexBlock = self.getIndexBlockByHash(newMainBranchBlockHash)
                                        for transaction in newMainBranchBlock.transactions:
                                            for txIn in transaction.inputs:
                                                UXTO.removeUnspentTransactionCoin(txIn.outpoint)
                                            uxtoOutputs = []
                                            uxtoOutputs.extend(transaction.outputs)
                                            uxtoOutputs.extend(transaction.internalOutputs)
                                            txOutputSize = 0
                                            for txOut in uxtoOutputs:
                                                if txOut.store:
                                                    txOutputSize += 1
                                            outputIndex = 0
                                            for txOut in uxtoOutputs:
                                                UXTO.removeStaleUnspentTransactionScript(txOut)
                                                if txOut.store:
                                                    coin = Coin()
                                                    coin.output = txOut
                                                    coin.txOutputSize = txOutputSize
                                                    coin.height = newMainBranchIndexBlock.height
                                                    coin.coinbase = transaction.isCoinbase()
                                                    UXTO.addUnspentTransactionCoin(Outpoint(transaction.hash(), outputIndex), coin)
                                                    outputIndex += 1
                                                    '''
                                                        For each transaction, "Add to wallet if mine"
                                                    '''

                                            '''
                                                For each transaction in the block, delete any matching transaction from the transaction pool
                                            '''
                                            MemoryPool.removeTransaction(transaction)
                        '''
                            (If we have not rejected):
                        '''
                        self.storage.set(blockHashBytes, block.serialize())

                        blockHeightKey = "{0}{1}{2}".format(self.BLOCK_HEIGHT_KEY, '_', blockHeight)
                        blockHeightKey = DataType.serialize(blockHeightKey)
                        self.index.set(blockHeightKey, blockHashBytes)
                        
                        indexBlock = IndexBlock()
                        indexBlock.chainWork = Bits.getChainworkFromBits(previousChainWork, bits)
                        indexBlock.previousHash = previousHash 
                        indexBlock.gasLimit = blockGasLimit
                        indexBlock.height = blockHeight
                        self.index.set(blockHashBytes, indexBlock.serialize())
        
                        '''
                            Relay block to our peers
                        '''
                        Sync.inv(InventoryType.BLOCK, blockHash)
                    
                    '''
                        For each orphan block for which this block is its prev, run all these steps (including this one) recursively on that orphan
                    '''
                    self.syncOrphanBlocks()
                    
                    return True
            finally:
                self.releaseBlockLock()
        '''
            For each orphan block for which this block is its prev, run all these steps (including this one) recursively on that orphan
        '''
        self.syncOrphanBlocks()
            
        '''     
            If we rejected, the block is not counted as part of the main branch
        '''
        return False
def createUnconfirmedTransaction(fromAccount,
                                 toAddress,
                                 value,
                                 gasLimit,
                                 gasPrice,
                                 script=None,
                                 parameters=None):
    transaction, outpoints = createNewUnconfirmedTransaction(
        fromAccount, value, gasLimit, gasPrice)
    if transaction != None:
        if script != None or parameters != None:
            #smart contract
            if script == None:
                #call
                witness = []
                witness.append(fromAccount.address)
                witness.extend(parameters)

                unspentTransactionOutpoint = UXTO.getUnspentTransactionOutpointByAddress(
                    toAddress)

                transaction.addInput(unspentTransactionOutpoint.txId,
                                     unspentTransactionOutpoint.outputIndex,
                                     witness)

                if value > 0:
                    #contract value transfer
                    _script = Script.merge()
                    transaction.addOutput(toAddress, _script, value)
            else:
                #deploy
                outpointBytes = bytearray()
                for outpoint in outpoints:
                    outpointBytes.extend(outpoint.serialize())
                extensionAddress = Crypto.generateAddress(outpointBytes)

                _script = bytearray()
                _script.append(Config.getIntValue("EXTENSION_SCRIPT_VERSION"))
                _script.extend(script)
                _script = DataType.serialize(_script)

                extraData = None
                if len(parameters) > 0:
                    extraData = parameters
                    extraData.append(fromAccount.address)

                transaction.addOutput(extensionAddress, _script, value,
                                      extraData)
        else:
            _script = None
            unspentTransactionScript = UXTO.getUnspentTransactionScript(
                toAddress)
            if unspentTransactionScript != None:
                #contract value transfer
                _script = Script.merge()
            if _script == None:
                #value
                _script = Script.verifySignature()
            transaction.addOutput(toAddress, _script, value)

        transaction.sign()

    return transaction
Beispiel #20
0
 def verifyUxtoReferencedOutput(self, transaction):
     for txIn in transaction.inputs:
         outpoint = txIn.outpoint
         if not UXTO.hasUnspentTransactionCoin(outpoint):
             return False
         return True