├── hornet-mainnet ├── config │ └── .gitkeep ├── config-template │ ├── peering-template.json │ ├── profiles.json │ └── config-template.json ├── .gitignore ├── docker-compose.yaml ├── utils.sh ├── README.md ├── README_AWS.md └── hornet.sh ├── hornet-mainnet-k8s ├── config │ └── .gitkeep ├── .gitignore ├── hornet-rest-service.yaml ├── hornet-service.yaml ├── hornet-ingress.yaml ├── README.md ├── hornet.yaml └── hornet-k8s.sh ├── explorer ├── .gitignore ├── config │ ├── webapp.config.local.json │ ├── api.config.local.json │ └── private-network.json ├── docker-compose.yaml ├── README.md └── tangle-explorer.sh ├── hornet-private-net ├── extra-nodes │ ├── peering.json │ ├── docker-compose.yaml │ ├── README.md │ └── private-hornet.sh ├── config │ ├── peering-node.json │ ├── peering-spammer.json │ ├── peering-coo.json │ ├── config-autopeering.json │ ├── profiles.json │ ├── config-node.json │ ├── config-coo.json │ └── config-spammer.json ├── README.md ├── utils.sh ├── docker-compose.yaml ├── README_AWS.md └── private-tangle.sh ├── bootstrap ├── private-net │ ├── parameters.sh │ ├── README.md │ ├── build-ami.sh │ └── install-private-tangle.sh ├── mainnet │ ├── README.md │ ├── install-hornet.sh │ └── build-ami.sh └── ami-install.sh ├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.md │ └── bug_report.md ├── SUPPORT.md ├── pull_request_template.md ├── SECURITY.md ├── CONTRIBUTING.md └── CODE_OF_CONDUCT.md ├── LICENSE ├── README_WINDOWS.md └── README.md /hornet-mainnet/config/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hornet-mainnet-k8s/config/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /explorer/.gitignore: -------------------------------------------------------------------------------- 1 | explorer-src 2 | application-data 3 | my-network.json 4 | -------------------------------------------------------------------------------- /hornet-mainnet/config-template/peering-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "peers": [] 3 | } 4 | -------------------------------------------------------------------------------- /hornet-private-net/extra-nodes/peering.json: -------------------------------------------------------------------------------- 1 | { 2 | "peers": [ 3 | ] 4 | } 5 | -------------------------------------------------------------------------------- /hornet-mainnet/.gitignore: -------------------------------------------------------------------------------- 1 | /config/config.json 2 | /config/profiles.json 3 | /config/peering.json 4 | -------------------------------------------------------------------------------- /bootstrap/private-net/parameters.sh: -------------------------------------------------------------------------------- 1 | export TANGLE_COO_BOOTSTRAP_WAIT=10 # We will wait 10 seconds for coordinator bootstrap -------------------------------------------------------------------------------- /hornet-mainnet-k8s/.gitignore: -------------------------------------------------------------------------------- 1 | /config/config.json 2 | /config/peering-*.json 3 | /config/profiles.json 4 | /config/keys/** 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.seed 2 | *.root 3 | *.addr 4 | *.txt 5 | logs 6 | 7 | db 8 | .DS_Store 9 | snapshots 10 | p2pstore 11 | nodes -------------------------------------------------------------------------------- /bootstrap/private-net/README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap utilities 2 | 3 | This folder contains different utilities related to bootstrapping a Private Tangle on AWS. 4 | -------------------------------------------------------------------------------- /bootstrap/mainnet/README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap for Chrysalis Hornet 2 | 3 | It contains the bootstrap files that allows to build an AMI ready to run Hornet Chrysalis for the mainnet 4 | -------------------------------------------------------------------------------- /explorer/config/webapp.config.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiEndpoint": "http://localhost:4000", 3 | "googleAnalyticsId": "GOOGLE-ANALYTICS-ID", 4 | "identityResolverEnabled": true 5 | } 6 | -------------------------------------------------------------------------------- /explorer/config/api.config.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "fixerApiKey": "FIXER-API-KEY", 3 | "rootStorageFolder": "/app/data/.local-storage", 4 | "allowedDomains": [ 5 | "*" 6 | ], 7 | "verboseLogging": true 8 | } 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Discord 4 | url: https://discord.iota.org/ 5 | about: Please ask and answer questions here. 6 | - name: Security vulnerabilities 7 | url: security@iota.org 8 | about: Please report security vulnerabilities here. -------------------------------------------------------------------------------- /hornet-mainnet-k8s/hornet-rest-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: hornet-rest 5 | labels: 6 | app: hornet-api 7 | source: one-click-tangle 8 | spec: 9 | type: NodePort 10 | ports: 11 | - name: rest 12 | port: 14265 13 | protocol: TCP 14 | targetPort: 14265 15 | selector: 16 | app: hornet 17 | -------------------------------------------------------------------------------- /hornet-private-net/config/peering-node.json: -------------------------------------------------------------------------------- 1 | { 2 | "peers": [ 3 | { 4 | "alias": "coo", 5 | "multiAddress": "/dns/coo/tcp/15600/p2p/12D3KooWSv699ZjCVJWwef5BWJBsbLXhJT8mC3tTvxEHY4PSSfdM" 6 | }, 7 | { 8 | "alias": "spammer", 9 | "multiAddress": "/dns/spammer/tcp/15600/p2p/12D3KooWCXTspxysRFFhNwcE4oEE2pQfDkaeagWJ8sKPir3JKQfE" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /hornet-private-net/config/peering-spammer.json: -------------------------------------------------------------------------------- 1 | { 2 | "peers": [ 3 | { 4 | "alias": "node1", 5 | "multiAddress": "/dns/node1/tcp/15600/p2p/12D3KooWK7JKfTubHzZYMML8mJGa1GpfGggGT6n5JXNTdm76cPxJ" 6 | }, 7 | { 8 | "alias": "coo", 9 | "multiAddress": "/dns/coo/tcp/15600/p2p/12D3KooWSv699ZjCVJWwef5BWJBsbLXhJT8mC3tTvxEHY4PSSfdM" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /hornet-private-net/config/peering-coo.json: -------------------------------------------------------------------------------- 1 | { 2 | "peers": [ 3 | { 4 | "alias": "node1", 5 | "multiAddress": "/dns/node1/tcp/15600/p2p/12D3KooWK7JKfTubHzZYMML8mJGa1GpfGggGT6n5JXNTdm76cPxJ" 6 | }, 7 | { 8 | "alias": "spammer", 9 | "multiAddress": "/dns/spammer/tcp/15600/p2p/12D3KooWCXTspxysRFFhNwcE4oEE2pQfDkaeagWJ8sKPir3JKQfE" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /explorer/config/private-network.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": "tangle", 3 | "label": "Tangle", 4 | "provider": "http://node1:14265", 5 | "protocolVersion": "chrysalis", 6 | "feedEndpoint": "mqtt://node1:1883", 7 | "coordinatorAddress": "", 8 | "primaryColor": "#131F37", 9 | "secondaryColor": "#485776", 10 | "isEnabled": true, 11 | "showMarket": false, 12 | "order": 0, 13 | "description": "Private Tangle Network" 14 | } 15 | -------------------------------------------------------------------------------- /bootstrap/mainnet/install-hornet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # General bootstrap script for Chrysalis Hornet 4 | 5 | scriptsInstall () { 6 | git clone https://github.com/iotaledger/one-click-tangle 7 | cd one-click-tangle 8 | git fetch origin 9 | git checkout -b chrysalis origin/chrysalis 10 | 11 | cd hornet-mainnet 12 | # The script that will launch all the process 13 | chmod +x ./hornet.sh 14 | } 15 | 16 | scriptsInstall 17 | ./hornet.sh install "$@" 18 | -------------------------------------------------------------------------------- /bootstrap/private-net/build-ami.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script that builds an AWS AMI that allows to install and then run a Private Tangle 4 | 5 | set -e 6 | 7 | wget https://raw.githubusercontent.com/iotaledger/one-click-tangle/chrysalis/bootstrap/ami-install.sh 8 | chmod +x ami-install.sh 9 | 10 | source ./ami-install.sh 11 | 12 | sudo wget https://raw.githubusercontent.com/iotaledger/one-click-tangle/chrysalis/bootstrap/private-net/install-private-tangle.sh -O /bin/install-private-tangle.sh 13 | sudo chmod +x /bin/install-private-tangle.sh 14 | -------------------------------------------------------------------------------- /bootstrap/mainnet/build-ami.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script that builds an AWS AMI that allows to install and then run a Chrysalis Hornet Node 4 | 5 | # All the git and Docker stuff is installed on the machine 6 | 7 | set -e 8 | 9 | wget https://raw.githubusercontent.com/iotaledger/one-click-tangle/chrysalis/bootstrap/ami-install.sh 10 | chmod +x ami-install.sh 11 | 12 | source ./ami-install.sh 13 | 14 | sudo wget https://raw.githubusercontent.com/iotaledger/one-click-tangle/chrysalis/bootstrap/mainnet/install-hornet.sh -O /bin/install-hornet.sh 15 | sudo chmod +x /bin/install-hornet.sh 16 | -------------------------------------------------------------------------------- /hornet-mainnet-k8s/hornet-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: hornet-0 5 | labels: 6 | source: one-click-tangle 7 | spec: 8 | type: NodePort 9 | externalTrafficPolicy: Local 10 | ports: 11 | - name: gossip 12 | port: 15600 13 | protocol: TCP 14 | targetPort: gossip 15 | - name: dashboard 16 | port: 8081 17 | protocol: TCP 18 | targetPort: dashboard 19 | - name: autopeering 20 | port: 14626 21 | protocol: UDP 22 | targetPort: autopeering 23 | selector: 24 | statefulset.kubernetes.io/pod-name: hornet-set-0 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Request a feature for Tangle Deployment Tools 3 | about: Request a feature 4 | --- 5 | 6 | ## Description 7 | 8 | Briefly describe the feature that you are requesting. 9 | 10 | ## Motivation 11 | 12 | Explain why this feature is needed. 13 | 14 | ## Requirements 15 | 16 | Write a list of what you want this feature to do. 17 | 18 | 1. 19 | 2. 20 | 3. 21 | 22 | ## Open questions (optional) 23 | 24 | Use this section to ask any questions that are related to the feature. 25 | 26 | ## Are you planning to do it yourself in a pull request? 27 | 28 | Yes/No. 29 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Community resources 2 | 3 | If you have a general or technical question, you can use one of the following resources instead of submitting an issue: 4 | 5 | - [**Developer documentation:**](https://docs.iota.org/) For official information about developing with IOTA technology 6 | - [**Discord:**](https://discord.iota.org/) For real-time chats with the developers and community members 7 | - [**IOTA cafe:**](https://iota.cafe/) For technical discussions with the Research and Development Department at the IOTA Foundation 8 | - [**StackExchange:**](https://iota.stackexchange.com/) For technical and troubleshooting questions -------------------------------------------------------------------------------- /hornet-private-net/extra-nodes/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | networks: 4 | tangle: 5 | external: 6 | name: private-tangle 7 | 8 | services: 9 | 10 | node: 11 | hostname: node 12 | # network_mode: host 13 | networks: 14 | - tangle 15 | image: iotaledger/hornet:1.2.4 16 | restart: unless-stopped 17 | container_name: node 18 | stop_grace_period: 5m 19 | expose: 20 | - 14265 21 | - 8081 22 | - 15600 23 | - "14626/udp" 24 | volumes: 25 | - ./config/config.json:/app/config.json:ro 26 | - ./config/profiles.json:/app/profiles.json 27 | - ./config/peering.json:/app/peering.json 28 | - ./db:/app/db 29 | - ./p2pstore:/app/p2pstore 30 | - ./snapshots:/app/snapshots 31 | cap_drop: 32 | - ALL 33 | -------------------------------------------------------------------------------- /hornet-mainnet-k8s/hornet-ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: hornet-ingress 5 | labels: 6 | source: one-click-tangle 7 | annotations: 8 | # 'gce' for GKE, 'alb' for 'EKS' 9 | kubernetes.io/ingress.class: nginx 10 | # Uncomment for AWS EKS: alb.ingress.kubernetes.io/subnets: subnet-aa1649cc, subnet-a656cffc, subnet-fdf3dcb5 11 | # Uncomment for AWS EKS: alb.ingress.kubernetes.io/scheme: internet-facing 12 | spec: 13 | rules: 14 | - http: 15 | paths: 16 | - path: /api 17 | pathType: Prefix 18 | backend: 19 | service: 20 | name: hornet-rest 21 | port: 22 | name: rest 23 | - path: / 24 | pathType: Prefix 25 | backend: 26 | service: 27 | name: hornet-0 28 | port: 29 | name: dashboard 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Report a bug in the Tangle Deployment Tools 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: bug 6 | --- 7 | 8 | ## Bug description 9 | 10 | Briefly describe the bug. 11 | 12 | ## Docker and docker-compose version 13 | 14 | Which version of Docker and docker-compose are you running? 15 | 16 | - Docker version: 17 | 18 | ## Hardware specification 19 | 20 | What hardware are you using? 21 | 22 | - Operating system: 23 | - RAM: 24 | - Cores: 25 | - Device: 26 | 27 | ## Steps To reproduce the bug 28 | 29 | Explain how the maintainer can reproduce the bug. 30 | 31 | 1. 32 | 2. 33 | 3. 34 | 35 | ## Expected behaviour 36 | 37 | Describe what you expect to happen. 38 | 39 | ## Actual behaviour 40 | 41 | Describe what actually happens. 42 | 43 | ## Errors 44 | 45 | Paste any errors that you see, including logs, errors, or screenshots. 46 | -------------------------------------------------------------------------------- /explorer/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | networks: 4 | tangle: 5 | external: 6 | name: private-tangle 7 | 8 | services: 9 | explorer-api: 10 | hostname: explorer-api 11 | networks: 12 | - tangle 13 | build: 14 | context: ./explorer-src/api 15 | dockerfile: Dockerfile 16 | image: iotaledger/explorer-api 17 | restart: unless-stopped 18 | container_name: explorer-api 19 | expose: 20 | - 4000 21 | ports: 22 | - "0.0.0.0:4000:4000" 23 | volumes: 24 | - ./application-data:/app/data/.local-storage 25 | 26 | explorer-webapp: 27 | hostname: explorer-webapp 28 | networks: 29 | - tangle 30 | build: 31 | context: ./explorer-src/client 32 | dockerfile: Dockerfile 33 | image: iotaledger/explorer-webapp 34 | restart: unless-stopped 35 | container_name: explorer-webapp 36 | depends_on: 37 | - explorer-api 38 | expose: 39 | - 80 40 | ports: 41 | - "0.0.0.0:8082:80" 42 | -------------------------------------------------------------------------------- /hornet-mainnet/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | networks: 4 | tangle: 5 | name: tangle 6 | enable_ipv6: false 7 | 8 | services: 9 | hornet: 10 | hostname: hornet 11 | working_dir: /app 12 | networks: 13 | - tangle 14 | image: iotaledger/hornet:1.2.4 15 | restart: unless-stopped 16 | container_name: hornet 17 | stop_grace_period: 5m 18 | expose: 19 | - 14265 20 | - 15600 21 | - 8081 22 | - "14626/udp" 23 | ports: 24 | - "0.0.0.0:14265:14265" 25 | - "0.0.0.0:14626:14626/udp" 26 | - "0.0.0.0:15600:15600" 27 | - "0.0.0.0:8081:8081" 28 | volumes: 29 | - ./config/config.json:/app/config.json:ro 30 | - ./config/profiles.json:/app/profiles.json 31 | - ./config/peering.json:/app/peering.json 32 | - ./db/mainnet:/app/mainnetdb 33 | - ./snapshots/mainnet:/app/snapshots/mainnet 34 | - ./p2pstore:/app/p2pstore 35 | cap_drop: 36 | - ALL 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 IOTA Stiftung 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /bootstrap/ami-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script that includes common scripts for builds an AWS AMI (Docker and Git Artefacts) 4 | 5 | # All the git and Docker stuff is installed on the machine 6 | 7 | set -e 8 | 9 | jqInstall () { 10 | sudo yum install jq -y 11 | } 12 | 13 | gitInstall () { 14 | echo "Installing git ..." 15 | sudo yum update -y 16 | sudo yum install git -y 17 | } 18 | 19 | dockerInstall () { 20 | echo "Installing docker ..." 21 | 22 | sudo yum install docker -y 23 | # Add the ec2-user to the docker group so you can execute Docker commands without using sudo. 24 | sudo gpasswd -a ec2-user docker 25 | 26 | sudo systemctl enable docker 27 | 28 | ## Start docker service 29 | sudo systemctl start docker 30 | 31 | echo "Installing docker-compose ..." 32 | ## Install docker-compose 33 | sudo curl -L "https://github.com/docker/compose/releases/download/1.27.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 34 | sudo chmod +x /usr/local/bin/docker-compose 35 | 36 | export PATH=$PATH:/usr/local/bin 37 | } 38 | 39 | gitInstall 40 | 41 | dockerInstall 42 | 43 | jqInstall 44 | -------------------------------------------------------------------------------- /explorer/README.md: -------------------------------------------------------------------------------- 1 | # Private Tangle Explorer Setup 2 | 3 | ## Usage 4 | 5 | * Make the bash script executable by running 6 | ``` 7 | chmod +x tangle-explorer.sh 8 | ``` 9 | 10 | * Install and start a new Tangle Explorer 11 | 12 | *Warning: It destroys previous data.* 13 | 14 | ``` 15 | ./tangle-explorer.sh install [ or ] 16 | ``` 17 | 18 | The `network-definition.json` parameter is optional. By default it will be taken the file present at 19 | `config/private-network.json`. The format of the file is described [here](https://github.com/iotaledger/explorer/blob/master/api/DEPLOYMENT.md). A template for the file is [here](./config/private-network.json). 20 | 21 | Alternatively it can be provided the `private-tangle-install-folder` parameter to convey a folder of a previous Private Tangle installation, such as the one [here](../hornet-private-net). 22 | 23 | * Stop all the containers by running 24 | 25 | ``` 26 | ./tangle-explorer.sh stop 27 | ``` 28 | 29 | * Start all the containers (keeping the already configured networks) 30 | 31 | ``` 32 | ./tangle-explorer.sh start 33 | ``` 34 | 35 | * Updates the Explorer to the latest version (keeping the already configured networks) 36 | 37 | ``` 38 | ./tangle-explorer.sh update 39 | ``` 40 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description of change 2 | 3 | Please write a summary of your changes and why you made them. Be sure to reference any related issues by adding `fixes # (issue)`. 4 | 5 | ## Type of change 6 | 7 | Choose a type of change, and delete any options that are not relevant. 8 | 9 | - Bug fix (a non-breaking change which fixes an issue) 10 | - Enhancement (a non-breaking change which adds functionality) 11 | - Breaking change (fix or feature that would cause existing functionality to not work as expected) 12 | - Documentation Fix 13 | 14 | ## How the change has been tested 15 | 16 | Describe the tests that you ran to verify your changes. 17 | 18 | Make sure to provide instructions for the maintainer as well as any relevant configurations. 19 | 20 | ## Change checklist 21 | 22 | Add an `x` to the boxes that are relevant to your changes, and delete any items that are not. 23 | 24 | - [] My code follows the contribution guidelines for this project 25 | - [] I have performed a self-review of my own code 26 | - [] I have commented my code, particularly in hard-to-understand areas 27 | - [] I have made corresponding changes to the documentation 28 | - [] I have added tests that prove my fix is effective or that my feature works 29 | - [] New and existing unit tests pass locally with my changes 30 | -------------------------------------------------------------------------------- /hornet-mainnet/utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Common utilities both used by hornet.sh and hornet-k8s.sh 4 | 5 | HORNET_UPSTREAM="https://raw.githubusercontent.com/gohornet/hornet/mainnet/" 6 | 7 | # The coordinator public key ranges are obtained 8 | cooSetup () { 9 | cat config/config.json | jq --argjson protocol \ 10 | "$(wget $HORNET_UPSTREAM/config.json -O - -q | jq '.protocol')" \ 11 | '. |= . + {$protocol}' > config/config-coo.json 12 | 13 | mv config/config-coo.json config/config.json 14 | } 15 | 16 | peerSetup () { 17 | # And now we configure our Node's peers 18 | if [ -n "$peer" ]; then 19 | echo "Peering with: $peer" 20 | # This is the case where no previous peer definition was there 21 | sed -i 's/\[\]/\[{"alias": "peer1","multiAddress": "'$peer'"}\]/g' config/peering.json 22 | else 23 | echo "Configuring autopeering ..." 24 | autopeeringSetup 25 | fi 26 | } 27 | 28 | autopeeringSetup () { 29 | # The autopeering plugin is enabled 30 | cat config/config.json | jq '.node.enablePlugins[.node.enablePlugins | length] |= . + "Autopeering"' > config/config-autopeering.json 31 | 32 | # Then the autopeering configuration is added from Hornet 33 | cat config/config-autopeering.json | jq --argjson autopeering \ 34 | "$(wget $HORNET_UPSTREAM/config.json -O - -q | jq '.p2p.autopeering')" \ 35 | '.p2p |= . + {$autopeering}' > config/config.json 36 | 37 | rm config/config-autopeering.json 38 | } 39 | -------------------------------------------------------------------------------- /bootstrap/private-net/install-private-tangle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # General bootstrap script 4 | 5 | # Detects the platform downloads the latest bootstrap from Github 6 | # And executes it 7 | # For the time being only the Linux AWS is supported 8 | 9 | scriptsInstall () { 10 | git clone https://github.com/iotaledger/one-click-tangle 11 | cd one-click-tangle 12 | git fetch origin 13 | git checkout -b chrysalis origin/chrysalis 14 | 15 | cd hornet-private-net 16 | # The script that will launch all the process 17 | chmod +x ./private-tangle.sh 18 | } 19 | 20 | tangleExplorer () { 21 | cd ../explorer 22 | cp ./config/private-network.json ./my-network.json 23 | 24 | # Set the Coordinator Address 25 | sed -i 's/"coordinatorAddress": \("\).*\("\)/"coordinatorAddress": \1'$(cat ../hornet-private-net/coo-milestones-public-key.txt)'\2/g' ./my-network.json 26 | 27 | # Set in the Front-End App configuration the API endpoint 28 | sed -i 's/"apiEndpoint": \("\).*\("\)/"apiEndpoint": \1http:\/\/'$(echo $(dig +short myip.opendns.com @resolver1.opendns.com))':4000\2/g' ./config/webapp.config.local.json 29 | 30 | # Run tangle explorer installation 31 | ./tangle-explorer.sh install my-network.json 32 | } 33 | 34 | ################################################### 35 | ## Script starts here. 36 | ################################################### 37 | 38 | # First we install all the scripts needed 39 | scriptsInstall 40 | 41 | # Load the parameters 42 | chmod +x ../bootstrap/private-net/parameters.sh 43 | source ../bootstrap/private-net/parameters.sh 44 | 45 | # First the private Tangle is installed 46 | ./private-tangle.sh install $TANGLE_COO_BOOTSTRAP_WAIT 47 | 48 | # And then the Tangle Explorer 49 | tangleExplorer 50 | -------------------------------------------------------------------------------- /hornet-private-net/README.md: -------------------------------------------------------------------------------- 1 | # Private Tangle Setup using Hornet 2 | 3 | You can also use these scripts under the [AWS Marketplace](./README_AWS.md) 4 | 5 | ## Usage 6 | 7 | * Make the bash script executable by running 8 | ``` 9 | chmod +x private-tangle.sh 10 | ``` 11 | 12 | * Install a new Tangle with Coordinator, Spammer and 1 Node 13 | 14 | *Warning: It destroys previous data.* 15 | 16 | ``` 17 | ./private-tangle.sh install 18 | ``` 19 | 20 | The parameter `coo_bootstrap_wait_time` is optional (default is `10` seconds) and denotes the time in seconds to wait for the coordinator to bootstrap. 21 | 22 | * Stop all the containers by running 23 | 24 | ``` 25 | ./private-tangle.sh stop 26 | ``` 27 | 28 | * Start all the containers by running 29 | 30 | ``` 31 | ./private-tangle.sh start 32 | ``` 33 | 34 | 35 | * Add extra Nodes to your Private Tangle 36 | 37 | Go to the `extra-nodes` folder and follow the recipe [here](./extra-nodes/README.md). 38 | 39 | ## Notes on IOTA Frameworks 40 | 41 | If you want to use [IOTA Identity](https://github.com/identity.rs) on your Private Tangle you can do it by assigning the network identifier `tangle` to the DID method used, for instance `did:iota:tangle:F7PAPm2LqngmmN2uu3DSmHAvu74zA5f8c7c9R75qnMkG`. A DID generation Rust example can be found [here](https://github.com/iotaledger/identity.rs/blob/dev/examples/low-level-api/private_tangle.rs). 42 | 43 | Note: If you install the Tangle Explorer the Identity Resolver will be enabled by default. The URL to inspect your generated DIDs will be typically of the form `http://localhost:8082/tangle/identity-resolver/{DID}`, for instance `http://localhost:8082/tangle/identity-resolver/did:iota:tangle:F7PAPm2LqngmmN2uu3DSmHAvu74zA5f8c7c9R75qnMkG` 44 | -------------------------------------------------------------------------------- /hornet-private-net/utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### Utility functions ### 4 | 5 | # Extracts the public key from a key pair 6 | getPublicKey () { 7 | cat $1 | awk -F : '{if ($1 ~ /public key/) print $2}' | sed "s/ \+//g" | tr -d "\n" | tr -d "\r" 8 | } 9 | 10 | # Extracts the private key from a key pair 11 | getPrivateKey () { 12 | cat $1 | awk -F : '{if ($1 ~ /private key/) print $2}' | sed "s/ \+//g" | tr -d "\n" | tr -d "\r" 13 | } 14 | 15 | setCooPublicKey () { 16 | local public_key="$1" 17 | sed -i 's/"key": ".*"/"key": "'$public_key'"/g' "$2" 18 | } 19 | 20 | generateP2PIdentity () { 21 | docker-compose run --rm "$1" tool p2pidentity-gen > "$2" 22 | } 23 | 24 | setupIdentityPrivateKey () { 25 | local private_key=$(cat $1 | awk -F : '{if ($1 ~ /private key/) print $2}' | sed "s/ \+//g" | tr -d "\n" | tr -d "\r") 26 | # and then set it on the config.json file 27 | sed -i 's/"identityPrivateKey": ".*"/"identityPrivateKey": "'$private_key'"/g' "$2" 28 | } 29 | 30 | # Extracts the peerID from the identity file 31 | getPeerID () { 32 | cat $1 | awk -F : '{if ($1 ~ /PeerID/) print $2}' | sed "s/ \+//g" | tr -d "\n" | tr -d "\r" 33 | } 34 | 35 | getAutopeeringID () { 36 | cat $1 | awk -F : '{if ($1 ~ /public key \(base58\)/) print $2}' | sed "s/ \+//g" | tr -d "\n" | tr -d "\r" 37 | } 38 | 39 | createSubfolders () { 40 | local folders="$@" 41 | 42 | for folder in $folders; do 43 | if ! [ -d "./$folder" ]; then 44 | mkdir "./$folder" 45 | fi 46 | done 47 | } 48 | 49 | removeSubfolderContent () { 50 | local folders="$@" 51 | 52 | for folder in $folders; do 53 | if [ -d "./$folder" ]; then 54 | sudo rm -Rf ./"$folder"/* 55 | fi 56 | done 57 | } 58 | 59 | # Sets entry node for autopeering 60 | setEntryNode () { 61 | sed -i 's/"entryNodes": \[.*\]/"entryNodes": \["'$1'"\]/g' "$2" 62 | } 63 | 64 | # Resets a peering file 65 | resetPeeringFile() { 66 | if [ -f "$1" ]; then 67 | sudo rm "$1" 68 | fi 69 | 70 | cat < "$1" 71 | { 72 | "peers": [ 73 | ] 74 | } 75 | EOF 76 | } 77 | -------------------------------------------------------------------------------- /hornet-private-net/config/config-autopeering.json: -------------------------------------------------------------------------------- 1 | { 2 | "restAPI": { 3 | "jwtAuth": { 4 | "enabled": false, 5 | "salt": "HORNET" 6 | }, 7 | "excludeHealthCheckFromAuth": false, 8 | "publicRoutes": [ 9 | "/health" 10 | ], 11 | "whitelistedAddresses": [ 12 | "127.0.0.1", 13 | "::1" 14 | ], 15 | "bindAddress": "0.0.0.0:14265", 16 | "powEnabled": true, 17 | "powWorkerCount": 1, 18 | "limits": { 19 | "bodyLength": "1M", 20 | "maxResults": 1000 21 | } 22 | }, 23 | "db": { 24 | "engine": "rocksdb", 25 | "path": "/app/db", 26 | "autoRevalidation": false 27 | }, 28 | "protocol": { 29 | "networkID": "private-tangle", 30 | "bech32HRP": "atoipt" 31 | }, 32 | "requests": { 33 | "discardOlderThan": "15s", 34 | "pendingReEnqueueInterval": "5s" 35 | }, 36 | "node": { 37 | "alias": "node-autopeering", 38 | "profile": "auto", 39 | "enablePlugins": [ 40 | "Autopeering" 41 | ] 42 | }, 43 | "p2p": { 44 | "bindMultiAddresses": [ 45 | "/ip4/0.0.0.0/tcp/15600" 46 | ], 47 | "connectionManager": { 48 | "highWatermark": 10, 49 | "lowWatermark": 5 50 | }, 51 | "gossipUnknownPeersLimit": 4, 52 | "db": { 53 | "path": "p2pstore" 54 | }, 55 | "reconnectInterval": "30s", 56 | "autopeering": { 57 | "bindAddress": "0.0.0.0:14626", 58 | "entryNodesPreferIPv6": false, 59 | "runAsEntryNode": true 60 | } 61 | }, 62 | "p2pdisc": { 63 | "advertiseInterval": "30s", 64 | "maxDiscoveredPeerConns": 4, 65 | "rendezvousPoint": "between-two-vertices", 66 | "routingTableRefreshPeriod": "60s" 67 | }, 68 | "logger": { 69 | "level": "info", 70 | "disableCaller": true, 71 | "encoding": "console", 72 | "outputPaths": [ 73 | "stdout" 74 | ] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /hornet-mainnet/README.md: -------------------------------------------------------------------------------- 1 | # Hornet Chrysalis Node 2 | 3 | You can also use these scripts under the [AWS Marketplace](./README_AWS.md) 4 | 5 | ## Usage 6 | 7 | * Make the bash script executable by running 8 | 9 | ``` 10 | chmod +x hornet.sh 11 | ``` 12 | 13 | * Install a Hornet Node connected to the Chrysalis mainnet 14 | 15 | ``` 16 | ./hornet.sh install -p -i 17 | ``` 18 | 19 | The `peer_multiAddress` parameter is optional and must conform to the format specified [here](https://hornet.docs.iota.org/post_installation/peering.html). If no peer specified [autopeering](https://hornet.docs.iota.org/post_installation/peering/#autopeering) will be enabled. 20 | 21 | Optionally a Docker image name can be passed, even though, by default, the image name present in the `docker-compose.yaml` file will be used, usually `iotaledger/hornet:1.2.4`. 22 | 23 | A back slash should be added wherever there is a forward slash. For example, when defining the docker image `iotaledger/hornet:1.2.4` should be `iotaledger\/hornet:1.2.4` and a peer multiaddress like `/ip4/x.x.x.x/tcp/15600/p2p/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` should be `\/ip4\/x.x.x.x\/tcp\/15600\/p2p\/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` to avoid any error occuring during running or installing hornet. 24 | 25 | * Stop Hornet by running 26 | ``` 27 | ./hornet.sh stop 28 | ``` 29 | 30 | * Start Hornet by running 31 | ``` 32 | ./hornet.sh start 33 | ``` 34 | 35 | ## Troubleshooting 36 | 37 | * [Autopeering](https://hornet.docs.iota.org/post_installation/peering/#autopeering) is only enabled if no peer address is provided. To check that autopeering is working correctly `node.enablePlugins` must include `"Autopeering"`. 38 | 39 | Ensure that there are entry nodes in the `p2p.autopeering.entryNodes`. Entry nodes are encoded in `multiaddr` format. 40 | 41 | NB: The `update` command will not update to new versions of the config files as they may contain local changes that cannot be merged with the upstream changes. If that is the case you would need to stop Hornet, merge your current config files with the config files at [https://github.com/iotaledger/one-click-tangle/blob/chrysalis/hornet-mainnet/config/config.json](https://github.com/iotaledger/one-click-tangle/blob/chrysalis/hornet-mainnet/config/config.json) and then start again Hornet. 42 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 |

