def make_neighbors(step, node1, node2):
    host1 = world.machine['nodes'][node1]['podip']
    port1 = world.machine['nodes'][node1]['clusterip_ports']['gossip-udp']
    host2 = world.machine['nodes'][node2]['podip']
    port2 = world.machine['nodes'][node2]['clusterip_ports']['gossip-udp']

    hosts = [host1, host2]
    ports = [port1, port2]

    api1 = api_utils.prepare_api_call(node1)
    api2 = api_utils.prepare_api_call(node2)

    response1 = api1.get_neighbors()
    response2 = api2.get_neighbors()
    neighbors1 = list(response1['neighbors'])
    neighbors2 = list(response2['neighbors'])
    host = hosts[0]
    port = ports[0]
    address1 = "udp://" + str(host) + ":" + str(port)
    host = hosts[1]
    port = ports[1]
    address2 = "udp://" + str(host) + ":" + str(port)

    logger.debug("Checking if nodes are paired")

    containsNeighbor = False
    for neighbor in range(len(neighbors1)):
        if neighbors1[neighbor]['address']:
            containsNeighbor = True
            logger.debug("Neighbor found")

    if containsNeighbor == False:
        api1.add_neighbors([address2.decode()])
        api2.add_neighbors([address1.decode()])
        logger.debug("Nodes paired")

    containsNeighbor = False
    for neighbor in range(len(neighbors2)):
        if neighbors2[neighbor]['address']:
            containsNeighbor = True
            logger.debug("Neighbor found")

    if containsNeighbor == False:
        api2.add_neighbors([address1.decode()])
        api1.add_neighbors([address2.decode()])
        logger.debug("Nodes paired")

    response = api1.get_neighbors()
    logger.info(response)
    response = api2.get_neighbors()
    logger.info(response)
def find_transactions_from_address(step):
    logger.info('Finding milestones')
    node = world.config['nodeId']

    api = api_utils.prepare_api_call(node)
    transactions = api.find_transactions(addresses=[step.multiline])
    world.responses['findTransactions'] = transactions
def issue_stitching_transaction(step, node, tag):
    world.config['nodeId'] = node
    world.config['stitchTag'] = tag

    api = api_utils.prepare_api_call(node)
    logger.info('Finding Transactions')
    side_tangle_transaction = static.SIDE_TANGLE_TRANSACTIONS[0]
    gtta_transactions = api.get_transactions_to_approve(depth=3)

    trunk = side_tangle_transaction
    branch = gtta_transactions['branchTransaction']
    stitching_address = static.STITCHING_ADDRESS

    logger.debug('Trunk: ' + str(trunk))
    logger.debug('Branch: ' + str(branch))

    bundle = transactions.create_transaction_bundle(stitching_address, tag, 0)
    trytes = bundle[0].as_tryte_string()
    sent_transaction = api.attach_to_tangle(trunk, branch, [trytes], 14)
    api.broadcast_and_store(sent_transaction.get('trytes'))

    # Finds transaction hash and stores it in world
    bundlehash = api.find_transactions(bundles=[bundle.hash])
    if 'previousTransaction' not in world.responses:
        world.responses['previousTransaction'] = {}
    world.responses['previousTransaction'][node] = bundlehash['hashes'][0]
def find_transaction_is_called(step, nodeName):
    logger.debug(nodeName)
    api = api_utils.prepare_api_call(nodeName)
    logger.info("Searching for Transaction with the tag: {} on {}".format(
        world.config['tag'], nodeName))
    response = api.find_transactions(tags=[world.config['tag']])
    world.config['findTransactionResponse'] = response
def threaded_call(step, apiCall, node):
    logger.info("Creating thread for {}".format(apiCall))
    world.config['apiCall'] = apiCall
    world.config['nodeId'] = node
    arg_list = step.hashes

    options = {}
    api_utils.prepare_options(arg_list, options)
    api = api_utils.prepare_api_call(node)

    def make_call(node, arg_list):
        response = api_utils.fetch_call(apiCall, arg_list['api'],
                                        arg_list['options'])
        arg_list['responses'][apiCall] = {}
        arg_list['responses'][apiCall][node] = response
        return response

    args = {
        node: {
            'api': api,
            'options': options,
            'responses': world.responses
        }
    }
    future_results = pool.start_pool(make_call, 1, args)

    if 'future_results' not in world.config:
        world.config['future_results'] = {}
    world.config['future_results'][apiCall] = future_results
