コード例 #1
0
def merkle_root(buffer: "List", start: "bool" = False) -> "bool or string":
    """
    merkle_tree: computes the merkle root for a list of transactions.
    Receives a list of transactions and a boolean flag to indicate whether 
    the function has been called for the first time or whether it is a
    recursive call from within the function.
    Returns the root of the merkle tree or False if there is an error.
    """
    try:
        # if start is False then we verify have a list of SHA-256 hashes
        if start == False:
            for value in buffer:
                if rcrypt.validate_SHA256_hash(value) == False: 
                    raise(ValueError("tx list SHA-256 validation failure"))
                buflen = len(buffer)     
                if buflen != 1 and len(buffer)%2 != 0:
                    buffer.append(buffer[-1])

        # make the merkle leaf nodes if we are entering the function 
        # for the first time 
        if start == True:
            tmp = buffer[:] 
            tmp = make_leaf_nodes(tmp)
            if tmp == False: return False
            buffer = tmp[:] 
              
        # if buffer has one element, we have the merkle root 
        if (len(buffer) == 1): 
            return buffer[0]     

        # construct the list of parent nodes from the child nodes
        index = 0
        parents = []

        while index < len(buffer):
            tmp = rcrypt.make_SHA256_hash(buffer[index] + buffer[index+1])
            parents.append(tmp)
            index += 2

        # recursively call merkle tree
        ret = merkle_root(parents, False)

    except Exception as error:
        logging.error("exception: %s: %s", "merkle_root",error)
        return False

    return ret
コード例 #2
0
def validate_vin(vin_element: 'dictionary') -> bool:
    """
    tests whether a vin element has valid values
    returns True if the vin is valid, False otherwise
    """
    try:
        if vin_element['vout_index'] < 0: return False
        if len(vin_element['ScriptSig']) != 2: return False
        if len(vin_element['ScriptSig'][0]) == 0: return False
        if len(vin_element['ScriptSig'][1]) == 0: return False

        if rcrypt.validate_SHA256_hash(vin_element['txid']) == False:
            raise (ValueError("txid is invalid"))

    except Exception as err:

        print("validate_vin exception" + str(err))
        logging.debug('validate_vin: exception: ' + str(err))
        return False

    return True
コード例 #3
0
def test_validate_SHA256_hash(digest, value):
    """
    validate whether a valid SHA-256 message digest format is generated
    """
    assert rcrypt.validate_SHA256_hash(digest) == value
コード例 #4
0
def test_make_SHA256_hash(input_string, value):
    """
    test that a SHA-256 message digest is created
    """
    ret = rcrypt.make_SHA256_hash(input_string)
    assert rcrypt.validate_SHA256_hash(ret) == value
コード例 #5
0
def validate_transaction(trans: "dictionary",
                         zero_inputs: "boolean" = False) -> "bool":
    """
    verifies that a transaction has valid values.  
    receives a transaction and a predicate.
    zero_inputs is True if the transacton is in the genesis block or if the transaction
    is a coinbase transaction, otherwise zero_inputs is False.
.

    The following transaction validation tests are performed:
        (1)  The required attributes are present. 
        (2)  The locktime is greater than or equal to zero.
        (3)  The version number is greater than zero.
        (4)  The transaction ID has a valid format.
        (5)  The vin list have positive length.
        (6)  The vin list is not greater than the maximum allowable length.
        (7)  The vin list has valid format.
        (8)  The vout list has positive length.
        (9)  The vout list is not greater than the maximum allowable length.
        (8)  The vout list elements have valid format.
        (9)  The The vout list implements a p2pkhash script.
        (10) The reference to a previous transaction ID is valid.
        (11) The total value spent is less than or equal to the total spendable value.
        (12) The spent values are greater than zero.
        (13) The index values in the vin array reference valid elements in the
             vout array of the previous transaction.
        (14) The transaction inputs can be spent
        (15) The genesis block does not have any inputs
    """

    try:
        if type(trans) != dict:
            raise (ValueError("not dict type"))

        # Verify that required attributes are present
        if trans.get("transactionid") == None: return False
        if 'version' not in trans: return False
        if trans['locktime'] == None: return False
        if trans['vin'] == None: return False
        if trans['vout'] == None: return False

        # validate the format of the transaction id
        if rcrypt.validate_SHA256_hash(trans['transactionid']) == False:
            raise (ValueError("not SHA-256 hash error"))

        # validate the transaction version and locktime values
        if trans['version'] != hconfig.conf["VERSION_NO"]:
            raise (ValueError("improper version no"))

        if trans['locktime'] < 0:
            raise (ValueError("invalid locktime"))

        # genesis block or a coinbase transaction do not have any inputs
        if zero_inputs == True and len(trans["vin"]) > 0:
            raise (ValueError("genesis block cannot have inputs"))

        # validate the vin elements
        # there are no vin inputs for a genesis block transaction
        spendable_fragments = []

        for vin_element in trans['vin']:
            if validate_vin(vin_element) == False: return False
            tx_key = vin_element['txid'] + '_' + str(vin_element['vout_index'])

            spendable_fragment = prevtx_value(tx_key)

            if spendable_fragment == False:
                raise (ValueError("invalid spendable input for transaction"))
            else:
                spendable_fragments.append(spendable_fragment)

        # validate the transaction's vout list
        if len(trans['vout']) > hconfig.conf['MAX_OUTPUTS'] or len(
                trans['vout']) <= 0:
            raise (ValueError("vout list length error"))

        for vout_element in trans['vout']:
            if validate_vout(vout_element) == False: return False

        # validate the transaction fee
        if zero_inputs == False:
            if (transaction_fee(trans, spendable_fragments)) == False:
                return False

        # test that the transaction inputs are unlocked
        ctr = 0
        for vin in trans['vin']:
            if unlock_transaction_fragment(vin,
                                           spendable_fragments[ctr]) == False:
                raise (ValueError("failed to unlock transaction"))
            ctr += 1

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

    return True
コード例 #6
0
def test_computes_previous_block_hash(monkeypatch):
    """
    test previous block hash has correct format
    """
    val = hblockchain.blockheader_hash(block_0)
    rcrypt.validate_SHA256_hash(val) == True