diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000..c7672f85e2
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,58 @@
+# Community Code of Conduct
+
+In the IOTA community, participants from all over the world come together to create. This is made possible by the support, hard work and enthusiasm of thousands of people, including those who create and use the IOTA technology.
+
+This document offers some guidance to ensure IOTA participants can cooperate effectively in a positive and inspiring atmosphere, and to explain how together we can strengthen and support each other.
+
+This Code of Conduct is shared by all contributors and users who engage with the IOTA Foundation team and its community services.
+
+## Overview
+
+This Code of Conduct presents a summary of the shared values and “common sense” thinking in our community. The basic social ingredients that hold our project together include:
+
+- Being considerate
+- Being respectful
+- Being collaborative
+- Being pragmatic
+- Supporting others in the community
+- Getting support from others in the community
+
+This Code of Conduct reflects the agreed standards of behavior for members of the IOTA community, in any social media platform, forum, mailing list, wiki, web site, discord channel, public meeting or private correspondence within the context of the IOTA Foundation team and the IOTA Tangle technology. The community acts according to the standards written down in this Code of Conduct and will defend these standards for the benefit of the community. Leaders of any group, such as moderators of social media groups, mailing lists, discord channels, forums, etc., will exercise the right to suspend access to any person who persistently breaks our shared Code of Conduct.
+
+## Be considerate
+
+Your actions and work will affect and be used by other people and you, in turn, will depend on the work and actions of others. Any decision you take will affect other community members, and we expect you to take those consequences into account when making decisions.
+
+As a user, remember that community members work hard on their part of IOTA and take great pride in it.
+
+## Be respectful
+
+In order for the IOTA community to stay healthy, its members must feel comfortable and accepted. Treating one another with respect is absolutely necessary for this. In a disagreement, in the first instance, assume that people mean well.
+
+We do not tolerate personal attacks, racism, sexism or any other form of discrimination. Disagreement is inevitable, from time to time, but respect for the views of others will go a long way to winning respect for your own view. Respecting other people, their work, their contributions and assuming well-meaning motivation will make community members feel comfortable and safe and will result in motivation and productivity.
+
+We expect members of our community to be respectful when dealing with other contributors, users, and communities. Remember that IOTA is an international project and that you may be unaware of important aspects of other cultures.
+
+## Be collaborative
+
+Your feedback is important, as is its form. Poorly thought out comments can cause pain and the demotivation of other community members, but considerate discussion of problems can bring positive results. An encouraging word works wonders.
+
+## Be pragmatic
+
+The IOTA community is pragmatic and fair. We value tangible results over having the last word in a discussion. We defend our core values like freedom and respectful collaboration, but we don’t let arguments about minor issues get in the way of achieving more important results. We are open to suggestions and welcome solutions regardless of their origin. When in doubt support a solution which helps to get things done over one which has theoretical merits, but isn’t being worked on. Use the tools and methods which help to get the job done. Let decisions be taken by those who do the work.
+
+## Support others in the community
+
+The IOTA community is made strong by mutual respect, collaboration and pragmatic, responsible behavior. Sometimes there are situations where this has to be defended and other community members need help.
+
+If you witness others being attacked, think first about how you can offer them personal support. If you feel that the situation is beyond your ability to help individually, go privately to the victim and ask if some form of official intervention is needed.
+
+When problems do arise, consider respectfully reminding those involved of our shared Code of Conduct as a first action. Leaders are defined by their actions and can help set a good example by working to resolve issues in the spirit of this Code of Conduct before they escalate.
+
+## Get support from others in the community
+
+Disagreements, both political and technical, happen all the time. Our community is no exception to the rule. The goal is not to avoid disagreements or differing views but to resolve them constructively. You should turn to the community to seek advice and to resolve disagreements and where possible consult the team most directly involved.
+
+Think deeply before turning a disagreement into a public dispute. If necessary, request mediation, and try to resolve differences in a less emotional medium. If you do feel that you or your work is being attacked, take your time to think things through before writing heated replies. Consider a 24-hour moratorium if emotional language is being used – a cooling-off period is sometimes all that is needed. If you really want to go a different way, then we encourage you to publish your ideas and your work, so that it can be tried and tested.
+
+This work, "IOTA Community Guidelines", is a derivative of the [Community code of conduct by ownCloud](https://owncloud.org/community/code-of-conduct/), used under [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/). "IOTA Community Guidelines" is licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) by IOTA Foundation.
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 70f4435bb3..8c06f1c68c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,40 +1,118 @@
-## How to contribute to IRI
+# Contribute to IRI
-#### **How should a Pull Request look like**?
-Before creating a PR make sure you have read the entire contributing guideline. Ensure the PR description clearly describes the problem and solution by following the template. It is best to discuss your changes in an issue before creating the PR. A PR should address a **specific concern**. If it addresses more than one concern it **should be split**. Small PRs get merged in faster. Very large PRs are difficult to review and test. This makes them less likely to be merged.
+This document describes how to contribute to IRI.
-#### **Did you find a bug?**
+We encourage everyone with knowledge of IOTA technology to contribute.
-* **Do not open a GitHub issue if the bug is a security vulnerability
- in IRI**, and instead, please contact us via [security@iota.org](mailto:security@iota.org).
+Thanks! :heart:
-* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/iotaledger/iri/issues). You can also look up related issues by a label. For example, if your issue is database-related, filter based on the `C-DB` label and look for related issues. If it's API related, use `C-API` and so on. `C` stands for component. Make sure you skim through the labels to find your category.
+## Do you have a question?
-* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/iotaledger/iri/issues/new). Be sure to include a **title and clear description**, and as much relevant information as possible. Make sure you follow our new issue template. The first part of the issue template is dedicated to reporting bugs, delete the second part. Steps to reproduce are particularly important. Add any relevant log output and screenshots. The easier it will be to reproduce your issue, the more likely it's getting fixed.
+If you have a general or technical question, you can use one of the following resources instead of submitting an issue:
-#### **Did you write a patch that fixes a bug?**
+- [**Developer documentation:**](https://docs.iota.org/) For official information about developing with IOTA technology
+- [**Discord:**](https://discord.iota.org/) For real-time chats with the developers and community members
+- [**IOTA cafe:**](https://iota.cafe/) For technical discussions with the Research and Development Department at the IOTA Foundation
+- [**StackExchange:**](https://iota.stackexchange.com/) For technical and troubleshooting questions
-* [New issues](https://github.com/iotaledger/iri/issues/new) should be used for reporting issues. If you already wrote a patch for an issue that you or someone else reported, make sure you link it to the open issue. You can do this by mentioning the issue number in the comment or description on the PR, for example `#123` to link issue "123".
+## Ways to contribute
-#### **Do you intend to add a new feature or change an existing one?**
+To contribute to IRI on GitHub, you can:
-* Suggest your change as a [new issues](https://github.com/iotaledger/iri/issues/new). Use the second part of the issue template, dedicated to new feature requests and delete the first part. If you plan on implementing the change yourself, start writing the code and submit a PR. Note that the fact that the feature is "code ready" doesn't mean it will get merged. It is advisable to gather feedback for the change first. You are encouraged to start and drive a discussion on [Discord](https://discord.iota.org/). The IRI team also monitors the repo and will provide feedback where relevant.
+- Report a bug
+- Suggest a new feature
+- Build a new feature
+- Contribute to the documentation
-#### **Want to write a regression test for your feature? Or to any other feature that needs a test?**
+## Report a bug
-* Please refer to our current [regression tests](https://github.com/iotaledger/iri/tree/dev/python-regression).
+This section guides you through reporting a bug. Following these guidelines helps maintainers and the community understand the bug, reproduce the behavior, and find related bugs.
+### Before reporting a bug
-#### **Do you have questions about the functioning of IRI nodes, the network or anything IOTA related?**
+Please check the following list:
-* Use our [Discord](https://discordapp.com/invite/fNGZXvh) to join the discussion and ask questions.
+- **Do not open a GitHub issue for [security vulnerabilities](SECURITY.MD)**, instead, please contact us at [security@iota.org](mailto:security@iota.org).
-#### **Do you want to contribute to the IRI documentation?**
+- **Ensure the bug was not already reported** by searching on GitHub under [**Issues**](https://github.com/iotaledger/iri/issues). If the bug has already been reported **and the issue is still open**, add a comment to the existing issue instead of opening a new one. You can also find related issues by their [label](https://github.com/iotaledger/iri/labels?page=1&sort=name-asc). For example, if your issue is database related, filter issues based on the `C-DB` label to look for related ones. `C` stands for component.
-The IOTA documentation is based in the [docs](https://github.com/iotaledger/docs) repo. You are welcome to contribute. Make sure you follow the instructions on adding new docs.
+**Note:** If you find a **Closed** issue that seems similar to what you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
-Thanks! :heart: :heart: :heart:
+### Submitting A Bug Report
-The contribution guidelines are inspired by the Ruby on Rails contribution guidelines.
+To report a bug, [open a new issue](https://github.com/iotaledger/iri/issues/new), and be sure to include as many details as possible, using the template.
-IRI Team
+**Note:** Minor changes such as fixing a typo can but do not need an open issue.
+
+If you also want to fix the bug, submit a [pull request](#pull-requests) and reference the issue.
+
+## Suggest a new feature
+
+This section guides you through suggesting a new feature. Following these guidelines helps maintainers and the community collaborate to find the best possible way forward with your suggestion.
+
+### Before suggesting a new feature
+
+**Ensure the feature has not already been suggested** by searching on GitHub under [**Issues**](https://github.com/iotaledger/iri/issues).
+
+### Suggesting a new feature
+
+To suggest a new feature, talk to the IOTA community and IOTA Foundation members in the #iri-discussion channel on [Discord](https://discord.iota.org/).
+
+If the IRI team approves your feature, the team will create an issue for it.
+
+## Build a new feature
+
+This section guides you through building a new feature. Following these guidelines helps give your feature the best chance of being approved and merged.
+
+### Before building a new feature
+
+Make sure to discuss the feature in the #iri-discussion channel on [Discord](https://discord.iota.org/).
+
+Otherwise, your feature may not be approved at all.
+
+### Building a new feature
+
+To build a new feature, check out a new branch based on the `dev` branch, and be sure to consider the following:
+
+- If the feature has a public facing API, make sure to document it, using Javadoc code comments
+
+- Where necessary, please write regression tests for your feature. Refer to our current [regression tests](https://github.com/iotaledger/iri/tree/dev/python-regression) for guidance.
+
+## Contribute to the IRI documentation
+
+The IRI documentation is hosted on https://docs.iota.org, which is built from content in the [documentation](https://github.com/iotaledger/documentation) repository.
+
+Please see the [guidelines](https://github.com/iotaledger/documentation/CONTRIBUTING.md) on the documentation repository for information on how to contribute to the documentation.
+
+## Pull requests
+
+This section guides you through submitting a pull request (PR). Following these guidelines helps give your PR the best chance of being approved and merged.
+
+### Before submitting a pull request
+
+When creating a pull request, please follow these steps to have your contribution considered by the maintainers:
+
+- A pull request should have exactly one concern (for example one feature or one bug). If a PR address more than one concern, it should be split into two or more PRs.
+
+- A pull request can be merged only if it references an open issue
+
+ **Note:** Minor changes such as fixing a typo can but do not need an open issue.
+
+- All code should be well tested and follow the [code styleguide](STYLEGUIDE.md)
+
+### Submitting a pull request
+
+The following is a typical workflow for submitting a new pull request:
+
+1. Fork this repository
+2. Create a new branch based on your fork
+3. Commit changes and push them to your fork
+4. Create a pull request against the `dev` branch
+
+If all [status checks](https://help.github.com/articles/about-status-checks/) pass, and the maintainer approves the PR, it will be merged.
+
+**Note:** Reviewers may ask you to complete additional work, tests, or other changes before your pull request can be approved and merged.
+
+## Code of Conduct
+
+This project and everyone participating in it is governed by the [IOTA Code of Conduct](CODE_OF_CONDUCT.md).
\ No newline at end of file
diff --git a/python-regression/README.md b/python-regression/README.md
index ed5e49d535..b9d2e96fc7 100644
--- a/python-regression/README.md
+++ b/python-regression/README.md
@@ -19,37 +19,39 @@ pip install -e .
```
### Available Tests
-Machine 1 - API Tests: This machine uses 2 nodes and tests each of the api calls, and ensures that the responses are
-the expected values
+Machine 1 - Local Snapshotting Tests: This machine uses 4 nodes. The first node contains the snapshot `meta` and `state`
+files, the `spent-addresses-db` and `testnetdb` of a synced node. The second only contains the database, and the third
+only contains the snapshot files. All three of these nodes are tested to ensure that they solidify to the same point,
+and that the proper information is contained in the snapshot files and databases. The fourth node has a larger database
+that contains more milestones than the `local-snapshots-pruning-depth`. This node is checked to make sure that after
+starting, transactions that should be pruned from the database have been pruned correctly. This machine also includes
+tests for spent addresses including a test for exporting and merging spent addresses using IXI
+modules.
-Machine 2 - Transaction Tests: This machine uses 2 nodes. Several zero value transactions are sent to the first node,
+Machine 2 - Blowball Tests: This machine uses 6 nodes by default, but can be customized to be performed on as many/few
+as desired. 1000 `getTransactionsToApprove` calls are made across these nodes, and the responses checked to make sure
+that less than 5% of the results are milestone transactions. If the responses are over this threshold, then that means
+blowballs are occurring.
+
+
+Machine 3 - Transaction Tests: This machine uses 2 nodes. Several zero value transactions are sent to the first node,
as well as a milestone transaction. Then node two is checked to make sure the transactions are all confirmed. After
these transactions are resolved, the same approach is used to ensure that value transactions are also being confirmed
correctly.
-Machine 3 - Blowball Tests: This machine uses 6 nodes by default, but can be customized to be performed on as many/few
-as desired. 1000 `getTransactionsToApprove` calls are made across these nodes, and the responses checked to make sure
-that less than 5% of the results are milestone transactions. If the responses are over this threshold, then that means
-blowballs are occurring.
+Machine 4 - API Tests: This machine uses 2 nodes and tests each of the api calls, and ensures that the responses are
+the expected values
-Machine 4 - Stitching Tests: This machine uses 1 node. The node is loaded with a db containing a large side tangle. A
+Machine 5 - Stitching Tests: This machine uses 1 node. The node is loaded with a db containing a large side tangle. A
stitching transaction is issued, and another transaction referencing that one is issued. After these transactions are
issued, making `getTransactionsToApprove` calls should not crash the node.
-Machine 5 - Milestone Validation Tests: This machine uses 2 nodes. Both nodes are loaded with the same db. The db
+Machine 6 - Milestone Validation Tests: This machine uses 2 nodes. Both nodes are loaded with the same db. The db
contains several signed milestone transactions, and several unsigned transactions. One node is set to validate the
testnet coordinator signature, while the other is not. The one that requires validation should solidify to one point,
while the other should solidify further.
-Machine 6 - Local Snapshotting Tests: This machine uses 4 nodes. The first node contains the snapshot `meta` and `state`
-files, the `spent-addresses-db` and `testnetdb` of a synced node. The second only contains the database, and the third
-only contains the snapshot files. All three of these nodes are tested to ensure that they solidify to the same point,
-and that the proper information is contained in the snapshot files and databases. The fourth node has a larger database
-that contains more milestones than the `local-snapshots-pruning-depth`. This node is checked to make sure that after
-starting, transactions that should be pruned from the database have been pruned correctly. This machine also includes
-tests for spent addresses including a test for exporting and merging spent addresses using IXI
-modules.
-
+__*Note:*__ _The db's used for these tests have been documented below for reference_
### Running Tests Locally
@@ -137,7 +139,7 @@ iri
--/tests
---/features
----/machine1 [Same structure for other machines]
------/1_api_tests.feature
+-----/4_api_tests.feature
-----/config.yml
-----/output.yml
```
@@ -151,7 +153,7 @@ From the `iri/python-regression` directory, a test can be run using the followin
```
i.e. For the api tests:
```
-aloe 1_api_tests.feature -w ./tests/features/machine1/ -v --nologcapture
+aloe 4_api_tests.feature -w ./tests/features/machine1/ -v --nologcapture
```
@@ -168,12 +170,64 @@ When running the aloe command, you can add the `-a` flag to register that you wo
the given attribute. Inversely you can also run all tests that do not contain that flag by using `!`. This is shown
below:
```
-aloe 1_api_tests.feature -w ./tests/features/machine1 -a getNodeInfo
+aloe 4_api_tests.feature -w ./tests/features/machine1 -a getNodeInfo
```
or to not run the flagged tests:
```
-aloe 1_api_tests.feature -w ./tests/features/machine1 -a '!getNodeInfo'
+aloe 4_api_tests.feature -w ./tests/features/machine1 -a '!getNodeInfo'
```
_Note: To negate running the tests using the flag requires the `!` and flag to be wrapped in parentheses as shown above_
The same flag can be used for several scenarios, and they will all either be included or negated by this flag.
+
+
+### _*DB Descriptions:*_
+##### _Machine 1_
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/LS_Test_Db_With_LS_Db.tar.gz - Full LocalSnapshot test db
+synced to milestone 10321 and a local snapshot at 10220. Contains mostly 0 value transactions with a few spends early on
+to generate the localsnapshot-db as well as to provide transactions for pruning reference
+
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/LS_Test_DB_and_Snapshot.tar - Full LocalSnapshot test db
+synced to milestone 10321 without any localsnapshots-db.
+
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/LS_Test_LS_Db.tar.gz - No LocalSnapshot test db provided,
+instead the localsnapshot-db from index 10220 is provided instead.
+
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/PruningTestDB.tar - A full db synced to milestone 15000
+containing a mix of value and 0 value transactions that will be pruned once the node takes its snapshot. This is used
+to ensure that any transaction below the threshold is pruned correctly.
+
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/SpentAddressesTestDB.tar - A full db synced to milestone
+10100 with a mix of value and 0 value transactions that will be pruned once the node takes its snapshot. This is used
+to ensure that spent addresses are persisted in the local snapshot data after pruning occurs.
+
+
+##### _Machine 2_
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Blowball_Tests_db.tar - A full db synced to milestone 27.
+There are several tips surrounding the last milestone, and the test is used to ensure that new transactions aren't
+attaching en masse to the last milestone present.
+
+
+##### _Machine 3_
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Transactions_Tests_db.tar - A small db synced to milestone
+50 with a snapshot file containing a list of addresses preset for value spending. This DB is used to test value and non
+value transactions and their inclusion in the next milestone.
+
+
+##### _Machine 4_
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/testnet_files.tgz - A full db synced to milestone 8412 used
+for testing basic api commands.
+
+
+##### _Machine 5_
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Stitching_tests_db.tar - A full db synced to milestone 37
+with a large subtangle that is building beside the main tangle. This db is used to test the success or failure of
+stitching this subtangle back into the original.
+
+
+##### _Machine 6_
+https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Validation_tests_db.tar - A full db containing 2 separate
+synchronisation points. The first point is hit at milestone 37, where the last milestone issued with valid signatures is
+present. The db contains several more milestones that have been attached without a valid signature. The test will sync
+to 37 if a valid signature is required and 45 if not.
+
diff --git a/python-regression/tests/features/machine6/6_local_snapshots_tests.feature b/python-regression/tests/features/machine1/1_local_snapshots_tests.feature
similarity index 70%
rename from python-regression/tests/features/machine6/6_local_snapshots_tests.feature
rename to python-regression/tests/features/machine1/1_local_snapshots_tests.feature
index 11ea4a12d1..31a6236f1e 100644
--- a/python-regression/tests/features/machine6/6_local_snapshots_tests.feature
+++ b/python-regression/tests/features/machine1/1_local_snapshots_tests.feature
@@ -10,13 +10,13 @@ Feature: Test Bootstrapping With LS
Check that the permanode has been started correctly and is synced.
#First make sure nodes are neighbored
- Given "nodeA-m6" and "nodeB-m6" are neighbors
- And "nodeA-m6" and "nodeC-m6" are neighbors
+ Given "nodeA-m1" and "nodeB-m1" are neighbors
+ And "nodeA-m1" and "nodeC-m1" are neighbors
#Default for test is to issue 10322
- When milestone 10322 is issued on "nodeA-m6"
+ When milestone 10322 is issued on "nodeA-m1"
And we wait "30" second/seconds
- Then "nodeA-m6" is synced up to milestone 10322
+ Then "nodeA-m1" is synced up to milestone 10322
Scenario: DB node is synced, and files contain expected values
@@ -24,21 +24,21 @@ Feature: Test Bootstrapping With LS
stored correctly.
#First make sure nodes are neighbored
- Given "nodeB-m6" and "nodeA-m6" are neighbors
- And "nodeB-m6" and "nodeC-m6" are neighbors
+ Given "nodeB-m1" and "nodeA-m1" are neighbors
+ And "nodeB-m1" and "nodeC-m1" are neighbors
# Default for test is to issue 10323
- When milestone 10323 is issued on "nodeA-m6"
+ When milestone 10323 is issued on "nodeA-m1"
#Give the node time to finish syncing properly, then make sure that the node is synced to the latest milestone.
And we wait "30" second/seconds
- Then "nodeB-m6" is synced up to milestone 10323
- And A local snapshot was taken on "nodeB-m6" at index 10220
+ Then "nodeB-m1" is synced up to milestone 10323
+ And A local snapshot was taken on "nodeB-m1" at index 10220
- When reading the local snapshot state on "nodeB-m6" returns with:
+ When reading the local snapshot state on "nodeB-m1" returns with:
|keys |values |type |
|address |LS_TEST_STATE_ADDRESSES |staticValue |
- And reading the local snapshot metadata on "nodeB-m6" returns with:
+ And reading the local snapshot metadata on "nodeB-m1" returns with:
|keys |values |type |
|hashes |LS_TEST_MILESTONE_HASHES |staticValue |
@@ -47,14 +47,14 @@ Feature: Test Bootstrapping With LS
Check that the node started with just a LS DB is synced correctly.
#First make sure nodes are neighbored
- Given "nodeC-m6" and "nodeA-m6" are neighbors
- And "nodeC-m6" and "nodeB-m6" are neighbors
+ Given "nodeC-m1" and "nodeA-m1" are neighbors
+ And "nodeC-m1" and "nodeB-m1" are neighbors
#Default for test is to issue 10324
- When milestone 10324 is issued on "nodeA-m6"
+ When milestone 10324 is issued on "nodeA-m1"
#Give the node time to finish syncing properly, then make sure that the node is synced to the latest milestone.
And we wait "120" second/seconds
- Then "nodeC-m6" is synced up to milestone 10324
+ Then "nodeC-m1" is synced up to milestone 10324
Scenario: Check DB for milestone hashes
@@ -62,12 +62,12 @@ Feature: Test Bootstrapping With LS
are present in the new node.
#First make sure nodes are neighbored
- Given "nodeC-m6" and "nodeA-m6" are neighbors
+ Given "nodeC-m1" and "nodeA-m1" are neighbors
#Default for test is to issue 10325
- When milestone 10325 is issued on "nodeA-m6"
+ When milestone 10325 is issued on "nodeA-m1"
And we wait "30" second/seconds
- Then "checkConsistency" is called on "nodeC-m6" with:
+ Then "checkConsistency" is called on "nodeC-m1" with:
|keys |values |type |
|tails |LS_TEST_MILESTONE_HASHES |staticValue |
@@ -80,23 +80,39 @@ Feature: Test Bootstrapping With LS
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.
- Given "checkConsistency" is called on "nodeD-m6" with:
+ Given "getInclusionStates" is called on "nodeD-m1" with:
|keys |values |type |
- |tails |LS_PRUNED_TRANSACTIONS |staticValue |
+ |transactions |LS_PRUNED_TRANSACTIONS |staticValue |
+ |tips |LS_PRUNING_TIP |staticList |
- Then the response for "checkConsistency" should return null
+ And the response for "getInclusionStates" should return with:
+ |keys |values |type |
+ |states |True |boolList |
+
+ # Trigger pruning and wait for it to finish
+ When the next 10 milestones are issued
+ And we wait "15" second/seconds
+
+ And "getInclusionStates" is called on "nodeD-m1" with:
+ |keys |values |type |
+ |transactions |LS_PRUNED_TRANSACTIONS |staticValue |
+ |tips |LS_PRUNING_TIP |staticList |
+
+ Then the response for "getInclusionStates" should return with:
+ |keys |values |type |
+ |states |False |boolList |
Scenario: Check unconfirmed transaction is spent from
Issues a value transaction that will be unconfirmed, and check that the address was spent from.
- Given a transaction is generated and attached on "nodeE-m6" with:
+ Given a transaction is generated and attached on "nodeE-m1" with:
|keys |values |type |
|address |TEST_ADDRESS |staticValue |
|value |10 |int |
|seed |UNCONFIRMED_TEST_SEED |staticValue |
- When "wereAddressesSpentFrom" is called on "nodeE-m6" with:
+ When "wereAddressesSpentFrom" is called on "nodeE-m1" with:
|keys |values |type |
|addresses |UNCONFIRMED_TEST_ADDRESS |staticValue |
@@ -110,7 +126,7 @@ Feature: Test Bootstrapping With LS
transaction has been pruned from the DB.
# Check that addresses were spent from before pruning
- Given "wereAddressesSpentFrom" is called on "nodeE-m6" with:
+ Given "wereAddressesSpentFrom" is called on "nodeE-m1" with:
|keys |values |type |
|addresses |LS_SPENT_ADDRESSES |staticValue |
@@ -122,7 +138,7 @@ Feature: Test Bootstrapping With LS
When the next 30 milestones are issued
# Check that addresses were spent after transaction have been pruned
- And "wereAddressesSpentFrom" is called on "nodeE-m6" with:
+ And "wereAddressesSpentFrom" is called on "nodeE-m1" with:
|keys |values |type |
|addresses |LS_SPENT_ADDRESSES |staticValue |
@@ -131,7 +147,7 @@ Feature: Test Bootstrapping With LS
|addresses |True |boolList |
# Check that transactions from those addresses were pruned
- And "getTrytes" is called on "nodeE-m6" with:
+ And "getTrytes" is called on "nodeE-m1" with:
|keys |values |type |
|hashes |LS_SPENT_TRANSACTIONS |staticValue |
diff --git a/python-regression/tests/features/machine1/config.yml b/python-regression/tests/features/machine1/config.yml
index 029b6ce6a8..0afa883fc4 100644
--- a/python-regression/tests/features/machine1/config.yml
+++ b/python-regression/tests/features/machine1/config.yml
@@ -1,26 +1,71 @@
-defaults: &api_tests_config_files
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/testnet_files.tgz
- db_checksum: 6eaa06d5442416b7b8139e337a1598d2bae6a7f55c2d9d01f8c5dac69c004f75
- iri_args: ['--testnet-coordinator',
- 'BTCAAFIH9CJIVIMWFMIHKFNWRTLJRKSTMRCVRE9CIP9AEDTOULVFRHQZT9QAQBZXXAZGBNMVOOKTKAXTB',
- '--milestone-start',
- '0',
- '--snapshot',
- './snapshot.txt',
- '--testnet-no-coo-validation',
- 'true',
- '--testnet',
- 'true'
+default_args: &args
+ ['--testnet-coordinator',
+ 'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
+ '--mwm',
+ '1',
+ '--milestone-start',
+ '0',
+ '--testnet-no-coo-validation',
+ 'true',
+ '--testnet',
+ 'true',
+ '--snapshot',
+ './snapshot.txt',
+ '--local-snapshots-pruning-enabled',
+ 'true',
+ '--local-snapshots-pruning-delay',
+ '10000',
+ '--remote',
+ 'true',
+ '--remote-limit-api',
+ '""'
]
- java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/iri/jacoco.exec,output=file,append=true,dumponexit=true
-seeds: # For internal use by the regression system.
- - SEED
- - SIID
+default_ixi: &ixi
+ ['IXI/LocalSnapshots.ixi']
+
+java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/iri/jacoco.exec,output=file,append=true,dumponexit=true
+
+defaults: &db_full
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/LS_Test_Db_With_LS_Db.tar.gz
+ db_checksum: 2055406bf312136d7cd0efa21248bd8cc9c407ab14ef0d18b921cf18c72c5270
+ iri_args: *args
+ ixis: *ixi
+
+db_with_snapshot: &db_with_snapshot
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/LS_Test_DB_and_Snapshot.tar
+ db_checksum: eabb81b0570a20e8d1c65c3d29e4b4e723de537ebca0eada536e3155d5a96972
+ iri_args: *args
+ ixis: *ixi
+
+db_with_ls_db: &db_with_ls_db
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/LS_Test_LS_Db.tar.gz
+ db_checksum: d217729fd5efb0432d179ec59472f283cd61e8ad4ca9aab32e5c1f82632a1a29
+ iri_args: *args
+ ixis: *ixi
+
+db_for_pruning: &db_for_pruning
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/PruningTestDB.tar
+ db_checksum: 15122ba80c0a03dc5b6b4186e5d880d0a1a15b5a6de48bafe4002c4c9b682221
+ iri_args: *args
+
+db_for_spent_addresses: &db_for_spent_addresses
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/SpentAddressesTestDB.tar
+ db_checksum: 7e15b2cbc76585d6483668cb1709201daa71314e7d488d9e7d71d7052479e73e
+ iri_args: *args
nodes:
nodeA-m1: #name
- <<: *api_tests_config_files
-
+ <<: *db_full
+
nodeB-m1:
- <<: *api_tests_config_files
+ <<: *db_with_snapshot
+
+ nodeC-m1:
+ <<: *db_with_ls_db
+
+ nodeD-m1:
+ <<: *db_for_pruning
+
+ nodeE-m1:
+ <<: *db_for_spent_addresses
diff --git a/python-regression/tests/features/machine1/output.yml b/python-regression/tests/features/machine1/output.yml
index e84b1543bc..27aaa66771 100644
--- a/python-regression/tests/features/machine1/output.yml
+++ b/python-regression/tests/features/machine1/output.yml
@@ -1,5 +1,5 @@
nodes:
- nodeA:
+ nodeA-m1:
host: localhost
podip: localhost
ports:
@@ -10,7 +10,7 @@ nodes:
api: 14265
gossip-tcp: 15600
zmq-feed: 5556
- nodeB:
+ nodeB-m1:
host: localhost
podip: localhost
ports:
@@ -20,4 +20,26 @@ nodes:
clusterip_ports:
api: 15265
gossip-tcp: 15605
- zmq-feed: 6556
\ No newline at end of file
+ zmq-feed: 6556
+ nodeC-m1:
+ host: localhost
+ podip: localhost
+ ports:
+ api: 14265
+ gossip-tcp: 15600
+ zmq-feed: 5556
+ clusterip_ports:
+ api: 14265
+ gossip-tcp: 15600
+ zmq-feed: 5556
+ nodeD-m1:
+ host: localhost
+ podip: localhost
+ ports:
+ api: 14265
+ gossip-tcp: 15600
+ zmq-feed: 5556
+ clusterip_ports:
+ api: 14265
+ gossip-tcp: 15600
+ zmq-feed: 5556
diff --git a/python-regression/tests/features/machine3/3_blowball_tests.feature b/python-regression/tests/features/machine2/2_blowball_tests.feature
similarity index 93%
rename from python-regression/tests/features/machine3/3_blowball_tests.feature
rename to python-regression/tests/features/machine2/2_blowball_tests.feature
index 2b6185b631..403194743a 100644
--- a/python-regression/tests/features/machine3/3_blowball_tests.feature
+++ b/python-regression/tests/features/machine2/2_blowball_tests.feature
@@ -10,7 +10,7 @@ Feature: Test GTTA for blowballs
|keys |values |type |
|depth |3 |int |
- And "findTransactions" is called on "nodeA-m3" with:
+ And "findTransactions" is called on "nodeA-m2" with:
|keys |values |type |
|addresses |TEST_BLOWBALL_COO |staticList |
diff --git a/python-regression/tests/features/machine2/config.yml b/python-regression/tests/features/machine2/config.yml
index 8eda2fe8a4..dcd4171e0a 100644
--- a/python-regression/tests/features/machine2/config.yml
+++ b/python-regression/tests/features/machine2/config.yml
@@ -1,19 +1,39 @@
-defaults: &transaction_tests_config_files
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Transactions_Tests_db.tar
- db_checksum: 756237276479da4b01deaa0c1211ca65a4c8ec6f081452ea7e8153648c53bd67
+defaults: &blowball_tests_config_files
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Blowball_Tests_db.tar
+ db_checksum: cf4da9fef58f74d8721eee7e2726f3321ecc2257ef111e6b8b2f4c348b40c980
iri_args: ['--testnet-coordinator',
'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
+ '--milestone-keys',
+ '18',
'--milestone-start',
- '0',
+ '2',
'--testnet-no-coo-validation',
'true',
'--testnet',
- 'true',
- '--snapshot',
- './snapshot.txt'
+ 'true'
]
java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/iri/jacoco.exec,output=file,append=true,dumponexit=true
+seeds: # For internal use by the regression system.
+ - SEED
+ - SIID
+
nodes:
nodeA-m2: #name
- <<: *transaction_tests_config_files
+ <<: *blowball_tests_config_files
+
+ nodeB-m2:
+ <<: *blowball_tests_config_files
+
+ nodeC-m2:
+ <<: *blowball_tests_config_files
+
+ nodeD-m2:
+ <<: *blowball_tests_config_files
+
+ nodeE-m2:
+ <<: *blowball_tests_config_files
+
+ nodeF-m2:
+ <<: *blowball_tests_config_files
+
diff --git a/python-regression/tests/features/machine2/output.yml b/python-regression/tests/features/machine2/output.yml
index 4afb135f97..b15b42d3c4 100644
--- a/python-regression/tests/features/machine2/output.yml
+++ b/python-regression/tests/features/machine2/output.yml
@@ -11,6 +11,50 @@ nodes:
gossip-tcp: 15600
zmq-feed: 5556
nodeB-m2:
+ host: localhost
+ podip: localhost
+ ports:
+ api: 15265
+ gossip-tcp: 15605
+ zmq-feed: 6556
+ clusterip_ports:
+ api: 15265
+ gossip-tcp: 15605
+ zmq-feed: 6556
+ nodeC-m2:
+ host: localhost
+ podip: localhost
+ ports:
+ api: 15265
+ gossip-tcp: 15605
+ zmq-feed: 6556
+ clusterip_ports:
+ api: 15265
+ gossip-tcp: 15605
+ zmq-feed: 6556
+ nodeD-m2:
+ host: localhost
+ podip: localhost
+ ports:
+ api: 15265
+ gossip-tcp: 15605
+ zmq-feed: 6556
+ clusterip_ports:
+ api: 15265
+ gossip-tcp: 15605
+ zmq-feed: 6556
+ nodeE-m2:
+ host: localhost
+ podip: localhost
+ ports:
+ api: 15265
+ gossip-tcp: 15605
+ zmq-feed: 6556
+ clusterip_ports:
+ api: 15265
+ gossip-tcp: 15605
+ zmq-feed: 6556
+ nodeF-m2:
host: localhost
podip: localhost
ports:
diff --git a/python-regression/tests/features/machine2/2_transaction_tests.feature b/python-regression/tests/features/machine3/3_transaction_tests.feature
similarity index 90%
rename from python-regression/tests/features/machine2/2_transaction_tests.feature
rename to python-regression/tests/features/machine3/3_transaction_tests.feature
index 18e275280f..2d1f7dc4bc 100644
--- a/python-regression/tests/features/machine2/2_transaction_tests.feature
+++ b/python-regression/tests/features/machine3/3_transaction_tests.feature
@@ -5,7 +5,7 @@ Feature: Test transaction confirmation
A milestone will be issued that references these transactions, and this should
confirm the transations.
- Given "10" transactions are issued on "nodeA-m2" with:
+ Given "10" transactions are issued on "nodeA-m3" with:
|keys |values |type |
|address |TEST_ADDRESS |staticValue |
|value |0 |int |
@@ -19,7 +19,7 @@ Feature: Test transaction confirmation
#Give the node 10 seconds to solidify the milestone
And we wait "15" second/seconds
- Then "getInclusionStates" is called on "nodeA-m2" with:
+ Then "getInclusionStates" is called on "nodeA-m3" with:
|keys |values |type |
|transactions |evaluate_and_send |responseValue |
|tips |latestMilestone |configValue |
@@ -29,12 +29,12 @@ Feature: Test transaction confirmation
| states | True True True True True True True True True True | boolListMixed |
- When a transaction is generated and attached on "nodeA-m2" with:
+ When a transaction is generated and attached on "nodeA-m3" with:
| keys | values | type |
| address | TEST_ADDRESS | staticValue |
| value | 0 | int |
- And "getInclusionStates" is called on "nodeA-m2" with:
+ And "getInclusionStates" is called on "nodeA-m3" with:
| keys | values | type |
| transactions | TEST_STORE_ADDRESS | staticList |
| tips | latestMilestone | configValue |
@@ -49,7 +49,7 @@ Feature: Test transaction confirmation
A milestone will be issued that references these transactions, and this should
confirm the transations.
- Given "10" transactions are issued on "nodeA-m2" with:
+ Given "10" transactions are issued on "nodeA-m3" with:
|keys |values |type |
|seed |THE_BANK |staticList |
|address |TEST_ADDRESS |staticValue |
@@ -64,21 +64,21 @@ Feature: Test transaction confirmation
#Give the node time to solidify the milestone
And we wait "15" second/seconds
- Then "getInclusionStates" is called on "nodeA-m2" with:
+ Then "getInclusionStates" is called on "nodeA-m3" with:
|keys |values |type |
|transactions |evaluate_and_send |responseValue |
|tips |latestMilestone |configValue |
And the response for "getInclusionStates" should return with:
|keys |values |type |
- | states | True True True True True True True True True False | boolListMixed |
+ | states | True True True True True True True True True True | boolListMixed |
- When a transaction is generated and attached on "nodeA-m2" with:
+ When a transaction is generated and attached on "nodeA-m3" with:
| keys | values | type |
| address | TEST_ADDRESS | staticValue |
| value | 0 | int |
- And "getInclusionStates" is called on "nodeA-m2" with:
+ And "getInclusionStates" is called on "nodeA-m3" with:
| keys | values | type |
| transactions | TEST_STORE_ADDRESS | staticList |
| tips | latestMilestone | configValue |
diff --git a/python-regression/tests/features/machine3/config.yml b/python-regression/tests/features/machine3/config.yml
index 0b5c3f5823..194bc1b2b0 100644
--- a/python-regression/tests/features/machine3/config.yml
+++ b/python-regression/tests/features/machine3/config.yml
@@ -1,39 +1,19 @@
-defaults: &blowball_tests_config_files
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Blowball_Tests_db.tar
- db_checksum: cf4da9fef58f74d8721eee7e2726f3321ecc2257ef111e6b8b2f4c348b40c980
+defaults: &transaction_tests_config_files
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Transactions_Tests_db.tar
+ db_checksum: 756237276479da4b01deaa0c1211ca65a4c8ec6f081452ea7e8153648c53bd67
iri_args: ['--testnet-coordinator',
'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
- '--milestone-keys',
- '18',
'--milestone-start',
- '2',
+ '0',
'--testnet-no-coo-validation',
'true',
'--testnet',
- 'true'
+ 'true',
+ '--snapshot',
+ './snapshot.txt'
]
java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/iri/jacoco.exec,output=file,append=true,dumponexit=true
-seeds: # For internal use by the regression system.
- - SEED
- - SIID
-
nodes:
nodeA-m3: #name
- <<: *blowball_tests_config_files
-
- nodeB-m3:
- <<: *blowball_tests_config_files
-
- nodeC-m3:
- <<: *blowball_tests_config_files
-
- nodeD-m3:
- <<: *blowball_tests_config_files
-
- nodeE-m3:
- <<: *blowball_tests_config_files
-
- nodeF-m3:
- <<: *blowball_tests_config_files
-
+ <<: *transaction_tests_config_files
diff --git a/python-regression/tests/features/machine3/output.yml b/python-regression/tests/features/machine3/output.yml
index 6e8258dd8c..95f32d9408 100644
--- a/python-regression/tests/features/machine3/output.yml
+++ b/python-regression/tests/features/machine3/output.yml
@@ -1,5 +1,5 @@
nodes:
- nodeA:
+ nodeA-m3:
host: localhost
podip: localhost
ports:
@@ -10,51 +10,7 @@ nodes:
api: 14265
gossip-tcp: 15600
zmq-feed: 5556
- nodeB:
- host: localhost
- podip: localhost
- ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
- clusterip_ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
- nodeC:
- host: localhost
- podip: localhost
- ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
- clusterip_ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
- nodeD:
- host: localhost
- podip: localhost
- ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
- clusterip_ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
- nodeE:
- host: localhost
- podip: localhost
- ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
- clusterip_ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
- nodeF:
+ nodeB-m3:
host: localhost
podip: localhost
ports:
diff --git a/python-regression/tests/features/machine1/1_api_tests.feature b/python-regression/tests/features/machine4/4_api_tests.feature
similarity index 83%
rename from python-regression/tests/features/machine1/1_api_tests.feature
rename to python-regression/tests/features/machine4/4_api_tests.feature
index 15f98f2eb9..3674917cb6 100644
--- a/python-regression/tests/features/machine1/1_api_tests.feature
+++ b/python-regression/tests/features/machine4/4_api_tests.feature
@@ -14,7 +14,7 @@ Feature: Test API calls on Machine 1
#See tests/features/steps/api_test_steps.py for further details
#
- Given "getNodeInfo" is called on "nodeA-m1" with:
+ Given "getNodeInfo" is called on "nodeA-m4" with:
|keys |values |type |
Then a response with the following is returned:
@@ -45,11 +45,11 @@ Feature: Test API calls on Machine 1
Scenario: GetNeighbors is called
- Given "addNeighbors" is called on "nodeA-m1" with:
+ Given "addNeighbors" is called on "nodeA-m4" with:
|keys |values |type |
- |uris |nodeB-m1 |nodeAddress |
+ |uris |nodeB-m4 |nodeAddress |
- And "getNeighbors" is called on "nodeA-m1" with:
+ And "getNeighbors" is called on "nodeA-m4" with:
|keys |values |type |
Then a response with the following is returned:
@@ -67,11 +67,11 @@ Feature: Test API calls on Machine 1
Scenario: Add and Remove Neighbors
- Adds nodeB-m1 as a neighbor to nodeA-m1, and then removes it.
+ Adds nodeB-m4 as a neighbor to nodeA-m4, and then removes it.
- Given "addNeighbors" is called on "nodeA-m1" with:
+ Given "addNeighbors" is called on "nodeA-m4" with:
|keys |values |type |
- |uris |nodeB-m1 |nodeAddress |
+ |uris |nodeB-m4 |nodeAddress |
Then a response with the following is returned:
|keys |
@@ -79,9 +79,9 @@ Feature: Test API calls on Machine 1
|duration |
- When "removeNeighbors" is called on "nodeA-m1" with:
+ When "removeNeighbors" is called on "nodeA-m4" with:
|keys |values |type |
- |uris |nodeB-m1 |nodeAddress |
+ |uris |nodeB-m4 |nodeAddress |
Then a response with the following is returned:
@@ -91,7 +91,7 @@ Feature: Test API calls on Machine 1
#Values can be found in util/static_vals.py
Scenario: GetTrytes is called
- Given "getTrytes" is called on "nodeA-m1" with:
+ Given "getTrytes" is called on "nodeA-m4" with:
|keys |values |type |
|hashes |TEST_HASH |staticList |
@@ -102,7 +102,7 @@ Feature: Test API calls on Machine 1
Scenario: GetTransactionsToApprove is called
- Given "getTransactionsToApprove" is called on "nodeA-m1" with:
+ Given "getTransactionsToApprove" is called on "nodeA-m4" with:
|keys |values |type |
|depth |3 |int |
@@ -114,7 +114,7 @@ Feature: Test API calls on Machine 1
Scenario: CheckConsistency is called
- Given "checkConsistency" is called on "nodeA-m1" with:
+ Given "checkConsistency" is called on "nodeA-m4" with:
|keys |values |type |
|tails |TEST_HASH |staticList |
@@ -122,9 +122,9 @@ Feature: Test API calls on Machine 1
|keys |values |type |
|state |True |bool |
- When an inconsistent transaction is generated on "nodeA-m1"
+ When an inconsistent transaction is generated on "nodeA-m4"
- And "checkConsistency" is called on "nodeA-m1" with:
+ And "checkConsistency" is called on "nodeA-m4" with:
|keys |values |type |
|tails |inconsistentTransactions |responseList |
@@ -136,7 +136,7 @@ Feature: Test API calls on Machine 1
#Values can be found in util/static_vals.py
Scenario: GetInclusionStates is called
- Given "getInclusionStates" is called on "nodeA-m1" with:
+ Given "getInclusionStates" is called on "nodeA-m4" with:
|keys |values |type |
|transactions |TEST_HASH |staticList |
|tips |TEST_TIP_LIST |staticValue |
@@ -147,7 +147,7 @@ Feature: Test API calls on Machine 1
#Values can be found in util/static_vals.py
Scenario: GetInclusionStates is called with transaction list
- Given "getInclusionStates" is called on "nodeA-m1" with:
+ Given "getInclusionStates" is called on "nodeA-m4" with:
| keys | values | type |
| transactions | TEST_HASH_LIST | staticValue |
| tips | TEST_TIP_LIST | staticValue |
@@ -159,7 +159,7 @@ Feature: Test API calls on Machine 1
#Address can be found in util/static_vals.py
Scenario: GetBalances is called
- Given "getBalances" is called on "nodeA-m1" with:
+ Given "getBalances" is called on "nodeA-m4" with:
|keys |values |type |
|addresses |TEST_EMPTY_ADDRESS |staticList |
|threshold |100 |int |
@@ -173,7 +173,7 @@ Feature: Test API calls on Machine 1
Begins attaching a transaction to the tangle with a high MWM, then issues an interrupt to the node
If the interrupt is successful, the attachToTangle response will return a null tryte list
- Given "attachToTangle" is called in parallel on "nodeA-m1" with:
+ Given "attachToTangle" is called in parallel on "nodeA-m4" with:
|keys |values |type |
|trytes |EMPTY_TRANSACTION_TRYTES|staticList |
|trunk_transaction |TEST_HASH |staticValue |
@@ -181,7 +181,7 @@ Feature: Test API calls on Machine 1
|min_weight_magnitude |50 |int |
And we wait "1" second/seconds
- Then "interruptAttachingToTangle" is called in parallel on "nodeA-m1" with:
+ Then "interruptAttachingToTangle" is called in parallel on "nodeA-m4" with:
|keys |values |type |
# Do not include duration in the return expectations as it will always return a variable amount
@@ -192,7 +192,7 @@ Feature: Test API calls on Machine 1
Scenario: WereAddressesSpentFrom is called
- Given "wereAddressesSpentFrom" is called on "nodeA-m1" with:
+ Given "wereAddressesSpentFrom" is called on "nodeA-m4" with:
|keys |values |type |
|addresses |TEST_EMPTY_ADDRESS |staticList |
@@ -207,7 +207,7 @@ Feature: Test API calls on Machine 1
Generate a transaction, attach it to the tangle, and store it locally. Then find
that transaction via its address.
- Given a transaction is generated and attached on "nodeA-m1" with:
+ Given a transaction is generated and attached on "nodeA-m4" with:
|keys |values |type |
|address |TEST_STORE_ADDRESS |staticValue |
|value |0 |int |
@@ -216,11 +216,11 @@ Feature: Test API calls on Machine 1
|keys |
|trytes |
- When "storeTransactions" is called on "nodeA-m1" with:
+ When "storeTransactions" is called on "nodeA-m4" with:
|keys |values |type |
|trytes |TEST_STORE_TRANSACTION |staticValue |
- And "findTransactions" is called on "nodeA-m1" with:
+ And "findTransactions" is called on "nodeA-m4" with:
|keys |values |type |
|addresses |TEST_STORE_ADDRESS |staticList |
@@ -234,8 +234,8 @@ Feature: Test API calls on Machine 1
Send a test transaction from one node in a machine with a unique tag, and find that transaction
through a different node in the same machine
- Given "nodeA-m1" and "nodeB-m1" are neighbors
- When a transaction is generated and attached on "nodeA-m1" with:
+ Given "nodeA-m4" and "nodeB-m4" are neighbors
+ When a transaction is generated and attached on "nodeA-m4" with:
|keys |values |type |
|address |TEST_ADDRESS |staticValue |
|tag |TEST9TAG9ONE |string |
@@ -244,7 +244,7 @@ Feature: Test API calls on Machine 1
#Give the transaction time to propagate
And we wait "3" second/seconds
- And "findTransactions" is called on "nodeB-m1" with:
+ And "findTransactions" is called on "nodeB-m4" with:
|keys |values |type |
|tags |TEST9TAG9ONE |list |
diff --git a/python-regression/tests/features/machine4/config.yml b/python-regression/tests/features/machine4/config.yml
index 21e69e895f..1b5f17b529 100644
--- a/python-regression/tests/features/machine4/config.yml
+++ b/python-regression/tests/features/machine4/config.yml
@@ -1,23 +1,26 @@
-defaults: &stitching_tests_config_files
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Stitching_tests_db.tar
- db_checksum: ac987dc8e61e37d6420e78da18c4cf94671f51e8014b4dd593f36bbd4fb0cfc1
+defaults: &api_tests_config_files
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/testnet_files.tgz
+ db_checksum: 6eaa06d5442416b7b8139e337a1598d2bae6a7f55c2d9d01f8c5dac69c004f75
iri_args: ['--testnet-coordinator',
- 'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
- '--milestone-keys',
- '18',
- '--milestone-start',
- '2',
+ 'BTCAAFIH9CJIVIMWFMIHKFNWRTLJRKSTMRCVRE9CIP9AEDTOULVFRHQZT9QAQBZXXAZGBNMVOOKTKAXTB',
+ '--milestone-start',
+ '0',
+ '--snapshot',
+ './snapshot.txt',
'--testnet-no-coo-validation',
'true',
'--testnet',
'true'
]
java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/iri/jacoco.exec,output=file,append=true,dumponexit=true
-
+
seeds: # For internal use by the regression system.
- SEED
- SIID
nodes:
nodeA-m4: #name
- <<: *stitching_tests_config_files
+ <<: *api_tests_config_files
+
+ nodeB-m4:
+ <<: *api_tests_config_files
diff --git a/python-regression/tests/features/machine4/output.yml b/python-regression/tests/features/machine4/output.yml
index e84b1543bc..a9a0d80060 100644
--- a/python-regression/tests/features/machine4/output.yml
+++ b/python-regression/tests/features/machine4/output.yml
@@ -1,5 +1,5 @@
nodes:
- nodeA:
+ nodeA-m4:
host: localhost
podip: localhost
ports:
@@ -10,7 +10,7 @@ nodes:
api: 14265
gossip-tcp: 15600
zmq-feed: 5556
- nodeB:
+ nodeB-m4:
host: localhost
podip: localhost
ports:
diff --git a/python-regression/tests/features/machine4/4_stitching.feature b/python-regression/tests/features/machine5/5_stitching.feature
similarity index 87%
rename from python-regression/tests/features/machine4/4_stitching.feature
rename to python-regression/tests/features/machine5/5_stitching.feature
index 7b5c9a000c..796258ac6f 100644
--- a/python-regression/tests/features/machine4/4_stitching.feature
+++ b/python-regression/tests/features/machine5/5_stitching.feature
@@ -8,8 +8,8 @@ Feature: Ensure node reliability while stitching a side tangle
Scenario: Check consistency on a stitching transaction responds
- Given a stitching transaction is issued on "nodeA-m4" with the tag "STITCHING"
- And "checkConsistency" is called in parallel on "nodeA-m4" with:
+ Given a stitching transaction is issued on "nodeA-m5" with the tag "STITCHING"
+ And "checkConsistency" is called in parallel on "nodeA-m5" with:
|keys |values |type |
|tails |previousTransaction |responseList |
@@ -19,7 +19,7 @@ Feature: Ensure node reliability while stitching a side tangle
When a transaction is issued referencing the previous transaction
- And "getTransactionsToApprove" is called on "nodeA-m4" with:
+ And "getTransactionsToApprove" is called on "nodeA-m5" with:
|keys |values |type |
|depth |3 |int |
diff --git a/python-regression/tests/features/machine5/config.yml b/python-regression/tests/features/machine5/config.yml
index 766079162e..6055f30f00 100644
--- a/python-regression/tests/features/machine5/config.yml
+++ b/python-regression/tests/features/machine5/config.yml
@@ -1,6 +1,6 @@
-defaults: &no_validation_tests_config_files
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Validation_tests_db.tar
- db_checksum: 40874a129db910be2466244b3cdeea2dde9f9601221cb94b837f55ac2be384f5
+defaults: &stitching_tests_config_files
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Stitching_tests_db.tar
+ db_checksum: ac987dc8e61e37d6420e78da18c4cf94671f51e8014b4dd593f36bbd4fb0cfc1
iri_args: ['--testnet-coordinator',
'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
'--milestone-keys',
@@ -12,30 +12,12 @@ defaults: &no_validation_tests_config_files
'--testnet',
'true'
]
- java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/workdir/jacoco.exec,output=file,append=true,dumponexit=true
-
-db_with_validation: &validation_tests_config_files
- db: https://s3.amazonaws.com/iota-db-files/dbs/machine4/validation_test_db.tar
- db_checksum: 40874a129db910be2466244b3cdeea2dde9f9601221cb94b837f55ac2be384f5
- iri_args: ['--testnet-coordinator',
- 'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
- '--milestone-keys',
- '18',
- '--milestone-start',
- '2',
- '--testnet',
- 'true'
- ]
- java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/workdir/jacoco.exec,output=file,append=true,dumponexit=true
-
-
+ java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/iri/jacoco.exec,output=file,append=true,dumponexit=true
+
seeds: # For internal use by the regression system.
- SEED
- SIID
nodes:
nodeA-m5: #name
- <<: *no_validation_tests_config_files
-
- nodeB-m5:
- <<: *validation_tests_config_files
+ <<: *stitching_tests_config_files
diff --git a/python-regression/tests/features/machine5/output.yml b/python-regression/tests/features/machine5/output.yml
index e84b1543bc..0f8081d76f 100644
--- a/python-regression/tests/features/machine5/output.yml
+++ b/python-regression/tests/features/machine5/output.yml
@@ -1,5 +1,5 @@
nodes:
- nodeA:
+ nodeA-m5:
host: localhost
podip: localhost
ports:
@@ -10,14 +10,3 @@ nodes:
api: 14265
gossip-tcp: 15600
zmq-feed: 5556
- nodeB:
- host: localhost
- podip: localhost
- ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
- clusterip_ports:
- api: 15265
- gossip-tcp: 15605
- zmq-feed: 6556
\ No newline at end of file
diff --git a/python-regression/tests/features/machine5/5_milestone_validation.feature b/python-regression/tests/features/machine6/6_milestone_validation.feature
similarity index 87%
rename from python-regression/tests/features/machine5/5_milestone_validation.feature
rename to python-regression/tests/features/machine6/6_milestone_validation.feature
index 6b74c619e9..e2b807a8ee 100644
--- a/python-regression/tests/features/machine5/5_milestone_validation.feature
+++ b/python-regression/tests/features/machine6/6_milestone_validation.feature
@@ -5,14 +5,14 @@ Feature: Test milestone validation
Scenario: Verify current milestone index
- Given "getNodeInfo" is called on "nodeA-m5" with:
+ Given "getNodeInfo" is called on "nodeA-m6" with:
|keys |values |type |
Then the response for "getNodeInfo" should return with:
|keys |values |type |
|latestMilestoneIndex |45 |int |
- And "getNodeInfo" is called on "nodeB-m5" with:
+ And "getNodeInfo" is called on "nodeB-m6" with:
|keys |values |type |
Then the response for "getNodeInfo" should return with:
diff --git a/python-regression/tests/features/machine6/__init__.py b/python-regression/tests/features/machine6/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/python-regression/tests/features/machine6/config.yml b/python-regression/tests/features/machine6/config.yml
index 1be1ae6bc9..465558b49e 100644
--- a/python-regression/tests/features/machine6/config.yml
+++ b/python-regression/tests/features/machine6/config.yml
@@ -1,71 +1,41 @@
-default_args: &args
- ['--testnet-coordinator',
- 'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
- '--mwm',
- '1',
- '--milestone-start',
- '0',
- '--testnet-no-coo-validation',
- 'true',
- '--testnet',
- 'true',
- '--snapshot',
- './snapshot.txt',
- '--local-snapshots-pruning-enabled',
- 'true',
- '--local-snapshots-pruning-delay',
- '10000',
- '--remote',
- 'true',
- '--remote-limit-api',
- '""'
+defaults: &no_validation_tests_config_files
+ db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/Validation_tests_db.tar
+ db_checksum: 40874a129db910be2466244b3cdeea2dde9f9601221cb94b837f55ac2be384f5
+ iri_args: ['--testnet-coordinator',
+ 'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
+ '--milestone-keys',
+ '18',
+ '--milestone-start',
+ '2',
+ '--testnet-no-coo-validation',
+ 'true',
+ '--testnet',
+ 'true'
]
+ java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/workdir/jacoco.exec,output=file,append=true,dumponexit=true
+
+db_with_validation: &validation_tests_config_files
+ db: https://s3.amazonaws.com/iota-db-files/dbs/machine4/validation_test_db.tar
+ db_checksum: 40874a129db910be2466244b3cdeea2dde9f9601221cb94b837f55ac2be384f5
+ iri_args: ['--testnet-coordinator',
+ 'EFPNKGPCBXXXLIBYFGIGYBYTFFPIOQVNNVVWTTIYZO9NFREQGVGDQQHUUQ9CLWAEMXVDFSSMOTGAHVIBH',
+ '--milestone-keys',
+ '18',
+ '--milestone-start',
+ '2',
+ '--testnet',
+ 'true'
+ ]
+ java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/workdir/jacoco.exec,output=file,append=true,dumponexit=true
-default_ixi: &ixi
- ['IXI/LocalSnapshots.ixi']
-
-java_options: -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=/iri/jacoco.exec,output=file,append=true,dumponexit=true
-
-defaults: &db_full
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/LS_Test_Db_With_LS_Db.tar.gz
- db_checksum: 2055406bf312136d7cd0efa21248bd8cc9c407ab14ef0d18b921cf18c72c5270
- iri_args: *args
- ixis: *ixi
-
-db_with_snapshot: &db_with_snapshot
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/LS_Test_DB_and_Snapshot.tar
- db_checksum: eabb81b0570a20e8d1c65c3d29e4b4e723de537ebca0eada536e3155d5a96972
- iri_args: *args
- ixis: *ixi
-
-db_with_ls_db: &db_with_ls_db
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/LS_Test_LS_Db.tar.gz
- db_checksum: d217729fd5efb0432d179ec59472f283cd61e8ad4ca9aab32e5c1f82632a1a29
- iri_args: *args
- ixis: *ixi
-
-db_for_pruning: &db_for_pruning
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/PruningTestDB.tar
- db_checksum: 15122ba80c0a03dc5b6b4186e5d880d0a1a15b5a6de48bafe4002c4c9b682221
- iri_args: *args
-db_for_spent_addresses: &db_for_spent_addresses
- db: https://s3.eu-central-1.amazonaws.com/iotaledger-dbfiles/dev/SpentAddressesTestDB.tar
- db_checksum: 7e15b2cbc76585d6483668cb1709201daa71314e7d488d9e7d71d7052479e73e
- iri_args: *args
+seeds: # For internal use by the regression system.
+ - SEED
+ - SIID
nodes:
nodeA-m6: #name
- <<: *db_full
-
+ <<: *no_validation_tests_config_files
+
nodeB-m6:
- <<: *db_with_snapshot
-
- nodeC-m6:
- <<: *db_with_ls_db
-
- nodeD-m6:
- <<: *db_for_pruning
-
- nodeE-m6:
- <<: *db_for_spent_addresses
+ <<: *validation_tests_config_files
diff --git a/python-regression/tests/features/machine6/output.yml b/python-regression/tests/features/machine6/output.yml
index 2b2fe945c9..7dd9f6e952 100644
--- a/python-regression/tests/features/machine6/output.yml
+++ b/python-regression/tests/features/machine6/output.yml
@@ -1,5 +1,5 @@
nodes:
- nodeA:
+ nodeA-m6:
host: localhost
podip: localhost
ports:
@@ -10,7 +10,7 @@ nodes:
api: 14265
gossip-tcp: 15600
zmq-feed: 5556
- nodeB:
+ nodeB-m6:
host: localhost
podip: localhost
ports:
@@ -20,26 +20,4 @@ nodes:
clusterip_ports:
api: 15265
gossip-tcp: 15605
- zmq-feed: 6556
- nodeC:
- host: localhost
- podip: localhost
- ports:
- api: 14265
- gossip-tcp: 15600
- zmq-feed: 5556
- clusterip_ports:
- api: 14265
- gossip-tcp: 15600
- zmq-feed: 5556
- nodeD:
- host: localhost
- podip: localhost
- ports:
- api: 14265
- gossip-tcp: 15600
- zmq-feed: 5556
- clusterip_ports:
- api: 14265
- gossip-tcp: 15600
- zmq-feed: 5556
+ zmq-feed: 6556
\ No newline at end of file
diff --git a/python-regression/tests/features/steps/api_test_steps.py b/python-regression/tests/features/steps/api_test_steps.py
index 886a4eea7b..9afdc7a8d5 100644
--- a/python-regression/tests/features/steps/api_test_steps.py
+++ b/python-regression/tests/features/steps/api_test_steps.py
@@ -23,7 +23,7 @@ def api_method_is_called(step, api_call, node_name):
:param api_call: The api call that will be requested
:param node_name: The name identifying the node you would like to make this request on
:param step.hashes: A gherkin table outlining any arguments needed for the call
- (See tests/features/machine1/1_api_tests.feature for examples)
+ (See tests/features/machine1/4_api_tests.feature for examples)
The table parameter is unique in that there are several input types available depending on the call
being made.
diff --git a/python-regression/tests/features/steps/response_handling_steps.py b/python-regression/tests/features/steps/response_handling_steps.py
index 87d372814b..c0c52584a1 100644
--- a/python-regression/tests/features/steps/response_handling_steps.py
+++ b/python-regression/tests/features/steps/response_handling_steps.py
@@ -1,4 +1,3 @@
-import logging
from aloe import world, step
from util.response_logic import response_handling as response_handling
from util.test_logic import api_test_logic as api_utils
diff --git a/python-regression/util/static_vals.py b/python-regression/util/static_vals.py
index a4d332bd50..035ea262ae 100644
--- a/python-regression/util/static_vals.py
+++ b/python-regression/util/static_vals.py
@@ -118,12 +118,13 @@
]
LS_PRUNED_TRANSACTIONS = [
- "FKGOUSFWFWSPQXPGEVBXQRYFRGFJWBXRYCXJDZTQWQBQKUJOGEY9JCIVYYSHGNFVIJBIXMZIVDUPBUIYA",
- "EVQEKYWYYDSPHYDVPHATRUHBMKANTTIRA9FXXUYSVRBSEMESKWDBJBWBDARWMGBCFWGI9CFOEI9MXGMYX",
- "HVGYYBVCBWKSMQFTFURLQWWRTNBKYXMXQ9QP9SHSNZJQQ9P9HL9IGNWZBTNMOOLV9GVOBPIBEUCXWNFAY",
- "KESYDCSVJ9TJJIOIMHJDMD9BSPWHQVUIKEBSMYLBTUZZTKKFALDTMATCQWAKIQHNHHZLP9NJFZJMFNEMC",
- "TJRXEMZZMORIHQSGOTRUFATRMMQF9NCGVVCKIDJFIMEZNXFGC9HZQQWZXTMIWILGYBBBFZURU99G9YRLY"
-]
+ "ZUGEWWWKGETGGVVVTXYFSMAP9KLRYQJSVHNTYWEXQONNNHTCMAMQANEPEFKNAJYRFJINTSHXTGFOWYWO9",
+ "UXBNYASZOCIGHTDTGHLJWRMUHXABNDSTDFVJLBIA9SMGYEFYZLKQETFIAERHSY9YZVUEJUMCTNQE9NIMY",
+ "XJZMRLGVXLIBAYPYWMZGXUZZWJEFAXRPGAAYIALSI9UBRSYDACGO9UEQJEOVROIBQMAMIFGZJHGHKUNNB",
+ "HDXVLKMJNKQNPTTSBETLNRY9WNWXILCTNICEEWEUKHKFFAHKA9D99XQCPQRHOVOBEYTLARJORYGMNHUOZ"
+ ]
+
+LS_PRUNING_TIP = "HO9YADXIDEUJUKOZYNWVRS9PWDXCFXNVM9LEGPZMBJSJKKQAZBFPXYMH9VABBG9NLNIDQPDLVWDKOEAOW"
UNCONFIRMED_TEST_ADDRESS = [
"OXKSHMEQYDMJMDPJX9FIEJVWOKCROTCBRPCDCCSBPMZ9EEQMHTEDSDKIKAMZTYNYWIIMZBFY9IXBUGTZD"
diff --git a/python-regression/util/test_logic/api_test_logic.py b/python-regression/util/test_logic/api_test_logic.py
index fbe2e4c204..f6fe3f858d 100644
--- a/python-regression/util/test_logic/api_test_logic.py
+++ b/python-regression/util/test_logic/api_test_logic.py
@@ -1,5 +1,4 @@
import json
-import logging
import urllib3
from aloe import world
from iota import Iota, Address, Tag, TryteString
diff --git a/python-regression/util/test_logic/value_fetch_logic.py b/python-regression/util/test_logic/value_fetch_logic.py
index 3dede4a655..9f662cb37c 100644
--- a/python-regression/util/test_logic/value_fetch_logic.py
+++ b/python-regression/util/test_logic/value_fetch_logic.py
@@ -121,6 +121,8 @@ def fetch_bool_list(value):
node = world.config['nodeId']
response = world.responses[api_call][node]
+ keys = list(response.keys())
+ response = response[keys[0]]
if value == "False":
return [False] * len(response)
diff --git a/src/main/java/com/iota/iri/Iota.java b/src/main/java/com/iota/iri/Iota.java
index c901fe8fff..420cc51c71 100644
--- a/src/main/java/com/iota/iri/Iota.java
+++ b/src/main/java/com/iota/iri/Iota.java
@@ -22,6 +22,8 @@
import com.iota.iri.service.transactionpruning.DepthPruningCondition;
import com.iota.iri.service.transactionpruning.SizePruningCondition;
import com.iota.iri.service.transactionpruning.TransactionPruner;
+import com.iota.iri.service.validation.TransactionSolidifier;
+import com.iota.iri.service.validation.TransactionValidator;
import com.iota.iri.storage.*;
import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider;
import com.iota.iri.utils.Pair;
@@ -95,6 +97,8 @@ public class Iota {
public final MilestoneSolidifier milestoneSolidifier;
+ public final TransactionSolidifier transactionSolidifier;
+
public final BundleValidator bundleValidator;
public final Tangle tangle;
@@ -126,7 +130,7 @@ public Iota(IotaConfig configuration, SpentAddressesProvider spentAddressesProvi
TransactionRequester transactionRequester, NeighborRouter neighborRouter,
TransactionProcessingPipeline transactionProcessingPipeline, TipsRequester tipsRequester,
TipsViewModel tipsViewModel, TipSelector tipsSelector, LocalSnapshotsPersistenceProvider localSnapshotsDb,
- CacheManager cacheManager) {
+ CacheManager cacheManager, TransactionSolidifier transactionSolidifier) {
this.configuration = configuration;
this.ledgerService = ledgerService;
@@ -144,9 +148,9 @@ public Iota(IotaConfig configuration, SpentAddressesProvider spentAddressesProvi
this.neighborRouter = neighborRouter;
this.txPipeline = transactionProcessingPipeline;
this.tipsRequester = tipsRequester;
+ this.transactionSolidifier = transactionSolidifier;
this.localSnapshotsDb = localSnapshotsDb;
-
// legacy classes
this.bundleValidator = bundleValidator;
this.tangle = tangle;
@@ -199,8 +203,6 @@ public void init() throws Exception {
tangle.clearMetadata(com.iota.iri.model.persistables.Transaction.class);
}
- transactionValidator.init();
-
txPipeline.start();
neighborRouter.start();
tipsRequester.start();
@@ -209,6 +211,7 @@ public void init() throws Exception {
latestSolidMilestoneTracker.start();
seenMilestonesRetriever.start();
milestoneSolidifier.start();
+ transactionSolidifier.start();
if (localSnapshotManager != null) {
localSnapshotManager.addSnapshotCondition(new SnapshotDepthCondition(configuration, snapshotProvider));
@@ -255,6 +258,7 @@ private void rescanDb() throws Exception {
public void shutdown() throws Exception {
// shutdown in reverse starting order (to not break any dependencies)
milestoneSolidifier.shutdown();
+ transactionSolidifier.shutdown();
seenMilestonesRetriever.shutdown();
latestSolidMilestoneTracker.shutdown();
latestMilestoneTracker.shutdown();
@@ -269,7 +273,6 @@ public void shutdown() throws Exception {
tipsRequester.shutdown();
txPipeline.shutdown();
neighborRouter.shutdown();
- transactionValidator.shutdown();
localSnapshotsDb.shutdown();
tangle.shutdown();
diff --git a/src/main/java/com/iota/iri/MainInjectionConfiguration.java b/src/main/java/com/iota/iri/MainInjectionConfiguration.java
index f512d3f7bc..ba01af69d2 100644
--- a/src/main/java/com/iota/iri/MainInjectionConfiguration.java
+++ b/src/main/java/com/iota/iri/MainInjectionConfiguration.java
@@ -4,7 +4,6 @@
import com.iota.iri.cache.impl.CacheManagerImpl;
import com.iota.iri.conf.IotaConfig;
import com.iota.iri.controllers.TipsViewModel;
-import com.iota.iri.model.persistables.Transaction;
import com.iota.iri.network.NeighborRouter;
import com.iota.iri.network.TipsRequester;
import com.iota.iri.network.TransactionRequester;
@@ -28,6 +27,9 @@
import com.iota.iri.service.tipselection.impl.*;
import com.iota.iri.service.transactionpruning.TransactionPruner;
import com.iota.iri.service.transactionpruning.async.AsyncTransactionPruner;
+import com.iota.iri.service.validation.TransactionSolidifier;
+import com.iota.iri.service.validation.TransactionValidator;
+import com.iota.iri.service.validation.impl.TransactionSolidifierImpl;
import com.iota.iri.storage.LocalSnapshotsPersistenceProvider;
import com.iota.iri.storage.Tangle;
import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider;
@@ -116,8 +118,8 @@ SeenMilestonesRetriever provideSeenMilestonesRetriever(Tangle tangle, SnapshotPr
@Singleton
@Provides
- MilestoneSolidifier provideMilestoneSolidifier(SnapshotProvider snapshotProvider, TransactionValidator transactionValidator) {
- return new MilestoneSolidifierImpl(snapshotProvider, transactionValidator);
+ MilestoneSolidifier provideMilestoneSolidifier(SnapshotProvider snapshotProvider, TransactionSolidifier transactionSolidifier) {
+ return new MilestoneSolidifierImpl(snapshotProvider, transactionSolidifier);
}
@Singleton
@@ -138,8 +140,14 @@ LocalSnapshotManager provideLocalSnapshotManager(SnapshotProvider snapshotProvid
@Singleton
@Provides
- TransactionValidator provideTransactionValidator(Tangle tangle, SnapshotProvider snapshotProvider, TipsViewModel tipsViewModel, TransactionRequester transactionRequester) {
- return new TransactionValidator(tangle, snapshotProvider, tipsViewModel, transactionRequester, configuration);
+ TransactionValidator provideTransactionValidator(SnapshotProvider snapshotProvider, TransactionRequester transactionRequester) {
+ return new TransactionValidator(snapshotProvider, transactionRequester, configuration);
+ }
+
+ @Singleton
+ @Provides
+ TransactionSolidifier provideTransactionSolidifier(Tangle tangle, SnapshotProvider snapshotProvider, TransactionRequester transactionRequester, TipsViewModel tipsViewModel){
+ return new TransactionSolidifierImpl(tangle, snapshotProvider, transactionRequester, tipsViewModel);
}
@Singleton
@@ -174,12 +182,12 @@ Iota provideIota(SpentAddressesProvider spentAddressesProvider, SpentAddressesSe
TransactionRequester transactionRequester, NeighborRouter neighborRouter,
TransactionProcessingPipeline transactionProcessingPipeline, TipsRequester tipsRequester,
TipsViewModel tipsViewModel, TipSelector tipsSelector, LocalSnapshotsPersistenceProvider localSnapshotsDb,
- CacheManager cacheManager) {
+ CacheManager cacheManager, TransactionSolidifier transactionSolidifier) {
return new Iota(configuration, spentAddressesProvider, spentAddressesService, snapshotProvider, snapshotService,
localSnapshotManager, milestoneService, latestMilestoneTracker, latestSolidMilestoneTracker,
seenMilestonesRetriever, ledgerService, transactionPruner, milestoneSolidifier, bundleValidator, tangle,
transactionValidator, transactionRequester, neighborRouter, transactionProcessingPipeline,
- tipsRequester, tipsViewModel, tipsSelector, localSnapshotsDb, cacheManager);
+ tipsRequester, tipsViewModel, tipsSelector, localSnapshotsDb, cacheManager, transactionSolidifier);
}
@Singleton
@@ -191,8 +199,8 @@ IXI provideIxi(Iota iota) {
@Singleton
@Provides
@Named("AsyncTipSelSolidifier")
- TipSelSolidifier provideAsyncTipSelSolidifier (TransactionValidator transactionValidator) {
- return new AsyncTipSelSolidifier(transactionValidator);
+ TipSelSolidifier provideAsyncTipSelSolidifier (TransactionSolidifier transactionSolidifier) {
+ return new AsyncTipSelSolidifier(transactionSolidifier);
}
@Singleton
@@ -204,15 +212,14 @@ TipSelSolidifier provideDummyTipSelSolidifier () {
@Singleton
@Provides
- API provideApi(IXI ixi, TransactionRequester transactionRequester, SpentAddressesService spentAddressesService,
- Tangle tangle, BundleValidator bundleValidator, SnapshotProvider snapshotProvider,
- LedgerService ledgerService, NeighborRouter neighborRouter, TipSelector tipsSelector,
- TipsViewModel tipsViewModel, TransactionValidator transactionValidator,
- LatestMilestoneTracker latestMilestoneTracker, TransactionProcessingPipeline txPipeline,
- @Named("DummyTipSelSolidifier") TipSelSolidifier checkConsistencySolidifier) {
+ API provideApi(IXI ixi, TransactionRequester transactionRequester,
+ SpentAddressesService spentAddressesService, Tangle tangle, BundleValidator bundleValidator,
+ SnapshotProvider snapshotProvider, LedgerService ledgerService, NeighborRouter neighborRouter, TipSelector tipsSelector,
+ TipsViewModel tipsViewModel, TransactionValidator transactionValidator,
+ LatestMilestoneTracker latestMilestoneTracker, TransactionProcessingPipeline txPipeline, TransactionSolidifier transactionSolidifier, @Named("DummyTipSelSolidifier") TipSelSolidifier checkConsistencySolidifier) {
return new API(configuration, ixi, transactionRequester, spentAddressesService, tangle, bundleValidator,
snapshotProvider, ledgerService, neighborRouter, tipsSelector, tipsViewModel, transactionValidator,
- latestMilestoneTracker, txPipeline, checkConsistencySolidifier);
+ latestMilestoneTracker, txPipeline,transactionSolidifier, checkConsistencySolidifier);
}
@Singleton
diff --git a/src/main/java/com/iota/iri/TransactionValidator.java b/src/main/java/com/iota/iri/TransactionValidator.java
deleted file mode 100644
index 23d1a77692..0000000000
--- a/src/main/java/com/iota/iri/TransactionValidator.java
+++ /dev/null
@@ -1,464 +0,0 @@
-package com.iota.iri;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.iota.iri.conf.ProtocolConfig;
-import com.iota.iri.controllers.TipsViewModel;
-import com.iota.iri.controllers.TransactionViewModel;
-import com.iota.iri.crypto.Curl;
-import com.iota.iri.crypto.Sponge;
-import com.iota.iri.crypto.SpongeFactory;
-import com.iota.iri.model.Hash;
-import com.iota.iri.model.TransactionHash;
-import com.iota.iri.network.TransactionRequester;
-import com.iota.iri.service.snapshot.SnapshotProvider;
-import com.iota.iri.storage.Tangle;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static com.iota.iri.controllers.TransactionViewModel.*;
-
-public class TransactionValidator {
- private static final Logger log = LoggerFactory.getLogger(TransactionValidator.class);
- private static final int TESTNET_MWM_CAP = 13;
- public static final int SOLID_SLEEP_TIME = 500;
-
- private final Tangle tangle;
- private final SnapshotProvider snapshotProvider;
- private final TipsViewModel tipsViewModel;
- private final TransactionRequester transactionRequester;
- private int minWeightMagnitude = 81;
- private static final long MAX_TIMESTAMP_FUTURE = 2L * 60L * 60L;
- private static final long MAX_TIMESTAMP_FUTURE_MS = MAX_TIMESTAMP_FUTURE * 1_000L;
-
-
- /////////////////////////////////fields for solidification thread//////////////////////////////////////
-
- private Thread newSolidThread;
-
- /**
- * If true use {@link #newSolidTransactionsOne} while solidifying. Else use {@link #newSolidTransactionsTwo}.
- */
- private final AtomicBoolean useFirst = new AtomicBoolean(true);
- /**
- * Is {@link #newSolidThread} shutting down
- */
- private final AtomicBoolean shuttingDown = new AtomicBoolean(false);
- /**
- * mutex for solidification
- */
- private final Object cascadeSync = new Object();
- private final Set
- * First the attachment timestamp (set after performing POW) is checked, and if not available
- * the regular timestamp is checked. Genesis transaction will always be valid.
- *
- *
- *
- *
- * @see #spawnSolidTransactionsPropagation()
- */
- public void init() {
- newSolidThread.start();
- }
-
- @VisibleForTesting
- void setMwm(boolean testnet, int mwm) {
- minWeightMagnitude = mwm;
-
- //lowest allowed MWM encoded in 46 bytes.
- if (!testnet){
- minWeightMagnitude = Math.max(minWeightMagnitude, TESTNET_MWM_CAP);
- }
- }
-
- /**
- * Shutdown roots to tip solidification thread
- * @throws InterruptedException
- * @see #spawnSolidTransactionsPropagation()
- */
- public void shutdown() throws InterruptedException {
- shuttingDown.set(true);
- newSolidThread.join();
- }
-
- /**
- * @return the minimal number of trailing 9s that have to be present at the end of the transaction hash
- * in order to validate that sufficient proof of work has been done
- */
- public int getMinWeightMagnitude() {
- return minWeightMagnitude;
- }
-
- /**
- * Checks that the timestamp of the transaction is below the last global snapshot time
- * or more than {@value #MAX_TIMESTAMP_FUTURE} seconds in the future, and thus invalid.
- *
- *
- *
- *Exception is thrown upon failure.
- *
- * @param transactionViewModel transaction that should be validated
- * @param minWeightMagnitude the minimal number of trailing 9s at the end of the transaction hash
- * @throws StaleTimestampException if timestamp check fails
- * @throws IllegalStateException if any of the other checks fail
- */
- public void runValidation(TransactionViewModel transactionViewModel, final int minWeightMagnitude) {
- transactionViewModel.setMetadata();
- transactionViewModel.setAttachmentData();
- if(hasInvalidTimestamp(transactionViewModel)) {
- throw new StaleTimestampException("Invalid transaction timestamp.");
- }
- for (int i = VALUE_TRINARY_OFFSET + VALUE_USABLE_TRINARY_SIZE; i < VALUE_TRINARY_OFFSET + VALUE_TRINARY_SIZE; i++) {
- if (transactionViewModel.trits()[i] != 0) {
- throw new IllegalStateException("Invalid transaction value");
- }
- }
-
- int weightMagnitude = transactionViewModel.weightMagnitude;
- if(weightMagnitude < minWeightMagnitude) {
- throw new IllegalStateException("Invalid weight magnitude");
- }
-
- if (transactionViewModel.value() != 0 && transactionViewModel.getAddressHash().trits()[Curl.HASH_LENGTH - 1] != 0) {
- throw new IllegalStateException("Invalid transaction address");
- }
- }
-
- /**
- * Creates a new transaction from {@code trits} and validates it with {@link #runValidation}.
- *
- * @param trits raw transaction trits
- * @param minWeightMagnitude minimal number of trailing 9s in transaction for POW validation
- * @return the transaction resulting from the raw trits if valid.
- * @throws RuntimeException if validation fails
- */
- public TransactionViewModel validateTrits(final byte[] trits, int minWeightMagnitude) {
- TransactionViewModel transactionViewModel = new TransactionViewModel(trits, TransactionHash.calculate(trits, 0, trits.length, SpongeFactory.create(SpongeFactory.Mode.CURLP81)));
- runValidation(transactionViewModel, minWeightMagnitude);
- return transactionViewModel;
- }
-
- /**
- * Creates a new transaction from {@code bytes} and validates it with {@link #runValidation}.
- *
- * @param bytes raw transaction bytes
- * @param minWeightMagnitude minimal number of trailing 9s in transaction for POW validation
- * @return the transaction resulting from the raw bytes if valid
- * @throws RuntimeException if validation fails
- */
- public TransactionViewModel validateBytes(final byte[] bytes, int minWeightMagnitude, Sponge curl) {
- TransactionViewModel transactionViewModel = new TransactionViewModel(bytes, TransactionHash.calculate(bytes, TRINARY_SIZE, curl));
- runValidation(transactionViewModel, minWeightMagnitude);
- return transactionViewModel;
- }
-
- /**
- * This method does the same as {@link #checkSolidity(Hash, int)} but defaults to an unlimited amount
- * of transactions that are allowed to be traversed.
- *
- * @param hash hash of the transactions that shall get checked
- * @return true if the transaction is solid and false otherwise
- * @throws Exception if anything goes wrong while trying to solidify the transaction
- */
- public boolean checkSolidity(Hash hash) throws Exception {
- return checkSolidity(hash, Integer.MAX_VALUE);
- }
-
- /**
- * This method checks transactions for solidity and marks them accordingly if they are found to be solid.
- *
- * It iterates through all approved transactions until it finds one that is missing in the database or until it
- * reached solid transactions on all traversed subtangles. In case of a missing transactions it issues a transaction
- * request and returns false. If no missing transaction is found, it marks the processed transactions as solid in
- * the database and returns true.
- *
- * Since this operation can potentially take a long time to terminate if it would have to traverse big parts of the
- * tangle, it is possible to limit the amount of transactions that are allowed to be processed, while looking for
- * unsolid / missing approvees. This can be useful when trying to "interrupt" the solidification of one transaction
- * (if it takes too many steps) to give another one the chance to be solidified instead (i.e. prevent blocks in the
- * solidification threads).
- *
- * @param hash hash of the transactions that shall get checked
- * @param maxProcessedTransactions the maximum amount of transactions that are allowed to be traversed
- * @return true if the transaction is solid and false otherwise
- * @throws Exception if anything goes wrong while trying to solidify the transaction
- */
- public boolean checkSolidity(Hash hash, int maxProcessedTransactions) throws Exception {
- if(fromHash(tangle, hash).isSolid()) {
- return true;
- }
- LinkedHashSet
- *
- * @param transactionViewModel received transaction that is being updated
- * @throws Exception if an error occurred while trying to solidify
- * @see TipsViewModel
- */
- //Not part of the validation process. This should be moved to a component in charge of
- //what transaction we gossip.
- public void updateStatus(TransactionViewModel transactionViewModel) throws Exception {
- transactionRequester.clearTransactionRequest(transactionViewModel.getHash());
- if(transactionViewModel.getApprovers(tangle).size() == 0) {
- tipsViewModel.addTipHash(transactionViewModel.getHash());
- }
- tipsViewModel.removeTipHash(transactionViewModel.getTrunkTransactionHash());
- tipsViewModel.removeTipHash(transactionViewModel.getBranchTransactionHash());
-
- if(quickSetSolid(transactionViewModel)) {
- tipsViewModel.setSolid(transactionViewModel.getHash());
- addSolidTransaction(transactionViewModel.getHash());
- }
- }
-
- /**
- * Perform a {@link #quickSetSolid} while capturing and logging errors
- * @param transactionViewModel transaction we try to solidify.
- * @return true if we managed to solidify, else false.
- */
- private boolean quietQuickSetSolid(TransactionViewModel transactionViewModel) {
- try {
- return quickSetSolid(transactionViewModel);
- } catch (Exception e) {
- log.error(e.getMessage(), e);
- return false;
- }
- }
-
- /**
- * Tries to solidify the transactions quickly by performing {@link #checkApproovee} on both parents (trunk and
- * branch). If the parents are solid, mark the transactions as solid.
- * @param transactionViewModel transaction to solidify
- * @return true if we made the transaction solid, else false.
- * @throws Exception
- */
- private boolean quickSetSolid(final TransactionViewModel transactionViewModel) throws Exception {
- if(!transactionViewModel.isSolid()) {
- boolean solid = true;
- if (!checkApproovee(transactionViewModel.getTrunkTransaction(tangle))) {
- solid = false;
- }
- if (!checkApproovee(transactionViewModel.getBranchTransaction(tangle))) {
- solid = false;
- }
- if(solid) {
- transactionViewModel.updateSolid(tangle, snapshotProvider.getInitialSnapshot(), true);
- transactionViewModel.updateHeights(tangle, snapshotProvider.getInitialSnapshot());
- return true;
- }
- }
- return false;
- }
-
- /**
- * If the the {@code approvee} is missing, request it from a neighbor.
- * @param approovee transaction we check.
- * @return true if {@code approvee} is solid.
- * @throws Exception if we encounter an error while requesting a transaction
- */
- private boolean checkApproovee(TransactionViewModel approovee) throws Exception {
- if(snapshotProvider.getInitialSnapshot().hasSolidEntryPoint(approovee.getHash())) {
- return true;
- }
- if(approovee.getType() == PREFILLED_SLOT) {
- // don't solidify from the bottom until cuckoo filters can identify where we deleted -> otherwise we will
- // continue requesting old transactions forever
- //transactionRequester.requestTransaction(approovee.getHash(), false);
- return false;
- }
- return approovee.isSolid();
- }
-
- @VisibleForTesting
- boolean isNewSolidTxSetsEmpty () {
- return newSolidTransactionsOne.isEmpty() && newSolidTransactionsTwo.isEmpty();
- }
-
- /**
- * Thrown if transaction fails {@link #hasInvalidTimestamp} check.
- */
- public static class StaleTimestampException extends RuntimeException {
- StaleTimestampException (String message) {
- super(message);
- }
- }
-}
diff --git a/src/main/java/com/iota/iri/controllers/TransactionViewModel.java b/src/main/java/com/iota/iri/controllers/TransactionViewModel.java
index 32e99df332..9c3da45ea6 100644
--- a/src/main/java/com/iota/iri/controllers/TransactionViewModel.java
+++ b/src/main/java/com/iota/iri/controllers/TransactionViewModel.java
@@ -4,6 +4,7 @@
import com.iota.iri.model.*;
import com.iota.iri.model.persistables.*;
import com.iota.iri.service.snapshot.Snapshot;
+import com.iota.iri.service.validation.TransactionValidator;
import com.iota.iri.storage.Indexable;
import com.iota.iri.storage.Persistable;
import com.iota.iri.storage.Tangle;
@@ -512,9 +513,10 @@ public final int getType() {
/**
* Sets the {@link Transaction#arrivalTime}.
*
- * @param tangle The tangle reference for the database.
- * @param initialSnapshot snapshot that acts as genesis
- * @param time The time to be set in the {@link Transaction}
+ * @param tangle The tangle reference for the database.
+ * @param initialSnapshot snapshot that acts as genesis
+ * @param time The time to be set in the {@link Transaction}
+ * @throws Exception Exception
*/
public void setArrivalTime(Tangle tangle, Snapshot initialSnapshot, long time) throws Exception {
transaction.arrivalTime = time;
@@ -778,36 +780,15 @@ public void setMetadata() {
: TransactionViewModel.FILLED_SLOT);
}
- /**
- * Update solid transactions
- * @param tangle Tangle
- * @param initialSnapshot Initial snapshot
- * @param analyzedHashes analyzed hashes
- * @throws Exception Exception
- */
- public static void updateSolidTransactions(Tangle tangle, Snapshot initialSnapshot,
- final Set
* Note: We want to find the next previous milestone and not get stuck somewhere at the end of the tangle with a - * long running {@link TransactionValidator#checkSolidity(Hash)} call. + * long running {@link TransactionSolidifier#checkSolidity(Hash)} call. *
*/ int SOLIDIFICATION_TRANSACTIONS_LIMIT = 50000; diff --git a/src/main/java/com/iota/iri/service/milestone/impl/MilestoneSolidifierImpl.java b/src/main/java/com/iota/iri/service/milestone/impl/MilestoneSolidifierImpl.java index a7677373ce..9db1887a42 100644 --- a/src/main/java/com/iota/iri/service/milestone/impl/MilestoneSolidifierImpl.java +++ b/src/main/java/com/iota/iri/service/milestone/impl/MilestoneSolidifierImpl.java @@ -1,6 +1,6 @@ package com.iota.iri.service.milestone.impl; -import com.iota.iri.TransactionValidator; +import com.iota.iri.service.validation.TransactionSolidifier; import com.iota.iri.model.Hash; import com.iota.iri.service.milestone.MilestoneSolidifier; import com.iota.iri.service.snapshot.SnapshotProvider; @@ -35,7 +35,19 @@ public class MilestoneSolidifierImpl implements MilestoneSolidifier { /** * Defines the interval in which solidity checks are issued (in milliseconds). */ - private static final int SOLIDIFICATION_INTERVAL = 500; + private static final int SOLIDIFICATION_INTERVAL = 100; + + /** + *+ * Defines the maximum amount of transactions that are allowed to get processed while trying to solidify a + * milestone. + *
+ *+ * Note: We want to find the next previous milestone and not get stuck somewhere at the end of the tangle with a + * long running {@link TransactionSolidifier#checkSolidity(Hash)} call. + *
+ */ + private static final int SOLIDIFICATION_TRANSACTIONS_LIMIT = 50000; /** * Logger for this class allowing us to dump debug and status messages. @@ -48,9 +60,9 @@ public class MilestoneSolidifierImpl implements MilestoneSolidifier { private final SnapshotProvider snapshotProvider; /** - * Holds a reference to the TransactionValidator which allows us to issue solidity checks. + * Holds a reference to the transactionSolidifier which allows us to issue solidity checks. */ - private final TransactionValidator transactionValidator; + private final TransactionSolidifier transactionSolidifier; /** * Holds a reference to the manager of the background worker. @@ -93,16 +105,16 @@ public class MilestoneSolidifierImpl implements MilestoneSolidifier { /** * @param snapshotProvider snapshot provider which gives us access to the relevant snapshots - * @param transactionValidator TransactionValidator instance that is used by the node + * @param transactionSolidifier transactionSolidifier instance that is used by the node */ - public MilestoneSolidifierImpl(SnapshotProvider snapshotProvider, TransactionValidator transactionValidator) { + public MilestoneSolidifierImpl(SnapshotProvider snapshotProvider, TransactionSolidifier transactionSolidifier) { this.snapshotProvider = snapshotProvider; - this.transactionValidator = transactionValidator; + this.transactionSolidifier = transactionSolidifier; } /** * {@inheritDoc} - * + * *
* Since this method might be called from a performance critical context, we simply add the milestone to a temporary
* pool, that gets examined later by the background process. This doesn't just speed up the addition of new jobs but
@@ -194,7 +206,7 @@ private void milestoneSolidificationThread() {
*/
private void processNewlyAddedMilestones() {
for (Iterator
* It first dumps a log message to keep the node operator informed about the progress of solidification, and then - * issues the {@link TransactionValidator#checkSolidity(Hash, int)} call that starts the solidification + * issues the {@link TransactionSolidifier#checkSolidity(Hash, int)} call that starts the solidification * process. *
*
@@ -329,11 +341,11 @@ private boolean isSolid(Map.Entry
+ * First the attachment timestamp (set after performing POW) is checked, and if not available
+ * the regular timestamp is checked. Genesis transaction will always be valid.
+ *
+ *
+ * @param transactionViewModel received transaction that is being updated
+ * @throws Exception if an error occurred while trying to solidify
+ * @see TipsViewModel
+ */
+ void updateStatus(TransactionViewModel transactionViewModel) throws Exception;
+
+ /**
+ * Tries to solidify the transactions quickly by performing {@link TransactionSolidifierImpl#checkApproovee} on
+ * both parents (trunk and branch). If the parents are solid, mark the transactions as solid.
+ * @param transactionViewModel transaction to solidify
+ * @return true if we made the transaction solid, else false.
+ * @throws Exception
+ */
+ boolean quickSetSolid(TransactionViewModel transactionViewModel) throws Exception;
+}
\ No newline at end of file
diff --git a/src/main/java/com/iota/iri/service/validation/TransactionValidator.java b/src/main/java/com/iota/iri/service/validation/TransactionValidator.java
new file mode 100644
index 0000000000..dd4ea75028
--- /dev/null
+++ b/src/main/java/com/iota/iri/service/validation/TransactionValidator.java
@@ -0,0 +1,170 @@
+package com.iota.iri.service.validation;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.iota.iri.conf.ProtocolConfig;
+import com.iota.iri.controllers.TransactionViewModel;
+import com.iota.iri.crypto.Curl;
+import com.iota.iri.crypto.Sponge;
+import com.iota.iri.crypto.SpongeFactory;
+import com.iota.iri.model.TransactionHash;
+import com.iota.iri.network.TransactionRequester;
+import com.iota.iri.service.snapshot.SnapshotProvider;
+
+/**
+ * Tool for determining validity of a transaction via a {@link TransactionViewModel}, tryte array or byte array.
+ */
+public class TransactionValidator {
+ private static final int TESTNET_MWM_CAP = 13;
+
+ private final SnapshotProvider snapshotProvider;
+ private final TransactionRequester transactionRequester;
+ private int minWeightMagnitude = 81;
+ private static final long MAX_TIMESTAMP_FUTURE = 2L * 60L * 60L;
+ private static final long MAX_TIMESTAMP_FUTURE_MS = MAX_TIMESTAMP_FUTURE * 1_000L;
+
+
+ /**
+ * Constructor for Tangle Validator
+ *
+ * @param snapshotProvider data provider for the snapshots that are relevant for the node
+ * @param transactionRequester used to request missing transactions from neighbors
+ * @param protocolConfig used for checking if we are in testnet and mwm. testnet true if we are in testnet
+ * mode, this caps {@code mwm} to {@value #TESTNET_MWM_CAP} regardless of parameter input.
+ * minimum weight magnitude: the minimal number of 9s that ought to appear at the end of the
+ * transaction hash
+ */
+ public TransactionValidator(SnapshotProvider snapshotProvider, TransactionRequester transactionRequester, ProtocolConfig protocolConfig) {
+ this.snapshotProvider = snapshotProvider;
+ this.transactionRequester = transactionRequester;
+ setMwm(protocolConfig.isTestnet(), protocolConfig.getMwm());
+ }
+
+ /**
+ * Set the Minimum Weight Magnitude for validation checks.
+ */
+ @VisibleForTesting
+ void setMwm(boolean testnet, int mwm) {
+ minWeightMagnitude = mwm;
+
+ //lowest allowed MWM encoded in 46 bytes.
+ if (!testnet){
+ minWeightMagnitude = Math.max(minWeightMagnitude, TESTNET_MWM_CAP);
+ }
+ }
+
+ /**
+ * @return the minimal number of trailing 9s that have to be present at the end of the transaction hash
+ * in order to validate that sufficient proof of work has been done
+ */
+ public int getMinWeightMagnitude() {
+ return minWeightMagnitude;
+ }
+
+ /**
+ * Checks that the timestamp of the transaction is below the last global snapshot time
+ * or more than {@value #MAX_TIMESTAMP_FUTURE} seconds in the future, and thus invalid.
+ *
+ *
+ *
+ *Exception is thrown upon failure.
+ *
+ * @param transactionViewModel transaction that should be validated
+ * @param minWeightMagnitude the minimal number of trailing 9s at the end of the transaction hash
+ * @throws StaleTimestampException if timestamp check fails
+ * @throws IllegalStateException if any of the other checks fail
+ */
+ public void runValidation(TransactionViewModel transactionViewModel, final int minWeightMagnitude) {
+ transactionViewModel.setMetadata();
+ transactionViewModel.setAttachmentData();
+ if (hasInvalidTimestamp(transactionViewModel)) {
+ throw new StaleTimestampException("Invalid transaction timestamp.");
+ }
+
+ confirmValidTransactionValues(transactionViewModel);
+ int weightMagnitude = transactionViewModel.weightMagnitude;
+ if (weightMagnitude < minWeightMagnitude) {
+ throw new IllegalStateException("Invalid transaction hash");
+ }
+
+ if (transactionViewModel.value() != 0 && transactionViewModel.getAddressHash().trits()[Curl.HASH_LENGTH - 1] != 0) {
+ throw new IllegalStateException("Invalid transaction address");
+ }
+ }
+
+ private void confirmValidTransactionValues(TransactionViewModel transactionViewModel) throws IllegalStateException {
+ for (int i = TransactionViewModel.VALUE_TRINARY_OFFSET + TransactionViewModel.VALUE_USABLE_TRINARY_SIZE;
+ i < TransactionViewModel.VALUE_TRINARY_OFFSET + TransactionViewModel.VALUE_TRINARY_SIZE; i++) {
+ if (transactionViewModel.trits()[i] != 0) {
+ throw new IllegalStateException("Invalid transaction value");
+ }
+ }
+ }
+
+ /**
+ * Creates a new transaction from {@code trits} and validates it with {@link #runValidation}.
+ *
+ * @param trits raw transaction trits
+ * @param minWeightMagnitude minimal number of trailing 9s in transaction for POW validation
+ * @return the transaction resulting from the raw trits if valid.
+ * @throws RuntimeException if validation fails
+ */
+ public TransactionViewModel validateTrits(final byte[] trits, int minWeightMagnitude) {
+ TransactionViewModel transactionViewModel = new TransactionViewModel(trits, TransactionHash.calculate(trits, 0, trits.length, SpongeFactory.create(SpongeFactory.Mode.CURLP81)));
+ runValidation(transactionViewModel, minWeightMagnitude);
+ return transactionViewModel;
+ }
+
+ /**
+ * Creates a new transaction from {@code bytes} and validates it with {@link #runValidation}.
+ *
+ * @param bytes raw transaction bytes
+ * @param minWeightMagnitude minimal number of trailing 9s in transaction for POW validation
+ * @return the transaction resulting from the raw bytes if valid
+ * @throws RuntimeException if validation fails
+ */
+ public TransactionViewModel validateBytes(final byte[] bytes, int minWeightMagnitude, Sponge curl) {
+ TransactionViewModel transactionViewModel = new TransactionViewModel(bytes, TransactionHash.calculate(bytes,
+ TransactionViewModel.TRINARY_SIZE, curl));
+ runValidation(transactionViewModel, minWeightMagnitude);
+ return transactionViewModel;
+ }
+
+ /**
+ * Thrown if transaction fails {@link #hasInvalidTimestamp} check.
+ */
+ public static class StaleTimestampException extends RuntimeException {
+ StaleTimestampException (String message) {
+ super(message);
+ }
+ }
+}
diff --git a/src/main/java/com/iota/iri/service/validation/impl/TransactionSolidifierImpl.java b/src/main/java/com/iota/iri/service/validation/impl/TransactionSolidifierImpl.java
new file mode 100644
index 0000000000..9c5c9f7363
--- /dev/null
+++ b/src/main/java/com/iota/iri/service/validation/impl/TransactionSolidifierImpl.java
@@ -0,0 +1,334 @@
+package com.iota.iri.service.validation.impl;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.iota.iri.controllers.TipsViewModel;
+import com.iota.iri.controllers.TransactionViewModel;
+import com.iota.iri.model.Hash;
+import com.iota.iri.network.pipeline.TransactionProcessingPipeline;
+import com.iota.iri.network.TransactionRequester;
+import com.iota.iri.service.snapshot.SnapshotProvider;
+import com.iota.iri.service.validation.TransactionSolidifier;
+import com.iota.iri.storage.Tangle;
+import com.iota.iri.utils.log.interval.IntervalLogger;
+import com.iota.iri.utils.thread.DedicatedScheduledExecutorService;
+import com.iota.iri.utils.thread.SilentScheduledExecutorService;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import static com.iota.iri.controllers.TransactionViewModel.PREFILLED_SLOT;
+import static com.iota.iri.controllers.TransactionViewModel.fromHash;
+
+/**
+ * A solidifier class for processing transactions. Transactions are checked for solidity, and missing transactions are
+ * subsequently requested. Once a transaction is solidified correctly it is placed into a broadcasting set to be sent to
+ * neighboring nodes.
+ */
+public class TransactionSolidifierImpl implements TransactionSolidifier {
+
+ private Tangle tangle;
+ private SnapshotProvider snapshotProvider;
+ private TransactionRequester transactionRequester;
+
+ /**
+ * Max size for all queues.
+ */
+ private static final int MAX_SIZE= 10000;
+
+ private static final int SOLIDIFICATION_INTERVAL = 100;
+
+ private static final IntervalLogger log = new IntervalLogger(TransactionSolidifier.class);
+
+ /**
+ * Executor service for running the {@link #processTransactionsToSolidify()}.
+ */
+ private SilentScheduledExecutorService executorService = new DedicatedScheduledExecutorService(
+ "Transaction Solidifier", log.delegate());
+
+ /**
+ * A set of transactions that will be called by the {@link TransactionProcessingPipeline} to be broadcast to
+ * neighboring nodes.
+ */
+ private BlockingQueue