def make_neighbors(step, node1, node2):
    """
    Ensures that the specified nodes are neighbored with one another.

    :param node1: The identifier for the first node (ie nodeA)
    :param node2: The identifier for the second node (ie nodeB)
    """
    neighbor_candidates = [node1, node2]
    neighbor_info = {}

    for node in neighbor_candidates:
        host = world.machine['nodes'][node]['podip']
        port = world.machine['nodes'][node]['clusterip_ports']['gossip-udp']
        api = api_utils.prepare_api_call(node)
        response = api.get_neighbors()
        neighbor_info[node] = {
            'api': api,
            'node_neighbors': list(response['neighbors']),
            'address': str(host) + ":" + str(port)
        }

    logger.info('Checking neighbors for {}'.format(node1))
    neighbors.check_if_neighbors(neighbor_info[node1]['api'],
                                 neighbor_info[node1]['node_neighbors'],
                                 neighbor_info[node2]['address'])

    logger.info('Checking neighbors for {}'.format(node2))
    neighbors.check_if_neighbors(neighbor_info[node2]['api'],
                                 neighbor_info[node2]['node_neighbors'],
                                 neighbor_info[node1]['address'])
def issue_multiple_transactions(step, num_transactions, node):
    transactions_to_store = []
    world.responses['evaluate_and_send'] = {}
    world.config['nodeId'] = node
    # Placeholder values for seed if present
    seed_value = ""
    seed_type = ""

    for arg_index, arg in enumerate(step.hashes):
        if arg['keys'] == "seed" and arg['type'] == "staticList":
            seed_value = arg['values']
            seed_type = arg['type']

    for iteration in range(int(num_transactions)):
        seed = ""
        if seed_value != "" and seed_type == "staticList":
            seed = getattr(static, seed_value)[iteration]

        api = api_utils.prepare_api_call(node, seed=seed)

        logger.info('Sending Transaction {}'.format(iteration + 1))
        transaction = transactions.evaluate_and_send(api, seed, step.hashes)
        transaction_hash = Transaction.from_tryte_string(
            transaction.get('trytes')[0]).hash
        transactions_to_store.append(transaction_hash)

    world.responses['evaluate_and_send'][node] = transactions_to_store
    logger.info("Transactions generated and stored")
def generate_transaction_and_attach(step, node):
    """
    Creates a zero value transaction with the specified arguments.

    :param node: The node that the transaction will be generated on.
    :param step.hashes: A gherkin table present in the feature file specifying the
                        arguments and the associated type.
    """
    arg_list = step.hashes
    world.config['nodeId'] = node
    world.config['apiCall'] = 'attachToTangle'

    options = {}
    api = api_utils.prepare_api_call(node)
    api_utils.prepare_options(arg_list, options)

    transaction_args = {}
    for key in options:
        transaction_args[key] = options.get(key)
    api_utils.prepare_transaction_arguments(transaction_args)

    transaction = transactions.create_and_attach_transaction(
        api, transaction_args)
    api.broadcast_and_store(transaction.get('trytes'))

    assert len(
        transaction['trytes']) > 0, "Transaction was not created correctly"

    world.responses['attachToTangle'] = {}
    world.responses['attachToTangle'][node] = transaction
    logger.info('Transaction Sent')

    setattr(static, "TEST_STORE_TRANSACTION", transaction.get('trytes'))