Responsible disclosure policy

2 | 3 | At the IOTA Foundation, we consider the security of our systems a top priority. But no matter how much effort we put into system security, there can still be vulnerabilities present. If you've discovered a vulnerability, please follow the guidelines below to report it to our security team: 4 |
    5 |
  • E-mail your findings to security@iota.org. If the report contains highly sensitive information, please consider encrypting your findings using our contact@iota.org (466385BD0B40D9550F93C04746A440CCE5664A64) PGP key.
  • 6 |
7 | Please follow these rules when testing/reporting vulnerabilities: 8 |
    9 |
  • Do not take advantage of the vulnerability you have discovered, for example by downloading more data than is necessary to demonstrate the vulnerability.
  • 10 |
  • Do not read, modify or delete data that you don't own.
  • 11 |
  • We ask that you do not to disclosure the problem to third parties until it has been resolved.
  • 12 |
  • The scope of the program is limited to technical vulnerabilities in IOTA Foundations's web applications and open source software packages distributed through GitHub, please do not try to test physical security or attempt phishing attacks against our employees, and so on.
  • 13 |
  • Out of concern for the availability of our services to all users, please do not attempt to carry out DoS attacks, leverage black hat SEO techniques, spam people, and do other similarly questionable things. We also discourage the use of any vulnerability testing tools that automatically generate significant volumes of traffic.
  • 14 |
15 | What we promise: 16 |
    17 |
  • We will respond to your report within 3 business days with our evaluation of the report and an expected resolution date.
  • 18 |
  • If you have followed the instructions above, we will not take any legal action against you in regard to the report.
  • 19 |
  • We will keep you informed during all stages of resolving the problem.
  • 20 |
  • To show our appreciation for your effort and cooperation during the report, we will list your name and a link to a personal website/social network profile on the page below so that the public can know you've helped keep the IOTA Foundation secure.
  • 21 |
