├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── regression-test.md └── pull_request_template.md ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── DOCKER.md ├── Dockerfile ├── LICENSE ├── README.md ├── STYLEGUIDE.md ├── changelog.txt ├── checkstyle.xml ├── codesigning.asc.enc ├── docker ├── entrypoint.sh └── ssl │ ├── README.md │ ├── docker-compose.yml │ ├── nginx-image │ ├── Dockerfile │ ├── nginx-secure.conf │ ├── nginx.conf │ └── start.sh │ └── start.sh ├── format.importorder ├── format_settings.epf ├── logo.utf8.ans ├── pom.xml ├── python-regression ├── .gitignore ├── README.md ├── ciglue.sh ├── setup.py ├── snapshot.txt ├── tests │ ├── __init__.py │ └── features │ │ ├── __init__.py │ │ ├── machine1 │ │ ├── 1_api_tests.feature │ │ ├── __init__.py │ │ └── config.yml │ │ ├── machine3 │ │ ├── 3_blowball_tests.feature │ │ ├── __init__.py │ │ └── config.yml │ │ ├── machine4 │ │ ├── 4_stitching.feature │ │ ├── __init__.py │ │ └── config.yml │ │ ├── machine5 │ │ ├── 5_milestone_validation.feature │ │ ├── __init__.py │ │ └── config.yml │ │ └── steps │ │ ├── __init__.py │ │ ├── api_test_steps.py │ │ ├── machine_configuration_steps.py │ │ ├── response_handling_steps.py │ │ └── transaction_steps.py └── util │ ├── __init__.py │ ├── checksum.py │ ├── neighbor_logic │ ├── __init__.py │ └── neighbor_logic.py │ ├── node │ ├── find_nodes.py │ ├── make_nodes.py │ ├── node_info_fetcher.py │ └── tear_down_nodes.py │ ├── response_logic │ ├── __init__.py │ └── response_handling.py │ ├── static_vals.py │ ├── test_logic │ ├── __init__.py │ └── api_test_logic.py │ ├── threading_logic │ ├── __init__.py │ ├── pool_logic.py │ └── thread_logic.py │ └── transaction_bundle_logic │ ├── __init__.py │ └── transaction_logic.py ├── ruleset.xml └── src ├── deb ├── control │ ├── control │ ├── postinst │ ├── postrm │ ├── preinst │ └── prerm └── init.d │ └── iri ├── main ├── java │ └── com │ │ └── iota │ │ └── iri │ │ ├── BundleValidator.java │ │ ├── CLIRI.java │ │ ├── IXI.java │ │ ├── Iota.java │ │ ├── IxiEvent.java │ │ ├── LedgerValidator.java │ │ ├── LedgerValidatorImpl.java │ │ ├── OsVariants.java │ │ ├── SignedFiles.java │ │ ├── TransactionValidator.java │ │ ├── conf │ │ ├── APIConfig.java │ │ ├── BaseIotaConfig.java │ │ ├── Config.java │ │ ├── ConfigFactory.java │ │ ├── DbConfig.java │ │ ├── IXIConfig.java │ │ ├── IotaConfig.java │ │ ├── MainnetConfig.java │ │ ├── NetworkConfig.java │ │ ├── NodeConfig.java │ │ ├── PearlDiverConfig.java │ │ ├── ProtocolConfig.java │ │ ├── TestnetConfig.java │ │ ├── TipSelConfig.java │ │ ├── ZMQConfig.java │ │ └── deserializers │ │ │ ├── CustomBoolDeserializer.java │ │ │ └── CustomStringDeserializer.java │ │ ├── controllers │ │ ├── AddressViewModel.java │ │ ├── ApproveeViewModel.java │ │ ├── BundleViewModel.java │ │ ├── HashesViewModel.java │ │ ├── TagViewModel.java │ │ ├── TipsViewModel.java │ │ └── TransactionViewModel.java │ │ ├── crypto │ │ ├── Curl.java │ │ ├── ISS.java │ │ ├── ISSInPlace.java │ │ ├── Kerl.java │ │ ├── PearlDiver.java │ │ ├── Sponge.java │ │ └── SpongeFactory.java │ │ ├── model │ │ ├── AbstractHash.java │ │ ├── AddressHash.java │ │ ├── BundleHash.java │ │ ├── Hash.java │ │ ├── HashFactory.java │ │ ├── HashId.java │ │ ├── HashPrefix.java │ │ ├── IntegerIndex.java │ │ ├── ObsoleteTagHash.java │ │ ├── TagHash.java │ │ ├── TransactionHash.java │ │ ├── persistables │ │ │ ├── Address.java │ │ │ ├── Approvee.java │ │ │ ├── Bundle.java │ │ │ ├── Hashes.java │ │ │ ├── ObsoleteTag.java │ │ │ ├── Tag.java │ │ │ └── Transaction.java │ │ └── safe │ │ │ ├── ByteSafe.java │ │ │ ├── HashSafeObject.java │ │ │ ├── SafeObject.java │ │ │ └── TritSafe.java │ │ ├── network │ │ ├── Neighbor.java │ │ ├── Node.java │ │ ├── TCPNeighbor.java │ │ ├── TransactionRequester.java │ │ ├── UDPNeighbor.java │ │ ├── UDPReceiver.java │ │ └── replicator │ │ │ ├── Replicator.java │ │ │ ├── ReplicatorSinkPool.java │ │ │ ├── ReplicatorSinkProcessor.java │ │ │ ├── ReplicatorSourcePool.java │ │ │ └── ReplicatorSourceProcessor.java │ │ ├── service │ │ ├── API.java │ │ ├── CallableRequest.java │ │ ├── DatabaseRecycler.java │ │ ├── Feature.java │ │ ├── TipsSolidifier.java │ │ ├── ValidationException.java │ │ ├── dto │ │ │ ├── AbstractResponse.java │ │ │ ├── AccessLimitedResponse.java │ │ │ ├── AddedNeighborsResponse.java │ │ │ ├── AttachToTangleResponse.java │ │ │ ├── CheckConsistency.java │ │ │ ├── ErrorResponse.java │ │ │ ├── ExceptionResponse.java │ │ │ ├── FindTransactionsResponse.java │ │ │ ├── GetBalancesResponse.java │ │ │ ├── GetConfidencesResponse.java │ │ │ ├── GetNeighborsResponse.java │ │ │ ├── GetNodeInfoResponse.java │ │ │ ├── GetTipsResponse.java │ │ │ ├── GetTransactionsToApproveResponse.java │ │ │ ├── GetTrytesResponse.java │ │ │ ├── IXIResponse.java │ │ │ ├── RemoveNeighborsResponse.java │ │ │ └── WereAddressesSpentFrom.java │ │ ├── stats │ │ │ ├── LagCalculator.java │ │ │ ├── TimeWindowedApproveeCounter.java │ │ │ └── TransactionStatsPublisher.java │ │ └── tipselection │ │ │ ├── EntryPointSelector.java │ │ │ ├── RatingCalculator.java │ │ │ ├── ReferenceChecker.java │ │ │ ├── StartingTipSelector.java │ │ │ ├── TailFinder.java │ │ │ ├── TipSelector.java │ │ │ ├── WalkValidator.java │ │ │ ├── Walker.java │ │ │ └── impl │ │ │ ├── ConnectedComponentsStartingTipSelector.java │ │ │ ├── CumulativeWeightCalculator.java │ │ │ ├── EntryPointSelectorCumulativeWeightThreshold.java │ │ │ ├── EntryPointSelectorGenesisImpl.java │ │ │ ├── RatingOne.java │ │ │ ├── ReferenceCheckerImpl.java │ │ │ ├── TailFinderImpl.java │ │ │ ├── TipSelectorImpl.java │ │ │ ├── WalkValidatorImpl.java │ │ │ └── WalkerAlpha.java │ │ ├── storage │ │ ├── Indexable.java │ │ ├── Persistable.java │ │ ├── PersistenceProvider.java │ │ ├── Tangle.java │ │ ├── ZmqPublishProvider.java │ │ └── rocksDB │ │ │ └── RocksDBPersistenceProvider.java │ │ ├── utils │ │ ├── Converter.java │ │ ├── IotaIOUtils.java │ │ ├── IotaUtils.java │ │ ├── MapIdentityManager.java │ │ ├── Pair.java │ │ ├── SafeUtils.java │ │ ├── Serializer.java │ │ ├── SlackBotFeed.java │ │ ├── collections │ │ │ ├── impl │ │ │ │ ├── BoundedHashSet.java │ │ │ │ ├── BoundedSetWrapper.java │ │ │ │ ├── TransformingBoundedHashSet.java │ │ │ │ └── TransformingMap.java │ │ │ └── interfaces │ │ │ │ ├── BoundedCollection.java │ │ │ │ ├── BoundedSet.java │ │ │ │ └── UnIterableMap.java │ │ ├── dag │ │ │ ├── DAGHelper.java │ │ │ ├── RecentTransactionsGetter.java │ │ │ ├── TraversalException.java │ │ │ └── impl │ │ │ │ └── RecentTransactionsGetterImpl.java │ │ ├── log │ │ │ ├── Logger.java │ │ │ ├── ProgressLogger.java │ │ │ └── interval │ │ │ │ ├── IntervalLogger.java │ │ │ │ └── IntervalProgressLogger.java │ │ └── thread │ │ │ ├── BoundedScheduledExecutorService.java │ │ │ ├── DedicatedScheduledExecutorService.java │ │ │ ├── ReportingExecutorService.java │ │ │ ├── SilentScheduledExecutorService.java │ │ │ ├── TaskDetails.java │ │ │ ├── ThreadIdentifier.java │ │ │ └── ThreadUtils.java │ │ └── zmq │ │ ├── MessageQ.java │ │ └── README.md └── resources │ └── logback.xml └── test └── java └── com └── iota └── iri ├── BundleValidatorTest.java ├── IXITest.java ├── TransactionTestUtils.java ├── TransactionValidatorTest.java ├── benchmarks ├── BenchmarkRunner.java └── dbbenchmark │ ├── RocksDbBenchmark.java │ └── states │ ├── DbState.java │ ├── EmptyState.java │ └── FullState.java ├── conf ├── ConfigFactoryTest.java └── ConfigTest.java ├── controllers ├── BundleViewModelTest.java ├── TagViewModelTest.java ├── TipsViewModelTest.java ├── TransactionRequesterTest.java └── TransactionViewModelTest.java ├── crypto ├── CurlTest.java ├── ISSTest.java ├── KerlTest.java └── PearlDiverTest.java ├── model ├── HashTest.java └── persistables │ └── TransactionTest.java ├── network └── UDPNeighborTest.java ├── service ├── APIIntegrationTests.java ├── NodeIntegrationTests.java ├── stats │ ├── LagCalculatorTest.java │ └── TimeWindowedApproveeCounterTest.java └── tipselection │ └── impl │ ├── ConnectedComponentsStartingTipSelectorTest.java │ ├── CumulativeWeightCalculatorTest.java │ ├── EntryPointSelectorCumulativeWeightThresholdTest.java │ ├── EntryPointSelectorGenesisImplTest.java │ ├── RatingOneTest.java │ ├── ReferenceCheckerImplTest.java │ ├── TailFinderImplTest.java │ ├── TipSelectorImplTest.java │ ├── WalkValidatorImplTest.java │ └── WalkerAlphaTest.java ├── storage ├── TangleTest.java └── rocksDB │ └── RocksDBPersistenceProviderTest.java └── utils ├── BoundedHashSetTest.java ├── ConverterTest.java ├── TestSerializer.java ├── collections └── impl │ └── BoundedSetWrapperTest.java └── dag └── RecentTransactionsGetterTest.java /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Report a bug in IRI 3 | about: Report a bug 4 | 5 | --- 6 | 7 | 8 | The issue tracker is only for reporting bugs or submitting feature requests. 9 | If you need technical assistance for running a node please consult the #fullnode channel on Discord (https://discord.gg/jrxApWC) or https://forum.helloiota.com/Technology/Help. 10 | If you have general questions on IOTA you can go to https://iota.stackexchange.com/, https://helloiota.com/, or browse Discord channels (https://discord.gg/C88Wexg). 11 | 12 | ### Bug description 13 | A general description of the bug. 14 | 15 | ### Hardware Spec 16 | On what hardware is the node running on? 17 | 18 | ### Steps To Reproduce 19 | 1. 20 | 2. 21 | 3. 22 | 23 | ### Expected behaviour 24 | What should happen. 25 | 26 | ### Actual behaviour 27 | What really happened. 28 | 29 | ### Errors 30 | Paste any errors that you see. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Request a feature for IRI 3 | about: Request a feature 4 | 5 | --- 6 | 7 | *Note* 8 | The feature request will probably be integrated faster if you do a pull request for it. 9 | If you want to discuss the feature before you actually write the code you are welcome to do it by first submitting an issue. 10 | 11 | ### Description 12 | Briefly describe the feature you want. 13 | 14 | ### Motivation 15 | Explain why this feature is needed. 16 | 17 | ### Requirements 18 | Create a list of what you want this feature request to fulfill. 19 | 20 | ### Open Questions (optional) 21 | Anything you want to discuss. 22 | 23 | ### Am I planning to do it myself with a PR? 24 | Yes/No. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/regression-test.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Regression test 3 | about: Create a regression test for IRI 4 | 5 | --- 6 | 7 | ### Description 8 | Briefly describe the regression test. 9 | 10 | ### Motivation 11 | Describe why the regression test is needed. 12 | 13 | ### Issues / Scenarios 14 | Describe the issues/scenarios addressed by this test 15 | 1. A node that does X and Y crashes. 16 | 2. Blowballs are being formed when... 17 | 18 | ### How to test for this 19 | Provide the steps on creating the actual test. 20 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # Description 11 | 12 | _Please include a summary of the change. Include the motivation for the change._ 13 | 14 | Fixes # (issue) 15 | 16 | ## Type of change 17 | 18 | _Please delete options that are not relevant._ 19 | 20 | - Bug fix (a non-breaking change which fixes an issue) 21 | - Enhancement (a non-breaking change which adds functionality) 22 | - Breaking change (fix or feature that would cause existing functionality to not work as expected) 23 | - Documentation Fix 24 | 25 | # How Has This Been Tested? 26 | 27 | _Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration_ 28 | 29 | - Test A 30 | - Test B 31 | 32 | 33 | # Checklist: 34 | 35 | _Please delete items that are not relevant._ 36 | 37 | - [ ] My code follows the style guidelines for this project 38 | - [ ] I have performed a self-review of my own code 39 | - [ ] I have commented my code, particularly in hard-to-understand areas 40 | - [ ] I have made corresponding changes to the documentation 41 | - [ ] I have added tests that prove my fix is effective or that my feature works 42 | - [ ] New and existing unit tests pass locally with my changes 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target* 2 | /.classpath 3 | /.project 4 | /.settings 5 | /tomcat.* 6 | /.idea 7 | /bin 8 | /mainnetdb 9 | /mainnet.log 10 | /*.iml 11 | .classpath 12 | .project 13 | *.class 14 | target/ 15 | mainnet.log/ 16 | mainnetdb/ 17 | bin/ 18 | *.iri 19 | *.jar 20 | src/main/ixi/ 21 | dependency-reduced-pom.xml 22 | 23 | 24 | # Created by https://www.gitignore.io/api/osx,linux,windows 25 | 26 | ### Linux ### 27 | *~ 28 | 29 | # temporary files which can be created if a process still has a handle open of a deleted file 30 | .fuse_hidden* 31 | 32 | # KDE directory preferences 33 | .directory 34 | 35 | # Linux trash folder which might appear on any partition or disk 36 | .Trash-* 37 | 38 | # .nfs files are created when an open file is removed but is still being accessed 39 | .nfs* 40 | 41 | ### OSX ### 42 | *.DS_Store 43 | .AppleDouble 44 | .LSOverride 45 | 46 | # Icon must end with two \r 47 | Icon 48 | 49 | # Thumbnails 50 | ._* 51 | 52 | # Files that might appear in the root of a volume 53 | .DocumentRevisions-V100 54 | .fseventsd 55 | .Spotlight-V100 56 | .TemporaryItems 57 | .Trashes 58 | .VolumeIcon.icns 59 | .com.apple.timemachine.donotpresent 60 | 61 | # Directories potentially created on remote AFP share 62 | .AppleDB 63 | .AppleDesktop 64 | Network Trash Folder 65 | Temporary Items 66 | .apdisk 67 | 68 | ### Windows ### 69 | # Windows thumbnail cache files 70 | Thumbs.db 71 | ehthumbs.db 72 | ehthumbs_vista.db 73 | 74 | # Folder config file 75 | Desktop.ini 76 | 77 | # Recycle Bin used on file shares 78 | $RECYCLE.BIN/ 79 | 80 | # Windows Installer files 81 | *.cab 82 | *.msi 83 | *.msm 84 | *.msp 85 | 86 | # Windows shortcuts 87 | *.lnk 88 | 89 | 90 | # End of https://www.gitignore.io/api/osx,linux,windows 91 | 92 | testnetdb* 93 | .vscode -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | - openjdk8 5 | - oraclejdk9 6 | 7 | cache: 8 | apt: true 9 | directories: 10 | - $HOME/.m2 11 | 12 | sudo: required 13 | 14 | addons: 15 | apt: 16 | packages: 17 | - jq 18 | 19 | matrix: 20 | allow_failures: 21 | - jdk: oraclejdk9 22 | 23 | script: 24 | #run tests and integration tests 25 | # see https://stackoverflow.com/questions/34405047/how-do-you-merge-into-another-branch-using-travis-with-git-commands 26 | - build_head=$(git rev-parse HEAD) 27 | - git config --replace-all remote.origin.fetch +refs/heads/*:refs/remotes/origin/* 28 | - git fetch origin $TRAVIS_BRANCH 29 | - git checkout -f $TRAVIS_BRANCH 30 | - git checkout $build_head 31 | - git merge $TRAVIS_BRANCH 32 | - mvn integration-test -Dlogging-level=INFO 33 | #run jar sanity tests 34 | - VERSION=$(mvn help:evaluate -Dexpression=project.version | grep -E '^[0-9.]+') 35 | - echo $VERSION 36 | 37 | after_success: 38 | #codacy-coverage send report. Uses Travis Env variable (CODACY_PROJECT_TOKEN) 39 | - test $TRAVIS_PULL_REQUEST = "false" && test $TRAVIS_JDK_VERSION = "oraclejdk8" && wget -O codacy-coverage-reporter-assembly-latest.jar $(curl https://api.github.com/repos/codacy/codacy-coverage-reporter/releases/latest | jq -r '.assets[0].browser_download_url') 40 | - test $TRAVIS_PULL_REQUEST = "false" && test $TRAVIS_JDK_VERSION = "oraclejdk8" && java -jar codacy-coverage-reporter-assembly-latest.jar report -l Java -r target/site/jacoco/jacoco.xml 41 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM iotacafe/maven:3.5.4.oracle8u181.1.webupd8.1.1-1 as local_stage_build 2 | MAINTAINER giorgio@iota.org 3 | 4 | WORKDIR /iri 5 | 6 | COPY . /iri 7 | RUN mvn clean package 8 | 9 | # execution image 10 | FROM iotacafe/java:oracle8u181.1.webupd8.1-1 11 | 12 | RUN apt-get update && apt-get install -y --no-install-recommends \ 13 | jq curl socat \ 14 | && rm -rf /var/lib/apt/lists/* 15 | 16 | COPY --from=local_stage_build /iri/target/iri*.jar /iri/target/ 17 | COPY docker/entrypoint.sh / 18 | 19 | # Java related options. Defaults set as below 20 | ENV JAVA_OPTIONS="-XX:+UnlockExperimentalVMOptions -XX:+DisableAttachMechanism -XX:InitiatingHeapOccupancyPercent=60 -XX:G1MaxNewSizePercent=75 -XX:MaxGCPauseMillis=10000 -XX:+UseG1GC" 21 | ENV JAVA_MIN_MEMORY 2G 22 | ENV JAVA_MAX_MEMORY 4G 23 | 24 | # Additional custom variables. See DOCKER.md for details 25 | ENV DOCKER_IRI_JAR_PATH "/iri/target/iri*.jar" 26 | ENV DOCKER_IRI_REMOTE_LIMIT_API "interruptAttachToTangle, attachToTangle, addNeighbors, removeNeighbors, getNeighbors" 27 | 28 | # Setting this to 1 will have socat exposing 14266 and pointing it on 29 | # localhost. See /entrypoint.sh 30 | # !!! DO NOT DOCKER EXPOSE (-p) 14266 as the remote api settings 31 | # will not be applied on that port !!! 32 | # You also have to maintain $DOCKER_IRI_MONITORING_API_PORT_DESTINATION 33 | # based on the actual API port exposed via IRI 34 | ENV DOCKER_IRI_MONITORING_API_PORT_ENABLE 0 35 | ENV DOCKER_IRI_MONITORING_API_PORT_DESTINATION 14265 36 | 37 | WORKDIR /iri/data 38 | ENTRYPOINT [ "/entrypoint.sh" ] 39 | -------------------------------------------------------------------------------- /checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /codesigning.asc.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/cliri/1f974cafb1c17d96ae7e0a6856f563dcf3794238/codesigning.asc.enc -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # See Dockerfile and DOCKER.md for further info 3 | 4 | if [ "${DOCKER_IRI_MONITORING_API_PORT_ENABLE}" == "1" ]; then 5 | nohup socat -lm TCP-LISTEN:14266,fork TCP:127.0.0.1:${DOCKER_IRI_MONITORING_API_PORT_DESTINATION} & 6 | fi 7 | 8 | exec java \ 9 | $JAVA_OPTIONS \ 10 | -Xms$JAVA_MIN_MEMORY \ 11 | -Xmx$JAVA_MAX_MEMORY \ 12 | -Djava.net.preferIPv4Stack=true \ 13 | -jar $DOCKER_IRI_JAR_PATH \ 14 | --remote --remote-limit-api "$DOCKER_IRI_REMOTE_LIMIT_API" \ 15 | "$@" 16 | -------------------------------------------------------------------------------- /docker/ssl/README.md: -------------------------------------------------------------------------------- 1 | # IRI with SSL for Docker 2 | 3 | This folder contains the files necessary to set up an IRI Docker container with an SSL certificate, using `nginx` proxy-pass to direct remote requests to IRI. 4 | 5 | ## Prerequisites 6 | You'll need the following in order to get started: 7 | - Docker 8 | - [Docker Compose](https://docs.docker.com/compose/install/) (This might already be included with Docker, depending on your installation method) 9 | - A domain name with DNS records set up 10 | 11 | ## Getting Started 12 | 1. Clone this repository: 13 | ``` 14 | git clone https://github.com/iotaledger/cliri 15 | ``` 16 | 17 | 2. Navigate to this directory: 18 | ``` 19 | cd iri/docker/ssl 20 | ``` 21 | 22 | 3. Run the setup script and follow the prompts: 23 | ``` 24 | ./start.sh 25 | ``` 26 | 27 | 4. Build the images: 28 | ``` 29 | docker-compose build 30 | ``` 31 | 32 | 5. Start the containers: 33 | ``` 34 | docker-compose up 35 | ``` 36 | 37 | ## Testing 38 | If you want to test the application before running in a production environment, ensure that you add the `--staging` flag to the `certbot` command on line 16 of `docker-compose.yml`. This will tell `certbot` to obtain a test certificate and allow you to exceed the normal [rate limits](https://letsencrypt.org/docs/rate-limits/). Note that the test certificate will be untrusted by most systems by default. 39 | 40 | ## Acknowledgements 41 | - Docker Compose setup based on [le-docker-compose](https://bitbucket.org/automationlogic/le-docker-compose/overview) by Automation Logic 42 | - `nginx` configuration based on [auto-nginx-https](https://github.com/eukaryote31/auto-nginx-https) by eukaryote31 43 | -------------------------------------------------------------------------------- /docker/ssl/docker-compose.yml: -------------------------------------------------------------------------------- 1 | nginx: 2 | build: nginx-image 3 | links: 4 | - letsencrypt 5 | - iri 6 | environment: 7 | - MY_DOMAIN_NAME=__DOMAIN__ 8 | ports: 9 | - "80:80" 10 | - "443:443" 11 | volumes_from: 12 | - letsencrypt 13 | letsencrypt: 14 | image: certbot/certbot@sha256:8a73ec490fc75a29b75552dc328258c74162b204c232e0fc47fe163a2d3aefea 15 | command: sh -c "certbot certonly --standalone --email "__EMAIL__" -d "__DOMAIN__" -n --agree-tos" 16 | entrypoint: "" 17 | volumes: 18 | - /etc/letsencrypt 19 | - /var/lib/letsencrypt 20 | ports: 21 | - "80" 22 | - "443" 23 | environment: 24 | - TERM=xterm 25 | iri: 26 | image: iotaledger/iri:latest 27 | command: -p 14265 28 | -------------------------------------------------------------------------------- /docker/ssl/nginx-image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:stable 2 | 3 | # Install dependencies and then remove apt-get lists to save space 4 | RUN apt-get update && apt-get install -y procps net-tools openssl && rm -rf /var/lib/apt/lists/* 5 | 6 | COPY start.sh / 7 | COPY nginx.conf /etc/nginx/ 8 | COPY nginx-secure.conf /etc/nginx/ 9 | 10 | RUN openssl dhparam -out /etc/ssl/private/dhparams.pem 2048 11 | CMD /start.sh 12 | -------------------------------------------------------------------------------- /docker/ssl/nginx-image/nginx-secure.conf: -------------------------------------------------------------------------------- 1 | events { worker_connections 1024; } 2 | http { 3 | server { 4 | listen 80; 5 | server_name ___my.example.com___; 6 | 7 | location /.well-known/acme-challenge { 8 | proxy_pass http://letsencrypt:80; 9 | proxy_set_header Host $host; 10 | proxy_set_header X-Forwarded-For $remote_addr; 11 | proxy_set_header X-Forwarded-Proto $scheme; 12 | } 13 | 14 | location / { 15 | add_header "Access-Control-Allow-Origin" *; 16 | proxy_set_header Host $host; 17 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 18 | proxy_set_header X-Forwarded-Proto $scheme; 19 | proxy_pass http://iri:14265; 20 | } 21 | 22 | } 23 | 24 | server { 25 | listen 443; 26 | server_name ___my.example.com___; 27 | 28 | ssl on; 29 | ssl_certificate /etc/letsencrypt/live/___my.example.com___/fullchain.pem; 30 | ssl_certificate_key /etc/letsencrypt/live/___my.example.com___/privkey.pem; 31 | ssl_session_timeout 5m; 32 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 33 | ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; 34 | ssl_prefer_server_ciphers on; 35 | 36 | ssl_session_cache shared:SSL:10m; 37 | ssl_dhparam /etc/ssl/private/dhparams.pem; 38 | 39 | location /.well-known/acme-challenge { 40 | proxy_pass http://letsencrypt:443; 41 | proxy_set_header Host $host; 42 | proxy_set_header X-Forwarded-For $remote_addr; 43 | proxy_set_header X-Forwarded-Proto $scheme; 44 | } 45 | 46 | location / { 47 | add_header "Access-Control-Allow-Origin" *; 48 | proxy_set_header Host $host; 49 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 50 | proxy_set_header X-Forwarded-Proto $scheme; 51 | proxy_pass http://iri:14265; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /docker/ssl/nginx-image/nginx.conf: -------------------------------------------------------------------------------- 1 | events { worker_connections 1024; } 2 | http { 3 | server { 4 | listen 80; 5 | server_name ___my.example.com___; 6 | 7 | location /.well-known/acme-challenge { 8 | proxy_pass http://letsencrypt:80; 9 | proxy_set_header Host $host; 10 | proxy_set_header X-Forwarded-For $remote_addr; 11 | proxy_set_header X-Forwarded-Proto $scheme; 12 | } 13 | 14 | location / { 15 | add_header "Access-Control-Allow-Origin" *; 16 | proxy_set_header Host $host; 17 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 18 | proxy_set_header X-Forwarded-Proto $scheme; 19 | proxy_pass http://iri:14265; 20 | } 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docker/ssl/nginx-image/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo build starting nginx config 4 | 5 | echo replacing ___my.example.com___/$MY_DOMAIN_NAME 6 | 7 | # Put your domain name into the nginx reverse proxy config. 8 | sed -i "s/___my.example.com___/$MY_DOMAIN_NAME/g" /etc/nginx/nginx.conf 9 | 10 | echo Firing up nginx in the background. 11 | nginx 12 | 13 | # Check user has specified domain name 14 | if [ -z "$MY_DOMAIN_NAME" ]; then 15 | echo "Need to set MY_DOMAIN_NAME (to a letsencrypt-registered name)." 16 | exit 1 17 | fi 18 | 19 | # This bit waits until the letsencrypt container has done its thing. 20 | # We see the changes here because there's a docker volume mapped. 21 | echo Waiting for folder /etc/letsencrypt/live/$MY_DOMAIN_NAME to exist 22 | while [ ! -d /etc/letsencrypt/live/$MY_DOMAIN_NAME ] ; 23 | do 24 | sleep 2 25 | done 26 | 27 | while [ ! -f /etc/letsencrypt/live/$MY_DOMAIN_NAME/fullchain.pem ] ; 28 | do 29 | echo Waiting for file fullchain.pem to exist 30 | sleep 2 31 | done 32 | 33 | while [ ! -f /etc/letsencrypt/live/$MY_DOMAIN_NAME/privkey.pem ] ; 34 | do 35 | echo Waiting for file privkey.pem to exist 36 | sleep 2 37 | done 38 | 39 | echo replacing ___my.example.com___/$MY_DOMAIN_NAME 40 | 41 | 42 | # Put your domain name into the nginx reverse proxy config. 43 | sed -i "s/___my.example.com___/$MY_DOMAIN_NAME/g" /etc/nginx/nginx-secure.conf 44 | 45 | #go! 46 | kill $(ps aux | grep '[n]ginx' | awk '{print $2}') 47 | cp /etc/nginx/nginx-secure.conf /etc/nginx/nginx.conf 48 | 49 | nginx -g 'daemon off;' 50 | -------------------------------------------------------------------------------- /docker/ssl/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | echo "Setting up Let's Encrypt SSL for IRI using nginx proxy_pass" 5 | 6 | while getopts 'e:d:t' flag; do 7 | case "${flag}" in 8 | e) EMAIL="${OPTARG}" ;; 9 | d) DOMAIN="${OPTARG}" ;; 10 | t) TOS="${OPTARG}" ;; 11 | esac 12 | done 13 | 14 | # Email 15 | if [[ -z "$EMAIL" ]]; then 16 | echo "Please enter your email (used by certbot for urgent renewal and security notices):" 17 | read EMAIL 18 | if [[ -z "$EMAIL" ]]; then 19 | echo "Error: You must enter an email" 20 | exit 1 21 | fi 22 | fi 23 | 24 | # Domain 25 | if [[ -z "$DOMAIN" ]]; then 26 | echo "Please enter a domain that points to this system's IP:" 27 | read DOMAIN 28 | if [[ -z "$DOMAIN" ]]; then 29 | echo "Error: You must enter a domain" 30 | exit 1 31 | fi 32 | fi 33 | 34 | # Terms of Service 35 | if [[ "$TOS" != "y" ]]; then 36 | echo "Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must agree in order to register with the ACME server at https://acme-v01.api.letsencrypt.org/directory. Please enter "y" to accept the ToS." 37 | read TOS 38 | if [[ "$TOS" != "y" ]]; then 39 | echo "Error: You must agree to the ToS in order to continue" 40 | exit 1 41 | fi 42 | fi 43 | 44 | # Modify docker-compose.yml 45 | sed -i "s/__DOMAIN__/$DOMAIN/g" ./docker-compose.yml 46 | sed -i "s/__EMAIL__/$EMAIL/g" ./docker-compose.yml 47 | -------------------------------------------------------------------------------- /format.importorder: -------------------------------------------------------------------------------- 1 | #Organize Import Order 2 | #Sun Oct 14 18:08:17 IDT 2018 3 | 6= 4 | 5=org 5 | 4=net 6 | 3=com 7 | 2=java 8 | 1=javax 9 | 0=com.iota 10 | 7=\# 11 | -------------------------------------------------------------------------------- /logo.utf8.ans: -------------------------------------------------------------------------------- 1 | ▄███▄ 2 |  ▀███ 3 | ▄▄ ▄▀▀▀ 4 | ▄██▄ ▀▀▀▀ ▀█▀ ▄▄▄▄ 5 | ▀▀▀▀■  ▀███ ▄▄ 6 | ▄██▄ ▄█▄ ▄▀▀▀  ███ 7 | ▄██▄ ▀▀ ▀▀▀▀ 8 | ▄▄ ▀▀▀▀▄▄ ▄▄▄█▄ ▄▄ 9 |  ███▄▄  ███ ▀▀▀ ■ ▀▀▀▀ ████ ▄▄ 10 | ▀▀ ███ ▀▀▀▀  ███ 11 | ▄▄▄ ▀▀▄██▄ ▄▄▀▀ 12 |  ▀███▄▀ ▀▀ ▀▀▀▀ ▄██▄ 13 | ▄▄▄ ▀▀▀▄▄▄▄ ▀▀ 14 | █████▄▄█▄▀▀▀ ▀▀▀ ▀▀▀ 15 | ▀ ▀▀▀▀ ▀▄▄▄█▄ 16 | ▄█▄ ▄ ▄██▄■▄ ▀ 17 | ▀ ▀▀▀ ▀▀▀▀■ 18 | ▄█▄ ▄▄ ▄██▄ 19 | ▀ ▀▀▀▀ ▀▀▀▀ ▄▄▄ 20 | I O T A▄██▄▄▄ ████ ▄███▄ 21 | -------------------▀▀ ███▀▀▀  ████ 22 |  Ledger of Things ▄██▄ ▀▀ ▄▄▀▀▀ 23 | ▀ ▀▀ ███ 24 | ▀▀ 25 | 26 | -------------------------------------------------------------------------------- /python-regression/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # Environments 86 | .env 87 | .venv 88 | env/ 89 | venv/ 90 | ENV/ 91 | env.bak/ 92 | venv.bak/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | 107 | # pyc files 108 | *.pyc 109 | 110 | #Metafiles 111 | .metadata/ 112 | -------------------------------------------------------------------------------- /python-regression/README.md: -------------------------------------------------------------------------------- 1 | Python Regression Testing 2 | A testing suite for performance and dynamic testing of IRI 3 | 4 | Aloe testing 5 | This suite uses aloe for performing tests. Once this repository is cloned, make sure you are in the PythonRegression 6 | directory, and install the necessary packages using: 7 | ``` 8 | pip install -e . 9 | ``` 10 | Once the packages are installed, you can run all the tests with the one line command: 11 | ``` 12 | aloe 13 | ``` 14 | Extra Features 15 | If you would like a more verbose readout of the tests being run, you can add the -v flag: 16 | ``` 17 | aloe -v 18 | ```` 19 | If you would like to run any particular feature file, you may enter the path to the file following the aloe command 20 | (this can be done in conjunction with other flags as well): 21 | ``` 22 | aloe -v ./tests/machine1/features/machine_1_tests.feature 23 | ``` 24 | Certain features will have tags on them that can be used for inclusion or exclusion in testing. For example: 25 | ``` 26 | aloe -a utilTests 27 | ``` 28 | and: 29 | ``` 30 | aloe -a '!utilTests' 31 | ``` 32 | Will run all tests that include or don't include the utilTests tag respectively (run the second command if you would 33 | like to only run the main tests) -------------------------------------------------------------------------------- /python-regression/ciglue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$#" -ne 1 ]; then 4 | echo "Please specify an image to test" 5 | exit 1 6 | fi 7 | 8 | set -x 9 | 10 | UUID=$(uuidgen) 11 | ERROR=0 12 | K8S_NAMESPACE=$(kubectl config get-contexts $(kubectl config current-context) | tail -n+2 | awk '{print $5}') 13 | IMAGE=$1 14 | 15 | if [ ! -d tiab ]; then 16 | git clone --depth 1 https://github.com/iotaledger/tiab tiab 17 | fi 18 | 19 | virtualenv -p python2 venv 20 | source venv/bin/activate 21 | 22 | cd tiab 23 | git pull 24 | echo "tiab revision: "; git rev-parse HEAD 25 | pip install -r requirements.txt 26 | cd .. 27 | 28 | pip install -e . 29 | 30 | for machine_dir in tests/features/machine?; do 31 | python tiab/create_cluster.py -i $IMAGE -t $UUID -n $K8S_NAMESPACE -c $machine_dir/config.yml -o $machine_dir/output.yml -d 32 | if [ $? -ne 0 ]; then 33 | ERROR=1 34 | python < 6 | Build-Depends: maven (>= 3) 7 | Depends: jdk (>= 1.8) 8 | Standards-Version: 3.9.8 9 | Homepage: https://iota.org 10 | Vcs-Git: https://github.com/iotaledger/iri.git 11 | Vcs-Browser: https://github.com/iotaledger/iri.git 12 | Architecture: any 13 | Depends: default-jre | java8-runtime 14 | Description: [[description]] 15 | -------------------------------------------------------------------------------- /src/deb/control/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | -------------------------------------------------------------------------------- /src/deb/control/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | -------------------------------------------------------------------------------- /src/deb/control/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | -------------------------------------------------------------------------------- /src/deb/control/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | -------------------------------------------------------------------------------- /src/deb/init.d/iri: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/cliri/1f974cafb1c17d96ae7e0a6856f563dcf3794238/src/deb/init.d/iri -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/IxiEvent.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri; 2 | 3 | import java.util.Arrays; 4 | import java.util.Optional; 5 | 6 | public enum IxiEvent { 7 | CREATE_MODULE("ENTRY_CREATE"), 8 | MODIFY_MODULE("ENTRY_MODIFY"), 9 | DELETE_MODULE("ENTRY_DELETE"), 10 | OVERFLOW("OVERFLOW"), 11 | UNKNOWN("UNKNOWN"); 12 | 13 | private String name; 14 | 15 | IxiEvent(String name) { 16 | this.name = name; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public static IxiEvent fromName(String name) { 24 | Optional ixiEvent = Arrays.stream(IxiEvent.values()).filter(event -> event.name.equals(name)).findFirst(); 25 | return ixiEvent.orElse(UNKNOWN); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/LedgerValidator.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | public interface LedgerValidator { 10 | 11 | boolean checkConsistency(List hashes) throws Exception; 12 | 13 | boolean updateDiff(Set approvedHashes, final Map diff, Hash tip) throws Exception; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/LedgerValidatorImpl.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | public class LedgerValidatorImpl implements LedgerValidator { 10 | 11 | public boolean checkConsistency(List hashes) { 12 | return true; 13 | } 14 | 15 | public boolean updateDiff(Set approvedHashes, final Map diff, Hash tip) { 16 | return true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/OsVariants.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri; 2 | 3 | public enum OsVariants { 4 | Windows, 5 | Unix; 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/APIConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Configurations for node API 7 | */ 8 | public interface APIConfig extends Config { 9 | 10 | 11 | /** 12 | * @return {@value Descriptions#PORT} 13 | */ 14 | int getPort(); 15 | 16 | /** 17 | * @return {@value Descriptions#API_HOST} 18 | */ 19 | String getApiHost(); 20 | 21 | 22 | /** 23 | * @return {@value Descriptions#REMOTE_LIMIT_API} 24 | */ 25 | List getRemoteLimitApi(); 26 | 27 | /** 28 | * @return {@value Descriptions#MAX_FIND_TRANSACTIONS} 29 | */ 30 | int getMaxFindTransactions(); 31 | 32 | /** 33 | * @return {@value Descriptions#MAX_REQUESTS_LIST} 34 | */ 35 | int getMaxRequestsList(); 36 | 37 | /** 38 | * @return {@value Descriptions#MAX_GET_TRYTES} 39 | */ 40 | int getMaxGetTrytes(); 41 | 42 | /** 43 | * @return {@value Descriptions#MAX_BODY_LENGTH} 44 | */ 45 | int getMaxBodyLength(); 46 | 47 | /** 48 | * @return {@value Descriptions#REMOTE_AUTH} 49 | */ 50 | String getRemoteAuth(); 51 | 52 | interface Descriptions { 53 | String PORT = "The port that will be used by the API."; 54 | String API_HOST = "The host on which the API will listen to. Set to 0.0.0.0 to accept any host."; 55 | String REMOTE_LIMIT_API = "Commands that should be ignored by API."; 56 | String REMOTE_AUTH = "A string in the form of :. Used to access the API"; 57 | String MAX_FIND_TRANSACTIONS = "The maximal number of transactions that may be returned by the \"findTransactions\" API call. If the number of transactions found exceeds this number an error will be returned."; 58 | String MAX_REQUESTS_LIST = "The maximal number of parameters one can place in an API call. If the number parameters exceeds this number an error will be returned"; 59 | String MAX_GET_TRYTES = "The maximal number of trytes that may be returned by the \"getTrytes\" API call. If the number of transactions found exceeds this number an error will be returned."; 60 | String MAX_BODY_LENGTH = "The maximal number of characters the body of an API call may hold. If a request body length exceeds this number an error will be returned."; 61 | String REMOTE = "Open the API interface to any host. Equivalent to \"--api-host 0.0.0.0\""; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/Config.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | /** 4 | * General configuration parameters that every module in IRI needs. 5 | */ 6 | public interface Config { 7 | 8 | String TESTNET_FLAG = "--testnet"; 9 | 10 | /** 11 | * @return {@value Descriptions#TESTNET} 12 | */ 13 | boolean isTestnet(); 14 | 15 | interface Descriptions { 16 | 17 | String TESTNET = "Start in testnet mode."; 18 | } 19 | 20 | class DescriptionHelper { 21 | 22 | protected static final String PROB_OF = "A number between 0 and 1 that represents the probability of "; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/ConfigFactory.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature; 4 | import com.fasterxml.jackson.databind.MapperFeature; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 7 | import com.fasterxml.jackson.databind.module.SimpleModule; 8 | import com.iota.iri.conf.deserializers.CustomBoolDeserializer; 9 | import com.iota.iri.conf.deserializers.CustomStringDeserializer; 10 | 11 | import java.io.File; 12 | import java.io.FileInputStream; 13 | import java.io.IOException; 14 | import java.util.Properties; 15 | 16 | public class ConfigFactory { 17 | 18 | public static IotaConfig createIotaConfig(boolean isTestnet) { 19 | IotaConfig iotaConfig; 20 | if (isTestnet) { 21 | iotaConfig = new TestnetConfig(); 22 | } 23 | else { 24 | iotaConfig = new MainnetConfig(); 25 | } 26 | return iotaConfig; 27 | } 28 | 29 | public static IotaConfig createFromFile(File configFile, boolean testnet) throws IOException, 30 | IllegalArgumentException { 31 | IotaConfig iotaConfig; 32 | 33 | try (FileInputStream confStream = new FileInputStream(configFile)) { 34 | Properties props = new Properties(); 35 | props.load(confStream); 36 | boolean isTestnet = testnet || Boolean.parseBoolean(props.getProperty("TESTNET", "false")); 37 | Class iotaConfigClass = isTestnet ? TestnetConfig.class : MainnetConfig.class; 38 | ObjectMapper objectMapper = new ObjectMapper(); 39 | objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); 40 | objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); 41 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 42 | objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true); 43 | objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); 44 | 45 | SimpleModule booleanParser = new SimpleModule("BooleanParser"); 46 | booleanParser.addDeserializer(Boolean.TYPE, new CustomBoolDeserializer()); 47 | objectMapper.registerModule(booleanParser); 48 | 49 | SimpleModule stringParser = new SimpleModule("StringParser"); 50 | stringParser.addDeserializer(String.class, new CustomStringDeserializer()); 51 | objectMapper.registerModule(stringParser); 52 | 53 | iotaConfig = objectMapper.convertValue(props, iotaConfigClass); 54 | } 55 | return iotaConfig; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/DbConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | /** 4 | * Configurations for tangle database. 5 | */ 6 | public interface DbConfig extends Config { 7 | 8 | /** 9 | * @return Descriptions#DB_PATH 10 | */ 11 | String getDbPath(); 12 | 13 | /** 14 | * @return {@value Descriptions#DB_LOG_PATH} 15 | */ 16 | String getDbLogPath(); 17 | 18 | /** 19 | * @return {@value Descriptions#DB_CACHE_SIZE} 20 | */ 21 | int getDbCacheSize(); 22 | 23 | /** 24 | * @return {@value Descriptions#MAIN_DB} 25 | */ 26 | String getMainDb(); 27 | 28 | /** 29 | * @return {@value Descriptions#RESCAN_DB} 30 | */ 31 | boolean isRescanDb(); 32 | 33 | interface Descriptions { 34 | 35 | String DB_PATH = "The folder where the DB saves its data."; 36 | String DB_LOG_PATH = "The folder where the DB logs info"; 37 | String DB_CACHE_SIZE = "The size of the DB cache in KB"; 38 | String MAIN_DB = "The DB engine used to store the transactions. Currently only RocksDB is supported."; 39 | String RESCAN_DB = "Rescan all transaction metadata (Approvees, Bundles, and Tags)"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/IXIConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | /** 4 | * Configurations for IXI modules 5 | */ 6 | public interface IXIConfig extends Config { 7 | 8 | String IXI_DIR = "ixi"; 9 | 10 | /** 11 | * @return Descriptions#IXI_DIR 12 | */ 13 | String getIxiDir(); 14 | 15 | interface Descriptions { 16 | String IXI_DIR = "The folder where ixi modules should be added for automatic discovery by CLIRI."; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/IotaConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | import com.beust.jcommander.JCommander; 4 | import com.beust.jcommander.ParameterException; 5 | 6 | import java.io.File; 7 | 8 | /** 9 | * A container for all possible configuration parameters of IRI. 10 | * In charge of how we parse the configuration from given inputs. 11 | */ 12 | public interface IotaConfig extends APIConfig, NodeConfig, 13 | IXIConfig, DbConfig, ZMQConfig, TipSelConfig, PearlDiverConfig { 14 | File CONFIG_FILE = new File("iota.ini"); 15 | 16 | /** 17 | * Parses the args to populate the configuration object 18 | * 19 | * @param args command line args 20 | * @return {@link JCommander} instance that was used for parsing. It contains metadata about the parsing. 21 | * @throws ParameterException if the parsing failed 22 | */ 23 | JCommander parseConfigFromArgs(String[] args) throws ParameterException; 24 | 25 | boolean isHelp(); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/MainnetConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | public class MainnetConfig extends BaseIotaConfig { 4 | 5 | public MainnetConfig() { 6 | //All the configs are defined in the super class 7 | super(); 8 | } 9 | 10 | @Override 11 | public boolean isTestnet() { 12 | return false; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/NetworkConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Configurations for the node networking. Including ports, DNS settings, list of neighbors, 7 | * and various optimization parameters. 8 | */ 9 | public interface NetworkConfig extends Config { 10 | 11 | /** 12 | * @return Descriptions#UDP_RECEIVER_PORT 13 | */ 14 | int getUdpReceiverPort(); 15 | 16 | /** 17 | * @return Descriptions#TCP_RECEIVER_PORT 18 | */ 19 | int getTcpReceiverPort(); 20 | 21 | /** 22 | * @return Descriptions#P_REMOVE_REQUEST 23 | */ 24 | double getpRemoveRequest(); 25 | 26 | /** 27 | * @return Descriptions#SEND_LIMIT 28 | */ 29 | int getSendLimit(); 30 | 31 | /** 32 | * @return Descriptions#MAX_PEERS 33 | */ 34 | int getMaxPeers(); 35 | 36 | /** 37 | * @return Descriptions#DNS_REFRESHER_ENABLED 38 | */ 39 | boolean isDnsRefresherEnabled(); 40 | 41 | /** 42 | * @return Descriptions#DNS_RESOLUTION_ENABLED 43 | */ 44 | boolean isDnsResolutionEnabled(); 45 | 46 | /** 47 | * @return Descriptions#NEIGHBORS 48 | */ 49 | List getNeighbors(); 50 | 51 | /** 52 | * @return Descriptions#Q_SIZE_NODE 53 | */ 54 | int getqSizeNode(); 55 | 56 | /** 57 | * @return Descriptions#P_DROP_CACHE_ENTRY 58 | */ 59 | double getpDropCacheEntry(); 60 | 61 | /** 62 | * @return Descriptions#CACHE_SIZE_BYTES 63 | */ 64 | int getCacheSizeBytes(); 65 | 66 | interface Descriptions { 67 | String UDP_RECEIVER_PORT = "The UDP Receiver Port."; 68 | String TCP_RECEIVER_PORT = "The TCP Receiver Port."; 69 | String P_REMOVE_REQUEST = DescriptionHelper.PROB_OF + " stopping to request a transaction. This number should be " + 70 | "closer to 0 so non-existing transaction hashes will eventually be removed."; 71 | String SEND_LIMIT = "The maximum number of packets that may be sent by this node in a 1 second interval. If this number is below 0 then there is no limit."; 72 | String MAX_PEERS = "The maximum number of non mutually tethered connections allowed. Works only in testnet mode"; 73 | String DNS_REFRESHER_ENABLED = "Reconnect to neighbors that have dynamic IPs."; 74 | String DNS_RESOLUTION_ENABLED = "Enable using DNS for neighbor peering."; 75 | String NEIGHBORS = "Urls of peer iota nodes."; 76 | String Q_SIZE_NODE = "The size of the REPLY, BROADCAST, and RECEIVE network queues."; 77 | String P_DROP_CACHE_ENTRY = DescriptionHelper.PROB_OF + "dropping recently seen transactions out of the network cache."; 78 | String CACHE_SIZE_BYTES = "The size of the network cache in bytes"; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/NodeConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | /** 4 | * A configuration that specifies how the node communicates with other nodes. 5 | * 6 | * @implNote It currently extends two other interfaces. This has been done due to lack of separation of concerns in 7 | * the current code base and will be changed in the future 8 | */ 9 | public interface NodeConfig extends ProtocolConfig, NetworkConfig { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/PearlDiverConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | /** 4 | * Configurations for PearlDiver proof-of-work hasher. 5 | */ 6 | public interface PearlDiverConfig extends Config { 7 | 8 | /** 9 | * @return {@value PearlDiverConfig.Descriptions#POW_THREADS} 10 | */ 11 | int getPowThreads(); 12 | 13 | /** 14 | * Field descriptions 15 | */ 16 | interface Descriptions { 17 | String POW_THREADS = "Number of threads to use for proof-of-work calculation"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/ProtocolConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | /** 4 | * Configuration for protocol rules. Controls what transactions will be accepted by the network, and how they will 5 | * be propagated to other nodes. 6 | **/ 7 | public interface ProtocolConfig extends Config { 8 | 9 | /** 10 | * @return Descriptions#MWM 11 | */ 12 | int getMwm(); 13 | 14 | /** 15 | * @return Descriptions#TRANSACTION_PACKET_SIZE 16 | */ 17 | int getTransactionPacketSize(); 18 | 19 | /** 20 | * @return Descriptions#REQUEST_HASH_SIZE 21 | */ 22 | int getRequestHashSize(); 23 | 24 | /** 25 | * @return Descriptions#P_REPLY_RANDOM_TIP 26 | */ 27 | double getpReplyRandomTip(); 28 | 29 | double getpDropTransaction(); 30 | 31 | double getpPropagateRequest(); 32 | 33 | interface Descriptions { 34 | String MWM = "The minimum weight magnitude is the number of trailing 0s that must appear in the end of a transaction hash. Increasing this number by 1 will result in proof of work that is 3 times as hard."; 35 | String TRANSACTION_PACKET_SIZE = "The size of the packet in bytes received by a node. In the mainnet the packet size should always be 1650. It consists of 1604 bytes of a received transaction and 46 bytes of a requested transaction hash. This value can be changed in order to create testnets with different rules."; 36 | String REQUEST_HASH_SIZE = "The size of the requested hash in a packet. Its size is derived from the minimal MWM value the network accepts. The larger the MWM -> the more trailing zeroes we can ignore -> smaller hash size."; 37 | String P_DROP_TRANSACTION = DescriptionHelper.PROB_OF + "dropping a received transaction. This is used only for testing purposes."; 38 | String P_REPLY_RANDOM_TIP = DescriptionHelper.PROB_OF + "replying to a random transaction request, even though your node doesn't have anything to request."; 39 | String P_PROPAGATE_REQUEST = DescriptionHelper.PROB_OF + "propagating the request of a transaction to a neighbor node if it can't be found. This should be low since we don't want to propagate non-existing transactions that spam the network."; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/TestnetConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | import com.beust.jcommander.Parameter; 4 | import com.beust.jcommander.ParameterException; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | import java.util.Objects; 8 | 9 | public class TestnetConfig extends BaseIotaConfig { 10 | 11 | protected int mwm = Defaults.MWM; 12 | protected int transactionPacketSize = Defaults.PACKET_SIZE; 13 | protected int requestHashSize = Defaults.REQUEST_HASH_SIZE; 14 | 15 | public TestnetConfig() { 16 | super(); 17 | dbPath = Defaults.DB_PATH; 18 | dbLogPath = Defaults.DB_LOG_PATH; 19 | } 20 | 21 | @Override 22 | public boolean isTestnet() { 23 | return true; 24 | } 25 | 26 | @Override 27 | public int getMwm() { 28 | return mwm; 29 | } 30 | 31 | @JsonProperty 32 | @Parameter(names = "--mwm", description = ProtocolConfig.Descriptions.MWM) 33 | protected void setMwm(int mwm) { 34 | this.mwm = mwm; 35 | } 36 | 37 | @Override 38 | public int getTransactionPacketSize() { 39 | return transactionPacketSize; 40 | } 41 | 42 | @JsonProperty 43 | @Parameter(names = {"--packet-size"}, description = ProtocolConfig.Descriptions.TRANSACTION_PACKET_SIZE) 44 | protected void setTransactionPacketSize(int transactionPacketSize) { 45 | this.transactionPacketSize = transactionPacketSize; 46 | } 47 | 48 | @Override 49 | public int getRequestHashSize() { 50 | return requestHashSize; 51 | } 52 | 53 | @JsonProperty 54 | @Parameter(names = {"--request-hash-size"}, description = ProtocolConfig.Descriptions.REQUEST_HASH_SIZE) 55 | public void setRequestHashSize(int requestHashSize) { 56 | this.requestHashSize = requestHashSize; 57 | } 58 | 59 | @JsonProperty 60 | @Override 61 | public void setDbPath(String dbPath) { 62 | if (Objects.equals(MainnetConfig.Defaults.DB_PATH, dbPath)) { 63 | throw new ParameterException("Testnet Db folder cannot be configured to mainnet's db folder"); 64 | } 65 | super.setDbPath(dbPath); 66 | } 67 | 68 | @JsonProperty 69 | @Override 70 | public void setDbLogPath(String dbLogPath) { 71 | if (Objects.equals(MainnetConfig.Defaults.DB_LOG_PATH, dbLogPath)) { 72 | throw new ParameterException("Testnet Db log folder cannot be configured to mainnet's db log folder"); 73 | } 74 | super.setDbLogPath(dbLogPath); 75 | } 76 | 77 | public interface Defaults { 78 | int REQUEST_HASH_SIZE = 49; 79 | int MWM = 9; 80 | int PACKET_SIZE = 1653; 81 | String DB_PATH = "testnetdb"; 82 | String DB_LOG_PATH = "testnetdb.log"; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/TipSelConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | /** 4 | * Configuration for how we perform tip selections. Tip selection is invoked when a client wants to find tips to 5 | * attach its transactions to. The tips are invoked via random walks that start at a certain point in the tangle. 6 | * The parameters here affect the length and randomness of this walk. 7 | */ 8 | public interface TipSelConfig extends Config { 9 | 10 | /** 11 | * @return Descriptions#ALPHA 12 | */ 13 | double getAlpha(); 14 | 15 | interface Descriptions { 16 | 17 | String ALPHA = "Parameter that defines the randomness of the tip selection. " + 18 | "Should be a number between 0 to infinity, where 0 is most random and infinity is most deterministic."; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/ZMQConfig.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf; 2 | 3 | public interface ZMQConfig extends Config { 4 | 5 | boolean isZmqEnabled(); 6 | 7 | int getZmqPort(); 8 | 9 | int getZmqThreads(); 10 | 11 | String getZmqIpc(); 12 | 13 | interface Descriptions { 14 | String ZMQ_ENABLED = "Enabling zmq channels."; 15 | String ZMQ_PORT = "The port used to connect to the ZMQ feed"; 16 | String ZMQ_IPC = "The path that is used to communicate with ZMQ in IPC"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/deserializers/CustomBoolDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf.deserializers; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.core.JsonToken; 5 | import com.fasterxml.jackson.databind.DeserializationContext; 6 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 7 | import org.apache.commons.lang3.StringUtils; 8 | 9 | import java.io.IOException; 10 | 11 | /** 12 | * Deserialize boolean type. 13 | */ 14 | public class CustomBoolDeserializer extends StdDeserializer{ 15 | 16 | /** 17 | * Default constructor 18 | */ 19 | public CustomBoolDeserializer() { 20 | super(Boolean.class); 21 | } 22 | 23 | @Override 24 | public Boolean deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException { 25 | JsonToken jsonToken = parser.getCurrentToken(); 26 | if (jsonToken == JsonToken.VALUE_TRUE) { 27 | return true; 28 | } 29 | if (jsonToken == JsonToken.VALUE_FALSE) { 30 | return false; 31 | } 32 | if (jsonToken == JsonToken.VALUE_NULL) { 33 | return parseNull(ctxt); 34 | } 35 | if (jsonToken == JsonToken.VALUE_STRING) { 36 | String text = parser.getText().trim(); 37 | if (StringUtils.isEmpty(text)) { 38 | return parseNull(ctxt); 39 | } 40 | return Boolean.valueOf(text); 41 | } 42 | return false; 43 | } 44 | 45 | private Boolean parseNull(DeserializationContext ctxt) throws IOException { 46 | _verifyNullForPrimitive(ctxt); 47 | return false; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/conf/deserializers/CustomStringDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.conf.deserializers; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.DeserializationContext; 6 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * Deserialize string and trims all leading and trailing whitespaces from string. 12 | */ 13 | public class CustomStringDeserializer extends StdDeserializer { 14 | 15 | /** 16 | * Default constructor 17 | */ 18 | public CustomStringDeserializer() { 19 | super(String.class); 20 | } 21 | 22 | @Override 23 | public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { 24 | return jsonParser.getValueAsString().trim(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/controllers/AddressViewModel.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.controllers; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.model.persistables.Address; 5 | import com.iota.iri.storage.Indexable; 6 | import com.iota.iri.storage.Persistable; 7 | import com.iota.iri.storage.Tangle; 8 | import com.iota.iri.utils.Pair; 9 | 10 | import java.util.Set; 11 | 12 | /** 13 | * Created by paul on 5/15/17. 14 | */ 15 | public class AddressViewModel implements HashesViewModel { 16 | private Address self; 17 | private Indexable hash; 18 | 19 | public AddressViewModel(Hash hash) { 20 | this.hash = hash; 21 | } 22 | 23 | private AddressViewModel(Address hashes, Indexable hash) { 24 | self = hashes == null || hashes.set == null ? new Address(): hashes; 25 | this.hash = hash; 26 | } 27 | 28 | public static AddressViewModel load(Tangle tangle, Indexable hash) throws Exception { 29 | return new AddressViewModel((Address) tangle.load(Address.class, hash), hash); 30 | } 31 | 32 | public boolean store(Tangle tangle) throws Exception { 33 | return tangle.save(self, hash); 34 | } 35 | 36 | public int size() { 37 | return self.set.size(); 38 | } 39 | 40 | public boolean addHash(Hash theHash) { 41 | return getHashes().add(theHash); 42 | } 43 | 44 | public Indexable getIndex() { 45 | return hash; 46 | } 47 | 48 | public Set getHashes() { 49 | return self.set; 50 | } 51 | @Override 52 | public void delete(Tangle tangle) throws Exception { 53 | tangle.delete(Address.class,hash); 54 | } 55 | 56 | public static AddressViewModel first(Tangle tangle) throws Exception { 57 | Pair bundlePair = tangle.getFirst(Address.class, Hash.class); 58 | if(bundlePair != null && bundlePair.hi != null) { 59 | return new AddressViewModel((Address) bundlePair.hi, (Hash) bundlePair.low); 60 | } 61 | return null; 62 | } 63 | 64 | public AddressViewModel next(Tangle tangle) throws Exception { 65 | Pair bundlePair = tangle.next(Address.class, hash); 66 | if(bundlePair != null && bundlePair.hi != null) { 67 | return new AddressViewModel((Address) bundlePair.hi, (Hash) bundlePair.low); 68 | } 69 | return null; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/controllers/ApproveeViewModel.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.controllers; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.model.persistables.Approvee; 5 | import com.iota.iri.storage.Indexable; 6 | import com.iota.iri.storage.Persistable; 7 | import com.iota.iri.storage.Tangle; 8 | import com.iota.iri.utils.Pair; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | public class ApproveeViewModel implements HashesViewModel { 15 | private Approvee self; 16 | private Indexable hash; 17 | 18 | public ApproveeViewModel(Hash hash) { 19 | this.hash = hash; 20 | } 21 | 22 | private ApproveeViewModel(Approvee hashes, Indexable hash) { 23 | self = hashes == null || hashes.set == null ? new Approvee(): hashes; 24 | this.hash = hash; 25 | } 26 | 27 | public static ApproveeViewModel load(Tangle tangle, Indexable hash) throws Exception { 28 | return new ApproveeViewModel((Approvee) tangle.load(Approvee.class, hash), hash); 29 | } 30 | 31 | public static Map.Entry getEntry(Hash hash, Hash hashToMerge) throws Exception { 32 | Approvee hashes = new Approvee(); 33 | hashes.set.add(hashToMerge); 34 | return new HashMap.SimpleEntry<>(hash, hashes); 35 | } 36 | 37 | public boolean store(Tangle tangle) throws Exception { 38 | return tangle.save(self, hash); 39 | } 40 | 41 | public int size() { 42 | return self.set.size(); 43 | } 44 | 45 | public boolean addHash(Hash theHash) { 46 | return getHashes().add(theHash); 47 | } 48 | 49 | public Indexable getIndex() { 50 | return hash; 51 | } 52 | 53 | public Set getHashes() { 54 | return self.set; 55 | } 56 | @Override 57 | public void delete(Tangle tangle) throws Exception { 58 | tangle.delete(Approvee.class,hash); 59 | } 60 | 61 | public static ApproveeViewModel first(Tangle tangle) throws Exception { 62 | Pair bundlePair = tangle.getFirst(Approvee.class, Hash.class); 63 | if(bundlePair != null && bundlePair.hi != null) { 64 | return new ApproveeViewModel((Approvee) bundlePair.hi, (Hash) bundlePair.low); 65 | } 66 | return null; 67 | } 68 | 69 | public ApproveeViewModel next(Tangle tangle) throws Exception { 70 | Pair bundlePair = tangle.next(Approvee.class, hash); 71 | if(bundlePair != null && bundlePair.hi != null) { 72 | return new ApproveeViewModel((Approvee) bundlePair.hi, (Hash) bundlePair.low); 73 | } 74 | return null; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/controllers/BundleViewModel.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.controllers; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.model.persistables.Bundle; 5 | import com.iota.iri.storage.Indexable; 6 | import com.iota.iri.storage.Persistable; 7 | import com.iota.iri.storage.Tangle; 8 | import com.iota.iri.utils.Pair; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | public class BundleViewModel implements HashesViewModel { 15 | private Bundle self; 16 | private Indexable hash; 17 | 18 | public BundleViewModel(Hash hash) { 19 | this.hash = hash; 20 | } 21 | 22 | private BundleViewModel(Bundle hashes, Indexable hash) { 23 | self = hashes == null || hashes.set == null ? new Bundle(): hashes; 24 | this.hash = hash; 25 | } 26 | 27 | public static BundleViewModel load(Tangle tangle, Indexable hash) throws Exception { 28 | return new BundleViewModel((Bundle) tangle.load(Bundle.class, hash), hash); 29 | } 30 | 31 | public static Map.Entry getEntry(Hash hash, Hash hashToMerge) throws Exception { 32 | Bundle hashes = new Bundle(); 33 | hashes.set.add(hashToMerge); 34 | return new HashMap.SimpleEntry<>(hash, hashes); 35 | } 36 | 37 | /* 38 | public static boolean merge(Hash hash, Hash hashToMerge) throws Exception { 39 | Bundle hashes = new Bundle(); 40 | hashes.set = new HashSet<>(Collections.singleton(hashToMerge)); 41 | return Tangle.instance().merge(hashes, hash); 42 | } 43 | */ 44 | 45 | public boolean store(Tangle tangle) throws Exception { 46 | return tangle.save(self, hash); 47 | } 48 | 49 | public int size() { 50 | return self.set.size(); 51 | } 52 | 53 | public boolean addHash(Hash theHash) { 54 | return getHashes().add(theHash); 55 | } 56 | 57 | public Indexable getIndex() { 58 | return hash; 59 | } 60 | 61 | public Set getHashes() { 62 | return self.set; 63 | } 64 | 65 | @Override 66 | public void delete(Tangle tangle) throws Exception { 67 | tangle.delete(Bundle.class,hash); 68 | } 69 | 70 | public static BundleViewModel first(Tangle tangle) throws Exception { 71 | Pair bundlePair = tangle.getFirst(Bundle.class, Hash.class); 72 | if(bundlePair != null && bundlePair.hi != null) { 73 | return new BundleViewModel((Bundle) bundlePair.hi, (Hash) bundlePair.low); 74 | } 75 | return null; 76 | } 77 | 78 | public BundleViewModel next(Tangle tangle) throws Exception { 79 | Pair bundlePair = tangle.next(Bundle.class, hash); 80 | if(bundlePair != null && bundlePair.hi != null) { 81 | return new BundleViewModel((Bundle) bundlePair.hi, (Hash) bundlePair.low); 82 | } 83 | return null; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/controllers/HashesViewModel.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.controllers; 2 | 3 | import java.util.Set; 4 | 5 | import com.iota.iri.model.Hash; 6 | import com.iota.iri.storage.Indexable; 7 | import com.iota.iri.storage.Tangle; 8 | 9 | public interface HashesViewModel { 10 | boolean store(Tangle tangle) throws Exception; 11 | int size(); 12 | boolean addHash(Hash theHash); 13 | Indexable getIndex(); 14 | Set getHashes(); 15 | void delete(Tangle tangle) throws Exception; 16 | 17 | HashesViewModel next(Tangle tangle) throws Exception; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/controllers/TagViewModel.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.controllers; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.model.persistables.ObsoleteTag; 5 | import com.iota.iri.model.persistables.Tag; 6 | import com.iota.iri.storage.Indexable; 7 | import com.iota.iri.storage.Persistable; 8 | import com.iota.iri.storage.Tangle; 9 | import com.iota.iri.utils.Pair; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import java.util.Set; 14 | 15 | public class TagViewModel implements HashesViewModel { 16 | private Tag self; 17 | private Indexable hash; 18 | 19 | public TagViewModel(Hash hash) { 20 | this.hash = hash; 21 | } 22 | 23 | private TagViewModel(Tag hashes, Indexable hash) { 24 | self = hashes == null || hashes.set == null ? new Tag(): hashes; 25 | this.hash = hash; 26 | } 27 | 28 | private static TagViewModel load(Tangle tangle, Indexable hash, Class model) throws Exception { 29 | return new TagViewModel((Tag) tangle.load(model, hash), hash); 30 | } 31 | 32 | public static TagViewModel load(Tangle tangle, Indexable hash) throws Exception { 33 | return load(tangle, hash, Tag.class); 34 | } 35 | 36 | public static TagViewModel loadObsolete(Tangle tangle, Indexable hash) throws Exception { 37 | return load(tangle, hash, ObsoleteTag.class); 38 | } 39 | 40 | public static Map.Entry getEntry(Hash hash, Hash hashToMerge) throws Exception { 41 | Tag hashes = new Tag(); 42 | hashes.set.add(hashToMerge); 43 | return new HashMap.SimpleEntry<>(hash, hashes); 44 | } 45 | 46 | public boolean store(Tangle tangle) throws Exception { 47 | return tangle.save(self, hash); 48 | } 49 | 50 | public int size() { 51 | return self.set.size(); 52 | } 53 | 54 | public boolean addHash(Hash theHash) { 55 | return getHashes().add(theHash); 56 | } 57 | 58 | public Indexable getIndex() { 59 | return hash; 60 | } 61 | 62 | public Set getHashes() { 63 | return self.set; 64 | } 65 | @Override 66 | public void delete(Tangle tangle) throws Exception { 67 | tangle.delete(Tag.class,hash); 68 | } 69 | public static TagViewModel first(Tangle tangle) throws Exception { 70 | Pair bundlePair = tangle.getFirst(Tag.class, Hash.class); 71 | if(bundlePair != null && bundlePair.hi != null) { 72 | return new TagViewModel((Tag) bundlePair.hi, (Hash) bundlePair.low); 73 | } 74 | return null; 75 | } 76 | 77 | public TagViewModel next(Tangle tangle) throws Exception { 78 | Pair bundlePair = tangle.next(Tag.class, hash); 79 | if(bundlePair != null && bundlePair.hi != null) { 80 | return new TagViewModel((Tag) bundlePair.hi, (Hash) bundlePair.low); 81 | } 82 | return null; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/crypto/Sponge.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.crypto; 2 | 3 | /** 4 | * Hash functions from the Sponge family. 5 | * @see https://en.wikipedia.org/wiki/Sponge_function
6 | * 7 | * Popular usage: Hash(x) 8 | *
 9 |  * new sponge 