def issue_a_milestone_with_reference(step, index):
    """
    This method issues a milestone with a given index and reference transaction. The input transaction pointer should
    always have the key "transactions", but may be a pointer to either a staticValue list stored in staticValues.py, or
    a responseList for "findTransactions".

    :param index: The index of the milestone you are issuing
    """
    node = world.config['nodeId']
    address = static.TEST_BLOWBALL_COO
    api = api_utils.prepare_api_call(node)

    reference_transaction = transactions.fetch_transaction_from_list(
        step.hashes, node)
    logger.info('Issuing milestone {}'.format(index))
    milestone = milestones.issue_milestone(address, api, index,
                                           reference_transaction)

    if 'latestMilestone' not in world.config:
        world.config['latestMilestone'] = {}

    milestone_hash = Transaction.from_tryte_string(milestone['trytes'][0]).hash
    milestone_hash2 = Transaction.from_tryte_string(
        milestone['trytes'][1]).hash
    world.config['latestMilestone'][node] = [milestone_hash, milestone_hash2]
def generate_transaction_and_attach(step, node):
    arg_list = step.hashes
    world.config['nodeId'] = node
    world.config['apiCall'] = 'attachToTangle'
    options = {}
    api = api_utils.prepare_api_call(node)

    api_utils.prepare_options(arg_list, options)
    addresses = options.get('address')
    value = options.get('value')

    transaction = ProposedTransaction(address=Address(addresses[0]),
                                      value=value)

    bundle = ProposedBundle()
    bundle.add_transaction(transaction)
    bundle.finalize()
    trytes = str(bundle[0].as_tryte_string())

    gtta = api.get_transactions_to_approve(depth=3)
    branch = str(gtta['branchTransaction'])
    trunk = str(gtta['trunkTransaction'])

    sent = api.attach_to_tangle(trunk, branch, [trytes], 9)
    world.responses['attachToTangle'] = {}
    world.responses['attachToTangle'][node] = sent
    logger.info('Transaction Sent')

    setattr(static_vals, "TEST_STORE_TRANSACTION", sent.get('trytes'))
def create_inconsistent_transaction(step, node):
    """
    Creates an inconsistent transaction by generating a zero value transaction that references
    a non-existent transaction as its branch and trunk, thus not connecting with any other part
    of the tangle.

    :param node: The node that the transaction will be generated on.
    """
    world.config['nodeId'] = node
    api = api_utils.prepare_api_call(node)
    trunk = static.NULL_HASH
    branch = trunk
    trytes = static.EMPTY_TRANSACTION_TRYTES

    argument_list = {
        'trunk_transaction': trunk,
        'branch_transaction': branch,
        'trytes': [trytes],
        'min_weight_magnitude': 14
    }

    transaction = transactions.attach_store_and_broadcast(api, argument_list)
    transaction_trytes = transaction.get('trytes')
    transaction_hash = Transaction.from_tryte_string(transaction_trytes[0])

    if 'inconsistentTransactions' not in world.responses:
        world.responses['inconsistentTransactions'] = {}
    world.responses['inconsistentTransactions'][node] = transaction_hash.hash
Exemple #12
0
def reference_stitch_transaction(step):
    node = world.config['nodeId']
    stitch = world.responses['previousTransaction'][node]
    referencing_address = static.REFERENCING_ADDRESS

    api = api_utils.prepare_api_call(node)

    transaction_bundle = transactions.create_transaction_bundle(referencing_address, 'REFERENCE9TAG', 0)

    def transactions_to_approve(node, arg_list):
        response = api_utils.fetch_call('getTransactionsToApprove', arg_list['api'], {'depth': 3})
        arg_list['responses']['getTransactionsToApprove'][node] = response
        return response

    gtta_results = pool.start_pool(transactions_to_approve, 1, {node: {'api': api, 'responses': world.responses}})
    branch = pool.fetch_results(gtta_results[0], 30)
    options = {'trunk': stitch, 'branch': branch, 'trytes': transaction_bundle.as_tryte_strings(),
               'min_weight_magnitude': 9}

    def make_transaction(node, arg_list):
        response = transactions.attach_store_and_broadcast(arg_list['api'], options)
        arg_list['responses']['attachToTangle'][node] = response
        return response

    transaction_results = pool.start_pool(make_transaction, 1, {node: {'api': api, 'responses': world.responses}})
    pool.fetch_results(transaction_results[0], 30)