22 | We sincerely appreciate the efforts of security researchers in keeping our community safe. 23 | 24 | -------------------------------------------------------------------------------- /hornet-private-net/extra-nodes/README.md: -------------------------------------------------------------------------------- 1 | # Private Tangle Extra Nodes 2 | 3 | You can also use these scripts under the [AWS Marketplace](../README_AWS.md). 4 | 5 | Once you have an up and running Private Tangle, this utility allows adding extra Hornet nodes. 6 | 7 | ## Usage 8 | 9 | * Make the bash script executable by running 10 | 11 | ``` 12 | chmod +x private-hornet.sh 13 | ``` 14 | 15 | * Install a new Hornet Node as part of a Private Tangle under the same local installation 16 | 17 | *Warning: If there is an existing Node with the same name, it destroys previous data.* 18 | 19 | ``` 20 | ./private-hornet.sh install "my-node:14266:15601:8082" 21 | ``` 22 | 23 | The first parameter is a Node connection string. Such string has different 24 | fields separated by a colon (`:`). The first field is the (container and host) name 25 | of your Node and, at installation time, it can be followed, optionally, by the TCP port 26 | numbers (exposed on the host) corresponding to 27 | the *API endpoint*, the *gossip peering endpoint* and the *dashboard endpoint*. 28 | 29 | *Note*: If no port numbers are provided, i.e. only the container name is supplied, no ports will be exposed to the host. 30 | 31 | *Note*: You can omit some of the ports but the separator `:` has to be kept, for instance, if you just only want to expose the dashboard port to the host you can run: 32 | 33 | ``` 34 | ./private-hornet.sh install "my-node:::8082" 35 | ``` 36 | 37 | *Note*: By default your Node will be peered using the default autopeering Entry Node provided off-the-shelf by the Private Tangle installation. 38 | 39 | * Install a new Hornet Node passing the Private Tangle parameters on the command line 40 | 41 | *Warning: If there is an existing Node with the same name, it destroys previous data.* 42 | 43 | ``` 44 | ./private-hornet.sh install "my-node" 45 | 61d564e6b20c060566110f1f0b59bb0569bd93315070f2ceaa33aba0be7f086b 46 | "\/dns\/my-other-node\/tcp\/15600\/p2p\/12D3KooWSXdWBH7NpzSMzsMnDivTgi6E5wA7awwHpcoJwXG9wUdx" 47 | "/my-snapshots/private-tangle/full_snapshot.bin" 48 | ``` 49 | 50 | The first parameter is the Node connection string as explained above. The second parameter is the 51 | *Coordinator's public key*. The third parameter can be either a *peer multi-address* of the Node you are going 52 | to peer with or an entry node for autopeering, for instance, `\/dns\/node-autopeering\/udp\/14626\/autopeering\/14bPxgiL7ALdQd9Qmb3z4uwCsX4M7PGPeouNaVPx45ax`. 53 | The last parameter is the *snapshot* file that will be used to sync up an initial ledger state. 54 | 55 | * Stop an existing Node by running 56 | 57 | ``` 58 | ./private-hornet.sh stop my-node 59 | ``` 60 | 61 | * Start an existing Node by running 62 | 63 | ``` 64 | ./private-hornet.sh start my-node 65 | ``` 66 | -------------------------------------------------------------------------------- /hornet-private-net/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | networks: 4 | tangle: 5 | external: 6 | name: private-tangle 7 | 8 | services: 9 | coo: 10 | hostname: coo 11 | # network_mode: host 12 | networks: 13 | - tangle 14 | image: iotaledger/hornet:1.2.4 15 | restart: unless-stopped 16 | container_name: coo 17 | stop_grace_period: 5m 18 | environment: 19 | - COO_PRV_KEYS 20 | expose: 21 | - 15600 22 | volumes: 23 | - ./config/config-coo.json:/app/config.json:ro 24 | - ./config/profiles.json:/app/profiles.json:ro 25 | - ./config/peering-coo.json:/app/peering.json:ro 26 | - ./db/private-tangle/coo.db:/app/db 27 | - ./p2pstore/coo:/app/p2pstore 28 | - ./db/private-tangle:/app/coo-state 29 | - ./snapshots:/app/snapshots 30 | cap_drop: 31 | - ALL 32 | 33 | node: 34 | hostname: node1 35 | # network_mode: host 36 | networks: 37 | - tangle 38 | image: iotaledger/hornet:1.2.4 39 | restart: unless-stopped 40 | container_name: node1 41 | stop_grace_period: 5m 42 | expose: 43 | - 14265 44 | - 8081 45 | - 1883 46 | - 15600 47 | - "14626/udp" 48 | ports: 49 | - "0.0.0.0:14265:14265" 50 | - "0.0.0.0:8081:8081" 51 | - "0.0.0.0:15600:15600" 52 | volumes: 53 | - ./config/config-node.json:/app/config.json:ro 54 | - ./config/profiles.json:/app/profiles.json 55 | - ./config/peering-node.json:/app/peering.json 56 | - ./db/private-tangle/node1.db:/app/db 57 | - ./p2pstore/node1:/app/p2pstore 58 | - ./snapshots:/app/snapshots 59 | cap_drop: 60 | - ALL 61 | 62 | spammer: 63 | hostname: spammer 64 | # network_mode: host 65 | networks: 66 | - tangle 67 | image: iotaledger/hornet:1.2.4 68 | restart: unless-stopped 69 | container_name: spammer 70 | stop_grace_period: 5m 71 | expose: 72 | - 15600 73 | - "14626/udp" 74 | volumes: 75 | - ./config/config-spammer.json:/app/config.json:ro 76 | - ./config/profiles.json:/app/profiles.json 77 | - ./config/peering-spammer.json:/app/peering.json 78 | - ./db/private-tangle/spammer.db:/app/db 79 | - ./p2pstore/spammer:/app/p2pstore 80 | - ./snapshots:/app/snapshots 81 | cap_drop: 82 | - ALL 83 | 84 | node-autopeering: 85 | hostname: node-autopeering 86 | # network_mode: host 87 | networks: 88 | - tangle 89 | image: iotaledger/hornet:1.2.4 90 | restart: unless-stopped 91 | container_name: node-autopeering 92 | stop_grace_period: 5m 93 | expose: 94 | - "14626/udp" 95 | ports: 96 | - "0.0.0.0:14626:14626/udp" 97 | volumes: 98 | - ./config/config-autopeering.json:/app/config.json:ro 99 | - ./config/profiles.json:/app/profiles.json 100 | - ./db/private-tangle/node-autopeering.db:/app/db 101 | - ./p2pstore/node-autopeering:/app/p2pstore 102 | cap_drop: 103 | - ALL 104 | -------------------------------------------------------------------------------- /README_WINDOWS.md: -------------------------------------------------------------------------------- 1 | ## Set up One-Click-Tangle Docker environment on Windows 10 2 | 3 | ##### 1. Docker Installation 4 | - Install [Docker for Windows](https://docs.docker.com/desktop/windows/install) 5 | - Make sure to also install the required Windows components for WSL 2 ([Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/about)) 6 | 7 | ##### 2. Check Version 8 | - After the installation you should check your **Docker** (`>=18.03`) and **Docker Compose** (`>=1.21`) versions using the following CMD commands 9 | ```console 10 | docker -v 11 | docker-compose -v 12 | ``` 13 | 14 | ##### 3. Install Ubuntu 15 | - Install Ubuntu distribution using the following CMD commands step by step (list available distributions / install Ubuntu / check version) 16 | ```console 17 | wsl --list --online 18 | wsl --install --distribution Ubuntu 19 | wsl -l -v 20 | ``` 21 | 22 | ##### 4. Set Default Distribution 23 | - Make Ubuntu your default WSL distribution by using the following CMD commands (set default distribution / check new default) 24 | ```console 25 | wsl --set-default Ubuntu 26 | wsl --list 27 | ``` 28 | 29 | ##### 5. Docker Desktop Settings 30 | - Enable WSL integration with new Ubuntu distribution (*Settings > Resources > WSL INTEGRATION*) 31 | - Make sure Docker Compose v2 is deactivated (*Settings>General*) 32 | - You can also deactivate Docker Compose v2 by running 33 | ```console 34 | docker-compose disable-v2 35 | ``` 36 | 37 | ##### 6. Clone Repo 38 | - Clone [one-click-tangle](https://github.com/iotaledger/one-click-tangle) repository with the following CMD commands 39 | ```console 40 | git clone https://github.com/iotaledger/one-click-tangle 41 | cd one-click-tangle 42 | ``` 43 | 44 | ##### 7. Install One-Click-Tangle Components 45 | - Now you can install different components available in the one-click-tangle repo 46 | - **NOTE:** Instead of using the mentioned `chmod` command in the referenced readme's, you need to run Ubuntu as administrator for the necessary rights 47 | 48 | - ##### Private Hornet Node Tangle 49 | - Navigate to `hornet-private-tangle` folder in the `one-click-tangle` repo 50 | ```console 51 | cd /mnt//one-click-tangle/hornet-private-net/ 52 | ``` 53 | - Run commands as described in the hornet-private-net [readme](/hornet-private-net/README.md) 54 | - **NOTE:** When installing the private tangle script it's recommended to use a `coo_bootstrap_wait_time` of 30 seconds 55 | - `./private-tangle.sh install 30` 56 | - ##### Mainnet Hornet Node 57 | - Navigate to `hornet-mainnet` folder in the `one-click-tangle` repo 58 | ```console 59 | cd /mnt//one-click-tangle/hornet-mainnet/ 60 | ``` 61 | - Run commands as described in the hornet-mainnet [readme](/hornet-mainnet/README.md) 62 | - ##### IOTA Explorer 63 | - Navigate to `explorer` folder in the `one-click-tangle` repo 64 | ```console 65 | cd /mnt//one-click-tangle/explorer/ 66 | ``` 67 | - Run commands as described in the explorer [readme](/explorer/README.md) -------------------------------------------------------------------------------- /hornet-mainnet-k8s/README.md: -------------------------------------------------------------------------------- 1 | # Hornet Chrysalis Node on Kubernetes 2 | 3 | (For a detailed explanation please read the [tutorial on the IOTA Wiki](https://wiki.iota.org/chrysalis-docs/tutorials/mainnet_hornet_node_k8s)) 4 | 5 | ## Prerequisites 6 | 7 | * Get access to a Kubernetes (K8s) cluster and install the `kubectl` command line tool. 8 | 9 | ## Usage 10 | 11 | * Make the bash script executable by running 12 | 13 | ```sh 14 | chmod +x hornet-k8s.sh 15 | ``` 16 | 17 | * Deploy a Hornet Node connected to the Chrysalis mainnet 18 | 19 | ```sh 20 | PEER= ./hornet-k8s.sh deploy 21 | ``` 22 | 23 | The `peer_multiAddress` parameter is optional and must conform to the format specified [here](https://hornet.docs.iota.org/post_installation/peering.html). If no peer specified [autopeering](https://hornet.docs.iota.org/post_installation/peering/#autopeering) will be enabled. 24 | 25 | A back slash should be added wherever there is a forward slash. For example, when defining the docker image `iotaledger/hornet:1.2.4` should be `iotaledger\/hornet:1.2.4` and a peer multiaddress like `/ip4/x.x.x.x/tcp/15600/p2p/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` should be `\/ip4\/x.x.x.x\/tcp\/15600\/p2p\/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` to avoid any error occurring during running or installing hornet. 26 | 27 | *By default the Node will be deployed under the `tangle` namespace* 28 | 29 | By default all the Nodes will be automatically peered among them. 30 | 31 | * Undeploy Hornet by running 32 | 33 | ```sh 34 | ./hornet-k8s.sh undeploy 35 | ``` 36 | 37 | * Scale Hornet by running 38 | 39 | ```sh 40 | INSTANCES= ./hornet-k8s.sh scale 41 | ``` 42 | 43 | If `INSTANCES=0` then your Hornet node will be stopped. 44 | 45 | ## Getting access to your Hornet Node 46 | 47 | Your Hornet node(s) will be exposed through K8s "Node Port" Services. Such Services are: 48 | 49 | * `hornet-rest` it is a K8s Service that exposes the REST endpoint and might be served by multiple Hornet nodes. 50 | * `hornet-` one or more K8s Services that exposes the gossip and dashboard and it is only served by one Hornet node. 51 | 52 | In order to know the ports on the K8s Workers where these Services are exposed, you can run (assuming you are using the `tangle` K8s namespace): 53 | 54 | ```sh 55 | kubectl -n tangle describe service hornet-rest 56 | ``` 57 | 58 | ```sh 59 | kubectl -n tangle describe service hornet-0 60 | ``` 61 | 62 | ## Additional parameters 63 | 64 | * `NAMESPACE`: conveys a Kubernetes namespace to be used to deploy Hornet. It will be created if it does not exist yet 65 | * `INGRESS_CLASS`: conveys the ingress class to be used in your Kubernetes environment (by default NGINX). For GKE it should be `gce` and for EKS should be `alb`. 66 | 67 | ## Troubleshooting 68 | 69 | * [Autopeering](https://hornet.docs.iota.org/post_installation/peering/#autopeering) is only enabled if no peer address is provided. To check that autopeering is working correctly `node.enablePlugins` must include `"Autopeering"`. 70 | 71 | Ensure that there are entry nodes in the `p2p.autopeering.entryNodes`. Entry nodes are encoded in `multiaddr` format. 72 | 73 | ## Limitations 74 | 75 | Network policies for isolating the Pods are not provided by this version. 76 | -------------------------------------------------------------------------------- /hornet-mainnet/README_AWS.md: -------------------------------------------------------------------------------- 1 | # Instructions to Set up a Chrysalis Hornet Node on AWS 2 | 3 | On the AWS Marketplace you can find the Hornet product [here](https://aws.amazon.com/marketplace/pp/B095HWF6JZ). 4 | 5 | 1. In the "Security Group Settings" before you launch the instance please click "Create New Based On Seller Settings" or make sure that ports, `8081` (Hornet's dashboard), `14265` (IOTA API), `15600` (IOTA Gossip Protocol), `14626` (Autopeering) are exposed to the Internet. 6 | 7 | 2. Run this script: `/bin/install-hornet.sh`. 8 | 9 | NB: Optionally you can pass the `-p` option to specify a multi-address peer as detailed [here](https://hornet.docs.iota.org/post_installation/peering.html). 10 | 11 | If you want to install a different Hornet Docker image / version than `iotaledger/hornet:1.2.4` you can do so by passing the `-i` option. 12 | 13 | 3. The bootstrap and installation process will be initiated. 14 | 15 | 4. Please note that the Hornet related config files are located at `one-click-tangle/hornet-mainnet/config/`. The Tangle DB files are located at `db/mainnet`. 16 | 17 | ## Dashboard 18 | 19 | You can get access to the Hornet dashboard by opening on your Web Browser the following page: `http://:8081`. 20 | 21 | The username and password of the dashboard application is `admin`. You can set a new password by executing 22 | 23 | ```console 24 | docker-compose run --rm hornet tool pwd-hash 25 | ``` 26 | and then edit the `config/config.json` file, changing the password hash and salt by the new values (under the `dashboard` section). Afterwards you will need to restart Hornet by running: 27 | 28 | ```console 29 | ./hornet.sh stop 30 | ./hornet.sh start 31 | ``` 32 | 33 | ## Peering 34 | 35 | The identity of your node is automatically generated and configured. You can find your Node P2P keys and identity in the `p2pidentity.txt` file. 36 | 37 | You can add new peers when installing (`-p` option), or later, by login into the dashboard, and then through the "Peers" menu. When installing, if no peer is specified then [autopeering](https://hornet.docs.iota.org/post_installation/peering/#autopeering) will be enabled, and your peers will be automatically discovered and configured. 38 | 39 | NB: Another option is to add a peer through the `config/peering.json` file as described [here](https://hornet.docs.iota.org/post_installation/peering.html). In that case you will need to first stop Hornet, then edit the file and finally start Hornet again. 40 | 41 | ## Sanity Checks 42 | 43 | Once the process finishes you should see at least the following docker containers up and running: 44 | 45 | ```console 46 | docker ps -a 47 | ``` 48 | 49 | ```console 50 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 51 | eec6d1dd21c5 iotaledger/hornet:1.2.4 "/app/hornet" 10 minutes ago Up 10 minutes 0.0.0.0:8081->8081/tcp, 0.0.0.0:14265->14265/tcp, 5556/tcp, 0.0.0.0:15600->15600/tcp, 14626/udp hornet 52 | ``` 53 | 54 | ## Node Operations 55 | 56 | You can stop Hornet by running: 57 | 58 | ```console 59 | ./hornet.sh stop 60 | ``` 61 | 62 | You can reinstall Hornet (**you will lose all data and configurations**) by running: 63 | 64 | ```console 65 | ./hornet.sh install 66 | ``` 67 | -------------------------------------------------------------------------------- /hornet-mainnet/hornet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to run a new Hornet Chrysalis Node 4 | # hornet.sh install .- Intalls a new Hornet Node (and starts it) 5 | # hornet.sh start .- Starts a new Hornet Node 6 | # hornet.sh stop .- Stops the Hornet Node 7 | 8 | set -e 9 | 10 | chmod +x ./utils.sh 11 | source ./utils.sh 12 | 13 | help () { 14 | echo "Installs Hornet version: $(cat docker-compose.yaml | grep image | cut -d : -f 3)" 15 | echo "usage: hornet.sh [install||start|stop] -p " 16 | } 17 | 18 | ##### Command line parameter processing 19 | 20 | command="$1" 21 | peer="" 22 | 23 | if [ $# -lt 1 ]; then 24 | echo "Illegal number of parameters" 25 | help 26 | exit 1 27 | fi 28 | 29 | if [ "$2" == "-p" ]; then 30 | peer="$3" 31 | fi 32 | 33 | if ! [ -x "$(command -v jq)" ]; then 34 | echo "jq utility not installed" 35 | echo "You can install it following the instructions at https://stedolan.github.io/jq/download/" 36 | exit 156 37 | fi 38 | 39 | HORNET_UPSTREAM="https://raw.githubusercontent.com/gohornet/hornet/mainnet/" 40 | 41 | ##### 42 | 43 | clean () { 44 | if [ -d ./db ]; then 45 | echo "Cleaning up previous DB files" 46 | sudo rm -Rf ./db 47 | fi 48 | 49 | if [ -d ./p2pstore ]; then 50 | echo "Cleaning up previous P2P files" 51 | sudo rm -Rf ./p2pstore 52 | fi 53 | 54 | if [ -d ./snapshots ]; then 55 | echo "Cleaning up previous snapshot files" 56 | sudo rm -Rf ./snapshots 57 | fi 58 | 59 | rm -f config/config.json || true 60 | rm -f config/peering.json || true 61 | rm -f config/profiles.json || true 62 | } 63 | 64 | # Sets up the necessary directories if they do not exist yet 65 | volumeSetup () { 66 | ## Directory for the Hornet DB files 67 | if ! [ -d ./db ]; then 68 | mkdir ./db 69 | mkdir ./db/mainnet 70 | fi 71 | 72 | if ! [ -d ./snapshots ]; then 73 | mkdir ./snapshots 74 | mkdir ./snapshots/mainnet 75 | fi 76 | 77 | if ! [ -d ./p2pstore ]; then 78 | mkdir ./p2pstore 79 | fi 80 | 81 | ## Change permissions so that the Tangle data can be written (hornet user) 82 | ## TODO: Check why on MacOS this cause permission problems 83 | if ! [[ "$OSTYPE" == "darwin"* ]]; then 84 | echo "Setting permissions for Hornet..." 85 | sudo chown -R 65532:65532 db 86 | sudo chown -R 65532:65532 snapshots 87 | sudo chown -R 65532:65532 p2pstore 88 | fi 89 | } 90 | 91 | startHornet () { 92 | if ! [ -f ./snapshots/mainnet/full_snapshot.bin ]; then 93 | echo "Install Hornet first with './hornet.sh install'" 94 | exit 129 95 | fi 96 | docker-compose --log-level ERROR up -d 97 | } 98 | 99 | installHornet () { 100 | clean 101 | 102 | volumeSetup 103 | 104 | cp config-template/profiles.json config/profiles.json 105 | cp config-template/config-template.json config/config.json 106 | cp config-template/peering-template.json config/peering.json 107 | 108 | cooSetup 109 | 110 | peerSetup 111 | } 112 | 113 | stopHornet () { 114 | echo "Stopping hornet..." 115 | docker-compose --log-level ERROR down -v --remove-orphans 116 | } 117 | 118 | ###################### 119 | ## Script starts here 120 | ###################### 121 | case "${command}" in 122 | "help") 123 | help 124 | ;; 125 | "install") 126 | stopHornet 127 | installHornet 128 | docker-compose --log-level ERROR up -d 129 | ;; 130 | "start") 131 | startHornet 132 | ;; 133 | "stop") 134 | stopHornet 135 | ;; 136 | *) 137 | echo "Command not Found." 138 | help 139 | exit 127; 140 | ;; 141 | esac 142 | -------------------------------------------------------------------------------- /hornet-private-net/config/profiles.json: -------------------------------------------------------------------------------- 1 | { 2 | "custom": { 3 | "caches": { 4 | "addresses": { 5 | "cacheTime": "100ms", 6 | "releaseExecutorWorkerCount": 10, 7 | "leakDetection": { 8 | "enabled": false, 9 | "maxConsumersPerObject": 50, 10 | "maxConsumerHoldTime": "30s" 11 | } 12 | }, 13 | "children": { 14 | "cacheTime": "1.5s", 15 | "releaseExecutorWorkerCount": 10, 16 | "leakDetection": { 17 | "enabled": false, 18 | "maxConsumersPerObject": 50, 19 | "maxConsumerHoldTime": "30s" 20 | } 21 | }, 22 | "indexations": { 23 | "cacheTime": "100ms", 24 | "releaseExecutorWorkerCount": 10, 25 | "leakDetection": { 26 | "enabled": false, 27 | "maxConsumersPerObject": 50, 28 | "maxConsumerHoldTime": "30s" 29 | } 30 | }, 31 | "milestones": { 32 | "cacheTime": "500ms", 33 | "releaseExecutorWorkerCount": 10, 34 | "leakDetection": { 35 | "enabled": false, 36 | "maxConsumersPerObject": 50, 37 | "maxConsumerHoldTime": "30s" 38 | } 39 | }, 40 | "messages": { 41 | "cacheTime": "1.5s", 42 | "releaseExecutorWorkerCount": 10, 43 | "leakDetection": { 44 | "enabled": false, 45 | "maxConsumersPerObject": 50, 46 | "maxConsumerHoldTime": "30s" 47 | } 48 | }, 49 | "unreferencedMessages": { 50 | "cacheTime": "100ms", 51 | "releaseExecutorWorkerCount": 10, 52 | "leakDetection": { 53 | "enabled": false, 54 | "maxConsumersPerObject": 50, 55 | "maxConsumerHoldTime": "30s" 56 | } 57 | }, 58 | "incomingMessagesFilter": { 59 | "cacheTime": "2s", 60 | "releaseExecutorWorkerCount": 10, 61 | "leakDetection": { 62 | "enabled": false, 63 | "maxConsumersPerObject": 50, 64 | "maxConsumerHoldTime": "30s" 65 | } 66 | } 67 | } 68 | }, 69 | "debug": { 70 | "caches": { 71 | "addresses": { 72 | "cacheTime": "1.5s", 73 | "releaseExecutorWorkerCount": 10, 74 | "leakDetection": { 75 | "enabled": true, 76 | "maxConsumersPerObject": 50, 77 | "maxConsumerHoldTime": "30s" 78 | } 79 | }, 80 | "children": { 81 | "cacheTime": "1.5s", 82 | "releaseExecutorWorkerCount": 10, 83 | "leakDetection": { 84 | "enabled": true, 85 | "maxConsumersPerObject": 50, 86 | "maxConsumerHoldTime": "30s" 87 | } 88 | }, 89 | "indexations": { 90 | "cacheTime": "1.5s", 91 | "releaseExecutorWorkerCount": 10, 92 | "leakDetection": { 93 | "enabled": true, 94 | "maxConsumersPerObject": 50, 95 | "maxConsumerHoldTime": "30s" 96 | } 97 | }, 98 | "milestones": { 99 | "cacheTime": "1.5s", 100 | "releaseExecutorWorkerCount": 10, 101 | "leakDetection": { 102 | "enabled": true, 103 | "maxConsumersPerObject": 50, 104 | "maxConsumerHoldTime": "30s" 105 | } 106 | }, 107 | "messages": { 108 | "cacheTime": "1.5s", 109 | "releaseExecutorWorkerCount": 10, 110 | "leakDetection": { 111 | "enabled": true, 112 | "maxConsumersPerObject": 50, 113 | "maxConsumerHoldTime": "30s" 114 | } 115 | }, 116 | "unreferencedMessages": { 117 | "cacheTime": "1.5s", 118 | "releaseExecutorWorkerCount": 10, 119 | "leakDetection": { 120 | "enabled": true, 121 | "maxConsumersPerObject": 50, 122 | "maxConsumerHoldTime": "30s" 123 | } 124 | }, 125 | "incomingMessagesFilter": { 126 | "cacheTime": "1.5s", 127 | "releaseExecutorWorkerCount": 10, 128 | "leakDetection": { 129 | "enabled": true, 130 | "maxConsumersPerObject": 50, 131 | "maxConsumerHoldTime": "30s" 132 | } 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /hornet-mainnet/config-template/profiles.json: -------------------------------------------------------------------------------- 1 | { 2 | "custom": { 3 | "caches": { 4 | "addresses": { 5 | "cacheTime": "100ms", 6 | "releaseExecutorWorkerCount": 10, 7 | "leakDetection": { 8 | "enabled": false, 9 | "maxConsumersPerObject": 50, 10 | "maxConsumerHoldTime": "30s" 11 | } 12 | }, 13 | "children": { 14 | "cacheTime": "1.5s", 15 | "releaseExecutorWorkerCount": 10, 16 | "leakDetection": { 17 | "enabled": false, 18 | "maxConsumersPerObject": 50, 19 | "maxConsumerHoldTime": "30s" 20 | } 21 | }, 22 | "indexations": { 23 | "cacheTime": "100ms", 24 | "releaseExecutorWorkerCount": 10, 25 | "leakDetection": { 26 | "enabled": false, 27 | "maxConsumersPerObject": 50, 28 | "maxConsumerHoldTime": "30s" 29 | } 30 | }, 31 | "milestones": { 32 | "cacheTime": "500ms", 33 | "releaseExecutorWorkerCount": 10, 34 | "leakDetection": { 35 | "enabled": false, 36 | "maxConsumersPerObject": 50, 37 | "maxConsumerHoldTime": "30s" 38 | } 39 | }, 40 | "messages": { 41 | "cacheTime": "1.5s", 42 | "releaseExecutorWorkerCount": 10, 43 | "leakDetection": { 44 | "enabled": false, 45 | "maxConsumersPerObject": 50, 46 | "maxConsumerHoldTime": "30s" 47 | } 48 | }, 49 | "unreferencedMessages": { 50 | "cacheTime": "100ms", 51 | "releaseExecutorWorkerCount": 10, 52 | "leakDetection": { 53 | "enabled": false, 54 | "maxConsumersPerObject": 50, 55 | "maxConsumerHoldTime": "30s" 56 | } 57 | }, 58 | "incomingMessagesFilter": { 59 | "cacheTime": "2s", 60 | "releaseExecutorWorkerCount": 10, 61 | "leakDetection": { 62 | "enabled": false, 63 | "maxConsumersPerObject": 50, 64 | "maxConsumerHoldTime": "30s" 65 | } 66 | } 67 | } 68 | }, 69 | "debug": { 70 | "caches": { 71 | "addresses": { 72 | "cacheTime": "1.5s", 73 | "releaseExecutorWorkerCount": 10, 74 | "leakDetection": { 75 | "enabled": true, 76 | "maxConsumersPerObject": 50, 77 | "maxConsumerHoldTime": "30s" 78 | } 79 | }, 80 | "children": { 81 | "cacheTime": "1.5s", 82 | "releaseExecutorWorkerCount": 10, 83 | "leakDetection": { 84 | "enabled": true, 85 | "maxConsumersPerObject": 50, 86 | "maxConsumerHoldTime": "30s" 87 | } 88 | }, 89 | "indexations": { 90 | "cacheTime": "1.5s", 91 | "releaseExecutorWorkerCount": 10, 92 | "leakDetection": { 93 | "enabled": true, 94 | "maxConsumersPerObject": 50, 95 | "maxConsumerHoldTime": "30s" 96 | } 97 | }, 98 | "milestones": { 99 | "cacheTime": "1.5s", 100 | "releaseExecutorWorkerCount": 10, 101 | "leakDetection": { 102 | "enabled": true, 103 | "maxConsumersPerObject": 50, 104 | "maxConsumerHoldTime": "30s" 105 | } 106 | }, 107 | "messages": { 108 | "cacheTime": "1.5s", 109 | "releaseExecutorWorkerCount": 10, 110 | "leakDetection": { 111 | "enabled": true, 112 | "maxConsumersPerObject": 50, 113 | "maxConsumerHoldTime": "30s" 114 | } 115 | }, 116 | "unreferencedMessages": { 117 | "cacheTime": "1.5s", 118 | "releaseExecutorWorkerCount": 10, 119 | "leakDetection": { 120 | "enabled": true, 121 | "maxConsumersPerObject": 50, 122 | "maxConsumerHoldTime": "30s" 123 | } 124 | }, 125 | "incomingMessagesFilter": { 126 | "cacheTime": "1.5s", 127 | "releaseExecutorWorkerCount": 10, 128 | "leakDetection": { 129 | "enabled": true, 130 | "maxConsumersPerObject": 50, 131 | "maxConsumerHoldTime": "30s" 132 | } 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /hornet-mainnet-k8s/hornet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: hornet-set 5 | labels: 6 | source: one-click-tangle 7 | spec: 8 | serviceName: hornet-rest 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: hornet 13 | template: 14 | metadata: 15 | labels: 16 | app: hornet 17 | spec: 18 | # restartPolicy: OnFailure 19 | terminationGracePeriodSeconds: 10 20 | initContainers: 21 | - name: create-volumes 22 | env: 23 | - name: POD_NAME 24 | valueFrom: 25 | fieldRef: 26 | fieldPath: metadata.name 27 | image: busybox 28 | command: 29 | - sh 30 | - -c 31 | args: 32 | - >- 33 | export POD_NUMBER=${POD_NAME##*-} && 34 | mkdir -p /ledger/peering && 35 | cp /peering/peering-${POD_NUMBER}.json /ledger/peering/peering.json && 36 | mkdir -p /ledger/mainnetdb && 37 | mkdir -p /ledger/snapshots && 38 | mkdir -p /ledger/p2pstore && 39 | cp /private-keys/identity-${POD_NUMBER}.key /secrets/identity.key && 40 | chown -R 65532:65532 /ledger && 41 | chown -R 65532:65532 /secrets 42 | volumeMounts: 43 | - mountPath: /ledger 44 | name: hornet-ledger 45 | - name: configuration 46 | mountPath: /peering 47 | readOnly: true 48 | - name: private-key 49 | mountPath: /private-keys 50 | readOnly: true 51 | - name: secrets-volume 52 | mountPath: /secrets 53 | readOnly: false 54 | containers: 55 | - name: hornet 56 | image: iotaledger/hornet:1.2.4 57 | envFrom: 58 | - secretRef: 59 | name: hornet-secret 60 | optional: false 61 | securityContext: 62 | runAsUser: 65532 63 | runAsGroup: 65532 64 | workingDir: /app 65 | terminationMessagePath: /dev/termination-log 66 | terminationMessagePolicy: File 67 | resources: 68 | requests: 69 | memory: "2Gi" 70 | cpu: "250m" 71 | readinessProbe: 72 | httpGet: 73 | path: /api/v1/info 74 | port: 14265 75 | initialDelaySeconds: 55 76 | livenessProbe: 77 | httpGet: 78 | # path: /health 79 | path: /api/v1/info 80 | port: 14265 81 | initialDelaySeconds: 60 82 | ports: 83 | - name: gossip 84 | protocol: TCP 85 | containerPort: 15600 86 | - name: autopeering 87 | protocol: UDP 88 | containerPort: 14626 89 | - name: rest 90 | protocol: TCP 91 | containerPort: 14265 92 | - name: dashboard 93 | protocol: TCP 94 | containerPort: 8081 95 | volumeMounts: 96 | - name: configuration 97 | mountPath: /app/config.json 98 | subPath: config.json 99 | - name: secrets-volume 100 | mountPath: /app/p2pstore/identity.key 101 | subPath: identity.key 102 | - name: hornet-ledger 103 | subPath: peering/peering.json 104 | mountPath: /app/peering.json 105 | - name: hornet-ledger 106 | subPath: mainnetdb 107 | mountPath: /app/mainnetdb 108 | - name: hornet-ledger 109 | subPath: p2pstore 110 | mountPath: /app/p2pstore 111 | - name: hornet-ledger 112 | subPath: snapshots 113 | mountPath: /app/snapshots/mainnet 114 | volumes: 115 | - name: configuration 116 | configMap: 117 | name: hornet-config 118 | - name: private-key 119 | secret: 120 | secretName: hornet-private-key 121 | - name: secrets-volume 122 | emptyDir: {} 123 | volumeClaimTemplates: 124 | - metadata: 125 | name: hornet-ledger 126 | spec: 127 | accessModes: 128 | - ReadWriteOnce 129 | resources: 130 | requests: 131 | storage: 20Gi 132 | -------------------------------------------------------------------------------- /hornet-mainnet/config-template/config-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "restAPI": { 3 | "jwtAuth": { 4 | "enabled": false, 5 | "salt": "HORNET" 6 | }, 7 | "excludeHealthCheckFromAuth": false, 8 | "publicRoutes": [ 9 | "/health", 10 | "/mqtt", 11 | "/api/v1/info", 12 | "/api/v1/tips", 13 | "/api/v1/messages*", 14 | "/api/v1/transactions*", 15 | "/api/v1/milestones*", 16 | "/api/v1/outputs*", 17 | "/api/v1/addresses*", 18 | "/api/v1/treasury", 19 | "/api/v1/receipts*", 20 | "/api/plugins/participation/events*", 21 | "/api/plugins/participation/outputs*", 22 | "/api/plugins/participation/addresses*" 23 | ], 24 | "protectedRoutes": [ 25 | "/api/v1/*", 26 | "/api/plugins/*" 27 | ], 28 | "whitelistedAddresses": [ 29 | "127.0.0.1", 30 | "::1" 31 | ], 32 | "bindAddress": "0.0.0.0:14265", 33 | "powEnabled": true, 34 | "powWorkerCount": 1, 35 | "limits": { 36 | "bodyLength": "1M", 37 | "maxResults": 1000 38 | } 39 | }, 40 | "dashboard": { 41 | "bindAddress": "0.0.0.0:8081", 42 | "auth": { 43 | "sessionTimeout": "72h", 44 | "username": "admin", 45 | "passwordHash": "a4d321654d646f4035bb1aafa98f9f032587a277e76a997a9422a830b471eb90", 46 | "passwordSalt": "c953f8eaf20f19531bc3403fee0ebb9b747ed2aeacf612b453307b0f68592e00" 47 | } 48 | }, 49 | "db": { 50 | "engine": "rocksdb", 51 | "path": "mainnetdb", 52 | "autoRevalidation": false 53 | }, 54 | "snapshots": { 55 | "depth": 50, 56 | "interval": 200, 57 | "fullPath": "snapshots/mainnet/full_snapshot.bin", 58 | "deltaPath": "snapshots/mainnet/delta_snapshot.bin", 59 | "deltaSizeThresholdPercentage": 50.0, 60 | "downloadURLs": [ 61 | { 62 | "full": "https://chrysalis-dbfiles.iota.org/snapshots/hornet/latest-full_snapshot.bin", 63 | "delta": "https://chrysalis-dbfiles.iota.org/snapshots/hornet/latest-delta_snapshot.bin" 64 | } 65 | ] 66 | }, 67 | "pruning": { 68 | "milestones": { 69 | "enabled": false, 70 | "maxMilestonesToKeep": 60480 71 | }, 72 | "size": { 73 | "enabled": true, 74 | "targetSize": "30GB", 75 | "thresholdPercentage": 10.0, 76 | "cooldownTime": "5m" 77 | }, 78 | "pruneReceipts": false 79 | }, 80 | "protocol": { 81 | "networkID": "chrysalis-mainnet", 82 | "bech32HRP": "iota", 83 | "minPoWScore": 4000, 84 | "milestonePublicKeyCount": 2, 85 | "publicKeyRanges": [ 86 | ] 87 | }, 88 | "pow": { 89 | "refreshTipsInterval": "5s" 90 | }, 91 | "requests": { 92 | "discardOlderThan": "15s", 93 | "pendingReEnqueueInterval": "5s" 94 | }, 95 | "tangle": { 96 | "milestoneTimeout": "30s" 97 | }, 98 | "tipsel": { 99 | "maxDeltaMsgYoungestConeRootIndexToCMI": 8, 100 | "maxDeltaMsgOldestConeRootIndexToCMI": 13, 101 | "belowMaxDepth": 15, 102 | "nonLazy": { 103 | "retentionRulesTipsLimit": 100, 104 | "maxReferencedTipAge": "3s", 105 | "maxChildren": 30, 106 | "spammerTipsThreshold": 0 107 | }, 108 | "semiLazy": { 109 | "retentionRulesTipsLimit": 20, 110 | "maxReferencedTipAge": "3s", 111 | "maxChildren": 2, 112 | "spammerTipsThreshold": 30 113 | } 114 | }, 115 | "node": { 116 | "alias": "HORNET node - one-click-tangle", 117 | "profile": "auto", 118 | "disablePlugins": [], 119 | "enablePlugins": [ 120 | ] 121 | }, 122 | "p2p": { 123 | "bindMultiAddresses": [ 124 | "/ip4/0.0.0.0/tcp/15600" 125 | ], 126 | "connectionManager": { 127 | "highWatermark": 10, 128 | "lowWatermark": 5 129 | }, 130 | "gossipUnknownPeersLimit": 4, 131 | "db": { 132 | "path": "p2pstore" 133 | }, 134 | "reconnectInterval": "30s" 135 | }, 136 | "p2pdisc": { 137 | "advertiseInterval": "30s", 138 | "maxDiscoveredPeerConns": 4, 139 | "rendezvousPoint": "between-two-vertices", 140 | "routingTableRefreshPeriod": "60s" 141 | }, 142 | "logger": { 143 | "level": "info", 144 | "disableCaller": true, 145 | "encoding": "console", 146 | "outputPaths": [ 147 | "stdout" 148 | ] 149 | }, 150 | "warpsync": { 151 | "advancementRange": 150 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /explorer/tangle-explorer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to deploy a Tangle Explorer component 4 | # tangle-explorer.sh install .- Installs a new Tangle Exlorer 5 | # tangle-explorer.sh start .- Starts a new Tangle Exlorer 6 | # tangle-explorer.sh update .- Updates the Tangle Exlorer 7 | # tangle-explorer.sh stop .- Stops the Tangle Exlorer 8 | 9 | set -e 10 | 11 | help () { 12 | echo "usage: tangle-explorer.sh [install|start|stop|update] [json-file-with-network-details.json] or [private-tangle-install-folder]" 13 | } 14 | 15 | if [ $# -lt 1 ]; then 16 | echo "Illegal number of parameters" 17 | help 18 | exit 1 19 | fi 20 | 21 | ### Initialization code 22 | 23 | EXPLORER_SRC=./explorer-src 24 | APP_DATA=./application-data 25 | 26 | command="$1" 27 | network_file="$2" 28 | is_config_folder=false 29 | 30 | DEFAULT_NETWORK_FILE="config/private-network.json" 31 | 32 | if [ "$command" == "install" ]; then 33 | if [ $# -lt 2 ]; then 34 | network_file="$DEFAULT_NETWORK_FILE" 35 | fi 36 | fi 37 | 38 | # Obtaining the source of the Explorer 39 | if ! [ -d $network_file ]; then 40 | if ! [ -f $network_file ]; then 41 | echo "The IOTA network definition file or private tangle installation folder does not exist" 42 | exit 1 43 | fi 44 | else 45 | is_config_folder=true 46 | folder_config="$2/config" 47 | # The copy process will leave the network configuration under this file 48 | network_file="./my-network.json" 49 | fi 50 | 51 | ################### 52 | 53 | clean () { 54 | if [ -d $EXPLORER_SRC ]; then 55 | rm -Rf $EXPLORER_SRC 56 | fi 57 | 58 | if [ -d $APP_DATA ]; then 59 | rm -Rf $APP_DATA 60 | fi 61 | } 62 | 63 | stopContainers () { 64 | echo "Stopping containers..." 65 | docker-compose --log-level ERROR down -v --remove-orphans 66 | } 67 | 68 | # Builds the network configuration file 69 | # in case only a folder with configuration files is given 70 | buildConfig() { 71 | echo "Config" 72 | 73 | echo $(cat $folder_config/../coo-milestones-public-key.txt) 74 | cp ./config/private-network.json ./my-network.json 75 | 76 | # Set the Coordinator Address 77 | sed -i 's/"coordinatorAddress": \("\).*\("\)/"coordinatorAddress": \1'$(cat $folder_config/../coo-milestones-public-key.txt)'\2/g' ./my-network.json 78 | 79 | # Set in the Front-End App configuration the API endpoint 80 | sed -i 's/"apiEndpoint": \("\).*\("\)/"apiEndpoint": \1http:\/\/localhost:4000\2/g' ./config/webapp.config.local.json 81 | } 82 | 83 | # Copies the configuration 84 | copyConfig () { 85 | if ! [ -d $APP_DATA ]; then 86 | mkdir $APP_DATA 87 | fi 88 | 89 | if ! [ -d $APP_DATA/network ]; then 90 | mkdir $APP_DATA/network 91 | fi 92 | 93 | cp $network_file ./application-data/network/private-network.json 94 | 95 | # Configuration of the API Server 96 | cp config/api.config.local.json $EXPLORER_SRC/api/src/data/config.local.json 97 | 98 | # Configuration of the Web App 99 | cp config/webapp.config.local.json $EXPLORER_SRC/client/src/assets/config/config.local.json 100 | 101 | # TODO: Check why is it really needed 102 | rm $EXPLORER_SRC/client/package-lock.json 103 | } 104 | 105 | installExplorer () { 106 | # We need to create network it will fail if it does exist 107 | set +e 108 | docker network create private-tangle 2> /dev/null 109 | set -e 110 | 111 | clean 112 | 113 | git clone https://github.com/iotaledger/explorer $EXPLORER_SRC 114 | 115 | # We stop container after having source code available otherwise docker-compose would fail 116 | stopContainers 117 | 118 | # If the input parameter is a folder with config then we need to build it 119 | if [ "$is_config_folder" = true ]; then 120 | buildConfig 121 | fi 122 | 123 | copyConfig 124 | } 125 | 126 | startExplorer () { 127 | if ! [ -d "$EXPLORER_SRC" ]; then 128 | echo "Install the Tangle explorer first with './tangle-explorer.sh install'" 129 | exit 129 130 | fi 131 | 132 | # Running the Explorer API 133 | docker-compose --log-level ERROR up -d --build 134 | } 135 | 136 | stopExplorer () { 137 | stopContainers 138 | } 139 | 140 | updateExplorer () { 141 | if ! [ -d "$EXPLORER_SRC" ]; then 142 | echo "Install the Tangle explorer first with './tangle-explorer.sh install'" 143 | exit 129 144 | fi 145 | 146 | stopExplorer 147 | 148 | cd $EXPLORER_SRC 149 | git pull 150 | 151 | startExplorer 152 | } 153 | 154 | case "${command}" in 155 | "help") 156 | help 157 | ;; 158 | "install") 159 | installExplorer 160 | startExplorer 161 | ;; 162 | "start") 163 | startExplorer 164 | ;; 165 | "stop") 166 | stopExplorer 167 | ;; 168 | "update") 169 | updateExplorer 170 | ;; 171 | *) 172 | echo "Command not Found." 173 | help 174 | exit 127; 175 | ;; 176 | esac 177 | -------------------------------------------------------------------------------- /hornet-private-net/README_AWS.md: -------------------------------------------------------------------------------- 1 | # Instructions to Set up a Private Tangle on AWS 2 | 3 | On the AWS Marketplace you can find the Private Tangle product [here](https://aws.amazon.com/marketplace/pp/B095WQQTNG). 4 | 5 | 1. In the "Security Group Settings" before you launch the instance please click "Create New Based On Seller Settings" or make sure that *TCP* ports `8081` (Hornet's dashboard), `14265` (IOTA protocol), `8082` (Tangle Explorer Frontend) and `4000` (Tangle Explorer API) are exposed to the Internet. Additionally, if you want to peer your regular Hornet Node (`node1`) with nodes in other external machines you will need to expose *TCP* port `15600` (gossip peering port). 6 | If you want your autopeering entry node to be available from the outside world you would also need to expose 7 | the *UDP* port `14626`. 8 | 9 | 2. Run this script: `/bin/install-private-tangle.sh` 10 | 11 | 3. The bootstrap and installation process will be initiated. 12 | 13 | 4. Afterwards, the Private Tangle should be up and running. You can get access to the `node1`'s Private Tangle dashboard at `http://:8081` and from such dashboard you will be able to check the status of `node1` and the rest of peered nodes (namely the coordinator, and the spammer). Also you can get access to the Tangle Explorer through `http://:8082`. 14 | 15 | 7. Please bear in mind, that it can take a little while for the nodes to be in synced state. 16 | 17 | 8. Please note that the Private Tangle related config files are located at `one-click-tangle/hornet-private-net/config/`. The Tangle DB files are located at `db/private-tangle`. 18 | 19 | 20 | # Sanity Checks 21 | 22 | Once the process finishes you should see at least the following docker containers up and running: 23 | 24 | ```console 25 | docker ps -a 26 | ``` 27 | 28 | ```console 29 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 30 | 07bbdbb89201 iotaledger/explorer-webapp "docker-entrypoint.s…" 5 seconds ago Up 2 seconds 0.0.0.0:8082->80/tcp explorer-webapp 31 | c68ca2deec5c iotaledger/explorer-api "docker-entrypoint.s…" 8 seconds ago Up 5 seconds 0.0.0.0:4000->4000/tcp explorer-api 32 | f82a28f90c71 iotaledger/hornet:1.2.4 "/app/hornet" 6 minutes ago Up 6 minutes 0.0.0.0:1883->1883/tcp, 0.0.0.0:8081->8081/tcp, 0.0.0.0:14265->14265/tcp, 14626/udp, 15600/tcp node1 33 | e0e8b6a44239 iotaledger/hornet:1.2.4 "/app/hornet" 6 minutes ago Up 6 minutes 8081/tcp, 14265/tcp, 15600/tcp, 14626/udp spammer 34 | 44fcdfd7cc5f iotaledger/hornet:1.2.4 "/app/hornet" 6 minutes ago Up 6 minutes 8081/tcp, 14265/tcp, 15600/tcp, 14626/udp coo 35 | 353b9358bde7 iotaledger/hornet:1.2.4 "/app/hornet" 3 minutes ago Up 3 minutes 1883/tcp, 8081/tcp, 14265/tcp, 15600/tcp, 0.0.0.0:14626->14626/udp node-autopeering 36 | ``` 37 | 38 | The three Hornet nodes (`coo`, `spammer` and ``node1`), the Explorer (API and Web App) and the autopeering entry node (`node-autopeering`). 39 | 40 | # Private Tangle Cryptographic materials, identities and addresses: 41 | 42 | Once the process finishes the following files should have been created for you as enumerated below. 43 | 44 | The P2P identities that can be used to peer these Nodes with other Nodes: 45 | 46 | * `coo.identity.txt`. The P2P identity of the Coordinator. 47 | * `node1.identity.txt`. The P2P identity of the node1. 48 | * `spammer.identity.txt`. The P2P identity of the Spammer. 49 | * `node-autopeering.identity.txt`. The P2P identity of the autopeering entry node. 50 | 51 | The address that holds all the IOTAs and its corresponding keys: 52 | 53 | * `key-pair.txt`. The Ed25519 Key pair corresponding to the address that holds all the IOTAs. 54 | * `address.txt`. The address that holds all IOTAs initially. 55 | 56 | The Coordinator's cryptographic materials: 57 | 58 | * `coo-milestones-key-pair.txt`. The Ed25519 key pair used by the Coordinator to sign milestones. Keep it safe! 59 | * `coo-milestones-public-key.txt`. The Ed25519 public key that can be used to verify Coordinator's milestones. 60 | 61 | The initial Private Tangle snapshot: 62 | 63 | * `snapshots/private-tangle/full_snapshot.bin`. It contains just one IOTA address that is holding all IOTAs. 64 | 65 | # Operations 66 | 67 | ## Stop 68 | 69 | You can stop your Private Tangle by running: 70 | 71 | ```console 72 | ./private-tangle.sh stop 73 | ``` 74 | 75 | ## Reinstall 76 | 77 | You can reinstall your Private Tangle (**you will lose all data and configurations**) by running: 78 | 79 | ```console 80 | ./private-tangle.sh install 81 | ``` 82 | 83 | ## Extra Nodes 84 | 85 | You can add extra Hornet nodes that will be *automatically* peered to your Private Tangle using the `private-hornet.sh` script found under the `extra-nodes` folder. The procedure is described [here](https://github.com/iotaledger/one-click-tangle/blob/chrysalis/hornet-private-net/extra-nodes/README.md). 86 | -------------------------------------------------------------------------------- /hornet-private-net/config/config-node.json: -------------------------------------------------------------------------------- 1 | { 2 | "restAPI": { 3 | "jwtAuth": { 4 | "enabled": false, 5 | "salt": "HORNET" 6 | }, 7 | "excludeHealthCheckFromAuth": false, 8 | "publicRoutes": [ 9 | "/health", 10 | "/mqtt", 11 | "/api/v1/info", 12 | "/api/v1/tips", 13 | "/api/v1/messages*", 14 | "/api/v1/transactions*", 15 | "/api/v1/milestones*", 16 | "/api/v1/outputs*", 17 | "/api/v1/addresses*", 18 | "/api/v1/treasury", 19 | "/api/v1/receipts*", 20 | "/api/plugins/participation/events*", 21 | "/api/plugins/participation/outputs*", 22 | "/api/plugins/participation/addresses*" 23 | ], 24 | "protectedRoutes": [ 25 | "/api/v1/*", 26 | "/api/plugins/*" 27 | ], 28 | "whitelistedAddresses": [ 29 | "127.0.0.1", 30 | "::1" 31 | ], 32 | "bindAddress": "0.0.0.0:14265", 33 | "powEnabled": true, 34 | "powWorkerCount": 1, 35 | "limits": { 36 | "bodyLength": "1M", 37 | "maxResults": 1000 38 | } 39 | }, 40 | "dashboard": { 41 | "bindAddress": "0.0.0.0:8081", 42 | "auth": { 43 | "sessionTimeout": "72h", 44 | "username": "admin", 45 | "passwordHash": "a4d321654d646f4035bb1aafa98f9f032587a277e76a997a9422a830b471eb90", 46 | "passwordSalt": "c953f8eaf20f19531bc3403fee0ebb9b747ed2aeacf612b453307b0f68592e00" 47 | } 48 | }, 49 | "db": { 50 | "engine": "rocksdb", 51 | "path": "/app/db", 52 | "autoRevalidation": false 53 | }, 54 | "snapshots": { 55 | "depth": 50, 56 | "interval": 200, 57 | "fullPath": "snapshots/private-tangle/full_snapshot.bin", 58 | "deltaPath": "snapshots/private-tangle/delta_snapshot.bin", 59 | "deltaSizeThresholdPercentage": 50.0 60 | }, 61 | "protocol": { 62 | "networkID": "private-tangle", 63 | "bech32HRP": "atoipt", 64 | "minPoWScore": 2000, 65 | "milestonePublicKeyCount": 1, 66 | "publicKeyRanges": [ 67 | { 68 | "key": "222b96706c2ce6be7ecbc6cc2812ff3b67d636af3da24b9bbad96593edafe917", 69 | "start": 0, 70 | "end": 0 71 | } 72 | ] 73 | }, 74 | "pow": { 75 | "refreshTipsInterval": "5s" 76 | }, 77 | "requests": { 78 | "discardOlderThan": "15s", 79 | "pendingReEnqueueInterval": "5s" 80 | }, 81 | "tangle": { 82 | "milestoneTimeout": "120s" 83 | }, 84 | "tipsel": { 85 | "maxDeltaMsgYoungestConeRootIndexToCMI": 8, 86 | "maxDeltaMsgOldestConeRootIndexToCMI": 13, 87 | "belowMaxDepth": 15, 88 | "nonLazy": { 89 | "retentionRulesTipsLimit": 100, 90 | "maxReferencedTipAge": "3s", 91 | "maxChildren": 30, 92 | "spammerTipsThreshold": 0 93 | }, 94 | "semiLazy": { 95 | "retentionRulesTipsLimit": 20, 96 | "maxReferencedTipAge": "3s", 97 | "maxChildren": 2, 98 | "spammerTipsThreshold": 30 99 | } 100 | }, 101 | "node": { 102 | "alias": "node1", 103 | "profile": "auto", 104 | "disablePlugins": [ 105 | "WarpSync", 106 | "Profiling", 107 | "Prometheus", 108 | "Spammer", 109 | "Coordinator", 110 | "ZMQ" 111 | ], 112 | "enablePlugins": [ 113 | "URTS", 114 | "RestAPI", 115 | "MQTT", 116 | "Autopeering" 117 | ] 118 | }, 119 | "p2p": { 120 | "bindMultiAddresses": [ 121 | "/ip4/0.0.0.0/tcp/15600" 122 | ], 123 | "connectionManager": { 124 | "highWatermark": 10, 125 | "lowWatermark": 5 126 | }, 127 | "gossipUnknownPeersLimit": 4, 128 | "db": { 129 | "path": "p2pstore" 130 | }, 131 | "reconnectInterval": "30s", 132 | "autopeering": { 133 | "bindAddress": "0.0.0.0:14626", 134 | "entryNodes": ["/dns/node-autopeering/udp/14626/autopeering/3rZokdSjHzEkcg3zY2ci27LuMowD9P3SQckNsQyHvc7b"], 135 | "entryNodesPreferIPv6": false, 136 | "runAsEntryNode": false 137 | } 138 | }, 139 | "p2pdisc": { 140 | "advertiseInterval": "30s", 141 | "maxDiscoveredPeerConns": 4, 142 | "rendezvousPoint": "between-two-vertices", 143 | "routingTableRefreshPeriod": "60s" 144 | }, 145 | "logger": { 146 | "level": "info", 147 | "disableCaller": true, 148 | "encoding": "console", 149 | "outputPaths": [ 150 | "stdout" 151 | ] 152 | }, 153 | "mqtt": { 154 | "bindAddress": "0.0.0.0:1883" 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /hornet-private-net/config/config-coo.json: -------------------------------------------------------------------------------- 1 | { 2 | "restAPI": { 3 | "jwtAuth": { 4 | "enabled": false, 5 | "salt": "HORNET" 6 | }, 7 | "excludeHealthCheckFromAuth": false, 8 | "publicRoutes": [ 9 | "/health", 10 | "/mqtt", 11 | "/api/v1/info", 12 | "/api/v1/tips", 13 | "/api/v1/messages*", 14 | "/api/v1/transactions*", 15 | "/api/v1/milestones*", 16 | "/api/v1/outputs*", 17 | "/api/v1/addresses*", 18 | "/api/v1/treasury", 19 | "/api/v1/receipts*", 20 | "/api/plugins/participation/events*", 21 | "/api/plugins/participation/outputs*", 22 | "/api/plugins/participation/addresses*" 23 | ], 24 | "protectedRoutes": [ 25 | "/api/v1/*", 26 | "/api/plugins/*" 27 | ], 28 | "bindAddress": "0.0.0.0:14265", 29 | "powEnabled": true, 30 | "powWorkerCount": 1, 31 | "limits": { 32 | "bodyLength": "1M", 33 | "maxResults": 1000 34 | } 35 | }, 36 | "dashboard": { 37 | "auth": { 38 | "sessionTimeout": "72h", 39 | "username": "admin", 40 | "passwordHash": "a4d321654d646f4035bb1aafa98f9f032587a277e76a997a9422a830b471eb90", 41 | "passwordSalt": "c953f8eaf20f19531bc3403fee0ebb9b747ed2aeacf612b453307b0f68592e00" 42 | } 43 | }, 44 | "db": { 45 | "engine": "rocksdb", 46 | "path": "/app/db", 47 | "autoRevalidation": false 48 | }, 49 | "snapshots": { 50 | "depth": 50, 51 | "interval": 200, 52 | "fullPath": "snapshots/private-tangle/full_snapshot.bin", 53 | "deltaPath": "snapshots/private-tangle/delta_snapshot_coo.bin", 54 | "deltaSizeThresholdPercentage": 50.0 55 | }, 56 | "protocol": { 57 | "networkID": "private-tangle", 58 | "bech32HRP": "atoipt", 59 | "minPoWScore": 2000, 60 | "milestonePublicKeyCount": 1, 61 | "publicKeyRanges": [ 62 | { 63 | "key": "222b96706c2ce6be7ecbc6cc2812ff3b67d636af3da24b9bbad96593edafe917", 64 | "start": 0, 65 | "end": 0 66 | } 67 | ] 68 | }, 69 | "pow": { 70 | "refreshTipsInterval": "5s" 71 | }, 72 | "requests": { 73 | "discardOlderThan": "15s", 74 | "pendingReEnqueueInterval": "5s" 75 | }, 76 | "tangle": { 77 | "milestoneTimeout": "120s" 78 | }, 79 | "tipsel": { 80 | "maxDeltaMsgYoungestConeRootIndexToCMI": 8, 81 | "maxDeltaMsgOldestConeRootIndexToCMI": 13, 82 | "belowMaxDepth": 15, 83 | "nonLazy": { 84 | "retentionRulesTipsLimit": 100, 85 | "maxReferencedTipAge": "3s", 86 | "maxChildren": 30, 87 | "spammerTipsThreshold": 0 88 | }, 89 | "semiLazy": { 90 | "retentionRulesTipsLimit": 20, 91 | "maxReferencedTipAge": "3s", 92 | "maxChildren": 2, 93 | "spammerTipsThreshold": 30 94 | } 95 | }, 96 | "node": { 97 | "alias": "coo", 98 | "profile": "auto", 99 | "disablePlugins": [ 100 | "WarpSync", 101 | "Spammer", 102 | "Autopeering", 103 | "ZMQ", 104 | "MQTT", 105 | "Prometheus", 106 | "Profiling" 107 | ], 108 | "enablePlugins": [ 109 | "Coordinator", 110 | "RestAPI", 111 | "URTS" 112 | ] 113 | }, 114 | "coordinator": { 115 | "stateFilePath": "./coo-state/coordinator.state", 116 | "interval": "60s", 117 | "checkpoints": { 118 | "maxTrackedMessages": 10000 119 | }, 120 | "tipsel": { 121 | "minHeaviestBranchUnreferencedMessagesThreshold": 20, 122 | "maxHeaviestBranchTipsPerCheckpoint": 10, 123 | "randomTipsPerCheckpoint": 2, 124 | "heaviestBranchSelectionTimeout": "100ms" 125 | }, 126 | "quorum": { 127 | "enabled": false, 128 | "groups": {}, 129 | "timeout": "2s" 130 | } 131 | }, 132 | "p2p": { 133 | "bindMultiAddresses": [ 134 | "/ip4/0.0.0.0/tcp/15600" 135 | ], 136 | "connectionManager": { 137 | "highWatermark": 10, 138 | "lowWatermark": 5 139 | }, 140 | "gossipUnknownPeersLimit": 4, 141 | "db": { 142 | "path": "p2pstore" 143 | }, 144 | "reconnectInterval": "30s" 145 | }, 146 | "p2pdisc": { 147 | "advertiseInterval": "30s", 148 | "maxDiscoveredPeerConns": 4, 149 | "rendezvousPoint": "between-two-vertices", 150 | "routingTableRefreshPeriod": "60s" 151 | }, 152 | "logger": { 153 | "level": "info", 154 | "disableCaller": true, 155 | "encoding": "console", 156 | "outputPaths": [ 157 | "stdout" 158 | ] 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