10 | * sponge.absorb(x)
11 | * return sponge.squeeze()
12 | *
13 | * 14 | */ 15 | public interface Sponge { 16 | int HASH_LENGTH = 243; 17 | 18 | /** 19 | * Absorbs {@code trits}, in chunks of {@value #HASH_LENGTH}.
20 | * can be called consecutively to absorb more trits. 21 | * 22 | * @param trits trits array to be absorbed by the sponge 23 | * @param offset starting position in trits array 24 | * @param length amount of trits to absorb, multiple of {@value #HASH_LENGTH} 25 | */ 26 | void absorb(final byte[] trits, int offset, int length); 27 | 28 | /** 29 | * Squeezes {@code length} trits from the sponge, in chunks of {@value #HASH_LENGTH}.
30 | * can be called consecutively to squeeze more trits.
31 | * this method will override the content of {@code trits} 32 | * 33 | * @param trits trits array to write squeezed trits to 34 | * @param offset starting position to write to in trits array 35 | * @param length amount of trits to squeeze, multiple of {@value #HASH_LENGTH} 36 | */ 37 | void squeeze(final byte[] trits, int offset, int length); 38 | 39 | /** 40 | * Resets the internal state of the sponge.
41 | * Can be used to re-use a Sponge object. 42 | */ 43 | void reset(); 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/crypto/SpongeFactory.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.crypto; 2 | 3 | /** 4 | * Creates sponge objects, based on required {@code Mode} 5 | * 6 | * @see Mode 7 | */ 8 | public abstract class SpongeFactory { 9 | /** 10 | * Modes of sponge constructions. 11 | * Determines which hash function we will use 12 | */ 13 | public enum Mode { 14 | CURLP81, 15 | CURLP27, 16 | KERL, 17 | //BCURLT 18 | } 19 | 20 | /** 21 | * Creates a new sponge object, based on required {@code Mode} 22 | * @param mode name of the hash function to use. 23 | * @return a newly initialized sponge 24 | */ 25 | public static Sponge create(Mode mode){ 26 | switch (mode) { 27 | case CURLP81: return new Curl(mode); 28 | case CURLP27: return new Curl(mode); 29 | case KERL: return new Kerl(); 30 | //case BCURLT: return new Curl(true, mode); 31 | default: return null; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/AddressHash.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model; 2 | 3 | public class AddressHash extends AbstractHash { 4 | 5 | protected AddressHash(byte[] bytes, int offset, int sizeInBytes) { 6 | super(bytes, offset, sizeInBytes); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/BundleHash.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model; 2 | 3 | public class BundleHash extends AbstractHash { 4 | 5 | protected BundleHash(byte[] bytes, int offset, int sizeInBytes) { 6 | super(bytes, offset, sizeInBytes); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/Hash.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model; 2 | 3 | import com.iota.iri.crypto.Curl; 4 | import com.iota.iri.storage.Indexable; 5 | 6 | public interface Hash extends Indexable, HashId { 7 | 8 | Hash NULL_HASH = HashFactory.TRANSACTION.create(new byte[Curl.HASH_LENGTH]); 9 | 10 | /** 11 | * The size of a hash stored in a byte[] when the data structure is trits 12 | */ 13 | int SIZE_IN_TRITS = 243; 14 | 15 | /** 16 | * The size of a hash stored in a byte[] when the data structure is bytes 17 | */ 18 | int SIZE_IN_BYTES = 49; 19 | 20 | /** 21 | * The data of this hash in trits 22 | * @return the trits 23 | */ 24 | public byte[] trits(); 25 | 26 | /** 27 | * The amount of zeros this hash has on the end. 28 | * Defines the weightMagnitude for a transaction. 29 | * @return the trailing zeros 30 | */ 31 | public int trailingZeros(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/HashId.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model; 2 | 3 | /** 4 | * Represents an ID of a transaction, address or bundle 5 | */ 6 | public interface HashId { 7 | 8 | /** 9 | * 10 | * @return the bytes of the Hash Id 11 | */ 12 | byte[] bytes(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/HashPrefix.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model; 2 | 3 | import com.iota.iri.crypto.Curl; 4 | import com.iota.iri.utils.Converter; 5 | 6 | import java.util.Arrays; 7 | 8 | public final class HashPrefix implements HashId { 9 | public static final int PREFIX_LENGTH = 44; 10 | private final byte[] bytes; 11 | 12 | public static HashPrefix createPrefix(HashId hashId) { 13 | if (hashId == null) { 14 | return null; 15 | } 16 | if (hashId instanceof HashPrefix) { 17 | return (HashPrefix) hashId; 18 | } 19 | 20 | byte[] bytes = hashId.bytes(); 21 | bytes = Arrays.copyOf(bytes, PREFIX_LENGTH); 22 | return new HashPrefix(bytes); 23 | } 24 | 25 | private HashPrefix(byte[] bytes) { 26 | this.bytes = bytes; 27 | } 28 | 29 | @Override 30 | public byte[] bytes() { 31 | return bytes; 32 | } 33 | 34 | @Override 35 | public boolean equals(Object o) { 36 | if (this == o) { 37 | return true; 38 | } 39 | if (o == null || getClass() != o.getClass()) { 40 | return false; 41 | } 42 | HashPrefix that = (HashPrefix) o; 43 | return Arrays.equals(bytes, that.bytes); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return Arrays.hashCode(bytes); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return trytes(bytes); 54 | } 55 | 56 | private static String trytes(byte[] bytes) { 57 | byte[] dest = new byte[Curl.HASH_LENGTH]; 58 | Converter.getTrits(bytes, dest); 59 | return Converter.trytes(dest); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/IntegerIndex.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model; 2 | 3 | import com.iota.iri.storage.Indexable; 4 | import com.iota.iri.utils.Serializer; 5 | 6 | public class IntegerIndex implements Indexable{ 7 | int value; 8 | public IntegerIndex(int value) { 9 | this.value = value; 10 | } 11 | 12 | public IntegerIndex() {} 13 | 14 | public int getValue() { 15 | return value; 16 | } 17 | 18 | @Override 19 | public byte[] bytes() { 20 | return Serializer.serialize(value); 21 | } 22 | 23 | @Override 24 | public void read(byte[] bytes) { 25 | this.value = Serializer.getInteger(bytes); 26 | } 27 | 28 | @Override 29 | public Indexable incremented() { 30 | return new IntegerIndex(value + 1); 31 | } 32 | 33 | @Override 34 | public Indexable decremented() { 35 | return new IntegerIndex(value - 1); 36 | } 37 | 38 | @Override 39 | public int compareTo(Indexable o) { 40 | IntegerIndex i = new IntegerIndex(Serializer.getInteger(o.bytes())); 41 | return value - ((IntegerIndex) o).value; 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return value; 47 | } 48 | 49 | @Override 50 | public boolean equals(Object obj) { 51 | if (obj == this) { 52 | return true; 53 | } 54 | 55 | if (!(obj instanceof IntegerIndex)) { 56 | return false; 57 | } 58 | 59 | return ((IntegerIndex) obj).value == value; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/ObsoleteTagHash.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model; 2 | 3 | public class ObsoleteTagHash extends AbstractHash { 4 | 5 | protected ObsoleteTagHash(byte[] tagBytes, int offset, int tagSizeInBytes) { 6 | super(tagBytes, offset, tagSizeInBytes); 7 | } 8 | } -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/TagHash.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model; 2 | 3 | public class TagHash extends AbstractHash { 4 | 5 | protected TagHash(byte[] tagBytes, int offset, int tagSizeInBytes) { 6 | super(tagBytes, offset, tagSizeInBytes); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/TransactionHash.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model; 2 | 3 | import com.iota.iri.crypto.Sponge; 4 | import com.iota.iri.crypto.SpongeFactory; 5 | import com.iota.iri.utils.Converter; 6 | 7 | public class TransactionHash extends AbstractHash { 8 | 9 | protected TransactionHash(byte[] source, int offset, int sourceSize) { 10 | super(source, offset, sourceSize); 11 | } 12 | 13 | /** 14 | * Calculates a transaction hash from an array of bytes. Uses the entire trits array 15 | * @param mode The mode we absorb the trits with 16 | * @param trits array of trits we calculate the hash with 17 | * @return The {@link TransactionHash} 18 | */ 19 | public static TransactionHash calculate(SpongeFactory.Mode mode, byte[] trits) { 20 | return calculate(trits, 0, trits.length, SpongeFactory.create(mode)); 21 | } 22 | 23 | /** 24 | * Calculates a transaction hash from an array of bytes 25 | * @param bytes The bytes that contain this transactionHash 26 | * @param tritsLength The length of trits the bytes represent 27 | * @param sponge The way we absorb the trits with 28 | * @return The {@link TransactionHash} 29 | */ 30 | public static TransactionHash calculate(byte[] bytes, int tritsLength, Sponge sponge) { 31 | byte[] trits = new byte[tritsLength]; 32 | Converter.getTrits(bytes, trits); 33 | return calculate(trits, 0, tritsLength, sponge); 34 | } 35 | 36 | /** 37 | * Calculates a transaction hash from an array of bytes 38 | * @param tritsToCalculate array of trits we calculate the hash with 39 | * @param offset The position we start reading from inside the tritsToCalculate array 40 | * @param length The length of trits the bytes represent 41 | * @param sponge The way we absorb the trits with 42 | * @return The {@link TransactionHash} 43 | */ 44 | public static TransactionHash calculate(byte[] tritsToCalculate, int offset, int length, Sponge sponge) { 45 | byte[] hashTrits = new byte[SIZE_IN_TRITS]; 46 | sponge.reset(); 47 | sponge.absorb(tritsToCalculate, offset, length); 48 | sponge.squeeze(hashTrits, 0, SIZE_IN_TRITS); 49 | return (TransactionHash) HashFactory.TRANSACTION.create(hashTrits, 0, SIZE_IN_TRITS); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/persistables/Address.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.persistables; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | public class Address extends Hashes{ 6 | public Address(){} 7 | public Address(Hash hash) { 8 | set.add(hash); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/persistables/Approvee.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.persistables; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | /** 6 | * Created by paul on 5/15/17. 7 | */ 8 | public class Approvee extends Hashes{ 9 | public Approvee(Hash hash) { 10 | set.add(hash); 11 | } 12 | 13 | public Approvee() { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/persistables/Bundle.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.persistables; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | /** 6 | * Created by paul on 5/15/17. 7 | */ 8 | public class Bundle extends Hashes{ 9 | public Bundle(Hash hash) { 10 | set.add(hash); 11 | } 12 | 13 | public Bundle() { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/persistables/Hashes.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.persistables; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.model.HashFactory; 5 | import com.iota.iri.storage.Persistable; 6 | import org.apache.commons.lang3.ArrayUtils; 7 | 8 | import java.util.LinkedHashSet; 9 | import java.util.Set; 10 | 11 | /** 12 | * Created by paul on 3/8/17 for iri. 13 | */ 14 | public class Hashes implements Persistable { 15 | public Set set = new LinkedHashSet<>(); 16 | private static final byte delimiter = ",".getBytes()[0]; 17 | 18 | public byte[] bytes() { 19 | return set.parallelStream() 20 | .map(Hash::bytes) 21 | .reduce((a,b) -> ArrayUtils.addAll(ArrayUtils.add(a, delimiter), b)) 22 | .orElse(new byte[0]); 23 | } 24 | 25 | public void read(byte[] bytes) { 26 | if(bytes != null) { 27 | set = new LinkedHashSet<>(bytes.length / (1 + Hash.SIZE_IN_BYTES) + 1); 28 | for (int i = 0; i < bytes.length; i += 1 + Hash.SIZE_IN_BYTES) { 29 | set.add(HashFactory.TRANSACTION.create(bytes, i, Hash.SIZE_IN_BYTES)); 30 | } 31 | } 32 | } 33 | 34 | @Override 35 | public byte[] metadata() { 36 | return new byte[0]; 37 | } 38 | 39 | @Override 40 | public void readMetadata(byte[] bytes) { 41 | 42 | } 43 | 44 | @Override 45 | public boolean merge() { 46 | return true; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/persistables/ObsoleteTag.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.persistables; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | public class ObsoleteTag extends Tag { 6 | 7 | public ObsoleteTag(Hash hash) { 8 | super(hash); 9 | } 10 | 11 | // used by the persistence layer to instantiate the object 12 | public ObsoleteTag() { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/persistables/Tag.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.persistables; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | /** 6 | * Created by paul on 5/15/17. 7 | */ 8 | public class Tag extends Hashes { 9 | public Tag(Hash hash) { 10 | set.add(hash); 11 | } 12 | 13 | public Tag() { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/safe/ByteSafe.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.safe; 2 | 3 | public class ByteSafe extends HashSafeObject { 4 | public ByteSafe(byte[] bytes) { 5 | super(bytes, "ByteSafe is attempted to be initialized with a null byte array"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/safe/HashSafeObject.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.safe; 2 | 3 | import java.util.Arrays; 4 | 5 | public class HashSafeObject extends SafeObject { 6 | 7 | private Integer hashcode; 8 | 9 | public HashSafeObject(byte[] obj, String messageIfUnsafe) { 10 | super(obj, messageIfUnsafe); 11 | 12 | this.hashcode = Arrays.hashCode(getData()); 13 | } 14 | 15 | /** 16 | * Returns the hash code from the contained data 17 | * @return the hashcode 18 | */ 19 | public Integer getHashcode() { 20 | return hashcode; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/safe/SafeObject.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.safe; 2 | 3 | import java.util.Objects; 4 | 5 | public class SafeObject { 6 | 7 | byte[] safeObj; 8 | 9 | /** 10 | * Creates an object which is verified during instantiation. 11 | * @param obj the array of bytes we check against 12 | * @param messageIfUnsafe The message we emit when it is not safe (inside an exception) 13 | */ 14 | SafeObject(byte[] obj, String messageIfUnsafe){ 15 | this.safeObj = obj; 16 | 17 | checkSafe(messageIfUnsafe); 18 | } 19 | 20 | /** 21 | * This data is checked against its "save" conditions. 22 | * @return the data this object guards 23 | */ 24 | public byte[] getData() { 25 | return safeObj; 26 | } 27 | 28 | protected void checkSafe(String messageIfUnsafe) { 29 | Objects.requireNonNull(safeObj, messageIfUnsafe); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/model/safe/TritSafe.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.safe; 2 | 3 | public class TritSafe extends SafeObject { 4 | public TritSafe(byte[] bytes) { 5 | super(bytes, "TritSafe is attempted to be initialized with a null byte array"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/network/UDPNeighbor.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.network; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.net.DatagramPacket; 7 | import java.net.DatagramSocket; 8 | import java.net.InetSocketAddress; 9 | 10 | /** 11 | * Created by paul on 4/15/17. 12 | */ 13 | 14 | /** 15 | * This class Extends {@link Neighbor} base class with UDP specific functionality. 16 | * It keeps reference of socket and doesnt maintains any queue for UDP outgoing packets. 17 | * 18 | */ 19 | public class UDPNeighbor extends Neighbor { 20 | 21 | private static final Logger log = LoggerFactory.getLogger(UDPNeighbor.class); 22 | 23 | private final DatagramSocket socket; 24 | 25 | UDPNeighbor(final InetSocketAddress address, final DatagramSocket socket, final boolean isConfigured) { 26 | super(address, isConfigured); 27 | this.socket = socket; 28 | } 29 | 30 | /** 31 | * This is a blocking write and it is not necessary to copy the sent data. 32 | * 33 | * @param packet the packet to be sent immediately. 34 | */ 35 | @Override 36 | public void send(DatagramPacket packet) { 37 | try { 38 | packet.setSocketAddress(getAddress()); 39 | socket.send(packet); 40 | incSentTransactions(); 41 | } catch (final Exception e) { 42 | log.error("Error sending UDP packet to [{}]: {}", getAddress(), e.toString()); 43 | } 44 | } 45 | 46 | @Override 47 | public int getPort() { 48 | return getAddress().getPort(); 49 | } 50 | 51 | @Override 52 | public String connectionType() { 53 | return "udp"; 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/network/replicator/Replicator.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.network.replicator; 2 | 3 | import com.iota.iri.conf.NodeConfig; 4 | import com.iota.iri.network.Node; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | 9 | /** 10 | * This class manages a set of Source and Sink pool workers {@link ReplicatorSourceProcessor} 11 | * and {@link ReplicatorSinkProcessor}. The workers are managed by the Pool manager threads 12 | * {@link ReplicatorSourcePool} and {@link ReplicatorSinkPool} 13 | *
14 | * A **Sink** is basically a received end point for TCP where all the peers send 15 | * trnasactions to. Since there is only one global endpoint for all the peers, we need 16 | * only a single thread to manage all the incoming messages. 17 | *
18 | * A **Source** is a single peer which sends packets to us, therefore we need multiple worker 19 | * threads to manage sending transaction to multiple peers. 20 | * 21 | */ 22 | 23 | public class Replicator { 24 | 25 | public static final int NUM_THREADS = 32; 26 | 27 | private static final Logger log = LoggerFactory.getLogger(Replicator.class); 28 | private final ReplicatorSinkPool replicatorSinkPool; 29 | private final int port; 30 | private ReplicatorSourcePool replicatorSourcePool; 31 | 32 | public Replicator(Node node, NodeConfig configuration) { 33 | this.port = configuration.getTcpReceiverPort(); 34 | replicatorSinkPool = new ReplicatorSinkPool(node, port, configuration.getTransactionPacketSize()); 35 | replicatorSourcePool = new ReplicatorSourcePool(replicatorSinkPool, node, configuration.getMaxPeers(), 36 | configuration.isTestnet()); 37 | } 38 | 39 | public void init() { 40 | new Thread(replicatorSinkPool).start(); 41 | new Thread(replicatorSourcePool.init(port)).start(); 42 | log.info("Started ReplicatorSourcePool"); 43 | } 44 | 45 | public void shutdown() throws InterruptedException { 46 | // TODO 47 | replicatorSourcePool.shutdown(); 48 | replicatorSinkPool.shutdown(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/network/replicator/ReplicatorSourcePool.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.network.replicator; 2 | 3 | import java.io.IOException; 4 | import java.net.ServerSocket; 5 | import java.net.Socket; 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import com.iota.iri.network.Node; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | public class ReplicatorSourcePool implements Runnable { 15 | 16 | private final ReplicatorSinkPool replicatorSinkPool; 17 | private final Node node; 18 | private final int maxPeers; 19 | private final boolean testnet; 20 | private volatile boolean shutdown = false; 21 | 22 | private static final Logger log = LoggerFactory.getLogger(ReplicatorSourcePool.class); 23 | private ExecutorService pool; 24 | private int port; 25 | 26 | public ReplicatorSourcePool(final ReplicatorSinkPool replicatorSinkPool, 27 | final Node node, 28 | final int maxPeers, 29 | final boolean testnet) { 30 | this.replicatorSinkPool = replicatorSinkPool; 31 | this.node = node; 32 | this.maxPeers = maxPeers; 33 | this.testnet = testnet; 34 | } 35 | 36 | @Override 37 | public void run() { 38 | ExecutorService pool; 39 | ServerSocket server = null; 40 | pool = Executors.newFixedThreadPool(Replicator.NUM_THREADS); 41 | this.pool = pool; 42 | try { 43 | server = new ServerSocket(port); 44 | log.info("TCP replicator is accepting connections on tcp port " + server.getLocalPort()); 45 | while (!shutdown) { 46 | try { 47 | Socket request = server.accept(); 48 | request.setSoLinger(true, 0); 49 | Runnable proc = new ReplicatorSourceProcessor( replicatorSinkPool, request, node, maxPeers, testnet); 50 | pool.submit(proc); 51 | } catch (IOException ex) { 52 | log.error("Error accepting connection", ex); 53 | } 54 | } 55 | log.info("ReplicatorSinkPool shutting down"); 56 | } catch (IOException e) { 57 | log.error("***** NETWORK ALERT ***** Cannot create server socket on port {}, {}", port, e.getMessage()); 58 | } finally { 59 | if (server != null) { 60 | try { 61 | server.close(); 62 | } 63 | catch (Exception e) { 64 | // don't care. 65 | } 66 | } 67 | } 68 | } 69 | 70 | public void shutdown() throws InterruptedException { 71 | shutdown = true; 72 | //notify(); 73 | pool.shutdown(); 74 | pool.awaitTermination(6, TimeUnit.SECONDS); 75 | } 76 | 77 | public ReplicatorSourcePool init(int port) { 78 | this.port = port; 79 | return this; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/CallableRequest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service; 2 | 3 | import java.util.Map; 4 | 5 | public interface CallableRequest { 6 | V call(Map request); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/ValidationException.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service; 2 | 3 | public class ValidationException extends Exception { 4 | 5 | /** 6 | * Initializes a new instance of the ValidationException. 7 | */ 8 | public ValidationException() { 9 | super("Invalid parameters are passed"); 10 | } 11 | 12 | /** 13 | * Initializes a new instance of the ValidationException with the specified detail message. 14 | */ 15 | public ValidationException(String msg) { 16 | super(msg); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/AbstractResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import org.apache.commons.lang3.builder.EqualsBuilder; 4 | import org.apache.commons.lang3.builder.HashCodeBuilder; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | import org.apache.commons.lang3.builder.ToStringStyle; 7 | 8 | /** 9 | * 10 | * Every response that the IRI API gives is a child of this class.
11 | * Duration for every response is recorded automatically during the processing of a request. 12 | * 13 | **/ 14 | public abstract class AbstractResponse { 15 | 16 | /** 17 | * An 'empty' Response class. 18 | * Will only contain values which are included in {@link AbstractResponse} itself. 19 | * This is used when an API command does not need to return data. 20 | */ 21 | private static class Emptyness extends AbstractResponse {} 22 | 23 | /** 24 | * The duration it took to process this command in milliseconds 25 | */ 26 | private Integer duration; 27 | 28 | /** 29 | * Builds a string representation of this object using multiple lines 30 | * 31 | * @return Returns a string representation of this object. 32 | */ 33 | @Override 34 | public String toString() { 35 | return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); 36 | } 37 | 38 | 39 | @Override 40 | public int hashCode() { 41 | return HashCodeBuilder.reflectionHashCode(this, false); 42 | } 43 | 44 | @Override 45 | public boolean equals(Object obj) { 46 | return EqualsBuilder.reflectionEquals(this, obj, false); 47 | } 48 | 49 | /** 50 | * 51 | * @return {@link #duration} 52 | */ 53 | public Integer getDuration() { 54 | return duration; 55 | } 56 | 57 | /** 58 | * 59 | * @param duration {@link #duration} 60 | */ 61 | public void setDuration(Integer duration) { 62 | this.duration = duration; 63 | } 64 | 65 | /** 66 | * If a response doesn't need to send data back, an {@link Emptyness} is used. 67 | * This has all the fields and functions of an AbstractResponse, and nothing more. 68 | * 69 | * @return Returns a plain AbstractResponse without extra fields 70 | */ 71 | public static AbstractResponse createEmptyResponse() { 72 | return new Emptyness(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/AccessLimitedResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | /** 4 | * 5 | * This class represents the API error for accessing a command when it is not allowed by this Node. 6 | * 7 | */ 8 | public class AccessLimitedResponse extends AbstractResponse { 9 | 10 | /** 11 | * The error identifies what caused this Response. 12 | * It is a readable message identifying the command that is limited. 13 | */ 14 | private String error; 15 | 16 | /** 17 | * Creates a new {@link AccessLimitedResponse} 18 | * 19 | * @param error {@link #error} 20 | * @return an {@link AccessLimitedResponse} filled with the error message 21 | */ 22 | public static AbstractResponse create(String error) { 23 | AccessLimitedResponse res = new AccessLimitedResponse(); 24 | res.error = error; 25 | return res; 26 | } 27 | 28 | /** 29 | * 30 | * @return {@link #error} 31 | */ 32 | public String getError() { 33 | return error; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/AddedNeighborsResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import com.iota.iri.service.API; 4 | 5 | /** 6 | * 7 | * Contains information about the result of a successful {@code addNeighbors} API call. 8 | * See {@link API#addNeighborsStatement} for how this response is created. 9 | * 10 | */ 11 | public class AddedNeighborsResponse extends AbstractResponse { 12 | 13 | /** 14 | * The amount of temporally added neighbors to this node. 15 | * Can be 0 or more. 16 | */ 17 | private int addedNeighbors; 18 | 19 | /** 20 | * Creates a new {@link AddedNeighborsResponse} 21 | * 22 | * @param numberOfAddedNeighbors {@link #addedNeighbors} 23 | * @return an {@link AddedNeighborsResponse} filled with the number of added neighbors 24 | */ 25 | public static AbstractResponse create(int numberOfAddedNeighbors) { 26 | AddedNeighborsResponse res = new AddedNeighborsResponse(); 27 | res.addedNeighbors = numberOfAddedNeighbors; 28 | return res; 29 | } 30 | 31 | /** 32 | * 33 | * @return {link #addedNeighbors} 34 | */ 35 | public int getAddedNeighbors() { 36 | return addedNeighbors; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/AttachToTangleResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import java.util.List; 4 | 5 | import com.iota.iri.service.API; 6 | 7 | /** 8 | * 9 | * Contains information about the result of a successful {@code attachToTangle} API call. 10 | * @see {@link API#attachToTangleStatement} for how this response is created. 11 | * 12 | */ 13 | public class AttachToTangleResponse extends AbstractResponse { 14 | 15 | /** 16 | * List of the attached transaction trytes. 17 | * The last 243 trytes of the return value consist of the: 18 | * trunkTransaction + branchTransaction + nonce. 19 | */ 20 | private List trytes; 21 | 22 | /** 23 | * Creates a new {@link AttachToTangleResponse} 24 | * @param elements {@link #trytes} 25 | * @return an {@link AttachToTangleResponse} filled with the trytes 26 | */ 27 | public static AbstractResponse create(List elements) { 28 | AttachToTangleResponse res = new AttachToTangleResponse(); 29 | res.trytes = elements; 30 | return res; 31 | } 32 | 33 | /** 34 | * 35 | * @return {@link #trytes} 36 | */ 37 | public List getTrytes() { 38 | return trytes; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/CheckConsistency.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import com.iota.iri.service.API; 4 | 5 | /** 6 | * 7 | * Contains information about the result of a successful {@code checkConsistency} API call. 8 | * See {@link API#checkConsistencyStatement} for how this response is created. 9 | * 10 | */ 11 | public class CheckConsistency extends AbstractResponse { 12 | 13 | /** 14 | * The state of all the provided tails, which is set to {@code false} on the following checks
15 | *
    16 | *
  1. Missing a reference transaction
  2. 17 | *
  3. Invalid bundle
  4. 18 | *
  5. Tails of tails are invalid
  6. 19 | *
20 | */ 21 | private boolean state; 22 | 23 | /** 24 | * If state is {@code false}, this provides information on the cause of the inconsistency. 25 | */ 26 | private String info; 27 | 28 | /** 29 | * Creates a new {@link CheckConsistency} 30 | * @param state {@link #state} 31 | * @param info {@link #info} 32 | * @return a {@link CheckConsistency} filled with the state and info 33 | */ 34 | public static AbstractResponse create(boolean state, String info) { 35 | CheckConsistency res = new CheckConsistency(); 36 | res.state = state; 37 | res.info = info; 38 | return res; 39 | } 40 | 41 | /** 42 | * 43 | * @return {@link #state} 44 | */ 45 | public boolean getState() { 46 | return state; 47 | } 48 | 49 | /** 50 | * 51 | * @return {@link #info} 52 | */ 53 | public String getInfo() { 54 | return info; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import com.iota.iri.service.API; 4 | 5 | /** 6 | * This class represents the response the API returns when an error has occurred. 7 | * This can be returned for various reasons, see {@link API#process} for the cases. 8 | **/ 9 | public class ErrorResponse extends AbstractResponse { 10 | 11 | /** 12 | * The error string is a readable message identifying what caused this Error response. 13 | */ 14 | private String error; 15 | 16 | /** 17 | * Creates a new {@link ErrorResponse} 18 | * 19 | * @param error {@link #error} 20 | * @return an {@link ErrorResponse} filled with the error message 21 | */ 22 | public static AbstractResponse create(String error) { 23 | ErrorResponse res = new ErrorResponse(); 24 | res.error = error; 25 | return res; 26 | } 27 | 28 | /** 29 | * 30 | * @return {@link #error} 31 | */ 32 | public String getError() { 33 | return error; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/ExceptionResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import com.iota.iri.service.API; 4 | 5 | /** 6 | * 7 | * This class represents the response the API returns when an exception has occurred. 8 | * This can be returned for various reasons, see {@link API#process} for the cases. 9 | * 10 | **/ 11 | public class ExceptionResponse extends AbstractResponse { 12 | 13 | /** 14 | * Contains a readable message as to why an exception has been thrown. 15 | * This is either due to invalid payload of an API request, or the message of an uncaught exception. 16 | */ 17 | private String exception; 18 | 19 | /** 20 | * 21 | * Creates a new {@link ExceptionResponse} 22 | * 23 | * @param exception {@link #exception} 24 | * @return an {@link ExceptionResponse} filled with the exception 25 | */ 26 | public static AbstractResponse create(String exception) { 27 | ExceptionResponse res = new ExceptionResponse(); 28 | res.exception = exception; 29 | return res; 30 | } 31 | 32 | /** 33 | * 34 | * @return {@link #exception} 35 | */ 36 | public String getException() { 37 | return exception; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/FindTransactionsResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import java.util.List; 4 | 5 | import com.iota.iri.service.API; 6 | 7 | /** 8 | * 9 | * Contains information about the result of a successful {@code findTransactions} API call. 10 | * See {@link API#findTransactionsStatement} for how this response is created. 11 | * 12 | */ 13 | public class FindTransactionsResponse extends AbstractResponse { 14 | 15 | /** 16 | * The transaction hashes which are returned depend on your input. 17 | * For each specified input value, the command will return the following: 18 | * bundles: returns the list of transactions which contain the specified bundle hash. 19 | * addresses: returns the list of transactions which have the specified address as an input/output field. 20 | * tags: returns the list of transactions which contain the specified tag value. 21 | * approvees: returns the list of transactions which reference (i.e. approve) the specified transaction. 22 | */ 23 | private String [] hashes; 24 | 25 | /** 26 | * Creates a new {@link FindTransactionsResponse} 27 | * 28 | * @param elements {@link #hashes} 29 | * @return an {@link FindTransactionsResponse} filled with the hashes 30 | */ 31 | public static AbstractResponse create(List elements) { 32 | FindTransactionsResponse res = new FindTransactionsResponse(); 33 | res.hashes = elements.toArray(new String[] {}); 34 | return res; 35 | } 36 | 37 | 38 | /** 39 | * 40 | * @return {@link #hashes} 41 | */ 42 | public String[] getHashes() { 43 | return hashes; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/GetBalancesResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import java.util.List; 4 | 5 | import com.iota.iri.service.API; 6 | 7 | /** 8 | * 9 | * Contains information about the result of a successful {@code getBalances} API call. 10 | * See {@link API#getBalancesStatement} for how this response is created. 11 | * 12 | */ 13 | public class GetBalancesResponse extends AbstractResponse { 14 | 15 | /** 16 | * The balances as a list in the same order as the addresses were provided as input 17 | */ 18 | private List balances; 19 | 20 | /** 21 | * The tips used to view the balances. If none were supplied this will be the latest confirmed milestone. 22 | */ 23 | private List references; 24 | 25 | /** 26 | * The milestone index with which the confirmed balance was determined 27 | */ 28 | private int milestoneIndex; 29 | 30 | /** 31 | * Creates a new {@link GetBalancesResponse} 32 | * 33 | * @param elements {@link #balances} 34 | * @param references {@link #references} 35 | * @param milestoneIndex {@link #milestoneIndex} 36 | * @return an {@link GetBalancesResponse} filled with the balances, references used and index used 37 | */ 38 | public static AbstractResponse create(List elements, List references, int milestoneIndex) { 39 | GetBalancesResponse res = new GetBalancesResponse(); 40 | res.balances = elements; 41 | res.references = references; 42 | res.milestoneIndex = milestoneIndex; 43 | return res; 44 | } 45 | 46 | /** 47 | * 48 | * @return {@link #references} 49 | */ 50 | public List getReferences() { 51 | return references; 52 | } 53 | 54 | /** 55 | * 56 | * @return {@link #milestoneIndex} 57 | */ 58 | public int getMilestoneIndex() { 59 | return milestoneIndex; 60 | } 61 | 62 | /** 63 | * 64 | * @return {@link #balances} 65 | */ 66 | public List getBalances() { 67 | return balances; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/GetConfidencesResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import com.iota.iri.service.API; 4 | import java.util.List; 5 | 6 | /** 7 | * 8 | * Contains information about the result of a successful {@code getConfidences} API call. 9 | * See {@link API#getConfidencesStatement} for how this response is created. 10 | * 11 | */ 12 | public class GetConfidencesResponse extends AbstractResponse { 13 | 14 | /** 15 | * A list of floating point values in the [0,1] interval, representing confirmation confidences 16 | */ 17 | private Double [] confidences; 18 | 19 | /** 20 | * Creates a new {@link GetConfidencesResponse} 21 | * 22 | * @param confidences {@link #confidences} 23 | * @return an {@link GetConfidencesResponse} filled with the error message 24 | */ 25 | public static AbstractResponse create(List confidences) { 26 | GetConfidencesResponse res = new GetConfidencesResponse(); 27 | res.confidences = confidences.toArray(new Double[confidences.size()]); 28 | return res; 29 | } 30 | 31 | /** 32 | * 33 | * @return {@link #confidences} 34 | */ 35 | public Double [] getConfidences() { 36 | return confidences; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/GetTipsResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import java.util.List; 4 | 5 | import com.iota.iri.service.API; 6 | 7 | /** 8 | * 9 | * Contains information about the result of a successful {@code getTips} API call. 10 | * See {@link API#getTipsStatement} for how this response is created. 11 | * 12 | */ 13 | public class GetTipsResponse extends AbstractResponse { 14 | 15 | /** 16 | * The current tips as seen by this node. 17 | */ 18 | private String[] hashes; 19 | 20 | /** 21 | * Creates a new {@link GetTipsResponse} 22 | * 23 | * @param elements {@link #hashes} 24 | * @return a {@link GetTipsResponse} filled with the provided tips 25 | */ 26 | public static AbstractResponse create(List elements) { 27 | GetTipsResponse res = new GetTipsResponse(); 28 | res.hashes = elements.toArray(new String[] {}); 29 | return res; 30 | } 31 | 32 | /** 33 | * 34 | * @return {@link #hashes} 35 | */ 36 | public String[] getHashes() { 37 | return hashes; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/GetTransactionsToApproveResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.service.API; 5 | 6 | /** 7 | * 8 | * Contains information about the result of a successful {@code getTransactionsToApprove} API call. 9 | * See {@link API#getTransactionsToApproveStatement} for how this response is created. 10 | * 11 | */ 12 | public class GetTransactionsToApproveResponse extends AbstractResponse { 13 | 14 | /** 15 | * The trunk transaction tip to reference in your transaction or bundle 16 | */ 17 | private String trunkTransaction; 18 | 19 | /** 20 | * The branch transaction tip to reference in your transaction or bundle 21 | */ 22 | private String branchTransaction; 23 | 24 | /** 25 | * Creates a new {@link GetTransactionsToApproveResponse} 26 | * 27 | * @param trunkTransactionToApprove {@link #trunkTransaction} 28 | * @param branchTransactionToApprove {@link #branchTransaction} 29 | * @return a {@link GetTransactionsToApproveResponse} filled with the provided tips 30 | */ 31 | public static AbstractResponse create(Hash trunkTransactionToApprove, Hash branchTransactionToApprove) { 32 | GetTransactionsToApproveResponse res = new GetTransactionsToApproveResponse(); 33 | res.trunkTransaction = trunkTransactionToApprove.toString(); 34 | res.branchTransaction = branchTransactionToApprove.toString(); 35 | return res; 36 | } 37 | 38 | /** 39 | * 40 | * @return {@link #branchTransaction} 41 | */ 42 | public String getBranchTransaction() { 43 | return branchTransaction; 44 | } 45 | 46 | /** 47 | * 48 | * @return {@link #trunkTransaction} 49 | */ 50 | public String getTrunkTransaction() { 51 | return trunkTransaction; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/GetTrytesResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import java.util.List; 4 | 5 | import com.iota.iri.model.persistables.Transaction; 6 | import com.iota.iri.service.API; 7 | 8 | /** 9 | * 10 | * Contains information about the result of a successful {@code getTrytes} API call. 11 | * See {@link API#getTrytesStatement} for how this response is created. 12 | * 13 | */ 14 | public class GetTrytesResponse extends AbstractResponse { 15 | 16 | /** 17 | * The raw transaction data (trytes) of the specified transactions. 18 | * These trytes can then be easily converted into the actual transaction object. 19 | * See library functions as to how to transform back to a {@link Transaction}. 20 | */ 21 | private String[] trytes; 22 | 23 | /** 24 | * Creates a new {@link GetTrytesResponse} 25 | * 26 | * @param elements {@link #trytes} 27 | * @return a {@link GetTrytesResponse} filled with the provided tips 28 | */ 29 | public static GetTrytesResponse create(List elements) { 30 | GetTrytesResponse res = new GetTrytesResponse(); 31 | res.trytes = elements.toArray(new String[] {}); 32 | return res; 33 | } 34 | 35 | /** 36 | * 37 | * @return {@link #trytes} 38 | */ 39 | public String [] getTrytes() { 40 | return trytes; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/IXIResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import com.iota.iri.IXI; 4 | 5 | /** 6 | *

7 | * When a command is not recognized by the default API, we try to process it as an IXI module. 8 | * IXI stands for Iota eXtension Interface. See {@link IXI} for more information. 9 | *

10 | *

11 | * The response will contain the reply that the IXI module gave. 12 | * This could be empty, depending on the module. 13 | *

14 | * 15 | * An example module can be found here: Snapshot.ixi 16 | * 17 | */ 18 | public class IXIResponse extends AbstractResponse { 19 | private Object ixi; 20 | 21 | public static IXIResponse create(Object myixi) { 22 | IXIResponse ixiResponse = new IXIResponse(); 23 | ixiResponse.ixi = myixi; 24 | return ixiResponse; 25 | } 26 | 27 | public Object getResponse() { 28 | return ixi; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/RemoveNeighborsResponse.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import com.iota.iri.service.API; 4 | 5 | /** 6 | * 7 | * Contains information about the result of a successful {@code removeNeighbors} API call. 8 | * See {@link API#removeNeighborsStatement} for how this response is created. 9 | * 10 | */ 11 | public class RemoveNeighborsResponse extends AbstractResponse { 12 | 13 | /** 14 | * The amount of temporarily removed neighbors from this node. 15 | * Can be 0 or more. 16 | */ 17 | private int removedNeighbors; 18 | 19 | /** 20 | * Creates a new {@link RemoveNeighborsResponse} 21 | * 22 | * @param numberOfRemovedNeighbors {@link #removedNeighbors} 23 | * @return an {@link RemoveNeighborsResponse} filled with the number of removed neighbors 24 | */ 25 | public static AbstractResponse create(int numberOfRemovedNeighbors) { 26 | RemoveNeighborsResponse res = new RemoveNeighborsResponse(); 27 | res.removedNeighbors = numberOfRemovedNeighbors; 28 | return res; 29 | } 30 | 31 | /** 32 | * 33 | * @return {@link #removedNeighbors} 34 | */ 35 | public int getRemovedNeighbors() { 36 | return removedNeighbors; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/dto/WereAddressesSpentFrom.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.dto; 2 | 3 | import com.iota.iri.service.API; 4 | 5 | /** 6 | * 7 | * Contains information about the result of a successful {@code wereAddressesSpentFrom} API call. 8 | * See {@link API#wereAddressesSpentFromStatement} for how this response is created. 9 | * 10 | */ 11 | public class WereAddressesSpentFrom extends AbstractResponse { 12 | 13 | /** 14 | * States of the specified addresses in Boolean 15 | * Order of booleans is equal to order of the supplied addresses. 16 | */ 17 | private boolean[] states; 18 | 19 | /** 20 | * Creates a new {@link WereAddressesSpentFrom} 21 | * 22 | * @param inclusionStates {@link #states} 23 | * @return a {@link WereAddressesSpentFrom} filled with the address states 24 | */ 25 | public static AbstractResponse create(boolean[] inclusionStates) { 26 | WereAddressesSpentFrom res = new WereAddressesSpentFrom(); 27 | res.states = inclusionStates; 28 | return res; 29 | } 30 | 31 | /** 32 | * 33 | * @return {@link #states} 34 | */ 35 | public boolean[] getStates() { 36 | return states; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/stats/LagCalculator.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.stats; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | 6 | import com.iota.iri.controllers.TransactionViewModel; 7 | import com.iota.iri.model.Hash; 8 | import com.iota.iri.storage.Tangle; 9 | import com.iota.iri.utils.dag.RecentTransactionsGetter; 10 | 11 | /** 12 | * Computes the node lag using various metrics 13 | */ 14 | public class LagCalculator { 15 | private int transactionCount; 16 | private RecentTransactionsGetter recentTransactionsGetter; 17 | private Tangle tangle; 18 | 19 | public LagCalculator(int transactionCount, Tangle tangle, RecentTransactionsGetter recentTransactionsGetter) { 20 | this.transactionCount = transactionCount; 21 | this.tangle = tangle; 22 | this.recentTransactionsGetter = recentTransactionsGetter; 23 | } 24 | 25 | public long getMedianArrivalLag() throws Exception { 26 | Collection recentTransactions = recentTransactionsGetter.getRecentTransactions(transactionCount); 27 | 28 | if (recentTransactions.isEmpty()) { 29 | return -1; 30 | } 31 | 32 | Long[] lags = recentTransactions.stream() 33 | .map(this::fromHash) 34 | .map(tx -> new Long(Math.abs(tx.getAttachmentTimestamp() - tx.getArrivalTime()))) 35 | .toArray(Long[]::new); 36 | 37 | Arrays.sort(lags); 38 | 39 | int middle = lags.length / 2; 40 | long median = lags.length % 2 == 1 ? 41 | lags[middle] : 42 | (lags[middle-1] + lags[middle]) / 2; 43 | 44 | return median; 45 | } 46 | 47 | private TransactionViewModel fromHash(Hash hash) { 48 | try { 49 | return TransactionViewModel.fromHash(tangle, hash); 50 | } catch (Exception e) { 51 | throw new RuntimeException("failed to load transaction"); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/EntryPointSelector.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | /** 6 | * Selects an entryPoint for tip selection. 7 | *

8 | * this point is used as the starting point where 9 | * the particle starts the random walk. 10 | *

11 | */ 12 | 13 | public interface EntryPointSelector { 14 | 15 | /** 16 | *get an entryPoint for tip selection 17 | * 18 | *Uses depth to determine the entry point for 19 | *the random walk. 20 | * 21 | * @param depth Depth, in milestones. a notion of how deep to search for a good starting point. 22 | * @return Entry point for walk method 23 | * @throws Exception If DB fails to retrieve transactions 24 | */ 25 | Hash getEntryPoint(int depth) throws Exception; 26 | 27 | /** 28 | *get an entryPoint for tip selection 29 | * 30 | *Uses depth to determine the entry point for 31 | *the random walk. 32 | * 33 | * @return Entry point for walk method 34 | * @throws Exception If DB fails to retrieve transactions 35 | */ 36 | Hash getEntryPoint() throws Exception; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/RatingCalculator.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.model.HashId; 5 | import com.iota.iri.utils.collections.interfaces.UnIterableMap; 6 | 7 | /** 8 | * Calculates the rating for a sub graph 9 | */ 10 | public interface RatingCalculator { 11 | 12 | /** 13 | * Rating calculator 14 | *

15 | * Calculates the rating of all the transactions that reference 16 | * a given entry point. 17 | *

18 | * 19 | * @param entryPoint Transaction hash of a selected entry point. 20 | * @return Map 21 | * @throws Exception If DB fails to retrieve transactions 22 | */ 23 | 24 | UnIterableMap calculate(Hash entryPoint) throws Exception; 25 | 26 | /** 27 | * Calculates rating for a single transactions 28 | * 29 | * @param transaction Transaction hash of transaction in question 30 | * @return Map 31 | * @throws Exception If DB fails to retrieve transaction 32 | */ 33 | int calculateSingle(Hash transaction) throws Exception; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/ReferenceChecker.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | /** 6 | * Checks if a given transaction references another 7 | */ 8 | public interface ReferenceChecker { 9 | boolean doesReference(Hash referencer, Hash target) throws Exception; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/StartingTipSelector.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | /** 6 | * Functional interface for selecting a tip to start backtracking from, 7 | * used in EntryPointSelectorCumulativeWeightThreshold. 8 | */ 9 | 10 | public interface StartingTipSelector { 11 | Hash getTip() throws Exception; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/TailFinder.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection; 2 | 3 | import java.util.Optional; 4 | 5 | import com.iota.iri.model.Hash; 6 | 7 | /** 8 | * Finds the tail of a bundle 9 | */ 10 | 11 | @FunctionalInterface 12 | public interface TailFinder { 13 | /** 14 | *Method for finding tails of bundles 15 | * 16 | *

17 | * This method is used to find a tail (current_index=0) of a bundle, 18 | * given any transaction hash in the bundle. 19 | *

20 | * 21 | * @param hash The transaction hash of any transaction in the bundle. 22 | * @return Hash of the tail transaction. 23 | * @throws Exception If DB fails to retrieve transactions 24 | */ 25 | Optional findTail(Hash hash) throws Exception; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/TipSelector.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | import com.iota.iri.model.Hash; 7 | 8 | /** 9 | * Selects tips to be approved 10 | */ 11 | 12 | 13 | public interface TipSelector { 14 | 15 | /** 16 | * Method for finding tips 17 | * 18 | *

19 | * This method is used to find tips for approval, 20 | * if reference is present then tips will also reference this transaction. 21 | *

22 | * 23 | * @param reference An optional transaction hash to be referenced by tips. 24 | * @return Transactions to approve 25 | * @throws Exception If DB fails to retrieve transactions 26 | */ 27 | List getTransactionsToApprove(Optional reference) throws Exception; 28 | 29 | List getConfidences(List transactions) throws Exception; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/WalkValidator.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection; 2 | 3 | import com.iota.iri.model.Hash; 4 | 5 | /** 6 | * Validates consistency of tails. 7 | */ 8 | @FunctionalInterface 9 | public interface WalkValidator { 10 | 11 | /** 12 | * Validation 13 | *

14 | * Checks if a given transaction is a valid tail. 15 | *

16 | * 17 | * @param transactionHash Transaction hash to validate consistency of. 18 | * @return True iff tail is valid. 19 | * @throws Exception If Validation fails to execute 20 | */ 21 | boolean isValid(Hash transactionHash) throws Exception; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/Walker.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.model.HashId; 5 | import com.iota.iri.utils.collections.interfaces.UnIterableMap; 6 | 7 | /** 8 | * Walks the tangle from an entry point towards tips 9 | * 10 | */ 11 | 12 | public interface Walker { 13 | 14 | /** 15 | * Walk algorithm 16 | *

17 | * Starts from given entry point to select valid transactions to be used 18 | * as tips. It will output a valid transaction as a tip. 19 | *

20 | * 21 | * @param entryPoint Transaction hash to start walk from. 22 | * @param ratings Map of ratings for each transaction that references entryPoint. 23 | * @param walkValidator Used to validate consistency of tails. 24 | * @return Transaction hash of tip. 25 | * @throws Exception If DB fails to retrieve transactions 26 | */ 27 | Hash walk(Hash entryPoint, UnIterableMap ratings, WalkValidator walkValidator) throws Exception; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorGenesisImpl.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection.impl; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.service.tipselection.EntryPointSelector; 5 | 6 | import org.apache.commons.lang3.NotImplementedException; 7 | 8 | /** 9 | * Implementation of EntryPointSelector that always returns the Genesis transaction: 10 | * {@link Hash#NULL_HASH} 11 | * Used to as a starting point for the random walk. 12 | */ 13 | public class EntryPointSelectorGenesisImpl implements EntryPointSelector { 14 | 15 | public EntryPointSelectorGenesisImpl() { 16 | } 17 | 18 | @Override 19 | public Hash getEntryPoint(int depth) { 20 | throw new NotImplementedException("Not supported"); 21 | } 22 | 23 | @Override 24 | public Hash getEntryPoint() { 25 | return Hash.NULL_HASH; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/impl/RatingOne.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection.impl; 2 | 3 | import com.iota.iri.controllers.ApproveeViewModel; 4 | import com.iota.iri.model.Hash; 5 | import com.iota.iri.model.HashId; 6 | import com.iota.iri.service.tipselection.RatingCalculator; 7 | import com.iota.iri.storage.Tangle; 8 | import com.iota.iri.utils.collections.impl.TransformingMap; 9 | import com.iota.iri.utils.collections.interfaces.UnIterableMap; 10 | 11 | import java.util.*; 12 | 13 | /** 14 | * Implementation of RatingCalculator that gives a uniform rating of 1 to each transaction. 15 | * Used to create uniform random walks. 16 | */ 17 | public class RatingOne implements RatingCalculator { 18 | 19 | private final Tangle tangle; 20 | 21 | public RatingOne(Tangle tangle) { 22 | this.tangle = tangle; 23 | } 24 | 25 | public UnIterableMap calculate(Hash entryPoint) throws Exception { 26 | UnIterableMap rating = new TransformingMap<>(null, null); 27 | 28 | Queue queue = new LinkedList<>(); 29 | queue.add(entryPoint); 30 | rating.put(entryPoint, 1); 31 | 32 | Hash hash; 33 | 34 | //traverse all transactions that reference entryPoint 35 | while ((hash = queue.poll()) != null) { 36 | Set approvers = ApproveeViewModel.load(tangle, hash).getHashes(); 37 | for (Hash tx : approvers) { 38 | if (!rating.containsKey(tx)) { 39 | //add to rating w/ value "1" 40 | rating.put(tx, 1); 41 | queue.add(tx); 42 | } 43 | } 44 | } 45 | return rating; 46 | } 47 | 48 | @Override 49 | public int calculateSingle(Hash transaction) throws Exception { 50 | return 1; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/impl/ReferenceCheckerImpl.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection.impl; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashSet; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.Objects; 8 | import java.util.Queue; 9 | 10 | import com.iota.iri.controllers.TransactionViewModel; 11 | import com.iota.iri.model.Hash; 12 | import com.iota.iri.service.tipselection.ReferenceChecker; 13 | import com.iota.iri.storage.Tangle; 14 | 15 | import org.apache.commons.collections4.CollectionUtils; 16 | 17 | public class ReferenceCheckerImpl implements ReferenceChecker { 18 | private Tangle tangle; 19 | 20 | public ReferenceCheckerImpl(Tangle tangle) { 21 | this.tangle = tangle; 22 | } 23 | 24 | @Override 25 | public boolean doesReference(Hash referencer, Hash target) throws Exception { 26 | if (!TransactionViewModel.exists(tangle, referencer) || 27 | !TransactionViewModel.exists(tangle, target)) { 28 | throw new IllegalStateException("Transactions not found"); 29 | } 30 | 31 | HashSet visitedHashes = new HashSet<>(); 32 | Queue queue = new LinkedList<>(); 33 | 34 | // Run BFS scan to look for approvee 35 | queue.add(referencer); 36 | visitedHashes.add(referencer); 37 | 38 | while (CollectionUtils.isNotEmpty(queue)) { 39 | Hash currentHash = queue.remove(); 40 | 41 | if (Objects.equals(currentHash, target)) { 42 | return true; 43 | } 44 | 45 | TransactionViewModel current = TransactionViewModel.fromHash(tangle, currentHash); 46 | List approveeHashes = Arrays.asList( 47 | current.getTrunkTransactionHash(), 48 | current.getBranchTransactionHash()); 49 | 50 | for (Hash approveeHash : approveeHashes) { 51 | if(approveeHash != null && !visitedHashes.contains(approveeHash)) { 52 | queue.add(approveeHash); 53 | visitedHashes.add(approveeHash); 54 | } 55 | } 56 | } 57 | 58 | return false; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/impl/TailFinderImpl.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection.impl; 2 | 3 | import com.iota.iri.controllers.TransactionViewModel; 4 | import com.iota.iri.model.Hash; 5 | import com.iota.iri.service.tipselection.TailFinder; 6 | import com.iota.iri.storage.Tangle; 7 | 8 | import java.util.Optional; 9 | import java.util.Set; 10 | 11 | /** 12 | * Implementation of TailFinder that given a transaction hash finds the tail of the associated bundle. 13 | * 14 | */ 15 | public class TailFinderImpl implements TailFinder { 16 | 17 | private final Tangle tangle; 18 | 19 | public TailFinderImpl(Tangle tangle) { 20 | this.tangle = tangle; 21 | } 22 | 23 | @Override 24 | public Optional findTail(Hash hash) throws Exception { 25 | TransactionViewModel tx = TransactionViewModel.fromHash(tangle, hash); 26 | final Hash bundleHash = tx.getBundleHash(); 27 | long index = tx.getCurrentIndex(); 28 | while (index-- > 0 && bundleHash.equals(tx.getBundleHash())) { 29 | Set approvees = tx.getApprovers(tangle).getHashes(); 30 | boolean foundApprovee = false; 31 | for (Hash approvee : approvees) { 32 | TransactionViewModel nextTx = TransactionViewModel.fromHash(tangle, approvee); 33 | if (nextTx.getCurrentIndex() == index && bundleHash.equals(nextTx.getBundleHash())) { 34 | tx = nextTx; 35 | foundApprovee = true; 36 | break; 37 | } 38 | } 39 | if (!foundApprovee) { 40 | break; 41 | } 42 | } 43 | if (tx.getCurrentIndex() == 0) { 44 | return Optional.of(tx.getHash()); 45 | } 46 | return Optional.empty(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection.impl; 2 | 3 | import com.iota.iri.LedgerValidator; 4 | import com.iota.iri.conf.TipSelConfig; 5 | import com.iota.iri.controllers.TransactionViewModel; 6 | import com.iota.iri.model.Hash; 7 | import com.iota.iri.service.tipselection.WalkValidator; 8 | import com.iota.iri.storage.Tangle; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.util.*; 13 | 14 | /** 15 | * Implementation of WalkValidator that checks consistency of the ledger as part of validity checks. 16 | * 17 | * A transaction is only valid if: 18 | *
    19 | *
  1. it is a tail 20 | *
  2. all the history of the transaction is present (is solid) 21 | *
  3. the ledger is still consistent if the transaction is added 22 | * (balances of all addresses are correct and all signatures are valid) 23 | *
24 | */ 25 | public class WalkValidatorImpl implements WalkValidator { 26 | 27 | private final Tangle tangle; 28 | private final Logger log = LoggerFactory.getLogger(WalkValidator.class); 29 | private final LedgerValidator ledgerValidator; 30 | 31 | private Map myDiff; 32 | private Set myApprovedHashes; 33 | 34 | public WalkValidatorImpl(Tangle tangle, LedgerValidator ledgerValidator) { 35 | this.tangle = tangle; 36 | this.ledgerValidator = ledgerValidator; 37 | 38 | myDiff = new HashMap<>(); 39 | myApprovedHashes = new HashSet<>(); 40 | } 41 | 42 | @Override 43 | public boolean isValid(Hash transactionHash) throws Exception { 44 | 45 | if (Hash.NULL_HASH.equals(transactionHash)) { 46 | return true; //Genesis 47 | } 48 | 49 | TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(tangle, transactionHash); 50 | if (transactionViewModel.getType() == TransactionViewModel.PREFILLED_SLOT) { 51 | log.debug("Validation failed: {} is missing in db", transactionHash); 52 | return false; 53 | } else if (transactionViewModel.getCurrentIndex() != 0) { 54 | log.debug("Validation failed: {} not a tail", transactionHash); 55 | return false; 56 | } else if (!transactionViewModel.isSolid()) { 57 | log.debug("Validation failed: {} is not solid", transactionHash); 58 | return false; 59 | } else if (!ledgerValidator.updateDiff(myApprovedHashes, myDiff, transactionViewModel.getHash())) { 60 | log.debug("Validation failed: {} is not consistent", transactionHash); 61 | return false; 62 | } 63 | return true; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/storage/Indexable.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.storage; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by paul on 5/6/17. 7 | */ 8 | public interface Indexable extends Comparable, Serializable { 9 | byte[] bytes(); 10 | void read(byte[] bytes); 11 | Indexable incremented(); 12 | Indexable decremented(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/storage/Persistable.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.storage; 2 | 3 | import java.io.Serializable; 4 | 5 | public interface Persistable extends Serializable { 6 | byte[] bytes(); 7 | void read(byte[] bytes); 8 | byte[] metadata(); 9 | void readMetadata(byte[] bytes); 10 | boolean merge(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/storage/PersistenceProvider.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.storage; 2 | 3 | import com.iota.iri.utils.Pair; 4 | 5 | import java.util.Collection; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | /** 10 | * Created by paul on 3/2/17 for iri. 11 | */ 12 | public interface PersistenceProvider { 13 | 14 | void init() throws Exception; 15 | boolean isAvailable(); 16 | void shutdown(); 17 | boolean save(Persistable model, Indexable index) throws Exception; 18 | void delete(Class model, Indexable index) throws Exception; 19 | 20 | boolean update(Persistable model, Indexable index, String item) throws Exception; 21 | 22 | boolean exists(Class model, Indexable key) throws Exception; 23 | 24 | Pair latest(Class model, Class indexModel) throws Exception; 25 | 26 | Set keysWithMissingReferences(Class modelClass, Class otherClass) throws Exception; 27 | 28 | Persistable get(Class model, Indexable index) throws Exception; 29 | 30 | boolean mayExist(Class model, Indexable index) throws Exception; 31 | 32 | long count(Class model) throws Exception; 33 | 34 | Set keysStartingWith(Class modelClass, byte[] value); 35 | 36 | Persistable seek(Class model, byte[] key) throws Exception; 37 | 38 | Pair next(Class model, Indexable index) throws Exception; 39 | Pair previous(Class model, Indexable index) throws Exception; 40 | 41 | Pair first(Class model, Class indexModel) throws Exception; 42 | 43 | boolean saveBatch(List> models) throws Exception; 44 | 45 | /** 46 | * Atomically delete all {@code models}. 47 | * @param models key value pairs that to be expunged from the db 48 | * @throws Exception 49 | */ 50 | void deleteBatch(Collection>> models) throws Exception; 51 | 52 | void clear(Class column) throws Exception; 53 | void clearMetadata(Class column) throws Exception; 54 | void clearAll() throws Exception; 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/IotaIOUtils.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils; 2 | 3 | 4 | import org.apache.commons.io.IOUtils; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class IotaIOUtils extends IOUtils { 9 | 10 | private static final Logger log = LoggerFactory.getLogger(IotaIOUtils.class); 11 | 12 | public static void closeQuietly(AutoCloseable... autoCloseables) { 13 | for (AutoCloseable it : autoCloseables) { 14 | try { 15 | if (it != null) { 16 | it.close(); 17 | } 18 | } catch (Exception ignored) { 19 | log.debug("Silent exception occured", ignored); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/IotaUtils.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import com.iota.iri.model.Hash; 6 | 7 | import java.lang.reflect.Method; 8 | import java.nio.ByteBuffer; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.Collections; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | import java.util.stream.Stream; 15 | 16 | public class IotaUtils { 17 | 18 | public static List splitStringToImmutableList(String string, String regexSplit) { 19 | return Arrays.stream(string.split(regexSplit)) 20 | .filter(StringUtils::isNoneBlank) 21 | .collect(Collectors 22 | .collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); 23 | } 24 | 25 | /** 26 | * Used to create low-memory index keys. 27 | * 28 | * @param hash the hash we create the key from 29 | * @param length the length of the desired subhash 30 | * @return a {@link ByteBuffer} that holds a subarray of {@link Hash#bytes()} 31 | * that has the specified {@code length} 32 | */ 33 | public static ByteBuffer getSubHash(Hash hash, int length) { 34 | if (hash == null) { 35 | return null; 36 | } 37 | 38 | return ByteBuffer.wrap(Arrays.copyOf(hash.bytes(), length)); 39 | } 40 | 41 | /** 42 | * @param clazz Class to inspect 43 | * @return All the declared and inherited setter method of {@code clazz} 44 | */ 45 | public static List getAllSetters(Class clazz) { 46 | List setters = new ArrayList<>(); 47 | while (clazz != Object.class) { 48 | setters.addAll(Stream.of(clazz.getDeclaredMethods()) 49 | .filter(method -> method.getName().startsWith("set")) 50 | .collect(Collectors.toList())); 51 | clazz = clazz.getSuperclass(); 52 | } 53 | return Collections.unmodifiableList(setters); 54 | } 55 | 56 | public static List createImmutableList(T... values) { 57 | return Collections.unmodifiableList(Arrays.asList(values)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/Pair.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils; 2 | 3 | public class Pair { 4 | public final S low; 5 | public final T hi; 6 | 7 | public Pair(S k, T v) { 8 | low = k; 9 | hi = v; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/SafeUtils.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils; 2 | 3 | import java.util.Collection; 4 | 5 | 6 | /** 7 | * Null safe utils 8 | */ 9 | public class SafeUtils { 10 | 11 | public static boolean isContaining(Collection collection, T element) { 12 | return collection != null && element != null && collection.contains(element); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/Serializer.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils; 2 | 3 | /** 4 | * Created by paul on 3/13/17 for iri-testnet. 5 | */ 6 | public class Serializer { 7 | public static byte[] serialize(long value) { 8 | byte[] result = new byte[Long.BYTES]; 9 | for (int i = Long.BYTES - 1; i >= 0; i--) { 10 | result[i] = (byte)(value & 0xFF); 11 | value >>= 8; 12 | } 13 | return result; 14 | } 15 | 16 | public static byte[] serialize(int integer) { 17 | byte[] result = new byte[Integer.BYTES]; 18 | for (int i = Integer.BYTES - 1; i >= 0; i--) { 19 | result[i] = (byte)(integer & 0xFF); 20 | integer >>= 8; 21 | } 22 | return result; 23 | } 24 | 25 | public static long getLong(byte[] bytes) { 26 | return getLong(bytes, 0); 27 | } 28 | public static long getLong(byte[] bytes, int start) { 29 | if(bytes == null) { 30 | return 0; 31 | } 32 | int length = Long.BYTES; 33 | long res = 0; 34 | for (int i=0; i< length;i++) { 35 | res |= (bytes[start + i] & 0xFFL) << ((length-i-1) * 8); 36 | } 37 | return res; 38 | } 39 | 40 | public static int getInteger(byte[] bytes) { 41 | return getInteger(bytes, 0); 42 | } 43 | public static int getInteger(byte[] bytes, int start) { 44 | if(bytes == null) { 45 | return 0; 46 | } 47 | int length = Integer.BYTES; 48 | int res = 0; 49 | for (int i=0; i< length;i++) { 50 | res |= (bytes[start + i] & 0xFFL) << ((length-i-1) * 8); 51 | } 52 | return res; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/SlackBotFeed.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.net.HttpURLConnection; 7 | import java.net.URL; 8 | import java.net.URLEncoder; 9 | 10 | import javax.net.ssl.HttpsURLConnection; 11 | 12 | public class SlackBotFeed { 13 | 14 | public static void reportToSlack(final String message) { 15 | 16 | try { 17 | 18 | final String request = "token=" 19 | + URLEncoder.encode("", "UTF-8") + "&channel=" 20 | + URLEncoder.encode("#botbox", "UTF-8") + "&text=" + URLEncoder.encode(message, "UTF-8") + "&as_user=true"; 21 | 22 | final HttpURLConnection connection = (HttpsURLConnection) (new URL("https://slack.com/api/chat.postMessage")).openConnection(); 23 | ((HttpsURLConnection)connection).setHostnameVerifier((hostname, session) -> true); 24 | connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 25 | connection.setRequestMethod("POST"); 26 | connection.setDoOutput(true); 27 | OutputStream out = connection.getOutputStream(); 28 | out.write(request.getBytes("UTF-8")); 29 | out.close(); 30 | ByteArrayOutputStream result = new ByteArrayOutputStream(); 31 | InputStream inputStream = connection.getInputStream(); 32 | byte[] buffer = new byte[1024]; 33 | int length; 34 | while ((length = inputStream.read(buffer)) != -1) { 35 | result.write(buffer, 0, length); 36 | } 37 | 38 | } catch (final Exception e) { 39 | 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/collections/impl/BoundedHashSet.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.collections.impl; 2 | 3 | import com.iota.iri.utils.collections.interfaces.BoundedSet; 4 | 5 | import java.util.Collection; 6 | import java.util.HashSet; 7 | import java.util.stream.Collectors; 8 | 9 | 10 | /** 11 | * A set that doesn't allow to add elements to it once it is full 12 | * 13 | * @param the type parameter 14 | */ 15 | public class BoundedHashSet extends HashSet implements BoundedSet{ 16 | final private int maxSize; 17 | 18 | /** 19 | * Instantiates a new Bounded hash set. 20 | * 21 | * @param initialCapacity the initial capacity 22 | * @param loadFactor the load factor of the hashmap 23 | * @param maxSize the max size 24 | */ 25 | public BoundedHashSet(int initialCapacity, float loadFactor, int maxSize) { 26 | super(initialCapacity, loadFactor); 27 | this.maxSize = maxSize; 28 | } 29 | 30 | /** 31 | * Instantiates a new Bounded hash set. 32 | * 33 | * @param initialCapacity the initial capacity 34 | * @param maxSize the max size 35 | */ 36 | public BoundedHashSet(int initialCapacity, int maxSize) { 37 | super(initialCapacity); 38 | this.maxSize = maxSize; 39 | } 40 | 41 | /** 42 | * Instantiates a new Bounded hash set. 43 | * 44 | * @param maxSize the max size 45 | */ 46 | public BoundedHashSet(int maxSize) { 47 | super(); 48 | this.maxSize = maxSize; 49 | } 50 | 51 | /** 52 | * Instantiates a new Bounded hash set. 53 | * 54 | * @param c the collection from which you create the set from 55 | * @param maxSize the max size 56 | * @throws NullPointerException if the specified collection is null 57 | */ 58 | public BoundedHashSet(Collection c, int maxSize) { 59 | this(maxSize); 60 | c = c.stream() 61 | .limit(maxSize) 62 | .collect(Collectors.toSet()); 63 | this.addAll(c); 64 | } 65 | 66 | @Override 67 | public int getMaxSize() { 68 | return maxSize; 69 | } 70 | 71 | @Override 72 | public boolean add(E e) { 73 | if (isFull()) { 74 | return false; 75 | } 76 | 77 | return super.add(e); 78 | } 79 | 80 | @Override 81 | public boolean addAll(Collection c) { 82 | if (isFull()) { 83 | return false; 84 | } 85 | 86 | if (!canCollectionBeFullyAdded(c)) { 87 | int remainingSize = getMaxSize() - this.size(); 88 | c = c.stream() 89 | .limit(remainingSize) 90 | .collect(Collectors.toSet()); 91 | } 92 | return super.addAll(c); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/collections/impl/TransformingBoundedHashSet.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.collections.impl; 2 | 3 | import java.util.Collection; 4 | import java.util.function.UnaryOperator; 5 | import java.util.stream.Collectors; 6 | 7 | 8 | public class TransformingBoundedHashSet extends BoundedHashSet{ 9 | 10 | private final UnaryOperator transformer; 11 | 12 | public TransformingBoundedHashSet(int maxSize, UnaryOperator transformer) { 13 | super(maxSize); 14 | this.transformer = transformer; 15 | } 16 | 17 | public TransformingBoundedHashSet(Collection c, int maxSize, UnaryOperator transformer) { 18 | super(maxSize); 19 | this.transformer = transformer; 20 | this.addAll(c); 21 | } 22 | 23 | @Override 24 | public boolean add(E e) { 25 | if (isFull()) { 26 | return false; 27 | } 28 | 29 | E el = transformer.apply(e); 30 | return super.add(el); 31 | } 32 | 33 | @Override 34 | public boolean addAll(Collection c) { 35 | Collection col = c; 36 | if (!isFull()) { 37 | col = c.stream() 38 | .map(el -> transformer.apply(el)) 39 | .collect(Collectors.toSet()); 40 | } 41 | return super.addAll(col); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/collections/impl/TransformingMap.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.collections.impl; 2 | 3 | import com.iota.iri.utils.collections.interfaces.UnIterableMap; 4 | 5 | import java.util.Collection; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.function.UnaryOperator; 9 | 10 | /** 11 | * A map that performs unary operations on key-value pairs that are inserted into it. 12 | * 13 | * @param key type 14 | * @param value type 15 | */ 16 | public class TransformingMap implements UnIterableMap { 17 | private Map delegateMap; 18 | private UnaryOperator keyOptimizer; 19 | private UnaryOperator valueTransformer; 20 | 21 | public TransformingMap(UnaryOperator keyOptimizer, UnaryOperator valueTransformer) { 22 | this(16, keyOptimizer, valueTransformer); 23 | } 24 | 25 | public TransformingMap(int initialCapacity, UnaryOperator keyOptimizer, UnaryOperator valueTransformer) { 26 | this.keyOptimizer = keyOptimizer == null ? UnaryOperator.identity() : keyOptimizer; 27 | this.valueTransformer = valueTransformer == null ? UnaryOperator.identity() : valueTransformer; 28 | 29 | this.delegateMap = new HashMap<>(initialCapacity); 30 | } 31 | 32 | @Override 33 | public int size() { 34 | return delegateMap.size(); 35 | } 36 | 37 | @Override 38 | public boolean isEmpty() { 39 | return delegateMap.isEmpty(); 40 | } 41 | 42 | @Override 43 | public boolean containsKey(K key) { 44 | K newKey = keyOptimizer.apply(key); 45 | return delegateMap.containsKey(newKey); 46 | } 47 | 48 | @Override 49 | public boolean containsValue(V value) { 50 | return delegateMap.containsValue(value); 51 | } 52 | 53 | @Override 54 | public V get(K key) { 55 | K newKey = keyOptimizer.apply(key); 56 | return delegateMap.get(newKey); 57 | } 58 | 59 | @Override 60 | public V put(K key, V value) { 61 | key = keyOptimizer.apply(key); 62 | value = valueTransformer.apply(value); 63 | return delegateMap.put(key, value); 64 | } 65 | 66 | @Override 67 | public V remove(K key) { 68 | return delegateMap.remove(key); 69 | } 70 | 71 | @Override 72 | public void clear() { 73 | delegateMap.clear(); 74 | } 75 | 76 | @Override 77 | public Collection values() { 78 | return delegateMap.values(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/collections/interfaces/BoundedCollection.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.collections.interfaces; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * A collection that can't hold more than {@link #getMaxSize()} elements 7 | * 8 | * @author galrogo on 08/02/18 9 | **/ 10 | public interface BoundedCollection extends Collection { 11 | 12 | /** 13 | * 14 | * @return the maximal number of elements that the collection cha hold 15 | */ 16 | int getMaxSize(); 17 | 18 | /** 19 | * @return true if no more elements can be added 20 | */ 21 | default boolean isFull() { 22 | return getMaxSize() <= this.size(); 23 | } 24 | 25 | /** 26 | * 27 | * @param c collection to be added 28 | * @return true only if all the elements in {@code c} can be added to this collection 29 | * else return false 30 | */ 31 | default boolean canCollectionBeFullyAdded(Collection c) { 32 | if (isFull()) { 33 | return false; 34 | } 35 | 36 | int remainingSize = getMaxSize() - this.size(); 37 | return (c.size() <= remainingSize); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/collections/interfaces/BoundedSet.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.collections.interfaces; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * A set that can't hold more than {@link #getMaxSize()} elements 7 | * 8 | * @author galrogo on 08/02/18 9 | **/ 10 | public interface BoundedSet extends BoundedCollection, Set{ 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/collections/interfaces/UnIterableMap.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.collections.interfaces; 2 | 3 | import java.util.Collection; 4 | import java.util.Map; 5 | 6 | 7 | /** 8 | * Similar to {@link Map} but hides key retrieval functionality. 9 | * Thus one can't iterate over key or entries. 10 | * Implementing class may transform keys to perform memory operations 11 | * 12 | * @param The key type 13 | * @param The value type 14 | */ 15 | public interface UnIterableMap { 16 | 17 | 18 | /** 19 | * {See {@link Map#size()}} 20 | */ 21 | int size(); 22 | 23 | /** 24 | * {See {@link Map#isEmpty()}} 25 | */ 26 | boolean isEmpty(); 27 | 28 | /** 29 | * {See {@link Map#containsKey(Object)}} 30 | */ 31 | boolean containsKey(K key); 32 | 33 | /** 34 | * {See {@link Map#containsValue(Object)}} 35 | */ 36 | boolean containsValue(V value); 37 | 38 | /** 39 | * 40 | * {See {@link Map#get}} 41 | */ 42 | V get(K key); 43 | 44 | /** 45 | * {See {@link Map#put} 46 | */ 47 | V put(K key, V value); 48 | 49 | /** 50 | * {See {@link Map#keySet()}} 51 | */ 52 | V remove(K key); 53 | 54 | /** 55 | * {See {@link Map#clear()}} 56 | */ 57 | void clear(); 58 | 59 | /** 60 | * {See {@link Map#values} 61 | */ 62 | Collection values(); 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/dag/RecentTransactionsGetter.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.dag; 2 | 3 | import java.util.Collection; 4 | 5 | import com.iota.iri.model.Hash; 6 | 7 | /** 8 | * Get N most recent transactions 9 | */ 10 | public interface RecentTransactionsGetter { 11 | Collection getRecentTransactions(int count) throws Exception; 12 | } -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/dag/TraversalException.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.dag; 2 | 3 | /** 4 | * This class is used to wrap exceptions that are specific to traversing the graph. 5 | * 6 | * It allows us to distinct between the different kinds of errors that can happen during the execution of the code. 7 | */ 8 | public class TraversalException extends Exception { 9 | /** 10 | * Constructor of the exception which allows us to provide a specific error message and the cause of the error. 11 | * 12 | * @param message reason why this error occured 13 | * @param cause wrapped exception that caused this error 14 | */ 15 | public TraversalException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | 19 | /** 20 | * Constructor of the exception which allows us to provide a specific error message without having an underlying 21 | * cause. 22 | * 23 | * @param message reason why this error occured 24 | */ 25 | public TraversalException(String message) { 26 | super(message); 27 | } 28 | 29 | /** 30 | * Constructor of the exception which allows us to wrap the underlying cause of the error without providing a 31 | * specific reason. 32 | * 33 | * @param cause wrapped exception that caused this error 34 | */ 35 | public TraversalException(Throwable cause) { 36 | super(cause); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/log/Logger.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.log; 2 | 3 | /** 4 | * Represents a wrapper for the logback Logger, which allows us to add aditional features to the logging capabilities of 5 | * IRI. 6 | */ 7 | public interface Logger { 8 | /** 9 | * This method allows us to set a new info message that shall get printed to the screen. 10 | * 11 | * @param message info message that shall get printed 12 | * @return the logger itself to allow the chaining of calls 13 | */ 14 | Logger info(String message); 15 | 16 | /** 17 | * This method allows us to set a new debug message that shall get printed to the screen. 18 | * 19 | * @param message debug message that shall get printed 20 | * @return the logger itself to allow the chaining of calls 21 | */ 22 | Logger debug(String message); 23 | 24 | /** 25 | * This method allows us to set a new error message that shall get printed to the screen. 26 | * 27 | * @param message debug message that shall get printed 28 | * @return the logger itself to allow the chaining of calls 29 | */ 30 | Logger error(String message); 31 | 32 | /** 33 | * This method allows us to set a new error message that shall get printed to the screen. 34 | * 35 | * @param message debug message that shall get printed 36 | * @param cause exception object that caused the error to happen (will be printed with the complete stacktrace) 37 | */ 38 | Logger error(String message, Throwable cause); 39 | 40 | /** 41 | * This method is the getter for the enabled flag of the logger. 42 | * 43 | * If the logger is disabled it will simply omit showing log messages. 44 | * 45 | * @return true if the logger shall output messages and false otherwise (the logger is enabled by default) 46 | */ 47 | boolean getEnabled(); 48 | 49 | /** 50 | * This method is the setter for the enabled flag of the logger. 51 | * 52 | * If the logger is disabled it will simply omit showing log messages. 53 | * 54 | * @param enabled true if the logger shall output messages and false otherwise (the logger is enabled by default) 55 | * @return the logger itself to allow the chaining of calls 56 | */ 57 | Logger setEnabled(boolean enabled); 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/thread/ReportingExecutorService.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.thread; 2 | 3 | /** 4 | * This interface defines a contract for {@link java.util.concurrent.ExecutorService}s that makes them call a 5 | * "reporting" method whenever an important event occurs.
6 | *
7 | * This way a child class extending these kind of {@link java.util.concurrent.ExecutorService}s can "hook" into these 8 | * events by overriding the specific method and add additional logic like logging or debugging capabilities.
9 | */ 10 | public interface ReportingExecutorService { 11 | /** 12 | * This method gets called whenever a new task is scheduled to run.
13 | *
14 | * In contrast to {@link #onStartTask(TaskDetails)} this method gets called only once for "recurring" tasks that are 15 | * scheduled to run in pre-defined intervals.
16 | * 17 | * @param taskDetails object containing details about this task 18 | */ 19 | void onScheduleTask(TaskDetails taskDetails); 20 | 21 | /** 22 | * This method gets called whenever a task is started.
23 | *
24 | * For recurring tasks it is called multiple times.
25 | * 26 | * @param taskDetails object containing details about this task 27 | */ 28 | void onStartTask(TaskDetails taskDetails); 29 | 30 | /** 31 | * This method gets called whenever a task is finished.
32 | *
33 | * For recurring tasks it is called multiple times.
34 | * 35 | * @param taskDetails object containing details about this task 36 | * @param error {@link Exception} that caused the task to complete 37 | */ 38 | void onFinishTask(TaskDetails taskDetails, Throwable error); 39 | 40 | /** 41 | * This method gets called whenever a task is cancelled through its {@link java.util.concurrent.Future} or through 42 | * the shutdown methods of the {@link java.util.concurrent.ExecutorService}.
43 | *
44 | * It only gets called once for every task.
45 | * 46 | * @param taskDetails object containing details about this task 47 | */ 48 | void onCancelTask(TaskDetails taskDetails); 49 | 50 | /** 51 | * This method gets called whenever a task completes.
52 | *
53 | * This can be through either raising an exception, cancelling from the outside or by simply terminating in a normal 54 | * manner. For recurring tasks this only gets called once.
55 | * 56 | * @param taskDetails object containing details about this task 57 | * @param error {@link Exception} that caused the task to complete 58 | */ 59 | void onCompleteTask(TaskDetails taskDetails, Throwable error); 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/utils/thread/ThreadIdentifier.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.thread; 2 | 3 | /** 4 | * The instances of this class are used by the {@link ThreadUtils} to map the {@link Thread}s and make the corresponding 5 | * spawn and stop methods thread safe. 6 | */ 7 | public class ThreadIdentifier { 8 | /** 9 | * Holds the name of the {@link Thread}. 10 | */ 11 | private final String name; 12 | 13 | /** 14 | * The constructor simply stores the passed in name in the private property of this instance. 15 | * 16 | * While the name is not required to identify the {@link Thread}, we still require to give one to be able to create 17 | * meaningful log messages. 18 | * 19 | * @param name name of the {@link Thread} that get referenced by this identifier. 20 | */ 21 | public ThreadIdentifier(String name) { 22 | this.name = name; 23 | } 24 | 25 | /** 26 | * Getter of the name that was used to create this identifier. 27 | * 28 | * It simply returns the internal property. 29 | * 30 | * @return name of the {@link Thread} that this identifier references 31 | */ 32 | public String getName() { 33 | return name; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/iota/iri/zmq/README.md: -------------------------------------------------------------------------------- 1 | ## IRI MessageQ 2 | 3 | MessageQ is a small wrapper for ZeroMQ inside IRI to allow streaming 4 | of topics from within a running full node. The goal of this is to allow 5 | for targeted event streams from subscribing clients to the node process. 6 | 7 | A client may want to be notified of a change in status of a transaction, 8 | or may want to see incoming transactions, or any number of data points. 9 | These can be filtered by topic, and the aim is for machine-readability 10 | over human readability. 11 | 12 | For instance, a light wallet connected to a remote node may want to know 13 | when a transaction is confirmed. It would, perhaps, after querying the API, 14 | subscribe to a topic which publishes on the update of a state. 15 | 16 | #### Topics 17 | 18 | A client interested in tip selection metrics may subscribe to `mctn`, short for 19 | "monte carlo transaction number", a metric that indicates how many transactions 20 | were traversed in a random walk simulation. It may subscribe to `rts`, for 21 | "reason to stop", to see information about walk terminations. 22 | 23 | Topics currently found in the latest code are 24 | * `mctn` transactions traversed during random walk 25 | * `rts` information about walk terminations 26 | * `dnscv` neighbor DNS validations 27 | * `dnscc` neighbor DNS confirmations 28 | * `dnscu` neighbor DNS updates 29 | * `hmr` for the hit to miss ratio 30 | * `antn` for added non-tethered neighbors ( testnet only ) 31 | * `rntn` for refused non-tethered neighbors 32 | * `rstat` for information about the tips requester 33 | * `rtl` for transactions randomly removed from the request list 34 | * `lmi` for the latest milestone index 35 | * `lmsi` for the latest solid milestone index 36 | * `lmhs` for the latest solid milestone hash 37 | * `sn` for newly confirmed transactions ( by solid milestone children measurement ) 38 | * `tx` for newly seen transactions 39 | * `tx_trytes` trytes of newly seen transactions 40 | * `ct5m2h` confirmed transactions older than 5m and younger than 2h 41 | * `t5m2h` total transactions older than 5m and younger than 2h 42 | * `
` to watch activity on an address 43 | 44 | All topic must be lowercase (to not clash with `
` containing the topic title - like `TXCR9...` & `TX`) 45 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | System.out 6 | 7 | TRACE 8 | ACCEPT 9 | NEUTRAL 10 | 11 | 12 | DEBUG 13 | ACCEPT 14 | NEUTRAL 15 | 16 | 17 | INFO 18 | ACCEPT 19 | NEUTRAL 20 | 21 | 22 | WARN 23 | ACCEPT 24 | DENY 25 | 26 | 27 | %d{MM/dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 28 | 29 | 30 | 31 | 32 | 33 | System.err 34 | 35 | ERROR 36 | ACCEPT 37 | DENY 38 | 39 | 40 | %d{MM/dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/IXITest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri; 2 | 3 | import com.iota.iri.service.dto.AbstractResponse; 4 | import com.iota.iri.service.dto.IXIResponse; 5 | import org.junit.AfterClass; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | import org.junit.rules.TemporaryFolder; 9 | 10 | public class IXITest { 11 | static TemporaryFolder ixiDir = new TemporaryFolder(); 12 | static IXI ixi; 13 | 14 | @BeforeClass 15 | public static void setUp() throws Exception { 16 | ixiDir.create(); 17 | ixi = new IXI(); 18 | ixi.init(ixiDir.getRoot().getAbsolutePath().toString()); 19 | } 20 | 21 | @AfterClass 22 | public static void tearDown() throws Exception { 23 | ixi.shutdown(); 24 | ixiDir.delete(); 25 | } 26 | 27 | @Test 28 | public void init() throws Exception { 29 | AbstractResponse response; 30 | IXIResponse ixiResponse; 31 | 32 | /* 33 | final String testJs = 34 | "var Callable = Java.type(\"com.iota.iri.service.CallableRequest\");\n" + 35 | "print(\"hello world\");\n" + 36 | "var IXIResponse = Java.type(\"com.iota.iri.service.dto.IXIResponse\");\n" + 37 | "API.put(\"getParser\", new Callable({\n" + 38 | "call: function(req) {\n" + 39 | "var IntArray = Java.type(\"int[]\");\n" + 40 | "var out = new IntArray(Math.floor(Math.random()*9)+1);\n" + 41 | "out[0] = 2;\n" + 42 | "var r = IXIResponse.create({\n" + 43 | "myArray: out,\n" + 44 | "name: \"Foo\"\n" + 45 | "});\n" + 46 | "return r;\n" + 47 | "}\n" + 48 | "}));"; 49 | final String testPackage = "{\"main\": \"index.js\"}"; 50 | 51 | 52 | ixiDir.newFolder("test"); 53 | try (OutputStream out = new BufferedOutputStream( 54 | Files.newOutputStream(Paths.get(ixiDir.getRoot().toString(),"test", "index.js"), CREATE))) { 55 | out.write(testJs.getBytes()); 56 | } 57 | try (OutputStream out = new BufferedOutputStream( 58 | Files.newOutputStream(Paths.get(ixiDir.getRoot().toString(),"test", "package.json"), CREATE))) { 59 | out.write(testPackage.getBytes()); 60 | } 61 | // Allow IXI to load the file 62 | Map request = new HashMap<>(); 63 | Thread.sleep(1000); 64 | response = IXI.instance().processCommand("test.getParser", request); 65 | 66 | assertFalse(response instanceof ErrorResponse); 67 | assertTrue(response instanceof IXIResponse); 68 | 69 | ixiResponse = ((IXIResponse) response); 70 | assertNotNull(ixiResponse.getResponse()); 71 | */ 72 | } 73 | 74 | @Test 75 | public void processCommand() throws Exception { 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/benchmarks/BenchmarkRunner.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.benchmarks; 2 | 3 | import com.iota.iri.benchmarks.dbbenchmark.RocksDbBenchmark; 4 | import org.junit.Test; 5 | import org.openjdk.jmh.annotations.Mode; 6 | import org.openjdk.jmh.runner.Runner; 7 | import org.openjdk.jmh.runner.RunnerException; 8 | import org.openjdk.jmh.runner.options.Options; 9 | import org.openjdk.jmh.runner.options.OptionsBuilder; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | 13 | public class BenchmarkRunner { 14 | 15 | @Test 16 | public void launchDbBenchmarks() throws RunnerException { 17 | Options opts = new OptionsBuilder() 18 | .include(RocksDbBenchmark.class.getName() + ".*") 19 | .mode(Mode.AverageTime) 20 | .timeUnit(TimeUnit.MILLISECONDS) 21 | .warmupIterations(5) 22 | .forks(1) 23 | .measurementIterations(10) 24 | .shouldFailOnError(true) 25 | .shouldDoGC(false) 26 | .build(); 27 | 28 | //possible to do assertions over run results 29 | new Runner(opts).run(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/benchmarks/dbbenchmark/RocksDbBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.benchmarks.dbbenchmark; 2 | 3 | import com.iota.iri.benchmarks.dbbenchmark.states.EmptyState; 4 | import com.iota.iri.benchmarks.dbbenchmark.states.FullState; 5 | import com.iota.iri.controllers.TransactionViewModel; 6 | import com.iota.iri.model.persistables.Transaction; 7 | import com.iota.iri.storage.Indexable; 8 | import com.iota.iri.storage.Persistable; 9 | import com.iota.iri.utils.Pair; 10 | import org.openjdk.jmh.annotations.Benchmark; 11 | 12 | 13 | public class RocksDbBenchmark { 14 | 15 | @Benchmark 16 | public void persistOneByOne(EmptyState state) throws Exception { 17 | for (TransactionViewModel tvm: state.getTransactions()) { 18 | tvm.store(state.getTangle()); 19 | } 20 | } 21 | 22 | @Benchmark 23 | public void deleteOneByOne(FullState state) throws Exception { 24 | for (TransactionViewModel tvm : state.getTransactions()) { 25 | tvm.delete(state.getTangle()); 26 | } 27 | } 28 | 29 | @Benchmark 30 | public void dropAll(FullState state) throws Exception { 31 | state.getTangle().clearColumn(Transaction.class); 32 | state.getTangle().clearMetadata(Transaction.class); 33 | } 34 | 35 | @Benchmark 36 | public void deleteBatch(FullState state) throws Exception { 37 | state.getTangle().deleteBatch(state.getPairs()); 38 | } 39 | 40 | @Benchmark 41 | public void fetchOneByOne(FullState state) throws Exception { 42 | for (Pair> pair : state.getPairs()) { 43 | state.getTangle().load(pair.hi, pair.low); 44 | } 45 | } 46 | 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/benchmarks/dbbenchmark/states/DbState.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.benchmarks.dbbenchmark.states; 2 | 3 | import com.iota.iri.TransactionTestUtils; 4 | import com.iota.iri.conf.BaseIotaConfig; 5 | import com.iota.iri.controllers.TransactionViewModel; 6 | import com.iota.iri.model.persistables.Transaction; 7 | import com.iota.iri.storage.PersistenceProvider; 8 | import com.iota.iri.storage.Tangle; 9 | import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider; 10 | import org.apache.commons.io.FileUtils; 11 | import org.openjdk.jmh.annotations.Param; 12 | import org.openjdk.jmh.annotations.Scope; 13 | import org.openjdk.jmh.annotations.State; 14 | 15 | import java.io.File; 16 | import java.util.ArrayList; 17 | import java.util.Collections; 18 | import java.util.List; 19 | 20 | @State(Scope.Benchmark) 21 | public abstract class DbState { 22 | private final File dbFolder = new File("db-bench"); 23 | private final File logFolder = new File("db-log-bench"); 24 | 25 | private Tangle tangle; 26 | private List transactions; 27 | 28 | @Param({"10", "100", "500", "1000", "3000"}) 29 | private int numTxsToTest; 30 | 31 | 32 | public void setup() throws Exception { 33 | System.out.println("-----------------------trial setup--------------------------------"); 34 | boolean mkdirs = dbFolder.mkdirs(); 35 | if (!mkdirs) { 36 | throw new IllegalStateException("db didn't start with a clean slate. Please delete " 37 | + dbFolder.getAbsolutePath()); 38 | } 39 | logFolder.mkdirs(); 40 | PersistenceProvider dbProvider = new RocksDBPersistenceProvider(dbFolder.getPath(), logFolder.getPath(), 41 | BaseIotaConfig.Defaults.DB_CACHE_SIZE); 42 | dbProvider.init(); 43 | tangle = new Tangle(); 44 | tangle.addPersistenceProvider(dbProvider); 45 | String trytes = ""; 46 | System.out.println("numTxsToTest = [" + numTxsToTest + "]"); 47 | transactions = new ArrayList<>(numTxsToTest); 48 | for (int i = 0; i < numTxsToTest; i++) { 49 | trytes = TransactionTestUtils.nextWord(trytes); 50 | TransactionViewModel tvm = TransactionTestUtils.createTransactionWithTrytes(trytes); 51 | transactions.add(tvm); 52 | } 53 | transactions = Collections.unmodifiableList(transactions); 54 | } 55 | 56 | public void teardown() throws Exception { 57 | System.out.println("-----------------------trial teardown--------------------------------"); 58 | tangle.shutdown(); 59 | FileUtils.forceDelete(dbFolder); 60 | FileUtils.forceDelete(logFolder); 61 | } 62 | 63 | public void clearDb() throws Exception { 64 | System.out.println("-----------------------iteration teardown--------------------------------"); 65 | tangle.clearColumn(Transaction.class); 66 | tangle.clearMetadata(Transaction.class); 67 | } 68 | 69 | public Tangle getTangle() { 70 | return tangle; 71 | } 72 | 73 | public List getTransactions() { 74 | return transactions; 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/benchmarks/dbbenchmark/states/EmptyState.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.benchmarks.dbbenchmark.states; 2 | 3 | import org.openjdk.jmh.annotations.*; 4 | 5 | @State(Scope.Benchmark) 6 | public class EmptyState extends DbState { 7 | 8 | @Override 9 | @Setup(Level.Trial) 10 | public void setup() throws Exception { 11 | super.setup(); 12 | } 13 | 14 | @Override 15 | @TearDown(Level.Trial) 16 | public void teardown() throws Exception { 17 | super.teardown(); 18 | } 19 | 20 | @Override 21 | @TearDown(Level.Iteration) 22 | public void clearDb() throws Exception { 23 | super.clearDb(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/benchmarks/dbbenchmark/states/FullState.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.benchmarks.dbbenchmark.states; 2 | 3 | import com.iota.iri.controllers.TransactionViewModel; 4 | import com.iota.iri.model.persistables.Transaction; 5 | import com.iota.iri.storage.Indexable; 6 | import com.iota.iri.storage.Persistable; 7 | import com.iota.iri.utils.Pair; 8 | import org.openjdk.jmh.annotations.*; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.stream.Collectors; 13 | 14 | @State(Scope.Benchmark) 15 | public class FullState extends DbState { 16 | 17 | private List>> pairs; 18 | 19 | @Override 20 | @Setup(Level.Trial) 21 | public void setup() throws Exception { 22 | super.setup(); 23 | pairs = getTransactions().stream() 24 | .map(tvm -> new Pair<>((Indexable) tvm.getHash(), Transaction.class)) 25 | .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); 26 | 27 | } 28 | 29 | @Override 30 | @TearDown(Level.Trial) 31 | public void teardown() throws Exception { 32 | super.teardown(); 33 | } 34 | 35 | @Override 36 | @TearDown(Level.Iteration) 37 | public void clearDb() throws Exception { 38 | super.clearDb(); 39 | } 40 | 41 | @Setup(Level.Iteration) 42 | public void populateDb() throws Exception { 43 | System.out.println("-----------------------iteration setup--------------------------------"); 44 | for (TransactionViewModel tvm : getTransactions()) { 45 | tvm.store(getTangle()); 46 | } 47 | } 48 | 49 | public List>> getPairs() { 50 | return pairs; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/controllers/BundleViewModelTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.controllers; 2 | 3 | import com.iota.iri.storage.Tangle; 4 | import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider; 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.junit.rules.TemporaryFolder; 9 | 10 | /** 11 | * Created by paul on 5/2/17. 12 | */ 13 | public class BundleViewModelTest { 14 | private static final TemporaryFolder dbFolder = new TemporaryFolder(); 15 | private static final TemporaryFolder logFolder = new TemporaryFolder(); 16 | private static Tangle tangle = new Tangle(); 17 | 18 | @Before 19 | public void setUp() throws Exception { 20 | dbFolder.create(); 21 | logFolder.create(); 22 | RocksDBPersistenceProvider rocksDBPersistenceProvider; 23 | rocksDBPersistenceProvider = new RocksDBPersistenceProvider(dbFolder.getRoot().getAbsolutePath(), 24 | logFolder.getRoot().getAbsolutePath(),1000); 25 | tangle.addPersistenceProvider(rocksDBPersistenceProvider); 26 | tangle.init(); 27 | 28 | } 29 | 30 | @After 31 | public void tearDown() throws Exception { 32 | tangle.shutdown(); 33 | dbFolder.delete(); 34 | logFolder.delete(); 35 | } 36 | 37 | @Test 38 | public void quietFromHash() throws Exception { 39 | 40 | } 41 | 42 | @Test 43 | public void fromHash() throws Exception { 44 | 45 | } 46 | 47 | @Test 48 | public void getTransactionViewModels() throws Exception { 49 | 50 | } 51 | 52 | @Test 53 | public void quietGetTail() throws Exception { 54 | 55 | } 56 | 57 | @Test 58 | public void getTail() throws Exception { 59 | 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/controllers/TagViewModelTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.controllers; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | /** 10 | * Created by paul on 5/2/17. 11 | */ 12 | public class TagViewModelTest { 13 | @Before 14 | public void setUp() throws Exception { 15 | 16 | } 17 | 18 | @After 19 | public void tearDown() throws Exception { 20 | 21 | } 22 | 23 | @Test 24 | public void getHash() throws Exception { 25 | 26 | } 27 | 28 | @Test 29 | public void getTransactionHashes() throws Exception { 30 | 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/controllers/TransactionRequesterTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.controllers; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.network.TransactionRequester; 5 | import com.iota.iri.storage.Tangle; 6 | import com.iota.iri.zmq.MessageQ; 7 | import org.junit.After; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Created by paul on 5/2/17. 15 | */ 16 | public class TransactionRequesterTest { 17 | private static Tangle tangle = new Tangle(); 18 | private MessageQ mq; 19 | 20 | @Before 21 | public void setUp() throws Exception { 22 | 23 | } 24 | 25 | @After 26 | public void tearDown() throws Exception { 27 | 28 | } 29 | 30 | @Test 31 | public void init() throws Exception { 32 | 33 | } 34 | 35 | @Test 36 | public void rescanTransactionsToRequest() throws Exception { 37 | 38 | } 39 | 40 | @Test 41 | public void getRequestedTransactions() throws Exception { 42 | 43 | } 44 | 45 | @Test 46 | public void numberOfTransactionsToRequest() throws Exception { 47 | 48 | } 49 | 50 | @Test 51 | public void clearTransactionRequest() throws Exception { 52 | 53 | } 54 | 55 | @Test 56 | public void requestTransaction() throws Exception { 57 | 58 | } 59 | 60 | @Test 61 | public void transactionToRequest() throws Exception { 62 | 63 | } 64 | 65 | @Test 66 | public void checkSolidity() throws Exception { 67 | 68 | } 69 | 70 | @Test 71 | public void instance() throws Exception { 72 | 73 | } 74 | 75 | @Test 76 | public void capacityLimited() throws Exception { 77 | TransactionRequester txReq = new TransactionRequester(tangle, mq); 78 | int capacity = TransactionRequester.MAX_TX_REQ_QUEUE_SIZE; 79 | //fill tips list 80 | for (int i = 0; i < capacity * 2 ; i++) { 81 | Hash hash = TransactionViewModelTest.getRandomTransactionHash(); 82 | txReq.requestTransaction(hash); 83 | } 84 | //check that limit wasn't breached 85 | assertEquals(capacity, txReq.numberOfTransactionsToRequest()); 86 | } 87 | 88 | @Test 89 | public void queueIsEmptyAfterCallingClearQueue() throws Exception { 90 | final int txCount = 60; 91 | TransactionRequester txReq = new TransactionRequester(tangle, mq); 92 | 93 | //fill tips list 94 | for (int i = 0; i < txCount; i++) { 95 | Hash hash = TransactionViewModelTest.getRandomTransactionHash(); 96 | txReq.requestTransaction(hash); 97 | } 98 | 99 | assertEquals(txCount, txReq.numberOfTransactionsToRequest()); 100 | 101 | txReq.clearQueue(); 102 | 103 | assertEquals(0, txReq.numberOfTransactionsToRequest()); 104 | } 105 | } -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/model/persistables/TransactionTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.model.persistables; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.Random; 6 | 7 | import com.iota.iri.controllers.TransactionViewModel; 8 | import com.iota.iri.utils.Converter; 9 | 10 | import org.junit.Test; 11 | 12 | public class TransactionTest { 13 | private static final Random seed = new Random(); 14 | 15 | @Test 16 | public void metadataParsedCorrectlyInHappyFlow() throws Exception { 17 | Transaction tx = getRandomTransaction(); 18 | 19 | Transaction fromMetaData = new Transaction(); 20 | byte[] bytes = tx.metadata(); 21 | fromMetaData.readMetadata(bytes); 22 | 23 | assertEquals(tx.address, fromMetaData.address); 24 | assertEquals(tx.bundle, fromMetaData.bundle); 25 | assertEquals(tx.trunk, fromMetaData.trunk); 26 | assertEquals(tx.branch, fromMetaData.branch); 27 | assertEquals(tx.obsoleteTag, fromMetaData.obsoleteTag); 28 | assertEquals(tx.value, fromMetaData.value); 29 | assertEquals(tx.currentIndex, fromMetaData.currentIndex); 30 | assertEquals(tx.lastIndex, fromMetaData.lastIndex); 31 | assertEquals(tx.timestamp, fromMetaData.timestamp); 32 | 33 | assertEquals(tx.tag, fromMetaData.tag); 34 | assertEquals(tx.attachmentTimestamp, fromMetaData.attachmentTimestamp); 35 | assertEquals(tx.attachmentTimestampLowerBound, fromMetaData.attachmentTimestampLowerBound); 36 | assertEquals(tx.attachmentTimestampUpperBound, fromMetaData.attachmentTimestampUpperBound); 37 | 38 | assertEquals(tx.validity, fromMetaData.validity); 39 | assertEquals(tx.type, fromMetaData.type); 40 | assertEquals(tx.arrivalTime, fromMetaData.arrivalTime); 41 | assertEquals(tx.height, fromMetaData.height); 42 | assertEquals(tx.solidificationTime, fromMetaData.solidificationTime); 43 | 44 | assertEquals(tx.solid, fromMetaData.solid); 45 | } 46 | 47 | private Transaction getRandomTransaction() { 48 | Transaction transaction = new Transaction(); 49 | 50 | byte[] trits = new byte[TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_SIZE]; 51 | for(int i = 0; i < trits.length; i++) { 52 | trits[i] = (byte) (seed.nextInt(3) - 1); 53 | } 54 | 55 | transaction.bytes = Converter.allocateBytesForTrits(trits.length); 56 | Converter.bytes(trits, 0, transaction.bytes, 0, trits.length); 57 | transaction.readMetadata(transaction.bytes); 58 | return transaction; 59 | } 60 | } -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/network/UDPNeighborTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.network; 2 | 3 | import org.junit.Test; 4 | 5 | import java.net.InetSocketAddress; 6 | import java.net.SocketAddress; 7 | 8 | import static org.junit.Assert.assertFalse; 9 | import static org.junit.Assert.assertTrue; 10 | 11 | public class UDPNeighborTest { 12 | 13 | private final UDPNeighbor neighbor = new UDPNeighbor(address("localhost", 42), null, false); 14 | 15 | @Test 16 | public void sameIpWhenMatchesThenTrue() { 17 | assertTrue("expected match", neighbor.matches(address("localhost", 42))); 18 | assertTrue("expected match", neighbor.matches(address("localhost", 666))); 19 | assertTrue("expected match", neighbor.matches(address("127.0.0.1", 42))); 20 | assertTrue("expected match", neighbor.matches(address("127.0.0.1", 666))); 21 | } 22 | 23 | @Test 24 | public void differentIpWhenMatchesThenFalse() { 25 | assertFalse("expected no match", neighbor.matches(address("foo.bar.com", 42))); 26 | assertFalse("expected no match", neighbor.matches(address("8.8.8.8", 42))); 27 | assertFalse("expected no match", neighbor.matches(null)); 28 | assertFalse("expected no match", neighbor.matches(new SocketAddress() {})); 29 | } 30 | 31 | private InetSocketAddress address(String hostOrIp, int port) { 32 | return new InetSocketAddress(hostOrIp, port); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorGenesisImplTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.service.tipselection.impl; 2 | 3 | import com.iota.iri.model.Hash; 4 | import com.iota.iri.service.tipselection.EntryPointSelector; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | public class EntryPointSelectorGenesisImplTest { 9 | 10 | @Test 11 | public void testEntryPointBWithTangleData() throws Exception { 12 | 13 | EntryPointSelector entryPointSelector = new EntryPointSelectorGenesisImpl(); 14 | Hash entryPoint = entryPointSelector.getEntryPoint(); 15 | 16 | Assert.assertEquals("The entry point should be the milestone in the Tangle", Hash.NULL_HASH, entryPoint); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/storage/TangleTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.storage; 2 | 3 | import com.iota.iri.controllers.TransactionViewModel; 4 | import com.iota.iri.crypto.SpongeFactory; 5 | import com.iota.iri.model.Hash; 6 | import com.iota.iri.model.TransactionHash; 7 | import com.iota.iri.model.persistables.Tag; 8 | import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider; 9 | import com.iota.iri.utils.Converter; 10 | import org.junit.After; 11 | import org.junit.Assert; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.junit.rules.TemporaryFolder; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | import java.util.*; 19 | 20 | public class TangleTest { 21 | private final TemporaryFolder dbFolder = new TemporaryFolder(); 22 | private final TemporaryFolder logFolder = new TemporaryFolder(); 23 | private Tangle tangle = new Tangle(); 24 | 25 | private static final Random seed = new Random(); 26 | Logger log = LoggerFactory.getLogger(Tangle.class); 27 | 28 | @Before 29 | public void setUp() throws Exception { 30 | dbFolder.create(); 31 | logFolder.create(); 32 | RocksDBPersistenceProvider rocksDBPersistenceProvider; 33 | rocksDBPersistenceProvider = new RocksDBPersistenceProvider(dbFolder.getRoot().getAbsolutePath(), 34 | logFolder.getRoot().getAbsolutePath(),1000); 35 | tangle.addPersistenceProvider(rocksDBPersistenceProvider); 36 | tangle.init(); 37 | } 38 | 39 | @After 40 | public void tearDown() throws Exception { 41 | tangle.shutdown(); 42 | } 43 | 44 | @Test 45 | public void save() throws Exception { 46 | } 47 | 48 | @Test 49 | public void getKeysStartingWithValue() throws Exception { 50 | byte[] trits = getRandomTransactionTrits(); 51 | TransactionViewModel transactionViewModel = new TransactionViewModel(trits, TransactionHash.calculate(SpongeFactory.Mode.CURLP81, trits)); 52 | transactionViewModel.store(tangle); 53 | Set tag = tangle.keysStartingWith(Tag.class, Arrays.copyOf(transactionViewModel.getTagValue().bytes(), 15)); 54 | Assert.assertNotEquals(tag.size(), 0); 55 | } 56 | 57 | @Test 58 | public void get() throws Exception { 59 | } 60 | 61 | public static byte[] getRandomTransactionTrits() { 62 | byte[] out = new byte[TransactionViewModel.TRINARY_SIZE]; 63 | 64 | for(int i = 0; i < out.length; i++) { 65 | out[i] = (byte) (seed.nextInt(3) - 1); 66 | } 67 | 68 | return out; 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/utils/BoundedHashSetTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils; 2 | 3 | import com.iota.iri.utils.collections.impl.BoundedHashSet; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | import java.util.Arrays; 8 | import java.util.HashSet; 9 | import java.util.List; 10 | 11 | public class BoundedHashSetTest { 12 | 13 | @Test 14 | public void createBoundedHashSetWithCollectionTest() { 15 | List list = Arrays.asList(1, 2 ,3, 4, 5, 6); 16 | BoundedHashSet boundedSet = new BoundedHashSet<>(list, 4); 17 | Assert.assertEquals(new HashSet<>(Arrays.asList(1, 2, 3, 4)), boundedSet); 18 | } 19 | 20 | @Test 21 | public void testAdd() { 22 | BoundedHashSet boundedSet = new BoundedHashSet<>(3); 23 | Assert.assertTrue("can't add to unfull set", boundedSet.add(1)); 24 | Assert.assertTrue("can't add to unfull set", boundedSet.add(2)); 25 | Assert.assertTrue("can't add to unfull set", boundedSet.add(3)); 26 | Assert.assertFalse("can add to full set", boundedSet.add(4)); 27 | Assert.assertEquals("bounded set doesn't have expected contents", 28 | new HashSet<>(Arrays.asList(1, 2, 3)), boundedSet); 29 | } 30 | 31 | @Test 32 | public void testAddAll() { 33 | BoundedHashSet boundedSet = new BoundedHashSet<>(3); 34 | Assert.assertTrue("set did not change after add", boundedSet.addAll(Arrays.asList(5, 6, 7, 8, 9))); 35 | Assert.assertEquals("bounded set doesn't have expected contents", 36 | new HashSet<>(Arrays.asList(5, 6, 7)), boundedSet); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/utils/ConverterTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils; 2 | 3 | public class ConverterTest { 4 | 5 | 6 | } -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/utils/TestSerializer.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | public class TestSerializer { 9 | 10 | @Test 11 | public void testSerEndian() { 12 | final long[] ltestvec = {0L, 1L, Long.MAX_VALUE, 123456789L}; 13 | final int[] itestvec = {0, 1, Integer.MAX_VALUE, 123456789}; 14 | 15 | for(long l : ltestvec) 16 | Assert.assertArrayEquals(Serializer.serialize(l), bbSerialize(l)); 17 | 18 | for(int i : itestvec) 19 | Assert.assertArrayEquals(Serializer.serialize(i), bbSerialize(i)); 20 | 21 | } 22 | 23 | // reference for original bytebuffer code 24 | public static byte[] bbSerialize(Long value) { 25 | ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); 26 | buffer.putLong(value); 27 | return buffer.array(); 28 | } 29 | public static byte[] bbSerialize(int integer) { 30 | ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES); 31 | buffer.putInt(integer); 32 | return buffer.array(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java: -------------------------------------------------------------------------------- 1 | package com.iota.iri.utils.collections.impl; 2 | 3 | import com.iota.iri.utils.collections.interfaces.BoundedSet; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | import org.mockito.internal.util.collections.Sets; 7 | 8 | import java.util.Arrays; 9 | import java.util.LinkedHashSet; 10 | import java.util.Set; 11 | 12 | public class BoundedSetWrapperTest { 13 | 14 | @Test(expected = IllegalArgumentException.class) 15 | public void createSetWithException() { 16 | Set set = Sets.newSet(1, 2, 3, 4, 5, 6); 17 | new BoundedSetWrapper<>(set, 4); 18 | } 19 | 20 | @Test 21 | public void createSetAndAssertEquals() { 22 | Set set = Sets.newSet(1, 2, 3, 4, 5, 6); 23 | BoundedSet boundedSetWrapper = new BoundedSetWrapper<>(set, 6); 24 | Assert.assertEquals("sets should be equal", set, boundedSetWrapper); 25 | 26 | } 27 | 28 | @Test 29 | public void testAdd() { 30 | BoundedSet boundedSet = new BoundedSetWrapper<>(new LinkedHashSet<>(), 3); 31 | Assert.assertTrue("can't add", boundedSet.add(1)); 32 | Assert.assertTrue("can't add", boundedSet.add(2)); 33 | Assert.assertTrue("can't add", boundedSet.add(3)); 34 | Assert.assertTrue("can't add", boundedSet.add(4)); 35 | Assert.assertEquals("bounded set doesn't have expected contents", 36 | Sets.newSet(2, 3, 4), boundedSet); 37 | } 38 | 39 | @Test(expected = IllegalArgumentException.class) 40 | public void testAddAll() { 41 | BoundedSet boundedSet = new BoundedSetWrapper<>(new LinkedHashSet<>(), 3); 42 | boundedSet.addAll(Arrays.asList(5, 6, 7, 8, 9)); 43 | } 44 | 45 | } --------------------------------------------------------------------------------