Exemple #13
0
def check_stitch_consistency(step):
    logger.info('Checking consistency of stitching transaction')
    node = world.config['nodeId']
    api = tests.prepare_api_call(node)

    transaction = world.responses['previousTransaction']

    timeout = False

    def consistency(responses):
        consistency_response = api.check_consistency(tails=[transaction])
        responses['checkConsistency'] = consistency_response
        return

    try:
        r = threading.Thread(target=consistency, args=(world.responses, ))
        r.setDaemon(True)
        r.start()
        r.join(timeout=60)

        if r.is_alive():
            raise ValueError(TIMEOUT_ERROR)

    except ValueError as error:
        logger.info('Failed')
        logger.info(error)
        timeout = True

    if timeout != True:
        logger.debug('Response: {}'.format(
            world.responses['checkConsistency']))
        logger.info('Consistency check completed, request did not time out')
    else:
        raise ValueError(TIMEOUT_ERROR)
def call_getTrytes(step, node, hash):
    api = api_utils.prepare_api_call(node)
    testHash = getattr(static_vals, hash)
    response = api.get_trytes([testHash])
    logger.debug("Call may not have responded correctly: \n%s", response)
    assert type(response) is dict
    world.responses['getTrytes'] = {}
    world.responses['getTrytes'][node] = response
Exemple #15
0
def issue_several_milestones(step, num_milestones):
    node = world.config['nodeId']
    api = api_utils.prepare_api_call(node)

    latest_milestone_index = int(
        api.get_node_info()['latestSolidSubtangleMilestoneIndex'])
    logger.info('Latest Milestone Index: {}'.format(latest_milestone_index))
    start_index = latest_milestone_index + 1
    end_index = start_index + int(num_milestones)

    for index in range(start_index, end_index):
        issue_a_milestone(step, index, node)
        #Give node a moment to update solid milestone
        wait_for_update(index, api)
def create_inconsistent_transaction(step, node):
    world.config['nodeId'] = node
    api = api_utils.prepare_api_call(node)
    branch = getattr(static_vals, "NULL_HASH")
    trunk = branch
    trytes = getattr(static_vals, "EMPTY_TRANSACTION_TRYTES")

    transaction = api.attach_to_tangle(trunk, branch, [trytes], 14)
    transaction_trytes = transaction.get('trytes')
    api.store_transactions(transaction_trytes)
    transaction_hash = Transaction.from_tryte_string(transaction_trytes[0])
    logger.info(transaction_hash.hash)

    if 'inconsistentTransactions' not in world.responses:
        world.responses['inconsistentTransactions'] = {}

    world.responses['inconsistentTransactions'][node] = transaction_hash.hash
def check_neighbors(step):
    api = api_utils.prepare_api_call(world.config['nodeId'])
    response = api.getNeighbors()
    containsNeighbor = [False, False]

    for i in response:
        expectedNeighbors = step.hashes
        if type(response[i]) != int:
            for x in range(len(response[i])):
                if expectedNeighbors[0]['neighbors'] == response[i][x][
                        'address']:
                    containsNeighbor[0] = True
                if expectedNeighbors[1]['neighbors'] == response[i][x][
                        'address']:
                    containsNeighbor[1] = True

    return containsNeighbor
Exemple #18
0
def reference_stitch_transaction(step):
    node = world.config['nodeId']
    stitch = world.responses['previousTransaction'][node]
    referencing_address = static.REFERENCING_ADDRESS

    api = api_utils.prepare_api_call(node)

    transaction_bundle = transactions.create_transaction_bundle(
        referencing_address, 'REFERENCE9TAG', 0)
    branch = api.get_transactions_to_approve(depth=3)['branchTransaction']
    options = {
        'trunk_transaction': stitch,
        'branch_transaction': branch,
        'trytes': transaction_bundle.as_tryte_strings(),
        'min_weight_magnitude': 9
    }

    transactions.attach_store_and_broadcast(api, options)