One Click Tangle

2 | 3 |

4 | Discord 5 | StackExchange 6 | MIT license 7 |

8 | 9 |

10 | About ◈ 11 | Prerequisites ◈ 12 | Getting started ◈ 13 | Supporting the project ◈ 14 | Joining the discussion 15 |

16 | 17 | --- 18 | 19 | ## About 20 | 21 | This repository is where the IOTA Foundation hosts the open-source code for deploying Chrysalis IOTA Nodes and Networks "in one click". If you are looking how to deploy Shimmer Nodes you should check the [Node Setup Repository](https://github.com/iotaledger/node-docker-setup). Those scripts are also compatible with Chrysalis. 22 | 23 | The code is composed of: 24 | 25 | - [**`hornet`:**](hornet-mainnet/README.md) Script to deploy a new Hornet Node connected to the mainnet. 26 | - [**`hornet-k8s`:**](hornet-mainnet-k8s/README.md) Script to deploy a set of Hornet Nodes connected to the mainnet (Kubernetes). 27 | - [**`private-tangle`:**](hornet-private-net/README.md) Script to deploy a new Private Tangle composed of Coordinator, Spammer and one regular Hornet Node. 28 | - [**`private-tangle/extra-nodes`:**](hornet-private-net/extra-nodes/README.md) Script to add extra Hornet Nodes 29 | to an existing Private Tangle. 30 | - [**`explorer`:**](explorer/README.md) Script to deploy a new [Tangle Explorer](https://github.com/iotaledger/explorer). 31 | - [**`bootstrap`:**](bootstrap/README.md) Scripts that support Deployment on the AWS Marketplace for [Hornet](https://aws.amazon.com/marketplace/pp/B095HWF6JZ) and the [Private Tangle](https://aws.amazon.com/marketplace/pp/TBD). 32 | 33 | This is beta software, so there may be issues. 34 | Please report any issues in our [issue tracker](https://github.com/iotaledger/one-click-tangle/issues/new). 35 | 36 | Related Community Projects: [Hornet Playbook](https://github.com/nuriel77/hornet-playbook) 37 | 38 | ## Prerequisites 39 | 40 | * `jq` JSON command line utility. [Download](https://stedolan.github.io/jq/download/) 41 | 42 | * [GNU Sed](https://www.gnu.org/software/sed/). 43 | 44 | Last but not least, to execute these scripts you need [Docker](https://www.docker.com) and Docker Compose. **Docker Compose** is a tool for defining and running multi-container Docker applications. A series [YAML files](./docker-compose.yaml) are used to configure the required services. This means all container services can be brought up in a single command. Docker Compose is installed by default as part of Docker for Windows and Docker for Mac, however Linux users will need to follow the instructions found [here](https://docs.docker.com/compose/install/) 45 | 46 | You can check your current **Docker** and **Docker Compose** versions using the following commands: 47 | 48 | ```console 49 | docker-compose -v 50 | docker version 51 | ``` 52 | 53 | Please ensure that you are using Docker version `18.03` or higher and Docker Compose `1.21` or higher and upgrade if 54 | necessary. 55 | 56 | ## Getting started 57 | 58 | ### Getting started - Hornet 59 | 60 | First you need to clone the Repository 61 | 62 | ``` 63 | git clone https://github.com/iotaledger/one-click-tangle 64 | ``` 65 | 66 | Afterwards you can install a Hornet Node by 67 | 68 | ``` 69 | cd hornet-mainnet 70 | chmod +x hornet.sh 71 | ./hornet.sh install 72 | ``` 73 | 74 | ### Getting started - Private Tangle 75 | 76 | First you need to clone the Repository 77 | 78 | ``` 79 | git clone https://github.com/iotaledger/one-click-tangle 80 | ``` 81 | 82 | ``` 83 | cd hornet-private-net 84 | chmod +x private-tangle.sh 85 | ./private-tangle.sh install 86 | ``` 87 | 88 | You may also want to [deploy a Tangle Explorer](./explorer). 89 | 90 | Additional instructions can be found on this [tutorial](https://wiki.iota.org/chrysalis-docs/tutorials/one_click_private_tangle). 91 | 92 | ## Supporting the project 93 | 94 | If this project has been useful to you and you feel like contributing, consider submitting a [bug report](https://github.com/iotaledger/one-click-tangle/issues/new), [feature request](https://github.com/iotaledger/one-click-tangle/issues/new) or a [pull request](https://github.com/iotaledger/one-click-tangle/pulls/). 95 | 96 | See our [contributing guidelines](.github/CONTRIBUTING.md) for more information. 97 | 98 | ## Joining the discussion 99 | 100 | If you want to get involved in the community, need help with getting set up, have any issues or just want to discuss IOTA, Distributed Registry Technology (DRT), and IoT with other people, feel free to join our [Discord](https://discord.iota.org/). 101 | -------------------------------------------------------------------------------- /hornet-private-net/config/config-spammer.json: -------------------------------------------------------------------------------- 1 | { 2 | "restAPI": { 3 | "jwtAuth": { 4 | "enabled": false, 5 | "salt": "HORNET" 6 | }, 7 | "excludeHealthCheckFromAuth": false, 8 | "publicRoutes": [ 9 | "/health", 10 | "/mqtt", 11 | "/api/v1/info", 12 | "/api/v1/tips", 13 | "/api/v1/messages*", 14 | "/api/v1/transactions*", 15 | "/api/v1/milestones*", 16 | "/api/v1/outputs*", 17 | "/api/v1/addresses*", 18 | "/api/v1/treasury", 19 | "/api/v1/receipts*", 20 | "/api/plugins/participation/events*", 21 | "/api/plugins/participation/outputs*", 22 | "/api/plugins/participation/addresses*" 23 | ], 24 | "protectedRoutes": [ 25 | "/api/v1/*", 26 | "/api/plugins/*" 27 | ], 28 | "whitelistedAddresses": [ 29 | "127.0.0.1", 30 | "::1" 31 | ], 32 | "bindAddress": "0.0.0.0:14265", 33 | "powEnabled": true, 34 | "powWorkerCount": 1, 35 | "limits": { 36 | "bodyLength": "1M", 37 | "maxResults": 1000 38 | } 39 | }, 40 | "dashboard": { 41 | "auth": { 42 | "sessionTimeout": "72h", 43 | "username": "admin", 44 | "passwordHash": "a4d321654d646f4035bb1aafa98f9f032587a277e76a997a9422a830b471eb90", 45 | "passwordSalt": "c953f8eaf20f19531bc3403fee0ebb9b747ed2aeacf612b453307b0f68592e00" 46 | } 47 | }, 48 | "db": { 49 | "engine": "rocksdb", 50 | "path": "/app/db", 51 | "autoRevalidation": false 52 | }, 53 | "snapshots": { 54 | "depth": 50, 55 | "interval": 200, 56 | "fullPath": "snapshots/private-tangle/full_snapshot.bin", 57 | "deltaPath": "snapshots/private-tangle/delta_snapshot_spammer.bin", 58 | "deltaSizeThresholdPercentage": 50.0 59 | }, 60 | "protocol": { 61 | "networkID": "private-tangle", 62 | "bech32HRP": "atoipt", 63 | "minPoWScore": 2000, 64 | "milestonePublicKeyCount": 1, 65 | "publicKeyRanges": [ 66 | { 67 | "key": "222b96706c2ce6be7ecbc6cc2812ff3b67d636af3da24b9bbad96593edafe917", 68 | "start": 0, 69 | "end": 0 70 | } 71 | ] 72 | }, 73 | "pow": { 74 | "refreshTipsInterval": "5s" 75 | }, 76 | "requests": { 77 | "discardOlderThan": "15s", 78 | "pendingReEnqueueInterval": "5s" 79 | }, 80 | "tangle": { 81 | "milestoneTimeout": "120s" 82 | }, 83 | "tipsel": { 84 | "maxDeltaMsgYoungestConeRootIndexToCMI": 8, 85 | "maxDeltaMsgOldestConeRootIndexToCMI": 13, 86 | "belowMaxDepth": 15, 87 | "nonLazy": { 88 | "retentionRulesTipsLimit": 100, 89 | "maxReferencedTipAge": "3s", 90 | "maxChildren": 30, 91 | "spammerTipsThreshold": 0 92 | }, 93 | "semiLazy": { 94 | "retentionRulesTipsLimit": 20, 95 | "maxReferencedTipAge": "3s", 96 | "maxChildren": 2, 97 | "spammerTipsThreshold": 30 98 | } 99 | }, 100 | "node": { 101 | "alias": "spammer", 102 | "profile": "auto", 103 | "disablePlugins": [ 104 | "WarpSync", 105 | "Coordinator", 106 | "Profiling", 107 | "Prometheus", 108 | "MQTT", 109 | "ZMQ" 110 | ], 111 | "enablePlugins": [ 112 | "Spammer", 113 | "URTS", 114 | "RestAPI", 115 | "Autopeering" 116 | ] 117 | }, 118 | "spammer": { 119 | "message": "one-click-tangle.", 120 | "index": "HORNET Spammer", 121 | "indexSemiLazy": "HORNET Spammer Semi-Lazy", 122 | "cpuMaxUsage": 0.8, 123 | "mpsRateLimit": 5.0, 124 | "workers": 0, 125 | "autostart": true 126 | }, 127 | "p2p": { 128 | "bindMultiAddresses": [ 129 | "/ip4/0.0.0.0/tcp/15600" 130 | ], 131 | "connectionManager": { 132 | "highWatermark": 10, 133 | "lowWatermark": 5 134 | }, 135 | "gossipUnknownPeersLimit": 4, 136 | "db": { 137 | "path": "p2pstore" 138 | }, 139 | "reconnectInterval": "30s", 140 | "autopeering": { 141 | "bindAddress": "0.0.0.0:14626", 142 | "entryNodes": ["/dns/node-autopeering/udp/14626/autopeering/3rZokdSjHzEkcg3zY2ci27LuMowD9P3SQckNsQyHvc7b"], 143 | "entryNodesPreferIPv6": false, 144 | "runAsEntryNode": false 145 | } 146 | }, 147 | "p2pdisc": { 148 | "advertiseInterval": "30s", 149 | "maxDiscoveredPeerConns": 4, 150 | "rendezvousPoint": "between-two-vertices", 151 | "routingTableRefreshPeriod": "60s" 152 | }, 153 | "logger": { 154 | "level": "error", 155 | "disableCaller": true, 156 | "encoding": "console", 157 | "outputPaths": [ 158 | "stdout" 159 | ] 160 | } 161 | } -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute to the Tangle Deployment Tools 2 | 3 | This document describes how to contribute to the Tangle Deployment Tools. 4 | 5 | We encourage everyone with knowledge of IOTA technology to contribute. 6 | 7 | Thanks! :heart: 8 | 9 |
10 | Do you have a question :question: 11 |
12 | 13 | If you have a general or technical question, you can use one of the following resources instead of submitting an issue: 14 | 15 | - [**Developer documentation:**](https://docs.iota.org/) For official information about developing with IOTA technology 16 | - [**Discord:**](https://discord.iota.org/) For real-time chats with the developers and community members 17 | - [**IOTA cafe:**](https://iota.cafe/) For technical discussions with the Research and Development Department at the IOTA Foundation 18 | - [**StackExchange:**](https://iota.stackexchange.com/) For technical and troubleshooting questions 19 |
20 | 21 |
22 | 23 |
24 | Ways to contribute :mag: 25 |
26 | 27 | To contribute to the Tangle Deployment Tools on GitHub, you can: 28 | 29 | - Report a bug 30 | - Suggest a new feature 31 | - Build a new feature 32 |
33 | 34 |
35 | 36 |
37 | Report a bug :bug: 38 |
39 | 40 | This section guides you through reporting a bug. Following these guidelines helps maintainers and the community understand the bug, reproduce the behavior, and find related bugs. 41 | 42 | ### Before reporting a bug 43 | 44 | Please check the following list: 45 | 46 | - **Do not open a GitHub issue for [security vulnerabilities](.github/SECURITY.MD)**, instead, please contact us at [security@iota.org](mailto:security@iota.org). 47 | 48 | - **Ensure the bug was not already reported** by searching on GitHub under [**Issues**](https://github.com/iotaledger/one-click-tangle/issues). If the bug has already been reported **and the issue is still open**, add a comment to the existing issue instead of opening a new one. 49 | 50 | **Note:** If you find a **Closed** issue that seems similar to what you're experiencing, open a new issue and include a link to the original issue in the body of your new one. 51 | 52 | ### Submitting A Bug Report 53 | 54 | To report a bug, [open a new issue](https://github.com/iotaledger/one-click-tangle/issues/new), and be sure to include as many details as possible, using the template. 55 | 56 | **Note:** Minor changes such as fixing a typo can but do not need an open issue. 57 | 58 | If you also want to fix the bug, submit a [pull request](#pull-requests) and reference the issue. 59 |
60 | 61 |
62 | 63 |
64 | Suggest a new feature :bulb: 65 |
66 | 67 | This section guides you through suggesting a new feature. Following these guidelines helps maintainers and the community collaborate to find the best possible way forward with your suggestion. 68 | 69 | ### Before suggesting a new feature 70 | 71 | **Ensure the feature has not already been suggested** by searching on GitHub under [**Issues**](https://github.com/iotaledger/one-click-tangle/issues). 72 | 73 | ### Suggesting a new feature 74 | 75 | To suggest a new feature, talk to the IOTA community and IOTA Foundation members on [Discord](https://discord.iota.org/). 76 | 77 | If the team members approve your feature, they will create an issue for it. 78 |
79 | 80 |
81 | 82 |
83 | Build a new feature :hammer: 84 |
85 | 86 | This section guides you through building a new feature. Following these guidelines helps give your feature the best chance of being approved and merged. 87 | 88 | ### Before building a new feature 89 | 90 | Make sure to discuss the feature on [Discord](https://discord.iota.org/). 91 | 92 | ### Building a new feature 93 | 94 | To build a new feature, check out a new branch based on the `master` branch, and be sure to consider the following: 95 | 96 | - If the feature has a public facing API, make sure to document it, using JSDoc code comments 97 |
98 | 99 |
100 | 101 |
102 | Pull requests :mega: 103 |
104 | 105 | This section guides you through submitting a pull request (PR). Following these guidelines helps give your PR the best chance of being approved and merged. 106 | 107 | ### Before submitting a pull request 108 | 109 | When creating a pull request, please follow these steps to have your contribution considered by the maintainers: 110 | 111 | - A pull request should have exactly one concern (for example one feature or one bug). If a PR addresses more than one concern, it should be split into two or more PRs. 112 | 113 | - A pull request can be merged only if it references an open issue 114 | 115 | **Note:** Minor changes such as fixing a typo can but do not need an open issue. 116 | 117 | ### Submitting a pull request 118 | 119 | The following is a typical workflow for submitting a new pull request: 120 | 121 | 1. Fork this repository 122 | 2. Create a new branch based on your fork. For example, `git checkout -b fix/my-fix` or ` git checkout -b feat/my-feature`. 123 | 3. Commit changes and push them to your fork 124 | 4. Target your pull request to be merged with `master` 125 | 126 | If all [status checks](https://help.github.com/articles/about-status-checks/) pass, and the maintainer approves the PR, it will be merged. 127 | 128 | **Note:** Reviewers may ask you to complete additional work, tests, or other changes before your pull request can be approved and merged. 129 |
130 | 131 |
132 | 133 |
134 | Code of Conduct :clipboard: 135 |
136 | 137 | This project and everyone participating in it is governed by the [IOTA Code of Conduct](.github/CODE_OF_CONDUCT.md). 138 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Code of Conduct 2 | 3 | In the IOTA community, participants from all over the world come together to create. This is made possible by the support, hard work and enthusiasm of thousands of people, including those who create and use the IOTA technology. 4 | 5 | This document offers some guidance to ensure IOTA participants can cooperate effectively in a positive and inspiring atmosphere, and to explain how together we can strengthen and support each other. 6 | 7 | This Code of Conduct is shared by all contributors and users who engage with the IOTA Foundation team and its community services. 8 | 9 | ## Overview 10 | 11 | This Code of Conduct presents a summary of the shared values and “common sense” thinking in our community. The basic social ingredients that hold our project together include: 12 | 13 | - Being considerate 14 | - Being respectful 15 | - Being collaborative 16 | - Being pragmatic 17 | - Supporting others in the community 18 | - Getting support from others in the community 19 | 20 | This Code of Conduct reflects the agreed standards of behavior for members of the IOTA community, in any social media platform, forum, mailing list, wiki, web site, discord channel, public meeting or private correspondence within the context of the IOTA Foundation team and the IOTA Tangle technology. The community acts according to the standards written down in this Code of Conduct and will defend these standards for the benefit of the community. Leaders of any group, such as moderators of social media groups, mailing lists, discord channels, forums, etc., will exercise the right to suspend access to any person who persistently breaks our shared Code of Conduct. 21 | 22 | ## Be considerate 23 | 24 | Your actions and work will affect and be used by other people and you, in turn, will depend on the work and actions of others. Any decision you take will affect other community members, and we expect you to take those consequences into account when making decisions. 25 | 26 | As a user, remember that community members work hard on their part of IOTA and take great pride in it. 27 | 28 | ## Be respectful 29 | 30 | In order for the IOTA community to stay healthy, its members must feel comfortable and accepted. Treating one another with respect is absolutely necessary for this. In a disagreement, in the first instance, assume that people mean well. 31 | 32 | We do not tolerate personal attacks, racism, sexism or any other form of discrimination. Disagreement is inevitable, from time to time, but respect for the views of others will go a long way to winning respect for your own view. Respecting other people, their work, their contributions and assuming well-meaning motivation will make community members feel comfortable and safe and will result in motivation and productivity. 33 | 34 | We expect members of our community to be respectful when dealing with other contributors, users, and communities. Remember that IOTA is an international project and that you may be unaware of important aspects of other cultures. 35 | 36 | ## Be collaborative 37 | 38 | Your feedback is important, as is its form. Poorly thought out comments can cause pain and the demotivation of other community members, but considerate discussion of problems can bring positive results. An encouraging word works wonders. 39 | 40 | ## Be pragmatic 41 | 42 | The IOTA community is pragmatic and fair. We value tangible results over having the last word in a discussion. We defend our core values like freedom and respectful collaboration, but we don’t let arguments about minor issues get in the way of achieving more important results. We are open to suggestions and welcome solutions regardless of their origin. When in doubt support a solution which helps to get things done over one which has theoretical merits, but isn’t being worked on. Use the tools and methods which help to get the job done. Let decisions be taken by those who do the work. 43 | 44 | ## Support others in the community 45 | 46 | The IOTA community is made strong by mutual respect, collaboration and pragmatic, responsible behavior. Sometimes there are situations where this has to be defended and other community members need help. 47 | 48 | If you witness others being attacked, think first about how you can offer them personal support. If you feel that the situation is beyond your ability to help individually, go privately to the victim and ask if some form of official intervention is needed. 49 | 50 | When problems do arise, consider respectfully reminding those involved of our shared Code of Conduct as a first action. Leaders are defined by their actions and can help set a good example by working to resolve issues in the spirit of this Code of Conduct before they escalate. 51 | 52 | ## Get support from others in the community 53 | 54 | Disagreements, both political and technical, happen all the time. Our community is no exception to the rule. The goal is not to avoid disagreements or differing views but to resolve them constructively. You should turn to the community to seek advice and to resolve disagreements and where possible consult the team most directly involved. 55 | 56 | Think deeply before turning a disagreement into a public dispute. If necessary, request mediation, and try to resolve differences in a less emotional medium. If you do feel that you or your work is being attacked, take your time to think things through before writing heated replies. Consider a 24-hour moratorium if emotional language is being used – a cooling-off period is sometimes all that is needed. If you really want to go a different way, then we encourage you to publish your ideas and your work, so that it can be tried and tested. 57 | 58 | This work, "IOTA Community Guidelines", is a derivative of the [Community code of conduct by ownCloud](https://owncloud.org/community/code-of-conduct/), used under [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/). "IOTA Community Guidelines" is licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) by IOTA Foundation. -------------------------------------------------------------------------------- /hornet-private-net/extra-nodes/private-hornet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to install and deploy an additional Hornet Node to a Private Tangle 4 | 5 | # private-hornet.sh install .- Installs a new Hornet Node on your Private Tangle 6 | # private-hornet.sh start .- Starts a Hornet Node of your Private Tangle 7 | # private-hornet.sh stop .- Stops a Hornet Node of your Private Tangle 8 | 9 | # must be a colon-separated string in the form 10 | # "node_name:api_port:peering_port:dashboard_port" 11 | # example: "mynode:14627:15601:8082" 12 | # if the ports are not provided the default ones (14265, 15600, 8081) will be used 13 | 14 | # Full signature and parameters is described below: 15 | # private-hornet.sh [install|start|stop] ? ? ? 16 | 17 | 18 | set -e 19 | 20 | # Common utility functions 21 | chmod +x ../utils.sh 22 | source ../utils.sh 23 | 24 | DEFAULT_API_PORT="14265" 25 | DEFAULT_PEERING_PORT="15600" 26 | DEFAULT_DASHBOARD_PORT="8081" 27 | 28 | help () { 29 | echo "Installs an extra node based on Hornet version: $(cat docker-compose.yaml | grep image | cut -d : -f 3)" 30 | echo "usage: private-hornet.sh [install|start|stop] ? ? ?" 31 | } 32 | 33 | if [ $# -lt 2 ]; then 34 | echo "Illegal number of parameters" 35 | help 36 | exit 1 37 | fi 38 | 39 | # Prepare all execution variables 40 | 41 | command="$1" 42 | node_details="$2" 43 | 44 | # Split the node details string 45 | IFS=':' 46 | read -a node_params <<< "$node_details" 47 | 48 | # Unless a port is specified no port will be open to the host 49 | 50 | node_name="${node_params[0]}" 51 | api_port="${node_params[1]}" 52 | peering_port="${node_params[2]}" 53 | dashboard_port="${node_params[3]}" 54 | 55 | if [ -n "$3" ]; then 56 | coo_public_key="$3" 57 | else 58 | if [ -f ../coo-milestones-public-key.txt ]; then 59 | coo_public_key=$(cat ../coo-milestones-public-key.txt | tr -d "\n") 60 | else 61 | echo "Please provide the coordinator's public key" 62 | exit 131 63 | fi 64 | fi 65 | 66 | if [ -n "$4" ]; then 67 | # We determine whether the address is a peer address or an entry node address 68 | if [[ "$4" =~ .*"\/autopeering\/".* ]]; then 69 | entry_node="$4" 70 | else 71 | peer_address="$4" 72 | fi 73 | else # If no peer address or autopeering entry node provided then autopeering is configured 74 | if [ -f ../node-autopeering.identity.txt ]; then 75 | entry_node="\/dns\/node-autopeering\/udp\/14626\/autopeering\/$(getAutopeeringID ../node-autopeering.identity.txt)" 76 | else 77 | echo "Please provide a peering address or an autopeering entry node" 78 | exit 132 79 | fi 80 | fi 81 | 82 | if [ -n "$5" ]; then 83 | snapshot_file="$5" 84 | else 85 | if [ -f ../snapshots/private-tangle/full_snapshot.bin ]; then 86 | snapshot_file="../../../snapshots/private-tangle/full_snapshot.bin" 87 | else 88 | echo "Please provide a snapshot file of your Private Tangle" 89 | exit 133 90 | fi 91 | fi 92 | 93 | 94 | # Basic bootstrapping of folders for our Node 95 | 96 | if ! [ -d ./nodes ]; then 97 | mkdir ./nodes 98 | fi 99 | 100 | if ! [ -d ./nodes/"$node_name" ]; then 101 | mkdir ./nodes/"$node_name" 102 | fi 103 | 104 | cd ./nodes/"$node_name" 105 | 106 | clean () { 107 | # We stop any container named as our node 108 | docker rm -f "$node_name" 2> /dev/null 109 | 110 | if [ -d ./db ]; then 111 | sudo rm -Rf ./db/* 112 | fi 113 | 114 | if [ -d ./p2pstore ]; then 115 | sudo rm -Rf ./p2pstore/* 116 | fi 117 | 118 | if [ -d ./config ]; then 119 | sudo rm -Rf ./config/* 120 | fi 121 | 122 | if [ -d ./snapshots/private-tangle ]; then 123 | sudo rm -Rf ./snapshots/private-tangle/* 124 | fi 125 | } 126 | 127 | # Sets up the necessary directories if they do not exist yet 128 | volumeSetup () { 129 | if ! [ -d ./config ]; then 130 | mkdir ./config 131 | fi 132 | 133 | if ! [ -d ./db ]; then 134 | mkdir ./db 135 | fi 136 | 137 | # P2P 138 | if ! [ -d ./p2pstore ]; then 139 | mkdir ./p2pstore 140 | fi 141 | 142 | if ! [ -d ./snapshots ]; then 143 | mkdir ./snapshots 144 | fi 145 | 146 | if ! [ -d ./snapshots/private-tangle ]; then 147 | mkdir ./snapshots/private-tangle 148 | fi 149 | 150 | ## Change permissions so that the Tangle data can be written (hornet user) 151 | ## TODO: Check why on MacOS this cause permission problems 152 | if ! [[ "$OSTYPE" == "darwin"* ]]; then 153 | echo "Setting permissions for Hornet..." 154 | sudo chown -R 65532:65532 ./db 155 | sudo chown -R 65532:65532 ./p2pstore 156 | sudo chown -R 65532:65532 ./snapshots 157 | fi 158 | } 159 | 160 | bootstrapFiles () { 161 | cp ../../docker-compose.yaml . 162 | sed -i 's/node/'$node_name'/g' docker-compose.yaml 163 | 164 | local ports_init_str=" ports:" 165 | 166 | # Setting up the open ports to the host 167 | local ports="$ports_init_str" 168 | local separator=" " 169 | 170 | if [ -n "$api_port" ]; then 171 | local api_str="${separator}- \"0.0.0.0:${api_port}:${DEFAULT_API_PORT}\"" 172 | ports="${ports}"$'\n'"${api_str}" 173 | fi 174 | 175 | if [ -n "$peering_port" ]; then 176 | local peering_str="${separator}- \"0.0.0.0:${peering_port}:${DEFAULT_PEERING_PORT}\"" 177 | ports="${ports}"$'\n'"${peering_str}" 178 | fi 179 | 180 | if [ -n "$dashboard_port" ]; then 181 | local dashboard_str="${separator}- \"0.0.0.0:${dashboard_port}:${DEFAULT_DASHBOARD_PORT}\"" 182 | ports="${ports}"$'\n'"${dashboard_str}" 183 | fi 184 | 185 | # If no ports are set we do not concat anything 186 | if ! [ "$ports" == "$ports_init_str" ]; then 187 | echo "$ports" >> docker-compose.yaml 188 | fi 189 | 190 | cp ../../../config/config-node.json ./config/config.json 191 | sed -i 's/node1/'$node_name'/g' ./config/config.json 192 | 193 | cp ../../../config/profiles.json ./config/profiles.json 194 | cp ../../peering.json ./config/peering.json 195 | 196 | if ! [[ "$OSTYPE" == "darwin"* ]]; then 197 | sudo cp "$snapshot_file" ./snapshots/private-tangle 198 | sudo chown -R 65532:65532 ./snapshots/private-tangle 199 | else 200 | cp "$snapshot_file" ./snapshots/private-tangle 201 | fi 202 | } 203 | 204 | installNode () { 205 | # Ensure the script does not stop if it has not been pruned 206 | set +e 207 | docker network create "private-tangle" 208 | set -e 209 | 210 | # First of all volumes have to be set up 211 | volumeSetup 212 | 213 | # A new installation implies cleaning files 214 | clean 215 | 216 | bootstrapFiles 217 | 218 | # P2P identity is generated 219 | setupIdentity 220 | 221 | # Peering of the nodes is configured 222 | if [ -n "$peer_address" ]; then 223 | echo "Setting up peer node: $peer_address" 224 | setupPeering 225 | else 226 | echo "Setting up autopeering entry node: $entry_node" 227 | setupAutopeering 228 | fi 229 | 230 | # Coordinator set up 231 | setupCoordinator 232 | 233 | # And finally containers are started 234 | startContainer 235 | } 236 | 237 | startContainer () { 238 | # Run a regular node 239 | docker-compose --log-level ERROR up -d "$node_name" 240 | } 241 | 242 | ### 243 | ### Sets the Coordinator address 244 | ### 245 | setupCoordinator () { 246 | setCooPublicKey "$coo_public_key" "./config/config.json" 247 | } 248 | 249 | ### 250 | ### Sets up the identities of the different nodes 251 | ### 252 | setupIdentity () { 253 | generateP2PIdentity "$node_name" identity.txt 254 | } 255 | 256 | # Sets up the identity of the peers 257 | setupPeerIdentity () { 258 | local peerName1="$1" 259 | local peerAddr="$2" 260 | 261 | local peer_conf_file="$3" 262 | 263 | cat < "$peer_conf_file" 264 | { 265 | "peers": [ 266 | { 267 | "alias": "$peerName1", 268 | "multiAddress": "$peerAddr" 269 | } 270 | ] 271 | } 272 | EOF 273 | 274 | } 275 | 276 | ### 277 | ### Sets the peering configuration 278 | ### 279 | setupPeering () { 280 | local node1_peerID=$(getPeerID identity.txt) 281 | 282 | setupPeerIdentity "peer1" "$peer_address" ./config/peering.json 283 | if ! [[ "$OSTYPE" == "darwin"* ]]; then 284 | sudo chown 65532:65532 ./config/peering.json 285 | fi 286 | } 287 | 288 | ### 289 | ### Sets the peering configuration 290 | ### 291 | setupAutopeering () { 292 | setEntryNode $entry_node ./config/config.json 293 | } 294 | 295 | stopContainers () { 296 | echo "Stopping containers..." 297 | docker-compose --log-level ERROR down -v --remove-orphans 298 | } 299 | 300 | stopNode () { 301 | if ! [ -f ./db/tangle/LOG ]; then 302 | echo "Install your Node first with './private-hornet.sh install'" 303 | exit 128 304 | fi 305 | 306 | stopContainers 307 | } 308 | 309 | startNode () { 310 | if ! [ -f ./db/tangle/LOG ]; then 311 | echo "Install your Node first with './private-hornet.sh install'" 312 | exit 128 313 | fi 314 | 315 | startContainer 316 | } 317 | 318 | case "${command}" in 319 | "help") 320 | help 321 | ;; 322 | "install") 323 | installNode 324 | ;; 325 | "start") 326 | startNode 327 | ;; 328 | "stop") 329 | stopNode 330 | ;; 331 | *) 332 | echo "Command not Found." 333 | help 334 | exit 127; 335 | ;; 336 | esac 337 | -------------------------------------------------------------------------------- /hornet-mainnet-k8s/hornet-k8s.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to deploy a new Hornet Chrysalis Node on Kubernetes 4 | # hornet.sh deploy .- Deploys a new Hornet Node on the cluster 5 | # hornet.sh scale .- Scales Hornet 6 | # hornet.sh undeploy .- Undeploys the Hornet Node 7 | 8 | set -e 9 | 10 | help () { 11 | echo "usage: hornet-k8s.sh [deploy|scale|undeploy]" 12 | echo "Parameter: NAMESPACE=" 13 | echo "Parameter: INSTANCES=" 14 | echo "Parameter: PEER=" 15 | echo "Parameter: INGRESS_CLASS=" 16 | } 17 | 18 | ##### Command line parameter processing 19 | 20 | command="$1" 21 | peer="$PEER" 22 | namespace="$NAMESPACE" 23 | declare -i instances=1 24 | declare -i replicas=0 25 | ingress_class="$INGRESS_CLASS" 26 | 27 | configmap_name="hornet-config" 28 | 29 | if [ -z "$namespace" ]; then 30 | namespace="tangle" 31 | fi 32 | 33 | if ! [ -z "$INSTANCES" ]; then 34 | instances=$INSTANCES 35 | fi 36 | 37 | if [ -z "$ingress_class" ]; then 38 | ingress_class="nginx" 39 | fi 40 | 41 | if [ $# -lt 1 ]; then 42 | echo "Illegal number of parameters" 43 | help 44 | exit 1 45 | fi 46 | 47 | if ! [ -x "$(command -v jq)" ]; then 48 | echo "jq utility not installed" 49 | echo "You can install it following the instructions at https://stedolan.github.io/jq/download/" 50 | exit 156 51 | fi 52 | 53 | if ! [ -x "$(command -v openssl)" ]; then 54 | echo "openssl not installed" 55 | echo "You can install it following instructions at https://formulae.brew.sh/formula/openssl@1.1" 56 | exit 156 57 | fi 58 | 59 | if ! [ -x "$(command -v kubectl)" ]; then 60 | echo "kubectl utility not installed" 61 | echo "You can install it following the instructions at https://kubernetes.io/docs/tasks/tools/" 62 | exit 158 63 | fi 64 | 65 | ##### 66 | 67 | hornet_base_dir="../hornet-mainnet" 68 | 69 | chmod +x $hornet_base_dir/utils.sh 70 | source $hornet_base_dir/utils.sh 71 | 72 | # P2P identities of the nodes 73 | declare -a p2p_identities 74 | 75 | createSecret () { 76 | # We remove the Dashboard secret from the config 77 | cat config/config-template.json \ 78 | | jq 'del(.dashboard.auth.passwordHash) | del(.dashboard.auth.passwordSalt)' - \ 79 | > config/config.json 80 | 81 | # Now these secrets are stored on a Secret 82 | local dashboard_hash=$(cat config/config-template.json | jq -r '.dashboard.auth.passwordHash' -) 83 | local dashboard_salt=$(cat config/config-template.json | jq -r '.dashboard.auth.passwordSalt' -) 84 | 85 | rm config/config-template.json 86 | 87 | kubectl -n $namespace create secret generic hornet-secret --from-literal='DASHBOARD_AUTH_PASSWORDHASH='"$dashboard_hash" \ 88 | --from-literal='DASHBOARD_AUTH_PASSWORDSALT='"$dashboard_salt" --dry-run=client -o yaml | kubectl apply -f - 89 | } 90 | 91 | createPrivateKeys () { 92 | mkdir -p config/keys 93 | 94 | # for each of the instances a new secret with private key is created 95 | for (( i=0; i config/peering-$i.json 156 | done 157 | 158 | if [ -f config/peering.json ]; then 159 | # Peering config of the first node 160 | mv config/peering.json config/peering-0.json 161 | fi 162 | 163 | echo "Nodes peered" 164 | } 165 | 166 | deleteNodePortServices () { 167 | for (( i=0; i<$instances; i++ )) 168 | do 169 | kubectl -n $namespace delete service hornet-"$i" 170 | done 171 | } 172 | 173 | initialise () { 174 | # Resetting previous state 175 | rm -Rf config/keys/* 176 | rm -Rf config/peering*.json 177 | 178 | cp $hornet_base_dir/config-template/profiles.json config/profiles.json 179 | cp $hornet_base_dir/config-template/config-template.json config/config-template.json 180 | cp $hornet_base_dir/config-template/peering-template.json config/peering.json 181 | } 182 | 183 | deployHornet () { 184 | initialise 185 | 186 | # Namespace on which the node or nodes will be living 187 | kubectl create namespace $namespace --dry-run=client -o yaml | kubectl apply -f - 188 | 189 | createSecret 190 | createPrivateKeys 191 | 192 | cooSetup 193 | 194 | peerSetup 195 | 196 | # Now we peer the nodes among themselves 197 | peerNodes 198 | 199 | # Config Map is created or overwritten 200 | kubectl -n $namespace create configmap $configmap_name --from-file=config --dry-run=client -o yaml | kubectl apply -f - 201 | 202 | # Service, Ingress associated and Statefulset associated 203 | kubectl apply -n $namespace -f hornet-rest-service.yaml 204 | createStatefulSet 205 | 206 | kubectl apply -n $namespace -f hornet-ingress.yaml 207 | kubectl annotate -f hornet-ingress.yaml -n $namespace --overwrite kubernetes.io/ingress.class=$ingress_class 208 | 209 | # Finally the NodePort services are created 210 | createNodePortServices 211 | } 212 | 213 | undeployHornet () { 214 | kubectl delete -n $namespace -f hornet-ingress.yaml 215 | kubectl delete -n $namespace -f hornet-rest-service.yaml 216 | deleteNodePortServices 217 | kubectl delete -n $namespace -f hornet.yaml 218 | kubectl delete -n $namespace configmap hornet-config 219 | kubectl delete -n $namespace secret hornet-secret 220 | kubectl delete -n $namespace secret hornet-private-key 221 | } 222 | 223 | scaleHornet () { 224 | # In order to scale we need to check whether the set already exists 225 | set +e 226 | kubectl get statefulsets/hornet-set -n $namespace > /dev/null 2>&1 227 | if ! [ $? -eq 0 ]; then 228 | echo "Error: Statefulset 'hornet-set' does not exist on namespace '$namespace'. Deploy first" 229 | exit 400 230 | fi 231 | set -e 232 | 233 | # First we need to know whether we are upscaling or downscaling 234 | # If upscaling we need to generate additional secrets and additional peering configuration 235 | replicas=$(kubectl get statefulsets/hornet-set -n $namespace -o jsonpath='{.spec.replicas}' | tr -d '\r\n') 236 | if [ $instances -gt $replicas ]; then 237 | # We create additional secrets if needed 238 | createPrivateKeys 239 | # Now we peer the nodes among themselves 240 | peerNodes 241 | fi 242 | 243 | # Config Map has to be recreated so that the new peering info is provided 244 | kubectl -n $namespace create configmap $configmap_name --from-file=config --dry-run=client -o yaml | kubectl apply -f - 245 | 246 | kubectl scale -n $namespace statefulsets hornet-set --replicas=$instances 247 | # Finally the NodePort services are created 248 | createNodePortServices 249 | } 250 | 251 | ###################### 252 | ## Script starts here 253 | ###################### 254 | case "${command}" in 255 | "help") 256 | help 257 | ;; 258 | "deploy") 259 | deployHornet 260 | ;; 261 | "undeploy") 262 | undeployHornet 263 | ;; 264 | "scale") 265 | scaleHornet 266 | ;; 267 | *) 268 | echo "Command not Found." 269 | help 270 | exit 127; 271 | ;; 272 | esac 273 | -------------------------------------------------------------------------------- /hornet-private-net/private-tangle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to run a new Private Tangle 4 | # private-tangle.sh install .- Installs a new Private Tangle 5 | # private-tangle.sh start .- Starts a new Private Tangle 6 | # private-tangle.sh stop .- Stops the Tangle 7 | 8 | set -e 9 | 10 | chmod +x ./utils.sh 11 | source ./utils.sh 12 | 13 | help () { 14 | echo "Installs Private Tangle based on Hornet version: $(cat docker-compose.yaml | grep image | cut -d : -f 3)" 15 | echo "usage: private-tangle.sh [start|stop|install] " 16 | } 17 | 18 | if [ $# -lt 1 ]; then 19 | echo "Illegal number of parameters" 20 | help 21 | exit 1 22 | fi 23 | 24 | command="$1" 25 | 26 | ip_address=$(echo $(dig +short myip.opendns.com @resolver1.opendns.com)) 27 | COO_BOOTSTRAP_WAIT=10 28 | 29 | if [ -n "$2" ]; then 30 | COO_BOOTSTRAP_WAIT="$2" 31 | fi 32 | 33 | clean () { 34 | # TODO: Differentiate between start, restart and remove 35 | stopContainers 36 | 37 | # We need sudo here as the files are going to be owned by the hornet user 38 | if [ -f ./db/private-tangle/coordinator.state ]; then 39 | sudo rm ./db/private-tangle/coordinator.state 40 | fi 41 | 42 | if [ -d ./db/private-tangle ]; then 43 | cd ./db/private-tangle 44 | removeSubfolderContent "coo.db" "node1.db" "spammer.db" "node-autopeering.db" 45 | cd ../.. 46 | fi 47 | 48 | if [ -d ./p2pstore ]; then 49 | cd ./p2pstore 50 | removeSubfolderContent coo node1 spammer "node-autopeering" 51 | cd .. 52 | fi 53 | 54 | if [ -d ./snapshots/private-tangle ]; then 55 | sudo rm -Rf ./snapshots/private-tangle/* 56 | fi 57 | 58 | # We need to do this so that initially the permissions are user's permissions 59 | resetPeeringFile config/peering-node.json 60 | resetPeeringFile config/peering-spammer.json 61 | } 62 | 63 | # Sets up the necessary directories if they do not exist yet 64 | volumeSetup () { 65 | ## Directories for the Tangle DB files 66 | if ! [ -d ./db ]; then 67 | mkdir ./db 68 | fi 69 | 70 | if ! [ -d ./db/private-tangle ]; then 71 | mkdir ./db/private-tangle 72 | fi 73 | 74 | cd ./db/private-tangle 75 | createSubfolders coo.db spammer.db node1.db node-autopeering.db 76 | cd ../.. 77 | 78 | # Snapshots 79 | if ! [ -d ./snapshots ]; then 80 | mkdir ./snapshots 81 | fi 82 | 83 | if ! [ -d ./snapshots/private-tangle ]; then 84 | mkdir ./snapshots/private-tangle 85 | fi 86 | 87 | # P2P 88 | if ! [ -d ./p2pstore ]; then 89 | mkdir ./p2pstore 90 | fi 91 | 92 | cd ./p2pstore 93 | createSubfolders coo spammer node1 node-autopeering 94 | cd .. 95 | 96 | ## Change permissions so that the Tangle data can be written (hornet user) 97 | ## TODO: Check why on MacOS this cause permission problems 98 | if ! [[ "$OSTYPE" == "darwin"* ]]; then 99 | echo "Setting permissions for Hornet..." 100 | sudo chown -R 65532:65532 db 101 | sudo chown -R 65532:65532 snapshots 102 | sudo chown -R 65532:65532 p2pstore 103 | fi 104 | } 105 | 106 | installTangle () { 107 | # First of all volumes have to be set up 108 | volumeSetup 109 | 110 | clean 111 | 112 | # The network is created to support the containers 113 | docker network prune -f 114 | # Ensure the script does not stop if it has not been pruned 115 | set +e 116 | docker network create "private-tangle" 117 | set -e 118 | 119 | # When we install we ensure container images are updated 120 | updateContainers 121 | 122 | # Initial snapshot 123 | generateSnapshot 124 | 125 | # P2P identities are generated 126 | setupIdentities 127 | 128 | # Peering of the nodes is configured 129 | setupPeering 130 | 131 | # Autopeering entry node is configured 132 | setupAutopeering 133 | 134 | # Autopeering entry node is started 135 | startAutopeering 136 | 137 | # Coordinator set up 138 | setupCoordinator 139 | 140 | # And finally containers are started 141 | startContainers 142 | } 143 | 144 | startContainers () { 145 | # Run the coordinator 146 | docker-compose --log-level ERROR up -d coo 147 | 148 | # Run the spammer 149 | docker-compose --log-level ERROR up -d spammer 150 | 151 | # Run a regular node 152 | docker-compose --log-level ERROR up -d node 153 | } 154 | 155 | updateContainers () { 156 | docker-compose pull 157 | } 158 | 159 | ### 160 | ### Generates the initial snapshot 161 | ### 162 | generateSnapshot () { 163 | echo "Generating an initial snapshot..." 164 | # First a key pair is generated 165 | docker-compose run --rm node tool ed25519-key > key-pair.txt 166 | 167 | # Extract the public key use to generate the address 168 | local public_key="$(getPublicKey key-pair.txt)" 169 | 170 | # Generate the address 171 | cat key-pair.txt | awk -F : '{if ($1 ~ /ed25519 address/) print $2}' \ 172 | | sed "s/ \+//g" | tr -d "\n" | tr -d "\r" > address.txt 173 | 174 | # Generate the snapshot 175 | cd snapshots/private-tangle 176 | docker-compose run --rm -v "$PWD:/output_dir" node tool snap-gen --networkID "private-tangle"\ 177 | --mintAddress "$(cat ../../address.txt)" --treasuryAllocation 1000000000 --outputPath /output_dir/full_snapshot.bin 178 | 179 | echo "Initial Ed25519 Address generated. You can find the keys at key-pair.txt and the address at address.txt" 180 | 181 | cd .. && cd .. 182 | } 183 | 184 | ### 185 | ### Sets the Coordinator up by creating a key pair 186 | ### 187 | setupCoordinator () { 188 | local coo_key_pair_file=coo-milestones-key-pair.txt 189 | 190 | docker-compose run --rm node tool ed25519-key > "$coo_key_pair_file" 191 | # Private Key is exported as it is needed to run the Coordinator 192 | export COO_PRV_KEYS="$(getPrivateKey $coo_key_pair_file)" 193 | 194 | local coo_public_key="$(getPublicKey $coo_key_pair_file)" 195 | echo "$coo_public_key" > coo-milestones-public-key.txt 196 | 197 | setCooPublicKey "$coo_public_key" config/config-coo.json 198 | setCooPublicKey "$coo_public_key" config/config-node.json 199 | setCooPublicKey "$coo_public_key" config/config-spammer.json 200 | 201 | bootstrapCoordinator 202 | } 203 | 204 | # Bootstraps the coordinator 205 | bootstrapCoordinator () { 206 | echo "Bootstrapping the Coordinator..." 207 | # Need to do it again otherwise the coo will not bootstrap 208 | if ! [[ "$OSTYPE" == "darwin"* ]]; then 209 | sudo chown -R 65532:65532 p2pstore 210 | fi 211 | 212 | # Bootstrap the coordinator 213 | docker-compose run -d --rm -e COO_PRV_KEYS=$COO_PRV_KEYS coo --cooBootstrap --cooStartIndex 0 > coo.bootstrap.container 214 | 215 | # Waiting for coordinator bootstrap 216 | # We guarantee that if bootstrap has not finished yet we sleep another time 217 | # for a few seconds more until bootstrap has been performed 218 | bootstrapped=1 219 | bootstrap_tick=$COO_BOOTSTRAP_WAIT 220 | echo "Waiting for $bootstrap_tick seconds ... ⏳" 221 | sleep $bootstrap_tick 222 | docker logs $(cat ./coo.bootstrap.container) 2>&1 | grep "milestone issued (1)" 223 | bootstrapped=$? 224 | 225 | if [ $bootstrapped -eq 0 ]; then 226 | echo "Coordinator bootstrapped!" 227 | docker kill -s SIGINT $(cat ./coo.bootstrap.container) 228 | echo "Waiting coordinator bootstrap to stop gracefully..." 229 | sleep 10 230 | docker rm $(cat ./coo.bootstrap.container) 231 | rm ./coo.bootstrap.container 232 | else 233 | echo "Error. Coordinator has not been boostrapped." 234 | clean 235 | exit 127 236 | fi 237 | } 238 | 239 | # Generates the P2P identities of the Nodes 240 | generateP2PIdentities () { 241 | generateP2PIdentity node node1.identity.txt 242 | generateP2PIdentity coo coo.identity.txt 243 | generateP2PIdentity spammer spammer.identity.txt 244 | 245 | # Identity of the autopeering node 246 | generateP2PIdentity node-autopeering node-autopeering.identity.txt 247 | } 248 | 249 | ### 250 | ### Sets up the identities of the different nodes 251 | ### 252 | setupIdentities () { 253 | generateP2PIdentities 254 | } 255 | 256 | # Sets up the identity of the peers 257 | setupPeerIdentity () { 258 | local peerName1="$1" 259 | local peerID1="$2" 260 | 261 | local peerName2="$3" 262 | local peerID2="$4" 263 | 264 | local peer_conf_file="$5" 265 | 266 | cat < "$peer_conf_file" 267 | { 268 | "peers": [ 269 | { 270 | "alias": "$peerName1", 271 | "multiAddress": "/dns/$peerName1/tcp/15600/p2p/$peerID1" 272 | }, 273 | { 274 | "alias": "$peerName2", 275 | "multiAddress": "/dns/$peerName2/tcp/15600/p2p/$peerID2" 276 | } 277 | ] 278 | } 279 | EOF 280 | 281 | } 282 | 283 | ### 284 | ### Sets the peering configuration 285 | ### 286 | setupPeering () { 287 | local node1_peerID=$(getPeerID node1.identity.txt) 288 | local coo_peerID=$(getPeerID coo.identity.txt) 289 | local spammer_peerID=$(getPeerID spammer.identity.txt) 290 | 291 | setupPeerIdentity "node1" "$node1_peerID" "spammer" "$spammer_peerID" config/peering-coo.json 292 | setupPeerIdentity "node1" "$node1_peerID" "coo" "$coo_peerID" config/peering-spammer.json 293 | setupPeerIdentity "coo" "$coo_peerID" "spammer" "$spammer_peerID" config/peering-node.json 294 | 295 | # We need this so that the peering can be properly updated 296 | if ! [[ "$OSTYPE" == "darwin"* ]]; then 297 | sudo chown 65532:65532 config/peering-node.json 298 | sudo chown 65532:65532 config/peering-spammer.json 299 | fi 300 | } 301 | 302 | ### 303 | ### Sets the autopeering configuration 304 | ### 305 | setupAutopeering () { 306 | local entry_peerID=$(getAutopeeringID node-autopeering.identity.txt) 307 | local multiaddr="\/dns\/node-autopeering\/udp\/14626\/autopeering\/$entry_peerID" 308 | 309 | setEntryNode $multiaddr config/config-node.json 310 | setEntryNode $multiaddr config/config-spammer.json 311 | } 312 | 313 | startAutopeering () { 314 | # Run the autopeering entry node 315 | echo "Starting autopeering entry node ..." 316 | docker-compose --log-level ERROR up -d node-autopeering 317 | sleep 5 318 | } 319 | 320 | stopContainers () { 321 | echo "Stopping containers..." 322 | docker-compose --log-level ERROR down -v --remove-orphans 323 | } 324 | 325 | startTangle () { 326 | if ! [ -f ./snapshots/private-tangle/full_snapshot.bin ]; then 327 | echo "Install your Private Tangle first with './private-tangle.sh install'" 328 | exit 128 329 | fi 330 | 331 | startAutopeering 332 | 333 | export COO_PRV_KEYS="$(getPrivateKey coo-milestones-key-pair.txt)" 334 | startContainers 335 | } 336 | 337 | case "${command}" in 338 | "help") 339 | help 340 | ;; 341 | "install") 342 | installTangle 343 | ;; 344 | "start") 345 | startTangle 346 | ;; 347 | "stop") 348 | stopContainers 349 | ;; 350 | *) 351 | echo "Command not Found." 352 | help 353 | exit 127; 354 | ;; 355 | esac 356 | --------------------------------------------------------------------------------