diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 5600e5b028..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,271 +0,0 @@ -version: 2.1 -commands: - setup_environment: - description: "Setup testing environment" - parameters: - cache_key: - type: string - default: snarkos-stable-cache - steps: - - run: set -e - - setup_remote_docker - - run: - name: Prepare environment and install dependencies - command: | - export SCCACHE_CACHE_SIZE=200M - export WORK_DIR="$CIRCLE_WORKING_DIRECTORY/.cache/sccache" - export SCCACHE_DIR="$CIRCLE_WORKING_DIRECTORY/.cache/sccache" - mkdir -p "$CIRCLE_WORKING_DIRECTORY/.bin" - wget https://github.com/mozilla/sccache/releases/download/0.2.13/sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz - tar -C "$CIRCLE_WORKING_DIRECTORY/.bin" -xvf sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz - mv $CIRCLE_WORKING_DIRECTORY/.bin/sccache-0.2.13-x86_64-unknown-linux-musl/sccache $CIRCLE_WORKING_DIRECTORY/.bin/sccache - export PATH="$PATH:$CIRCLE_WORKING_DIRECTORY/.bin" - export RUSTC_WRAPPER="sccache" - rm -rf "$CIRCLE_WORKING_DIRECTORY/.cargo/registry" - sudo apt-get update && sudo apt-get install -y clang llvm-dev llvm pkg-config xz-utils make libssl-dev libssl-dev - - restore_cache: - keys: - - << parameters.cache_key >> - - clear_environment: - description: "Clear environment" - parameters: - cache_key: - type: string - default: snarkos-stable-cache - steps: - - run: (sccache -s||true) - - run: set +e - - save_cache: - key: << parameters.cache_key >> - paths: - - .cache/sccache - - .cargo - - run_parallel: - description: "Build and run tests (in parallel)" - parameters: - workspace_member: - type: string - features: - type: string - steps: - - run: - no_output_timeout: 30m - command: | - cd << parameters.workspace_member >> - cargo test --features=<< parameters.features >> -- --list --format terse | sed 's/: test//' > test_names.txt - TEST_NAMES=$(circleci tests split test_names.txt) - for i in $(echo $TEST_NAMES | sed "s/ / /g") - do - RUST_MIN_STACK=8388608 cargo test --features=<< parameters.features >> $i - done - - install_rust_nightly: - description: "Install Rust nightly toolchain" - steps: - - run: rustup toolchain install nightly-x86_64-unknown-linux-gnu - -jobs: - - environment: - docker: - - image: cimg/rust:1.62 - resource_class: xlarge - parallelism: 1 - steps: - - checkout - - setup_environment: - cache_key: snarkos-environment-cache - - run_parallel: - workspace_member: environment - features: "" - - clear_environment: - cache_key: snarkos-environment-cache - - snarkos: - docker: - - image: cimg/rust:1.62 - resource_class: xlarge - parallelism: 20 - steps: - - checkout - - setup_environment: - cache_key: snarkos-stable-cache - - run_parallel: - workspace_member: . - features: "" - - clear_environment: - cache_key: snarkos-stable-cache - - # codecov: - # machine: - # image: ubuntu-1604:202004-01 - # docker_layer_caching: true - # resource_class: xlarge - # steps: - # - attach_workspace: - # at: /home/circleci/project/ - # - run: - # name: Run kcov - # command: > - # cd ~/project/project/ && - # docker run --security-opt seccomp=unconfined -v ~/project/project/:/home/circleci/project/ - # howardwu/snarkos-codecov:2021-03-25 bash /home/circleci/project/ci/kcov.sh - # - run: cd ./project/ && bash <(curl -s https://codecov.io/bash) - - fmt: - docker: - - image: cimg/rust:1.62 - resource_class: xlarge - steps: - - checkout - - install_rust_nightly - - setup_environment: - cache_key: snarkos-fmt-cache - - run: - name: Check style - no_output_timeout: 35m - command: cargo +nightly fmt --all -- --check - - clear_environment: - cache_key: snarkos-fmt-cache - - clippy: - docker: - - image: cimg/rust:1.62 - resource_class: xlarge - steps: - - checkout - - install_rust_nightly - - setup_environment: - cache_key: snarkos-clippy-cache - - run: - name: Check style - no_output_timeout: 35m - command: cargo +nightly clippy --workspace --all-targets - - clear_environment: - cache_key: snarkos-clippy-cache - - - build-and-publish-docker-arm: - machine: - image: ubuntu-2004:202101-01 - docker_layer_caching: true - resource_class: arm.large - steps: - - checkout - - run: mkdir -p my_workspace - - run: - name: "Build snarkOS Docker Image ARM V8" - no_output_timeout: 2h - command: | - VERSION=$(git rev-parse --short HEAD) - docker build -f Dockerfile -t $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-arm64 . - - run: - name: "Push snarkOS Docker Image ARM V8" - command: | - VERSION=$(git rev-parse --short HEAD) - echo $DOCKERHUB_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin - # CREATE THE SHELL FILE WITH IMAGE NAME AND TAG - docker push $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-arm64 - echo "Pushed $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-arm64" - - run: - name: "Save arm64 image tag" - command: | - VERSION=$(git rev-parse --short HEAD) - echo "$CIRCLE_BRANCH-$VERSION-arm64" > my_workspace/docker_tag_arm - - persist_to_workspace: - root: my_workspace - paths: - - docker_tag_arm - - build-and-publish-docker-amd: - machine: - image: ubuntu-2004:202101-01 - docker_layer_caching: true - resource_class: xlarge - steps: - - checkout - - run: mkdir -p my_workspace - - run: - name: "Build snarkOS Docker Image AMD" - no_output_timeout: 2h - command: | - VERSION=$(git rev-parse --short HEAD) - docker build -f Dockerfile -t $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-amd64 . - - run: - name: "Push snarkOS Docker Image AMD" - command: | - VERSION=$(git rev-parse --short HEAD) - echo $DOCKERHUB_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin - docker push $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-amd64 - echo "Pushed $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-amd64" - - run: - name: "Save amd64 image tag" - command: | - VERSION=$(git rev-parse --short HEAD) - echo "$CIRCLE_BRANCH-$VERSION-amd64" > my_workspace/docker_tag_amd - - persist_to_workspace: - root: my_workspace - paths: - - docker_tag_amd - - publish_snarkos_manifest: - machine: - image: ubuntu-2004:202101-01 - docker_layer_caching: true - resource_class: medium - steps: - - checkout - - attach_workspace: - at: my_workspace - - run: - name: "Pull ARM Docker image" - command: | - ARM_TAG=$(cat my_workspace/docker_tag_arm) - echo $ARM_TAG - echo $DOCKERHUB_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin - docker pull $DOCKER_REPO:$ARM_TAG - - run: - name: "Pull AMD Docker image" - command: | - AMD_TAG=$(cat my_workspace/docker_tag_amd) - echo $AMD_TAG - docker pull $DOCKER_REPO:$AMD_TAG - - run: - name: "Create and push Docker multi arch manifest" - command: | - ARM_TAG=$(cat my_workspace/docker_tag_arm) - AMD_TAG=$(cat my_workspace/docker_tag_amd) - echo $DOCKERHUB_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin - echo $DOCKER_REPO - echo $CIRCLE_BRANCH - echo $ARM_TAG - echo $AMD_TAG - docker manifest create $DOCKER_REPO:${CIRCLE_BRANCH}-latest --amend $DOCKER_REPO:${ARM_TAG} --amend $DOCKER_REPO:${AMD_TAG} - docker manifest inspect $DOCKER_REPO:${CIRCLE_BRANCH}-latest - docker manifest push $DOCKER_REPO:${CIRCLE_BRANCH}-latest - echo "Pushed $DOCKER_REPO:${CIRCLE_BRANCH}-latest" - -workflows: - main-workflow: - jobs: - - environment - - snarkos - # - codecov: - # requires: - # - rust-stable - - fmt - - clippy - build-snarkos-docker-images: - when: - or: - - equal: [ testnet3, << pipeline.git.branch >> ] - - equal: [ docker-builds, << pipeline.git.branch >> ] - jobs: - - build-and-publish-docker-arm - - build-and-publish-docker-amd - - publish_snarkos_manifest: - requires: - - build-and-publish-docker-arm - - build-and-publish-docker-amd diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index eac3163eb6..0000000000 --- a/.codecov.yml +++ /dev/null @@ -1,5 +0,0 @@ -coverage: - status: - project: - default: - threshold: 2% diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 1b9551b169..0000000000 --- a/.dockerignore +++ /dev/null @@ -1,11 +0,0 @@ -.vscode -**/*.idea/ -**/target -**/.DS_Store -**/.ledger* -**/.operator* -**/.prover* -**inner.proving* -**outer.proving* -**posw.proving* -**universal.srs* diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 0343a037be..3192336e78 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -7,35 +7,15 @@ labels: bug ## πŸ› Bug Report - - -(Write your description here) + ## Steps to Reproduce - - -1. Step 1... -2. Step 2... -3. Step 3... + ## Expected Behavior - - -(Write what you expected to happen here) + ## Your Environment diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md index 9b4b21b41e..3570d88fe6 100644 --- a/.github/ISSUE_TEMPLATE/documentation.md +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -7,9 +7,4 @@ labels: 'documentation' ## πŸ“š Documentation - - -(Write your answer here.) + diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md index 891abcae16..1d3907cde8 100644 --- a/.github/ISSUE_TEMPLATE/feature.md +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -7,30 +7,14 @@ labels: feature ## πŸš€ Feature - - -(Write your description here) + ## Motivation - - -(Outline your motivation here) + ## Implementation - + **Are you willing to open a pull request?** (See [CONTRIBUTING](../../CONTRIBUTING.md)) diff --git a/.github/ISSUE_TEMPLATE/proposal.md b/.github/ISSUE_TEMPLATE/proposal.md index 3c203e3833..add6692081 100644 --- a/.github/ISSUE_TEMPLATE/proposal.md +++ b/.github/ISSUE_TEMPLATE/proposal.md @@ -7,10 +7,4 @@ labels: 'proposal' ## πŸ’₯ Proposal - - -(Write your proposal here) + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5d029741ff..81cc4e3308 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,16 +6,8 @@ ## Test Plan - - -(Write your test plan here) +(If you changed any code, please provide clear instructions on how you verified your changes work.) ## Related PRs - - -(Link your related PRs here) +(Link any related PRs here) diff --git a/.github/workflows/sync-snarkos-documentation.yml b/.github/workflows/sync-snarkos-documentation.yml deleted file mode 100644 index 00128048d4..0000000000 --- a/.github/workflows/sync-snarkos-documentation.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Sync snarkOS Documentation - -on: - push: - paths: - - '**/documentation/**.md' - - '**/documentation/config.json' - branches: - - 'master' - -jobs: - sync: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Fetch branch name - run: echo Running on branch ${GITHUB_REF#refs/heads/} - - - name: Sync repository - run: | - curl \ - -X POST \ - -u "${{ secrets.SYNC_USERNAME }}:${{ secrets.SYNC_TOKEN }}" \ - -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/${{ secrets.SYNC_ORGANIZATION }}/${{ secrets.SYNC_APPLICATION }}/dispatches \ - -d '{"event_type":"sync-snarkos-documentation", "client_payload": { "branch": "'"${GITHUB_REF#refs/heads/}"'" }}' diff --git a/.github/workflows/sync-snarkos-to-welcome-documentation.yml b/.github/workflows/sync-snarkos-to-welcome-documentation.yml deleted file mode 100644 index 2c15588243..0000000000 --- a/.github/workflows/sync-snarkos-to-welcome-documentation.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Sync snarkOS to Welcome Documentation - -on: - push: - paths: - - '**/documentation/**.md' - - '**/documentation/config.json' - branches: - - 'master' - -jobs: - sync: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Fetch branch name - run: echo Running on branch ${GITHUB_REF#refs/heads/} - - - name: Sync repository - run: | - curl \ - -X POST \ - -u "${{ secrets.SYNC_USERNAME }}:${{ secrets.SYNC_TOKEN }}" \ - -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/${{ secrets.SYNC_ORGANIZATION }}/${{ secrets.SYNC_APPLICATION }}/dispatches \ - -d '{"event_type":"sync-snarkos-to-welcome-documentation", "client_payload": { "branch": "'"${GITHUB_REF#refs/heads/}"'" }}' diff --git a/.gitignore b/.gitignore index 1b9551b169..8ee7a69e92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,7 @@ -.vscode **/*.idea/ **/target -**/.DS_Store -**/.ledger* -**/.operator* -**/.prover* -**inner.proving* -**outer.proving* -**posw.proving* -**universal.srs* +**.DS_Store +storage*/ +wasm/Cargo.lock +**/build +**.ledger-* diff --git a/.license_header b/.resources/license_header similarity index 97% rename from .license_header rename to .resources/license_header index 68e5a3e7d8..6f945b8f98 100644 --- a/.license_header +++ b/.resources/license_header @@ -12,4 +12,4 @@ // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with the snarkOS library. If not, see . +// along with the snarkOS library. If not, see . \ No newline at end of file diff --git a/.rustfmt.toml b/.rustfmt.toml index 282f934e68..df2276c812 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -2,9 +2,10 @@ # Stable configurations edition = "2021" -max_width = 140 +max_width = 120 merge_derives = true use_field_init_shorthand = true +use_small_heuristics = "Max" use_try_shorthand = true # Nightly configurations @@ -13,3 +14,4 @@ imports_granularity = "Crate" overflow_delimited_expr = true reorder_impl_items = true version = "Two" + diff --git a/.rusty-hook.toml b/.rusty-hook.toml index 9c57ceedf9..afddd71b5e 100644 --- a/.rusty-hook.toml +++ b/.rusty-hook.toml @@ -1,5 +1,5 @@ [hooks] -pre-commit = "cargo +nightly clippy && cargo +nightly fmt --all -- --check" +#pre-commit = "cargo +nightly clippy && cargo +nightly fmt --all -- --check" [logging] verbose = true diff --git a/Cargo.lock b/Cargo.lock index 2c6e73c19b..43d5bf0c4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,7 +80,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6118baab6285accf088b31d5ea5029c37bbf9d98e62b4d8720a0a5a66bc2e427" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -91,15 +91,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e4f181fc1a372e8ceff89612e5c9b13f72bff5b066da9f8d6827ae65af492c4" -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anyhow" version = "1.0.65" @@ -124,7 +115,7 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -193,7 +184,7 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "regex", "rustc-hash", @@ -206,6 +197,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "blake2" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" +dependencies = [ + "digest", +] + [[package]] name = "blake2s_simd" version = "1.0.0" @@ -217,15 +217,6 @@ dependencies = [ "constant_time_eq", ] -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.10.3" @@ -269,16 +260,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" -[[package]] -name = "bzip2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" -dependencies = [ - "bzip2-sys", - "libc", -] - [[package]] name = "bzip2-sys" version = "0.1.11+1.0.8" @@ -320,19 +301,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" -dependencies = [ - "iana-time-zone", - "num-integer", - "num-traits", - "serde", - "winapi", -] - [[package]] name = "chunked_transfer" version = "1.4.0" @@ -367,8 +335,8 @@ checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", "bitflags", - "clap_derive 3.2.18", - "clap_lex 0.2.4", + "clap_derive", + "clap_lex", "indexmap", "once_cell", "strsim", @@ -376,21 +344,6 @@ dependencies = [ "textwrap", ] -[[package]] -name = "clap" -version = "4.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea54a38e4bce14ff6931c72e5b3c43da7051df056913d4e7e1fcdb1c03df69d" -dependencies = [ - "atty", - "bitflags", - "clap_derive 4.0.13", - "clap_lex 0.3.0", - "once_cell", - "strsim", - "termcolor", -] - [[package]] name = "clap_derive" version = "3.2.18" @@ -399,20 +352,7 @@ checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.46", - "quote 1.0.21", - "syn 1.0.102", -] - -[[package]] -name = "clap_derive" -version = "4.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -426,25 +366,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "clap_lex" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "colored" version = "2.0.0" @@ -555,25 +476,9 @@ dependencies = [ [[package]] name = "crossterm" -version = "0.23.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" -dependencies = [ - "bitflags", - "crossterm_winapi", - "libc", - "mio", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9f7409c70a38a56216480fba371ee460207dd8926ccf5b4160591759559170" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" dependencies = [ "bitflags", "crossterm_winapi", @@ -604,16 +509,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "curl" version = "0.4.44" @@ -644,50 +539,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "cxx" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2 1.0.46", - "quote 1.0.21", - "scratch", - "syn 1.0.102", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea" -dependencies = [ - "proc-macro2 1.0.46", - "quote 1.0.21", - "syn 1.0.102", -] - [[package]] name = "dashmap" version = "5.4.0" @@ -707,28 +558,20 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "block-buffer 0.10.3", + "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -740,16 +583,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" version = "0.3.7" @@ -761,23 +594,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - [[package]] name = "either" version = "1.8.0" @@ -920,6 +736,7 @@ dependencies = [ "futures-core", "futures-task", "futures-util", + "num_cpus", ] [[package]] @@ -934,7 +751,7 @@ version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -1088,16 +905,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "http" version = "0.2.8" @@ -1169,30 +976,6 @@ dependencies = [ "tokio-native-tls", ] -[[package]] -name = "iana-time-zone" -version = "0.1.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa" -dependencies = [ - "cxx", - "cxx-build", -] - [[package]] name = "idna" version = "0.3.0" @@ -1328,15 +1111,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "link-cplusplus" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" -dependencies = [ - "cc", -] - [[package]] name = "lock_api" version = "0.4.9" @@ -1365,17 +1139,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "md-5" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "memchr" version = "2.5.0" @@ -1513,7 +1276,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -1568,12 +1331,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - [[package]] name = "openssl" version = "0.10.42" @@ -1595,7 +1352,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -1687,7 +1444,7 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -1723,7 +1480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", "version_check", @@ -1735,7 +1492,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "version_check", ] @@ -1751,9 +1508,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -1794,7 +1551,7 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", ] [[package]] @@ -1977,75 +1734,6 @@ dependencies = [ "librocksdb-sys", ] -[[package]] -name = "rusoto_core" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db30db44ea73551326269adcf7a2169428a054f14faf9e1768f2163494f2fa2" -dependencies = [ - "async-trait", - "base64", - "bytes", - "crc32fast", - "futures", - "http", - "hyper", - "hyper-tls", - "lazy_static", - "log", - "rusoto_credential", - "rusoto_signature", - "rustc_version", - "serde", - "serde_json", - "tokio", - "xml-rs", -] - -[[package]] -name = "rusoto_credential" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee0a6c13db5aad6047b6a44ef023dbbc21a056b6dab5be3b79ce4283d5c02d05" -dependencies = [ - "async-trait", - "chrono", - "dirs-next", - "futures", - "hyper", - "serde", - "serde_json", - "shlex", - "tokio", - "zeroize", -] - -[[package]] -name = "rusoto_signature" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ae95491c8b4847931e291b151127eccd6ff8ca13f33603eb3d0035ecb05272" -dependencies = [ - "base64", - "bytes", - "chrono", - "digest 0.9.0", - "futures", - "hex", - "hmac", - "http", - "hyper", - "log", - "md-5", - "percent-encoding", - "pin-project-lite", - "rusoto_credential", - "rustc_version", - "serde", - "sha2 0.9.9", - "tokio", -] - [[package]] name = "rustc-hash" version = "1.1.0" @@ -2063,9 +1751,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.6" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" dependencies = [ "log", "ring", @@ -2137,12 +1825,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" - [[package]] name = "sct" version = "0.7.0" @@ -2182,8 +1864,6 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e08f3ce73aed26096783c26570ba416ff8f4524c89a14bcdf068967dc80daef" dependencies = [ - "either", - "flate2", "hyper", "indicatif", "log", @@ -2193,7 +1873,6 @@ dependencies = [ "semver", "serde_json", "tempfile", - "zip", ] [[package]] @@ -2217,7 +1896,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -2266,7 +1945,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b6f5d1c3087fb119617cff2966fe3808a80e5eb59a8c1601d5994d66f4346a5" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -2279,7 +1958,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.5", + "digest", ] [[package]] @@ -2290,20 +1969,7 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.5", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "digest", ] [[package]] @@ -2314,7 +1980,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.5", + "digest", ] [[package]] @@ -2380,70 +2046,169 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snarkos" version = "2.0.2" +dependencies = [ + "anyhow", + "clap", + "rusty-hook", + "snarkos-account", + "snarkos-cli", + "snarkos-display", + "snarkos-node", + "snarkos-node-executor", + "snarkos-node-ledger", + "snarkos-node-router", + "snarkos-node-store", + "walkdir", +] + +[[package]] +name = "snarkos-account" +version = "2.0.2" +dependencies = [ + "anyhow", + "colored", + "rand", + "snarkvm", +] + +[[package]] +name = "snarkos-cli" +version = "2.0.2" dependencies = [ "aleo-std", "anyhow", - "backoff", - "bincode", - "bytes", - "clap 4.0.14", + "clap", "colored", - "crossterm 0.24.0", - "dotenv", - "futures", - "hyper", - "hyper-tls", - "indexmap", "num_cpus", - "once_cell", "parking_lot", "rand", + "rand_chacha", "rayon", - "reqwest", - "rocksdb", - "rusoto_core", - "rusty-hook", "self_update", "serde", "serde_json", - "serial_test", - "snarkos-environment", + "snarkos-account", + "snarkos-display", + "snarkos-node", "snarkvm", - "tempfile", "thiserror", - "time", "tokio", - "tokio-util", +] + +[[package]] +name = "snarkos-display" +version = "2.0.2" +dependencies = [ + "anyhow", + "colored", + "crossterm", + "snarkos-node", + "snarkvm", + "tokio", "tracing", "tracing-subscriber", "tui", - "walkdir", - "warp", ] [[package]] -name = "snarkos-environment" +name = "snarkos-node" +version = "2.0.2" +dependencies = [ + "anyhow", + "async-trait", + "rand", + "serde_json", + "snarkos-account", + "snarkos-node-executor", + "snarkos-node-ledger", + "snarkos-node-router", + "snarkvm", + "tokio", + "tracing", +] + +[[package]] +name = "snarkos-node-executor" version = "2.0.2" dependencies = [ "anyhow", + "async-trait", "num_cpus", "once_cell", "rayon", "serde", - "serde_json", - "snarkvm", "tokio", "tracing", "tracing-subscriber", ] +[[package]] +name = "snarkos-node-ledger" +version = "2.0.2" +dependencies = [ + "anyhow", + "backoff", + "colored", + "futures", + "indexmap", + "parking_lot", + "rand", + "rayon", + "reqwest", + "snarkos-node-router", + "snarkos-node-store", + "snarkvm", + "tokio", + "tracing", + "warp", +] + +[[package]] +name = "snarkos-node-router" +version = "2.0.2" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "bytes", + "futures", + "indexmap", + "once_cell", + "rand", + "serde", + "snarkos-node-executor", + "snarkvm", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", +] + +[[package]] +name = "snarkos-node-store" +version = "2.0.2" +dependencies = [ + "aleo-std", + "anyhow", + "bincode", + "indexmap", + "once_cell", + "parking_lot", + "rocksdb", + "serde", + "serial_test", + "snarkvm", + "tempfile", + "tracing", +] + [[package]] name = "snarkvm" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "anyhow", - "clap 3.2.22", + "clap", "colored", "indexmap", "once_cell", @@ -2468,7 +2233,7 @@ dependencies = [ [[package]] name = "snarkvm-algorithms" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "aleo-std", "anyhow", @@ -2481,7 +2246,7 @@ dependencies = [ "rand_core", "rayon", "serde", - "sha2 0.10.6", + "sha2", "smallvec", "snarkvm-curves", "snarkvm-fields", @@ -2494,7 +2259,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -2508,7 +2273,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-account" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-network", @@ -2519,7 +2284,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-algorithms" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-types", "snarkvm-console-algorithms", @@ -2529,7 +2294,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-collections" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-types", @@ -2539,7 +2304,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "indexmap", "itertools", @@ -2557,12 +2322,12 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment-witness" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" [[package]] name = "snarkvm-circuit-network" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-collections", @@ -2573,7 +2338,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-program" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-network", @@ -2585,7 +2350,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-address", @@ -2600,7 +2365,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-address" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2613,7 +2378,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-boolean" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-environment", "snarkvm-console-types-boolean", @@ -2622,7 +2387,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-field" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2632,7 +2397,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-group" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2644,7 +2409,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-integers" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2655,7 +2420,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-scalar" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2666,7 +2431,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-string" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2678,9 +2443,10 @@ dependencies = [ [[package]] name = "snarkvm-compiler" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "anyhow", + "blake2", "colored", "indexmap", "once_cell", @@ -2703,7 +2469,7 @@ dependencies = [ [[package]] name = "snarkvm-console" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-console-account", "snarkvm-console-algorithms", @@ -2716,7 +2482,7 @@ dependencies = [ [[package]] name = "snarkvm-console-account" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "bs58", "snarkvm-console-network", @@ -2726,7 +2492,7 @@ dependencies = [ [[package]] name = "snarkvm-console-algorithms" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "blake2s_simd", "smallvec", @@ -2738,7 +2504,7 @@ dependencies = [ [[package]] name = "snarkvm-console-collections" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "aleo-std", "rayon", @@ -2749,7 +2515,7 @@ dependencies = [ [[package]] name = "snarkvm-console-network" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "anyhow", "itertools", @@ -2770,7 +2536,7 @@ dependencies = [ [[package]] name = "snarkvm-console-network-environment" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "anyhow", "bech32", @@ -2787,7 +2553,7 @@ dependencies = [ [[package]] name = "snarkvm-console-program" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "enum_index", "enum_index_derive", @@ -2804,7 +2570,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-address", @@ -2819,7 +2585,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-address" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2830,7 +2596,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-boolean" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-console-network-environment", ] @@ -2838,7 +2604,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-field" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2847,7 +2613,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-group" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2858,7 +2624,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-integers" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2868,7 +2634,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-scalar" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2878,7 +2644,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-string" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2889,7 +2655,7 @@ dependencies = [ [[package]] name = "snarkvm-curves" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "rand", "rustc_version", @@ -2902,7 +2668,7 @@ dependencies = [ [[package]] name = "snarkvm-fields" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "aleo-std", "anyhow", @@ -2919,7 +2685,7 @@ dependencies = [ [[package]] name = "snarkvm-parameters" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "aleo-std", "anyhow", @@ -2933,7 +2699,7 @@ dependencies = [ "paste", "rand", "serde_json", - "sha2 0.10.6", + "sha2", "snarkvm-curves", "snarkvm-utilities", "thiserror", @@ -2942,7 +2708,7 @@ dependencies = [ [[package]] name = "snarkvm-r1cs" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "anyhow", "cfg-if", @@ -2958,7 +2724,7 @@ dependencies = [ [[package]] name = "snarkvm-rest" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "anyhow", "http", @@ -2975,7 +2741,7 @@ dependencies = [ [[package]] name = "snarkvm-utilities" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ "aleo-std", "anyhow", @@ -2993,9 +2759,9 @@ dependencies = [ [[package]] name = "snarkvm-utilities-derives" version = "0.9.0" -source = "git+https://github.com/AleoHQ/snarkVM.git?rev=1f0f2c9#1f0f2c98e7a04fc9e6a5ee61b6936257a599addc" +source = "git+https://github.com/AleoHQ/snarkVM.git?rev=d9f4c52#d9f4c5221aceb3026c0831938865bd768ff4eb81" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -3056,7 +2822,7 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "unicode-ident", ] @@ -3124,7 +2890,7 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -3144,18 +2910,10 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" dependencies = [ - "itoa", "libc", "num_threads", - "time-macros", ] -[[package]] -name = "time-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" - [[package]] name = "tinyvec" version = "1.6.0" @@ -3183,7 +2941,6 @@ dependencies = [ "memchr", "mio", "num_cpus", - "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -3197,7 +2954,7 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -3283,7 +3040,7 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", ] @@ -3318,7 +3075,6 @@ dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "parking_lot", "regex", "sharded-slab", "smallvec", @@ -3336,13 +3092,13 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "tui" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fe69244ec2af261bced1d9046a6fee6c8c2a6b0228e59e5ba39bc8ba4ed729" +checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" dependencies = [ "bitflags", "cassowary", - "crossterm 0.23.2", + "crossterm", "unicode-segmentation", "unicode-width", ] @@ -3572,7 +3328,7 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", "wasm-bindgen-shared", @@ -3606,7 +3362,7 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ - "proc-macro2 1.0.46", + "proc-macro2 1.0.47", "quote 1.0.21", "syn 1.0.102", "wasm-bindgen-backend", @@ -3730,29 +3486,3 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] - -[[package]] -name = "xml-rs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" - -[[package]] -name = "zeroize" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" - -[[package]] -name = "zip" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080" -dependencies = [ - "byteorder", - "bzip2", - "crc32fast", - "crossbeam-utils", - "flate2", - "time", -] diff --git a/Cargo.toml b/Cargo.toml index fe59750a28..620df2fafc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,137 +6,66 @@ description = "A decentralized operating system" homepage = "https://aleo.org" repository = "https://github.com/AleoHQ/snarkOS" keywords = [ - "aleo", - "cryptography", - "blockchain", - "decentralized", - "zero-knowledge" + "aleo", + "cryptography", + "blockchain", + "decentralized", + "zero-knowledge" ] categories = [ "cryptography", "operating-systems" ] license = "GPL-3.0" edition = "2021" [workspace] -members = [ "environment" ] +members = [ "account", "cli", "display", "node", "node/executor", "node/ledger", "node/router", "node/store" ] -[lib] -path = "snarkos/lib.rs" +#[lib] +#path = "snarkos/lib.rs" [[bin]] name = "snarkos" path = "snarkos/main.rs" -#[[bin]] -#name = "main" -#path = "src/main.rs" - -[dependencies] -backoff = { version = "0.4", features = ["tokio"] } -bytes = { version = "1" } -dotenv = { version = "0.15" } -futures = { version = "0.3" } -hyper = { version = "0.14" } -hyper-tls = { version = "0.5" } -indexmap = { version = "1.9", features = ["rayon"] } -once_cell = { version = "1.15.0" } -parking_lot = { version = "0.12" } -rusoto_core = { version = "0.48" } -tokio-util = { version = "0.7.4" } -warp = { version = "0.3" } - -[dependencies.snarkos-environment] -path = "./environment" -version = "2.0.2" - -[dependencies.snarkvm] -#path = "../snarkVM" +[workspace.dependencies.snarkvm] +# path = "../snarkvm" git = "https://github.com/AleoHQ/snarkVM.git" -rev = "1f0f2c9" -features = ["circuit", "console", "parallel", "rest", "utilities"] +rev = "d9f4c52" +features = ["circuit", "console", "parallel", "rest"] -[dependencies.aleo-std] -version = "0.1.14" -features = [ "cpu" ] +[dependencies.snarkos-account] +path = "./account" -[dependencies.anyhow] -version = "1" - -[dependencies.bincode] -version = "1.0" - -[dependencies.clap] -version = "4" -features = [ "derive" ] +[dependencies.snarkos-cli] +path = "./cli" -[dependencies.colored] -version = "2.0" - -[dependencies.crossterm] -version = "0.24" -optional = true - -[dependencies.num_cpus] -version = "1" - -[dependencies.rand] -version = "0.8" - -[dependencies.rayon] -version = "1" +[dependencies.snarkos-display] +path = "./display" -[dependencies.reqwest] -version = "0.11.12" - -[dependencies.rocksdb] -version = "0.19" -default-features = false -features = [ "lz4" ] - -[dependencies.self_update] -version = "0.32" -features = [ - "archive-zip", - "compression-zip-bzip2", - "compression-zip-deflate", - "compression-flate2" -] +[dependencies.snarkos-node] +path = "./node" -[dependencies.serde] -version = "1" +[dependencies.snarkos-node-executor] +path = "./node/executor" -[dependencies.serde_json] -version = "1" +[dependencies.snarkos-node-ledger] +path = "./node/ledger" -[dependencies.thiserror] -version = "1.0" +[dependencies.snarkos-node-router] +path = "./node/router" -[dependencies.time] -version = "0.3.14" +[dependencies.snarkos-node-store] +path = "./node/store" -[dependencies.tokio] +[dependencies.anyhow] version = "1" -features = [ "full" ] -[dependencies.tracing] -version = "0.1" - -[dependencies.tracing-subscriber] -version = "0.3" -features = [ "env-filter", "parking_lot" ] - -[dependencies.tui] -version = "0.18" -optional = true +[dependencies.clap] +version = "3.2" +features = ["derive"] [dev-dependencies.rusty-hook] version = "0.11.2" -[dev-dependencies.serial_test] -version = "0.9.0" - -[dev-dependencies.tempfile] -version = "3.2" - [build-dependencies.walkdir] version = "2" @@ -154,12 +83,12 @@ incremental = true debug-assertions = false [profile.dev] -opt-level = 3 +opt-level = 2 lto = "thin" incremental = true [profile.test] -opt-level = 3 +opt-level = 2 lto = "thin" incremental = true debug = true diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 5228cec147..0000000000 --- a/Dockerfile +++ /dev/null @@ -1,59 +0,0 @@ -FROM ubuntu:18.04 AS builder -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH \ - DEBIAN_FRONTEND=noninteractive -RUN set -eux ; \ - apt-get update -y && \ - apt-get dist-upgrade -y && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - gcc \ - libc6-dev \ - wget \ - build-essential \ - clang \ - gcc \ - libssl-dev \ - make \ - pkg-config \ - xz-utils && \ - dpkgArch="$(dpkg --print-architecture)"; \ - case "${dpkgArch##*-}" in \ - amd64) rustArch='x86_64-unknown-linux-gnu' ;; \ - arm64) rustArch='aarch64-unknown-linux-gnu' ;; \ - *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ - esac; \ - \ - url="https://static.rust-lang.org/rustup/dist/${rustArch}/rustup-init"; \ - wget "$url"; \ - chmod +x rustup-init; \ - ./rustup-init -y --no-modify-path --default-toolchain stable; \ - rm rustup-init; \ - chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \ - rustup --version; \ - cargo --version; \ - rustc --version; \ - apt-get remove -y --auto-remove wget && \ - apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/*; -WORKDIR /usr/src/snarkOS -COPY . . -RUN cargo build --release -FROM ubuntu:18.04 -SHELL ["/bin/bash", "-c"] -VOLUME ["/aleo/data"] -RUN set -ex && \ - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y -o DPkg::Options::=--force-confold && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - ca-certificates curl jq && \ - apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* && \ - mkdir -p /aleo/{bin,data} && \ - mkdir /usr/local/cargo -COPY --from=builder /usr/src/snarkOS/target/release/snarkos /aleo/bin/ -COPY --from=builder /usr/src/snarkOS/start /aleo/ -CMD ["/aleo/start"] \ No newline at end of file diff --git a/README.md b/README.md index e65e4cd498..7f5b34c551 100644 --- a/README.md +++ b/README.md @@ -160,22 +160,17 @@ SUBCOMMANDS: ## 6. Development -[//]: # (In one terminal, start the first node by running:) - -[//]: # (```) - -[//]: # (cargo run --release -- --dev 1 --node 0.0.0.0:4135 --rpc 0.0.0.0:3035 --prover aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah) - -[//]: # (```) - -[//]: # () -[//]: # (After the first node starts, in a second terminal, run:) - -[//]: # (```) +In one terminal, start the first node by running: +``` +cargo run --release -- start --dev 0 --nodisplay +``` -[//]: # (cargo run --release -- --dev 2) +In a second terminal, run: +``` +cargo run --release -- start --dev 1 --nodisplay +``` -[//]: # (```) +This prodedure can be repeated to start more nodes. We welcome all contributions to snarkOS. Please refer to the [license](#7-license) for the terms of contributions. diff --git a/account/Cargo.toml b/account/Cargo.toml new file mode 100644 index 0000000000..f414916bc2 --- /dev/null +++ b/account/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "snarkos-account" +version = "2.0.2" +authors = [ "The Aleo Team " ] +description = "Account for a decentralized operating system" +homepage = "https://aleo.org" +repository = "https://github.com/AleoHQ/snarkOS" +keywords = [ + "aleo", + "cryptography", + "blockchain", + "decentralized", + "zero-knowledge" +] +categories = [ "cryptography", "operating-systems" ] +license = "GPL-3.0" +edition = "2021" + +[dependencies.anyhow] +version = "1" + +[dependencies.colored] +version = "2" + +[dependencies.rand] +version = "0.8" +default-features = false + +[dependencies.snarkvm] +workspace = true diff --git a/environment/LICENSE.md b/account/LICENSE.md similarity index 100% rename from environment/LICENSE.md rename to account/LICENSE.md diff --git a/account/README.md b/account/README.md new file mode 100644 index 0000000000..50d091b9c3 --- /dev/null +++ b/account/README.md @@ -0,0 +1,7 @@ +# snarkos-account + +[![Crates.io](https://img.shields.io/crates/v/snarkos-account.svg?color=neon)](https://crates.io/crates/snarkos-account) +[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](https://aleo.org) +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md) + +The `snarkos-account` crate provides the `Account` struct, which is responsible for managing a user's private key, view key, and address. diff --git a/snarkos/account/mod.rs b/account/src/lib.rs similarity index 72% rename from snarkos/account/mod.rs rename to account/src/lib.rs index abff4feb8d..b74acbe8d1 100644 --- a/snarkos/account/mod.rs +++ b/account/src/lib.rs @@ -14,12 +14,16 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . +#![forbid(unsafe_code)] + use snarkvm::{console::types::Field, prelude::*}; use ::rand::thread_rng; +use colored::*; +use core::fmt; /// A helper struct for an Aleo account. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Account { /// The account private key. private_key: PrivateKey, @@ -34,23 +38,19 @@ impl FromStr for Account { /// Initializes a new account from a private key string. fn from_str(private_key: &str) -> Result { - Self::new(FromStr::from_str(private_key)?) + Self::from(FromStr::from_str(private_key)?) } } impl Account { /// Initializes a new account. - pub fn new(private_key: PrivateKey) -> Result { - Ok(Self { - private_key, - view_key: ViewKey::try_from(&private_key)?, - address: Address::try_from(&private_key)?, - }) + pub fn from(private_key: PrivateKey) -> Result { + Ok(Self { private_key, view_key: ViewKey::try_from(&private_key)?, address: Address::try_from(&private_key)? }) } /// Samples a new account. pub fn sample() -> Result { - Self::new(PrivateKey::new(&mut thread_rng())?) + Self::from(PrivateKey::new(&mut thread_rng())?) } /// Signs a given message. @@ -78,3 +78,19 @@ impl Account { &self.address } } + +impl Display for Account { + /// Renders the account as a string. + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + " {:>12} {}\n {:>12} {}\n {:>12} {}", + "Private Key".cyan().bold(), + self.private_key, + "View Key".cyan().bold(), + self.view_key, + "Address".cyan().bold(), + self.address + ) + } +} diff --git a/build.rs b/build.rs index bef63da11e..8a3eba0b2f 100644 --- a/build.rs +++ b/build.rs @@ -19,10 +19,10 @@ use std::{fs::File, io::Read, path::Path}; use walkdir::WalkDir; // The following license text that should be present at the beginning of every source file. -const EXPECTED_LICENSE_TEXT: &[u8] = include_bytes!(".license_header"); +const EXPECTED_LICENSE_TEXT: &[u8] = include_bytes!(".resources/license_header"); // The following directories will be excluded from the license scan. -const DIRS_TO_SKIP: [&str; 7] = [".circleci", ".git", ".github", "artifacts", "corpus", "target", "fuzz_targets"]; +const DIRS_TO_SKIP: [&str; 8] = [".cargo", ".circleci", ".git", ".github", ".resources", "examples", "js", "target"]; fn check_file_licenses>(path: P) { let path = path.as_ref(); diff --git a/build_ubuntu.sh b/build_ubuntu.sh deleted file mode 100755 index d29192e7fb..0000000000 --- a/build_ubuntu.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -if [[ $(/usr/bin/id -u) -ne 0 ]]; then - echo "Aborting: run as root user!" - exit 1 -fi - -echo "================================================" -echo " Attention - Building snarkOS from source code." -echo "================================================" - -# Install Ubuntu dependencies - -apt-get update -apt-get install -y \ - build-essential \ - curl \ - clang \ - gcc \ - libssl-dev \ - llvm \ - make \ - pkg-config \ - tmux \ - xz-utils - -# Install Rust - -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -source $HOME/.cargo/env - -# Install snarkOS -# cargo clean -cargo install --path . - -echo "==================================================" -echo " Attention - Please ensure ports 4130 and 4180" -echo " are enabled on your local network." -echo "" -echo " Cloud Providers - Enable ports 4130 and 4180" -echo " in your network firewall" -echo "" -echo " Home Users - Enable port forwarding or NAT rules" -echo " for 4130 and 4180 on your router." -echo "==================================================" - -# Open ports on system -ufw allow 4130/tcp -ufw allow 4180/tcp diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 0000000000..62f700a0e4 --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,77 @@ +[package] +name = "snarkos-cli" +version = "2.0.2" +authors = [ "The Aleo Team " ] +description = "A CLI for a decentralized operating system" +homepage = "https://aleo.org" +repository = "https://github.com/AleoHQ/snarkOS" +keywords = [ + "aleo", + "cryptography", + "blockchain", + "decentralized", + "zero-knowledge" +] +categories = [ "cryptography", "operating-systems" ] +license = "GPL-3.0" +edition = "2021" + +[dependencies.snarkos-account] +path = "../account" + +[dependencies.snarkos-display] +path = "../display" + +[dependencies.snarkos-node] +path = "../node" + +[dependencies.aleo-std] +version = "0.1.15" +default-features = false + +[dependencies.anyhow] +version = "1" + +[dependencies.clap] +version = "3.2" +features = ["derive"] + +[dependencies.colored] +version = "2" + +[dependencies.num_cpus] +version = "1" + +[dependencies.parking_lot] +version = "0.12" + +[dependencies.rand] +version = "0.8" +default-features = false + +[dependencies.rand_chacha] +version = "0.3.0" +default-features = false + +[dependencies.rayon] +version = "1" + +[dependencies.self_update] +version = "0.32" + +[dependencies.serde] +version = "1" + +[dependencies.serde_json] +version = "1" + +[dependencies.snarkvm] +workspace = true + +[dependencies.thiserror] +version = "1.0" + +[dependencies.tokio] +version = "1.21" +features = ["rt"] + diff --git a/cli/LICENSE.md b/cli/LICENSE.md new file mode 100644 index 0000000000..b95c626e2a --- /dev/null +++ b/cli/LICENSE.md @@ -0,0 +1,596 @@ +GNU General Public License +========================== + +Version 3, 29 June 2007 + +Copyright Β© 2007 Free Software Foundation, Inc. <> + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: **(1)** assert +copyright on the software, and **(2)** offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions + +β€œThis License” refers to version 3 of the GNU General Public License. + +β€œCopyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +β€œThe Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as β€œyou”. β€œLicensees” and +β€œrecipients” may be individuals or organizations. + +To β€œmodify” a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a β€œmodified version” of the earlier work or a +work β€œbased on” the earlier work. + +A β€œcovered work” means either the unmodified Program or a work based on +the Program. + +To β€œpropagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To β€œconvey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays β€œAppropriate Legal Notices” to the +extent that it includes a convenient and prominently visible feature that **(1)** +displays an appropriate copyright notice, and **(2)** tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code + +The β€œsource code” for a work means the preferred form of the work for +making modifications to it. β€œObject code” means any non-source form of a +work. + +A β€œStandard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The β€œSystem Libraries” of an executable work include anything, other than +the work as a whole, that **(a)** is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and **(b)** serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A β€œMajor Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The β€œCorresponding Source” for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to β€œkeep intact all notices”. +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an β€œaggregate” if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either **(1)** a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or **(2)** access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A β€œUser Product” is either **(1)** a β€œconsumer product”, which +means any tangible personal property which is normally used for personal, family, or +household purposes, or **(2)** anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, β€œnormally used” refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +β€œInstallation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms + +β€œAdditional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered β€œfurther +restrictions” within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated **(a)** provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and **(b)** permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An β€œentity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents + +A β€œcontributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's β€œcontributor version”. + +A contributor's β€œessential patent claims” are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, β€œcontrol” includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a β€œpatent license” is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To β€œgrant” such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either **(1)** cause the Corresponding +Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the +patent license for this particular work, or **(3)** arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. β€œKnowingly relying” means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is β€œdiscriminatory” if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license **(a)** in connection with +copies of the covered work conveyed by you (or copies made from those copies), or **(b)** +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License β€œor any later +version” applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM β€œAS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16 + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +_END OF TERMS AND CONDITIONS_ + +## How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to +the public, the best way to achieve this is to make it free software which everyone +can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them +to the start of each source file to most effectively state the exclusion of warranty; +and each file should have at least the β€œcopyright” line and a pointer to +where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands `show w` and `show c` should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an β€œabout box”. + +You should also get your employer (if you work as a programmer) or school, if any, to +sign a β€œcopyright disclaimer” for the program, if necessary. For more +information on this, and how to apply and follow the GNU GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 0000000000..9d7d1e5399 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,7 @@ +# snarkos-cli + +[![Crates.io](https://img.shields.io/crates/v/snarkos-cli.svg?color=neon)](https://crates.io/crates/snarkos-cli) +[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](https://aleo.org) +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md) + +The `snarkos-cli` crate provides the `CLI` struct, which is responsible for providing a command-line interface to the node. diff --git a/cli/src/commands/account.rs b/cli/src/commands/account.rs new file mode 100644 index 0000000000..107a7b2c00 --- /dev/null +++ b/cli/src/commands/account.rs @@ -0,0 +1,88 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use snarkvm::prelude::PrivateKey; + +use anyhow::Result; +use clap::Parser; +use rand::SeedableRng; +use rand_chacha::ChaChaRng; + +type Network = snarkvm::prelude::Testnet3; + +/// Commands to manage Aleo accounts. +#[derive(Debug, Parser)] +pub enum Account { + /// Generates a new Aleo account + New { + /// Seed the RNG with a numeric value + #[clap(short = 's', long)] + seed: Option, + }, +} + +impl Account { + pub fn parse(self) -> Result { + match self { + Self::New { seed } => { + // Sample a new Aleo account. + let account = snarkos_account::Account::from(match seed { + Some(seed) => PrivateKey::::new(&mut ChaChaRng::seed_from_u64(seed))?, + None => PrivateKey::new(&mut rand::thread_rng())?, + })?; + // Print the new Aleo account. + Ok(account.to_string()) + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::commands::Account; + use colored::Colorize; + + #[test] + fn test_new() { + for _ in 0..3 { + let account = Account::New { seed: None }; + assert!(account.parse().is_ok()); + } + } + + #[test] + fn test_new_seeded() { + let seed = Some(1231275789u64); + let mut expected = format!( + " {:>12} {}\n", + "Private Key".cyan().bold(), + "APrivateKey1zkp2oVPTci9kKcUprnbzMwq95Di1MQERpYBhEeqvkrDirK1" + ); + expected += &format!( + " {:>12} {}\n", + "View Key".cyan().bold(), + "AViewKey1mmLWAuYDaM1NfgNaD1Jy7THG8uS4Ui2zyugFuPEijgyQ" + ); + expected += &format!( + " {:>12} {}", + "Address".cyan().bold(), + "aleo1whnlxsgnhc8ywft2l4nu9hywedspcjpwcsgg490ckz34tthqsupqdh5z64" + ); + let account = Account::New { seed }; + let actual = account.parse().unwrap(); + assert_eq!(expected, actual); + } +} diff --git a/cli/src/commands/clean.rs b/cli/src/commands/clean.rs new file mode 100644 index 0000000000..723fb4c0e1 --- /dev/null +++ b/cli/src/commands/clean.rs @@ -0,0 +1,60 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use anyhow::{bail, Result}; +use clap::Parser; +use colored::Colorize; + +/// Cleans the snarkOS node storage. +#[derive(Debug, Parser)] +pub struct Clean { + /// Specify the network to remove from storage. + #[clap(default_value = "3", long = "network")] + pub network: u16, + /// Enables development mode, specify the unique ID of the local node to clean. + #[clap(long)] + pub dev: Option, +} + +impl Clean { + /// Cleans the snarkOS node storage. + pub fn parse(self) -> Result { + // Remove the specified ledger from storage. + Self::remove_ledger(self.network, self.dev) + } + + /// Removes the specified ledger from storage. + fn remove_ledger(network: u16, dev: Option) -> Result { + // Construct the path to the ledger in storage. + let path = aleo_std::aleo_ledger_dir(network, dev); + + // Prepare the path string. + let path_string = format!("(in \"{}\")", path.join("build").display()).dimmed(); + + // Check if the path to the ledger exists in storage. + if path.exists() { + // Remove the ledger files from storage. + match std::fs::remove_dir_all(&path) { + Ok(_) => Ok(format!("βœ… Cleaned the snarkOS node storage {path_string}")), + Err(error) => { + bail!("Failed to remove the snarkOS node storage {path_string}\n{}", error.to_string().dimmed()) + } + } + } else { + Ok(format!("βœ… No snarkOS node storage was found {path_string}")) + } + } +} diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs new file mode 100644 index 0000000000..76d119d935 --- /dev/null +++ b/cli/src/commands/mod.rs @@ -0,0 +1,77 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +mod account; +pub use account::*; + +mod clean; +pub use clean::*; + +mod start; +pub use start::*; + +mod update; +pub use update::*; + +use anyhow::Result; +use clap::Parser; + +#[derive(Debug, Parser)] +#[clap(name = "snarkOS", author = "The Aleo Team ", setting = clap::AppSettings::ColoredHelp)] +pub struct CLI { + /// Specify the verbosity [options: 0, 1, 2, 3] + #[clap(default_value = "2", short, long)] + pub verbosity: u8, + /// Specify a subcommand. + #[clap(subcommand)] + pub command: Command, +} + +#[derive(Debug, Parser)] +pub enum Command { + #[clap(subcommand)] + Account(Account), + #[clap(name = "clean")] + Clean(Clean), + #[clap(name = "start")] + Start(Start), + #[clap(name = "update")] + Update(Update), +} + +impl Command { + /// Parses the command. + pub fn parse(self) -> Result { + match self { + Self::Account(command) => command.parse(), + Self::Clean(command) => command.parse(), + Self::Start(command) => command.parse(), + Self::Update(command) => command.parse(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // As per the official clap recommendation. + #[test] + fn verify_cli() { + use clap::CommandFactory; + CLI::command().debug_assert() + } +} diff --git a/cli/src/commands/start.rs b/cli/src/commands/start.rs new file mode 100644 index 0000000000..dffcd60ea4 --- /dev/null +++ b/cli/src/commands/start.rs @@ -0,0 +1,187 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use snarkos_account::Account; +use snarkos_display::Display; +use snarkos_node::Node; +use snarkvm::prelude::PrivateKey; + +use anyhow::{bail, Result}; +use clap::Parser; +use core::str::FromStr; +use std::net::SocketAddr; +use tokio::runtime::{self, Runtime}; + +type Network = snarkvm::prelude::Testnet3; + +/// Starts the snarkOS node. +#[derive(Debug, Clone, Parser)] +pub struct Start { + /// Specify the network of this node. + #[clap(default_value = "3", long = "network")] + pub network: u16, + + /// Specify this as a beacon, with the given account private key for this node. + #[clap(long = "beacon")] + pub beacon: Option, + /// Specify this as a validator, with the given account private key for this node. + #[clap(long = "validator")] + pub validator: Option, + /// Specify this as a prover, with the given account private key for this node. + #[clap(long = "prover")] + pub prover: Option, + /// Specify this as a client, with an optional account private key for this node. + #[clap(long = "client")] + pub client: Option, + + /// Specify the IP address and port of a peer to connect to. + #[clap(default_value = "", long = "connect")] + pub connect: String, + /// Specify the IP address and port for the node server. + #[clap(default_value = "0.0.0.0:4133", long = "node")] + pub node: SocketAddr, + /// Specify the IP address and port for the REST server. + #[clap(parse(try_from_str), default_value = "0.0.0.0:3033")] + pub rest: SocketAddr, + /// If the flag is set, the node will not initialize the REST server. + #[clap(long)] + pub norest: bool, + + /// Specify the verbosity of the node [options: 0, 1, 2, 3] + #[clap(default_value = "2", long = "verbosity")] + pub verbosity: u8, + /// Enables development mode, specify a unique ID for the local node. + #[clap(long)] + pub dev: Option, + /// If the flag is set, the node will not render the display. + #[clap(long)] + pub nodisplay: bool, +} + +impl Start { + /// Starts the snarkOS node. + pub fn parse(self) -> Result { + // Initialize the runtime. + Self::runtime().block_on(async move { + // Clone the configurations. + let mut cli = self.clone(); + // Parse the node from the configurations. + let node = cli.parse_node().await.expect("Failed to parse the node"); + // Initialize the display. + let _ = Display::start(node, cli.verbosity, cli.nodisplay).expect("Failed to initialize the display"); + // Note: Do not move this. The pending await must be here otherwise + // other snarkOS commands will not exit. + std::future::pending::<()>().await; + }); + + Ok(String::new()) + } +} + +impl Start { + /// Returns the initial node(s) to connect to, from the given configurations. + fn parse_trusted_peers(&self) -> Result> { + match self.connect.is_empty() { + true => Ok(vec![]), + false => Ok(self + .connect + .split(',') + .flat_map(|ip| match ip.parse::() { + Ok(ip) => Some(ip), + Err(e) => { + eprintln!("The IP supplied to --connect ('{ip}') is malformed: {e}"); + None + } + }) + .collect()), + } + } + + /// Returns the node type corresponding to the given configurations. + #[rustfmt::skip] + async fn parse_node(&mut self) -> Result> { + // Parse the trusted IPs to connect to. + let mut trusted_peers = self.parse_trusted_peers()?; + // Parse the node IP. + let mut node_ip = self.node; + + // If `--dev` is set, assume the dev nodes are initialized from 0 to `dev`, + // and add each of them to the trusted peers. In addition, set the node IP to `4130 + dev`. + if let Some(dev) = self.dev { + // Add the dev nodes to the trusted peers. + for i in 0..dev { + trusted_peers.push(SocketAddr::from_str(&format!("127.0.0.1:{}", 4130 + i))?); + } + // Set the node IP to `4130 + dev`. + node_ip = SocketAddr::from_str(&format!("0.0.0.0:{}", 4130 + dev))?; + + // If the node type flag is set, but no private key is provided, then sample one. + let sample_account = |node: &mut Option| -> Result<()> { + let account = Account::::sample()?; + *node = Some(account.private_key().to_string()); + println!("ATTENTION - No private key was provided, sampling a one-time account for this node:\n\n{account}\n"); + Ok(()) + }; + if let Some("") = self.beacon.as_ref().map(|s| s.as_str()) { + sample_account(&mut self.beacon)?; + } else if let Some("") = self.validator.as_ref().map(|s| s.as_str()) { + sample_account(&mut self.validator)?; + } else if let Some("") = self.prover.as_ref().map(|s| s.as_str()) { + sample_account(&mut self.prover)?; + } else if let Some("") = self.client.as_ref().map(|s| s.as_str()) { + sample_account(&mut self.client)?; + } + } + + // Ensures only one of the four flags is set. If no flags are set, defaults to a client node. + match (&self.beacon, &self.validator, &self.prover, &self.client) { + (Some(private_key), None, None, None) => Node::new_beacon(node_ip, PrivateKey::::from_str(private_key)?, &trusted_peers, self.dev).await, + (None, Some(private_key), None, None) => Node::new_validator(node_ip, PrivateKey::::from_str(private_key)?, &trusted_peers, self.dev).await, + (None, None, Some(private_key), None) => Node::new_prover(node_ip, PrivateKey::::from_str(private_key)?, &trusted_peers, self.dev).await, + (None, None, None, Some(private_key)) => Node::new_client(node_ip, PrivateKey::::from_str(private_key)?, &trusted_peers, self.dev).await, + (None, None, None, None) => Node::new_client(node_ip, PrivateKey::::new(&mut rand::thread_rng())?, &trusted_peers, self.dev).await, + _ => bail!("Unsupported node configuration"), + } + } + + /// Returns a runtime for the node. + fn runtime() -> Runtime { + // TODO (howardwu): Fix this. + // let (num_tokio_worker_threads, max_tokio_blocking_threads, num_rayon_cores_global) = if !Self::node_type().is_beacon() { + // ((num_cpus::get() / 8 * 2).max(1), num_cpus::get(), (num_cpus::get() / 8 * 5).max(1)) + // } else { + // (num_cpus::get(), 512, num_cpus::get()) // 512 is tokio's current default + // }; + let (num_tokio_worker_threads, max_tokio_blocking_threads, num_rayon_cores_global) = + { ((num_cpus::get() / 8 * 2).max(1), num_cpus::get(), (num_cpus::get() / 8 * 5).max(1)) }; + + // Initialize the parallelization parameters. + rayon::ThreadPoolBuilder::new() + .stack_size(8 * 1024 * 1024) + .num_threads(num_rayon_cores_global) + .build_global() + .unwrap(); + + // Initialize the runtime configuration. + runtime::Builder::new_multi_thread() + .enable_all() + .thread_stack_size(8 * 1024 * 1024) + .worker_threads(num_tokio_worker_threads) + .max_blocking_threads(max_tokio_blocking_threads) + .build() + .expect("Failed to initialize a runtime for the router") + } +} diff --git a/cli/src/commands/update.rs b/cli/src/commands/update.rs new file mode 100644 index 0000000000..9481903d8e --- /dev/null +++ b/cli/src/commands/update.rs @@ -0,0 +1,65 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use crate::helpers::Updater; + +use anyhow::Result; +use clap::Parser; + +/// Update snarkOS. +#[derive(Debug, Parser)] +pub struct Update { + /// Lists all available versions of snarkOS + #[clap(short = 'l', long)] + list: bool, + /// Suppress outputs to terminal + #[clap(short = 'q', long)] + quiet: bool, + /// Update to specified version + #[clap(short = 'v', long)] + version: Option, +} + +impl Update { + /// Update snarkOS. + pub fn parse(self) -> Result { + match self.list { + true => match Updater::show_available_releases() { + Ok(output) => Ok(output), + Err(error) => Ok(format!("Failed to list the available versions of snarkOS\n{}\n", error)), + }, + false => { + let result = Updater::update_to_release(!self.quiet, self.version); + if !self.quiet { + match result { + Ok(status) => { + if status.uptodate() { + Ok("\nsnarkOS is already on the latest version".to_string()) + } else if status.updated() { + Ok(format!("\nsnarkOS has updated to version {}", status.version())) + } else { + Ok(String::new()) + } + } + Err(e) => Ok(format!("\nFailed to update snarkOS to the latest version\n{}\n", e)), + } + } else { + Ok(String::new()) + } + } + } + } +} diff --git a/cli/src/helpers/ledger.rs b/cli/src/helpers/ledger.rs new file mode 100644 index 0000000000..b20b170093 --- /dev/null +++ b/cli/src/helpers/ledger.rs @@ -0,0 +1,203 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use snarkvm::prelude::{ + Address, + Block, + BlockMemory, + Identifier, + Network, + PrivateKey, + Program, + ProgramID, + ProgramMemory, + ProgramStore, + RecordsFilter, + Transaction, + Value, + ViewKey, + Zero, + VM, +}; + +use anyhow::{bail, ensure, Result}; +use core::str::FromStr; +use parking_lot::RwLock; +use std::{convert::TryFrom, sync::Arc}; +use warp::{reply, Filter, Rejection}; + +pub(crate) type InternalStorage = ProgramMemory; +pub(crate) type InternalLedger = snarkvm::prelude::Ledger, InternalStorage>; +pub(crate) type InternalServer = snarkvm::prelude::Server, InternalStorage>; + +#[allow(dead_code)] +pub struct Ledger { + /// The internal ledger. + pub ledger: Arc>>, + /// The runtime. + runtime: tokio::runtime::Runtime, + /// The server. + server: InternalServer, + /// The account private key. + private_key: PrivateKey, + /// The account view key. + view_key: ViewKey, + /// The account address. + address: Address, +} + +impl Ledger { + /// Initializes a new instance of the ledger. + pub fn load(private_key: &PrivateKey) -> Result> { + // Derive the view key and address. + let view_key = ViewKey::try_from(private_key)?; + let address = Address::try_from(&view_key)?; + + // Initialize an RNG. + let rng = &mut ::rand::thread_rng(); + // Initialize the store. + let store = ProgramStore::<_, InternalStorage<_>>::open(None)?; + // Create a genesis block. + let genesis = Block::genesis(&VM::new(store)?, private_key, rng)?; + + // Initialize the ledger. + let ledger = Arc::new(RwLock::new(InternalLedger::new_with_genesis(&genesis, address, None)?)); + + // Initialize the additional routes. + let additional_routes = { + // GET /testnet3/development/privateKey + let get_development_private_key = warp::get() + .and(warp::path!("testnet3" / "development" / "privateKey")) + .and(snarkvm::rest::with(*private_key)) + .and_then(|private_key: PrivateKey| async move { + Ok::<_, Rejection>(reply::json(&private_key.to_string())) + }); + + // GET /testnet3/development/viewKey + let get_development_view_key = warp::get() + .and(warp::path!("testnet3" / "development" / "viewKey")) + .and(snarkvm::rest::with(view_key)) + .and_then(|view_key: ViewKey| async move { Ok::<_, Rejection>(reply::json(&view_key.to_string())) }); + + // GET /testnet3/development/address + let get_development_address = warp::get() + .and(warp::path!("testnet3" / "development" / "address")) + .and(snarkvm::rest::with(address)) + .and_then(|address: Address| async move { Ok::<_, Rejection>(reply::json(&address.to_string())) }); + + get_development_private_key.or(get_development_view_key).or(get_development_address) + }; + + // Initialize a runtime. + let runtime = + tokio::runtime::Builder::new_multi_thread().enable_all().thread_stack_size(8 * 1024 * 1024).build()?; + + // Initialize the server. + let ledger_clone = ledger.clone(); + let server = runtime.block_on(async move { + // Start the server. + InternalServer::::start(ledger_clone, Some(additional_routes), Some(4180)) + })?; + + // Return the ledger. + Ok(Arc::new(Self { ledger, runtime, server, private_key: *private_key, view_key, address })) + } + + /// Returns the account address. + pub const fn address(&self) -> &Address { + &self.address + } +} + +impl Ledger { + /// Adds the given transaction to the memory pool. + pub fn add_to_memory_pool(&self, transaction: Transaction) -> Result<()> { + self.ledger.write().add_to_memory_pool(transaction) + } + + /// Advances the ledger to the next block. + pub fn advance_to_next_block(&self) -> Result> { + // Initialize an RNG. + let rng = &mut ::rand::thread_rng(); + // Propose the next block. + let next_block = self.ledger.read().propose_next_block(&self.private_key, rng)?; + // Add the next block to the ledger. + if let Err(error) = self.ledger.write().add_next_block(&next_block) { + // Log the error. + eprintln!("{error}"); + } + // Return the next block. + Ok(next_block) + } + + /// Creates a deploy transaction. + pub fn create_deploy(&self, program: &Program, additional_fee: u64) -> Result> { + // Fetch the unspent record with the most gates. + let record = self + .ledger + .read() + .find_records(&self.view_key, RecordsFilter::Unspent)? + .max_by(|(_, a), (_, b)| (**a.gates()).cmp(&**b.gates())); + + // Prepare the additional fee. + let credits = match record { + Some((_, record)) => record, + None => bail!("The Aleo account has no records to spend."), + }; + ensure!(***credits.gates() >= additional_fee, "The additional fee exceeds the record balance."); + + // Deploy. + let transaction = Transaction::deploy( + self.ledger.read().vm(), + &self.private_key, + program, + (credits, additional_fee), + &mut rand::thread_rng(), + )?; + // Verify. + assert!(self.ledger.read().vm().verify(&transaction)); + // Return the transaction. + Ok(transaction) + } + + /// Creates a transfer transaction. + pub fn create_transfer(&self, to: &Address, amount: u64) -> Result> { + // Fetch the unspent record with the least gates. + let record = self + .ledger + .read() + .find_records(&self.view_key, RecordsFilter::Unspent)? + .filter(|(_, record)| !record.gates().is_zero()) + .min_by(|(_, a), (_, b)| (**a.gates()).cmp(&**b.gates())); + + // Prepare the record. + let record = match record { + Some((_, record)) => record, + None => bail!("The Aleo account has no records to spend."), + }; + + // Create a new transaction. + Transaction::execute( + self.ledger.read().vm(), + &self.private_key, + &ProgramID::from_str("credits.aleo")?, + Identifier::from_str("transfer")?, + &[Value::Record(record), Value::from_str(&format!("{to}"))?, Value::from_str(&format!("{amount}u64"))?], + None, + &mut rand::thread_rng(), + ) + } +} diff --git a/cli/src/helpers/mod.rs b/cli/src/helpers/mod.rs new file mode 100644 index 0000000000..3b0fabe804 --- /dev/null +++ b/cli/src/helpers/mod.rs @@ -0,0 +1,21 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +// pub mod ledger; +// pub use ledger::*; + +pub mod updater; +pub use updater::*; diff --git a/snarkos/updater.rs b/cli/src/helpers/updater.rs similarity index 100% rename from snarkos/updater.rs rename to cli/src/helpers/updater.rs diff --git a/cli/src/lib.rs b/cli/src/lib.rs new file mode 100644 index 0000000000..0f5ef75b88 --- /dev/null +++ b/cli/src/lib.rs @@ -0,0 +1,23 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +#![forbid(unsafe_code)] + +#[macro_use] +extern crate thiserror; + +pub mod commands; +pub mod helpers; diff --git a/display/Cargo.toml b/display/Cargo.toml new file mode 100644 index 0000000000..d3c24c740c --- /dev/null +++ b/display/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "snarkos-display" +version = "2.0.2" +authors = [ "The Aleo Team " ] +description = "A display for a decentralized operating system" +homepage = "https://aleo.org" +repository = "https://github.com/AleoHQ/snarkOS" +keywords = [ + "aleo", + "cryptography", + "blockchain", + "decentralized", + "zero-knowledge" +] +categories = [ "cryptography", "operating-systems" ] +license = "GPL-3.0" +edition = "2021" + +[dependencies.snarkos-node] +path = "../node" + +[dependencies.anyhow] +version = "1" + +[dependencies.colored] +version = "2.0" + +[dependencies.crossterm] +version = "0.25" + +[dependencies.snarkvm] +workspace = true + +[dependencies.tokio] +version = "1.21" +features = ["rt"] + +[dependencies.tracing] +version = "0.1" + +[dependencies.tracing-subscriber] +version = "0.3" +features = [ "env-filter" ] + +[dependencies.tui] +version = "0.19" diff --git a/display/LICENSE.md b/display/LICENSE.md new file mode 100644 index 0000000000..b95c626e2a --- /dev/null +++ b/display/LICENSE.md @@ -0,0 +1,596 @@ +GNU General Public License +========================== + +Version 3, 29 June 2007 + +Copyright Β© 2007 Free Software Foundation, Inc. <> + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: **(1)** assert +copyright on the software, and **(2)** offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions + +β€œThis License” refers to version 3 of the GNU General Public License. + +β€œCopyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +β€œThe Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as β€œyou”. β€œLicensees” and +β€œrecipients” may be individuals or organizations. + +To β€œmodify” a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a β€œmodified version” of the earlier work or a +work β€œbased on” the earlier work. + +A β€œcovered work” means either the unmodified Program or a work based on +the Program. + +To β€œpropagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To β€œconvey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays β€œAppropriate Legal Notices” to the +extent that it includes a convenient and prominently visible feature that **(1)** +displays an appropriate copyright notice, and **(2)** tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code + +The β€œsource code” for a work means the preferred form of the work for +making modifications to it. β€œObject code” means any non-source form of a +work. + +A β€œStandard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The β€œSystem Libraries” of an executable work include anything, other than +the work as a whole, that **(a)** is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and **(b)** serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A β€œMajor Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The β€œCorresponding Source” for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to β€œkeep intact all notices”. +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an β€œaggregate” if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either **(1)** a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or **(2)** access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A β€œUser Product” is either **(1)** a β€œconsumer product”, which +means any tangible personal property which is normally used for personal, family, or +household purposes, or **(2)** anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, β€œnormally used” refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +β€œInstallation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms + +β€œAdditional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered β€œfurther +restrictions” within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated **(a)** provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and **(b)** permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An β€œentity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents + +A β€œcontributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's β€œcontributor version”. + +A contributor's β€œessential patent claims” are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, β€œcontrol” includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a β€œpatent license” is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To β€œgrant” such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either **(1)** cause the Corresponding +Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the +patent license for this particular work, or **(3)** arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. β€œKnowingly relying” means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is β€œdiscriminatory” if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license **(a)** in connection with +copies of the covered work conveyed by you (or copies made from those copies), or **(b)** +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License β€œor any later +version” applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM β€œAS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16 + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +_END OF TERMS AND CONDITIONS_ + +## How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to +the public, the best way to achieve this is to make it free software which everyone +can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them +to the start of each source file to most effectively state the exclusion of warranty; +and each file should have at least the β€œcopyright” line and a pointer to +where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands `show w` and `show c` should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an β€œabout box”. + +You should also get your employer (if you work as a programmer) or school, if any, to +sign a β€œcopyright disclaimer” for the program, if necessary. For more +information on this, and how to apply and follow the GNU GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. diff --git a/display/README.md b/display/README.md new file mode 100644 index 0000000000..aa15bf5132 --- /dev/null +++ b/display/README.md @@ -0,0 +1,7 @@ +# snarkos-display + +[![Crates.io](https://img.shields.io/crates/v/snarkos-display.svg?color=neon)](https://crates.io/crates/snarkos-display) +[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](https://aleo.org) +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md) + +The `snarkos-display` crate provides the `Display` struct, which is responsible for displaying information about the node. diff --git a/display/src/lib.rs b/display/src/lib.rs new file mode 100644 index 0000000000..88328f303d --- /dev/null +++ b/display/src/lib.rs @@ -0,0 +1,266 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +#![forbid(unsafe_code)] + +mod log_writer; +use log_writer::*; + +mod pages; +use pages::*; + +mod tabs; +use tabs::Tabs; + +use snarkos_node::Node; +use snarkvm::prelude::Network; + +use anyhow::Result; +use colored::*; +use crossterm::{ + event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}, + execute, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, + tty::IsTty, +}; +use std::{ + io, + thread, + time::{Duration, Instant}, +}; +use tokio::sync::mpsc; +use tracing_subscriber::EnvFilter; +use tui::{ + backend::{Backend, CrosstermBackend}, + layout::{Constraint, Direction, Layout}, + style::{Color, Modifier, Style}, + text::{Span, Spans}, + widgets::{Block, Borders, Tabs as TabsTui}, + Frame, + Terminal, +}; + +pub struct Display { + /// An instance of the node. + node: Node, + /// The tick rate of the display. + tick_rate: Duration, + /// The state of the tabs. + tabs: Tabs, + /// The logs tab. + logs: Logs, +} + +impl<'a, N: Network> Display { + /// Initializes a new display. + pub fn start(node: Node, verbosity: u8, nodisplay: bool) -> Result<()> { + // Initialize the logger. + let log_receiver = Self::initialize_logger(verbosity, nodisplay); + + // If the display is not enabled, render the welcome message. + if nodisplay { + // Print the welcome. + println!("{}", Self::welcome_message()); + // Print the Aleo address. + println!("Your Aleo address is {}.\n", node.address().to_string().bold()); + // Print the node type and network. + println!("Starting {} on {}.\n", node.node_type().description().bold(), N::NAME.bold()); + } + // If the display is enabled, render the display. + else { + // Initialize the display. + enable_raw_mode()?; + let mut stdout = io::stdout(); + execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; + let backend = CrosstermBackend::new(stdout); + let mut terminal = Terminal::new(backend)?; + + // Initialize the display. + let mut display = Self { + node, + tick_rate: Duration::from_secs(1), + tabs: Tabs::new(PAGES.to_vec()), + logs: Logs::new(log_receiver), + }; + + // Render the display. + let res = display.render(&mut terminal); + + // Terminate the display. + disable_raw_mode()?; + execute!(terminal.backend_mut(), LeaveAlternateScreen, DisableMouseCapture)?; + terminal.show_cursor()?; + + // Exit. + if let Err(err) = res { + println!("{:?}", err) + } + } + + Ok(()) + } +} + +impl Display { + /// Initializes the logger. + fn initialize_logger(verbosity: u8, nodisplay: bool) -> mpsc::Receiver> { + match verbosity { + 0 => std::env::set_var("RUST_LOG", "info"), + 1 => std::env::set_var("RUST_LOG", "debug"), + 2 | 3 => std::env::set_var("RUST_LOG", "trace"), + _ => std::env::set_var("RUST_LOG", "info"), + }; + + // Filter out undesirable logs. + let filter = EnvFilter::from_default_env() + .add_directive("mio=off".parse().unwrap()) + .add_directive("tokio_util=off".parse().unwrap()) + .add_directive("hyper::proto::h1::conn=off".parse().unwrap()) + .add_directive("hyper::proto::h1::decode=off".parse().unwrap()) + .add_directive("hyper::proto::h1::io=off".parse().unwrap()) + .add_directive("hyper::proto::h1::role=off".parse().unwrap()) + .add_directive("jsonrpsee=off".parse().unwrap()); + + // Initialize the log channel. + let (log_sender, log_receiver) = mpsc::channel(1024); + + // Initialize the log sender. + let log_sender = match nodisplay { + true => None, + false => Some(log_sender), + }; + + // Initialize tracing. + let _ = tracing_subscriber::fmt() + .with_env_filter(filter) + .with_ansi(log_sender.is_none() && io::stdout().is_tty()) + .with_writer(move || LogWriter::new(&log_sender)) + .with_target(verbosity == 3) + .try_init(); + + log_receiver + } + + /// Renders the display. + fn render(&mut self, terminal: &mut Terminal) -> io::Result<()> { + let mut last_tick = Instant::now(); + loop { + terminal.draw(|f| self.draw(f))?; + + // Set the timeout duration. + let timeout = self.tick_rate.checked_sub(last_tick.elapsed()).unwrap_or_else(|| Duration::from_secs(0)); + + if event::poll(timeout)? { + if let Event::Key(key) = event::read()? { + match key.code { + KeyCode::Esc => { + // // TODO (howardwu): @ljedrz to implement a wrapping scope for Display within Node/Server. + // #[allow(unused_must_use)] + // { + // self.node.shut_down(); + // } + return Ok(()); + } + KeyCode::Left => self.tabs.previous(), + KeyCode::Right => self.tabs.next(), + _ => {} + } + } + } + + if last_tick.elapsed() >= self.tick_rate { + thread::sleep(Duration::from_millis(50)); + last_tick = Instant::now(); + } + } + } + + /// Draws the display. + fn draw(&mut self, f: &mut Frame) { + /* Layout */ + + // Initialize the layout of the page. + let chunks = Layout::default() + .margin(1) + .direction(Direction::Vertical) + .constraints([Constraint::Length(3), Constraint::Min(0)].as_ref()) + .split(f.size()); + + /* Tabs */ + + // Initialize the tabs. + let block = Block::default().style(Style::default().bg(Color::Black).fg(Color::White)); + f.render_widget(block, f.size()); + let titles = self + .tabs + .titles + .iter() + .map(|t| { + let (first, rest) = t.split_at(1); + Spans::from(vec![ + Span::styled(first, Style::default().fg(Color::Yellow)), + Span::styled(rest, Style::default().fg(Color::Green)), + ]) + }) + .collect(); + let tabs = TabsTui::new(titles) + .block( + Block::default() + .borders(Borders::ALL) + .title("Welcome to Aleo.") + .style(Style::default().add_modifier(Modifier::BOLD)), + ) + .select(self.tabs.index) + .style(Style::default().fg(Color::Cyan)) + .highlight_style(Style::default().add_modifier(Modifier::BOLD).bg(Color::White)); + f.render_widget(tabs, chunks[0]); + + /* Pages */ + + // Initialize the page. + match self.tabs.index { + 0 => Overview.draw(f, chunks[1]), + 1 => self.logs.draw(f, chunks[1]), + _ => unreachable!(), + }; + } + + /// Returns the welcome message as a string. + fn welcome_message() -> String { + use colored::*; + + let mut output = String::new(); + output += &r#" + + ╦╬╬╬╬╬╦ + ╬╬╬╬╬╬╬╬╬ β–„β–„β–„β–„ β–„β–„β–„ + ╬╬╬╬╬╬╬╬╬╬╬ β–β–“β–“β–“β–“β–Œ β–“β–“β–“ + ╬╬╬╬╬╬╬╬╬╬╬╬╬ β–β–“β–“β–“β–“β–“β–“β–Œ β–“β–“β–“ β–„β–„β–„β–„β–„β–„ β–„β–„β–„β–„β–„β–„ + ╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ▐▓▓▓ β–“β–“β–“β–Œ β–“β–“β–“ β–„β–“β–“β–€β–€β–€β–€β–“β–“β–„ β–β–“β–“β–“β–“β–“β–“β–“β–“β–Œ + β•¬β•¬β•¬β•¬β•¬β•¬β•¬β•œ ╙╬╬╬╬╬╬╬ β–β–“β–“β–“β–Œ β–β–“β–“β–“β–Œ β–“β–“β–“ β–β–“β–“β–“β–„β–„β–„β–„β–“β–“β–“β–Œ ▐▓▓▓ β–“β–“β–“β–Œ + ╬╬╬╬╬╬╣ ╠╬╬╬╬╬╬ β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“ β–“β–“β–“ β–β–“β–“β–€β–€β–€β–€β–€β–€β–€β–€β–˜ ▐▓▓▓ β–“β–“β–“β–Œ + ╬╬╬╬╬╬╣ ╠╬╬╬╬╬╬ β–“β–“β–“β–“β–Œ ▐▓▓▓▓ β–“β–“β–“ β–€β–“β–“β–„β–„β–„β–„β–“β–“β–€ β–β–“β–“β–“β–“β–“β–“β–“β–“β–Œ + ╬╬╬╬╬╬╣ ╠╬╬╬╬╬╬ ▝▀▀▀▀ β–€β–€β–€β–€β–˜ β–€β–€β–€ β–€β–€β–€β–€β–€β–€ β–€β–€β–€β–€β–€β–€ +β•šβ•¬β•¬β•¬β•¬β•¬β•© ╩╬╬╬╬╩ + + +"# + .white() + .bold(); + output += &"Welcome to Aleo! We thank you for running a node and supporting privacy.\n".bold(); + output + } +} diff --git a/display/src/log_writer.rs b/display/src/log_writer.rs new file mode 100644 index 0000000000..da60fe681d --- /dev/null +++ b/display/src/log_writer.rs @@ -0,0 +1,51 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use std::io; +use tokio::sync::mpsc; + +pub enum LogWriter { + /// Writes to stdout. + Stdout(io::Stdout), + /// Writes to a channel. + Sender(mpsc::Sender>), +} + +impl LogWriter { + /// Initialize a new log writer. + pub fn new(log_sender: &Option>>) -> Self { + if let Some(sender) = log_sender { Self::Sender(sender.clone()) } else { Self::Stdout(io::stdout()) } + } +} + +impl io::Write for LogWriter { + /// Writes the given buffer into the log writer. + fn write(&mut self, buf: &[u8]) -> io::Result { + match self { + Self::Stdout(stdout) => stdout.write(buf), + Self::Sender(sender) => { + let log = buf.to_vec(); + let _ = sender.try_send(log); + Ok(buf.len()) + } + } + } + + /// Flushes the log writer (no-op). + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} diff --git a/display/src/pages/logs.rs b/display/src/pages/logs.rs new file mode 100644 index 0000000000..f624370c54 --- /dev/null +++ b/display/src/pages/logs.rs @@ -0,0 +1,76 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use std::collections::VecDeque; +use tokio::sync::mpsc; +use tui::{ + backend::Backend, + layout::{Constraint, Direction, Layout, Rect}, + widgets::{Block, Borders, Paragraph}, + Frame, +}; + +pub(crate) struct Logs { + log_receiver: mpsc::Receiver>, + log_cache: VecDeque, + log_limit: usize, +} + +impl Logs { + pub(crate) fn new(log_receiver: mpsc::Receiver>) -> Self { + let log_limit = 128; // an arbitrary number fitting the testing terminal room + + Self { log_receiver, log_cache: VecDeque::with_capacity(log_limit), log_limit } + } + + pub(crate) fn draw(&mut self, f: &mut Frame, area: Rect) { + // Initialize the layout of the page. + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([Constraint::Percentage(100)].as_ref()) + .split(area); + + let mut new_logs = Vec::new(); + while let Ok(log) = self.log_receiver.try_recv() { + new_logs.push(match String::from_utf8(log) { + Ok(log) => log, + _ => String::new(), + }); + } + + let all_logs = self.log_cache.len() + new_logs.len(); + if all_logs > self.log_limit { + let remaining_room = self.log_limit - self.log_cache.len(); + let overflow = all_logs - self.log_cache.len(); + + if overflow > self.log_limit { + self.log_cache.clear(); + } else { + let missing_room = all_logs - remaining_room; + for _ in 0..missing_room { + self.log_cache.pop_front(); + } + } + }; + + self.log_cache.extend(new_logs.into_iter().take(self.log_limit)); + + let combined_logs = self.log_cache.iter().map(|s| s.as_str()).collect::(); + + let combined_logs = Paragraph::new(combined_logs).block(Block::default().borders(Borders::ALL).title("Logs")); + f.render_widget(combined_logs, chunks[0]); + } +} diff --git a/display/src/pages/mod.rs b/display/src/pages/mod.rs new file mode 100644 index 0000000000..d46e2fc91d --- /dev/null +++ b/display/src/pages/mod.rs @@ -0,0 +1,23 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +mod logs; +pub(crate) use logs::Logs; + +mod overview; +pub(crate) use overview::Overview; + +pub(crate) const PAGES: [&'static str; 2] = [" Overview ", " Logs "]; diff --git a/display/src/pages/overview.rs b/display/src/pages/overview.rs new file mode 100644 index 0000000000..e1af1882ae --- /dev/null +++ b/display/src/pages/overview.rs @@ -0,0 +1,51 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use tui::{ + backend::Backend, + layout::{Constraint, Direction, Layout, Rect}, + style::{Color, Style}, + text::Span, + widgets::{canvas::Canvas, Block, Borders}, + Frame, +}; + +pub(crate) struct Overview; + +impl Overview { + pub(crate) fn draw(&self, f: &mut Frame, area: Rect) { + // Initialize the layout of the page. + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([Constraint::Percentage(10), Constraint::Percentage(70), Constraint::Max(2)].as_ref()) + .split(area); + + let canvas = Canvas::default().block(Block::default().borders(Borders::ALL).title("Block")).paint(|_ctx| { + // ctx.draw(&ball); + }); + f.render_widget(canvas, chunks[0]); + + let canvas = Canvas::default().block(Block::default().borders(Borders::ALL).title("Peers")).paint(|_ctx| { + // ctx.draw(&ball); + }); + f.render_widget(canvas, chunks[1]); + + let canvas = Canvas::default().block(Block::default().borders(Borders::ALL).title("Help")).paint(|ctx| { + ctx.print(0f64, 0f64, Span::styled("Press ESC to quit", Style::default().fg(Color::White))); + }); + f.render_widget(canvas, chunks[2]); + } +} diff --git a/display/src/tabs.rs b/display/src/tabs.rs new file mode 100644 index 0000000000..80da36e399 --- /dev/null +++ b/display/src/tabs.rs @@ -0,0 +1,38 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +pub(super) struct Tabs { + pub titles: Vec<&'static str>, + pub index: usize, +} + +impl Tabs { + pub fn new(titles: Vec<&'static str>) -> Self { + Self { titles, index: 0 } + } + + pub fn next(&mut self) { + self.index = (self.index + 1) % self.titles.len(); + } + + pub fn previous(&mut self) { + if self.index > 0 { + self.index -= 1; + } else { + self.index = self.titles.len() - 1; + } + } +} diff --git a/environment/README.md b/environment/README.md deleted file mode 100644 index ef99949b31..0000000000 --- a/environment/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# snarkos-environment - -[![Crates.io](https://img.shields.io/crates/v/snarkos-environment.svg?color=neon)](https://crates.io/crates/snarkos-environment) -[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](https://aleo.org) -[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md) diff --git a/environment/src/helpers/block_locators.rs b/environment/src/helpers/block_locators.rs deleted file mode 100644 index c968ef82ed..0000000000 --- a/environment/src/helpers/block_locators.rs +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (C) 2019-2022 Aleo Systems Inc. -// This file is part of the snarkOS library. - -// The snarkOS library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The snarkOS library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the snarkOS library. If not, see . - -// TODO (raychu86): Move block locators out of the network module. - -/// The maximum number of linear block locators. -pub const MAXIMUM_LINEAR_BLOCK_LOCATORS: u32 = 64; -/// The maximum number of quadratic block locators. -pub const MAXIMUM_QUADRATIC_BLOCK_LOCATORS: u32 = 32; -/// The total maximum number of block locators. -pub const MAXIMUM_BLOCK_LOCATORS: u32 = MAXIMUM_LINEAR_BLOCK_LOCATORS.saturating_add(MAXIMUM_QUADRATIC_BLOCK_LOCATORS); - -use snarkvm::{ - compiler::Header, - prelude::Network, - utilities::{ - fmt, - io::{Read, Result as IoResult, Write}, - str::FromStr, - FromBytes, - FromBytesDeserializer, - ToBytes, - ToBytesSerializer, - }, -}; - -use anyhow::{bail, Result}; -use rayon::{iter::IntoParallelIterator, prelude::*}; -use serde::{de, ser, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer}; -use std::{ - collections::BTreeMap, - io::{Error, ErrorKind}, - ops::Deref, -}; - -/// -/// A helper struct to represent block locators from the ledger. -/// -/// The current format of block locators is \[(block_height, block_hash, block_header)\]. -/// -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BlockLocators { - block_locators: BTreeMap>)>, -} - -impl BlockLocators { - #[inline] - pub fn from(block_locators: BTreeMap>)>) -> Result { - // Check that the number of block_locators is greater than 0 and less than the MAXIMUM_BLOCK_LOCATORS. - let num_locators = block_locators.len(); - match num_locators > 0 && num_locators <= MAXIMUM_BLOCK_LOCATORS as usize { - true => Ok(Self { block_locators }), - false => { - let error = format!( - "Invalid number of block locators. Expected between 1 and {}, found {}", - MAXIMUM_BLOCK_LOCATORS, num_locators - ); - error!("{}", error); - bail!("{}", error) - } - } - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.block_locators.is_empty() - } - - #[inline] - pub fn len(&self) -> usize { - self.block_locators.len() - } - - #[inline] - pub fn get_block_hash(&self, block_height: u32) -> Option { - self.block_locators.get(&block_height).map(|(block_hash, _)| *block_hash) - } - - // #[inline] - // pub fn get_cumulative_weight(&self, block_height: u32) -> Option { - // match self.block_locators.get(&block_height) { - // Some((_, header)) => header.as_ref().map(|header| header.cumulative_weight()), - // _ => None, - // } - // } -} - -impl FromBytes for BlockLocators { - #[inline] - fn read_le(mut reader: R) -> IoResult { - let num_locators: u32 = FromBytes::read_le(&mut reader)?; - - // Check that the number of block_locators is greater than 0 and less than the MAXIMUM_BLOCK_LOCATORS. - if num_locators == 0 || num_locators > MAXIMUM_BLOCK_LOCATORS { - error!( - "Invalid number of block locators. Expected between 1 and {}, found {}", - MAXIMUM_BLOCK_LOCATORS, num_locators - ); - return Err(ErrorKind::Other.into()); - } - - let mut block_headers_bytes = Vec::with_capacity(num_locators as usize); - - for _ in 0..num_locators { - let height: u32 = FromBytes::read_le(&mut reader)?; - let hash: N::BlockHash = FromBytes::read_le(&mut reader)?; - let header_exists: bool = FromBytes::read_le(&mut reader)?; - - if header_exists { - // TODO (raychu86): Reintroduce formal block header size. - // let mut buffer = vec![0u8; Header::::size_in_bytes()]; - let mut buffer = vec![0u8; 102]; - reader.read_exact(&mut buffer)?; - block_headers_bytes.push((height, hash, Some(buffer))); - } else { - block_headers_bytes.push((height, hash, None)); - } - } - - let block_locators = block_headers_bytes - .into_par_iter() - .map(|(height, hash, bytes)| (height, (hash, bytes.map(|bytes| Header::::read_le(&bytes[..]).unwrap())))) - .collect::>(); - - Self::from(block_locators).map_err(|error| Error::new(ErrorKind::Other, error)) - } -} - -impl ToBytes for BlockLocators { - #[inline] - fn write_le(&self, mut writer: W) -> IoResult<()> { - (self.block_locators.len() as u32).write_le(&mut writer)?; - - for (height, (hash, header)) in &self.block_locators { - height.write_le(&mut writer)?; - hash.write_le(&mut writer)?; - match header { - Some(header) => { - true.write_le(&mut writer)?; - header.write_le(&mut writer)?; - } - None => false.write_le(&mut writer)?, - } - } - Ok(()) - } -} - -impl FromStr for BlockLocators { - type Err = anyhow::Error; - - fn from_str(block_locators: &str) -> Result { - Ok(serde_json::from_str(block_locators)?) - } -} - -impl fmt::Display for BlockLocators { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", serde_json::to_string(self).map_err::(ser::Error::custom)?) - } -} - -impl Serialize for BlockLocators { - fn serialize(&self, serializer: S) -> Result { - match serializer.is_human_readable() { - true => { - let mut block_locators = serializer.serialize_struct("BlockLocators", 1)?; - block_locators.serialize_field("block_locators", &self.block_locators)?; - block_locators.end() - } - false => ToBytesSerializer::serialize_with_size_encoding(self, serializer), - } - } -} - -impl<'de, N: Network> Deserialize<'de> for BlockLocators { - fn deserialize>(deserializer: D) -> Result { - match deserializer.is_human_readable() { - true => { - let block_locators = serde_json::Value::deserialize(deserializer)?; - let block_locators: BTreeMap>)> = - serde_json::from_value(block_locators["block_locators"].clone()).map_err(de::Error::custom)?; - Self::from(block_locators).map_err(de::Error::custom) - } - false => FromBytesDeserializer::::deserialize_with_size_encoding(deserializer, "block locators"), - } - } -} - -impl Default for BlockLocators { - #[inline] - fn default() -> Self { - // Initialize the list of block locators. - let mut block_locators: BTreeMap>)> = Default::default(); - // Add the genesis locator. - // TODO (raychu86): Insert the genesis block hash. - block_locators.insert(0, (N::BlockHash::default(), None)); - // block_locators.insert(0, (N::genesis_block().hash(), None)); - - Self { block_locators } - } -} - -impl Deref for BlockLocators { - type Target = BTreeMap>)>; - - fn deref(&self) -> &Self::Target { - &self.block_locators - } -} - -#[cfg(test)] -mod tests { - use super::*; - - pub type CurrentNetwork = snarkvm::prelude::Testnet3; - - #[test] - fn test_block_locators_serde_json() { - // let expected_block_height = CurrentNetwork::genesis_block().height(); - // let expected_block_hash = CurrentNetwork::genesis_block().hash(); - // let expected_block_header = CurrentNetwork::genesis_block().header().clone(); - // let expected_block_locators = - // BlockLocators::::from([(expected_block_height, (expected_block_hash, Some(expected_block_header)))].into()) - // .unwrap(); - // - // // Serialize - // let expected_string = expected_block_locators.to_string(); - // let candidate_string = serde_json::to_string(&expected_block_locators).unwrap(); - // assert_eq!(1703, candidate_string.len(), "Update me if serialization has changed"); - // assert_eq!(expected_string, candidate_string); - // - // // Deserialize - // assert_eq!(expected_block_locators, BlockLocators::from_str(&candidate_string).unwrap()); - // assert_eq!(expected_block_locators, serde_json::from_str(&candidate_string).unwrap()); - } - - #[test] - fn test_block_locators_bincode() { - // let expected_block_height = CurrentNetwork::genesis_block().height(); - // let expected_block_hash = CurrentNetwork::genesis_block().hash(); - // let expected_block_header = CurrentNetwork::genesis_block().header().clone(); - // let expected_block_locators = - // BlockLocators::::from([(expected_block_height, (expected_block_hash, Some(expected_block_header)))].into()) - // .unwrap(); - // - // // Serialize - // let expected_bytes = expected_block_locators.to_bytes_le().unwrap(); - // let candidate_bytes = bincode::serialize(&expected_block_locators).unwrap(); - // assert_eq!(944, expected_bytes.len(), "Update me if serialization has changed"); - // // TODO (howardwu): Serialization - Handle the inconsistency between ToBytes and Serialize (off by a length encoding). - // assert_eq!(&expected_bytes[..], &candidate_bytes[8..]); - // - // // Deserialize - // assert_eq!(expected_block_locators, BlockLocators::read_le(&expected_bytes[..]).unwrap()); - // assert_eq!(expected_block_locators, bincode::deserialize(&candidate_bytes[..]).unwrap()); - } -} diff --git a/environment/src/lib.rs b/environment/src/lib.rs deleted file mode 100644 index f86bc7320a..0000000000 --- a/environment/src/lib.rs +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (C) 2019-2022 Aleo Systems Inc. -// This file is part of the snarkOS library. - -// The snarkOS library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The snarkOS library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the snarkOS library. If not, see . - -#![forbid(unsafe_code)] - -#[macro_use] -extern crate tracing; - -pub mod helpers; - -use crate::helpers::{NodeType, RawStatus, Resources}; -use snarkvm::prelude::Network; - -use core::{fmt::Debug, marker::PhantomData}; -use once_cell::sync::OnceCell; -use rayon::{ThreadPool, ThreadPoolBuilder}; -use std::{ - collections::HashSet, - net::SocketAddr, - sync::{atomic::AtomicBool, Arc}, -}; - -#[rustfmt::skip] -pub trait Environment: 'static + Clone + Debug + Send + Sync { - type Network: Network; - /// The specified type of node. - const NODE_TYPE: NodeType; - /// The version of the network protocol; it can be incremented in order to force users to update. - const MESSAGE_VERSION: u32 = 0; - /// If `true`, a mining node will craft public coinbase transactions. - const COINBASE_IS_PUBLIC: bool = false; - - /// The port for communicating with the node server. - const DEFAULT_NODE_PORT: u16 = 4130 + Self::Network::ID; - /// The port for communicating with the RPC server. - const DEFAULT_RPC_PORT: u16 = 3030 + Self::Network::ID; - - /// The list of sync nodes to bootstrap the node server with. - const BEACON_NODES: &'static [&'static str] = &["127.0.0.1:4135"]; - /// The list of nodes to attempt to maintain connections with. - const TRUSTED_NODES: &'static [&'static str] = &[]; - - /// The duration in seconds to sleep in between heartbeat executions. - const HEARTBEAT_IN_SECS: u64 = 9; - /// The maximum duration in seconds permitted for establishing a connection with a node, - /// before dropping the connection; it should be no greater than the `HEARTBEAT_IN_SECS`. - const CONNECTION_TIMEOUT_IN_MILLIS: u64 = 500; - /// The duration in seconds to sleep in between ping requests with a connected peer. - const PING_SLEEP_IN_SECS: u64 = 60; - /// The duration in seconds after which a connected peer is considered inactive or - /// disconnected if no message has been received in the meantime. - const RADIO_SILENCE_IN_SECS: u64 = 210; // 3.5 minutes - /// The duration in seconds after which to expire a failure from a peer. - const FAILURE_EXPIRY_TIME_IN_SECS: u64 = 7200; // 2 hours - - /// The minimum number of peers required to maintain connections with. - const MINIMUM_NUMBER_OF_PEERS: usize; - /// The maximum number of peers permitted to maintain connections with. - const MAXIMUM_NUMBER_OF_PEERS: usize; - /// The maximum number of connection failures permitted by an inbound connecting peer. - const MAXIMUM_CONNECTION_FAILURES: u32 = 3; - /// The maximum number of candidate peers permitted to be stored in the node. - const MAXIMUM_CANDIDATE_PEERS: usize = 10_000; - - /// The maximum number of blocks that may be fetched in one request. - const MAXIMUM_BLOCK_REQUEST: u32 = 250; - /// The maximum number of failures tolerated before disconnecting from a peer. - const MAXIMUM_NUMBER_OF_FAILURES: usize = 1024; - - /// Returns the list of sync nodes to bootstrap the node server with. - fn beacon_nodes() -> &'static HashSet { - static NODES: OnceCell> = OnceCell::new(); - NODES.get_or_init(|| Self::BEACON_NODES.iter().map(|ip| ip.parse().unwrap()).collect()) - } - - /// Returns the list of trusted nodes. - fn trusted_nodes() -> &'static HashSet { - static NODES: OnceCell> = OnceCell::new(); - NODES.get_or_init(|| Self::TRUSTED_NODES.iter().map(|ip| ip.parse().unwrap()).collect()) - } - - /// Returns the resource handler for the node. - fn resources() -> &'static Resources { - static RESOURCES: OnceCell = OnceCell::new(); - RESOURCES.get_or_init(Resources::default) - } - - /// Returns the status of the node. - fn status() -> &'static RawStatus { - static STATUS: OnceCell = OnceCell::new(); - STATUS.get_or_init(RawStatus::default) - } - - /// Returns the terminator bit for the prover. - fn terminator() -> &'static Arc { - static TERMINATOR: OnceCell> = OnceCell::new(); - TERMINATOR.get_or_init(|| Arc::new(AtomicBool::new(false))) - } - - /// Returns a thread pool for the node to perform intensive operations. - fn thread_pool() -> &'static Arc { - static POOL: OnceCell> = OnceCell::new(); - POOL.get_or_init(|| { - Arc::new(ThreadPoolBuilder::new() - .stack_size(8 * 1024 * 1024) - .num_threads((num_cpus::get() * 7 / 8).max(2)) - .build() - .expect("Failed to initialize a thread pool for the node")) - }) - } -} - -#[derive(Clone, Debug, Default)] -pub struct Client(PhantomData); - -#[rustfmt::skip] -impl Environment for Client { - type Network = N; - const NODE_TYPE: NodeType = NodeType::Client; - const MINIMUM_NUMBER_OF_PEERS: usize = 2; - const MAXIMUM_NUMBER_OF_PEERS: usize = 21; -} - -#[derive(Clone, Debug, Default)] -pub struct Validator(PhantomData); - -#[rustfmt::skip] -impl Environment for Validator { - type Network = N; - const NODE_TYPE: NodeType = NodeType::Validator; - const COINBASE_IS_PUBLIC: bool = true; - const MINIMUM_NUMBER_OF_PEERS: usize = 21; - const MAXIMUM_NUMBER_OF_PEERS: usize = 100; -} - -#[derive(Clone, Debug, Default)] -pub struct Prover(PhantomData); - -#[rustfmt::skip] -impl Environment for Prover { - type Network = N; - const NODE_TYPE: NodeType = NodeType::Prover; - const COINBASE_IS_PUBLIC: bool = true; - const MINIMUM_NUMBER_OF_PEERS: usize = 2; - const MAXIMUM_NUMBER_OF_PEERS: usize = 21; -} - -#[derive(Clone, Debug, Default)] -pub struct Beacon(PhantomData); - -#[rustfmt::skip] -impl Environment for Beacon { - type Network = N; - const NODE_TYPE: NodeType = NodeType::Beacon; - const MINIMUM_NUMBER_OF_PEERS: usize = 35; - const MAXIMUM_NUMBER_OF_PEERS: usize = 1024; - const HEARTBEAT_IN_SECS: u64 = 5; -} - -#[derive(Clone, Debug, Default)] -pub struct ClientTrial(PhantomData); - -#[rustfmt::skip] -impl Environment for ClientTrial { - type Network = N; - const NODE_TYPE: NodeType = NodeType::Client; - const BEACON_NODES: &'static [&'static str] = &[ - "144.126.219.193:4132", "165.232.145.194:4132", "143.198.164.241:4132", "188.166.7.13:4132", "167.99.40.226:4132", - "159.223.124.150:4132", "137.184.192.155:4132", "147.182.213.228:4132", "137.184.202.162:4132", "159.223.118.35:4132", - "161.35.106.91:4132", "157.245.133.62:4132", "143.198.166.150:4132", - ]; - const MINIMUM_NUMBER_OF_PEERS: usize = 11; - const MAXIMUM_NUMBER_OF_PEERS: usize = 31; -} - -#[derive(Clone, Debug, Default)] -pub struct ValidatorTrial(PhantomData); - -#[rustfmt::skip] -impl Environment for ValidatorTrial { - type Network = N; - const NODE_TYPE: NodeType = NodeType::Validator; - const BEACON_NODES: &'static [&'static str] = &[ - "144.126.219.193:4132", "165.232.145.194:4132", "143.198.164.241:4132", "188.166.7.13:4132", "167.99.40.226:4132", - "159.223.124.150:4132", "137.184.192.155:4132", "147.182.213.228:4132", "137.184.202.162:4132", "159.223.118.35:4132", - "161.35.106.91:4132", "157.245.133.62:4132", "143.198.166.150:4132", - ]; - const MINIMUM_NUMBER_OF_PEERS: usize = 11; - const MAXIMUM_NUMBER_OF_PEERS: usize = 1000; - const COINBASE_IS_PUBLIC: bool = true; -} - -#[derive(Clone, Debug, Default)] -pub struct ProverTrial(PhantomData); - -#[rustfmt::skip] -impl Environment for ProverTrial { - type Network = N; - const NODE_TYPE: NodeType = NodeType::Prover; - const BEACON_NODES: &'static [&'static str] = &[ - "144.126.219.193:4132", "165.232.145.194:4132", "143.198.164.241:4132", "188.166.7.13:4132", "167.99.40.226:4132", - "159.223.124.150:4132", "137.184.192.155:4132", "147.182.213.228:4132", "137.184.202.162:4132", "159.223.118.35:4132", - "161.35.106.91:4132", "157.245.133.62:4132", "143.198.166.150:4132", - ]; - const MINIMUM_NUMBER_OF_PEERS: usize = 11; - const MAXIMUM_NUMBER_OF_PEERS: usize = 21; - const COINBASE_IS_PUBLIC: bool = true; -} - -#[derive(Clone, Debug, Default)] -pub struct TestEnvironment(PhantomData); - -#[rustfmt::skip] -impl Environment for TestEnvironment { - type Network = N; - const NODE_TYPE: NodeType = NodeType::Prover; - const BEACON_NODES: &'static [&'static str] = &[]; - const MINIMUM_NUMBER_OF_PEERS: usize = 1; - const MAXIMUM_NUMBER_OF_PEERS: usize = 5; - const COINBASE_IS_PUBLIC: bool = true; -} diff --git a/node/Cargo.toml b/node/Cargo.toml new file mode 100644 index 0000000000..d9f9a13e7d --- /dev/null +++ b/node/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "snarkos-node" +version = "2.0.2" +authors = [ "The Aleo Team " ] +description = "A node for a decentralized operating system" +homepage = "https://aleo.org" +repository = "https://github.com/AleoHQ/snarkOS" +keywords = [ + "aleo", + "cryptography", + "blockchain", + "decentralized", + "zero-knowledge" +] +categories = [ "cryptography", "operating-systems" ] +license = "GPL-3.0" +edition = "2021" + +[dependencies.snarkos-account] +path = "../account" + +[dependencies.snarkos-node-executor] +path = "./executor" + +[dependencies.snarkos-node-ledger] +path = "./ledger" + +[dependencies.snarkos-node-router] +path = "./router" + +[dependencies.anyhow] +version = "1" + +[dependencies.async-trait] +version = "0.1" + +[dependencies.rand] +version = "0.8" +default-features = false + +[dependencies.serde_json] +version = "1" + +[dependencies.snarkvm] +workspace = true + +[dependencies.tokio] +version = "1.21" +features = ["rt", "signal"] + +[dependencies.tracing] +version = "0.1" diff --git a/node/LICENSE.md b/node/LICENSE.md new file mode 100644 index 0000000000..b95c626e2a --- /dev/null +++ b/node/LICENSE.md @@ -0,0 +1,596 @@ +GNU General Public License +========================== + +Version 3, 29 June 2007 + +Copyright Β© 2007 Free Software Foundation, Inc. <> + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: **(1)** assert +copyright on the software, and **(2)** offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions + +β€œThis License” refers to version 3 of the GNU General Public License. + +β€œCopyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +β€œThe Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as β€œyou”. β€œLicensees” and +β€œrecipients” may be individuals or organizations. + +To β€œmodify” a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a β€œmodified version” of the earlier work or a +work β€œbased on” the earlier work. + +A β€œcovered work” means either the unmodified Program or a work based on +the Program. + +To β€œpropagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To β€œconvey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays β€œAppropriate Legal Notices” to the +extent that it includes a convenient and prominently visible feature that **(1)** +displays an appropriate copyright notice, and **(2)** tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code + +The β€œsource code” for a work means the preferred form of the work for +making modifications to it. β€œObject code” means any non-source form of a +work. + +A β€œStandard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The β€œSystem Libraries” of an executable work include anything, other than +the work as a whole, that **(a)** is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and **(b)** serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A β€œMajor Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The β€œCorresponding Source” for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to β€œkeep intact all notices”. +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an β€œaggregate” if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either **(1)** a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or **(2)** access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A β€œUser Product” is either **(1)** a β€œconsumer product”, which +means any tangible personal property which is normally used for personal, family, or +household purposes, or **(2)** anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, β€œnormally used” refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +β€œInstallation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms + +β€œAdditional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered β€œfurther +restrictions” within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated **(a)** provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and **(b)** permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An β€œentity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents + +A β€œcontributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's β€œcontributor version”. + +A contributor's β€œessential patent claims” are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, β€œcontrol” includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a β€œpatent license” is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To β€œgrant” such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either **(1)** cause the Corresponding +Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the +patent license for this particular work, or **(3)** arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. β€œKnowingly relying” means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is β€œdiscriminatory” if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license **(a)** in connection with +copies of the covered work conveyed by you (or copies made from those copies), or **(b)** +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License β€œor any later +version” applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM β€œAS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16 + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +_END OF TERMS AND CONDITIONS_ + +## How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to +the public, the best way to achieve this is to make it free software which everyone +can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them +to the start of each source file to most effectively state the exclusion of warranty; +and each file should have at least the β€œcopyright” line and a pointer to +where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands `show w` and `show c` should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an β€œabout box”. + +You should also get your employer (if you work as a programmer) or school, if any, to +sign a β€œcopyright disclaimer” for the program, if necessary. For more +information on this, and how to apply and follow the GNU GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. diff --git a/node/README.md b/node/README.md new file mode 100644 index 0000000000..213d82c9ed --- /dev/null +++ b/node/README.md @@ -0,0 +1,7 @@ +# snarkos-node + +[![Crates.io](https://img.shields.io/crates/v/snarkos-node.svg?color=neon)](https://crates.io/crates/snarkos-node) +[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](https://aleo.org) +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md) + +The `snarkos-node` crate provides the `Node` struct, which is responsible for running a node in the Aleo network. diff --git a/environment/Cargo.toml b/node/executor/Cargo.toml similarity index 60% rename from environment/Cargo.toml rename to node/executor/Cargo.toml index 398772f5a5..d8d290f07a 100644 --- a/environment/Cargo.toml +++ b/node/executor/Cargo.toml @@ -1,8 +1,8 @@ [package] -name = "snarkos-environment" +name = "snarkos-node-executor" version = "2.0.2" authors = [ "The Aleo Team " ] -description = "Environment for a decentralized operating system" +description = "A node executor for a decentralized operating system" homepage = "https://aleo.org" repository = "https://github.com/AleoHQ/snarkOS" keywords = [ @@ -19,6 +19,9 @@ edition = "2021" [dependencies.anyhow] version = "1" +[dependencies.async-trait] +version = "0.1" + [dependencies.num_cpus] version = "1" @@ -29,27 +32,14 @@ version = "1" version = "1" [dependencies.serde] -version = "1.0.145" - -[dependencies.serde_json] version = "1" -[dependencies.snarkvm] -#path = "../../snarkVM" -git = "https://github.com/AleoHQ/snarkVM.git" -rev = "1f0f2c9" -features = ["console", "utilities"] - [dependencies.tokio] -version = "1" -features = ["sync", "rt", "time"] +version = "1.21" +features = ["rt"] [dependencies.tracing] version = "0.1" [dev-dependencies.tracing-subscriber] version = "0.3" - -[dev-dependencies.tokio] -version = "1" -features = ["macros", "rt-multi-thread", "time"] diff --git a/node/executor/LICENSE.md b/node/executor/LICENSE.md new file mode 100644 index 0000000000..b95c626e2a --- /dev/null +++ b/node/executor/LICENSE.md @@ -0,0 +1,596 @@ +GNU General Public License +========================== + +Version 3, 29 June 2007 + +Copyright Β© 2007 Free Software Foundation, Inc. <> + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: **(1)** assert +copyright on the software, and **(2)** offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions + +β€œThis License” refers to version 3 of the GNU General Public License. + +β€œCopyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +β€œThe Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as β€œyou”. β€œLicensees” and +β€œrecipients” may be individuals or organizations. + +To β€œmodify” a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a β€œmodified version” of the earlier work or a +work β€œbased on” the earlier work. + +A β€œcovered work” means either the unmodified Program or a work based on +the Program. + +To β€œpropagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To β€œconvey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays β€œAppropriate Legal Notices” to the +extent that it includes a convenient and prominently visible feature that **(1)** +displays an appropriate copyright notice, and **(2)** tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code + +The β€œsource code” for a work means the preferred form of the work for +making modifications to it. β€œObject code” means any non-source form of a +work. + +A β€œStandard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The β€œSystem Libraries” of an executable work include anything, other than +the work as a whole, that **(a)** is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and **(b)** serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A β€œMajor Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The β€œCorresponding Source” for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to β€œkeep intact all notices”. +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an β€œaggregate” if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either **(1)** a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or **(2)** access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A β€œUser Product” is either **(1)** a β€œconsumer product”, which +means any tangible personal property which is normally used for personal, family, or +household purposes, or **(2)** anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, β€œnormally used” refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +β€œInstallation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms + +β€œAdditional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered β€œfurther +restrictions” within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated **(a)** provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and **(b)** permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An β€œentity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents + +A β€œcontributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's β€œcontributor version”. + +A contributor's β€œessential patent claims” are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, β€œcontrol” includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a β€œpatent license” is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To β€œgrant” such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either **(1)** cause the Corresponding +Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the +patent license for this particular work, or **(3)** arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. β€œKnowingly relying” means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is β€œdiscriminatory” if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license **(a)** in connection with +copies of the covered work conveyed by you (or copies made from those copies), or **(b)** +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License β€œor any later +version” applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM β€œAS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16 + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +_END OF TERMS AND CONDITIONS_ + +## How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to +the public, the best way to achieve this is to make it free software which everyone +can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them +to the start of each source file to most effectively state the exclusion of warranty; +and each file should have at least the β€œcopyright” line and a pointer to +where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands `show w` and `show c` should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an β€œabout box”. + +You should also get your employer (if you work as a programmer) or school, if any, to +sign a β€œcopyright disclaimer” for the program, if necessary. For more +information on this, and how to apply and follow the GNU GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. diff --git a/node/executor/README.md b/node/executor/README.md new file mode 100644 index 0000000000..c3b119777d --- /dev/null +++ b/node/executor/README.md @@ -0,0 +1,8 @@ +# snarkos-node-executor + +[![Crates.io](https://img.shields.io/crates/v/snarkos-node-executor.svg?color=neon)](https://crates.io/crates/snarkos-node-executor) +[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](https://aleo.org) +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md) + +The `snarkos-node-executor` crate provides the `Executor` struct, which is responsible for executing computations, +such as transaction generation and block production, in the context of a given node. diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs new file mode 100644 index 0000000000..831567551d --- /dev/null +++ b/node/executor/src/lib.rs @@ -0,0 +1,105 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +#![forbid(unsafe_code)] + +#[macro_use] +extern crate async_trait; +#[macro_use] +extern crate tracing; + +mod macros; + +mod node_type; +pub use node_type::*; + +mod resources; +pub use resources::Resource; + +mod status; +pub use status::*; + +use crate::resources::Resources; + +use once_cell::sync::OnceCell; +use rayon::{ThreadPool, ThreadPoolBuilder}; +use std::sync::Arc; + +#[async_trait] +pub trait Executor: 'static + Clone + Send + Sync { + /// The node type. + const NODE_TYPE: NodeType; + + /// Returns the node type. + fn node_type() -> NodeType { + Self::NODE_TYPE + } + + /// Returns the status of the node. + fn status() -> &'static RawStatus { + static STATUS: OnceCell = OnceCell::new(); + STATUS.get_or_init(RawStatus::default) + } + + /// Returns the resource handler for the node. + fn resources() -> &'static Resources { + static RESOURCES: OnceCell = OnceCell::new(); + RESOURCES.get_or_init(Resources::default) + } + + /// Returns a thread pool for the executor to perform intensive operations. + fn executor_pool() -> &'static Arc { + static POOL: OnceCell> = OnceCell::new(); + POOL.get_or_init(|| { + Arc::new( + ThreadPoolBuilder::new() + .stack_size(8 * 1024 * 1024) + .num_threads((num_cpus::get() * 7 / 8).max(2)) + .build() + .expect("Failed to initialize a thread pool for the node"), + ) + }) + } + + /// Handles OS signals for the node to intercept and perform a clean shutdown. + /// Note: Only Ctrl-C is supported; it should work on both Unix-family systems and Windows. + fn handle_signals(&self) { + let node = self.clone(); + Self::resources().register_task( + None, // No need to provide an id, as the task will run indefinitely. + tokio::task::spawn(async move { + match tokio::signal::ctrl_c().await { + Ok(()) => { + node.shut_down().await; + std::process::exit(0); + } + Err(error) => error!("tokio::signal::ctrl_c encountered an error: {}", error), + } + }), + ); + } + + /// Disconnects from peers and shuts down the node. + async fn shut_down(&self) { + info!("Shutting down..."); + // Update the node status. + Self::status().update(Status::ShuttingDown); + + // Flush the tasks. + Self::resources().shut_down(); + trace!("Node has shut down."); + } +} diff --git a/node/executor/src/macros.rs b/node/executor/src/macros.rs new file mode 100644 index 0000000000..46bdeb3583 --- /dev/null +++ b/node/executor/src/macros.rs @@ -0,0 +1,102 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +#[macro_export] +macro_rules! spawn_task { + ///////////////////////////////////////////////////////////////////////////// + + // Spawns a new task, without a task ID. + ($logic:block) => {{ + let (router, handler) = tokio::sync::oneshot::channel(); + // Register the task with the environment. + // No need to provide an id, as the task will run indefinitely. + E::resources().register_task( + None, + tokio::task::spawn(async move { + // Notify the outer function that the task is ready. + let _ = router.send(()); + $logic + }), + ); + // Wait until the task is ready. + let _ = handler.await; + }}; + + // Spawns a new task, without a task ID. + ($logic:expr) => {{ $crate::spawn_task!(E, None, { $logic }) }}; + + ///////////////////////////////////////////////////////////////////////////// + + // Spawns a new task, without a task ID, using a custom executor. + ($E:ident, $logic:block) => {{ + let (router, handler) = tokio::sync::oneshot::channel(); + // Register the task with the environment. + // No need to provide an id, as the task will run indefinitely. + $E::resources().register_task( + None, + tokio::task::spawn(async move { + // Notify the outer function that the task is ready. + let _ = router.send(()); + $logic + }), + ); + // Wait until the task is ready. + let _ = handler.await; + }}; + + // Spawns a new task, without a task ID, using a custom executor. + ($E:ident, $logic:expr) => {{ $crate::spawn_task!($E, None, { $logic }) }}; + + ///////////////////////////////////////////////////////////////////////////// + + // Spawns a new task, with a task ID. + ($id:expr, $logic:block) => {{ + // Procure a resource ID for the task, as it may terminate at any time. + let resource_id = $id; + // Register the task with the environment. + E::resources().register_task( + Some(resource_id), + tokio::task::spawn(async move { + let result = $logic; + E::resources().deregister(resource_id); + result + }), + ); + }}; + + // Spawns a new task, with a task ID. + ($id:expr, $logic:expr) => {{ $crate::spawn_task!(E, $id, { $logic }) }}; + + ///////////////////////////////////////////////////////////////////////////// + + // Spawns a new task, with a task ID, using a custom executor. + ($E:ident, $id:expr, $logic:block) => {{ + // Procure a resource ID for the task, as it may terminate at any time. + let resource_id = $id; + // Register the task with the environment. + $E::resources().register_task( + Some(resource_id), + tokio::task::spawn(async move { + let result = $logic; + $E::resources().deregister(resource_id); + result + }), + ); + }}; + + // Spawns a new task, with a task ID, using a custom executor. + ($E:ident, $id:expr, $logic:expr) => {{ $crate::spawn_task!($E, $id, { $logic }) }}; +} diff --git a/environment/src/helpers/node_type.rs b/node/executor/src/node_type.rs similarity index 57% rename from environment/src/helpers/node_type.rs rename to node/executor/src/node_type.rs index 225e54bdd6..e48226bff1 100644 --- a/environment/src/helpers/node_type.rs +++ b/node/executor/src/node_type.rs @@ -15,7 +15,6 @@ // along with the snarkOS library. If not, see . use serde::{Deserialize, Serialize}; -use std::fmt; #[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] #[repr(u8)] @@ -31,18 +30,39 @@ pub enum NodeType { } impl NodeType { - pub fn description(&self) -> &str { + /// Returns a string representation of the node type. + pub const fn description(&self) -> &str { match self { - Self::Client => "a client", - Self::Prover => "a prover", - Self::Validator => "a validator", - Self::Beacon => "a beacon", + Self::Client => "a client node", + Self::Prover => "a prover node", + Self::Validator => "a validator node", + Self::Beacon => "a beacon node", } } + + /// Returns `true` if the node type is a client. + pub const fn is_client(&self) -> bool { + matches!(self, Self::Client) + } + + /// Returns `true` if the node type is a prover. + pub const fn is_prover(&self) -> bool { + matches!(self, Self::Prover) + } + + /// Returns `true` if the node type is a validator. + pub const fn is_validator(&self) -> bool { + matches!(self, Self::Validator) + } + + /// Returns `true` if the node type is a beacon. + pub const fn is_beacon(&self) -> bool { + matches!(self, Self::Beacon) + } } -impl fmt::Display for NodeType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl core::fmt::Display for NodeType { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:?}", self) } } diff --git a/environment/src/helpers/resources.rs b/node/executor/src/resources.rs similarity index 89% rename from environment/src/helpers/resources.rs rename to node/executor/src/resources.rs index 3fd0120830..e411cdac01 100644 --- a/environment/src/helpers/resources.rs +++ b/node/executor/src/resources.rs @@ -27,14 +27,17 @@ use tokio::{ time::sleep, }; -pub type ResourceId = usize; +/// Provides the means to shut down a background resource. +pub type AbortSignal = oneshot::Sender<()>; +/// A resource that can be managed. +pub type ResourceID = usize; /// The types of messages that the resource manager can handle. pub enum ResourceRequest { - /// A request to register the given resource under the given id. - Register(Resource, ResourceId), - /// A request to deregister the resource with the given id. - Deregister(ResourceId), + /// A request to register the given resource under the given ID. + Register(Resource, ResourceID), + /// A request to deregister the resource with the given ID. + Deregister(ResourceID), /// A request to deregister all the resources. Shutdown, /// A request to print a resource use summary in the logs. @@ -42,9 +45,6 @@ pub enum ResourceRequest { LogSummary, } -/// Provides the means to shut down a background resource. -pub type AbortSignal = oneshot::Sender<()>; - /// A background task or thread. pub enum Resource { /// An asynchronous task. @@ -80,10 +80,7 @@ pub struct Resources { impl Clone for Resources { fn clone(&self) -> Self { - Self { - sender: self.sender.clone(), - index: self.index.clone(), - } + Self { sender: self.sender.clone(), index: self.index.clone() } } } @@ -99,12 +96,12 @@ impl Resources { let (sender, mut receiver) = mpsc::unbounded_channel(); tokio::spawn(async move { - let mut resources: HashMap = Default::default(); + let mut resources: HashMap = Default::default(); while let Some(request) = receiver.recv().await { match request { ResourceRequest::Register(resource, id) => { if resources.insert(id, resource).is_some() { - error!("A resource with ID {} already exists!", id); + error!("A resource with ID {id} already exists!"); } } ResourceRequest::Deregister(id) => { @@ -116,7 +113,7 @@ impl Resources { resource.abort().await; }); } else { - error!("Resource with ID {} was not found", id); + error!("Resource with ID {id} was not found"); } } ResourceRequest::Shutdown => break, @@ -138,26 +135,23 @@ impl Resources { resources.sort_unstable_by_key(|(id, _res)| *id); for (id, resource) in resources.into_iter().rev() { - trace!("Aborting resource with ID {}", id); + trace!("Aborting resource with ID {id}"); resource.abort().await; } }); - Self { - sender, - index: Default::default(), - } + Self { sender, index: Default::default() } } /// Obtains an ID that can be used to register a resource. - pub fn procure_id(&self) -> ResourceId { + pub fn procure_id(&self) -> ResourceID { self.index.fetch_add(1, Ordering::SeqCst) } /// Register the given resource with the resource handler and optionally - /// with an associated resource id which - if provided - must be obtained + /// with an associated resource ID which - if provided - must be obtained /// earlier via `Resources::procure_id`. - pub fn register(&self, resource: Resource, id: Option) { + pub fn register(&self, resource: Resource, id: Option) { // Prepare a resource request, assigning a resource ID if one was not given. let request = ResourceRequest::Register(resource, match id { Some(id) => id, @@ -167,13 +161,18 @@ impl Resources { let _ = self.sender.send(request); } - /// Register the given task with the resource handler and an (optional) resource id. - pub fn register_task(&self, id: Option, handle: tokio::task::JoinHandle<()>) { + /// Register the given task with the resource handler and an (optional) resource ID. + pub fn register_task(&self, id: Option, handle: tokio::task::JoinHandle<()>) { self.register(Resource::Task(handle), id); } - /// Register the given thread with the resource handler and an (optional) resource id. - pub fn register_thread(&self, id: Option, handle: std::thread::JoinHandle<()>, abort_sender: AbortSignal) { + /// Register the given thread with the resource handler and an (optional) resource ID. + pub fn register_thread( + &self, + id: Option, + handle: std::thread::JoinHandle<()>, + abort_sender: AbortSignal, + ) { self.register(Resource::Thread(handle, abort_sender), id); } @@ -181,7 +180,7 @@ impl Resources { #[cfg(feature = "task-metrics")] pub fn register_instrumented_task( &self, - id: Option, + id: Option, name: String, interval: std::time::Duration, handle: tokio::task::JoinHandle<()>, @@ -215,7 +214,7 @@ impl Resources { } /// Deregisters and frees a resource with the given ID. - pub fn deregister(&self, id: ResourceId) { + pub fn deregister(&self, id: ResourceID) { let request = ResourceRequest::Deregister(id); // This channel will not be closed before the final shutdown. diff --git a/environment/src/helpers/status.rs b/node/executor/src/status.rs similarity index 84% rename from environment/src/helpers/status.rs rename to node/executor/src/status.rs index bde9d9a41c..8073dae9c0 100644 --- a/environment/src/helpers/status.rs +++ b/node/executor/src/status.rs @@ -26,15 +26,15 @@ use std::{ #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)] #[repr(u8)] pub enum Status { - /// The ledger is ready to handle requests. + /// The node is ready to handle requests. Ready = 0, - /// The ledger is mining the next block. - Mining, - /// The ledger is connecting to the minimum number of required peers. + /// The node is producing a coinbase proof. + Proving, + /// The node is connecting to the minimum number of required peers. Peering, - /// The ledger is syncing blocks with a connected peer. + /// The node is syncing blocks with a connected peer. Syncing, - /// The ledger is terminating and shutting down. + /// The node is terminating and shutting down. ShuttingDown, } @@ -62,7 +62,7 @@ impl RawStatus { pub fn get(&self) -> Status { match self.0.load(Ordering::SeqCst) { 0 => Status::Ready, - 1 => Status::Mining, + 1 => Status::Proving, 2 => Status::Peering, 3 => Status::Syncing, 4 => Status::ShuttingDown, @@ -75,9 +75,9 @@ impl RawStatus { self.get() == Status::Ready } - /// Returns `true` if the node is currently mining. - pub fn is_mining(&self) -> bool { - self.get() == Status::Mining + /// Returns `true` if the node is currently proving. + pub fn is_proving(&self) -> bool { + self.get() == Status::Proving } /// Returns `true` if the node is currently peering. diff --git a/node/ledger/Cargo.toml b/node/ledger/Cargo.toml new file mode 100644 index 0000000000..6e08256e7c --- /dev/null +++ b/node/ledger/Cargo.toml @@ -0,0 +1,65 @@ +[package] +name = "snarkos-node-ledger" +version = "2.0.2" +authors = [ "The Aleo Team " ] +description = "A node ledger for a decentralized operating system" +homepage = "https://aleo.org" +repository = "https://github.com/AleoHQ/snarkOS" +keywords = [ + "aleo", + "cryptography", + "blockchain", + "decentralized", + "zero-knowledge" +] +categories = [ "cryptography", "operating-systems" ] +license = "GPL-3.0" +edition = "2021" + +[dependencies.anyhow] +version = "1" + +[dependencies.backoff] +version = "0.4" +features = [ "tokio" ] + +[dependencies.colored] +version = "2.0" + +[dependencies.futures] +version = "0.3" + +[dependencies.indexmap] +version = "1.9" +features = [ "rayon" ] + +[dependencies.parking_lot] +version = "0.12" + +[dependencies.rand] +version = "0.8" + +[dependencies.rayon] +version = "1" + +[dependencies.reqwest] +version = "0.11" + +[dependencies.snarkos-node-router] +path = "../router" + +[dependencies.snarkos-node-store] +path = "../store" + +[dependencies.snarkvm] +workspace = true + +[dependencies.tokio] +version = "1.21" +features = ["rt"] + +[dependencies.tracing] +version = "0.1" + +[dependencies.warp] +version = "0.3" diff --git a/node/ledger/LICENSE.md b/node/ledger/LICENSE.md new file mode 100644 index 0000000000..b95c626e2a --- /dev/null +++ b/node/ledger/LICENSE.md @@ -0,0 +1,596 @@ +GNU General Public License +========================== + +Version 3, 29 June 2007 + +Copyright Β© 2007 Free Software Foundation, Inc. <> + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: **(1)** assert +copyright on the software, and **(2)** offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions + +β€œThis License” refers to version 3 of the GNU General Public License. + +β€œCopyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +β€œThe Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as β€œyou”. β€œLicensees” and +β€œrecipients” may be individuals or organizations. + +To β€œmodify” a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a β€œmodified version” of the earlier work or a +work β€œbased on” the earlier work. + +A β€œcovered work” means either the unmodified Program or a work based on +the Program. + +To β€œpropagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To β€œconvey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays β€œAppropriate Legal Notices” to the +extent that it includes a convenient and prominently visible feature that **(1)** +displays an appropriate copyright notice, and **(2)** tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code + +The β€œsource code” for a work means the preferred form of the work for +making modifications to it. β€œObject code” means any non-source form of a +work. + +A β€œStandard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The β€œSystem Libraries” of an executable work include anything, other than +the work as a whole, that **(a)** is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and **(b)** serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A β€œMajor Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The β€œCorresponding Source” for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to β€œkeep intact all notices”. +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an β€œaggregate” if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either **(1)** a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or **(2)** access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A β€œUser Product” is either **(1)** a β€œconsumer product”, which +means any tangible personal property which is normally used for personal, family, or +household purposes, or **(2)** anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, β€œnormally used” refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +β€œInstallation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms + +β€œAdditional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered β€œfurther +restrictions” within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated **(a)** provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and **(b)** permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An β€œentity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents + +A β€œcontributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's β€œcontributor version”. + +A contributor's β€œessential patent claims” are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, β€œcontrol” includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a β€œpatent license” is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To β€œgrant” such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either **(1)** cause the Corresponding +Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the +patent license for this particular work, or **(3)** arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. β€œKnowingly relying” means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is β€œdiscriminatory” if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license **(a)** in connection with +copies of the covered work conveyed by you (or copies made from those copies), or **(b)** +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License β€œor any later +version” applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM β€œAS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16 + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +_END OF TERMS AND CONDITIONS_ + +## How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to +the public, the best way to achieve this is to make it free software which everyone +can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them +to the start of each source file to most effectively state the exclusion of warranty; +and each file should have at least the β€œcopyright” line and a pointer to +where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands `show w` and `show c` should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an β€œabout box”. + +You should also get your employer (if you work as a programmer) or school, if any, to +sign a β€œcopyright disclaimer” for the program, if necessary. For more +information on this, and how to apply and follow the GNU GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. diff --git a/node/ledger/README.md b/node/ledger/README.md new file mode 100644 index 0000000000..235598314c --- /dev/null +++ b/node/ledger/README.md @@ -0,0 +1,7 @@ +# snarkos-node-ledger + +[![Crates.io](https://img.shields.io/crates/v/snarkos-node-ledger.svg?color=neon)](https://crates.io/crates/snarkos-node-ledger) +[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](https://aleo.org) +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md) + +The `snarkos-node-ledger` crate provides the ledger and API interface for the Aleo blockchain. diff --git a/snarkos/ledger/mod.rs b/node/ledger/src/lib.rs similarity index 74% rename from snarkos/ledger/mod.rs rename to node/ledger/src/lib.rs index b96be8e3b7..93bf6ae654 100644 --- a/snarkos/ledger/mod.rs +++ b/node/ledger/src/lib.rs @@ -14,17 +14,23 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . -use crate::{handle_dispatch_error, BlockDB, Data, ProgramDB}; +#![forbid(unsafe_code)] + +#[macro_use] +extern crate tracing; + +use snarkos_node_router::{Data, Message, Router, RouterRequest, UnconfirmedBlock}; +use snarkos_node_store::{BlockDB, ProgramDB}; use snarkvm::prelude::*; +use anyhow::{anyhow, bail, ensure, Result}; +use backoff::{future::retry, ExponentialBackoff}; use colored::Colorize; -use futures::StreamExt; +use core::time::Duration; +use futures::{Future, StreamExt}; use indexmap::IndexMap; use parking_lot::RwLock; -use std::{ - net::{IpAddr, SocketAddr}, - sync::Arc, -}; +use std::{net::IpAddr, sync::Arc}; use tokio::task; use warp::{reply, Filter, Rejection, Reply}; @@ -34,16 +40,40 @@ pub(crate) type InternalLedger = snarkvm::prelude::Ledger, Prog pub(crate) type InternalServer = snarkvm::prelude::Server, ProgramDB>; // pub(crate) type InternalServer = snarkvm::prelude::Server, ProgramMemory>; -pub(crate) type Peers = Arc>>>; +pub(crate) async fn handle_dispatch_error<'a, T, F>(func: impl Fn() -> F + 'a) -> Result +where + F: Future>, +{ + fn default_backoff() -> ExponentialBackoff { + ExponentialBackoff { + max_interval: Duration::from_secs(10), + max_elapsed_time: Some(Duration::from_secs(45)), + ..Default::default() + } + } + + fn from_anyhow_err(err: Error) -> backoff::Error { + use backoff::Error; + + if let Ok(err) = err.downcast::() { + debug!("Server error: {err}; retrying..."); + Error::Transient { err: err.into(), retry_after: None } + } else { + Error::Transient { err: anyhow!("Block parse error"), retry_after: None } + } + } + + retry(default_backoff(), || async { func().await.map_err(from_anyhow_err) }).await +} -#[allow(dead_code)] +#[derive(Clone)] pub struct Ledger { /// The ledger. ledger: Arc>>, /// The server. - server: InternalServer, - /// The peers. - peers: Peers, + server: Arc>, + /// The router. + router: Router, /// The account private key. private_key: PrivateKey, /// The account view key. @@ -53,10 +83,17 @@ pub struct Ledger { } impl Ledger { - /// Initializes a new instance of the ledger. - pub(super) fn new_with_genesis(private_key: PrivateKey, genesis_block: Block, dev: Option) -> Result> { + /// Initializes a new instance of the ledger with a fresh genesis block. + /// This is used for testing purposes only. + fn new_with_genesis( + private_key: PrivateKey, + genesis_block: Block, + dev: Option, + router: Router, + ) -> Result { // Initialize the ledger. - let ledger = match InternalLedger::new_with_genesis(&genesis_block, genesis_block.signature().to_address(), dev) { + let ledger = match InternalLedger::new_with_genesis(&genesis_block, genesis_block.signature().to_address(), dev) + { Ok(ledger) => Arc::new(RwLock::new(ledger)), Err(_) => { // Open the internal ledger. @@ -70,28 +107,24 @@ impl Ledger { }; // Return the ledger. - Self::from(ledger, private_key) + Self::from(ledger, private_key, router) } /// Opens an instance of the ledger. - pub fn load(private_key: PrivateKey, dev: Option) -> Result> { + pub fn load(private_key: PrivateKey, dev: Option, router: Router) -> Result { // Initialize the ledger. let ledger = Arc::new(RwLock::new(InternalLedger::open(dev)?)); // Return the ledger. - Self::from(ledger, private_key) + Self::from(ledger, private_key, router) } /// Initializes a new instance of the ledger. - pub fn from(ledger: Arc>>, private_key: PrivateKey) -> Result> { + pub fn from(ledger: Arc>>, private_key: PrivateKey, router: Router) -> Result { // Derive the view key and address. let view_key = ViewKey::try_from(private_key)?; let address = Address::try_from(&view_key)?; - // Initialize the peers. - let peers: Peers = Default::default(); - // Initialize the additional routes. - #[allow(clippy::let_and_return)] let additional_routes = { // GET /testnet3/node/address let get_node_address = warp::get() @@ -102,40 +135,33 @@ impl Ledger { // GET /testnet3/peers/count let get_peers_count = warp::get() .and(warp::path!("testnet3" / "peers" / "count")) - .and(with(peers.clone())) + .and(with(router.clone())) .and_then(get_peers_count); // GET /testnet3/peers/all let get_peers_all = warp::get() .and(warp::path!("testnet3" / "peers" / "all")) - .and(with(peers.clone())) + .and(with(router.clone())) .and_then(get_peers_all); /// Returns the number of peers connected to the node. - async fn get_peers_count(peers: Peers) -> Result { - Ok(reply::json(&peers.read().len())) + async fn get_peers_count(router: Router) -> Result { + Ok(reply::json(&router.number_of_connected_peers().await)) } /// Returns the peers connected to the node. - async fn get_peers_all(peers: Peers) -> Result { - Ok(reply::json(&peers.read().keys().map(|addr| addr.ip()).collect::>())) + async fn get_peers_all(router: Router) -> Result { + Ok(reply::json(&router.connected_peers().await)) } get_node_address.or(get_peers_count).or(get_peers_all) }; // Initialize the server. - let server = InternalServer::::start(ledger.clone(), Some(additional_routes), None)?; + let server = Arc::new(InternalServer::::start(ledger.clone(), Some(additional_routes), None)?); // Return the ledger. - Ok(Arc::new(Self { - ledger, - server, - peers, - private_key, - view_key, - address, - })) + Ok(Self { ledger, server, router, private_key, view_key, address }) } // TODO (raychu86): Restrict visibility. @@ -145,13 +171,13 @@ impl Ledger { } /// Returns the ledger address. - pub const fn address(&self) -> &Address { - &self.address + pub const fn address(&self) -> Address { + self.address } - /// Returns the connected peers. - pub(super) const fn peers(&self) -> &Peers { - &self.peers + /// Returns the router. + const fn router(&self) -> &Router { + &self.router } } @@ -161,8 +187,13 @@ impl Ledger { self.ledger.write().add_to_memory_pool(transaction) } + /// Adds the given transaction to the memory pool. + pub fn add_to_coinbase_memory_pool(&self, prover_puzzle_solution: ProverSolution) -> Result<()> { + self.ledger.write().add_to_coinbase_memory_pool(prover_puzzle_solution) + } + /// Advances the ledger to the next block. - pub async fn advance_to_next_block(self: &Arc) -> Result> { + pub async fn advance_to_next_block(&self) -> Result> { let self_clone = self.clone(); let next_block = task::spawn_blocking(move || { // Initialize an RNG. @@ -179,11 +210,13 @@ impl Ledger { let serialized_block = Data::Object(next_block.clone()).serialize().await?; // Broadcast the block to all peers. - let peers = self.peers().read().clone(); - for (_, sender) in peers.iter() { - let _ = sender - .send(crate::Message::::BlockBroadcast(Data::Buffer(serialized_block.clone()))) - .await; + let message = Message::::UnconfirmedBlock(UnconfirmedBlock { + block_height: next_block.height(), + block_hash: next_block.hash(), + block: Data::Buffer(serialized_block.clone()), + }); + if let Err(error) = self.router().process(RouterRequest::MessagePropagate(message)).await { + trace!("Failed to broadcast the next block: {error}"); } // Return the next block. @@ -191,7 +224,7 @@ impl Ledger { } /// Attempts to add the given block to the ledger. - pub(crate) async fn add_next_block(self: &Arc, next_block: Block) -> Result<()> { + pub(crate) async fn add_next_block(&self, next_block: Block) -> Result<()> { // Add the next block to the ledger. let self_clone = self.clone(); if let Err(error) = task::spawn_blocking(move || self_clone.ledger.write().add_next_block(&next_block)).await? { @@ -208,28 +241,22 @@ impl Ledger { impl Ledger { /// Returns the unspent records. pub fn find_unspent_records(&self) -> Result, Record>>> { - // Fetch the unspent records. - let records = self + Ok(self .ledger .read() .find_records(&self.view_key, RecordsFilter::Unspent)? .filter(|(_, record)| !record.gates().is_zero()) - .collect::>(); - // Return the unspent records. - Ok(records) + .collect::>()) } /// Returns the spent records. pub fn find_spent_records(&self) -> Result, Record>>> { - // Fetch the unspent records. - let records = self + Ok(self .ledger .read() .find_records(&self.view_key, RecordsFilter::Spent)? .filter(|(_, record)| !record.gates().is_zero()) - .collect::>(); - // Return the unspent records. - Ok(records) + .collect::>()) } /// Creates a deploy transaction. @@ -240,15 +267,13 @@ impl Ledger { // Prepare the additional fee. let credits = records.values().max_by(|a, b| (**a.gates()).cmp(&**b.gates())).unwrap().clone(); - ensure!( - ***credits.gates() >= additional_fee, - "The additional fee is more than the record balance." - ); + ensure!(***credits.gates() >= additional_fee, "The additional fee is more than the record balance."); // Initialize an RNG. let rng = &mut ::rand::thread_rng(); // Deploy. - let transaction = Transaction::deploy(self.ledger.read().vm(), &self.private_key, program, (credits, additional_fee), rng)?; + let transaction = + Transaction::deploy(self.ledger.read().vm(), &self.private_key, program, (credits, additional_fee), rng)?; // Verify. assert!(self.ledger.read().vm().verify(&transaction)); // Return the transaction. @@ -326,7 +351,8 @@ impl Ledger { let block_bytes = client.get(block_url).send().await?.bytes().await?; // Parse the block. - let block = task::spawn_blocking(move || Block::from_bytes_le(&block_bytes)).await.unwrap()?; + let block = + task::spawn_blocking(move || Block::from_bytes_le(&block_bytes)).await.unwrap()?; std::future::ready(Ok(block)).await } diff --git a/node/router/Cargo.toml b/node/router/Cargo.toml new file mode 100644 index 0000000000..2134b719df --- /dev/null +++ b/node/router/Cargo.toml @@ -0,0 +1,74 @@ +[package] +name = "snarkos-node-router" +version = "2.0.2" +authors = [ "The Aleo Team " ] +description = "A node router for a decentralized operating system" +homepage = "https://aleo.org" +repository = "https://github.com/AleoHQ/snarkOS" +keywords = [ + "aleo", + "cryptography", + "blockchain", + "decentralized", + "zero-knowledge" +] +categories = [ "cryptography", "operating-systems" ] +license = "GPL-3.0" +edition = "2021" + +[dependencies.snarkos-node-executor] +path = "../executor" + +[dependencies.anyhow] +version = "1" + +[dependencies.async-trait] +version = "0.1" + +[dependencies.bincode] +version = "1.0" + +[dependencies.bytes] +version = "1.0.0" + +[dependencies.futures] +version = "0.3.21" +features = [ "thread-pool" ] + +[dependencies.indexmap] +version = "1.9" +features = ["rayon"] + +[dependencies.once_cell] +version = "1" + +[dependencies.rand] +version = "0.8" + +[dependencies.serde] +version = "1" + +[dependencies.snarkvm] +workspace = true + +[dependencies.tokio] +version = "1.21" +features = [ + "io-util", + "macros", + "net", + "rt-multi-thread", + "signal", + "sync", + "time" +] + +[dependencies.tokio-util] +version = "0.7" +features = [ "codec" ] + +[dependencies.tokio-stream] +version = "=0.1" + +[dependencies.tracing] +version = "0.1" diff --git a/node/router/LICENSE.md b/node/router/LICENSE.md new file mode 100644 index 0000000000..b95c626e2a --- /dev/null +++ b/node/router/LICENSE.md @@ -0,0 +1,596 @@ +GNU General Public License +========================== + +Version 3, 29 June 2007 + +Copyright Β© 2007 Free Software Foundation, Inc. <> + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: **(1)** assert +copyright on the software, and **(2)** offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions + +β€œThis License” refers to version 3 of the GNU General Public License. + +β€œCopyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +β€œThe Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as β€œyou”. β€œLicensees” and +β€œrecipients” may be individuals or organizations. + +To β€œmodify” a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a β€œmodified version” of the earlier work or a +work β€œbased on” the earlier work. + +A β€œcovered work” means either the unmodified Program or a work based on +the Program. + +To β€œpropagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To β€œconvey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays β€œAppropriate Legal Notices” to the +extent that it includes a convenient and prominently visible feature that **(1)** +displays an appropriate copyright notice, and **(2)** tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code + +The β€œsource code” for a work means the preferred form of the work for +making modifications to it. β€œObject code” means any non-source form of a +work. + +A β€œStandard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The β€œSystem Libraries” of an executable work include anything, other than +the work as a whole, that **(a)** is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and **(b)** serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A β€œMajor Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The β€œCorresponding Source” for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to β€œkeep intact all notices”. +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an β€œaggregate” if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either **(1)** a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or **(2)** access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A β€œUser Product” is either **(1)** a β€œconsumer product”, which +means any tangible personal property which is normally used for personal, family, or +household purposes, or **(2)** anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, β€œnormally used” refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +β€œInstallation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms + +β€œAdditional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered β€œfurther +restrictions” within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated **(a)** provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and **(b)** permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An β€œentity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents + +A β€œcontributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's β€œcontributor version”. + +A contributor's β€œessential patent claims” are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, β€œcontrol” includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a β€œpatent license” is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To β€œgrant” such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either **(1)** cause the Corresponding +Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the +patent license for this particular work, or **(3)** arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. β€œKnowingly relying” means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is β€œdiscriminatory” if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license **(a)** in connection with +copies of the covered work conveyed by you (or copies made from those copies), or **(b)** +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License β€œor any later +version” applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM β€œAS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16 + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +_END OF TERMS AND CONDITIONS_ + +## How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to +the public, the best way to achieve this is to make it free software which everyone +can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them +to the start of each source file to most effectively state the exclusion of warranty; +and each file should have at least the β€œcopyright” line and a pointer to +where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands `show w` and `show c` should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an β€œabout box”. + +You should also get your employer (if you work as a programmer) or school, if any, to +sign a β€œcopyright disclaimer” for the program, if necessary. For more +information on this, and how to apply and follow the GNU GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. diff --git a/node/router/README.md b/node/router/README.md new file mode 100644 index 0000000000..e93b83553f --- /dev/null +++ b/node/router/README.md @@ -0,0 +1,7 @@ +# snarkos-node-router + +[![Crates.io](https://img.shields.io/crates/v/snarkos-node-router.svg?color=neon)](https://crates.io/crates/snarkos-node-router) +[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](https://aleo.org) +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md) + +The `snarkos-node-router` crate provides the `Router` struct, which is responsible for routing messages between nodes. diff --git a/node/router/src/handshake.rs b/node/router/src/handshake.rs new file mode 100644 index 0000000000..fbb3ea37fa --- /dev/null +++ b/node/router/src/handshake.rs @@ -0,0 +1,206 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use crate::{ + ChallengeRequest, + ChallengeResponse, + Data, + DisconnectReason, + Message, + MessageCodec, + Peer, + Ping, + Router, + ALEO_MAXIMUM_FORK_DEPTH, +}; +use snarkos_node_executor::{Executor, NodeType, Status}; +use snarkvm::prelude::{Block, FromBytes, Network}; + +use anyhow::{bail, Result}; +use core::time::Duration; +use futures::SinkExt; +use tokio::{net::TcpStream, time::timeout}; +use tokio_stream::StreamExt; +use tokio_util::codec::Framed; + +#[async_trait] +pub trait Handshake: Executor { + /// Performs the handshake protocol, returning the peer upon success. + async fn handshake(router: Router, stream: TcpStream) -> Result> { + // Construct the socket. + let mut outbound_socket = Framed::>::new(stream, Default::default()); + + // Get the IP address of the peer. + let mut peer_ip = outbound_socket.get_ref().peer_addr()?; + + // TODO (howardwu): Make this step more efficient (by not deserializing every time). + // Retrieve the genesis block header. + let genesis_header = Block::::from_bytes_le(N::genesis_bytes())?.header().clone(); + + // Send a challenge request to the peer. + let message = Message::::ChallengeRequest(ChallengeRequest { + version: Message::::VERSION, + fork_depth: ALEO_MAXIMUM_FORK_DEPTH, + node_type: Self::node_type(), + status: Self::status().get(), + listener_port: router.local_ip().port(), + }); + trace!("Sending '{}-A' to {peer_ip}", message.name()); + outbound_socket.send(message).await?; + + // Wait for the counterparty challenge request to come in. + let (node_type, status) = match outbound_socket.next().await { + Some(Ok(message)) => { + // Process the message. + trace!("Received '{}-B' from {peer_ip}", message.name()); + match message { + Message::ChallengeRequest(ChallengeRequest { + version, + fork_depth, + node_type, + status: peer_status, + listener_port, + }) => { + // Ensure the message protocol version is not outdated. + if version < Message::::VERSION { + warn!("Dropping {peer_ip} on version {version} (outdated)"); + + // Send the disconnect message. + outbound_socket + .send(Message::Disconnect(DisconnectReason::OutdatedClientVersion.into())) + .await?; + + bail!("Dropping {peer_ip} on version {version} (outdated)"); + } + // Ensure the maximum fork depth is correct. + if fork_depth != ALEO_MAXIMUM_FORK_DEPTH { + // Send the disconnect message. + outbound_socket + .send(Message::Disconnect(DisconnectReason::InvalidForkDepth.into())) + .await?; + + bail!("Dropping {peer_ip} for an incorrect maximum fork depth of {fork_depth}"); + } + // If this node is not a beacon node and is syncing, the peer is a beacon node, and this node is ahead, proceed to disconnect. + if Self::NODE_TYPE != NodeType::Beacon + && Self::status().is_syncing() + && node_type == NodeType::Beacon + { + // Send the disconnect message. + outbound_socket + .send(Message::Disconnect(DisconnectReason::YouNeedToSyncFirst.into())) + .await?; + + bail!("Dropping {peer_ip} as this node is ahead"); + } + // If this node is a beacon node, the peer is not a beacon node and is syncing, and the peer is ahead, proceed to disconnect. + if Self::NODE_TYPE == NodeType::Beacon + && node_type != NodeType::Beacon + && peer_status == Status::Syncing + { + // Send the disconnect message. + outbound_socket + .send(Message::Disconnect(DisconnectReason::INeedToSyncFirst.into())) + .await?; + + bail!("Dropping {peer_ip} as this node is ahead"); + } + // Verify the listener port. + if peer_ip.port() != listener_port { + // Update the peer IP to the listener port. + peer_ip.set_port(listener_port); + + // Ensure the claimed listener port is open. + if let Err(error) = timeout( + Duration::from_millis(Router::::CONNECTION_TIMEOUT_IN_MILLIS), + TcpStream::connect(peer_ip), + ) + .await + { + // Send the disconnect message. + let message = + Message::Disconnect(DisconnectReason::YourPortIsClosed(listener_port).into()); + outbound_socket.send(message).await?; + + bail!("Unable to reach '{peer_ip}': '{:?}'", error); + } + } + // Send the challenge response. + let message = Message::ChallengeResponse(ChallengeResponse { + header: Data::Object(genesis_header.clone()), + }); + trace!("Sending '{}-B' to {peer_ip}", message.name()); + outbound_socket.send(message).await?; + + (node_type, peer_status) + } + Message::Disconnect(reason) => { + bail!("Peer {peer_ip} disconnected for the following reason: {:?}", reason); + } + message => { + bail!("Expected challenge request, received '{}' from {peer_ip}", message.name()); + } + } + } + // An error occurred. + Some(Err(error)) => bail!("Failed to get challenge request from {peer_ip}: {:?}", error), + // Did not receive anything. + None => bail!("Dropped prior to challenge request of {peer_ip}"), + }; + + // Wait for the challenge response to come in. + match outbound_socket.next().await { + Some(Ok(message)) => { + // Process the message. + trace!("Received '{}-A' from {peer_ip}", message.name()); + match message { + Message::ChallengeResponse(message) => { + // Perform the deferred non-blocking deserialization of the block header. + let block_header = match message.header.deserialize().await { + Ok(block_header) => block_header, + Err(error) => bail!("Handshake with {peer_ip} failed (incorrect block header): {error}"), + }; + match block_header == genesis_header { + true => { + // Send the first `Ping` message to the peer. + let message = Message::Ping(Ping { + version: Message::::VERSION, + fork_depth: ALEO_MAXIMUM_FORK_DEPTH, + node_type: Self::NODE_TYPE, + status: Self::status().get(), + }); + trace!("Sending '{}' to {peer_ip}", message.name()); + outbound_socket.send(message).await?; + + // Initialize the peer. + Peer::initialize::(peer_ip, node_type, status, router, outbound_socket).await + } + false => bail!("Challenge response from {peer_ip} failed, received '{block_header}'"), + } + } + Message::Disconnect(reason) => { + bail!("Peer {peer_ip} disconnected for the following reason: {:?}", reason) + } + message => bail!("Expected challenge response, received '{}' from {peer_ip}", message.name()), + } + } + // An error occurred. + Some(Err(error)) => bail!("Failed to get challenge response from {peer_ip}: {:?}", error), + // Did not receive anything. + None => bail!("Failed to get challenge response from {peer_ip}, peer has disconnected"), + } + } +} diff --git a/node/router/src/helpers/codec.rs b/node/router/src/helpers/codec.rs new file mode 100644 index 0000000000..9108792164 --- /dev/null +++ b/node/router/src/helpers/codec.rs @@ -0,0 +1,78 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use crate::message::Message; +use snarkvm::prelude::Network; + +use ::bytes::{BufMut, BytesMut}; +use core::marker::PhantomData; +use tokio_util::codec::{Decoder, Encoder, LengthDelimitedCodec}; + +/// The maximum size of a message that can be transmitted in the network. +const MAXIMUM_MESSAGE_SIZE: usize = 128 * 1024 * 1024; // 128 MiB + +/// The codec used to decode and encode network `Message`s. +pub struct MessageCodec { + codec: LengthDelimitedCodec, + _phantom: PhantomData, +} + +impl Default for MessageCodec { + fn default() -> Self { + Self { + codec: LengthDelimitedCodec::builder().max_frame_length(MAXIMUM_MESSAGE_SIZE).little_endian().new_codec(), + _phantom: Default::default(), + } + } +} + +impl Encoder> for MessageCodec { + type Error = std::io::Error; + + fn encode(&mut self, message: Message, dst: &mut BytesMut) -> Result<(), Self::Error> { + // Serialize the payload directly into dst. + message + .serialize(&mut dst.writer()) + // This error should never happen, the conversion is for greater compatibility. + .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "serialization error"))?; + + let serialized_message = dst.split_to(dst.len()).freeze(); + + self.codec.encode(serialized_message, dst) + } +} + +impl Decoder for MessageCodec { + type Error = std::io::Error; + type Item = Message; + + fn decode(&mut self, source: &mut BytesMut) -> Result, Self::Error> { + // Decode a frame containing bytes belonging to a message. + let bytes = match self.codec.decode(source)? { + Some(bytes) => bytes, + None => return Ok(None), + }; + + // Convert the bytes to a message, or fail if it is not valid. + match Message::deserialize(bytes) { + Ok(message) => Ok(Some(message)), + Err(error) => { + error!("Failed to deserialize a message: {}", error); + Err(std::io::ErrorKind::InvalidData.into()) + } + } + } +} diff --git a/node/router/src/helpers/data.rs b/node/router/src/helpers/data.rs new file mode 100644 index 0000000000..be8a012402 --- /dev/null +++ b/node/router/src/helpers/data.rs @@ -0,0 +1,69 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use snarkvm::prelude::{FromBytes, ToBytes}; + +use ::bytes::Bytes; +use anyhow::Result; +use std::io::Write; +use tokio::task; + +/// This object enables deferred deserialization / ahead-of-time serialization for objects that +/// take a while to deserialize / serialize, in order to allow these operations to be non-blocking. +#[derive(Clone, Debug)] +pub enum Data { + Object(T), + Buffer(Bytes), +} + +impl Data { + pub async fn deserialize(self) -> Result { + match self { + Self::Object(x) => Ok(x), + Self::Buffer(bytes) => match task::spawn_blocking(move || T::from_bytes_le(&bytes)).await { + Ok(x) => x, + Err(err) => Err(err.into()), + }, + } + } + + pub fn deserialize_blocking(self) -> Result { + match self { + Self::Object(x) => Ok(x), + Self::Buffer(bytes) => T::from_bytes_le(&bytes), + } + } + + pub async fn serialize(self) -> Result { + match self { + Self::Object(x) => match task::spawn_blocking(move || x.to_bytes_le()).await { + Ok(bytes) => bytes.map(|vec| vec.into()), + Err(err) => Err(err.into()), + }, + Self::Buffer(bytes) => Ok(bytes), + } + } + + pub fn serialize_blocking_into(&self, writer: &mut W) -> Result<()> { + match self { + Self::Object(x) => { + let bytes = x.to_bytes_le()?; + Ok(writer.write_all(&bytes)?) + } + Self::Buffer(bytes) => Ok(writer.write_all(bytes)?), + } + } +} diff --git a/node/router/src/helpers/disconnect.rs b/node/router/src/helpers/disconnect.rs new file mode 100644 index 0000000000..ad50e13df6 --- /dev/null +++ b/node/router/src/helpers/disconnect.rs @@ -0,0 +1,46 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use serde::{Deserialize, Serialize}; + +/// The reason behind the node disconnecting from a peer. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub enum DisconnectReason { + /// The fork length limit was exceeded. + ExceededForkRange, + /// The peer's client uses an invalid fork depth. + InvalidForkDepth, + /// The node is a sync node and the peer is ahead. + INeedToSyncFirst, + /// No reason given. + NoReasonGiven, + /// The peer's client is outdated, judging by its version. + OutdatedClientVersion, + /// Dropping a dead connection. + PeerHasDisconnected, + /// The node is shutting down. + ShuttingDown, + /// The sync node has served its purpose. + SyncComplete, + /// The peer has caused too many failures. + TooManyFailures, + /// The node has too many connections already. + TooManyPeers, + /// The peer is a sync node that's behind our node, and it needs to sync itself first. + YouNeedToSyncFirst, + /// The peer's listening port is closed. + YourPortIsClosed(u16), +} diff --git a/node/router/src/helpers/mod.rs b/node/router/src/helpers/mod.rs new file mode 100644 index 0000000000..a74ba89f58 --- /dev/null +++ b/node/router/src/helpers/mod.rs @@ -0,0 +1,24 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +mod codec; +pub use codec::MessageCodec; + +mod data; +pub use data::Data; + +mod disconnect; +pub use disconnect::DisconnectReason; diff --git a/node/router/src/inbound.rs b/node/router/src/inbound.rs new file mode 100644 index 0000000000..7c837a1196 --- /dev/null +++ b/node/router/src/inbound.rs @@ -0,0 +1,381 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use crate::{message::*, Peer, Ping, Pong, Router, RouterRequest, ALEO_MAXIMUM_FORK_DEPTH}; +use snarkos_node_executor::{spawn_task, Executor}; +use snarkvm::prelude::Network; + +use core::time::Duration; +use std::{net::SocketAddr, time::SystemTime}; + +#[async_trait] +pub trait Inbound: Executor { + /// Handles the receiving of a message from a peer. Upon success, returns `true`. + #[rustfmt::skip] + async fn inbound(peer: &Peer, message: Message, router: &Router) -> bool { + // Retrieve the peer IP. + let peer_ip = *peer.ip(); + + // Process the message. + trace!("Received '{}' from {peer_ip}", message.name()); + match message { + Message::BlockRequest(message) => Self::block_request(message).await, + Message::BlockResponse(message) => Self::block_response(message).await, + Message::ChallengeRequest(..) | Message::ChallengeResponse(..) => { + // Peer is not following the protocol. + warn!("Peer {peer_ip} is not following the protocol"); + false + } + Message::Disconnect(message) => { + debug!("Peer {peer_ip} disconnected for the following reason: {:?}", message.reason); + false + } + Message::PeerRequest(..) => Self::peer_request(peer_ip, router).await, + Message::PeerResponse(message) => Self::peer_response(message, router).await, + Message::Ping(message) => Self::ping(message, peer_ip, peer).await, + Message::Pong(message) => Self::pong(message, peer_ip, router).await, + Message::UnconfirmedBlock(message) => Self::unconfirmed_block(message, peer_ip, peer, router).await, + Message::UnconfirmedSolution(message) => Self::unconfirmed_solution(message, peer_ip, peer, router).await, + Message::UnconfirmedTransaction(message) => Self::unconfirmed_transaction(message, peer_ip, peer, router).await + } + } + + async fn block_request(_message: BlockRequest) -> bool { + // // Ensure the request is within the accepted limits. + // let number_of_blocks = end_block_height.saturating_sub(start_block_height); + // if number_of_blocks > Router::::MAXIMUM_BLOCK_REQUEST { + // // Route a `Failure` to the ledger. + // let failure = format!("Attempted to request {} blocks", number_of_blocks); + // if let Err(error) = state.ledger().router().send(LedgerRequest::Failure(peer_ip, failure)).await { + // warn!("[Failure] {}", error); + // } + // continue; + // } + // // Retrieve the requested blocks. + // let blocks = match state.ledger().reader().get_blocks(start_block_height, end_block_height) { + // Ok(blocks) => blocks, + // Err(error) => { + // // Route a `Failure` to the ledger. + // if let Err(error) = state.ledger().router().send(LedgerRequest::Failure(peer_ip, format!("{}", error))).await { + // warn!("[Failure] {}", error); + // } + // continue; + // } + // }; + // // Send a `BlockResponse` message for each block to the peer. + // for block in blocks { + // debug!("Sending 'BlockResponse {}' to {}", block.height(), peer_ip); + // if let Err(error) = peer.outbound_socket.send(Message::BlockResponse(Data::Object(block))).await { + // warn!("[BlockResponse] {}", error); + // break; + // } + // } + true + } + + async fn block_response(_message: BlockResponse) -> bool { + // // Perform the deferred non-blocking deserialization of the block. + // match block.deserialize().await { + // Ok(block) => { + // // Route the `BlockResponse` to the ledger. + // if let Err(error) = state.ledger().router().send(LedgerRequest::BlockResponse(peer_ip, block)).await { + // warn!("[BlockResponse] {}", error); + // } + // }, + // // Route the `Failure` to the ledger. + // Err(error) => if let Err(error) = state.ledger().router().send(LedgerRequest::Failure(peer_ip, format!("{}", error))).await { + // warn!("[Failure] {}", error); + // } + // } + true + } + + async fn peer_request(peer_ip: SocketAddr, router: &Router) -> bool { + // Send a `PeerResponse` message. + if let Err(error) = router.process(RouterRequest::SendPeerResponse(peer_ip)).await { + warn!("[PeerRequest] {error}"); + } + true + } + + async fn peer_response(message: PeerResponse, router: &Router) -> bool { + // Adds the given peer IPs to the list of candidate peers. + if let Err(error) = router.process(RouterRequest::ReceivePeerResponse(message.peers)).await { + warn!("[PeerResponse] {error}"); + } + true + } + + async fn ping(message: Ping, peer_ip: SocketAddr, peer: &Peer) -> bool { + // Ensure the message protocol version is not outdated. + if message.version < Message::::VERSION { + warn!("Dropping {peer_ip} on version {} (outdated)", message.version); + return false; + } + // Ensure the maximum fork depth is correct. + if message.fork_depth != ALEO_MAXIMUM_FORK_DEPTH { + warn!("Dropping {peer_ip} for an incorrect maximum fork depth of {}", message.fork_depth); + return false; + } + // // Perform the deferred non-blocking deserialization of the block header. + // match block_header.deserialize().await { + // Ok(block_header) => { + // // If this node is not a sync node and is syncing, the peer is a sync node, and this node is ahead, proceed to disconnect. + // if E::NODE_TYPE != NodeType::Beacon + // && E::status().is_syncing() + // && node_type == NodeType::Beacon + // && state.ledger().reader().latest_cumulative_weight() > block_header.cumulative_weight() + // { + // trace!("Disconnecting from {} (ahead of sync node)", peer_ip); + // break; + // } + // + // // Update peer's block height. + // peer.block_height = block_header.height(); + // } + // Err(error) => warn!("[Ping] {}", error), + // } + + // Update the version of the peer. + *peer.version.write().await = message.version; + // Update the node type of the peer. + *peer.node_type.write().await = message.node_type; + // Update the status of the peer. + *peer.status.write().await = message.status; + + // // Determine if the peer is on a fork (or unknown). + // let is_fork = match state.ledger().reader().get_block_hash(peer.block_height) { + // Ok(expected_block_hash) => Some(expected_block_hash != block_hash), + // Err(_) => None, + // }; + let is_fork = Some(false); + + // Send a `Pong` message to the peer. + if let Err(error) = peer.send(Message::Pong(Pong { is_fork })).await { + warn!("[Pong] {error}"); + } + true + } + + async fn pong(_message: Pong, peer_ip: SocketAddr, router: &Router) -> bool { + // // Perform the deferred non-blocking deserialization of block locators. + // let request = match block_locators.deserialize().await { + // // Route the `Pong` to the ledger. + // Ok(block_locators) => LedgerRequest::Pong(peer_ip, peer.node_type, peer.status, is_fork, block_locators), + // // Route the `Failure` to the ledger. + // Err(error) => LedgerRequest::Failure(peer_ip, format!("{}", error)), + // }; + // + // // Route the request to the ledger. + // if let Err(error) = state.ledger().router().send(request).await { + // warn!("[Pong] {}", error); + // } + + // Spawn an asynchronous task for the `Ping` request. + let router = router.clone(); + spawn_task!(Self, Self::resources().procure_id(), { + // Sleep for the preset time before sending a `Ping` request. + tokio::time::sleep(Duration::from_secs(Router::::PING_SLEEP_IN_SECS)).await; + + // Send a `Ping` request to the peer. + let message = Message::Ping(Ping { + version: Message::::VERSION, + fork_depth: ALEO_MAXIMUM_FORK_DEPTH, + node_type: Self::NODE_TYPE, + status: Self::status().get(), + }); + if let Err(error) = router.process(RouterRequest::MessageSend(peer_ip, message)).await { + warn!("[Ping] {error}"); + } + }); + true + } + + async fn unconfirmed_block( + message: UnconfirmedBlock, + peer_ip: SocketAddr, + peer: &Peer, + router: &Router, + ) -> bool { + // Drop the peer, if they have sent more than 5 unconfirmed blocks in the last 5 seconds. + let frequency = + peer.seen_inbound_blocks.read().await.values().filter(|t| t.elapsed().unwrap().as_secs() <= 5).count(); + if frequency >= 10 { + warn!("Dropping {peer_ip} for spamming unconfirmed blocks (frequency = {frequency})"); + // Send a `PeerRestricted` message. + if let Err(error) = router.process(RouterRequest::PeerRestricted(peer_ip)).await { + warn!("[PeerRestricted] {error}"); + } + return false; + } + + // Acquire the lock on the seen inbound blocks. + let mut seen_inbound_blocks = peer.seen_inbound_blocks.write().await; + + // Retrieve the last seen timestamp of the received block. + let last_seen = seen_inbound_blocks.entry(message.block_hash).or_insert(SystemTime::UNIX_EPOCH); + let is_router_ready = last_seen.elapsed().unwrap().as_secs() > Router::::RADIO_SILENCE_IN_SECS; + + // Update the timestamp for the received block. + seen_inbound_blocks.insert(message.block_hash, SystemTime::now()); + + // Drop the lock on the seen inbound blocks. + drop(seen_inbound_blocks); + + // // Ensure the unconfirmed block is at least within 2 blocks of the latest block height, + // // and no more that 2 blocks ahead of the latest block height. + // // If it is stale, skip the routing of this unconfirmed block to the ledger. + // let latest_block_height = state.ledger().reader().latest_block_height(); + // let lower_bound = latest_block_height.saturating_sub(2); + // let upper_bound = latest_block_height.saturating_add(2); + // let is_within_range = block_height >= lower_bound && block_height <= upper_bound; + // + // // Ensure the node is not peering. + // let is_node_ready = !Self::status().is_peering(); + // + // if !is_router_ready || !is_within_range || !is_node_ready { + // trace!("Skipping 'UnconfirmedBlock {}' from {}", block_height, peer_ip) + // } else { + // // Perform the deferred non-blocking deserialization of the block. + // let request = match block.deserialize().await { + // // Ensure the claimed block height and block hash matches in the deserialized block. + // Ok(block) => match block_height == block.height() && block_hash == block.hash() { + // // Route the `UnconfirmedBlock` to the ledger. + // true => LedgerRequest::UnconfirmedBlock(peer_ip, block), + // // Route the `Failure` to the ledger. + // false => LedgerRequest::Failure(peer_ip, "Malformed UnconfirmedBlock message".to_string()) + // }, + // // Route the `Failure` to the ledger. + // Err(error) => LedgerRequest::Failure(peer_ip, format!("{}", error)), + // }; + // + // // Route the request to the ledger. + // if let Err(error) = state.ledger().router().send(request).await { + // warn!("[UnconfirmedBlock] {}", error); + // } + // } + true + } + + async fn unconfirmed_solution( + message: UnconfirmedSolution, + peer_ip: SocketAddr, + peer: &Peer, + router: &Router, + ) -> bool { + // Drop the peer, if they have sent more than 500 unconfirmed solutions in the last 5 seconds. + let frequency = + peer.seen_inbound_solutions.read().await.values().filter(|t| t.elapsed().unwrap().as_secs() <= 5).count(); + if frequency >= 500 { + warn!("Dropping {peer_ip} for spamming unconfirmed solutions (frequency = {frequency})"); + // Send a `PeerRestricted` message. + if let Err(error) = router.process(RouterRequest::PeerRestricted(peer_ip)).await { + warn!("[PeerRestricted] {error}"); + } + return false; + } + + // Perform the deferred non-blocking deserialization of the solution. + match message.solution.deserialize().await { + Ok(solution) => { + // Acquire the lock on the seen inbound solutions. + let mut seen_inbound_solutions = peer.seen_inbound_solutions.write().await; + + // Retrieve the last seen timestamp of the received solution. + let last_seen = seen_inbound_solutions.entry(solution.commitment()).or_insert(SystemTime::UNIX_EPOCH); + let is_router_ready = last_seen.elapsed().unwrap().as_secs() > Router::::RADIO_SILENCE_IN_SECS; + + // Update the timestamp for the received solution. + seen_inbound_solutions.insert(solution.commitment(), SystemTime::now()); + + // Drop the lock on the seen inbound solutions. + drop(seen_inbound_solutions); + + // Ensure the node is not peering. + let is_node_ready = !Self::status().is_peering(); + + if !is_router_ready || !is_node_ready { + trace!("Skipping 'UnconfirmedSolution {:?}' from {peer_ip}", solution.commitment()); + // } else { + // // // Route the `UnconfirmedSolution` to the prover. + // // if let Err(error) = state.prover().router().send(ProverRequest::UnconfirmedSolution(peer_ip, solution)).await { + // // warn!("[UnconfirmedSolution] {}", error); + // // + // // } + } + } + Err(error) => warn!("[UnconfirmedSolution] {error}"), + } + true + } + + async fn unconfirmed_transaction( + message: UnconfirmedTransaction, + peer_ip: SocketAddr, + peer: &Peer, + router: &Router, + ) -> bool { + // Drop the peer, if they have sent more than 500 unconfirmed transactions in the last 5 seconds. + let frequency = peer + .seen_inbound_transactions + .read() + .await + .values() + .filter(|t| t.elapsed().unwrap().as_secs() <= 5) + .count(); + if frequency >= 500 { + warn!("Dropping {peer_ip} for spamming unconfirmed transactions (frequency = {frequency})"); + // Send a `PeerRestricted` message. + if let Err(error) = router.process(RouterRequest::PeerRestricted(peer_ip)).await { + warn!("[PeerRestricted] {error}"); + } + return false; + } + + // Perform the deferred non-blocking deserialization of the transaction. + match message.transaction.deserialize().await { + Ok(transaction) => { + // Acquire the lock on the seen inbound transactions. + let mut seen_inbound_transactions = peer.seen_inbound_transactions.write().await; + + // Retrieve the last seen timestamp of the received transaction. + let last_seen = seen_inbound_transactions.entry(transaction.id()).or_insert(SystemTime::UNIX_EPOCH); + let is_router_ready = last_seen.elapsed().unwrap().as_secs() > Router::::RADIO_SILENCE_IN_SECS; + + // Update the timestamp for the received transaction. + seen_inbound_transactions.insert(transaction.id(), SystemTime::now()); + + // Drop the lock on the seen inbound transactions. + drop(seen_inbound_transactions); + + // Ensure the node is not peering. + let is_node_ready = !Self::status().is_peering(); + + if !is_router_ready || !is_node_ready { + trace!("Skipping 'UnconfirmedTransaction {}' from {peer_ip}", transaction.id()); + // } else { + // // // Route the `UnconfirmedTransaction` to the prover. + // // if let Err(error) = state.prover().router().send(ProverRequest::UnconfirmedTransaction(peer_ip, transaction)).await { + // // warn!("[UnconfirmedTransaction] {}", error); + // // + // // } + } + } + Err(error) => warn!("[UnconfirmedTransaction] {error}"), + } + true + } +} diff --git a/node/router/src/lib.rs b/node/router/src/lib.rs new file mode 100644 index 0000000000..59a33c45ff --- /dev/null +++ b/node/router/src/lib.rs @@ -0,0 +1,726 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +#![forbid(unsafe_code)] + +#[macro_use] +extern crate async_trait; +#[macro_use] +extern crate tracing; + +mod handshake; +pub use handshake::*; + +mod helpers; +pub use helpers::*; + +mod inbound; +pub use inbound::*; + +mod message; +pub use message::*; + +mod outbound; +pub use outbound::*; + +mod peer; +pub use peer::*; + +use snarkos_node_executor::{spawn_task, Executor, NodeType}; +use snarkvm::prelude::{Address, Network}; + +use anyhow::Result; +use indexmap::{IndexMap, IndexSet}; +use rand::{prelude::IteratorRandom, rngs::OsRng}; +use std::{ + net::SocketAddr, + sync::Arc, + time::{Duration, Instant, SystemTime}, +}; +use tokio::{ + net::{TcpListener, TcpStream}, + sync::{mpsc, mpsc::error::SendError, RwLock}, + time::timeout, +}; +use tokio_stream::StreamExt; +use tokio_util::codec::Framed; + +// TODO (raychu86): Move this declaration. +const ALEO_MAXIMUM_FORK_DEPTH: u32 = 4096; + +/// Shorthand for the parent half of the `Router` channel. +pub type RouterSender = mpsc::Sender>; +/// Shorthand for the child half of the `Router` channel. +pub type RouterReceiver = mpsc::Receiver>; + +/// An enum of requests that the `Router` processes. +pub enum RouterRequest { + /// Heartbeat + Heartbeat, + /// MessagePropagate := (message) + MessagePropagate(Message), + /// MessageSend := (peer_ip, message) + MessageSend(SocketAddr, Message), + /// PeerConnect := (peer_ip) + PeerConnect(SocketAddr), + /// PeerConnecting := (stream, peer_ip) + PeerConnecting(TcpStream, SocketAddr), + /// PeerConnected := (peer, outbound_socket, peer_handler) + PeerConnected(Peer, Framed>, PeerHandler), + /// PeerDisconnected := (peer_ip) + PeerDisconnected(SocketAddr), + /// PeerRestricted := (peer_ip) + PeerRestricted(SocketAddr), + /// SendPeerResponse := (peer_ip) + SendPeerResponse(SocketAddr), + /// ReceivePeerResponse := (\[peer_ip\]) + ReceivePeerResponse(Vec), +} + +#[derive(Clone, Debug)] +pub struct Router { + /// The router sender. + router_sender: RouterSender, + /// The local IP of the node. + local_ip: SocketAddr, + /// The account address of the node. + address: Address, + /// The node type. + node_type: NodeType, + /// The set of trusted peers. + trusted_peers: Arc>, + /// The map of connected peer IPs to their peer handlers. + connected_peers: Arc>>>, + /// The set of candidate peer IPs. + candidate_peers: Arc>>, + /// The set of restricted peer IPs. + restricted_peers: Arc>>, + /// The map of peers to their first-seen port number, number of attempts, and timestamp of the last inbound connection request. + seen_inbound_connections: Arc>>, + /// The map of peers to the timestamp of their last outbound connection request. + seen_outbound_connections: Arc>>, +} + +#[rustfmt::skip] +impl Router { + /// The maximum duration in seconds permitted for establishing a connection with a node, before dropping the connection. + const CONNECTION_TIMEOUT_IN_MILLIS: u64 = 210; // 3.5 minutes + /// The duration in seconds after which to expire a failure from a peer. + const FAILURE_EXPIRY_TIME_IN_SECS: u64 = 7200; // 2 hours + /// The duration in seconds to sleep in between heartbeat executions. + const HEARTBEAT_IN_SECS: u64 = 9; // 9 seconds + /// The maximum number of candidate peers permitted to be stored in the node. + const MAXIMUM_CANDIDATE_PEERS: usize = 10_000; + /// The maximum number of connection failures permitted by an inbound connecting peer. + const MAXIMUM_CONNECTION_FAILURES: u32 = 3; + /// The maximum number of peers permitted to maintain connections with. + const MAXIMUM_NUMBER_OF_PEERS: usize = 21; + /// The minimum number of peers required to maintain connections with. + const MINIMUM_NUMBER_OF_PEERS: usize = 1; + /// The duration in seconds to sleep in between ping requests with a connected peer. + const PING_SLEEP_IN_SECS: u64 = 60; // 1 minute + /// The duration in seconds after which a connected peer is considered inactive or + /// disconnected if no message has been received in the meantime. + const RADIO_SILENCE_IN_SECS: u64 = 180; // 3 minutes +} + +impl Router { + /// Initializes a new `Router` instance. + pub async fn new( + node_ip: SocketAddr, + address: Address, + node_type: NodeType, + trusted_peers: &[SocketAddr], + ) -> Result { + // Initialize a new TCP listener at the given IP. + let (local_ip, listener) = match TcpListener::bind(node_ip).await { + Ok(listener) => (listener.local_addr().expect("Failed to fetch the local IP"), listener), + Err(error) => panic!("Failed to bind listener: {:?}. Check if another Aleo node is running", error), + }; + + // Initialize an MPSC channel for sending requests to the `Router` struct. + let (router_sender, router_receiver) = mpsc::channel(1024); + + // Initialize the router. + let router = Self { + router_sender, + local_ip, + address, + node_type, + trusted_peers: Arc::new(trusted_peers.iter().copied().collect()), + connected_peers: Default::default(), + candidate_peers: Default::default(), + restricted_peers: Default::default(), + seen_inbound_connections: Default::default(), + seen_outbound_connections: Default::default(), + }; + + // Initialize the handler. + router.initialize_handler::(router_receiver).await; + // Initialize the listener. + router.initialize_listener::(listener).await; + // Initialize the heartbeat. + router.initialize_heartbeat::().await; + + Ok(router) + } + + /// Returns `true` if the given IP is this node. + pub fn is_local_ip(&self, ip: &SocketAddr) -> bool { + *ip == self.local_ip || (ip.ip().is_unspecified() || ip.ip().is_loopback()) && ip.port() == self.local_ip.port() + } + + /// Returns the IP address of this node. + pub const fn local_ip(&self) -> &SocketAddr { + &self.local_ip + } + + /// Returns the account address of this node. + pub const fn address(&self) -> &Address { + &self.address + } + + /// Returns the node type. + pub const fn node_type(&self) -> &NodeType { + &self.node_type + } + + /// Returns `true` if the node is connected to the given IP. + pub async fn is_connected_to(&self, ip: SocketAddr) -> bool { + self.connected_peers.read().await.contains_key(&ip) + } + + /// Returns `true` if the given IP is restricted. + pub async fn is_restricted(&self, ip: SocketAddr) -> bool { + match self.restricted_peers.read().await.get(&ip) { + Some(timestamp) => timestamp.elapsed().as_secs() < Self::RADIO_SILENCE_IN_SECS, + None => false, + } + } + + /// Returns the list of trusted peers. + pub fn trusted_peers(&self) -> &IndexSet { + &self.trusted_peers + } + + /// Returns the list of connected peers. + pub async fn connected_peers(&self) -> Vec { + self.connected_peers.read().await.keys().copied().collect() + } + + /// Returns the list of connected peers that are beacons. + pub async fn connected_beacons(&self) -> Vec { + let mut connected_beacons = Vec::new(); + for (ip, peer) in self.connected_peers.read().await.iter() { + if peer.is_beacon().await { + connected_beacons.push(*ip); + } + } + connected_beacons + } + + /// Returns the list of candidate peers. + pub async fn candidate_peers(&self) -> IndexSet { + self.candidate_peers.read().await.clone() + } + + /// Returns the list of restricted peers. + pub async fn restricted_peers(&self) -> Vec { + self.restricted_peers.read().await.keys().copied().collect() + } + + /// Returns the number of connected peers. + pub async fn number_of_connected_peers(&self) -> usize { + self.connected_peers.read().await.len() + } + + /// Returns the number of candidate peers. + pub async fn number_of_candidate_peers(&self) -> usize { + self.candidate_peers.read().await.len() + } + + /// Returns the number of restricted peers. + pub async fn number_of_restricted_peers(&self) -> usize { + self.restricted_peers.read().await.len() + } +} + +impl Router { + /// Initialize the handler for router requests. + async fn initialize_handler(&self, mut router_receiver: RouterReceiver) { + let router = self.clone(); + spawn_task!({ + // Asynchronously wait for a router request. + while let Some(request) = router_receiver.recv().await { + let router = router.clone(); + spawn_task!(E::resources().procure_id(), { + // Update the router. + router.handler::(request).await; + }); + } + }); + } + + /// Initialize the connection listener for new peers. + async fn initialize_listener(&self, listener: TcpListener) { + let router = self.clone(); + spawn_task!({ + info!("Listening for peers at {}", router.local_ip); + loop { + // Don't accept connections if the node is breaching the configured peer limit. + if router.number_of_connected_peers().await < Self::MAXIMUM_NUMBER_OF_PEERS { + // Asynchronously wait for an inbound TcpStream. + match listener.accept().await { + // Process the inbound connection request. + Ok((stream, peer_ip)) => { + if let Err(error) = router.process(RouterRequest::PeerConnecting(stream, peer_ip)).await { + error!("Failed to send request to peers: {error}") + } + } + Err(error) => error!("Failed to accept a connection: {error}"), + } + // Add a small delay to prevent overloading the network from handshakes. + tokio::time::sleep(Duration::from_millis(150)).await; + } else { + // Add a sleep delay as the node has reached peer capacity. + tokio::time::sleep(Duration::from_secs(10)).await; + } + } + }); + } + + /// Initialize a new instance of the heartbeat. + async fn initialize_heartbeat(&self) { + let router = self.clone(); + spawn_task!({ + loop { + // Transmit a heartbeat request to the router. + if let Err(error) = router.process(RouterRequest::Heartbeat).await { + error!("Failed to send heartbeat to router: {error}") + } + // Sleep for `Self::HEARTBEAT_IN_SECS` seconds. + tokio::time::sleep(Duration::from_secs(Self::HEARTBEAT_IN_SECS)).await; + } + }); + } +} + +impl Router { + /// Routes the given request to the router to process during `Self::handler`. + pub async fn process(&self, request: RouterRequest) -> Result<(), SendError>> { + self.router_sender.send(request).await + } + + /// Performs the given `request` to the peers. + /// All requests must go through this `handler`, so that a unified view is preserved. + pub(crate) async fn handler(&self, request: RouterRequest) { + debug!("Peers: {:?}", self.connected_peers().await); + + match request { + RouterRequest::Heartbeat => self.handle_heartbeat().await, + RouterRequest::MessagePropagate(message) => self.handle_propagate(message).await, + RouterRequest::MessageSend(sender, message) => self.handle_send(sender, message).await, + RouterRequest::PeerConnect(peer_ip) => self.handle_peer_connect::(peer_ip).await, + RouterRequest::PeerConnecting(stream, peer_ip) => self.handle_peer_connecting::(stream, peer_ip).await, + RouterRequest::PeerConnected(peer, outbound_socket, peer_handler) => { + // Add an entry for this `Peer` in the connected peers. + self.connected_peers.write().await.insert(*peer.ip(), peer.clone()); + // Remove an entry for this `Peer` in the candidate peers, if it exists. + self.candidate_peers.write().await.remove(peer.ip()); + // Handle the peer connection. + self.handle_peer_connected::(peer, outbound_socket, peer_handler).await; + } + RouterRequest::PeerDisconnected(peer_ip) => { + // Remove an entry for this `Peer` in the connected peers, if it exists. + self.connected_peers.write().await.remove(&peer_ip); + // Add an entry for this `Peer` in the candidate peers. + self.candidate_peers.write().await.insert(peer_ip); + } + RouterRequest::PeerRestricted(peer_ip) => { + // Remove an entry for this `Peer` in the connected peers, if it exists. + self.connected_peers.write().await.remove(&peer_ip); + // Add an entry for this `Peer` in the restricted peers. + self.restricted_peers.write().await.insert(peer_ip, Instant::now()); + } + RouterRequest::SendPeerResponse(recipient) => { + // Send a `PeerResponse` message. + let connected_peers = self.connected_peers().await; + self.handle_send(recipient, Message::PeerResponse(PeerResponse { peers: connected_peers })).await; + } + RouterRequest::ReceivePeerResponse(peer_ips) => { + self.add_candidate_peers(peer_ips.iter()).await; + } + } + } + + /// Handles the heartbeat request. + async fn handle_heartbeat(&self) { + // Obtain the number of connected peers. + let number_of_connected_peers = self.number_of_connected_peers().await; + // Ensure the number of connected peers is below the maximum threshold. + if number_of_connected_peers > Self::MAXIMUM_NUMBER_OF_PEERS { + debug!("Exceeded maximum number of connected peers"); + + // Determine the peers to disconnect from. + let num_excess_peers = number_of_connected_peers.saturating_sub(Self::MAXIMUM_NUMBER_OF_PEERS); + let peer_ips_to_disconnect = self + .connected_peers + .read() + .await + .keys() + .filter( + |peer_ip| /* !E::beacon_nodes().contains(peer_ip) && */ !self.trusted_peers().contains(*peer_ip), + ) + .take(num_excess_peers) + .copied() + .collect::>(); + + // Proceed to send disconnect requests to these peers. + for peer_ip in peer_ips_to_disconnect { + info!("Disconnecting from {peer_ip} (exceeded maximum connections)"); + self.handle_send(peer_ip, Message::Disconnect(DisconnectReason::TooManyPeers.into())).await; + // Add an entry for this `Peer` in the restricted peers. + self.restricted_peers.write().await.insert(peer_ip, Instant::now()); + } + } + + // TODO (howardwu): This logic can be optimized and unified with the context around it. + // Determine if the node is connected to more sync nodes than expected. + let connected_beacons = self.connected_beacons().await; + let number_of_connected_beacons = connected_beacons.len(); + let num_excess_beacons = number_of_connected_beacons.saturating_sub(1); + if num_excess_beacons > 0 { + debug!("Exceeded maximum number of beacons"); + + // Proceed to send disconnect requests to these peers. + for peer_ip in connected_beacons.iter().copied().choose_multiple(&mut OsRng::default(), num_excess_beacons) + { + info!("Disconnecting from 'beacon' {peer_ip} (exceeded maximum connections)"); + self.handle_send(peer_ip, Message::Disconnect(DisconnectReason::TooManyPeers.into())).await; + // Add an entry for this `Peer` in the restricted peers. + self.restricted_peers.write().await.insert(peer_ip, Instant::now()); + } + } + + // Ensure that the trusted nodes are connected. + if !self.trusted_peers().is_empty() { + let connected_peers = self.connected_peers().await.into_iter().collect::>(); + let disconnected_trusted_nodes = self.trusted_peers().difference(&connected_peers).copied(); + for peer_ip in disconnected_trusted_nodes { + if let Err(error) = self.process(RouterRequest::PeerConnect(peer_ip)).await { + warn!("Failed to transmit the request: '{error}'"); + } + } + } + + // Skip if the number of connected peers is above the minimum threshold. + match number_of_connected_peers < Self::MINIMUM_NUMBER_OF_PEERS { + true => { + if number_of_connected_peers > 0 { + trace!("Sending requests for more peer connections"); + // Request more peers if the number of connected peers is below the threshold. + for peer_ip in self.connected_peers().await.iter().choose_multiple(&mut OsRng::default(), 3) { + self.handle_send(*peer_ip, Message::PeerRequest(PeerRequest)).await; + } + } + } + false => return, + }; + + // Attempt to connect to more peers if the number of connected peers is below the minimum threshold. + // Select the peers randomly from the list of candidate peers. + let midpoint_number_of_peers = Self::MINIMUM_NUMBER_OF_PEERS.saturating_add(Self::MAXIMUM_NUMBER_OF_PEERS) / 2; + for peer_ip in self + .candidate_peers() + .await + .iter() + .copied() + .choose_multiple(&mut OsRng::default(), midpoint_number_of_peers) + { + // TODO (howardwu): This check is skipped because we no longer have a fixed set of beacon nodes. + // Introduce network-level connection safety for beacon nodes. + // // Ensure this node is not connected to more than the permitted number of sync nodes. + // if E::beacon_nodes().contains(&peer_ip) && number_of_connected_beacons >= 1 { + // continue; + // } + + if !self.is_connected_to(peer_ip).await { + trace!("Attempting connection to {peer_ip}..."); + if let Err(error) = self.process(RouterRequest::PeerConnect(peer_ip)).await { + warn!("Failed to transmit the request: '{error}'"); + } + } + } + } + + /// Handles the request to connect to the given IP. + async fn handle_peer_connect(&self, peer_ip: SocketAddr) { + // Ensure the peer IP is not this node. + if self.is_local_ip(&peer_ip) { + debug!("Skipping connection request to {peer_ip} (attempted to self-connect)"); + } + // Ensure the node does not surpass the maximum number of peer connections. + else if self.number_of_connected_peers().await >= Self::MAXIMUM_NUMBER_OF_PEERS { + debug!("Skipping connection request to {peer_ip} (maximum peers reached)"); + } + // Ensure the peer is a new connection. + else if self.is_connected_to(peer_ip).await { + debug!("Skipping connection request to {peer_ip} (already connected)"); + } + // Ensure the peer is not restricted. + else if self.is_restricted(peer_ip).await { + debug!("Skipping connection request to {peer_ip} (restricted)"); + } + // Attempt to open a TCP stream. + else { + // Lock seen_outbound_connections for further processing. + let mut seen_outbound_connections = self.seen_outbound_connections.write().await; + + // Ensure the node respects the connection frequency limit. + let last_seen = seen_outbound_connections.entry(peer_ip).or_insert(SystemTime::UNIX_EPOCH); + let elapsed = last_seen.elapsed().unwrap_or(Duration::MAX).as_secs(); + if elapsed < Self::RADIO_SILENCE_IN_SECS { + trace!("Skipping connection request to {peer_ip} (tried {elapsed} secs ago)"); + } else { + debug!("Connecting to {peer_ip}..."); + // Update the last seen timestamp for this peer. + seen_outbound_connections.insert(peer_ip, SystemTime::now()); + + // Release the lock over seen_outbound_connections. + drop(seen_outbound_connections); + + // Initialize the peer. + match timeout(Duration::from_millis(Self::CONNECTION_TIMEOUT_IN_MILLIS), TcpStream::connect(peer_ip)) + .await + { + Ok(stream) => match stream { + Ok(stream) => { + let router = self.clone(); + spawn_task!(E::resources().procure_id(), { + if let Err(error) = E::handshake(router, stream).await { + trace!("{error}"); + } + }); + } + Err(error) => { + trace!("Failed to connect to '{peer_ip}': '{:?}'", error); + self.candidate_peers.write().await.remove(&peer_ip); + } + }, + Err(error) => { + error!("Unable to reach '{peer_ip}': '{:?}'", error); + self.candidate_peers.write().await.remove(&peer_ip); + } + }; + } + } + } + + /// Handles the peer connecting request. + async fn handle_peer_connecting(&self, stream: TcpStream, peer_ip: SocketAddr) { + // Ensure the peer IP is not this node. + if self.is_local_ip(&peer_ip) { + debug!("Dropping connection request from {peer_ip} (attempted to self-connect)"); + } + // Ensure the node does not surpass the maximum number of peer connections. + else if self.number_of_connected_peers().await >= Self::MAXIMUM_NUMBER_OF_PEERS { + debug!("Dropping connection request from {peer_ip} (maximum peers reached)"); + } + // Ensure the node is not already connected to this peer. + else if self.is_connected_to(peer_ip).await { + debug!("Dropping connection request from {peer_ip} (already connected)"); + } + // Ensure the peer is not restricted. + else if self.is_restricted(peer_ip).await { + debug!("Dropping connection request from {peer_ip} (restricted)"); + } + // Spawn a handler to be run asynchronously. + else { + // Sanitize the port from the peer, if it is a remote IP address. + let (peer_lookup, peer_port) = match peer_ip.ip().is_loopback() { + // Loopback case - Do not sanitize, merely pass through. + true => (peer_ip, peer_ip.port()), + // Remote case - Sanitize, storing u16::MAX for the peer IP address to dedup the peer next time. + false => (SocketAddr::new(peer_ip.ip(), u16::MAX), peer_ip.port()), + }; + + // Lock seen_inbound_connections for further processing. + let mut seen_inbound_connections = self.seen_inbound_connections.write().await; + + // Fetch the inbound tracker entry for this peer. + let ((initial_port, num_attempts), last_seen) = + seen_inbound_connections.entry(peer_lookup).or_insert(((peer_port, 0), SystemTime::UNIX_EPOCH)); + let elapsed = last_seen.elapsed().unwrap_or(Duration::MAX).as_secs(); + + // Reset the inbound tracker entry for this peer, if the predefined elapsed time has passed. + if elapsed > Self::RADIO_SILENCE_IN_SECS { + // Reset the initial port for this peer. + *initial_port = peer_port; + // Reset the number of attempts for this peer. + *num_attempts = 0; + // Reset the last seen timestamp for this peer. + *last_seen = SystemTime::now(); + } + + // Ensure the connecting peer has not surpassed the connection attempt limit. + if *num_attempts > Self::MAXIMUM_CONNECTION_FAILURES { + trace!("Dropping connection request from {peer_ip} (tried {elapsed} secs ago)"); + // Add an entry for this `Peer` in the restricted peers. + self.restricted_peers.write().await.insert(peer_ip, Instant::now()); + } else { + debug!("Received a connection request from {peer_ip}"); + // Update the number of attempts for this peer. + *num_attempts += 1; + + // Release the lock over seen_inbound_connections. + drop(seen_inbound_connections); + + // Initialize the peer handler. + let router = self.clone(); + spawn_task!(E::resources().procure_id(), { + if let Err(error) = E::handshake(router, stream).await { + trace!("{error}"); + } + }); + } + } + } + + /// Initialize the handler for the new peer. + async fn handle_peer_connected( + &self, + peer: Peer, + mut outbound_socket: Framed>, + mut peer_handler: PeerHandler, + ) { + let router = self.clone(); + spawn_task!(E::resources().procure_id(), { + // Retrieve the peer IP. + let peer_ip = *peer.ip(); + + info!("Connected to {peer_ip}"); + + // Process incoming messages until this stream is disconnected. + loop { + tokio::select! { + // Message channel is routing a message outbound to the peer. + Some(message) = peer_handler.recv() => { + // Retrieve the peer IP. + let peer_ip = peer.ip(); + + // Disconnect if the peer has not communicated back within the predefined time. + let last_seen_elapsed = peer.last_seen.read().await.elapsed().as_secs(); + if last_seen_elapsed > Self::RADIO_SILENCE_IN_SECS { + warn!("Peer {peer_ip} has not communicated in {last_seen_elapsed} seconds"); + break; + } + + E::outbound(&peer, message, &mut outbound_socket).await + }, + result = outbound_socket.next() => match result { + // Received a message from the peer. + Some(Ok(message)) => { + // Retrieve the peer IP. + let peer_ip = *peer.ip(); + + // Disconnect if the peer has not communicated back within the predefined time. + let last_seen_elapsed = peer.last_seen.read().await.elapsed().as_secs(); + match last_seen_elapsed > Self::RADIO_SILENCE_IN_SECS { + true => { + warn!("Failed to receive a message from {peer_ip} in {last_seen_elapsed} seconds"); + break; + } + // Update the last seen timestamp. + false => *peer.last_seen.write().await = Instant::now(), + } + + // Process the message. + let success = E::inbound(&peer, message, &router).await; + // Disconnect if the peer violated the protocol. + if !success { + warn!("Disconnecting from {peer_ip} (violated protocol)"); + break; + } + }, + // An error occurred. + Some(Err(error)) => error!("Failed to read message from {peer_ip}: {error}"), + // The stream has been disconnected. + None => break, + }, + } + } + + warn!("[Peer::Disconnect] Peer {peer_ip} has disconnected"); + + // // When this is reached, it means the peer has disconnected. + // // Route a `Disconnect` to the ledger. + // if let Err(error) = state.ledger().router() + // .send(LedgerRequest::Disconnect(peer_ip, DisconnectReason::PeerHasDisconnected)) + // .await + // { + // warn!("[Peer::Disconnect] {}", error); + // } + }); + } + + /// Sends the given message to specified peer. + async fn handle_send(&self, peer_ip: SocketAddr, message: Message) { + let target_peer = self.connected_peers.read().await.get(&peer_ip).cloned(); + match target_peer { + Some(peer) => { + if let Err(error) = peer.send(message).await { + trace!("Failed to send message to {peer_ip}: {error}"); + self.connected_peers.write().await.remove(&peer_ip); + } + } + None => warn!("Attempted to send to a non-connected peer {peer_ip}"), + } + } + + /// Sends the given message to every connected peer, excluding the sender. + async fn handle_propagate(&self, mut message: Message) { + // Perform ahead-of-time, non-blocking serialization just once for applicable objects. + if let Message::UnconfirmedBlock(ref mut message) = message { + let serialized_block = Data::serialize(message.block.clone()).await.expect("Block serialization is bugged"); + let _ = std::mem::replace(&mut message.block, Data::Buffer(serialized_block)); + } + + // Iterate through all peers that are not the sender. + for peer in self.connected_peers().await.iter().filter(|peer_ip| !self.is_local_ip(peer_ip)) { + self.handle_send(*peer, message.clone()).await; + } + } + + /// Adds the given peer IPs to the set of candidate peers. + /// + /// This method skips adding any given peers if the combined size exceeds the threshold, + /// as the peer providing this list could be subverting the protocol. + async fn add_candidate_peers<'a, T: ExactSizeIterator + IntoIterator>(&self, peers: T) { + // Acquire the candidate peers write lock. + let mut candidate_peers = self.candidate_peers.write().await; + // Ensure the combined number of peers does not surpass the threshold. + for peer_ip in peers.take(Self::MAXIMUM_CANDIDATE_PEERS.saturating_sub(candidate_peers.len())) { + // Ensure the peer is not itself, is not already connected, and is not restricted. + if !self.is_local_ip(peer_ip) + && !self.is_connected_to(*peer_ip).await + && !self.is_restricted(*peer_ip).await + { + // Proceed to insert each new candidate peer IP. + candidate_peers.insert(*peer_ip); + } + } + } +} diff --git a/node/router/src/message/block_request.rs b/node/router/src/message/block_request.rs new file mode 100644 index 0000000000..7de8e3f729 --- /dev/null +++ b/node/router/src/message/block_request.rs @@ -0,0 +1,47 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct BlockRequest { + pub start_block_height: u32, + pub end_block_height: u32, +} + +impl MessageTrait for BlockRequest { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "BlockRequest" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + Ok(bincode::serialize_into(writer, &(self.start_block_height, self.end_block_height))?) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + let mut reader = bytes.reader(); + Ok(Self { + start_block_height: bincode::deserialize_from(&mut reader)?, + end_block_height: bincode::deserialize_from(&mut reader)?, + }) + } +} diff --git a/node/router/src/message/block_response.rs b/node/router/src/message/block_response.rs new file mode 100644 index 0000000000..f2025ad143 --- /dev/null +++ b/node/router/src/message/block_response.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct BlockResponse { + pub block: Data>, +} + +impl MessageTrait for BlockResponse { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "BlockResponse" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + self.block.serialize_blocking_into(writer) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + Ok(Self { block: Data::Buffer(bytes.freeze()) }) + } +} diff --git a/node/router/src/message/challenge_request.rs b/node/router/src/message/challenge_request.rs new file mode 100644 index 0000000000..e7ec790558 --- /dev/null +++ b/node/router/src/message/challenge_request.rs @@ -0,0 +1,50 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct ChallengeRequest { + pub version: u32, + pub fork_depth: u32, + pub node_type: NodeType, + pub status: Status, + pub listener_port: u16, +} + +impl MessageTrait for ChallengeRequest { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "ChallengeRequest" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + Ok(bincode::serialize_into( + writer, + &(self.version, self.fork_depth, self.node_type, self.status, self.listener_port), + )?) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + let (version, fork_depth, node_type, status, listener_port) = bincode::deserialize_from(&mut bytes.reader())?; + Ok(Self { version, fork_depth, node_type, status, listener_port }) + } +} diff --git a/node/router/src/message/challenge_response.rs b/node/router/src/message/challenge_response.rs new file mode 100644 index 0000000000..3cf8db12bd --- /dev/null +++ b/node/router/src/message/challenge_response.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct ChallengeResponse { + pub header: Data>, +} + +impl MessageTrait for ChallengeResponse { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "ChallengeResponse" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + Ok(self.header.serialize_blocking_into(writer)?) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + Ok(Self { header: Data::Buffer(bytes.freeze()) }) + } +} diff --git a/node/router/src/message/disconnect.rs b/node/router/src/message/disconnect.rs new file mode 100644 index 0000000000..6b13b02e63 --- /dev/null +++ b/node/router/src/message/disconnect.rs @@ -0,0 +1,54 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct Disconnect { + pub reason: DisconnectReason, +} + +impl MessageTrait for Disconnect { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "Disconnect" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + Ok(bincode::serialize_into(writer, &self.reason)?) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + if bytes.remaining() == 0 { + Ok(Self { reason: DisconnectReason::NoReasonGiven }) + } else if let Ok(reason) = bincode::deserialize_from(&mut bytes.reader()) { + Ok(Self { reason }) + } else { + bail!("Invalid 'Disconnect' message"); + } + } +} + +impl From for Disconnect { + fn from(reason: DisconnectReason) -> Self { + Self { reason } + } +} diff --git a/node/router/src/message/mod.rs b/node/router/src/message/mod.rs new file mode 100644 index 0000000000..c575d6b42b --- /dev/null +++ b/node/router/src/message/mod.rs @@ -0,0 +1,181 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +mod block_request; +pub use block_request::BlockRequest; + +mod block_response; +pub use block_response::BlockResponse; + +mod challenge_request; +pub use challenge_request::ChallengeRequest; + +mod challenge_response; +pub use challenge_response::ChallengeResponse; + +mod disconnect; +pub use disconnect::Disconnect; + +mod peer_request; +pub use peer_request::PeerRequest; + +mod peer_response; +pub use peer_response::PeerResponse; + +mod ping; +pub use ping::Ping; + +mod pong; +pub use pong::Pong; + +mod unconfirmed_block; +pub use unconfirmed_block::UnconfirmedBlock; + +mod unconfirmed_solution; +pub use unconfirmed_solution::UnconfirmedSolution; + +mod unconfirmed_transaction; +pub use unconfirmed_transaction::UnconfirmedTransaction; + +use crate::{Data, DisconnectReason}; +use snarkos_node_executor::{NodeType, Status}; +use snarkvm::prelude::{Block, Header, Network, ProverSolution, ToBytes, Transaction}; + +use ::bytes::{Buf, BytesMut}; +use anyhow::{bail, Result}; +use std::{io::Write, net::SocketAddr}; + +pub trait MessageTrait { + /// Returns the message name. + fn name(&self) -> &str; + /// Serializes the message into the buffer. + fn serialize(&self, writer: &mut W) -> Result<()>; + /// Deserializes the given buffer into a message. + fn deserialize(bytes: BytesMut) -> Result + where + Self: Sized; +} + +#[derive(Clone, Debug)] +pub enum Message { + BlockRequest(BlockRequest), + BlockResponse(BlockResponse), + ChallengeRequest(ChallengeRequest), + ChallengeResponse(ChallengeResponse), + Disconnect(Disconnect), + PeerRequest(PeerRequest), + PeerResponse(PeerResponse), + Ping(Ping), + Pong(Pong), + UnconfirmedBlock(UnconfirmedBlock), + UnconfirmedSolution(UnconfirmedSolution), + UnconfirmedTransaction(UnconfirmedTransaction), +} + +impl Message { + /// The version of the network protocol; it can be incremented in order to force users to update. + pub const VERSION: u32 = 1; + + /// Returns the message name. + #[inline] + pub fn name(&self) -> &str { + match self { + Self::BlockRequest(message) => message.name(), + Self::BlockResponse(message) => message.name(), + Self::ChallengeRequest(message) => message.name(), + Self::ChallengeResponse(message) => message.name(), + Self::Disconnect(message) => message.name(), + Self::PeerRequest(message) => message.name(), + Self::PeerResponse(message) => message.name(), + Self::Ping(message) => message.name(), + Self::Pong(message) => message.name(), + Self::UnconfirmedBlock(message) => message.name(), + Self::UnconfirmedSolution(message) => message.name(), + Self::UnconfirmedTransaction(message) => message.name(), + } + } + + /// Returns the message ID. + #[inline] + pub fn id(&self) -> u16 { + match self { + Self::BlockRequest(..) => 0, + Self::BlockResponse(..) => 1, + Self::ChallengeRequest(..) => 2, + Self::ChallengeResponse(..) => 3, + Self::Disconnect(..) => 4, + Self::PeerRequest(..) => 5, + Self::PeerResponse(..) => 6, + Self::Ping(..) => 7, + Self::Pong(..) => 8, + Self::UnconfirmedBlock(..) => 9, + Self::UnconfirmedSolution(..) => 10, + Self::UnconfirmedTransaction(..) => 11, + } + } + + /// Serializes the message into the buffer. + #[inline] + pub fn serialize(&self, writer: &mut W) -> Result<()> { + writer.write_all(&self.id().to_le_bytes()[..])?; + + match self { + Self::BlockRequest(message) => message.serialize(writer), + Self::BlockResponse(message) => message.serialize(writer), + Self::ChallengeRequest(message) => message.serialize(writer), + Self::ChallengeResponse(message) => message.serialize(writer), + Self::Disconnect(message) => message.serialize(writer), + Self::PeerRequest(message) => message.serialize(writer), + Self::PeerResponse(message) => message.serialize(writer), + Self::Ping(message) => message.serialize(writer), + Self::Pong(message) => message.serialize(writer), + Self::UnconfirmedBlock(message) => message.serialize(writer), + Self::UnconfirmedSolution(message) => message.serialize(writer), + Self::UnconfirmedTransaction(message) => message.serialize(writer), + } + } + + /// Deserializes the given buffer into a message. + #[inline] + pub fn deserialize(mut bytes: BytesMut) -> Result { + // Ensure there is at least a message ID in the buffer. + if bytes.remaining() < 2 { + bail!("Missing message ID"); + } + + // Read the message ID. + let id: u16 = bytes.get_u16_le(); + + // Deserialize the data field. + let message = match id { + 0 => Self::BlockRequest(MessageTrait::deserialize(bytes)?), + 1 => Self::BlockResponse(MessageTrait::deserialize(bytes)?), + 2 => Self::ChallengeRequest(MessageTrait::deserialize(bytes)?), + 3 => Self::ChallengeResponse(MessageTrait::deserialize(bytes)?), + 4 => Self::Disconnect(MessageTrait::deserialize(bytes)?), + 5 => Self::PeerRequest(MessageTrait::deserialize(bytes)?), + 6 => Self::PeerResponse(MessageTrait::deserialize(bytes)?), + 7 => Self::Ping(MessageTrait::deserialize(bytes)?), + 8 => Self::Pong(MessageTrait::deserialize(bytes)?), + 9 => Self::UnconfirmedBlock(MessageTrait::deserialize(bytes)?), + 10 => Self::UnconfirmedSolution(MessageTrait::deserialize(bytes)?), + 11 => Self::UnconfirmedTransaction(MessageTrait::deserialize(bytes)?), + _ => bail!("Unknown message ID {id}"), + }; + + Ok(message) + } +} diff --git a/node/router/src/message/peer_request.rs b/node/router/src/message/peer_request.rs new file mode 100644 index 0000000000..f2155b4a92 --- /dev/null +++ b/node/router/src/message/peer_request.rs @@ -0,0 +1,43 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct PeerRequest; + +impl MessageTrait for PeerRequest { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "PeerRequest" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, _writer: &mut W) -> Result<()> { + Ok(()) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + match bytes.remaining() == 0 { + true => Ok(Self), + false => bail!("Invalid 'PeerRequest' message"), + } + } +} diff --git a/node/router/src/message/peer_response.rs b/node/router/src/message/peer_response.rs new file mode 100644 index 0000000000..f64c62ecf6 --- /dev/null +++ b/node/router/src/message/peer_response.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct PeerResponse { + pub peers: Vec, +} + +impl MessageTrait for PeerResponse { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "PeerResponse" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + Ok(bincode::serialize_into(writer, &self.peers)?) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + Ok(Self { peers: bincode::deserialize_from(&mut bytes.reader())? }) + } +} diff --git a/node/router/src/message/ping.rs b/node/router/src/message/ping.rs new file mode 100644 index 0000000000..66080b5efb --- /dev/null +++ b/node/router/src/message/ping.rs @@ -0,0 +1,47 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct Ping { + pub version: u32, + pub fork_depth: u32, + pub node_type: NodeType, + pub status: Status, +} + +impl MessageTrait for Ping { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "Ping" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + Ok(bincode::serialize_into(&mut *writer, &(self.version, self.fork_depth, self.node_type, self.status))?) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + let mut reader = bytes.reader(); + let (version, fork_depth, node_type, status) = bincode::deserialize_from(&mut reader)?; + Ok(Self { version, fork_depth, node_type, status }) + } +} diff --git a/node/router/src/message/pong.rs b/node/router/src/message/pong.rs new file mode 100644 index 0000000000..ec2d7d1c9a --- /dev/null +++ b/node/router/src/message/pong.rs @@ -0,0 +1,62 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct Pong { + pub is_fork: Option, +} + +impl MessageTrait for Pong { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "Pong" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + let serialized_is_fork: u8 = match self.is_fork { + Some(true) => 0, + Some(false) => 1, + None => 2, + }; + + Ok(writer.write_all(&[serialized_is_fork])?) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(mut bytes: BytesMut) -> Result { + // Make sure a byte for the fork flag is available. + if bytes.remaining() == 0 { + bail!("Missing fork flag in a 'Pong'"); + } + + let fork_flag = bytes.get_u8(); + + let is_fork = match fork_flag { + 0 => Some(true), + 1 => Some(false), + 2 => None, + _ => bail!("Invalid 'Pong' message"), + }; + + Ok(Self { is_fork }) + } +} diff --git a/node/router/src/message/unconfirmed_block.rs b/node/router/src/message/unconfirmed_block.rs new file mode 100644 index 0000000000..b26ccf5dc4 --- /dev/null +++ b/node/router/src/message/unconfirmed_block.rs @@ -0,0 +1,51 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct UnconfirmedBlock { + pub block_height: u32, + pub block_hash: N::BlockHash, + pub block: Data>, +} + +impl MessageTrait for UnconfirmedBlock { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "UnconfirmedBlock" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + writer.write_all(&self.block_height.to_le_bytes())?; + writer.write_all(&self.block_hash.to_bytes_le()?)?; + self.block.serialize_blocking_into(writer) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + let mut reader = bytes.reader(); + Ok(Self { + block_height: bincode::deserialize_from(&mut reader)?, + block_hash: bincode::deserialize_from(&mut reader)?, + block: Data::Buffer(reader.into_inner().freeze()), + }) + } +} diff --git a/node/router/src/message/unconfirmed_solution.rs b/node/router/src/message/unconfirmed_solution.rs new file mode 100644 index 0000000000..b7a9ece91d --- /dev/null +++ b/node/router/src/message/unconfirmed_solution.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct UnconfirmedSolution { + pub solution: Data>, +} + +impl MessageTrait for UnconfirmedSolution { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "UnconfirmedSolution" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + Ok(self.solution.serialize_blocking_into(writer)?) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + Ok(Self { solution: Data::Buffer(bytes.freeze()) }) + } +} diff --git a/node/router/src/message/unconfirmed_transaction.rs b/node/router/src/message/unconfirmed_transaction.rs new file mode 100644 index 0000000000..93abdfd734 --- /dev/null +++ b/node/router/src/message/unconfirmed_transaction.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[derive(Clone, Debug)] +pub struct UnconfirmedTransaction { + pub transaction: Data>, +} + +impl MessageTrait for UnconfirmedTransaction { + /// Returns the message name. + #[inline] + fn name(&self) -> &str { + "UnconfirmedTransaction" + } + + /// Serializes the message into the buffer. + #[inline] + fn serialize(&self, writer: &mut W) -> Result<()> { + Ok(self.transaction.serialize_blocking_into(writer)?) + } + + /// Deserializes the given buffer into a message. + #[inline] + fn deserialize(bytes: BytesMut) -> Result { + Ok(Self { transaction: Data::Buffer(bytes.freeze()) }) + } +} diff --git a/node/router/src/outbound.rs b/node/router/src/outbound.rs new file mode 100644 index 0000000000..979ee5079b --- /dev/null +++ b/node/router/src/outbound.rs @@ -0,0 +1,143 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use crate::{Data, Message, MessageCodec, Peer, Router}; +use snarkvm::prelude::Network; + +use futures::SinkExt; +use std::time::SystemTime; +use tokio::net::TcpStream; +use tokio_util::codec::Framed; + +#[async_trait] +pub trait Outbound { + /// Handles the sending of a message to a peer. + async fn outbound( + peer: &Peer, + mut message: Message, + outbound_socket: &mut Framed>, + ) { + // Retrieve the peer IP. + let peer_ip = peer.ip(); + + // Ensure sufficient time has passed before needing to send the message. + let is_ready_to_send = match message { + Message::UnconfirmedBlock(ref mut message) => { + // Retrieve the last seen timestamp of this block for this peer. + let last_seen = peer + .seen_outbound_blocks + .write() + .await + .entry(message.block_hash) + .or_insert(SystemTime::UNIX_EPOCH) + .elapsed() + .unwrap() + .as_secs(); + let is_ready_to_send = last_seen > Router::::RADIO_SILENCE_IN_SECS; + + // Update the timestamp for the peer and sent block. + peer.seen_outbound_blocks.write().await.insert(message.block_hash, SystemTime::now()); + // Report the unconfirmed block height. + if is_ready_to_send { + trace!("Preparing to send 'UnconfirmedBlock {}' to {peer_ip}", message.block_height); + } + + // Perform non-blocking serialization of the block (if it hasn't been serialized yet). + let serialized_block = + Data::serialize(message.block.clone()).await.expect("Block serialization is bugged"); + let _ = std::mem::replace(&mut message.block, Data::Buffer(serialized_block)); + + is_ready_to_send + } + Message::UnconfirmedSolution(ref mut message) => { + let solution_commitment = if let Data::Object(solution) = &message.solution { + solution.commitment() + } else { + panic!("Logic error: the solution shouldn't have been serialized yet."); + }; + + // Retrieve the last seen timestamp of this solution for this peer. + let last_seen = peer + .seen_outbound_solutions + .write() + .await + .entry(solution_commitment) + .or_insert(SystemTime::UNIX_EPOCH) + .elapsed() + .unwrap() + .as_secs(); + let is_ready_to_send = last_seen > Router::::RADIO_SILENCE_IN_SECS; + + // Update the timestamp for the peer and sent solution. + peer.seen_outbound_solutions.write().await.insert(solution_commitment, SystemTime::now()); + // Report the unconfirmed block height. + if is_ready_to_send { + trace!("Preparing to send 'UnconfirmedSolution {:?}' to {peer_ip}", solution_commitment); + } + + // Perform non-blocking serialization of the solution. + let serialized_solution = + Data::serialize(message.solution.clone()).await.expect("Solution serialization is bugged"); + let _ = std::mem::replace(&mut message.solution, Data::Buffer(serialized_solution)); + + is_ready_to_send + } + Message::UnconfirmedTransaction(ref mut message) => { + let transaction_id = if let Data::Object(transaction) = &message.transaction { + transaction.id() + } else { + panic!("Logic error: the transaction shouldn't have been serialized yet."); + }; + + // Retrieve the last seen timestamp of this transaction for this peer. + let last_seen = peer + .seen_outbound_transactions + .write() + .await + .entry(transaction_id) + .or_insert(SystemTime::UNIX_EPOCH) + .elapsed() + .unwrap() + .as_secs(); + let is_ready_to_send = last_seen > Router::::RADIO_SILENCE_IN_SECS; + + // Update the timestamp for the peer and sent transaction. + peer.seen_outbound_transactions.write().await.insert(transaction_id, SystemTime::now()); + // Report the unconfirmed block height. + if is_ready_to_send { + trace!("Preparing to send 'UnconfirmedTransaction {transaction_id}' to {peer_ip}"); + } + + // Perform non-blocking serialization of the transaction. + let serialized_transaction = + Data::serialize(message.transaction.clone()).await.expect("Transaction serialization is bugged"); + let _ = std::mem::replace(&mut message.transaction, Data::Buffer(serialized_transaction)); + + is_ready_to_send + } + _ => true, + }; + + // Send the message, if it is ready. + if is_ready_to_send { + trace!("Sending '{}' to {peer_ip}", message.name()); + // Route the message to the peer. + if let Err(error) = outbound_socket.send(message).await { + warn!("[OutboundRouter] {error}"); + } + } + } +} diff --git a/node/router/src/peer/mod.rs b/node/router/src/peer/mod.rs new file mode 100644 index 0000000000..b1e6c5efaa --- /dev/null +++ b/node/router/src/peer/mod.rs @@ -0,0 +1,141 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use crate::{Message, MessageCodec, Router, RouterRequest}; +use snarkos_node_executor::{Executor, NodeType, Status}; +use snarkvm::prelude::*; + +use anyhow::Result; +use std::{ + collections::HashMap, + net::SocketAddr, + sync::Arc, + time::{Instant, SystemTime}, +}; +use tokio::{ + net::TcpStream, + sync::{mpsc, mpsc::error::SendError, RwLock}, +}; +use tokio_util::codec::Framed; + +/// Shorthand for the parent half of the `Peer` outbound message channel. +pub(crate) type PeerSender = mpsc::Sender>; +/// Shorthand for the child half of the `Peer` outbound message channel. +pub(crate) type PeerHandler = mpsc::Receiver>; + +/// The state for each connected peer. +#[derive(Clone, Debug)] +pub struct Peer { + /// The IP address of the peer, with the port set to the listener port. + ip: Arc, + /// The message version of the peer. + pub version: Arc>, + /// The node type of the peer. + pub node_type: Arc>, + /// The node type of the peer. + pub status: Arc>, + /// The block height of the peer. + pub block_height: Arc>, + /// The timestamp of the last message received from this peer. + pub last_seen: Arc>, + /// The map of block hashes to their last seen timestamp. + pub seen_inbound_blocks: Arc>>, + /// The map of solution commitments to their last seen timestamp. + pub seen_inbound_solutions: Arc, SystemTime>>>, + /// The map of transaction IDs to their last seen timestamp. + pub seen_inbound_transactions: Arc>>, + /// The map of peers to a map of block hashes to their last seen timestamp. + pub seen_outbound_blocks: Arc>>, + /// The map of peers to a map of solution commitments to their last seen timestamp. + pub seen_outbound_solutions: Arc, SystemTime>>>, + /// The map of peers to a map of transaction IDs to their last seen timestamp. + pub seen_outbound_transactions: Arc>>, + /// The sender channel to the peer. + peer_sender: PeerSender, +} + +impl Peer { + /// Initializes a new instance of `Peer`. + pub async fn initialize( + ip: SocketAddr, + node_type: NodeType, + status: Status, + router: Router, + outbound_socket: Framed>, + ) -> Result { + // Initialize an MPSC channel for sending requests to the `Peer` struct. + let (peer_sender, peer_handler) = mpsc::channel(1024); + + // Construct the peer. + let peer = Peer { + ip: Arc::new(ip), + version: Arc::new(RwLock::new(0)), + node_type: Arc::new(RwLock::new(node_type)), + status: Arc::new(RwLock::new(status)), + block_height: Arc::new(RwLock::new(0)), + last_seen: Arc::new(RwLock::new(Instant::now())), + seen_inbound_blocks: Default::default(), + seen_inbound_solutions: Default::default(), + seen_inbound_transactions: Default::default(), + seen_outbound_blocks: Default::default(), + seen_outbound_solutions: Default::default(), + seen_outbound_transactions: Default::default(), + peer_sender, + }; + + // Add an entry for this `Peer` in the connected peers. + match router.process(RouterRequest::PeerConnected(peer.clone(), outbound_socket, peer_handler)).await { + // Return the peer. + Ok(_) => Ok(peer), + Err(error) => bail!("[PeerConnected] {error}"), + } + } + + /// Returns the IP address of the peer, with the port set to the listener port. + pub fn ip(&self) -> &SocketAddr { + &self.ip + } + + /// Returns the node type. + pub async fn node_type(&self) -> NodeType { + *self.node_type.read().await + } + + /// Returns `true` if the peer is a beacon. + pub async fn is_beacon(&self) -> bool { + self.node_type().await.is_beacon() + } + + /// Returns `true` if the peer is a validator. + pub async fn is_validator(&self) -> bool { + self.node_type().await.is_validator() + } + + /// Returns `true` if the peer is a prover. + pub async fn is_prover(&self) -> bool { + self.node_type().await.is_prover() + } + + /// Returns `true` if the peer is a client. + pub async fn is_client(&self) -> bool { + self.node_type().await.is_client() + } + + /// Sends the given message to this peer. + pub async fn send(&self, message: Message) -> Result<(), SendError>> { + self.peer_sender.send(message).await + } +} diff --git a/node/src/beacon/mod.rs b/node/src/beacon/mod.rs new file mode 100644 index 0000000000..637a015107 --- /dev/null +++ b/node/src/beacon/mod.rs @@ -0,0 +1,157 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +mod router; + +use crate::traits::NodeInterface; +use snarkos_account::Account; +use snarkos_node_executor::{spawn_task, Executor, NodeType, Status}; +use snarkos_node_ledger::Ledger; +use snarkos_node_router::{Handshake, Inbound, Outbound, Router}; +use snarkvm::prelude::{Address, Network, PrivateKey, ViewKey}; + +use anyhow::Result; +use std::{ + net::SocketAddr, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, +}; + +/// A beacon is a full node, capable of producing blocks. +#[derive(Clone)] +pub struct Beacon { + /// The account of the node. + account: Account, + /// The router of the node. + router: Router, + /// The ledger of the node. + ledger: Ledger, + /// The shutdown signal. + shutdown: Arc, +} + +impl Beacon { + /// Initializes a new beacon node. + pub async fn new( + node_ip: SocketAddr, + private_key: PrivateKey, + trusted_peers: &[SocketAddr], + dev: Option, + ) -> Result { + // Initialize the node account. + let account = Account::from(private_key)?; + // Initialize the node router. + let router = Router::new::(node_ip, *account.address(), NodeType::Beacon, trusted_peers).await?; + // Initialize the ledger. + let ledger = Ledger::::load(private_key, dev, router.clone())?; + // Initialize the node. + let node = Self { account, router, ledger, shutdown: Default::default() }; + + // Initialize the block production. + node.initialize_block_production().await; + + // Initialize the signal handler. + let _ = node.handle_signals(); + // Return the node. + Ok(node) + } + + /// Initialize a new instance of the heartbeat. + async fn initialize_block_production(&self) { + let beacon = self.clone(); + spawn_task!(Self, { + loop { + // Produce a transaction if the mempool is empty. + if beacon.ledger.ledger().read().memory_pool().len() == 0 { + // Create a transfer transaction. + let transaction = match beacon.ledger.create_transfer(beacon.address(), 1) { + Ok(transaction) => transaction, + Err(error) => { + error!("Failed to create a transfer transaction for the next block: {error}"); + continue; + } + }; + // Add the transaction to the memory pool. + if let Err(error) = beacon.ledger.ledger().write().add_to_memory_pool(transaction) { + error!("Failed to add a transfer transaction to the memory pool: {error}"); + continue; + } + } + + // Advance to the next block. + match beacon.ledger.advance_to_next_block().await { + Ok(next_block) => trace!( + "Block {}: {}", + next_block.height(), + serde_json::to_string_pretty(&next_block).expect("Failed to print next block") + ), + Err(error) => error!("Failed to advance to the next block: {error}"), + } + } + }); + } +} + +#[async_trait] +impl Executor for Beacon { + /// The node type. + const NODE_TYPE: NodeType = NodeType::Beacon; + + /// Disconnects from peers and shuts down the node. + async fn shut_down(&self) { + info!("Shutting down..."); + // Update the node status. + Self::status().update(Status::ShuttingDown); + + // Shut down the ledger. + trace!("Proceeding to shut down the ledger..."); + // self.state.ledger().shut_down().await; + self.shutdown.store(true, Ordering::Relaxed); + + // Flush the tasks. + Self::resources().shut_down(); + trace!("Node has shut down."); + } +} + +impl NodeInterface for Beacon { + /// Returns the node type. + fn node_type(&self) -> NodeType { + Self::NODE_TYPE + } + + /// Returns the node router. + fn router(&self) -> &Router { + &self.router + } + + /// Returns the account private key of the node. + fn private_key(&self) -> &PrivateKey { + self.account.private_key() + } + + /// Returns the account view key of the node. + fn view_key(&self) -> &ViewKey { + self.account.view_key() + } + + /// Returns the account address of the node. + fn address(&self) -> &Address { + self.account.address() + } +} diff --git a/environment/src/helpers/mod.rs b/node/src/beacon/router.rs similarity index 79% rename from environment/src/helpers/mod.rs rename to node/src/beacon/router.rs index 79b36f89d7..2e3c2a3d3e 100644 --- a/environment/src/helpers/mod.rs +++ b/node/src/beacon/router.rs @@ -14,14 +14,13 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . -pub mod block_locators; -pub use block_locators::*; +use super::*; -mod node_type; -pub use node_type::NodeType; +#[async_trait] +impl Handshake for Beacon {} -mod resources; -pub use resources::{Resource, Resources}; +#[async_trait] +impl Inbound for Beacon {} -mod status; -pub use status::{RawStatus, Status}; +#[async_trait] +impl Outbound for Beacon {} diff --git a/node/src/client/mod.rs b/node/src/client/mod.rs new file mode 100644 index 0000000000..393ca776fa --- /dev/null +++ b/node/src/client/mod.rs @@ -0,0 +1,89 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +mod router; + +use crate::traits::NodeInterface; +use snarkos_account::Account; +use snarkos_node_executor::{Executor, NodeType}; +use snarkos_node_router::{Handshake, Inbound, Outbound, Router}; +use snarkvm::prelude::{Address, Network, PrivateKey, ViewKey}; + +use anyhow::Result; +use std::net::SocketAddr; + +/// A client node is a full node, capable of querying with the network. +#[derive(Clone)] +pub struct Client { + /// The account of the node. + account: Account, + /// The router of the node. + router: Router, +} + +impl Client { + /// Initializes a new client node. + pub async fn new( + node_ip: SocketAddr, + private_key: PrivateKey, + trusted_peers: &[SocketAddr], + dev: Option, + ) -> Result { + // Initialize the node account. + let account = Account::from(private_key)?; + // Initialize the node router. + let router = Router::new::(node_ip, *account.address(), NodeType::Client, trusted_peers).await?; + // Initialize the node. + let node = Self { account, router }; + // Initialize the signal handler. + let _ = node.handle_signals(); + // Return the node. + Ok(node) + } +} + +#[async_trait] +impl Executor for Client { + /// The node type. + const NODE_TYPE: NodeType = NodeType::Client; +} + +impl NodeInterface for Client { + /// Returns the node type. + fn node_type(&self) -> NodeType { + Self::NODE_TYPE + } + + /// Returns the node router. + fn router(&self) -> &Router { + &self.router + } + + /// Returns the account private key of the node. + fn private_key(&self) -> &PrivateKey { + self.account.private_key() + } + + /// Returns the account view key of the node. + fn view_key(&self) -> &ViewKey { + self.account.view_key() + } + + /// Returns the account address of the node. + fn address(&self) -> &Address { + self.account.address() + } +} diff --git a/node/src/client/router.rs b/node/src/client/router.rs new file mode 100644 index 0000000000..36c57ac1fa --- /dev/null +++ b/node/src/client/router.rs @@ -0,0 +1,26 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[async_trait] +impl Handshake for Client {} + +#[async_trait] +impl Inbound for Client {} + +#[async_trait] +impl Outbound for Client {} diff --git a/node/src/lib.rs b/node/src/lib.rs new file mode 100644 index 0000000000..0ed6ecd170 --- /dev/null +++ b/node/src/lib.rs @@ -0,0 +1,136 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +#![forbid(unsafe_code)] + +#[macro_use] +extern crate async_trait; +#[macro_use] +extern crate tracing; + +mod beacon; +pub use beacon::*; + +mod client; +pub use client::*; + +mod prover; +pub use prover::*; + +mod validator; +pub use validator::*; + +mod traits; +pub use traits::*; + +use snarkos_node_executor::NodeType; +use snarkvm::prelude::{Address, Network, PrivateKey, ViewKey}; + +use anyhow::Result; +use std::{net::SocketAddr, sync::Arc}; + +pub enum Node { + /// A beacon is a full node, capable of producing blocks. + Beacon(Arc>), + /// A validator is a full node, capable of validating blocks. + Validator(Arc>), + /// A prover is a full node, capable of producing proofs for consensus. + Prover(Arc>), + /// A client node is a full node, capable of querying with the network. + Client(Arc>), +} + +impl Node { + /// Initializes a new beacon node. + pub async fn new_beacon( + node_ip: SocketAddr, + private_key: PrivateKey, + trusted_peers: &[SocketAddr], + dev: Option, + ) -> Result { + Ok(Self::Beacon(Arc::new(Beacon::new(node_ip, private_key, trusted_peers, dev).await?))) + } + + /// Initializes a new validator node. + pub async fn new_validator( + node_ip: SocketAddr, + private_key: PrivateKey, + trusted_peers: &[SocketAddr], + dev: Option, + ) -> Result { + Ok(Self::Validator(Arc::new(Validator::new(node_ip, private_key, trusted_peers, dev).await?))) + } + + /// Initializes a new prover node. + pub async fn new_prover( + node_ip: SocketAddr, + private_key: PrivateKey, + trusted_peers: &[SocketAddr], + dev: Option, + ) -> Result { + Ok(Self::Prover(Arc::new(Prover::new(node_ip, private_key, trusted_peers, dev).await?))) + } + + /// Initializes a new client node. + pub async fn new_client( + node_ip: SocketAddr, + private_key: PrivateKey, + trusted_peers: &[SocketAddr], + dev: Option, + ) -> Result { + Ok(Self::Client(Arc::new(Client::new(node_ip, private_key, trusted_peers, dev).await?))) + } + + /// Returns the node type. + pub fn node_type(&self) -> NodeType { + match self { + Self::Beacon(beacon) => beacon.node_type(), + Self::Validator(validator) => validator.node_type(), + Self::Prover(prover) => prover.node_type(), + Self::Client(client) => client.node_type(), + } + } + + /// Returns the account private key of the node. + pub fn private_key(&self) -> &PrivateKey { + match self { + Self::Beacon(node) => node.private_key(), + Self::Validator(node) => node.private_key(), + Self::Prover(node) => node.private_key(), + Self::Client(node) => node.private_key(), + } + } + + /// Returns the account view key of the node. + pub fn view_key(&self) -> &ViewKey { + match self { + Self::Beacon(node) => node.view_key(), + Self::Validator(node) => node.view_key(), + Self::Prover(node) => node.view_key(), + Self::Client(node) => node.view_key(), + } + } + + /// Returns the account address of the node. + pub fn address(&self) -> &Address { + match self { + Self::Beacon(node) => node.address(), + Self::Validator(node) => node.address(), + Self::Prover(node) => node.address(), + Self::Client(node) => node.address(), + } + } +} diff --git a/node/src/prover/mod.rs b/node/src/prover/mod.rs new file mode 100644 index 0000000000..60120e2b4e --- /dev/null +++ b/node/src/prover/mod.rs @@ -0,0 +1,89 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +mod router; + +use crate::traits::NodeInterface; +use snarkos_account::Account; +use snarkos_node_executor::{Executor, NodeType}; +use snarkos_node_router::{Handshake, Inbound, Outbound, Router}; +use snarkvm::prelude::{Address, Network, PrivateKey, ViewKey}; + +use anyhow::Result; +use std::net::SocketAddr; + +/// A prover is a full node, capable of producing proofs for consensus. +#[derive(Clone)] +pub struct Prover { + /// The account of the node. + account: Account, + /// The router of the node. + router: Router, +} + +impl Prover { + /// Initializes a new prover node. + pub async fn new( + node_ip: SocketAddr, + private_key: PrivateKey, + trusted_peers: &[SocketAddr], + dev: Option, + ) -> Result { + // Initialize the node account. + let account = Account::from(private_key)?; + // Initialize the node router. + let router = Router::new::(node_ip, *account.address(), NodeType::Prover, trusted_peers).await?; + // Initialize the node. + let node = Self { account, router }; + // Initialize the signal handler. + let _ = node.handle_signals(); + // Return the node. + Ok(node) + } +} + +#[async_trait] +impl Executor for Prover { + /// The node type. + const NODE_TYPE: NodeType = NodeType::Prover; +} + +impl NodeInterface for Prover { + /// Returns the node type. + fn node_type(&self) -> NodeType { + Self::NODE_TYPE + } + + /// Returns the node router. + fn router(&self) -> &Router { + &self.router + } + + /// Returns the account private key of the node. + fn private_key(&self) -> &PrivateKey { + self.account.private_key() + } + + /// Returns the account view key of the node. + fn view_key(&self) -> &ViewKey { + self.account.view_key() + } + + /// Returns the account address of the node. + fn address(&self) -> &Address { + self.account.address() + } +} diff --git a/node/src/prover/router.rs b/node/src/prover/router.rs new file mode 100644 index 0000000000..9b1e86ffd5 --- /dev/null +++ b/node/src/prover/router.rs @@ -0,0 +1,26 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[async_trait] +impl Handshake for Prover {} + +#[async_trait] +impl Inbound for Prover {} + +#[async_trait] +impl Outbound for Prover {} diff --git a/node/src/traits.rs b/node/src/traits.rs new file mode 100644 index 0000000000..fef743d5d0 --- /dev/null +++ b/node/src/traits.rs @@ -0,0 +1,36 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use snarkos_node_executor::{Executor, NodeType}; +use snarkos_node_router::Router; +use snarkvm::prelude::{Address, Network, PrivateKey, ViewKey}; + +pub trait NodeInterface: Executor { + /// Returns the node type. + fn node_type(&self) -> NodeType; + + /// Returns the node router. + fn router(&self) -> &Router; + + /// Returns the account private key of the node. + fn private_key(&self) -> &PrivateKey; + + /// Returns the account view key of the node. + fn view_key(&self) -> &ViewKey; + + /// Returns the account address of the node. + fn address(&self) -> &Address; +} diff --git a/node/src/validator/mod.rs b/node/src/validator/mod.rs new file mode 100644 index 0000000000..865ff96a50 --- /dev/null +++ b/node/src/validator/mod.rs @@ -0,0 +1,109 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +mod router; + +use crate::traits::NodeInterface; +use snarkos_account::Account; +use snarkos_node_executor::{Executor, NodeType, Status}; +use snarkos_node_ledger::Ledger; +use snarkos_node_router::{Handshake, Inbound, Outbound, Router}; +use snarkvm::prelude::{Address, Network, PrivateKey, ViewKey}; + +use anyhow::Result; +use std::net::SocketAddr; + +/// A validator is a full node, capable of validating blocks. +#[derive(Clone)] +pub struct Validator { + /// The account of the node. + account: Account, + /// The router of the node. + router: Router, + /// The ledger of the node. + ledger: Ledger, +} + +impl Validator { + /// Initializes a new validator node. + pub async fn new( + node_ip: SocketAddr, + private_key: PrivateKey, + trusted_peers: &[SocketAddr], + dev: Option, + ) -> Result { + // Initialize the node account. + let account = Account::from(private_key)?; + // Initialize the node router. + let router = Router::new::(node_ip, *account.address(), NodeType::Validator, trusted_peers).await?; + // Initialize the ledger. + let ledger = Ledger::::load(private_key, dev, router.clone())?; + // Initialize the node. + let node = Self { account, router, ledger }; + // Initialize the signal handler. + let _ = node.handle_signals(); + // Return the node. + Ok(node) + } +} + +#[async_trait] +impl Executor for Validator { + /// The node type. + const NODE_TYPE: NodeType = NodeType::Validator; + + /// Disconnects from peers and shuts down the node. + async fn shut_down(&self) { + info!("Shutting down..."); + // Update the node status. + Self::status().update(Status::ShuttingDown); + + // Shut down the ledger. + trace!("Proceeding to shut down the ledger..."); + // self.state.ledger().shut_down().await; + + // Flush the tasks. + Self::resources().shut_down(); + trace!("Node has shut down."); + } +} + +impl NodeInterface for Validator { + /// Returns the node type. + fn node_type(&self) -> NodeType { + Self::NODE_TYPE + } + + /// Returns the node router. + fn router(&self) -> &Router { + &self.router + } + + /// Returns the account private key of the node. + fn private_key(&self) -> &PrivateKey { + self.account.private_key() + } + + /// Returns the account view key of the node. + fn view_key(&self) -> &ViewKey { + self.account.view_key() + } + + /// Returns the account address of the node. + fn address(&self) -> &Address { + self.account.address() + } +} diff --git a/node/src/validator/router.rs b/node/src/validator/router.rs new file mode 100644 index 0000000000..9270508396 --- /dev/null +++ b/node/src/validator/router.rs @@ -0,0 +1,26 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the snarkOS library. + +// The snarkOS library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The snarkOS library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the snarkOS library. If not, see . + +use super::*; + +#[async_trait] +impl Handshake for Validator {} + +#[async_trait] +impl Inbound for Validator {} + +#[async_trait] +impl Outbound for Validator {} diff --git a/node/store/Cargo.toml b/node/store/Cargo.toml new file mode 100644 index 0000000000..9ab60e38eb --- /dev/null +++ b/node/store/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "snarkos-node-store" +version = "2.0.2" +authors = [ "The Aleo Team " ] +description = "A node storage for a decentralized operating system" +homepage = "https://aleo.org" +repository = "https://github.com/AleoHQ/snarkOS" +keywords = [ + "aleo", + "cryptography", + "blockchain", + "decentralized", + "zero-knowledge" +] +categories = [ "cryptography", "operating-systems" ] +license = "GPL-3.0" +edition = "2021" + +[dependencies.aleo-std] +version = "0.1.15" + +[dependencies.anyhow] +version = "1" + +[dependencies.bincode] +version = "1.0" + +[dependencies.indexmap] +version = "1.9" + +[dependencies.once_cell] +version = "1.15" + +[dependencies.parking_lot] +version = "0.12" + +[dependencies.rocksdb] +version = "0.19" +default-features = false +features = [ "lz4" ] + +[dependencies.serde] +version = "1" + +[dependencies.snarkvm] +workspace = true + +[dependencies.tracing] +version = "0.1" + +[dev-dependencies.serial_test] +version = "0.9.0" + +[dev-dependencies.tempfile] +version = "3.2" diff --git a/node/store/LICENSE.md b/node/store/LICENSE.md new file mode 100644 index 0000000000..b95c626e2a --- /dev/null +++ b/node/store/LICENSE.md @@ -0,0 +1,596 @@ +GNU General Public License +========================== + +Version 3, 29 June 2007 + +Copyright Β© 2007 Free Software Foundation, Inc. <> + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: **(1)** assert +copyright on the software, and **(2)** offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions + +β€œThis License” refers to version 3 of the GNU General Public License. + +β€œCopyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +β€œThe Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as β€œyou”. β€œLicensees” and +β€œrecipients” may be individuals or organizations. + +To β€œmodify” a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a β€œmodified version” of the earlier work or a +work β€œbased on” the earlier work. + +A β€œcovered work” means either the unmodified Program or a work based on +the Program. + +To β€œpropagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To β€œconvey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays β€œAppropriate Legal Notices” to the +extent that it includes a convenient and prominently visible feature that **(1)** +displays an appropriate copyright notice, and **(2)** tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code + +The β€œsource code” for a work means the preferred form of the work for +making modifications to it. β€œObject code” means any non-source form of a +work. + +A β€œStandard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The β€œSystem Libraries” of an executable work include anything, other than +the work as a whole, that **(a)** is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and **(b)** serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A β€œMajor Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The β€œCorresponding Source” for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to β€œkeep intact all notices”. +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an β€œaggregate” if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either **(1)** a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or **(2)** access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A β€œUser Product” is either **(1)** a β€œconsumer product”, which +means any tangible personal property which is normally used for personal, family, or +household purposes, or **(2)** anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, β€œnormally used” refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +β€œInstallation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms + +β€œAdditional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered β€œfurther +restrictions” within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated **(a)** provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and **(b)** permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An β€œentity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents + +A β€œcontributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's β€œcontributor version”. + +A contributor's β€œessential patent claims” are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, β€œcontrol” includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a β€œpatent license” is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To β€œgrant” such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either **(1)** cause the Corresponding +Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the +patent license for this particular work, or **(3)** arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. β€œKnowingly relying” means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is β€œdiscriminatory” if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license **(a)** in connection with +copies of the covered work conveyed by you (or copies made from those copies), or **(b)** +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License β€œor any later +version” applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM β€œAS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16 + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +_END OF TERMS AND CONDITIONS_ + +## How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to +the public, the best way to achieve this is to make it free software which everyone +can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them +to the start of each source file to most effectively state the exclusion of warranty; +and each file should have at least the β€œcopyright” line and a pointer to +where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like this +when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type 'show c' for details. + +The hypothetical commands `show w` and `show c` should show the appropriate parts of +the General Public License. Of course, your program's commands might be different; +for a GUI interface, you would use an β€œabout box”. + +You should also get your employer (if you work as a programmer) or school, if any, to +sign a β€œcopyright disclaimer” for the program, if necessary. For more +information on this, and how to apply and follow the GNU GPL, see +<>. + +The GNU General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may consider it +more useful to permit linking proprietary applications with the library. If this is +what you want to do, use the GNU Lesser General Public License instead of this +License. But first, please read +<>. diff --git a/node/store/README.md b/node/store/README.md new file mode 100644 index 0000000000..e7cc77ab72 --- /dev/null +++ b/node/store/README.md @@ -0,0 +1,7 @@ +# snarkos-node-store + +[![Crates.io](https://img.shields.io/crates/v/snarkos-node-store.svg?color=neon)](https://crates.io/crates/snarkos-node-store) +[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](https://aleo.org) +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md) + +The `snarkos-node-store` crate provides a persistent storage layer for the `snarkos` node. diff --git a/snarkos/store/block.rs b/node/store/src/block.rs similarity index 90% rename from snarkos/store/block.rs rename to node/store/src/block.rs index 18d59c1324..3dfc78c5b2 100644 --- a/snarkos/store/block.rs +++ b/node/store/src/block.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . -use crate::store::{ +use crate::{ rocksdb::{self, DataMap, Database}, DataID, TransactionDB, @@ -37,6 +37,8 @@ pub struct BlockDB { reverse_transactions_map: DataMap, /// The transaction store. transaction_store: TransactionStore>, + /// The coinbase solution map. + coinbase_proof_map: DataMap>>, /// The signature map. signature_map: DataMap>, } @@ -50,6 +52,7 @@ impl BlockStorage for BlockDB { type ReverseTransactionsMap = DataMap; type TransactionStorage = TransactionDB; type TransitionStorage = TransitionDB; + type CoinbaseProofMap = DataMap>>; type SignatureMap = DataMap>; /// Initializes the block storage. @@ -66,6 +69,7 @@ impl BlockStorage for BlockDB { transactions_map: rocksdb::RocksDB::open_map(N::ID, dev, DataID::BlockTransactionsMap)?, reverse_transactions_map: rocksdb::RocksDB::open_map(N::ID, dev, DataID::BlockReverseTransactionsMap)?, transaction_store, + coinbase_proof_map: rocksdb::RocksDB::open_map(N::ID, dev, DataID::BlockCoinbaseProofMap)?, signature_map: rocksdb::RocksDB::open_map(N::ID, dev, DataID::BlockSignatureMap)?, }) } @@ -100,6 +104,11 @@ impl BlockStorage for BlockDB { &self.transaction_store } + /// Returns the coinbase proof map. + fn coinbase_proof_map(&self) -> &Self::CoinbaseProofMap { + &self.coinbase_proof_map + } + /// Returns the signature map. fn signature_map(&self) -> &Self::SignatureMap { &self.signature_map diff --git a/snarkos/store/mod.rs b/node/store/src/lib.rs similarity index 96% rename from snarkos/store/mod.rs rename to node/store/src/lib.rs index 45a443b704..8f67fc5c27 100644 --- a/snarkos/store/mod.rs +++ b/node/store/src/lib.rs @@ -14,6 +14,11 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . +#![forbid(unsafe_code)] + +#[macro_use] +extern crate tracing; + pub mod rocksdb; mod block; @@ -37,6 +42,7 @@ pub enum DataID { BlockHeaderMap, BlockTransactionsMap, BlockReverseTransactionsMap, + BlockCoinbaseProofMap, BlockSignatureMap, // Deployment DeploymentIDMap, diff --git a/snarkos/store/program.rs b/node/store/src/program.rs similarity index 99% rename from snarkos/store/program.rs rename to node/store/src/program.rs index c9e5e02f07..b219710338 100644 --- a/snarkos/store/program.rs +++ b/node/store/src/program.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . -use crate::store::{ +use crate::{ rocksdb::{self, DataMap, Database}, DataID, }; diff --git a/snarkos/store/rocksdb/iterator.rs b/node/store/src/rocksdb/iterator.rs similarity index 89% rename from snarkos/store/rocksdb/iterator.rs rename to node/store/src/rocksdb/iterator.rs index 70d2b74c94..0e9ed6ab3b 100644 --- a/snarkos/store/rocksdb/iterator.rs +++ b/node/store/src/rocksdb/iterator.rs @@ -28,14 +28,14 @@ pub struct Iter< _phantom: PhantomData<(K, V)>, } -impl<'a, K: 'a + Debug + PartialEq + Eq + Hash + Serialize + DeserializeOwned, V: 'a + PartialEq + Eq + Serialize + DeserializeOwned> - Iter<'a, K, V> +impl< + 'a, + K: 'a + Debug + PartialEq + Eq + Hash + Serialize + DeserializeOwned, + V: 'a + PartialEq + Eq + Serialize + DeserializeOwned, +> Iter<'a, K, V> { pub(super) fn new(db_iter: rocksdb::DBIterator<'a>) -> Self { - Self { - db_iter, - _phantom: PhantomData, - } + Self { db_iter, _phantom: PhantomData } } } @@ -70,10 +70,7 @@ pub struct Keys<'a, K: 'a + Debug + PartialEq + Eq + Hash + Serialize + Deserial impl<'a, K: 'a + Debug + PartialEq + Eq + Hash + Serialize + DeserializeOwned> Keys<'a, K> { pub(crate) fn new(db_iter: rocksdb::DBIterator<'a>) -> Self { - Self { - db_iter, - _phantom: PhantomData, - } + Self { db_iter, _phantom: PhantomData } } } @@ -102,10 +99,7 @@ pub struct Values<'a, V: 'a + PartialEq + Eq + Serialize + DeserializeOwned> { impl<'a, V: 'a + PartialEq + Eq + Serialize + DeserializeOwned> Values<'a, V> { pub(crate) fn new(db_iter: rocksdb::DBIterator<'a>) -> Self { - Self { - db_iter, - _phantom: PhantomData, - } + Self { db_iter, _phantom: PhantomData } } } diff --git a/snarkos/store/rocksdb/map.rs b/node/store/src/rocksdb/map.rs similarity index 100% rename from snarkos/store/rocksdb/map.rs rename to node/store/src/rocksdb/map.rs diff --git a/snarkos/store/rocksdb/mod.rs b/node/store/src/rocksdb/mod.rs similarity index 97% rename from snarkos/store/rocksdb/mod.rs rename to node/store/src/rocksdb/mod.rs index 463c6cc47d..5d8303b9b1 100644 --- a/snarkos/store/rocksdb/mod.rs +++ b/node/store/src/rocksdb/mod.rs @@ -23,7 +23,7 @@ use iterator::*; #[cfg(test)] mod tests; -use crate::store::DataID; +use crate::DataID; use anyhow::{bail, Result}; use core::{fmt::Debug, hash::Hash}; @@ -133,11 +133,7 @@ impl Database for RocksDB { context.extend_from_slice(&(data_id as u16).to_le_bytes()); // Return the DataMap. - Ok(DataMap { - database, - context, - _phantom: PhantomData, - }) + Ok(DataMap { database, context, _phantom: PhantomData }) } } @@ -202,11 +198,7 @@ impl RocksDB { context.extend_from_slice(&(data_id as u16).to_le_bytes()); // Return the DataMap. - Ok(DataMap { - database, - context, - _phantom: PhantomData, - }) + Ok(DataMap { database, context, _phantom: PhantomData }) } } diff --git a/snarkos/store/rocksdb/tests.rs b/node/store/src/rocksdb/tests.rs similarity index 88% rename from snarkos/store/rocksdb/tests.rs rename to node/store/src/rocksdb/tests.rs index ebbaa63adf..f0f62c6ff2 100644 --- a/snarkos/store/rocksdb/tests.rs +++ b/node/store/src/rocksdb/tests.rs @@ -14,17 +14,14 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . -use crate::store::{ +use crate::{ rocksdb::{DataMap, RocksDB}, DataID, }; use snarkvm::{ compiler::{Map, MapRead}, - console::{ - network::{Network, Testnet3}, - types::Scalar, - }, - utilities::{TestRng, Uniform}, + console::{network::Testnet3, types::Scalar}, + prelude::{Network, TestRng, Uniform}, }; use serial_test::serial; @@ -37,10 +34,7 @@ pub(crate) fn temp_dir() -> std::path::PathBuf { } pub(crate) fn temp_file() -> std::path::PathBuf { - tempfile::NamedTempFile::new() - .expect("Failed to open temporary file") - .path() - .to_owned() + tempfile::NamedTempFile::new().expect("Failed to open temporary file").path().to_owned() } #[test] @@ -52,7 +46,8 @@ fn test_open() { #[test] #[serial] fn test_open_map() { - let _map = RocksDB::open_map_testing::(temp_dir(), None, DataID::Test).expect("Failed to open data map"); + let _map = + RocksDB::open_map_testing::(temp_dir(), None, DataID::Test).expect("Failed to open data map"); } #[test] @@ -71,10 +66,7 @@ fn test_insert_and_get() { let map = RocksDB::open_map_testing(temp_dir(), None, DataID::Test).expect("Failed to open data map"); map.insert(123456789, "123456789".to_string()).expect("Failed to insert"); - assert_eq!( - Some("123456789".to_string()), - map.get(&123456789).expect("Failed to get").map(|v| v.to_string()) - ); + assert_eq!(Some("123456789".to_string()), map.get(&123456789).expect("Failed to get").map(|v| v.to_string())); assert_eq!(None, map.get(&000000000).expect("Failed to get")); } @@ -85,10 +77,7 @@ fn test_insert_and_remove() { let map = RocksDB::open_map_testing(temp_dir(), None, DataID::Test).expect("Failed to open data map"); map.insert(123456789, "123456789".to_string()).expect("Failed to insert"); - assert_eq!( - map.get(&123456789).expect("Failed to get").map(|v| v.to_string()), - Some("123456789".to_string()) - ); + assert_eq!(map.get(&123456789).expect("Failed to get").map(|v| v.to_string()), Some("123456789".to_string())); map.remove(&123456789).expect("Failed to remove"); assert!(map.get(&123456789).expect("Failed to get").is_none()); @@ -102,10 +91,7 @@ fn test_insert_and_iter() { map.insert(123456789, "123456789".to_string()).expect("Failed to insert"); let mut iter = map.iter(); - assert_eq!( - Some((123456789, "123456789".to_string())), - iter.next().map(|(k, v)| (*k, v.to_string())) - ); + assert_eq!(Some((123456789, "123456789".to_string())), iter.next().map(|(k, v)| (*k, v.to_string()))); assert_eq!(None, iter.next()); } diff --git a/snarkos/store/transaction.rs b/node/store/src/transaction.rs similarity index 99% rename from snarkos/store/transaction.rs rename to node/store/src/transaction.rs index 534ebbfbdf..72b1e2307d 100644 --- a/snarkos/store/transaction.rs +++ b/node/store/src/transaction.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . -use crate::store::{ +use crate::{ rocksdb::{self, DataMap, Database}, DataID, TransitionDB, diff --git a/snarkos/store/transition.rs b/node/store/src/transition.rs similarity index 99% rename from snarkos/store/transition.rs rename to node/store/src/transition.rs index 40c3be0662..ee6bfd85b9 100644 --- a/snarkos/store/transition.rs +++ b/node/store/src/transition.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . -use crate::store::{ +use crate::{ rocksdb::{self, DataMap, Database}, DataID, }; diff --git a/run-client.sh b/run-client.sh deleted file mode 100755 index 3260441740..0000000000 --- a/run-client.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -# USAGE examples: - # CLI : ./run-client.sh - -COMMAND='cargo run --release -- --verbosity 2' - -for word in $*; -do - COMMAND="${COMMAND} ${word}" -done - -function exit_node() -{ - echo "Exiting..." - kill $! - exit -} - -trap exit_node SIGINT - -echo "Running client node..." -$COMMAND & - -while : -do - echo "Checking for updates..." - git stash - rm Cargo.lock - STATUS=$(git pull) - - if [ "$STATUS" != "Already up to date." ]; then - echo "Updated code found, rebuilding and relaunching client node" - cargo clean - kill -INT $!; sleep 2; $COMMAND & - fi - - sleep 1800 - -done diff --git a/snarkos/cli.rs b/snarkos/cli.rs deleted file mode 100644 index fb473d4f37..0000000000 --- a/snarkos/cli.rs +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright (C) 2019-2022 Aleo Systems Inc. -// This file is part of the snarkOS library. - -// The snarkOS library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The snarkOS library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the snarkOS library. If not, see . - -use crate::{Account, Node, Updater}; -use snarkos_environment::{helpers::NodeType, Client, Environment}; -use snarkvm::prelude::{Address, Network, PrivateKey, ViewKey}; - -use anyhow::{bail, ensure, Result}; -use clap::Parser; -use colored::*; -use std::{fmt::Write, net::SocketAddr, str::FromStr}; - -#[derive(Debug, Parser)] -#[clap(name = "snarkos", author = "The Aleo Team ")] -pub struct CLI { - /// Specify the network of this node. - #[clap(default_value = "3", long = "network")] - pub network: u16, - /// Specify the account private key of this node. - #[clap(long = "private_key")] - pub private_key: Option, - /// Specify this as a prover node, with the given prover address. - #[clap(long = "prover")] - pub prover: Option, - /// Specify this as a validator node, with the given validator address. - #[clap(long = "validator")] - pub validator: Option, - #[clap(hide = true, long)] - pub beacon: bool, - - /// Specify the IP address and port for the node server. - #[clap(default_value = "0.0.0.0:4133", long = "node")] - pub node: SocketAddr, - /// Specify the IP address and port of a beacon node to connect to. - #[clap(hide = true, default_value = "159.203.77.113:4130", long = "connect_to_beacon")] - pub beacon_addr: SocketAddr, - /// Specify the IP address and port of a peer to connect to. - #[clap(long = "connect")] - pub connect: Option, - - /// Specify the IP address and port for the RPC server. - #[clap(default_value = "0.0.0.0:3033", long = "rpc")] - pub rpc: SocketAddr, - /// Specify the username for the RPC server. - #[clap(default_value = "root", long = "username")] - pub rpc_username: String, - /// Specify the password for the RPC server. - #[clap(default_value = "pass", long = "password")] - pub rpc_password: String, - /// If the flag is set, the node will not initialize the RPC server. - #[clap(long)] - pub norpc: bool, - - /// Specify the verbosity of the node [options: 0, 1, 2, 3] - #[clap(default_value = "2", long = "verbosity")] - pub verbosity: u8, - /// Enables development mode, specify a unique ID for the local node. - #[clap(long)] - pub dev: Option, - - /// Specify an optional subcommand. - #[clap(subcommand)] - commands: Option, -} - -impl CLI { - /// Starts the node. - pub async fn start(self) -> Result<()> { - // A type for Aleo Testnet3. - pub type Testnet3 = snarkvm::prelude::Testnet3; - - // Parse optional subcommands first. - match self.commands { - Some(command) => { - println!("{}", command.parse()?); - Ok(()) - } - None => match (self.network, self.node_type()?) { - (3, NodeType::Client) => self.start_node::>(&None).await, - (3, NodeType::Prover) => bail!("Provers will be available in Phase 2"), - (3, NodeType::Validator) => bail!("Validators will be available in Phase 3"), - (3, NodeType::Beacon) => bail!("Beacons will be available in Phase 3"), - _ => bail!("Unsupported network"), - }, - } - } - - /// Returns the node type corresponding to the given CLI configurations. - pub fn node_type(&self) -> Result { - match (&self.prover, &self.validator, self.beacon) { - (None, None, false) => Ok(NodeType::Client), - (Some(_), None, false) => Ok(NodeType::Prover), - (None, Some(_), false) => Ok(NodeType::Validator), - (None, None, true) => Ok(NodeType::Beacon), - _ => bail!("Unsupported node type"), - } - } - - /// Starts the node server. - async fn start_node(&self, address: &Option) -> Result<()> { - // Construct the Aleo account. - let account = match (&self.private_key, address) { - (Some(private_key), Some(address)) => { - // Construct the account from the private key string. - let account = Account::from_str(private_key)?; - // Ensure the account address matches the declared address. - ensure!( - account.address() == &Address::from_str(address)?, - "Mismatching private key and address" - ); - // Return the account. - account - } - // Construct the account from the private key string. - (Some(private_key), None) => Account::from_str(private_key)?, - // Throw an error, if no private key is provided but an address is given. - (None, Some(address)) => { - bail!("Missing a private key (use '--private_key {{PRIVATE_KEY}}') for address {address}") - } - // Sample a new account. - (None, None) => Account::sample()?, - }; - - // Print the welcome. - println!("{}", crate::logger::welcome_message()); - // Print the Aleo address. - println!("Your Aleo address is {}.\n", account.address()); - // Print the node type and network. - println!("Starting {} on {}.\n", E::NODE_TYPE.description(), N::NAME); - - // Initialize the node. - let node = Node::::new(self, account).await?; - - // Initialize signal handling and maintain ownership of the node - to keep it in scope. - Self::handle_signals(node.clone()); - - // Connect to peer(s) if given as an argument. - if let Some(peer_ips) = &self.connect { - // Separate the IP addresses. - for peer_ip in peer_ips.split(',') { - // Parse each IP address. - node.connect_to(match peer_ip.parse() { - Ok(ip) => ip, - Err(e) => { - error!("The IP supplied to --connect ('{peer_ip}') is malformed: {e}"); - continue; - } - }) - .await?; - } - } - - // Note: Do not move this. The pending await must be here otherwise - // other snarkOS commands will not exit. - std::future::pending::<()>().await; - - Ok(()) - } - - /// Handles OS signals for the node to intercept and perform a clean shutdown. - /// Note: Only Ctrl-C is supported; it should work on both Unix-family systems and Windows. - pub fn handle_signals(node: Node) { - E::resources().register_task( - None, // No need to provide an id, as the task will run indefinitely. - tokio::task::spawn(async move { - match tokio::signal::ctrl_c().await { - Ok(()) => { - node.shut_down().await; - std::process::exit(0); - } - Err(error) => error!("tokio::signal::ctrl_c encountered an error: {}", error), - } - }), - ); - } -} - -#[derive(Debug, Parser)] -pub enum Command { - #[clap(name = "clean", about = "Removes the ledger files from storage")] - Clean(Clean), - #[clap(name = "update", about = "Updates snarkOS to the latest version")] - Update(Update), - #[clap(name = "experimental", about = "Experimental features")] - Experimental(Experimental), -} - -impl Command { - pub fn parse(self) -> Result { - match self { - Self::Clean(command) => command.parse(), - Self::Update(command) => command.parse(), - Self::Experimental(command) => command.parse(), - } - } -} - -#[derive(Debug, Parser)] -pub struct Clean { - /// Specify the network of the ledger to remove from storage. - #[clap(default_value = "3", long = "network")] - pub network: u16, - /// Enables development mode, specify the unique ID of the local node to clean. - #[clap(long)] - pub dev: Option, -} - -impl Clean { - pub fn parse(self) -> Result { - // Remove the specified ledger from storage. - Self::remove_ledger(self.network, self.dev) - } - - /// Removes the specified ledger from storage. - fn remove_ledger(network: u16, dev: Option) -> Result { - // Construct the path to the ledger in storage. - let path = aleo_std::aleo_ledger_dir(network, dev); - // Check if the path to the ledger exists in storage. - if path.exists() { - // Remove the ledger files from storage. - match std::fs::remove_dir_all(&path) { - Ok(_) => Ok(format!("Successfully removed the ledger files from storage. ({})", path.display())), - Err(error) => bail!("Failed to remove the ledger files from storage. ({})\n{}", path.display(), error), - } - } else { - Ok(format!("No ledger files were found in storage. ({})", path.display())) - } - } -} - -#[derive(Debug, Parser)] -pub struct Update { - /// Lists all available versions of snarkOS - #[clap(short = 'l', long)] - list: bool, - /// Suppress outputs to terminal - #[clap(short = 'q', long)] - quiet: bool, - /// Update to specified version - #[clap(short = 'v', long)] - version: Option, -} - -impl Update { - pub fn parse(self) -> Result { - match self.list { - true => match Updater::show_available_releases() { - Ok(output) => Ok(output), - Err(error) => Ok(format!("Failed to list the available versions of snarkOS\n{}\n", error)), - }, - false => { - let result = Updater::update_to_release(!self.quiet, self.version); - if !self.quiet { - match result { - Ok(status) => { - if status.uptodate() { - Ok("\nsnarkOS is already on the latest version".to_string()) - } else if status.updated() { - Ok(format!("\nsnarkOS has updated to version {}", status.version())) - } else { - Ok(String::new()) - } - } - Err(e) => Ok(format!("\nFailed to update snarkOS to the latest version\n{}\n", e)), - } - } else { - Ok(String::new()) - } - } - } - } -} - -#[derive(Debug, Parser)] -pub struct Experimental { - #[clap(subcommand)] - commands: ExperimentalCommands, -} - -impl Experimental { - pub fn parse(self) -> Result { - match self.commands { - ExperimentalCommands::NewAccount(command) => command.parse(), - } - } -} - -#[derive(Debug, Parser)] -pub enum ExperimentalCommands { - #[clap(name = "new_account", about = "Generate a new Aleo account.")] - NewAccount(NewAccount), -} - -#[derive(Debug, Parser)] -pub struct NewAccount {} - -impl NewAccount { - pub fn parse(self) -> Result { - // Sample a new private key, view key, and address. - let private_key = PrivateKey::::new(&mut rand::thread_rng())?; - let view_key = ViewKey::try_from(&private_key)?; - let address = Address::try_from(&view_key)?; - - // Print the new Aleo account. - let mut output = "".to_string(); - write!( - output, - "\n {:>12}\n", - "Attention - Remember to store this account private key and view key.".red().bold() - )?; - writeln!(output, "\n {:>12} {}", "Private Key".cyan().bold(), private_key)?; - writeln!(output, " {:>12} {}", "View Key".cyan().bold(), view_key)?; - writeln!(output, " {:>12} {}", "Address".cyan().bold(), address)?; - - Ok(output) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // As per the official clap recommendation. - #[test] - fn verify_cli() { - use clap::CommandFactory; - CLI::command().debug_assert() - } -} diff --git a/snarkos/lib.rs b/snarkos/lib.rs deleted file mode 100644 index 6bd547526a..0000000000 --- a/snarkos/lib.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (C) 2019-2022 Aleo Systems Inc. -// This file is part of the snarkOS library. - -// The snarkOS library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The snarkOS library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the snarkOS library. If not, see . - -#![forbid(unsafe_code)] -#![allow(clippy::module_inception)] -#![allow(clippy::suspicious_else_formatting)] -#![allow(clippy::type_complexity)] - -#[macro_use] -extern crate thiserror; -#[macro_use] -extern crate tracing; - -pub mod logger; - -mod account; -pub use account::*; - -mod cli; -pub use cli::*; - -mod ledger; -pub use ledger::*; - -mod network; -pub use network::*; - -mod node; -pub use node::*; - -mod store; -pub use store::*; - -mod updater; -pub use updater::*; - -pub use snarkos_environment as environment; - -#[cfg(feature = "rpc")] -pub use snarkos_rpc as rpc; - -pub use snarkvm::prelude::{Address, Network}; - -pub mod prelude { - pub use crate::environment::*; - - #[cfg(feature = "rpc")] - pub use crate::rpc::*; - - pub use snarkvm::prelude::{Address, Network}; -} - -use anyhow::anyhow; -use backoff::{future::retry, ExponentialBackoff}; -use futures::Future; -use std::time::Duration; - -pub(crate) async fn handle_dispatch_error<'a, T, F>(func: impl Fn() -> F + 'a) -> anyhow::Result -where - F: Future>, -{ - fn default_backoff() -> ExponentialBackoff { - ExponentialBackoff { - max_interval: Duration::from_secs(10), - max_elapsed_time: Some(Duration::from_secs(45)), - ..Default::default() - } - } - - fn from_anyhow_err(err: anyhow::Error) -> backoff::Error { - use backoff::Error; - - if let Ok(err) = err.downcast::() { - debug!("Server error: {err}; retrying..."); - Error::Transient { - err: err.into(), - retry_after: None, - } - } else { - Error::Transient { - err: anyhow!("Block parse error"), - retry_after: None, - } - } - } - - retry(default_backoff(), || async { func().await.map_err(from_anyhow_err) }).await -} diff --git a/snarkos/logger.rs b/snarkos/logger.rs deleted file mode 100644 index 936f0b6c81..0000000000 --- a/snarkos/logger.rs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (C) 2019-2022 Aleo Systems Inc. -// This file is part of the snarkOS library. - -// The snarkOS library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The snarkOS library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the snarkOS library. If not, see . - -use snarkvm::prelude::*; - -use colored::*; -use std::fmt::Write; - -pub fn initialize_logger(verbosity: u8) { - match verbosity { - 0 => env::set_var("RUST_LOG", "info"), - 1 => env::set_var("RUST_LOG", "debug"), - 2 | 3 => env::set_var("RUST_LOG", "trace"), - _ => env::set_var("RUST_LOG", "info"), - }; - - // Filter out undesirable logs. - let filter = tracing_subscriber::EnvFilter::from_default_env() - .add_directive("hyper::client=off".parse().unwrap()) - .add_directive("hyper::proto=off".parse().unwrap()) - .add_directive("jsonrpsee=off".parse().unwrap()) - .add_directive("mio=off".parse().unwrap()) - .add_directive("rusoto_core=off".parse().unwrap()) - .add_directive("tokio_util=off".parse().unwrap()) - .add_directive("want=off".parse().unwrap()) - .add_directive("reqwest=off".parse().unwrap()); - - // Initialize tracing. - let _ = tracing_subscriber::fmt() - .with_env_filter(filter) - .with_target(verbosity == 3) - .try_init(); -} - -pub fn welcome_message() -> String { - let mut output = String::new(); - output += &r#" - - ╦╬╬╬╬╬╦ - ╬╬╬╬╬╬╬╬╬ β–„β–„β–„β–„ β–„β–„β–„ - ╬╬╬╬╬╬╬╬╬╬╬ β–β–“β–“β–“β–“β–Œ β–“β–“β–“ - ╬╬╬╬╬╬╬╬╬╬╬╬╬ β–β–“β–“β–“β–“β–“β–“β–Œ β–“β–“β–“ β–„β–„β–„β–„β–„β–„ β–„β–„β–„β–„β–„β–„ - ╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ▐▓▓▓ β–“β–“β–“β–Œ β–“β–“β–“ β–„β–“β–“β–€β–€β–€β–€β–“β–“β–„ β–β–“β–“β–“β–“β–“β–“β–“β–“β–Œ - β•¬β•¬β•¬β•¬β•¬β•¬β•¬β•œ ╙╬╬╬╬╬╬╬ β–β–“β–“β–“β–Œ β–β–“β–“β–“β–Œ β–“β–“β–“ β–β–“β–“β–“β–„β–„β–„β–„β–“β–“β–“β–Œ ▐▓▓▓ β–“β–“β–“β–Œ - ╬╬╬╬╬╬╣ ╠╬╬╬╬╬╬ β–ˆβ–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–ˆ β–“β–“β–“ β–β–“β–“β–€β–€β–€β–€β–€β–€β–€β–€β–˜ ▐▓▓▓ β–“β–“β–“β–Œ - ╬╬╬╬╬╬╣ ╠╬╬╬╬╬╬ β–ˆβ–“β–“β–“β–Œ β–β–“β–“β–“β–ˆ β–“β–“β–“ β–€β–“β–“β–„β–„β–„β–„β–“β–“β–€ β–β–“β–“β–“β–“β–“β–“β–“β–“β–Œ - ╬╬╬╬╬╬╣ ╠╬╬╬╬╬╬ ▝▀▀▀▀ β–€β–€β–€β–€β–˜ β–€β–€β–€ β–€β–€β–€β–€β–€β–€ β–€β–€β–€β–€β–€β–€ -β•šβ•¬β•¬β•¬β•¬β•¬β•© ╩╬╬╬╬╩ - -"# - .white() - .bold(); - output += &"Welcome to Aleo! We thank you for running a node and supporting privacy.\n".bold(); - output -} - -pub fn notification_message(miner: Option>) -> String { - let mut output = String::new(); - output += &r#" - - ================================================================================================== - - Welcome to Aleo Testnet3 - Incentivization Period - - ================================================================================================== - - The incentivized testnet will be announced on Discord. Visit https://www.aleo.org/discord - for the official launch announcement on Month Date, Year, from the Aleo team. - - Minimum requirements: - - - CPU: 16-cores (32-cores preferred) - - RAM: 16GB of memory (32GB preferred) - - Storage: 128GB of disk space - - Network: 50 Mbps of upload and download bandwidth - - To get started (after Month Date, Year): - - 1. Generate one Aleo account, and save the account private key and view key. - 2. Ensure ports 4132/tcp and 3032/tcp are open on your router and OS firewall. - 3. Ensure your Aleo node is running the `run-client.sh` or `run-miner.sh` script, - in order to automatically stay up to date on the incentivized testnet. - 4. File technical issues on Github at https://github.com/AleoHQ/snarkOS/issues/new/choose - 5. Ask questions on Discord at https://www.aleo.org/discord - 6. Please be respectful to all members of the Aleo community. - - To claim rewards (after Month Date, Year): - - 1. Participants will be required to KYC at the end of incentivized testnet3. - 2. Participants must demonstrate ownership of their Aleo miner address. - 3. [For United States & Canada] Participants must be accredited investors. - 4. The Aleo team reserves the right to maintain discretion in rewarding participants. - - Thank you for participating in incentivized testnet3 and for supporting privacy! - - ================================================================================================== -"# - .white() - .bold(); - - if let Some(miner) = miner { - let _ = write!( - output, - " - Your Aleo miner address is {} - - ================================================================================================== -", - miner - ); - } - - output -} diff --git a/snarkos/main.rs b/snarkos/main.rs index c705f1dcd8..504c332ba7 100644 --- a/snarkos/main.rs +++ b/snarkos/main.rs @@ -14,53 +14,19 @@ // You should have received a copy of the GNU General Public License // along with the snarkOS library. If not, see . -use snarkos::{logger::initialize_logger, CLI}; +use snarkos_cli::{commands::CLI, helpers::Updater}; -use anyhow::Result; use clap::Parser; -use tokio::runtime; -fn main() -> Result<()> { - if num_cpus::get() < 16 { - eprintln!("\nWARNING - Your machine must have at least 16-cores to run a node.\n"); - } - - // Parse the provided arguments. +fn main() -> anyhow::Result<()> { + // Parse the given arguments. let cli = CLI::parse(); - - // Start logging. - initialize_logger(cli.verbosity); - - let (num_tokio_worker_threads, max_tokio_blocking_threads) = if !cli.beacon { - ((num_cpus::get() / 8 * 2).max(1), num_cpus::get()) - } else { - (num_cpus::get(), 512) // 512 is tokio's current default - }; - - // Initialize the runtime configuration. - let runtime = runtime::Builder::new_multi_thread() - .enable_all() - .thread_stack_size(8 * 1024 * 1024) - .worker_threads(num_tokio_worker_threads) - .max_blocking_threads(max_tokio_blocking_threads) - .build()?; - - let num_rayon_cores_global = if !cli.beacon { - (num_cpus::get() / 8 * 5).max(1) - } else { - num_cpus::get() - }; - - // Initialize the parallelization parameters. - rayon::ThreadPoolBuilder::new() - .stack_size(8 * 1024 * 1024) - .num_threads(num_rayon_cores_global) - .build_global() - .unwrap(); - - runtime.block_on(async move { - cli.start().await.expect("Failed to start the node"); - }); - + // Run the updater. + println!("{}", Updater::print_cli()); + // Run the CLI. + match cli.command.parse() { + Ok(output) => println!("{output}\n"), + Err(error) => println!("⚠️ {error}\n"), + } Ok(()) } diff --git a/snarkos/network/message.rs b/snarkos/network/message.rs deleted file mode 100644 index 46e4aba563..0000000000 --- a/snarkos/network/message.rs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (C) 2019-2022 Aleo Systems Inc. -// This file is part of the snarkOS library. - -// The snarkOS library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The snarkOS library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the snarkOS library. If not, see . - -use snarkvm::prelude::*; - -use ::bytes::{Buf, BufMut, Bytes, BytesMut}; -use std::marker::PhantomData; -use tokio::task; -use tokio_util::codec::{Decoder, Encoder, LengthDelimitedCodec}; - -/// This object enables deferred deserialization / ahead-of-time serialization for objects that -/// take a while to deserialize / serialize, in order to allow these operations to be non-blocking. -#[derive(Clone, Debug)] -pub enum Data { - Object(T), - Buffer(Bytes), -} - -impl Data { - pub fn deserialize_blocking(self) -> Result { - match self { - Self::Object(x) => Ok(x), - Self::Buffer(bytes) => T::from_bytes_le(&bytes), - } - } - - pub async fn deserialize(self) -> Result { - match self { - Self::Object(x) => Ok(x), - Self::Buffer(bytes) => match task::spawn_blocking(move || T::from_bytes_le(&bytes)).await { - Ok(x) => x, - Err(err) => Err(err.into()), - }, - } - } - - pub fn serialize_blocking_into(&self, writer: &mut W) -> Result<()> { - match self { - Self::Object(x) => { - let bytes = x.to_bytes_le()?; - Ok(writer.write_all(&bytes)?) - } - Self::Buffer(bytes) => Ok(writer.write_all(bytes)?), - } - } - - pub async fn serialize(self) -> Result { - match self { - Self::Object(x) => match task::spawn_blocking(move || x.to_bytes_le()).await { - Ok(bytes) => bytes.map(|vec| vec.into()), - Err(err) => Err(err.into()), - }, - Self::Buffer(bytes) => Ok(bytes), - } - } -} - -#[derive(Clone)] -pub enum Message { - /// Ping with the current block height. - Ping, - /// Pong with the current block height. - Pong(u32), - /// Request a block for a given height. - BlockRequest(u32), - /// A response to a `BlockRequest`. - BlockResponse(Data>), - /// A message containing a transaction to be broadcast. - TransactionBroadcast(Data>), - /// A message containing a new block to be broadcast. - BlockBroadcast(Data>), -} - -impl Message { - /// Returns the message name. - #[inline] - pub fn name(&self) -> &str { - match self { - Self::Ping => "Ping", - Self::Pong(..) => "Pong", - Self::BlockRequest(..) => "BlockRequest", - Self::BlockResponse(..) => "BlockResponse", - Self::TransactionBroadcast(..) => "TransactionBroadcast", - Self::BlockBroadcast(..) => "BlockBroadcast", - } - } - - /// Returns the message ID. - #[inline] - pub fn id(&self) -> u16 { - match self { - Self::Ping => 0, - Self::Pong(..) => 1, - Self::BlockRequest(..) => 2, - Self::BlockResponse(..) => 3, - Self::TransactionBroadcast(..) => 4, - Self::BlockBroadcast(..) => 5, - } - } - - /// Returns the message data as bytes. - #[inline] - fn serialize_data_into(&self, writer: &mut W) -> Result<()> { - writer.write_all(&self.id().to_le_bytes()[..])?; - - match self { - Self::Ping => Ok(()), - Self::Pong(block_height) => Ok(writer.write_all(&block_height.to_le_bytes())?), - Self::BlockRequest(block_height) => Ok(writer.write_all(&block_height.to_le_bytes())?), - Self::BlockResponse(block) | Self::BlockBroadcast(block) => block.serialize_blocking_into(writer), - Self::TransactionBroadcast(transaction) => transaction.serialize_blocking_into(writer), - } - } - - /// Deserialize the given buffer into a message. - fn deserialize(mut bytes: BytesMut) -> Result { - if bytes.remaining() < 2 { - bail!("Missing message ID"); - } - - // Read the message ID. - let id: u16 = bytes.get_u16_le(); - - // Deserialize the data field. - let message = match id { - 0 => { - if bytes.remaining() != 0 { - bail!("Unexpected data for Ping"); - } - Message::::Ping - } - 1 => { - let mut reader = bytes.reader(); - Message::::Pong(bincode::deserialize_from(&mut reader)?) - } - 2 => { - let mut reader = bytes.reader(); - Message::::BlockRequest(bincode::deserialize_from(&mut reader)?) - } - 3 => Message::::BlockResponse(Data::Buffer(bytes.freeze())), - 4 => Message::::TransactionBroadcast(Data::Buffer(bytes.freeze())), - 5 => Message::::BlockBroadcast(Data::Buffer(bytes.freeze())), - _ => bail!("Unknown message ID"), - }; - - Ok(message) - } -} - -/// The maximum size of a message that can be transmitted in the network. -const MAXIMUM_MESSAGE_SIZE: usize = 128 * 1024 * 1024; // 128 MiB - -/// The codec used to decode and encode network `Message`s. -pub struct MessageCodec { - codec: LengthDelimitedCodec, - _phantom: PhantomData, -} - -impl Default for MessageCodec { - fn default() -> Self { - Self { - codec: LengthDelimitedCodec::builder() - .max_frame_length(MAXIMUM_MESSAGE_SIZE) - .little_endian() - .new_codec(), - _phantom: Default::default(), - } - } -} - -impl Encoder> for MessageCodec { - type Error = std::io::Error; - - fn encode(&mut self, message: Message, dst: &mut BytesMut) -> Result<(), Self::Error> { - // Serialize the payload directly into dst. - message - .serialize_data_into(&mut dst.writer()) - // This error should never happen, the conversion is for greater compatibility. - .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "serialization error"))?; - - let serialized_message = dst.split_to(dst.len()).freeze(); - - self.codec.encode(serialized_message, dst) - } -} - -impl Decoder for MessageCodec { - type Error = std::io::Error; - type Item = Message; - - fn decode(&mut self, source: &mut BytesMut) -> Result, Self::Error> { - // Decode a frame containing bytes belonging to a message. - let bytes = match self.codec.decode(source)? { - Some(bytes) => bytes, - None => return Ok(None), - }; - - // Convert the bytes to a message, or fail if it is not valid. - match Message::deserialize(bytes) { - Ok(message) => Ok(Some(message)), - Err(error) => { - warn!("Failed to deserialize a message: {}", error); - Err(std::io::ErrorKind::InvalidData.into()) - } - } - } -} diff --git a/snarkos/network/mod.rs b/snarkos/network/mod.rs deleted file mode 100644 index 91442c30b0..0000000000 --- a/snarkos/network/mod.rs +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright (C) 2019-2022 Aleo Systems Inc. -// This file is part of the snarkOS library. - -// The snarkOS library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The snarkOS library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the snarkOS library. If not, see . - -mod message; -pub use message::*; - -use crate::Ledger; - -use snarkvm::prelude::*; - -use futures::{SinkExt, StreamExt}; -use std::{ - net::{IpAddr, SocketAddr}, - sync::Arc, -}; -use tokio::{ - net::{TcpListener, TcpStream}, - sync::mpsc, - task, -}; -use tokio_util::codec::Framed; - -pub type Sender = mpsc::Sender>; -pub type Receiver = mpsc::Receiver>; - -pub struct Peer { - ip: SocketAddr, - outbound: Framed>, - inbound: Receiver, -} - -impl Peer { - async fn new(stream: TcpStream, ledger: Arc>) -> io::Result { - let outbound = Framed::new(stream, Default::default()); - let addr = outbound.get_ref().peer_addr()?; - - // Create a channel for this peer - let (outbound_sender, inbound) = mpsc::channel(1024); - - // Send initial ping. - if let Err(err) = outbound_sender.send(Message::::Ping).await { - warn!("Failed to send ping {} to {}", err, addr); - } - - // Store the new peer. - if ledger.peers().read().contains_key(&addr) { - return Err(error(format!("Peer {} already exists", addr))); - } else { - ledger.peers().write().insert(addr, outbound_sender); - } - - Ok(Self { - ip: addr, - outbound, - inbound, - }) - } -} - -/// Create a message handler for each peer. -pub(crate) async fn handle_peer( - stream: TcpStream, - peer_ip: SocketAddr, - ledger: Arc>, -) -> Result<(), Box> { - let mut peer = Peer::::new(stream, ledger.clone()).await?; - - info!("Connected to peer: {:?}", peer_ip); - - // Process incoming messages until our stream is exhausted by a disconnect. - loop { - tokio::select! { - // A message was received from a peer. - Some(msg) = peer.inbound.recv() => { - peer.outbound.send(msg).await?; - } - result = peer.outbound.next() => match result { - // A message was received from the current user, we should - // broadcast this message to the other users. - Some(Ok(message)) => { - trace!("Received '{}' from {}", message.name(), peer.ip); - - match message { - Message::Ping => { - let latest_height = ledger.ledger().read().latest_height(); - let response = Message::::Pong(latest_height); - peer.outbound.send(response).await?; - }, - Message::Pong(height) => { - // TODO (raychu86): Handle syncs. Currently just asks for one new block at a time. - // If the peer is ahead, ask for next block. - let latest_height = ledger.ledger().read().latest_height(); - if height > latest_height { - let request = Message::::BlockRequest(latest_height + 1); - peer.outbound.send(request).await?; - } - }, - Message::BlockRequest(height) => { - let latest_height = ledger.ledger().read().latest_height(); - if height > latest_height { - trace!("Peer requested block {height}, which is greater than the current height {latest_height}"); - } else { - let block = ledger.ledger().read().get_block(height)?; - let response = Message::BlockResponse(Data::Object(block)); - - peer.outbound.send(response).await?; - } - }, - Message::BlockResponse(block_bytes) => { - // Perform deferred deserialization. - let block = block_bytes.deserialize().await?; - - let block_height = block.height(); - let block_hash = block.hash(); - - // Check if the block can be added to the ledger. - if block_height == ledger.ledger().read().latest_height() + 1 { - // Attempt to add the block to the ledger. - match ledger.add_next_block(block).await { - Ok(_) => info!("Advanced to block {} ({})", block_height, block_hash), - Err(err) => warn!("Failed to process block {} (height: {}): {:?}", block_hash, block_height, err) - }; - - // Send a ping. - peer.outbound.send(Message::::Ping).await?; - } else { - trace!("Skipping block {} (height: {})", block_hash, block_height); - } - }, - Message::TransactionBroadcast(transaction_bytes) => { - // Perform deferred deserialization. - let transaction = transaction_bytes.clone().deserialize().await?; - - let transaction_id = transaction.id(); - - // Check that the transaction doesn't already exist in the ledger or mempool. - if let Ok(true) = ledger.ledger().read().contains_transaction_id(&transaction_id) { - // Attempt to insert the transaction into the mempool. - match ledger.add_to_memory_pool(transaction) { - Ok(_) => { - // Broadcast transaction to all peers except the sender. - let peers = ledger.peers().read().clone(); - tokio::spawn(async move { - for (_, sender) in peers.iter().filter(|(ip, _)| *ip != &peer.ip) { - let _ = sender.send(Message::::TransactionBroadcast(transaction_bytes.clone())).await; - } - }); - - }, - Err(err) => { - trace!( - "Failed to add transaction {} to mempool: {:?}", - transaction_id, - err - ); - } - } - } - }, - Message::BlockBroadcast(block_bytes) => { - // Perform deferred deserialization. - let block = block_bytes.clone().deserialize().await?; - - let block_height = block.height(); - let block_hash = block.hash(); - - // Check if the block can be added to the ledger. - if block_height == ledger.ledger().read().latest_height() + 1 { - // Attempt to add the block to the ledger. - match ledger.add_next_block(block).await { - Ok(_) => { - info!("Advanced to block {} ({})", block_height, block_hash); - - // Broadcast block to all peers except the sender. - let peers = ledger.peers().read().clone(); - tokio::spawn(async move { - for (_, sender) in peers.iter().filter(|(ip, _)| *ip != &peer.ip) { - let _ = sender.send(Message::::BlockBroadcast(block_bytes.clone())).await; - } - }); - }, - Err(err) => { - trace!( - "Failed to process block {} (height: {}): {:?}", - block_hash, - block_height, - err - ); - } - }; - } else { - trace!("Skipping block {} (height: {})", block_hash, block_height); - } - } - } - } - // An error occurred. - Some(Err(e)) => { - warn!( - "an error occurred while processing messages for {}; error = {:?}", - peer.ip, - e - ); - } - // The stream has been exhausted. - None => { - // Remove the peer from the ledger. - debug!("Removing connection with peer {}", peer.ip); - ledger.peers().write().remove(&peer.ip); - return Ok(())}, - }, - } - } -} - -/// Handle connection listener for new peers. -pub fn handle_listener(listener: TcpListener, ledger: Arc>) -> task::JoinHandle<()> { - info!("Listening to connections at: {}", listener.local_addr().unwrap()); - - tokio::spawn(async move { - loop { - let ledger_clone = ledger.clone(); - - match listener.accept().await { - // Process the inbound connection request. - Ok((stream, peer_ip)) => { - tokio::spawn(async move { - if let Err(err) = handle_peer::(stream, peer_ip, ledger_clone.clone()).await { - warn!("Error handling peer {}: {:?}", peer_ip, err); - } - }); - } - Err(error) => warn!("Failed to accept a connection: {}", error), - } - } - }) -} - -// TODO (raychu86): Handle this request via `Message::BlockRequest`. This is currently not done, -// because the node has not established the leader as a peer. -/// Request the genesis block from the leader. -pub(super) async fn request_genesis_block(leader_ip: IpAddr) -> Result> { - info!("Requesting genesis block from {}", leader_ip); - let block_string = reqwest::get(format!("http://{leader_ip}/testnet3/block/0")).await?.text().await?; - - Block::from_str(&block_string) -} - -/// Send a ping to all peers every 10 seconds. -pub fn send_pings(ledger: Arc>) -> task::JoinHandle<()> { - tokio::spawn(async move { - let mut interval = tokio::time::interval(time::Duration::from_secs(10)); - loop { - interval.tick().await; - - let peers = ledger.peers().read().clone(); - - for (addr, outbound) in peers.iter() { - if let Err(err) = outbound.try_send(Message::::Ping) { - warn!("Error sending ping {} to {}", err, addr); - } - } - } - }) -} - -/// Handle connection with the leader. -pub fn connect_to_leader(initial_peer: SocketAddr, ledger: Arc>) -> task::JoinHandle<()> { - tokio::spawn(async move { - let mut interval = tokio::time::interval(time::Duration::from_secs(10)); - loop { - if !ledger.peers().read().contains_key(&initial_peer) { - trace!("Attempting to connect to peer {}", initial_peer); - match TcpStream::connect(initial_peer).await { - Ok(stream) => { - let ledger_clone = ledger.clone(); - tokio::spawn(async move { - if let Err(err) = handle_peer::(stream, initial_peer, ledger_clone).await { - warn!("Error handling peer {}: {:?}", initial_peer, err); - } - }); - } - Err(error) => warn!("Failed to connect to peer {}: {}", initial_peer, error), - } - } - interval.tick().await; - } - }) -} diff --git a/snarkos/node.rs b/snarkos/node.rs deleted file mode 100644 index 81f6c58635..0000000000 --- a/snarkos/node.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2019-2022 Aleo Systems Inc. -// This file is part of the snarkOS library. - -// The snarkOS library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The snarkOS library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the snarkOS library. If not, see . - -use crate::CLI; - -use crate::{connect_to_leader, handle_listener, handle_peer, request_genesis_block, send_pings, Account, Ledger}; -use snarkos_environment::{helpers::Status, Environment}; -use snarkvm::prelude::Network; - -use anyhow::{bail, Result}; -use core::marker::PhantomData; -use std::{net::SocketAddr, sync::Arc}; - -#[derive(Clone)] -pub struct Node { - /// The ledger. - ledger: Arc>, - /// PhantomData. - _phantom: PhantomData<(N, E)>, -} - -impl Node { - /// Initializes a new instance of the node. - pub async fn new(cli: &CLI, account: Account) -> Result { - // Initialize the ledger. - let ledger = match cli.dev { - None => { - // Initialize the ledger. - let ledger = Ledger::::load(*account.private_key(), cli.dev)?; - // Sync the ledger with the network. - ledger.initial_sync_with_network(cli.beacon_addr.ip()).await?; - - ledger - } - Some(_) => { - // TODO (raychu86): Formalize this process via network messages. - // Currently this operations pulls from the leader's server. - // Request genesis block from the beacon leader. - let genesis_block = request_genesis_block::(cli.beacon_addr.ip()).await?; - - // Initialize the ledger from the provided genesis block. - Ledger::::new_with_genesis(*account.private_key(), genesis_block, cli.dev)? - } - }; - - // Initialize the listener. - let listener = tokio::net::TcpListener::bind(cli.node).await?; - - // Handle incoming connections. - let _handle_listener = handle_listener::(listener, ledger.clone()); - - // Connect to the leader node and listen for new blocks. - let leader_addr = cli.beacon_addr; - trace!("Connecting to '{}'...", leader_addr); - let _leader_conn_task = connect_to_leader::(leader_addr, ledger.clone()); - - // Send pings to all peers every 10 seconds. - let _pings = send_pings::(ledger.clone()); - - Ok(Self { - ledger: ledger.clone(), - _phantom: PhantomData, - }) - } - - /// Sends a connection request to the given IP address. - pub async fn connect_to(&self, peer_ip: SocketAddr) -> Result<()> { - trace!("Attempting to connect to peer {}", peer_ip); - match tokio::net::TcpStream::connect(peer_ip).await { - Ok(stream) => { - let ledger = self.ledger.clone(); - tokio::spawn(async move { - if let Err(err) = handle_peer::(stream, peer_ip, ledger).await { - warn!("Failed to handle connection with peer {}: {:?}", peer_ip, err); - } - }); - Ok(()) - } - Err(error) => { - warn!("Failed to connect to peer {}: {}", peer_ip, error); - bail!("{error}") - } - } - } - - /// - /// Disconnects from peers and proceeds to shut down the node. - /// - pub async fn shut_down(&self) { - info!("Shutting down..."); - // Update the node status. - E::status().update(Status::ShuttingDown); - - // Shut down the ledger. - trace!("Proceeding to shut down the ledger..."); - // self.state.ledger().shut_down().await; - - // Flush the tasks. - E::resources().shut_down(); - trace!("Node has shut down."); - } -}