def send_transaction(step, tag, nodeName):
    logger.debug('Preparing Transaction...')
    logger.debug('Node: %s', nodeName)
    world.config['tag'] = tag
    api = api_utils.prepare_api_call(nodeName)
    txn = \
        ProposedTransaction(
            address =
            Address(testAddress),
            message = TryteString.from_unicode('Test Transaction propagation'),
            tag = Tag(tag),
            value = 0,
            )

    logger.info("Sending Transaction with tag '{}' to {}...".format(
        tag, nodeName))
    txn_sent = api.send_transfer(depth=3, transfers=[txn])
    logger.debug("Giving the transaction time to propagate...")
    sleep(10)
def spam_call_gtta(step, numTests):
    """Spams getTransactionsToApprove calls a number of times among available nodes in a cluster"""

    start = time()
    node = next(iter(world.machine['nodes']))
    apiCall = 'getTransactionsToApprove'

    world.config['nodeId'] = node
    world.config['apiCall'] = apiCall

    nodes = {}

    for current_node in world.machine['nodes']:
        api = api_utils.prepare_api_call(current_node)
        nodes[current_node] = api

    def run_call(node, api):
        logger.debug('Running Thread on {}'.format(node))
        response = api.get_transactions_to_approve(depth=3)
        return response

    logging.info('Calls being made to %s', node)
    responseVal = []

    args = (nodes)
    future_results = pool.start_pool(run_call, numTests, args)

    i = 0
    for result in future_results:
        i += 1
        if i % 25 == 0:
            logger.info('Fetching result: {}/{}'.format(i, numTests))
        response = pool.fetch_results(result, 30)
        responseVal.append(response)

    logger.info(len(responseVal))
    world.responses[apiCall] = {}
    world.responses[apiCall][node] = responseVal

    end = time()
    time_spent = end - start
    logger.info('Time spent on loop: {}'.format(time_spent))
Exemple #21
0
def reference_stitch_transaction(step):
    node = world.config['nodeId']
    stitch = world.responses['previousTransaction']

    api = tests.prepare_api_call(node)

    timeout = False

    def transactions_to_approve(responses):
        response = api.get_transactions_to_approve(depth=3)
        responses['getTransactionsToApprove'] = response
        return

    try:
        t = threading.Thread(target=transactions_to_approve,
                             args=(world.responses, ))
        t.setDaemon(True)
        t.start()
        t.join(timeout=60)

        if t.is_alive():
            raise ValueError(TIMEOUT_ERROR)

    except ValueError as error:
        logger.info('Failed')
        logger.info(error)
        timeout = True

    if timeout != True:
        branch = world.responses['getTransactionsToApprove'][
            'branchTransaction']

        bundle = transactions.create_transaction_bundle(
            referencing_address, 'REFERENCING9STITCH', 0)

        trytes = bundle[0].as_tryte_string()

        sent_transaction = api.attach_to_tangle(stitch, branch, [trytes], 14)
        api.broadcast_and_store(sent_transaction.get('trytes'))

    else:
        raise ValueError(TIMEOUT_ERROR)
Exemple #22
0
def issue_a_milestone_with_reference(step, index):
    """
    This method issues a milestone with a given index and reference transaction. The input transaction pointer should
    always have the key "transactions", but may be a pointer to either a staticValue list stored in staticValues.py, or
    a responseList for "findTransactions".

    :param index: The index of the milestone you are issuing
    :param step.hashes: Contains a reference pointer for list of transactions to get a reference from
    """
    node = world.config['nodeId']
    address = static.TEST_BLOWBALL_COO
    api = api_utils.prepare_api_call(node)

    reference_transaction = transactions.fetch_transaction_from_list(
        step.hashes, node)
    logger.info('Issuing milestone {}'.format(index))
    milestone = milestones.issue_milestone(address, api, index,
                                           reference_transaction)

    milestones.update_latest_milestone(world.config, node, milestone)
