def test_negative_locktime():
    """
    test for a negative locktime
    """
    trns = make_synthetic_transaction(1)
    trns["locktime"] = -1
    assert tx.validate_transaction(trns) == False
def test_invalid_vout_length():
    """
    test that the vout list length is not greater than
    the maximum allowed by the Helium config
    """
    trn = make_synthetic_transaction(11)
    assert tx.validate_transaction(trn) == False
def test_missing_transactionid():
    """
    test missing transaction id
    """
    trns = make_synthetic_transaction(1)
    del trns["transactionid"]
    assert tx.validate_transaction(trns) == False
def test_zero_version_number():
    """
    test zero version no
    """
    trns = make_synthetic_transaction(1)
    trns["version"] = 0
    assert tx.validate_transaction(trns) == False
def test_bad_transactionid():
    """
    test transaction id with an invalid length
    """
    trns = make_synthetic_transaction(1)
    # replace the last char with an invalid char
    trns["transactionid"] = trns["transactionid"][:-1] + "z"
    assert tx.validate_transaction(trns) == False
def test_empty_scriptSig_pubkey():
    """
    test that ScriptSig public key field is not empty
    """
    txn = make_synthetic_transaction(2)
    indices = randomize_list(txn['vin'])

    for ctr in list(range(len(indices))):
        txn['vin'][indices[ctr]]['ScriptSig'][1] = ''
        assert tx.validate_transaction(txn) == False
def test_negative_output_value(monkeypatch):
    """
    test a negative transaction output value 
    """
    txn = make_synthetic_transaction(4)

    indices = randomize_list(txn['vout'])
    ctr = secrets.randbelow(len(indices))

    monkeypatch.setitem(txn['vout'][indices[ctr]], 'value', -456712)
    assert tx.validate_transaction(txn) == False
def test_scriptpubkey_length_error():
    """
    test that ScriptPubKey list has a valid length
    """
    txn = make_synthetic_transaction(4)
    indices = randomize_list(txn['vout'])

    for ctr in list(range(len(indices))):
        element = txn['vout'][indices[ctr]]['ScriptPubKey'][1] 
        txn['vout'][indices[ctr]]['ScriptPubKey'].append(element)
        assert tx.validate_transaction(txn) == False
def test_no_prev_tx_reference():
    """
    test that the transaction's vin element has a
    reference to a previous transaction.
    """
    txn = make_synthetic_transaction(1)
    indices = randomize_list(txn["vin"]) 
    
    for ctr in list(range(len(indices))):
        txn['vin'][indices[ctr]]['txid'] = ""
        assert tx.validate_transaction(txn) == False
def test_invalid_txid_length():
    """
    test a previous transaction id for length
    """
    txn = make_synthetic_transaction(2)
    id = rcrypt.make_uuid()
    id = "p" + id[0:]
    indices = randomize_list(txn['vin'])

    ctr = secrets.randbelow(len(indices))
    txn['vin'][indices[ctr]]['txid'] = id
    assert tx.validate_transaction(txn) == False
def receive_transaction(transaction: "dictionary") -> "bool":

     # verify that the incoming transaction is valid
     if tx.validate_transaction(transaction) == False:
        logging.debug('receive_transaction: miner received an invalid transaction')
        return False

     # do not add the transaction if it already exists in the mempool
     for trans in mempool:
         if trans == transaction: return True

     # add the transaction to the mempool
     mempool.append(transaction)
     return True
def add_block(block: "dictionary") -> "bool":
    """
    add_block: adds a block to the blockchain. Receives a block.
    The block attributes are checked for validity and each transaction in the block is
    tested for validity. If there are no errors, the block is written to a file as a 
    sequence of raw bytes. Then the block is added to the blockchain.
    The chainstate database and the blk_index databases are updated.
    returns True if the block is added to the blockchain and False otherwise
    """
    try:
        # validate the received block parameters
        if validate_block(block) == False:
            raise(ValueError("block validation error"))

        # validate the transactions in the block
        # update the chainstate database
     
        for trx in block['tx']:
            # first transaction in the block is a coinbase transaction
            if block["height"] == 0 or block['tx'][0] == trx: zero_inputs = True
            else: zero_inputs = False

            if tx.validate_transaction(trx, zero_inputs) == False: 
                raise(ValueError("transaction validation error"))
                    
            if hchaindb.transaction_update(trx) == False:
                raise(ValueError("chainstate update transaction error"))

        # serialize the block to a file
        if (serialize_block(block) == False):
                raise(ValueError("serialize block error"))

        # add the block to the blockchain in memory
        blockchain.append(block)

        #  update the blk_index
        for transaction in block['tx']:
            blockindex.put_index(transaction["transactionid"], block["height"])

    except Exception as err:
        print(str(err))
        logging.debug('add_block: exception: ' + str(err))
        return False

    return True
def receive_mined_block(block):

    # verify the proof of work
    if proof_of_work(block) == False:
        logging.debug("receive_mined_block: no proof of work")
        return False

    # Verify that the block is valid. Note that because of the False parameter 
    # we are not validating the value of the block's previousblockhash value
    ret = bchain.validate_block(block, False)    
    if ret == False:
        logging.debug('receive_mined_block: block is invalid')
        return False

    # validate transactions in the block
    for trans in block['tx']:
        if tx.validate_transaction(trans) == False:
            logging.debug("receive_mined_block: invalid transaction")
            return False


    # test if block is in the received_blocks list
    for blk in received_blocks:
        if blk == block: return False

    #test if block is in the primary or secondary blockchains
    if len(bchain.blockchain) > 0:
       if block == bchain.blockchain[-1]: return False          
   
    if len(bchain.blockchain) > 1:
       if block == bchain.blockchain[-2]: return False          
       
    if len(bchain.secondary_blockchain) > 0:
       if block == bchain.secondary_blockchain[-1]: return False          

    if len(bchain.secondary_blockchain) > 1:
       if block == bchain.secondary_blockchain[-2]: return False          

    # add the block to the blocks_received list
    received_blocks.append(block)
    
    return True
Example #14
0
def receive_transaction(transaction: "dictionary") -> "bool":
    """
    receives a transaction propagating over the P2P cryptocurrency network
    this function executes in a thread
    """
    # do not add the transaction if:
    #     it already exists in the mempool
    #     it exists in the Chainstate
    #     it is invalid

    try:
        # if the transaction is in the mempool, return
        for trans in mempool:
            if trans == transaction: return False

        # do not add the transaction if it has been accounted for in
        # the chainstate database.
        tx_fragment_id = transaction["transactionid"] + "_" + "0"

        if hchaindb.get_transaction(tx_fragment_id) != False:
            return True

        # verify that the incoming transaction is valid
        if len(transaction["vin"]) > 0: zero_inputs = False
        else: zero_inputs = True
        if tx.validate_transaction(transaction, zero_inputs) == False:
            raise (ValueError("invalid transaction received"))

        # add the transaction to the mempool
        mempool.append(transaction)

        # place the transaction on the P2P network for further
        # propagation
        propagate_transaction(transaction)

    except Exception as err:
        logging.debug('receive_transaction: exception: ' + str(err))
        return False

    return True
def test_type_transaction():
    """
    test transaction type
    """
    assert tx.validate_transaction([]) == False