Skip to content
This repository has been archived by the owner on Aug 23, 2020. It is now read-only.

[DRAFT] Test: (In)valid bundle regression: split test #1807

Open
wants to merge 25 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion python-regression/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
author='DyrellC',
packages=['util','tests'],
install_requires=[
'pyota',
'pyota[pow]',
'aloe',
'pyyaml',
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ Feature: Test Bootstrapping With LS
|keys |values |type |
|state |True |bool |


Scenario: Old transactions are pruned
Takes a node with a large db and transaction pruning enabled, and checks to make sure that the transactions below
the pruning depth are no longer present.
Expand Down
112 changes: 111 additions & 1 deletion python-regression/tests/features/machine3/3_transaction_tests.feature
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ Feature: Test transaction confirmation
| keys | values | type |
| states | False | boolListMixed |


Scenario: Value Transactions are confirmed
In this test, a number of value transactions will be made to a specified node.
A milestone will be issued that references these transactions, and this should
Expand Down Expand Up @@ -87,3 +86,114 @@ Feature: Test transaction confirmation
| keys | values | type |
| states | False | boolListMixed |

Scenario: Valid value transfer bundle that doesnt affect ledger state
We want to ascertain that ledger state is always calculated correctly.
Even in the presence of a bundle that handles funds but without changing address

Then "1" transaction is issued on "nodeA-m3" with:
|keys |values |type |
|address |TEST_ADDRESS |staticValue |
|value |0 |int |
|tag |ZERO9VALUE |string |

Then a value bundle which moves funds back and forth from an address is generated referencing the previous transaction with:
|keys |values |type |
|seed |THE_BANK |staticList |
|value |100 |int |
|tag |FAKE9VALUE |string |

Then a transaction is issued referencing the previous transaction
|keys |values |type |
|seed |THE_BANK |staticList |
|address |TEST_ADDRESS |staticValue |
|value |11 |int |
|tag |VALUE9TRANSACTION |string |

#In the default test, the latest sent index will be 52. The next milestone issued should be 53.
When a milestone is issued with index 53 and references:
|keys |values |type |
|transactions |previousTransaction |responseValue |

#Give the node time to solidify the milestone
And we wait "15" second/seconds

Given "getBalances" is called on "nodeA-m3" with:
|keys |values |type |
|addresses |FAKE_SPEND_ADDRESSES |staticList |

Then the response for "getBalances" should return with:
|keys |values |type |
|balances |0 |int |

Scenario: Double spend only affects the ledger once
We want to ascertain that ledger state is always calculated correctly.
Even in the presence of double spend, the confirmed state should have spent only once

Then "1" transaction is issued on "nodeA-m3" with:
|keys |values |type |
|address |TEST_ADDRESS |staticValue |
|value |0 |int |
|tag |ZERO9VALUE |string |

Then a double spend is generated referencing the previous transaction with:
|keys |values |type |
|seed |DOUBLE_SPEND_SEED |staticValue |
|value |1000 |int |
|tag |FAKE9VALUE |string |

#In the default test, the latest sent index will be 53. The next milestone issued should be 54.
When a milestone is issued with index 54 and references:
|keys |values |type |
|transactions |firstDoubleSpend |responseValue |

#Give the node time to solidify the milestone
And we wait "15" second/seconds

Given "getBalances" is called on "nodeA-m3" with:
|keys |values |type |
|addresses |DOUBLE_SPEND_ADDRESSES |staticList |

Then the response for "getBalances" should return with:
|keys |values |type |
|balances |1000 0 |intList |

Scenario: Split transaction over 2 bundles
We want to ascertain that ledger state is always calculated correctly.
Even when there is a transaction used in 2 different bundles. A split bundle is
a bundle that uses a transaction from another bundle.

Then "1" transaction is issued on "nodeA-m3" with:
|keys |values |type |
|address |TEST_ADDRESS |staticValue |
|value |0 |int |
|tag |ZERO9VALUE |string |

Then a split bundle is generated referencing the previous transaction with:
|keys |values |type |
|seed |SPLIT_BUNDLE_SEED |staticValue |
|value |2000 |int |
|tag |FAKE9VALUE |string |
|address |SPLIT_TO_ADDRESS |staticValue |

Then a transaction is issued referencing the previous transaction
|keys |values |type |
|seed |THE_BANK |staticList |
|address |TEST_ADDRESS |staticValue |
|value |11 |int |
|tag |VALUE9TRANSACTION |string |

#In the default test, the latest sent index will be 54. The next milestone issued should be 55.
When a milestone is issued with index 55 and references:
|keys |values |type |
|transactions |previousTransaction |responseValue |

#Give the node time to solidify the milestone
And we wait "15" second/seconds

Given "getBalances" is called on "nodeA-m3" with:
|keys |values |type |
|addresses |SPLIT_TO_ADDRESS |staticList |

Then the response for "getBalances" should return with:
|keys |values |type |
|balances |2000 |intList |
4 changes: 2 additions & 2 deletions python-regression/tests/features/machine3/config.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defaults: &transaction_tests_config_files
db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Transactions_Tests_db.tar
db_checksum: 756237276479da4b01deaa0c1211ca65a4c8ec6f081452ea7e8153648c53bd67
db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/TransactionsTestsDb.tar
db_checksum: 4d94ae65b38ea0f8461d5ec24e5140b20eb86590d54e87e30aa9a72b26a131be
iri_args: ['--testnet-coordinator',
'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
'--milestone-start',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ Feature: Test API calls on Machine 1
Given "getBalances" is called on "nodeA-m4" with:
|keys |values |type |
|addresses |TEST_EMPTY_ADDRESS |staticList |
|threshold |100 |int |
|threshold |100 |int |

Then the response for "getBalances" should return with:
|keys |values |type |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,12 @@ def check_response_for_value(step, api_call):
expected_values = {}
args = step.hashes
api_utils.prepare_options(args, expected_values)

for expected_value_key in expected_values:
if expected_value_key in response_values:
expected_value = expected_values[expected_value_key]
response_value = response_values[expected_value_key]

if isinstance(response_value, list) and api_call != 'getTrytes' and api_call != 'getInclusionStates':
if isinstance(response_value, list) and isinstance(expected_value, list) != True and api_call != 'getTrytes' and api_call != 'getInclusionStates':
response_value = response_value[0]

assert expected_value == response_value, "The expected value {} does not match""\
Expand Down
136 changes: 126 additions & 10 deletions python-regression/tests/features/steps/transaction_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from util import static_vals as static
from util import logger as log
from util.test_logic import api_test_logic as api_utils
from util.transaction_bundle_logic import transaction_logic as transactions
from util.transaction_bundle_logic import bundle_scenario_setup, transaction_logic as transactions
from util.milestone_logic import milestones
from time import sleep

Expand Down Expand Up @@ -31,7 +31,79 @@ def generate_transaction_and_attach(step, node):

setattr(static, "TEST_STORE_TRANSACTION", transaction.get('trytes'))
return transaction

@step(r'Then a value bundle which moves funds back and forth from an address is generated referencing the previous transaction with:')
def fake_value_transaction(step):
"""
Creates a bundle that both receives and sends value between 2 addresses.
This makes the total ledger change zero
:param step.hashes: A gherkin table present in the feature file specifying the
arguments and the associated type.
"""

node = world.config['nodeId']
previous = world.responses['evaluate_and_send'][node][0]

seed = get_step_value(step, "seed")[0]
api = api_utils.prepare_api_call(node, seed=seed)

logger.info('Finding Transactions')
gtta_transactions = api.get_transactions_to_approve(depth=3)

trunk = previous
branch = gtta_transactions['branchTransaction']

value = int(get_step_value(step, "value"))
tag = get_step_value(step, "tag")

bundle = bundle_scenario_setup.create_fake_transfer_bundle(api, seed, tag, value)

argument_list = {'trunk_transaction': trunk, 'branch_transaction': branch,
'trytes': bundle.as_tryte_strings(), 'min_weight_magnitude': 14}

bundle = transactions.attach_store_and_broadcast(api, argument_list)
transaction_trytes = bundle.get('trytes')
transaction_hash = Transaction.from_tryte_string(transaction_trytes[0])
set_previous_transaction(node, [transaction_hash.hash])

@step(r'a double spend is generated referencing the previous transaction with:')
def create_double_spent(step):
"""
Creates two bundles which both try to spend the same address.
This test fails if they are both confirmed
:param step.hashes: A gherkin table present in the feature file specifying the
arguments and the associated type.
"""
node = world.config['nodeId']
previous = world.responses['evaluate_and_send'][node][0]
seed = get_step_value(step, "seed")
api = api_utils.prepare_api_call(node, seed=seed)

tag = get_step_value(step, "tag")[0]
value = int(get_step_value(step, "value"))

response = api.get_inputs(start=0, stop=1, threshold=0, security_level=2)
addressFrom = response['inputs'][0]

bundles = bundle_scenario_setup.create_double_spend_bundles(seed, addressFrom, static.DOUBLE_SPEND_ADDRESSES[0], static.DOUBLE_SPEND_ADDRESSES[1], tag, value)

logger.info('Finding Transactions')
gtta_transactions = api.get_transactions_to_approve(depth=3)
trunk1 = previous
branch1 = gtta_transactions['branchTransaction']
trunk2 = previous
branch2 = gtta_transactions['trunkTransaction']

argument_list = {'trunk_transaction': trunk1, 'branch_transaction': branch1,
'trytes': bundles[0].as_tryte_strings(), 'min_weight_magnitude': 14}
firstDoubleSpend = Transaction.from_tryte_string( transactions.attach_store_and_broadcast(api, argument_list).get('trytes')[0] )

argument_list = {'trunk_transaction': trunk2, 'branch_transaction': branch2,
'trytes': bundles[1].as_tryte_strings(), 'min_weight_magnitude': 14}
secondDoubleSpend = Transaction.from_tryte_string( transactions.attach_store_and_broadcast(api, argument_list).get('trytes')[0] )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


set_previous_transaction(node, [firstDoubleSpend.hash])
set_world_object(node, "firstDoubleSpend", [firstDoubleSpend.hash])

@step(r'an inconsistent transaction is generated on "([^"]+)"')
def create_inconsistent_transaction(step, node):
Expand All @@ -55,10 +127,36 @@ def create_inconsistent_transaction(step, node):
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
set_world_object(node, 'inconsistentTransactions', transaction_hash.hash)

@step(r'a split bundle is generated referencing the previous transaction with:')
def create_split_bundle(step):
"""
Create a bundle that reuses the last transaction from another bundle in its own

This test fails if we do not find the correct balance after confirming the second bundle(reattachment)
:param step.hashes: A gherkin table present in the feature file specifying the
arguments and the associated type.
"""
node = world.config['nodeId']
previous = world.responses['evaluate_and_send'][node][0]
seed = get_step_value(step, "seed")
api = api_utils.prepare_api_call(node, seed=seed)

tag = get_step_value(step, "tag")[0]
value = int(get_step_value(step, "value"))
addressTo = get_step_value(step, "address")[0]

response = api.get_inputs(start=0, stop=1, threshold=0, security_level=3)
addressFrom = response['inputs'][0]

bundles = bundle_scenario_setup.create_split_bundles(api, seed, addressFrom, addressTo, static.SPLIT_REST_ADDRESS, tag, value, previous)

api.broadcast_and_store(bundles[0].as_tryte_strings())
api.broadcast_and_store(bundles[1].as_tryte_strings())

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codacy Issue found: Trailing whitespace

set_previous_transaction(node, [bundles[1][0].hash])
set_world_object(node, "reattachSplitSpend", [bundles[1][0].hash])

@step(r'a stitching transaction is issued on "([^"]*)" with the tag "([^"]*)"')
def issue_stitching_transaction(step, node, tag):
Expand All @@ -84,9 +182,7 @@ def issue_stitching_transaction(step, node, tag):

# 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]
set_previous_transaction(node, bundlehash['hashes'][0])


@step(r'a transaction is issued referencing the previous transaction')
Expand All @@ -99,13 +195,17 @@ def reference_stitch_transaction(step):

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':
options = {'trunk_transaction': stitch[0], 'branch_transaction': branch, 'trytes':
transaction_bundle.as_tryte_strings(), 'min_weight_magnitude': 9}

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

set_previous_transaction(node, [transaction_hash.hash])


@step(r'"(\d+)" transactions are issued on "([^"]+)" with:')
@step(r'"(\d+)" transactions? (?:is|are) issued on "([^"]+)" with:')
def issue_multiple_transactions(step, num_transactions, node):
transactions_to_store = []
world.responses['evaluate_and_send'] = {}
Expand Down Expand Up @@ -193,6 +293,22 @@ def issue_a_milestone(step, index, node):
milestone_hash2 = Transaction.from_tryte_string(milestone['trytes'][1]).hash
world.config['latestMilestone'][node] = [milestone_hash, milestone_hash2]

def set_previous_transaction(node, txHash):
set_world_object(node, 'previousTransaction', txHash)

def set_world_object(node, objectName, value):
if objectName not in world.responses:
world.responses[objectName] = {}
world.responses[objectName][node] = value

def get_step_value(step, key_name):
for arg_index, arg in enumerate(step.hashes):
if arg['keys'] == key_name :
if arg['type'] == "staticValue" or arg['type'] == "staticList":
return getattr(static, arg['values'])
else:
return arg['values']
return 0

def wait_for_update(index, api):
updated = False
Expand Down
10 changes: 10 additions & 0 deletions python-regression/util/static_vals.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@
"THIS9TEST9ADDRESS9HAS9ONE9HUNDRED9IOTA9NINE99999999999999999999999999999999999999",
"THIS9TEST9ADDRESS9HAS9ONE9HUNDRED9IOTA9TEN999999999999999999999999999999999999999"]

FAKE_SPEND_ADDRESSES = ["CTCFZQHZ9MVOQVKOASZJFFQYCYSUZOIXFUDGBNQQWNUVNYXJVOYHMQPJVVKNICNRCUDEWXJIEDKXCLVWY",
"DRDSKHQ9XHRFMXXHTGZPGUIKWVQYSDQDPUTHEUXEROVUTAQDRCJIWLARCTAQHMYAUVNYNVCEBD9QNC9SD"]

DOUBLE_SPEND_SEED = "THIS9DOUBLE9SPEND9ADDRESS9HAS9ONE9THOUSAND9IOTA9999999999999999999999999999999999"
DOUBLE_SPEND_ADDRESSES = ["YIYPLJDLF9MNSCAORRGFNJNDXOFQZXEXTPDD9TROXZCJPY9AWDTIJY9RKIPLUDPFPLKZRP9NKHPKBJAYA",
"DHGTQLJRYMJTHSYGKCAJYMMWHYYM9XKGYMMKYLEUWOQOAMORGTSWMRHVZ9VKPRTDUGUPBKRB9WMQOBRHY"]

SPLIT_BUNDLE_SEED = "THIS9SPLIT9BUNDLE9ADDRESS9HAS9ONE9THOUSAND9IOTA9999999999999999999999999999999999"
SPLIT_TO_ADDRESS = ["9JMLFZINDAQ99YYDWSYDZMADO9PHWTIZOXHKTSNYFMFMFOQVNAWCATWECJBRYRGPHMBZHYAPTQFFEWZKC"]
SPLIT_REST_ADDRESS = "USUXAWWGZSEJICZQJSMJSEYBBDOPGBJFEOYAMDMXKZAOPDDJBMUXIETNYXGRFWWROIOTRDYODJEALZRE9"

SIDE_TANGLE_ADDRESS = "SIDE9TANGLE9999999999999999999999999999999999999999999999999999999999999999999999"
STITCHING_ADDRESS = "STITCHING9TRANSACTIONS99999999999999999999999999999999999999999999999999999999999"
Expand Down
Loading