def issue_a_milestone(step, index, node):
    """
    This method issues a milestone with a given index.

    :param index: The index of the milestone you are issuing
    :param node: The node that the milestone will be attached to
    """
    world.config['nodeId'] = node
    address = static.TEST_BLOWBALL_COO
    api = api_utils.prepare_api_call(node)

    logger.info('Issuing milestone {}'.format(index))
    milestone = milestones.issue_milestone(address, api, index)

    if 'latestMilestone' not in world.config:
        world.config['latestMilestone'] = {}

    milestone_hash = Transaction.from_tryte_string(milestone['trytes'][0]).hash
    milestone_hash2 = Transaction.from_tryte_string(
        milestone['trytes'][1]).hash
    world.config['latestMilestone'][node] = [milestone_hash, milestone_hash2]
Exemple #24
0
def generate_transaction_and_attach(step, node):
    """
    Creates a transaction with the specified arguments.

    :param node: The node that the transaction will be generated on.
    :param step.hashes: A gherkin table present in the feature file specifying the
                        arguments and the associated type.
    """
    world.config['nodeId'] = node
    world.config['apiCall'] = 'attachToTangle'

    seed = transactions.check_for_seed(step.hashes)
    api = api_utils.prepare_api_call(node, seed=seed)
    transaction = transactions.evaluate_and_send(api, seed, step.hashes)

    assert len(transaction['trytes']) > 0, "Transaction was not created correctly"
    world.responses['attachToTangle'] = {}
    world.responses['attachToTangle'][node] = transaction

    setattr(static, "TEST_STORE_TRANSACTION", transaction.get('trytes'))
    return transaction
def api_method_is_called(step, apiCall, nodeName):
    """
    This is the general api calling function. There are 3 inputs

    :param apiCAll:     The api call that will be requested
    :param nodeName:    The name identifying the node you would like to make this request on
    :param table:       A gherkin table outlining any arguments needed for the call
                        (See tests/features/machine1/1_api+tests.feature for examples)

        The table parameter is unique in that there are several input types available depending on the call
        being made.
            :type string: Basic string argument, will be taken as is
            :type int: Basic integer argument, will be converted to int before call is made
            :type nodeAddress: Node name identifier, will create address from node configuration
            :type staticValue: Static name identifier, will fetch value from util/static_vals.py
            :type staticList: Same as staticValue, except it places the results into a list
            :type responseValue: Identifier for api call response value
            :type responseList: Same as responseValue, ecept it places the results into a list
            :type bool: Bool argument, returns True or False

    """
    logger.info('%s is called on %s', apiCall, nodeName)
    world.config['apiCall'] = apiCall
    world.config['nodeId'] = nodeName
    arg_list = step.hashes

    options = {}
    api_utils.prepare_options(arg_list, options)

    api = api_utils.prepare_api_call(nodeName)
    response = api_utils.fetch_call(apiCall, api, options)

    assert type(
        response
    ) is dict, 'There may be something wrong with the response format: {}'.format(
        response)

    world.responses[apiCall] = {}
    world.responses[apiCall][nodeName] = response
def threaded_call(step, api_call, node):
    """
    Makes an asynchronous API call on the specified node and stores the future result reference in the
    world.config variable.

    :param api_call: The API call you would like to make.
    :param node: The identifier for the node you would like to run the call on.
    :param step.hashes: A gherkin table present in the feature file specifying the
                        arguments and the associated type.
    """
    logger.info("Creating thread for {}".format(api_call))
    world.config['apiCall'] = api_call
    world.config['nodeId'] = node
    arg_list = step.hashes

    options = {}
    api_utils.prepare_options(arg_list, options)
    api = api_utils.prepare_api_call(node)

    def make_call(node, arg_list):
        response = api_utils.fetch_call(api_call, arg_list['api'],
                                        arg_list['options'])
        arg_list['responses'][api_call] = {}
        arg_list['responses'][api_call][node] = response
        return response

    args = {
        node: {
            'api': api,
            'options': options,
            'responses': world.responses
        }
    }
    future_results = pool.start_pool(make_call, 1, args)

    if 'future_results' not in world.config:
        world.config['future_results'] = {}
    world.config['future_results'][api_call] = future_results