├── .github └── workflows │ └── windows.yml ├── .gitignore ├── .gitlab-ci.yml ├── .images ├── both-logos.svg ├── kanvas-logo.svg ├── roc-to-can-0.png ├── roc-to-can-1.png ├── roc-to-can-xcm.png └── thippy-logo.svg ├── .rustfmt.toml ├── CODEOWNERS ├── Cargo.lock ├── Cargo.toml ├── LICENSE-GPL3 ├── README.md ├── build.rs ├── node ├── Cargo.toml ├── build.rs └── src │ ├── chain_spec.rs │ ├── cli.rs │ ├── command.rs │ ├── lib.rs │ ├── main.rs │ ├── rpc.rs │ └── service.rs ├── polkadot-launch └── config.json ├── res └── testnet-1.json ├── runtime ├── Cargo.lock ├── Cargo.toml ├── build.rs └── src │ └── lib.rs ├── scripts ├── ci │ └── pre_cache.sh ├── dockerfiles │ └── thippy_injected.Dockerfile ├── init.sh ├── prepare-test-net.sh └── substrate-diff.sh └── src ├── chain_spec.rs ├── cli.rs ├── command.rs ├── main.rs └── service.rs /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: continuous-intergration/windows 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | paths-ignore: 8 | - 'README.md' 9 | 10 | jobs: 11 | check: 12 | name: build-windows 13 | strategy: 14 | matrix: 15 | platform: 16 | - windows-latest 17 | toolchain: 18 | - nightly 19 | runs-on: ${{ matrix.platform }} 20 | env: 21 | RUST_BACKTRACE: full 22 | steps: 23 | # Required for `CI_REF_NAME` 24 | - name: Add GitHub Environment Variables 25 | uses: FranzDiebold/github-env-vars-action@v2 26 | 27 | # Required for `librocksb-sys` 28 | - name: Install LLVM and Clang 29 | uses: KyleMayes/install-llvm-action@latest 30 | if: matrix.platform == 'windows-latest' 31 | with: 32 | version: "12.0.1" 33 | directory: ${{ runner.temp }}/llvm 34 | 35 | # Required for `librocksb-sys` 36 | - name: Set LIBCLANG_PATH 37 | run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV 38 | if: matrix.platform == 'windows-latest' 39 | 40 | - name: Install toolchain 41 | uses: actions-rs/toolchain@master 42 | with: 43 | profile: minimal 44 | toolchain: ${{ matrix.toolchain }} 45 | components: rust-src 46 | target: wasm32-unknown-unknown 47 | override: true 48 | 49 | - name: Checkout sources & submodules 50 | uses: actions/checkout@master 51 | with: 52 | fetch-depth: 1 53 | submodules: recursive 54 | 55 | - name: Rust Cache 56 | uses: Swatinem/rust-cache@v1.2.0 57 | 58 | - name: Build windows binary on ${{ matrix.platform }}-${{ matrix.toolchain }} 59 | run: | 60 | cargo -vV 61 | cargo build --release 62 | 63 | - name: Test thippy binary works 64 | run: | 65 | ./target/release/thippy --version 66 | 67 | - name: Check if release already exists 68 | id: check-exists 69 | run: | 70 | curl -s https://api.github.com/repos/ng8eke/thippy/releases ` 71 | -H "Cookie: logged_in=no" ` 72 | -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" ` 73 | | jq -r '[.[].tag_name] | any(. == \"${{ Env.CI_REF_NAME }}\")' 74 | $exists = (curl -s https://api.github.com/repos/ng8eke/thippy/releases ` 75 | -H "Cookie: logged_in=no" ` 76 | -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" ` 77 | | jq -r '[.[].tag_name] | any(. == \"${{ Env.CI_REF_NAME }}\")') 78 | echo $exists 79 | Write-Output "::set-output name=EXISTS::$exists" 80 | 81 | - name: Create release from tag, if necessary 82 | if: steps.check-exists.outputs.EXISTS == 'false' 83 | uses: marvinpinto/action-automatic-releases@latest 84 | # Creating a release might fail, since there is a GitLab job which 85 | # does the same thing for Linux & Mac binaries. This GitLab job 86 | # might already have created the release. 87 | continue-on-error: true 88 | with: 89 | repo_token: ${{ secrets.GITHUB_TOKEN }} 90 | automatic_release_tag: ${{ Env.CI_REF_NAME }} 91 | prerelease: false 92 | draft: true 93 | title: ${{ Env.CI_REF_NAME }} 94 | 95 | - name: Fetch release id 96 | id: fetch-id 97 | run: | 98 | $release_id = (curl -s https://api.github.com/repos/ng8eke/thippy/releases ` 99 | -H "Cookie: logged_in=no" ` 100 | -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" ` 101 | | jq -r '.[] | select(.tag_name == \"${{ Env.CI_REF_NAME }}\") | .id') 102 | echo $release_id 103 | Write-Output "::set-output name=RELEASE_ID::$release_id" 104 | 105 | - name: Upload windows binary as release asset 106 | run: | 107 | $URI = -join("https://uploads.github.com/repos/ng8eke/thippy/releases/", "${{ steps.fetch-id.outputs.RELEASE_ID }}", "/assets?name=thippy.exe"); 108 | echo $URI 109 | curl -X "POST" $URI ` 110 | --fail-early ` 111 | -H "Cookie: logged_in=no" ` 112 | -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" ` 113 | -H "Content-Type: application/octet-stream" ` 114 | -d "@target/release/thippy.exe" 115 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | **/*.rs.bk 3 | *.swp 4 | .wasm-binaries 5 | .vscode 6 | .DS_Store 7 | .idea/ 8 | rls*.log 9 | runtime/Cargo.lock 10 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # .gitlab-ci.yml 2 | # 3 | # thippy 4 | # 5 | # pipelines can be triggered manually in the web 6 | 7 | 8 | stages: 9 | - fmt 10 | - build-linux 11 | - build-mac 12 | - publish 13 | 14 | variables: &default-vars 15 | GIT_STRATEGY: fetch 16 | GIT_DEPTH: 100 17 | CARGO_INCREMENTAL: 0 18 | CARGO_TARGET_DIR: "/ci-cache/${CI_PROJECT_NAME}/targets/${CI_COMMIT_REF_NAME}/${CI_JOB_NAME}" 19 | VAULT_SERVER_URL: "https://vault.parity-mgmt-vault.parity.io" 20 | VAULT_AUTH_PATH: "gitlab-parity-io-jwt" 21 | VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" 22 | 23 | workflow: 24 | rules: 25 | - if: $CI_COMMIT_TAG 26 | - if: $CI_COMMIT_BRANCH 27 | 28 | .collect-artifacts: &collect-artifacts 29 | artifacts: 30 | name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" 31 | when: on_success 32 | expire_in: 7 days 33 | paths: 34 | - artifacts/ 35 | 36 | .docker-env: &docker-env 37 | image: ng8eke/ci-linux:production 38 | before_script: 39 | - cargo -vV 40 | - rustc -vV 41 | - rustup show 42 | - bash --version 43 | - mkdir -p ${CARGO_TARGET_DIR} 44 | - ./scripts/ci/pre_cache.sh 45 | - sccache -s 46 | interruptible: true 47 | retry: 48 | max: 2 49 | when: 50 | - runner_system_failure 51 | - unknown_failure 52 | - api_failure 53 | tags: 54 | - linux-docker 55 | 56 | .kubernetes-env: &kubernetes-env 57 | retry: 58 | max: 2 59 | when: 60 | - runner_system_failure 61 | - unknown_failure 62 | - api_failure 63 | interruptible: true 64 | tags: 65 | - kubernetes-parity-build 66 | 67 | .build-refs: &build-refs 68 | rules: 69 | - if: $CI_PIPELINE_SOURCE == "web" 70 | - if: $CI_PIPELINE_SOURCE == "schedule" 71 | - if: $CI_COMMIT_REF_NAME == "master" 72 | - if: $CI_COMMIT_REF_NAME == "tags" 73 | - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs 74 | - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 75 | 76 | .master-refs: &master-refs 77 | rules: 78 | - if: $CI_PIPELINE_SOURCE == "web" 79 | - if: $CI_PIPELINE_SOURCE == "schedule" 80 | - if: $CI_COMMIT_REF_NAME == "master" 81 | - if: $CI_COMMIT_REF_NAME == "tags" 82 | - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 83 | 84 | .publish-refs: &publish-refs 85 | rules: 86 | - if: $CI_PIPELINE_SOURCE == "web" 87 | - if: $CI_PIPELINE_SOURCE == "schedule" 88 | - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 89 | 90 | 91 | ### stage: fmt 92 | 93 | fmt: 94 | stage: fmt 95 | <<: *docker-env 96 | script: 97 | - cargo +nightly fmt --verbose --all -- --check 98 | 99 | ### stage: build-linux 100 | 101 | build-linux: 102 | stage: build-linux 103 | <<: *docker-env 104 | <<: *collect-artifacts 105 | <<: *build-refs 106 | script: 107 | - time cargo build --release 108 | - time cargo test --release --all 109 | - mkdir -p ./artifacts/thippy-linux/ 110 | - cp ${CARGO_TARGET_DIR}/release/thippy ./artifacts/thippy-linux/thippy 111 | - cp ${CARGO_TARGET_DIR}/release/wbuild/thippy-runtime/thippy_runtime* ./artifacts/thippy-linux/ 112 | - cp ./scripts/dockerfiles/thippy_injected.Dockerfile ./artifacts/thippy-linux/thippy_injected.Dockerfile 113 | 114 | ### stage: build-mac 115 | 116 | build-mac: 117 | stage: build-mac 118 | <<: *docker-env 119 | <<: *collect-artifacts 120 | # we run the mac build only when we actually want to publish 121 | <<: *publish-refs 122 | before_script: 123 | - unset CARGO_TARGET_DIR 124 | script: 125 | - time cargo build --release 126 | - mkdir -p ./artifacts/thippy-mac/ 127 | - cp target/release/thippy ./artifacts/thippy-mac/thippy 128 | tags: 129 | - osx 130 | 131 | ### stage: publish 132 | 133 | .build-push-docker-image: &build-push-docker-image 134 | <<: *master-refs 135 | <<: *kubernetes-env 136 | image: quay.io/buildah/stable 137 | variables: 138 | <<: *default-vars 139 | GIT_STRATEGY: none 140 | DOCKERFILE: thippy_injected.Dockerfile 141 | IMAGE_NAME: docker.io/ng8eke/thippy 142 | secrets: 143 | DOCKER_HUB_USER: 144 | vault: cicd/gitlab/parity/DOCKER_HUB_USER@kv 145 | file: false 146 | DOCKER_HUB_PASS: 147 | vault: cicd/gitlab/parity/DOCKER_HUB_PASS@kv 148 | file: false 149 | needs: 150 | - job: build-linux 151 | artifacts: true 152 | before_script: 153 | - if [[ "${CI_COMMIT_TAG}" ]]; then 154 | VERSION=${CI_COMMIT_TAG}; 155 | elif [[ "${CI_COMMIT_SHORT_SHA}" ]]; then 156 | VERSION=${CI_COMMIT_SHORT_SHA}; 157 | fi 158 | - echo "Effective tags = ${VERSION} sha-${CI_COMMIT_SHORT_SHA} latest" 159 | script: 160 | - cd ./artifacts/thippy-linux/ 161 | - test "$DOCKER_HUB_USER" -a "$DOCKER_HUB_PASS" || 162 | ( echo "no docker credentials provided"; exit 1 ) 163 | - buildah bud 164 | --format=docker 165 | --build-arg VCS_REF="${CI_COMMIT_SHA}" 166 | --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" 167 | --build-arg VERSION="$VERSION" 168 | --tag "$IMAGE_NAME:$VERSION" 169 | --tag "$IMAGE_NAME:latest" 170 | --file "$DOCKERFILE" . 171 | - echo "$DOCKER_HUB_PASS" | 172 | buildah login --username "$DOCKER_HUB_USER" --password-stdin docker.io 173 | - buildah info 174 | - buildah push --format=v2s2 "$IMAGE_NAME:$VERSION" 175 | - buildah push --format=v2s2 "$IMAGE_NAME:latest" 176 | after_script: 177 | - buildah logout --all 178 | 179 | 180 | publish-docker: 181 | stage: publish 182 | <<: *build-push-docker-image 183 | 184 | publish: 185 | stage: publish 186 | <<: *kubernetes-env 187 | image: ng8eke/tools:latest 188 | <<: *publish-refs 189 | needs: 190 | - job: build-linux 191 | artifacts: true 192 | - job: build-mac 193 | artifacts: true 194 | secrets: 195 | GITHUB_TOKEN: 196 | vault: cicd/gitlab/parity/GITHUB_TOKEN@kv 197 | file: false 198 | script: 199 | - git describe --tags 200 | - TAG_NAME=`git describe --tags` 201 | - echo "tag name ${TAG_NAME}" 202 | - tar -czvf ./thippy-linux.tar.gz ./artifacts/thippy-linux/thippy 203 | - tar -czvf ./thippy-mac.tar.gz ./artifacts/thippy-mac/thippy 204 | - 'curl https://api.github.com/repos/ng8eke/thippy/releases 205 | --fail-with-body 206 | -H "Cookie: logged_in=no" 207 | -H "Authorization: token ${GITHUB_TOKEN}"' 208 | - 'curl https://api.github.com/repos/ng8eke/thippy/releases 209 | --fail-with-body 210 | -H "Cookie: logged_in=no" 211 | -H "Authorization: token ${GITHUB_TOKEN}" | jq .' 212 | - 'RELEASE_ID=$(curl https://api.github.com/repos/ng8eke/thippy/releases 213 | --fail-with-body 214 | -H "Cookie: logged_in=no" 215 | -H "Authorization: token ${GITHUB_TOKEN}" 216 | | jq -r ".[] | select(.tag_name == \"$TAG_NAME\") | .id"); 217 | echo "release id if existent: ${RELEASE_ID}"' 218 | - 'if [ -z "$RELEASE_ID" ]; then 219 | RESP=$(curl -X "POST" "https://api.github.com/repos/ng8eke/thippy/releases" 220 | --fail-with-body 221 | -H "Cookie: logged_in=no" 222 | -H "Authorization: token ${GITHUB_TOKEN}" 223 | -H "Content-Type: application/json; charset=utf-8" 224 | -d $"{ 225 | \"tag_name\": \"${TAG_NAME}\", 226 | \"name\": \"${TAG_NAME}\", 227 | \"prerelease\": false, 228 | \"draft\": true 229 | }"); 230 | echo "api response ${RESP}"; 231 | RELEASE_ID=$(echo $RESP | jq -r .id); 232 | echo "release id of created release ${RELEASE_ID}"; 233 | fi' 234 | - echo "release id ${RELEASE_ID}" 235 | - 'curl -X "POST" "https://uploads.github.com/repos/ng8eke/thippy/releases/$RELEASE_ID/assets?name=thippy-linux.tar.gz" 236 | --fail-with-body 237 | -H "Cookie: logged_in=no" 238 | -H "Authorization: token ${GITHUB_TOKEN}" 239 | -H "Content-Type: application/octet-stream" 240 | --data-binary @"./thippy-linux.tar.gz"' 241 | - 'curl -X "POST" "https://uploads.github.com/repos/ng8eke/thippy/releases/$RELEASE_ID/assets?name=thippy-mac.tar.gz" 242 | --fail-with-body 243 | -H "Cookie: logged_in=no" 244 | -H "Authorization: token ${GITHUB_TOKEN}" 245 | -H "Content-Type: application/octet-stream" 246 | --data-binary @"./thippy-mac.tar.gz"' 247 | -------------------------------------------------------------------------------- /.images/both-logos.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 43 | 50 | 57 | 64 | 68 | 72 | 76 | 80 | 84 | 88 | Kanvas 99 | Thippy 110 | 113 | 119 | 123 | 127 | 131 | 135 | 139 | 140 | 143 | 149 | 153 | 157 | 161 | 165 | 169 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /.images/kanvas-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.images/roc-to-can-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArthurTh0mas/Thippy/b4fe971cf2dcdaa1c798584ba4029a59e50b3436/.images/roc-to-can-0.png -------------------------------------------------------------------------------- /.images/roc-to-can-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArthurTh0mas/Thippy/b4fe971cf2dcdaa1c798584ba4029a59e50b3436/.images/roc-to-can-1.png -------------------------------------------------------------------------------- /.images/roc-to-can-xcm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArthurTh0mas/Thippy/b4fe971cf2dcdaa1c798584ba4029a59e50b3436/.images/roc-to-can-xcm.png -------------------------------------------------------------------------------- /.images/thippy-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | # Basic 2 | edition = "2021" 3 | hard_tabs = true 4 | max_width = 100 5 | use_small_heuristics = "Max" 6 | 7 | # Imports 8 | imports_granularity = "Crate" 9 | reorder_imports = true 10 | 11 | # Consistency 12 | newline_style = "Unix" 13 | normalize_comments = true 14 | normalize_doc_attributes = true 15 | 16 | # Misc 17 | chain_width = 80 18 | spaces_around_ranges = false 19 | binop_separator = "Back" 20 | reorder_impl_items = false 21 | match_arm_leading_pipes = "Preserve" 22 | match_arm_blocks = false 23 | match_block_trailing_comma = true 24 | trailing_comma = "Vertical" 25 | trailing_semicolon = false 26 | 27 | # Thippy specific 28 | license_template_path = "FILE_HEADER" 29 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lists some code owners. 2 | # 3 | # A codeowner just oversees some part of the codebase. If an owned file is changed then the 4 | # corresponding codeowner receives a review request. An approval of the codeowner might be 5 | # required for merging a PR (depends on repository settings). 6 | # 7 | # For details about syntax, see: 8 | # https://help.github.com/en/articles/about-code-owners 9 | # But here are some important notes: 10 | # 11 | # - Glob syntax is git-like, e.g. `/core` means the core directory in the root, unlike `core` 12 | # which can be everywhere. 13 | # - Multiple owners are supported. 14 | # - Either handle (e.g, @github_user or @github/team) or email can be used. Keep in mind, 15 | # that handles might work better because they are more recognizable on GitHub, 16 | # eyou can use them for mentioning unlike an email. 17 | # - The latest matching rule, if multiple, takes precedence. 18 | 19 | # CI 20 | /.github/ @ng8eke/ci @HCastano @cmichi 21 | /.gitlab-ci.yml @ng8eke/ci @HCastano @cmichi 22 | /scripts/ @ng8eke/ci @HCastano @cmichi 23 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | 'node', 4 | 'runtime', 5 | ] 6 | 7 | [profile.release] 8 | panic = 'unwind' 9 | -------------------------------------------------------------------------------- /LICENSE-GPL3: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | 676 | "CLASSPATH" EXCEPTION TO THE GPL 677 | 678 | Linking this library statically or dynamically with other modules is making 679 | a combined work based on this library. Thus, the terms and conditions of the 680 | GNU General Public License cover the whole combination. 681 | 682 | As a special exception, the copyright holders of this library give you 683 | permission to link this library with independent modules to produce an 684 | executable, regardless of the license terms of these independent modules, 685 | and to copy and distribute the resulting executable under terms of your 686 | choice, provided that you also meet, for each linked independent module, 687 | the terms and conditions of the license of that module. An independent 688 | module is a module which is not derived from or based on this library. 689 | If you modify this library, you may extend this exception to your version 690 | of the library, but you are not obligated to do so. If you do not wish to 691 | do so, delete this exception statement from your version. 692 | 693 | NOTE 694 | 695 | Individual files contain the following tag instead of the full license text. 696 | 697 | SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 698 | 699 | This enables machine processing of license information based on the SPDX 700 | License Identifiers that are here available: http://spdx.org/licenses/ 701 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Thippy ‒- A Smart Contracts Parachain 2 | 3 | This is a node implementation of Thippy, a Substrate parachain for smart contracts. 4 | 5 | 6 | ## Developing Smart Contracts for Thippy 7 | 8 | This node is based on the 'parachain-template', which we configured to use Substrate's smart contracts module ‒ the `contracts` pallet. 9 | This `contracts` pallet takes smart contracts as WebAssembly blobs and defines an API 10 | for everything a smart contract needs (storage access, …). 11 | As long as a programming language compiles to WebAssembly and there exists an implementation 12 | of this API in it, you can write a smart contract for this pallet ‒ and thus for Thippy ‒ in 13 | that language. 14 | 15 | This is a list of languages you can currently choose from: 16 | 17 | * [ask!](https://github.com/patractlabs/ask) for Assembly Script 18 | * The [Solang](https://github.com/hyperledger-labs/solang) compiler for Solidity 19 | 20 | There are also different user interfaces and command-line tools you can use to deploy 21 | or interact with contracts: 22 | 23 | * [polkadot-js](https://polkadot.js.org/apps/) 24 | 25 | If you are looking for a quickstart, we can recommend 26 | [ink!'s Guided Tutorial for Beginners](https://docs.substrate.io/tutorials/v3/ink-workshop/pt1/). 27 | 28 | ## Rococo Deployment 29 | 30 | We have a live deployment of the Thippy parachain on [Rococo](https://wiki.polkadot.network/docs/build-pdk#rococo-testnet) ‒ 31 | a testnet for Polkadot and Kusama parachains. 32 | You can interact with the network through Polkadot JS Apps, 33 | [click here for a direct link to Thippy](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-Thippy-rpc.polkadot.io#/explorer). 34 | 35 | The Thippy parachain uses the Rococo relay chain's native token (ROC) instead of having its own token. 36 | Due to this you'll need ROC in order to deploy contracts on Thippy. 37 | 38 | As a first step, you should create an account. See [here](https://wiki.polkadot.network/docs/learn-account-generation) 39 | for a detailed guide. 40 | 41 | As a second step, you have to get ROC testnet tokens through the [Rococo Faucet](https://wiki.polkadot.network/docs/learn-DOT#getting-rococo-tokens). 42 | This is a chat room in which you need to write: 43 | ``` 44 | !drip YOUR_SS_58_ADDRESS:1002 45 | ``` 46 | The number `1002` is the parachain id of Thippy on Rococo, by supplying it the faucet will teleport ROC 47 | tokens directly to your account on the parachain. 48 | 49 | If everything worked out, the teleported ROC tokens will show up under 50 | [the "Accounts" tab for Thippy](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-Thippy-rpc.polkadot.io#/accounts). 51 | 52 | Once you have ROC on Thippy you can deploy a contract as you would normally. 53 | If you're unsure about this, our [guided tutorial](https://docs.substrate.io/tutorials/v3/ink-workshop/pt1/) 54 | will clarify that for you in no time. 55 | 56 | 57 | ## Run it Locally 58 | 59 | ### Installation 60 | 61 | You need to have executables of both Polkadot and Thippy. 62 | 63 | Binary releases can be found here: 64 | [Polkadot releases](https://github.com/ng8eke/polkadot/releases), 65 | [Thippy releases](https://github.com/ng8eke/Thippy/releases). 66 | 67 | Alternatively you can install (or build) the projects yourself: 68 | 69 | * `cargo install --git https://github.com/ng8eke/polkadot.git --force --locked` 70 | * `cargo install --git https://github.com/ng8eke/Thippy.git --force --locked` 71 | 72 | The `--locked` flag makes the installation (or build) use the same versions as the `Cargo.lock` 73 | in those repositories ‒ ensuring that the last known-to-work version of the dependencies is used. 74 | 75 | ### Launching 76 | 77 | Starting this project is best done using the [`polkadot-launch`](https://github.com/ng8eke/polkadot-launch) tool ‒ 78 | it starts Polkadot and registers the Thippy parachain on it automatically. 79 | 80 | To use `polkadot-launch` you must ensure that you're using Node.js `v14.x` or newer. If 81 | you're on macOS, you must also ensure that your machine's firewall is disabled. You can 82 | do this by going to "System Preferences" > "Security & Privacy" > "Firewall" and ensuring 83 | that it's off. 84 | 85 | Now that you have the prerequisites: 86 | 1. Install it with `yarn global add polkadot-launch` or `npm i polkadot-launch -g` 87 | 1. Check that the paths in `polkadot-launch/config.json` point to the `polkadot` and `Thippy` executables 88 | 1. Launch the network with `polkadot-launch polkadot-launch/config.json` 89 | 90 | At this point you should be able to use [Polkadot JS Apps](https://polkadot.js.org/apps/) 91 | to connect to the Polkadot relay chain nodes as well as the Thippy collator. 92 | 93 | ## Building from source 94 | 95 | Follow the [official installation steps](https://docs.substrate.io/v3/getting-started/installation/) 96 | to set up all Substrate prerequisites. 97 | 98 | Afterwards you can install this node via 99 | 100 | ```bash 101 | git clone https://github.com/ng8eke/Thippy.git 102 | cd Thippy/ 103 | cargo build --release --locked 104 | ``` 105 | 106 | ### Unstable Features 107 | 108 | If you're the type of person that likes to drink your soup before it cools, you might 109 | also be wondering about how to activate unstable `pallet-contracts` features. To do this 110 | you can run the previous installation command with the following flag: 111 | `--features contracts-unstable-interface`. 112 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use vergen::{ConstantsFlags, generate_cargo_keys}; 2 | 3 | const ERROR_MSG: &str = "Failed to generate metadata files"; 4 | 5 | fn main() { 6 | generate_cargo_keys(ConstantsFlags::SHA_SHORT).expect(ERROR_MSG); 7 | 8 | build_script_utils::rerun_if_git_head_changed(); 9 | } 10 | -------------------------------------------------------------------------------- /node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thippy-node" 3 | version = "0.2.0" 4 | authors = ["Annie Lai "] 5 | license = "GPL-3.0-only" 6 | description = "A node implementation for Thippy, a Substrate parachain for smart contracts." 7 | homepage = "https://github.com/ng8eke/thippy" 8 | repository = "https://github.com/ng8eke/thippy" 9 | build = "build.rs" 10 | edition = "2021" 11 | rust-version = "1.56.1" 12 | 13 | [package.metadata.docs.rs] 14 | targets = ["x86_64-unknown-linux-gnu"] 15 | 16 | [build-dependencies] 17 | substrate-build-script-utils = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 18 | 19 | [[bin]] 20 | name = 'thippy' 21 | path = 'src/main.rs' 22 | 23 | [features] 24 | runtime-benchmarks = ['thippy-runtime/runtime-benchmarks'] 25 | contracts-unstable-interface = ['thippy-runtime/contracts-unstable-interface'] 26 | try-runtime = ["thippy-runtime/try-runtime"] 27 | 28 | [dependencies] 29 | clap = { version = "3.0", features = ["derive"] } 30 | derive_more = '0.99.2' 31 | log = '0.4.14' 32 | codec = { package = 'parity-scale-codec', version = '2.0.0' } 33 | serde = { version = '1.0.119', features = ['derive'] } 34 | hex-literal = "0.3.1" 35 | 36 | # RPC related Dependencies 37 | jsonrpc-core = '18.0.0' 38 | 39 | # Local Dependencies 40 | thippy-runtime = { path = '../runtime' } 41 | 42 | # Substrate Dependencies 43 | frame-benchmarking = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 44 | frame-benchmarking-cli = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 45 | try-runtime-cli = { git = "https://github.com/ng8eke/substrate", branch = "master" } 46 | 47 | pallet-transaction-payment-rpc = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 48 | 49 | substrate-frame-rpc-system = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 50 | substrate-prometheus-endpoint = { git = "https://github.com/ng8eke/substrate", branch = "master" } 51 | 52 | ## Substrate Client Dependencies 53 | sc-basic-authorship = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 54 | sc-chain-spec = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 55 | sc-cli = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 56 | sc-client-api = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 57 | sc-consensus = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 58 | sc-executor = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 59 | sc-network = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 60 | sc-keystore = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 61 | sc-rpc = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 62 | sc-rpc-api = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 63 | sc-service = { git = 'https://github.com/ng8eke/substrate', features = ['wasmtime'], branch = "master" } 64 | sc-telemetry = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 65 | sc-transaction-pool = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 66 | sc-transaction-pool-api = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 67 | sc-tracing = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 68 | 69 | ## Substrate Primitive Dependencies 70 | sp-api = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 71 | sp-block-builder = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 72 | sp-blockchain = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 73 | sp-consensus = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 74 | sp-consensus-aura = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 75 | sp-core = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 76 | sp-inherents = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 77 | sp-keystore = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 78 | sp-offchain = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 79 | sp-runtime = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 80 | sp-session = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 81 | sp-timestamp = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 82 | sp-transaction-pool = { git = 'https://github.com/ng8eke/substrate', branch = "master" } 83 | 84 | # Cumulus dependencies 85 | cumulus-client-consensus-aura = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 86 | cumulus-client-consensus-common = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 87 | cumulus-client-collator = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 88 | cumulus-client-cli = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 89 | cumulus-client-network = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 90 | cumulus-client-service = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 91 | cumulus-primitives-core = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 92 | cumulus-primitives-parachain-inherent = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 93 | cumulus-relay-chain-interface = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 94 | cumulus-relay-chain-local = { git = 'https://github.com/ng8eke/cumulus', branch = "master" } 95 | 96 | # Polkadot dependencies 97 | polkadot-cli = { git = 'https://github.com/ng8eke/polkadot', branch = "master" } 98 | polkadot-parachain = { git = 'https://github.com/ng8eke/polkadot', branch = "master" } 99 | polkadot-primitives = { git = 'https://github.com/ng8eke/polkadot', branch = "master" } 100 | polkadot-service = { git = 'https://github.com/ng8eke/polkadot', branch = "master" } 101 | xcm = { git = "https://github.com/ng8eke/polkadot", default-features = false, branch = "master" } 102 | polkadot-test-service = { git = 'https://github.com/ng8eke/polkadot', branch = "master" } 103 | 104 | # Contracts specific packages 105 | pallet-contracts-rpc = { git = "https://github.com/ng8eke/substrate", branch = "master" } 106 | -------------------------------------------------------------------------------- /node/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; 18 | 19 | fn main() { 20 | generate_cargo_keys(); 21 | 22 | rerun_if_git_head_changed(); 23 | } 24 | -------------------------------------------------------------------------------- /node/src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | use thippy_runtime::{AccountId, AuraId, Signature, EXISTENTIAL_DEPOSIT}; 18 | use cumulus_primitives_core::ParaId; 19 | use hex_literal::hex; 20 | use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; 21 | use sc_service::ChainType; 22 | use serde::{Deserialize, Serialize}; 23 | use sp_core::{crypto::UncheckedInto, sr25519, Pair, Public}; 24 | use sp_runtime::traits::{IdentifyAccount, Verify}; 25 | 26 | /// The ID of this Parachain as registered on the Relay Chain. 27 | /// 28 | /// TODO: When we register as a common good parachain this will need to change. 29 | pub const PARA_ID: u32 = 1002; 30 | 31 | /// Specialized `ChainSpec` for the normal parachain runtime. 32 | pub type ChainSpec = sc_service::GenericChainSpec; 33 | 34 | /// The default XCM version to set in genesis config. 35 | const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; 36 | 37 | /// Helper function to generate a crypto pair from seed 38 | pub fn get_public_from_seed(seed: &str) -> ::Public { 39 | TPublic::Pair::from_string(&format!("//{}", seed), None) 40 | .expect("static values are valid; qed") 41 | .public() 42 | } 43 | 44 | /// The extensions for the [`ChainSpec`]. 45 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] 46 | #[serde(deny_unknown_fields)] 47 | pub struct Extensions { 48 | /// The relay chain of the Parachain. 49 | pub relay_chain: String, 50 | /// The id of the Parachain. 51 | pub para_id: u32, 52 | } 53 | 54 | impl Extensions { 55 | /// Try to get the extension from the given `ChainSpec`. 56 | pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { 57 | sc_chain_spec::get_extension(chain_spec.extensions()) 58 | } 59 | } 60 | 61 | type AccountPublic = ::Signer; 62 | 63 | /// Generate collator keys from seed. 64 | /// 65 | /// This function's return type must always match the session keys of the chain in tuple format. 66 | pub fn get_collator_keys_from_seed(seed: &str) -> AuraId { 67 | get_public_from_seed::(seed) 68 | } 69 | 70 | /// Helper function to generate an account ID from seed 71 | pub fn get_account_id_from_seed(seed: &str) -> AccountId 72 | where 73 | AccountPublic: From<::Public>, 74 | { 75 | AccountPublic::from(get_public_from_seed::(seed)).into_account() 76 | } 77 | 78 | /// Generate the session keys from individual elements. 79 | /// 80 | /// The input must be a tuple of individual keys (a single arg for now since we have just one key). 81 | pub fn thippy_session_keys(keys: AuraId) -> thippy_runtime::SessionKeys { 82 | thippy_runtime::SessionKeys { aura: keys } 83 | } 84 | 85 | pub fn development_config() -> ChainSpec { 86 | // Give your base currency a unit name and decimal places 87 | let mut properties = sc_chain_spec::Properties::new(); 88 | properties.insert("tokenSymbol".into(), "ROC".into()); 89 | properties.insert("tokenDecimals".into(), 12.into()); 90 | properties.insert("ss58Format".into(), 42.into()); 91 | 92 | ChainSpec::from_genesis( 93 | // Name 94 | "Development", 95 | // ID 96 | "dev", 97 | ChainType::Development, 98 | move || { 99 | thippy_genesis( 100 | // initial collators. 101 | vec![ 102 | ( 103 | get_account_id_from_seed::("Alice"), 104 | get_collator_keys_from_seed("Alice"), 105 | ), 106 | ( 107 | get_account_id_from_seed::("Bob"), 108 | get_collator_keys_from_seed("Bob"), 109 | ), 110 | ], 111 | vec![ 112 | get_account_id_from_seed::("Alice"), 113 | get_account_id_from_seed::("Bob"), 114 | get_account_id_from_seed::("Charlie"), 115 | get_account_id_from_seed::("Dave"), 116 | get_account_id_from_seed::("Eve"), 117 | get_account_id_from_seed::("Ferdie"), 118 | get_account_id_from_seed::("Alice//stash"), 119 | get_account_id_from_seed::("Bob//stash"), 120 | get_account_id_from_seed::("Charlie//stash"), 121 | get_account_id_from_seed::("Dave//stash"), 122 | get_account_id_from_seed::("Eve//stash"), 123 | get_account_id_from_seed::("Ferdie//stash"), 124 | ], 125 | PARA_ID.into(), 126 | ) 127 | }, 128 | Vec::new(), 129 | None, 130 | None, 131 | None, 132 | None, 133 | Extensions { 134 | relay_chain: "rococo-local".into(), // You MUST set this to the correct network! 135 | para_id: PARA_ID, 136 | }, 137 | ) 138 | } 139 | 140 | pub fn local_testnet_config() -> ChainSpec { 141 | // Give your base currency a unit name and decimal places 142 | let mut properties = sc_chain_spec::Properties::new(); 143 | properties.insert("tokenSymbol".into(), "ROC".into()); 144 | properties.insert("tokenDecimals".into(), 12.into()); 145 | properties.insert("ss58Format".into(), 42.into()); 146 | 147 | ChainSpec::from_genesis( 148 | // Name 149 | "Thippy", 150 | // ID 151 | "thippy_local", 152 | ChainType::Local, 153 | move || { 154 | thippy_genesis( 155 | // initial collators. 156 | vec![ 157 | ( 158 | get_account_id_from_seed::("Alice"), 159 | get_collator_keys_from_seed("Alice"), 160 | ), 161 | ( 162 | get_account_id_from_seed::("Bob"), 163 | get_collator_keys_from_seed("Bob"), 164 | ), 165 | ], 166 | vec![ 167 | get_account_id_from_seed::("Alice"), 168 | get_account_id_from_seed::("Bob"), 169 | get_account_id_from_seed::("Charlie"), 170 | get_account_id_from_seed::("Dave"), 171 | get_account_id_from_seed::("Eve"), 172 | get_account_id_from_seed::("Ferdie"), 173 | get_account_id_from_seed::("Alice//stash"), 174 | get_account_id_from_seed::("Bob//stash"), 175 | get_account_id_from_seed::("Charlie//stash"), 176 | get_account_id_from_seed::("Dave//stash"), 177 | get_account_id_from_seed::("Eve//stash"), 178 | get_account_id_from_seed::("Ferdie//stash"), 179 | ], 180 | PARA_ID.into(), 181 | ) 182 | }, 183 | // Bootnodes 184 | Vec::new(), 185 | // Telemetry 186 | None, 187 | // Protocol ID 188 | Some("thippy-local"), 189 | // Fork ID 190 | None, 191 | // Properties 192 | Some(properties), 193 | // Extensions 194 | Extensions { 195 | relay_chain: "rococo-local".into(), // You MUST set this to the correct network! 196 | para_id: PARA_ID, 197 | }, 198 | ) 199 | } 200 | 201 | pub fn rococo_testnet_config() -> ChainSpec { 202 | // Give your base currency a unit name and decimal places 203 | let mut properties = sc_chain_spec::Properties::new(); 204 | properties.insert("tokenSymbol".into(), "ROC".into()); 205 | properties.insert("tokenDecimals".into(), 12.into()); 206 | 207 | ChainSpec::from_genesis( 208 | // Name 209 | "Thippy", 210 | // ID 211 | "thippy_rococo", 212 | ChainType::Live, 213 | move || { 214 | thippy_genesis( 215 | // Initial collators. 216 | // 217 | // Generated with: ./thippy_setup.sh 4. 218 | // 219 | // Note that these are SR25519 Aura public keys. 220 | // 221 | // Ask DevOps team for the $SECRET 🤫. 222 | vec![ 223 | // 5GKFbTTgrVS4Vz1UWWHPqMZQNFWZtqo7H2KpCDyYhEL3aS26 224 | ( 225 | hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] 226 | .into(), 227 | hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] 228 | .unchecked_into(), 229 | ), 230 | // 5EPRJHm2GpABVWcwnAujcrhnrjFZyDGd5TwKFzkBoGgdRyv2 231 | ( 232 | hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] 233 | .into(), 234 | hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] 235 | .unchecked_into(), 236 | ), 237 | // 5GH62vrJrVZxLREcHzm2PR5uTLAT5RQMJitoztCGyaP4o3uM 238 | ( 239 | hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] 240 | .into(), 241 | hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] 242 | .unchecked_into(), 243 | ), 244 | // 5FHfoJDLdjRYX5KXLRqMDYBbWrwHLMtti21uK4QByUoUAbJF 245 | ( 246 | hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] 247 | .into(), 248 | hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] 249 | .unchecked_into(), 250 | ), 251 | ], 252 | // Warning: The configuration for a production chain should not contain 253 | // any endowed accounts here, otherwise it'll be minting extra native tokens 254 | // from the relay chain on the parachain. 255 | vec![ 256 | // NOTE: Remove endowed accounts if deployed on other relay chains. 257 | // Endowed accounts 258 | hex!["baa78c7154c7f82d6d377177e20bcab65d327eca0086513f9964f5a0f6bdad56"].into(), 259 | // AccountId of an account which `ink-waterfall` uses for automated testing 260 | hex!["0e47e2344d523c3cc5c34394b0d58b9a4200e813a038e6c5a6163cc07d70b069"].into(), 261 | ], 262 | PARA_ID.into(), 263 | ) 264 | }, 265 | // Bootnodes 266 | vec![ 267 | "/ip4/34.90.191.237/tcp/30333/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj" 268 | .parse() 269 | .expect("MultiaddrWithPeerId"), 270 | "/ip4/35.204.68.28/tcp/30333/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh" 271 | .parse() 272 | .expect("MultiaddrWithPeerId"), 273 | "/ip4/34.90.139.15/tcp/30333/p2p/12D3KooWEVU8AFNary4nP4qEnEcwJaRuy59Wefekzdu9pKbnVEhk" 274 | .parse() 275 | .expect("MultiaddrWithPeerId"), 276 | "/ip4/35.204.99.97/tcp/30333/p2p/12D3KooWP6pV3ZmcXzGDjv8ZMgA6nZxfAKDxSz4VNiLx6vVCQgJX" 277 | .parse() 278 | .expect("MultiaddrWithPeerId"), 279 | ], 280 | // Telemetry 281 | None, 282 | // Protocol ID 283 | Some("thippy-rococo"), 284 | // Fork ID 285 | None, 286 | // Properties 287 | Some(properties), 288 | // Extensions 289 | Extensions { relay_chain: "rococo".into(), para_id: PARA_ID }, 290 | ) 291 | } 292 | 293 | fn thippy_genesis( 294 | invulnerables: Vec<(AccountId, AuraId)>, 295 | endowed_accounts: Vec, 296 | id: ParaId, 297 | ) -> thippy_runtime::GenesisConfig { 298 | thippy_runtime::GenesisConfig { 299 | system: thippy_runtime::SystemConfig { 300 | code: thippy_runtime::WASM_BINARY 301 | .expect("WASM binary was not build, please build it!") 302 | .to_vec(), 303 | }, 304 | balances: thippy_runtime::BalancesConfig { 305 | balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), 306 | }, 307 | parachain_info: thippy_runtime::ParachainInfoConfig { parachain_id: id }, 308 | collator_selection: thippy_runtime::CollatorSelectionConfig { 309 | invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), 310 | candidacy_bond: EXISTENTIAL_DEPOSIT * 16, 311 | ..Default::default() 312 | }, 313 | session: thippy_runtime::SessionConfig { 314 | keys: invulnerables 315 | .into_iter() 316 | .map(|(acc, aura)| { 317 | ( 318 | acc.clone(), // account id 319 | acc, // validator id 320 | thippy_session_keys(aura), // session keys 321 | ) 322 | }) 323 | .collect(), 324 | }, 325 | // no need to pass anything to aura, in fact it will panic if we do. Session will take care 326 | // of this. 327 | aura: Default::default(), 328 | aura_ext: Default::default(), 329 | parachain_system: Default::default(), 330 | polkadot_xcm: thippy_runtime::PolkadotXcmConfig { 331 | safe_xcm_version: Some(SAFE_XCM_VERSION), 332 | }, 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /node/src/cli.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | use crate::chain_spec; 18 | use clap::{AppSettings, Parser}; 19 | use std::path::PathBuf; 20 | 21 | /// Sub-commands supported by the collator. 22 | #[derive(Debug, clap::Subcommand)] 23 | pub enum Subcommand { 24 | /// Export the genesis state of the parachain. 25 | #[clap(name = "export-genesis-state")] 26 | ExportGenesisState(ExportGenesisStateCommand), 27 | 28 | /// Export the genesis wasm of the parachain. 29 | #[clap(name = "export-genesis-wasm")] 30 | ExportGenesisWasm(ExportGenesisWasmCommand), 31 | 32 | /// Build a chain specification. 33 | BuildSpec(sc_cli::BuildSpecCmd), 34 | 35 | /// Validate blocks. 36 | CheckBlock(sc_cli::CheckBlockCmd), 37 | 38 | /// Export blocks. 39 | ExportBlocks(sc_cli::ExportBlocksCmd), 40 | 41 | /// Export the state of a given block into a chain spec. 42 | ExportState(sc_cli::ExportStateCmd), 43 | 44 | /// Import blocks. 45 | ImportBlocks(sc_cli::ImportBlocksCmd), 46 | 47 | /// Remove the whole chain. 48 | PurgeChain(cumulus_client_cli::PurgeChainCmd), 49 | 50 | /// Revert the chain to a previous state. 51 | Revert(sc_cli::RevertCmd), 52 | 53 | /// The custom benchmark subcommmand benchmarking runtime pallets. 54 | #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] 55 | Benchmark(frame_benchmarking_cli::BenchmarkCmd), 56 | 57 | /// Try some testing command against a specified runtime state. 58 | TryRuntime(try_runtime_cli::TryRuntimeCmd), 59 | } 60 | 61 | /// Command for exporting the genesis state of the parachain 62 | #[derive(Debug, Parser)] 63 | pub struct ExportGenesisStateCommand { 64 | /// Output file name or stdout if unspecified. 65 | #[clap(parse(from_os_str))] 66 | pub output: Option, 67 | 68 | /// Write output in binary. Default is to write in hex. 69 | #[clap(short, long)] 70 | pub raw: bool, 71 | 72 | /// The name of the chain for that the genesis state should be exported. 73 | #[clap(long)] 74 | pub chain: Option, 75 | } 76 | 77 | /// Command for exporting the genesis wasm file. 78 | #[derive(Debug, Parser)] 79 | pub struct ExportGenesisWasmCommand { 80 | /// Output file name or stdout if unspecified. 81 | #[clap(parse(from_os_str))] 82 | pub output: Option, 83 | 84 | /// Write output in binary. Default is to write in hex. 85 | #[clap(short, long)] 86 | pub raw: bool, 87 | 88 | /// The name of the chain for that the genesis wasm file should be exported. 89 | #[clap(long)] 90 | pub chain: Option, 91 | } 92 | 93 | #[derive(Debug, Parser)] 94 | #[clap(setting( 95 | AppSettings::PropagateVersion | 96 | AppSettings::ArgsNegateSubcommands | 97 | AppSettings::SubcommandsNegateReqs, 98 | ))] 99 | pub struct Cli { 100 | #[clap(subcommand)] 101 | pub subcommand: Option, 102 | 103 | #[clap(flatten)] 104 | pub run: cumulus_client_cli::RunCmd, 105 | 106 | /// Relay chain arguments 107 | #[clap(raw = true)] 108 | pub relay_chain_args: Vec, 109 | } 110 | 111 | #[derive(Debug)] 112 | pub struct RelayChainCli { 113 | /// The actual relay chain cli object. 114 | pub base: polkadot_cli::RunCmd, 115 | 116 | /// Optional chain id that should be passed to the relay chain. 117 | pub chain_id: Option, 118 | 119 | /// The base path that should be used by the relay chain. 120 | pub base_path: Option, 121 | } 122 | 123 | impl RelayChainCli { 124 | /// Parse the relay chain CLI parameters using the para chain `Configuration`. 125 | pub fn new<'a>( 126 | para_config: &sc_service::Configuration, 127 | relay_chain_args: impl Iterator, 128 | ) -> Self { 129 | let extension = chain_spec::Extensions::try_get(&*para_config.chain_spec); 130 | let chain_id = extension.map(|e| e.relay_chain.clone()); 131 | let base_path = para_config.base_path.as_ref().map(|x| x.path().join("polkadot")); 132 | Self { base_path, chain_id, base: polkadot_cli::RunCmd::parse_from(relay_chain_args) } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /node/src/command.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | use crate::{ 18 | chain_spec, 19 | cli::{Cli, RelayChainCli, Subcommand}, 20 | service::{new_partial, ThippyRuntimeExecutor}, 21 | }; 22 | use thippy_runtime::{Block, RuntimeApi}; 23 | use codec::Encode; 24 | use cumulus_client_service::genesis::generate_genesis_block; 25 | use cumulus_primitives_core::ParaId; 26 | use log::info; 27 | use polkadot_parachain::primitives::AccountIdConversion; 28 | use sc_cli::{ 29 | ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, 30 | NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli, 31 | }; 32 | use sc_service::{ 33 | config::{BasePath, PrometheusConfig}, 34 | TaskManager, 35 | }; 36 | use sp_core::hexdisplay::HexDisplay; 37 | use sp_runtime::traits::Block as BlockT; 38 | use std::{io::Write, net::SocketAddr}; 39 | 40 | fn load_spec(id: &str) -> std::result::Result, String> { 41 | Ok(match id { 42 | "dev" => Box::new(chain_spec::development_config()), 43 | "thippy-rococo" => Box::new(chain_spec::rococo_testnet_config()), 44 | "" | "local" => Box::new(chain_spec::local_testnet_config()), 45 | path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?), 46 | }) 47 | } 48 | 49 | impl SubstrateCli for Cli { 50 | fn impl_name() -> String { 51 | "Thippy".into() 52 | } 53 | 54 | fn impl_version() -> String { 55 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 56 | } 57 | 58 | fn description() -> String { 59 | format!( 60 | "Thippy Node\n\nThe command-line arguments provided first will be \ 61 | passed to the parachain node, while the arguments provided after -- will be passed \ 62 | to the relay chain node.\n\n\ 63 | {} -- ", 64 | Self::executable_name() 65 | ) 66 | } 67 | 68 | fn author() -> String { 69 | env!("CARGO_PKG_AUTHORS").into() 70 | } 71 | 72 | fn support_url() -> String { 73 | "https://github.com/ng8eke/thippy/issues/new".into() 74 | } 75 | 76 | fn copyright_start_year() -> i32 { 77 | 2020 78 | } 79 | 80 | fn load_spec(&self, id: &str) -> std::result::Result, String> { 81 | load_spec(id) 82 | } 83 | 84 | fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { 85 | &thippy_runtime::VERSION 86 | } 87 | } 88 | 89 | impl SubstrateCli for RelayChainCli { 90 | fn impl_name() -> String { 91 | "Thippy Node".into() 92 | } 93 | 94 | fn impl_version() -> String { 95 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 96 | } 97 | 98 | fn description() -> String { 99 | "Thippy Node\n\nThe command-line arguments provided first will be \ 100 | passed to the parachain node, while the arguments provided after -- will be passed \ 101 | to the relaychain node.\n\n\ 102 | parachain-collator [parachain-args] -- [relaychain-args]" 103 | .into() 104 | } 105 | 106 | fn author() -> String { 107 | env!("CARGO_PKG_AUTHORS").into() 108 | } 109 | 110 | fn support_url() -> String { 111 | "https://github.com/ng8eke/thippy/issues/new".into() 112 | } 113 | 114 | fn copyright_start_year() -> i32 { 115 | 2020 116 | } 117 | 118 | fn load_spec(&self, id: &str) -> std::result::Result, String> { 119 | polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id) 120 | } 121 | 122 | fn native_runtime_version(chain_spec: &Box) -> &'static RuntimeVersion { 123 | polkadot_cli::Cli::native_runtime_version(chain_spec) 124 | } 125 | } 126 | 127 | #[allow(clippy::borrowed_box)] 128 | fn extract_genesis_wasm(chain_spec: &Box) -> Result> { 129 | let mut storage = chain_spec.build_storage()?; 130 | 131 | storage 132 | .top 133 | .remove(sp_core::storage::well_known_keys::CODE) 134 | .ok_or_else(|| "Could not find wasm file in genesis state!".into()) 135 | } 136 | 137 | macro_rules! construct_async_run { 138 | (|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{ 139 | let runner = $cli.create_runner($cmd)?; 140 | runner.async_run(|$config| { 141 | let $components = new_partial::< 142 | RuntimeApi, 143 | ThippyRuntimeExecutor, 144 | _ 145 | >( 146 | &$config, 147 | crate::service::parachain_build_import_queue, 148 | )?; 149 | let task_manager = $components.task_manager; 150 | { $( $code )* }.map(|v| (v, task_manager)) 151 | }) 152 | }} 153 | } 154 | 155 | /// Parse command line arguments into service configuration. 156 | pub fn run() -> Result<()> { 157 | let cli = Cli::from_args(); 158 | 159 | match &cli.subcommand { 160 | Some(Subcommand::BuildSpec(cmd)) => { 161 | let runner = cli.create_runner(cmd)?; 162 | runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) 163 | }, 164 | Some(Subcommand::CheckBlock(cmd)) => { 165 | construct_async_run!(|components, cli, cmd, config| { 166 | Ok(cmd.run(components.client, components.import_queue)) 167 | }) 168 | }, 169 | Some(Subcommand::ExportBlocks(cmd)) => { 170 | construct_async_run!(|components, cli, cmd, config| { 171 | Ok(cmd.run(components.client, config.database)) 172 | }) 173 | }, 174 | Some(Subcommand::ExportState(cmd)) => { 175 | construct_async_run!(|components, cli, cmd, config| { 176 | Ok(cmd.run(components.client, config.chain_spec)) 177 | }) 178 | }, 179 | Some(Subcommand::ImportBlocks(cmd)) => { 180 | construct_async_run!(|components, cli, cmd, config| { 181 | Ok(cmd.run(components.client, components.import_queue)) 182 | }) 183 | }, 184 | Some(Subcommand::PurgeChain(cmd)) => { 185 | let runner = cli.create_runner(cmd)?; 186 | 187 | runner.sync_run(|config| { 188 | let polkadot_cli = RelayChainCli::new( 189 | &config, 190 | [RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()), 191 | ); 192 | 193 | let polkadot_config = SubstrateCli::create_configuration( 194 | &polkadot_cli, 195 | &polkadot_cli, 196 | config.tokio_handle.clone(), 197 | ) 198 | .map_err(|err| format!("Relay chain argument error: {}", err))?; 199 | 200 | cmd.run(config, polkadot_config) 201 | }) 202 | }, 203 | Some(Subcommand::Revert(cmd)) => { 204 | construct_async_run!(|components, cli, cmd, config| { 205 | Ok(cmd.run(components.client, components.backend)) 206 | }) 207 | }, 208 | Some(Subcommand::ExportGenesisState(params)) => { 209 | let mut builder = sc_cli::LoggerBuilder::new(""); 210 | builder.with_profiling(sc_tracing::TracingReceiver::Log, ""); 211 | let _ = builder.init(); 212 | 213 | let spec = load_spec(¶ms.chain.clone().unwrap_or_default())?; 214 | let state_version = Cli::native_runtime_version(&spec).state_version(); 215 | 216 | let block: Block = generate_genesis_block(&spec, state_version)?; 217 | 218 | let raw_header = block.header().encode(); 219 | let output_buf = if params.raw { 220 | raw_header 221 | } else { 222 | format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes() 223 | }; 224 | 225 | if let Some(output) = ¶ms.output { 226 | std::fs::write(output, output_buf)?; 227 | } else { 228 | std::io::stdout().write_all(&output_buf)?; 229 | } 230 | 231 | Ok(()) 232 | }, 233 | Some(Subcommand::ExportGenesisWasm(params)) => { 234 | let mut builder = sc_cli::LoggerBuilder::new(""); 235 | builder.with_profiling(sc_tracing::TracingReceiver::Log, ""); 236 | let _ = builder.init(); 237 | 238 | let raw_wasm_blob = 239 | extract_genesis_wasm(&cli.load_spec(¶ms.chain.clone().unwrap_or_default())?)?; 240 | let output_buf = if params.raw { 241 | raw_wasm_blob 242 | } else { 243 | format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes() 244 | }; 245 | 246 | if let Some(output) = ¶ms.output { 247 | std::fs::write(output, output_buf)?; 248 | } else { 249 | std::io::stdout().write_all(&output_buf)?; 250 | } 251 | 252 | Ok(()) 253 | }, 254 | Some(Subcommand::Benchmark(cmd)) => 255 | if cfg!(feature = "runtime-benchmarks") { 256 | let runner = cli.create_runner(cmd)?; 257 | 258 | runner.sync_run(|config| cmd.run::(config)) 259 | } else { 260 | Err("Benchmarking wasn't enabled when building the node. \ 261 | You can enable it with `--features runtime-benchmarks`." 262 | .into()) 263 | }, 264 | Some(Subcommand::TryRuntime(cmd)) => { 265 | if cfg!(feature = "try-runtime") { 266 | let runner = cli.create_runner(cmd)?; 267 | 268 | // grab the task manager. 269 | let registry = &runner.config().prometheus_config.as_ref().map(|cfg| &cfg.registry); 270 | let task_manager = 271 | TaskManager::new(runner.config().tokio_handle.clone(), *registry) 272 | .map_err(|e| format!("Error: {:?}", e))?; 273 | 274 | runner.async_run(|config| { 275 | Ok((cmd.run::(config), task_manager)) 276 | }) 277 | } else { 278 | Err("Try-runtime must be enabled by `--features try-runtime`.".into()) 279 | } 280 | }, 281 | None => { 282 | let runner = cli.create_runner(&cli.run.normalize())?; 283 | 284 | runner.run_node_until_exit(|config| async move { 285 | let _ = &cli; 286 | let para_id = chain_spec::Extensions::try_get(&*config.chain_spec) 287 | .map(|e| e.para_id) 288 | .ok_or("Could not find parachain ID in chain-spec.")?; 289 | 290 | let polkadot_cli = RelayChainCli::new( 291 | &config, 292 | [RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()), 293 | ); 294 | 295 | let id = ParaId::from(para_id); 296 | 297 | let parachain_account = 298 | AccountIdConversion::::into_account(&id); 299 | 300 | let state_version = 301 | RelayChainCli::native_runtime_version(&config.chain_spec).state_version(); 302 | let block: Block = generate_genesis_block(&config.chain_spec, state_version) 303 | .map_err(|e| format!("{:?}", e))?; 304 | 305 | let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode())); 306 | 307 | let tokio_handle = config.tokio_handle.clone(); 308 | let polkadot_config = 309 | SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle) 310 | .map_err(|err| format!("Relay chain argument error: {}", err))?; 311 | 312 | info!("Parachain id: {:?}", id); 313 | info!("Parachain Account: {}", parachain_account); 314 | info!("Parachain genesis state: {}", genesis_state); 315 | info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); 316 | 317 | crate::service::start_parachain_node(config, polkadot_config, id) 318 | .await 319 | .map(|r| r.0) 320 | .map_err(Into::into) 321 | }) 322 | }, 323 | } 324 | } 325 | 326 | impl DefaultConfigurationValues for RelayChainCli { 327 | fn p2p_listen_port() -> u16 { 328 | 30334 329 | } 330 | 331 | fn rpc_ws_listen_port() -> u16 { 332 | 9945 333 | } 334 | 335 | fn rpc_http_listen_port() -> u16 { 336 | 9934 337 | } 338 | 339 | fn prometheus_listen_port() -> u16 { 340 | 9616 341 | } 342 | } 343 | 344 | impl CliConfiguration for RelayChainCli { 345 | fn shared_params(&self) -> &SharedParams { 346 | self.base.base.shared_params() 347 | } 348 | 349 | fn import_params(&self) -> Option<&ImportParams> { 350 | self.base.base.import_params() 351 | } 352 | 353 | fn network_params(&self) -> Option<&NetworkParams> { 354 | self.base.base.network_params() 355 | } 356 | 357 | fn keystore_params(&self) -> Option<&KeystoreParams> { 358 | self.base.base.keystore_params() 359 | } 360 | 361 | fn base_path(&self) -> Result> { 362 | Ok(self 363 | .shared_params() 364 | .base_path() 365 | .or_else(|| self.base_path.clone().map(Into::into))) 366 | } 367 | 368 | fn rpc_http(&self, default_listen_port: u16) -> Result> { 369 | self.base.base.rpc_http(default_listen_port) 370 | } 371 | 372 | fn rpc_ipc(&self) -> Result> { 373 | self.base.base.rpc_ipc() 374 | } 375 | 376 | fn rpc_ws(&self, default_listen_port: u16) -> Result> { 377 | self.base.base.rpc_ws(default_listen_port) 378 | } 379 | 380 | fn prometheus_config( 381 | &self, 382 | default_listen_port: u16, 383 | chain_spec: &Box, 384 | ) -> Result> { 385 | self.base.base.prometheus_config(default_listen_port, chain_spec) 386 | } 387 | 388 | fn init( 389 | &self, 390 | _support_url: &String, 391 | _impl_version: &String, 392 | _logger_hook: F, 393 | _config: &sc_service::Configuration, 394 | ) -> Result<()> 395 | where 396 | F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), 397 | { 398 | unreachable!("PolkadotCli is never initialized; qed"); 399 | } 400 | 401 | fn chain_id(&self, is_dev: bool) -> Result { 402 | let chain_id = self.base.base.chain_id(is_dev)?; 403 | 404 | Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id }) 405 | } 406 | 407 | fn role(&self, is_dev: bool) -> Result { 408 | self.base.base.role(is_dev) 409 | } 410 | 411 | fn transaction_pool(&self) -> Result { 412 | self.base.base.transaction_pool() 413 | } 414 | 415 | fn state_cache_child_ratio(&self) -> Result> { 416 | self.base.base.state_cache_child_ratio() 417 | } 418 | 419 | fn rpc_methods(&self) -> Result { 420 | self.base.base.rpc_methods() 421 | } 422 | 423 | fn rpc_ws_max_connections(&self) -> Result> { 424 | self.base.base.rpc_ws_max_connections() 425 | } 426 | 427 | fn rpc_cors(&self, is_dev: bool) -> Result>> { 428 | self.base.base.rpc_cors(is_dev) 429 | } 430 | 431 | fn default_heap_pages(&self) -> Result> { 432 | self.base.base.default_heap_pages() 433 | } 434 | 435 | fn force_authoring(&self) -> Result { 436 | self.base.base.force_authoring() 437 | } 438 | 439 | fn disable_grandpa(&self) -> Result { 440 | self.base.base.disable_grandpa() 441 | } 442 | 443 | fn max_runtime_instances(&self) -> Result> { 444 | self.base.base.max_runtime_instances() 445 | } 446 | 447 | fn announce_block(&self) -> Result { 448 | self.base.base.announce_block() 449 | } 450 | 451 | fn telemetry_endpoints( 452 | &self, 453 | chain_spec: &Box, 454 | ) -> Result> { 455 | self.base.base.telemetry_endpoints(chain_spec) 456 | } 457 | } 458 | -------------------------------------------------------------------------------- /node/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | pub mod chain_spec; 18 | mod rpc; 19 | pub mod service; 20 | -------------------------------------------------------------------------------- /node/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | //! Substrate Parachain Node CLI 18 | 19 | #![warn(missing_docs)] 20 | 21 | mod chain_spec; 22 | #[macro_use] 23 | mod service; 24 | mod cli; 25 | mod command; 26 | mod rpc; 27 | 28 | fn main() -> sc_cli::Result<()> { 29 | command::run() 30 | } 31 | -------------------------------------------------------------------------------- /node/src/rpc.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | //! A collection of node-specific RPC methods. 18 | //! Substrate provides the `sc-rpc` crate, which defines the core RPC layer 19 | //! used by Substrate nodes. This file extends those RPC definitions with 20 | //! capabilities that are specific to this project's runtime configuration. 21 | 22 | #![warn(missing_docs)] 23 | 24 | use std::sync::Arc; 25 | 26 | use thippy_runtime::{opaque::Block, AccountId, Balance, BlockNumber, Hash, Index as Nonce}; 27 | use pallet_contracts_rpc::{Contracts, ContractsApi}; 28 | 29 | use sc_client_api::AuxStore; 30 | pub use sc_rpc::{DenyUnsafe, SubscriptionTaskExecutor}; 31 | use sc_transaction_pool_api::TransactionPool; 32 | use sp_api::ProvideRuntimeApi; 33 | use sp_block_builder::BlockBuilder; 34 | use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; 35 | 36 | /// A type representing all RPC extensions. 37 | pub type RpcExtension = jsonrpc_core::IoHandler; 38 | 39 | /// Full client dependencies 40 | pub struct FullDeps { 41 | /// The client instance to use. 42 | pub client: Arc, 43 | /// Transaction pool instance. 44 | pub pool: Arc

, 45 | /// Whether to deny unsafe calls 46 | pub deny_unsafe: DenyUnsafe, 47 | } 48 | 49 | /// Instantiate all RPC extensions. 50 | pub fn create_full(deps: FullDeps) -> RpcExtension 51 | where 52 | C: ProvideRuntimeApi 53 | + HeaderBackend 54 | + AuxStore 55 | + HeaderMetadata 56 | + Send 57 | + Sync 58 | + 'static, 59 | C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, 60 | C::Api: substrate_frame_rpc_system::AccountNonceApi, 61 | C::Api: pallet_contracts_rpc::ContractsRuntimeApi, 62 | C::Api: BlockBuilder, 63 | P: TransactionPool + Sync + Send + 'static, 64 | { 65 | use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; 66 | use substrate_frame_rpc_system::{FullSystem, SystemApi}; 67 | 68 | let mut io = jsonrpc_core::IoHandler::default(); 69 | let FullDeps { client, pool, deny_unsafe } = deps; 70 | 71 | io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))); 72 | io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))); 73 | io.extend_with(ContractsApi::to_delegate(Contracts::new(client))); 74 | 75 | io 76 | } 77 | -------------------------------------------------------------------------------- /node/src/service.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. 18 | 19 | // std 20 | use std::{sync::Arc, time::Duration}; 21 | 22 | // Local Runtime Types 23 | use thippy_runtime::{ 24 | opaque::Block, AccountId, Balance, BlockNumber, Hash, Index as Nonce, RuntimeApi, 25 | }; 26 | 27 | // Cumulus Imports 28 | use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion}; 29 | use cumulus_client_consensus_common::ParachainConsensus; 30 | use cumulus_client_network::BlockAnnounceValidator; 31 | use cumulus_client_service::{ 32 | prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, 33 | }; 34 | use cumulus_primitives_core::ParaId; 35 | use cumulus_relay_chain_interface::RelayChainInterface; 36 | use cumulus_relay_chain_local::build_relay_chain_interface; 37 | 38 | // Substrate Imports 39 | use sc_client_api::ExecutorProvider; 40 | use sc_executor::NativeElseWasmExecutor; 41 | use sc_network::NetworkService; 42 | use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager}; 43 | use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; 44 | use sp_api::ConstructRuntimeApi; 45 | use sp_consensus::SlotData; 46 | use sp_keystore::SyncCryptoStorePtr; 47 | use sp_runtime::traits::BlakeTwo256; 48 | use substrate_prometheus_endpoint::Registry; 49 | 50 | /// Native executor instance. 51 | pub struct ThippyRuntimeExecutor; 52 | 53 | impl sc_executor::NativeExecutionDispatch for ThippyRuntimeExecutor { 54 | type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; 55 | 56 | fn dispatch(method: &str, data: &[u8]) -> Option> { 57 | thippy_runtime::api::dispatch(method, data) 58 | } 59 | 60 | fn native_version() -> sc_executor::NativeVersion { 61 | thippy_runtime::native_version() 62 | } 63 | } 64 | 65 | /// Starts a `ServiceBuilder` for a full service. 66 | /// 67 | /// Use this macro if you don't actually need the full service, but just the builder in order to 68 | /// be able to perform chain operations. 69 | #[allow(clippy::type_complexity)] 70 | pub fn new_partial( 71 | config: &Configuration, 72 | build_import_queue: BIQ, 73 | ) -> Result< 74 | PartialComponents< 75 | TFullClient>, 76 | TFullBackend, 77 | (), 78 | sc_consensus::DefaultImportQueue< 79 | Block, 80 | TFullClient>, 81 | >, 82 | sc_transaction_pool::FullPool< 83 | Block, 84 | TFullClient>, 85 | >, 86 | (Option, Option), 87 | >, 88 | sc_service::Error, 89 | > 90 | where 91 | RuntimeApi: ConstructRuntimeApi>> 92 | + Send 93 | + Sync 94 | + 'static, 95 | RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue 96 | + sp_api::Metadata 97 | + sp_session::SessionKeys 98 | + sp_api::ApiExt< 99 | Block, 100 | StateBackend = sc_client_api::StateBackendFor, Block>, 101 | > + sp_offchain::OffchainWorkerApi 102 | + sp_block_builder::BlockBuilder, 103 | sc_client_api::StateBackendFor, Block>: sp_api::StateBackend, 104 | Executor: sc_executor::NativeExecutionDispatch + 'static, 105 | BIQ: FnOnce( 106 | Arc>>, 107 | &Configuration, 108 | Option, 109 | &TaskManager, 110 | ) -> Result< 111 | sc_consensus::DefaultImportQueue< 112 | Block, 113 | TFullClient>, 114 | >, 115 | sc_service::Error, 116 | >, 117 | { 118 | let telemetry = config 119 | .telemetry_endpoints 120 | .clone() 121 | .filter(|x| !x.is_empty()) 122 | .map(|endpoints| -> Result<_, sc_telemetry::Error> { 123 | let worker = TelemetryWorker::new(16)?; 124 | let telemetry = worker.handle().new_telemetry(endpoints); 125 | Ok((worker, telemetry)) 126 | }) 127 | .transpose()?; 128 | 129 | let executor = sc_executor::NativeElseWasmExecutor::::new( 130 | config.wasm_method, 131 | config.default_heap_pages, 132 | config.max_runtime_instances, 133 | config.runtime_cache_size, 134 | ); 135 | 136 | let (client, backend, keystore_container, task_manager) = 137 | sc_service::new_full_parts::( 138 | config, 139 | telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), 140 | executor, 141 | )?; 142 | let client = Arc::new(client); 143 | 144 | let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); 145 | 146 | let telemetry = telemetry.map(|(worker, telemetry)| { 147 | task_manager.spawn_handle().spawn("telemetry", None, worker.run()); 148 | telemetry 149 | }); 150 | 151 | let transaction_pool = sc_transaction_pool::BasicPool::new_full( 152 | config.transaction_pool.clone(), 153 | config.role.is_authority().into(), 154 | config.prometheus_registry(), 155 | task_manager.spawn_essential_handle(), 156 | client.clone(), 157 | ); 158 | 159 | let import_queue = build_import_queue( 160 | client.clone(), 161 | config, 162 | telemetry.as_ref().map(|telemetry| telemetry.handle()), 163 | &task_manager, 164 | )?; 165 | 166 | let params = PartialComponents { 167 | backend, 168 | client, 169 | import_queue, 170 | keystore_container, 171 | task_manager, 172 | transaction_pool, 173 | select_chain: (), 174 | other: (telemetry, telemetry_worker_handle), 175 | }; 176 | 177 | Ok(params) 178 | } 179 | 180 | /// Start a node with the given parachain `Configuration` and relay chain `Configuration`. 181 | /// 182 | /// This is the actual implementation that is abstract over the executor and the runtime api. 183 | #[sc_tracing::logging::prefix_logs_with("Parachain")] 184 | async fn start_node_impl( 185 | parachain_config: Configuration, 186 | polkadot_config: Configuration, 187 | id: ParaId, 188 | _rpc_ext_builder: RB, 189 | build_import_queue: BIQ, 190 | build_consensus: BIC, 191 | ) -> sc_service::error::Result<( 192 | TaskManager, 193 | Arc>>, 194 | )> 195 | where 196 | RuntimeApi: ConstructRuntimeApi>> 197 | + Send 198 | + Sync 199 | + 'static, 200 | RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue 201 | + sp_api::Metadata 202 | + sp_session::SessionKeys 203 | + sp_api::ApiExt< 204 | Block, 205 | StateBackend = sc_client_api::StateBackendFor, Block>, 206 | > + sp_offchain::OffchainWorkerApi 207 | + sp_block_builder::BlockBuilder 208 | + cumulus_primitives_core::CollectCollationInfo 209 | + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi 210 | + substrate_frame_rpc_system::AccountNonceApi 211 | + pallet_contracts_rpc::ContractsRuntimeApi, 212 | sc_client_api::StateBackendFor, Block>: sp_api::StateBackend, 213 | Executor: sc_executor::NativeExecutionDispatch + 'static, 214 | RB: Fn( 215 | Arc>, 216 | ) -> Result, sc_service::Error> 217 | + Send 218 | + 'static, 219 | BIQ: FnOnce( 220 | Arc>>, 221 | &Configuration, 222 | Option, 223 | &TaskManager, 224 | ) -> Result< 225 | sc_consensus::DefaultImportQueue< 226 | Block, 227 | TFullClient>, 228 | >, 229 | sc_service::Error, 230 | > + 'static, 231 | BIC: FnOnce( 232 | Arc>>, 233 | Option<&Registry>, 234 | Option, 235 | &TaskManager, 236 | Arc, 237 | Arc< 238 | sc_transaction_pool::FullPool< 239 | Block, 240 | TFullClient>, 241 | >, 242 | >, 243 | Arc>, 244 | SyncCryptoStorePtr, 245 | bool, 246 | ) -> Result>, sc_service::Error>, 247 | { 248 | if matches!(parachain_config.role, Role::Light) { 249 | return Err("Light client not supported!".into()) 250 | } 251 | 252 | let parachain_config = prepare_node_config(parachain_config); 253 | 254 | let params = new_partial::(¶chain_config, build_import_queue)?; 255 | let (mut telemetry, telemetry_worker_handle) = params.other; 256 | 257 | let client = params.client.clone(); 258 | let backend = params.backend.clone(); 259 | let mut task_manager = params.task_manager; 260 | 261 | let (relay_chain_interface, collator_key) = 262 | build_relay_chain_interface(polkadot_config, telemetry_worker_handle, &mut task_manager) 263 | .map_err(|e| match e { 264 | polkadot_service::Error::Sub(x) => x, 265 | s => format!("{}", s).into(), 266 | })?; 267 | 268 | let block_announce_validator = BlockAnnounceValidator::new(relay_chain_interface.clone(), id); 269 | 270 | let force_authoring = parachain_config.force_authoring; 271 | let validator = parachain_config.role.is_authority(); 272 | let prometheus_registry = parachain_config.prometheus_registry().cloned(); 273 | let transaction_pool = params.transaction_pool.clone(); 274 | let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue); 275 | let (network, system_rpc_tx, start_network) = 276 | sc_service::build_network(sc_service::BuildNetworkParams { 277 | config: ¶chain_config, 278 | client: client.clone(), 279 | transaction_pool: transaction_pool.clone(), 280 | spawn_handle: task_manager.spawn_handle(), 281 | import_queue: import_queue.clone(), 282 | block_announce_validator_builder: Some(Box::new(|_| { 283 | Box::new(block_announce_validator) 284 | })), 285 | warp_sync: None, 286 | })?; 287 | 288 | let rpc_extensions_builder = { 289 | let client = client.clone(); 290 | let transaction_pool = transaction_pool.clone(); 291 | 292 | Box::new(move |deny_unsafe, _| { 293 | let deps = crate::rpc::FullDeps { 294 | client: client.clone(), 295 | pool: transaction_pool.clone(), 296 | deny_unsafe, 297 | }; 298 | 299 | Ok(crate::rpc::create_full(deps)) 300 | }) 301 | }; 302 | 303 | sc_service::spawn_tasks(sc_service::SpawnTasksParams { 304 | rpc_extensions_builder, 305 | client: client.clone(), 306 | transaction_pool: transaction_pool.clone(), 307 | task_manager: &mut task_manager, 308 | config: parachain_config, 309 | keystore: params.keystore_container.sync_keystore(), 310 | backend: backend.clone(), 311 | network: network.clone(), 312 | system_rpc_tx, 313 | telemetry: telemetry.as_mut(), 314 | })?; 315 | 316 | let announce_block = { 317 | let network = network.clone(); 318 | Arc::new(move |hash, data| network.announce_block(hash, data)) 319 | }; 320 | 321 | let relay_chain_slot_duration = Duration::from_secs(6); 322 | 323 | if validator { 324 | let parachain_consensus = build_consensus( 325 | client.clone(), 326 | prometheus_registry.as_ref(), 327 | telemetry.as_ref().map(|t| t.handle()), 328 | &task_manager, 329 | relay_chain_interface.clone(), 330 | transaction_pool, 331 | network, 332 | params.keystore_container.sync_keystore(), 333 | force_authoring, 334 | )?; 335 | 336 | let spawner = task_manager.spawn_handle(); 337 | 338 | let params = StartCollatorParams { 339 | para_id: id, 340 | block_status: client.clone(), 341 | announce_block, 342 | client: client.clone(), 343 | task_manager: &mut task_manager, 344 | relay_chain_interface, 345 | spawner, 346 | parachain_consensus, 347 | import_queue, 348 | collator_key, 349 | relay_chain_slot_duration, 350 | }; 351 | 352 | start_collator(params).await?; 353 | } else { 354 | let params = StartFullNodeParams { 355 | client: client.clone(), 356 | announce_block, 357 | task_manager: &mut task_manager, 358 | para_id: id, 359 | relay_chain_interface, 360 | relay_chain_slot_duration, 361 | import_queue, 362 | }; 363 | 364 | start_full_node(params)?; 365 | } 366 | 367 | start_network.start_network(); 368 | 369 | Ok((task_manager, client)) 370 | } 371 | 372 | /// Build the import queue for the parachain runtime. 373 | #[allow(clippy::type_complexity)] 374 | pub fn parachain_build_import_queue( 375 | client: Arc>>, 376 | config: &Configuration, 377 | telemetry: Option, 378 | task_manager: &TaskManager, 379 | ) -> Result< 380 | sc_consensus::DefaultImportQueue< 381 | Block, 382 | TFullClient>, 383 | >, 384 | sc_service::Error, 385 | > { 386 | let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; 387 | 388 | cumulus_client_consensus_aura::import_queue::< 389 | sp_consensus_aura::sr25519::AuthorityPair, 390 | _, 391 | _, 392 | _, 393 | _, 394 | _, 395 | _, 396 | >(cumulus_client_consensus_aura::ImportQueueParams { 397 | block_import: client.clone(), 398 | client: client.clone(), 399 | create_inherent_data_providers: move |_, _| async move { 400 | let time = sp_timestamp::InherentDataProvider::from_system_time(); 401 | 402 | let slot = 403 | sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration( 404 | *time, 405 | slot_duration.slot_duration(), 406 | ); 407 | 408 | Ok((time, slot)) 409 | }, 410 | registry: config.prometheus_registry(), 411 | can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()), 412 | spawner: &task_manager.spawn_essential_handle(), 413 | telemetry, 414 | }) 415 | .map_err(Into::into) 416 | } 417 | 418 | /// Start a parachain node. 419 | pub async fn start_parachain_node( 420 | parachain_config: Configuration, 421 | polkadot_config: Configuration, 422 | id: ParaId, 423 | ) -> sc_service::error::Result<( 424 | TaskManager, 425 | Arc>>, 426 | )> { 427 | start_node_impl::( 428 | parachain_config, 429 | polkadot_config, 430 | id, 431 | |_| Ok(Default::default()), 432 | parachain_build_import_queue, 433 | |client, 434 | prometheus_registry, 435 | telemetry, 436 | task_manager, 437 | relay_chain_interface, 438 | transaction_pool, 439 | sync_oracle, 440 | keystore, 441 | force_authoring| { 442 | let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; 443 | 444 | let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( 445 | task_manager.spawn_handle(), 446 | client.clone(), 447 | transaction_pool, 448 | prometheus_registry, 449 | telemetry.clone(), 450 | ); 451 | 452 | Ok(AuraConsensus::build::( 453 | BuildAuraConsensusParams { 454 | proposer_factory, 455 | create_inherent_data_providers: move |_, (relay_parent, validation_data)| { 456 | let relay_chain_interface = relay_chain_interface.clone(); 457 | async move { 458 | let parachain_inherent = 459 | cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( 460 | relay_parent, 461 | &relay_chain_interface, 462 | &validation_data, 463 | id, 464 | ).await; 465 | let time = sp_timestamp::InherentDataProvider::from_system_time(); 466 | 467 | let slot = 468 | sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration( 469 | *time, 470 | slot_duration.slot_duration(), 471 | ); 472 | 473 | let parachain_inherent = parachain_inherent.ok_or_else(|| { 474 | Box::::from( 475 | "Failed to create parachain inherent", 476 | ) 477 | })?; 478 | Ok((time, slot, parachain_inherent)) 479 | } 480 | }, 481 | block_import: client.clone(), 482 | para_client: client, 483 | backoff_authoring_blocks: Option::<()>::None, 484 | sync_oracle, 485 | keystore, 486 | force_authoring, 487 | slot_duration, 488 | // We got around 500ms for proposing 489 | block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32), 490 | // And a maximum of 750ms if slots are skipped 491 | max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)), 492 | telemetry, 493 | }, 494 | )) 495 | }, 496 | ) 497 | .await 498 | } 499 | -------------------------------------------------------------------------------- /polkadot-launch/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "relaychain": { 3 | "bin": "../../polkadot/target/release/polkadot", 4 | "chain": "rococo-local", 5 | "nodes": [ 6 | { 7 | "name": "alice", 8 | "wsPort": 9944, 9 | "port": 30444 10 | }, 11 | { 12 | "name": "bob", 13 | "wsPort": 9955, 14 | "port": 30555 15 | } 16 | ] 17 | }, 18 | "parachains": [ 19 | { 20 | "bin": "../target/release/thippy", 21 | "balance": "1000000000000000000000", 22 | "nodes": [ 23 | { 24 | "wsPort": 9988, 25 | "name": "alice", 26 | "port": 31200, 27 | "flags": [ 28 | "--", 29 | "--execution=wasm" 30 | ] 31 | } 32 | ] 33 | } 34 | ], 35 | "types": { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thippy-runtime" 3 | version = "0.2.0" 4 | authors = ["Annie Lai "] 5 | license = "GPL-3.0-only" 6 | edition = "2021" 7 | rust-version = "1.56.1" 8 | 9 | [package.metadata.docs.rs] 10 | targets = ["x86_64-unknown-linux-gnu"] 11 | 12 | [build-dependencies] 13 | substrate-wasm-builder = { git = "https://github.com/ng8eke/substrate", branch = "master" } 14 | 15 | [dependencies] 16 | hex-literal = { version = '0.3.1', optional = true } 17 | codec = { package = 'parity-scale-codec', version = '2.0.0', default-features = false, features = ['derive']} 18 | log = { version = "0.4.14", default-features = false } 19 | scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } 20 | serde = { version = '1.0.119', optional = true, features = ['derive'] } 21 | smallvec = "1.6.1" 22 | 23 | # Substrate Dependencies 24 | ## Substrate Primitive Dependencies 25 | sp-api = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 26 | sp-block-builder = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 27 | sp-consensus-aura = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 28 | sp-core = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 29 | sp-inherents = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 30 | sp-io = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 31 | sp-offchain = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 32 | sp-runtime = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 33 | sp-session = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 34 | sp-std = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 35 | sp-transaction-pool = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 36 | sp-version = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 37 | 38 | ## Substrate FRAME Dependencies 39 | frame-benchmarking = { git = 'https://github.com/ng8eke/substrate', default-features = false, optional = true , branch = "master" } 40 | frame-try-runtime = { git = "https://github.com/ng8eke/substrate", default-features = false, optional = true , branch = "master" } 41 | frame-executive = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 42 | frame-support = { git = 'https://github.com/ng8eke/substrate', default-features = false, branch = "master" } 43 | frame-system = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 44 | frame-system-benchmarking = { git = 'https://github.com/ng8eke/substrate', default-features = false, optional = true , branch = "master" } 45 | frame-system-rpc-runtime-api = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 46 | 47 | ## Substrate Pallet Dependencies 48 | pallet-aura = { git = "https://github.com/ng8eke/substrate", default-features = false , branch = "master" } 49 | pallet-authorship = { git = "https://github.com/ng8eke/substrate", default-features = false , branch = "master" } 50 | pallet-randomness-collective-flip = { git = "https://github.com/ng8eke/substrate", default-features = false , branch = "master" } 51 | pallet-balances = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 52 | pallet-session = { git = "https://github.com/ng8eke/substrate", default-features = false , branch = "master" } 53 | pallet-timestamp = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 54 | pallet-transaction-payment = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 55 | pallet-transaction-payment-rpc-runtime-api = { git = 'https://github.com/ng8eke/substrate', default-features = false , branch = "master" } 56 | 57 | pallet-sudo = { git = "https://github.com/ng8eke/substrate", default-features = false , branch = "master" } 58 | 59 | # Cumulus Dependencies 60 | cumulus-pallet-aura-ext = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 61 | cumulus-pallet-dmp-queue = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 62 | cumulus-pallet-parachain-system = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 63 | cumulus-pallet-xcm = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 64 | cumulus-pallet-xcmp-queue = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 65 | cumulus-primitives-core = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 66 | cumulus-primitives-timestamp = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 67 | cumulus-primitives-utility = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 68 | pallet-collator-selection = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 69 | parachain-info = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 70 | cumulus-pallet-session-benchmarking = { git = 'https://github.com/ng8eke/cumulus', default-features = false , branch = "master" } 71 | 72 | # Polkadot Dependencies 73 | polkadot-parachain = { git = 'https://github.com/ng8eke/polkadot', default-features = false , branch = "master" } 74 | polkadot-runtime-common = { git = "https://github.com/ng8eke/polkadot", default-features = false, branch = "master" } 75 | xcm = { git = 'https://github.com/ng8eke/polkadot', default-features = false , branch = "master" } 76 | xcm-builder = { git = 'https://github.com/ng8eke/polkadot', default-features = false , branch = "master" } 77 | xcm-executor = { git = 'https://github.com/ng8eke/polkadot', default-features = false , branch = "master" } 78 | pallet-xcm = { git = 'https://github.com/ng8eke/polkadot', default-features = false , branch = "master" } 79 | 80 | # Contracts specific packages 81 | pallet-contracts = { git = "https://github.com/ng8eke/substrate", default-features = false, branch = "master" } 82 | pallet-contracts-primitives = { git = "https://github.com/ng8eke/substrate", default-features = false, branch = "master" } 83 | pallet-contracts-rpc-runtime-api = { git = "https://github.com/ng8eke/substrate", default-features = false, branch = "master" } 84 | 85 | [features] 86 | default = [ 87 | "std", 88 | ] 89 | std = [ 90 | "codec/std", 91 | "serde", 92 | "scale-info/std", 93 | "log/std", 94 | "sp-api/std", 95 | "sp-block-builder/std", 96 | "sp-consensus-aura/std", 97 | "sp-core/std", 98 | "sp-inherents/std", 99 | "sp-io/std", 100 | "sp-offchain/std", 101 | "sp-runtime/std", 102 | "sp-session/std", 103 | "sp-std/std", 104 | "sp-transaction-pool/std", 105 | "sp-version/std", 106 | "frame-executive/std", 107 | "frame-support/std", 108 | "frame-system/std", 109 | "pallet-authorship/std", 110 | "pallet-aura/std", 111 | "pallet-sudo/std", 112 | "pallet-balances/std", 113 | "pallet-collator-selection/std", 114 | "pallet-randomness-collective-flip/std", 115 | "pallet-contracts-primitives/std", 116 | "pallet-contracts-rpc-runtime-api/std", 117 | "pallet-contracts/std", 118 | "pallet-session/std", 119 | "pallet-timestamp/std", 120 | "pallet-transaction-payment/std", 121 | "pallet-transaction-payment-rpc-runtime-api/std", 122 | "cumulus-pallet-aura-ext/std", 123 | "cumulus-pallet-dmp-queue/std", 124 | "cumulus-pallet-parachain-system/std", 125 | "cumulus-pallet-xcm/std", 126 | "cumulus-pallet-xcmp-queue/std", 127 | "cumulus-primitives-core/std", 128 | "cumulus-primitives-timestamp/std", 129 | "cumulus-primitives-utility/std", 130 | "parachain-info/std", 131 | "polkadot-parachain/std", 132 | "polkadot-runtime-common/std", 133 | "xcm/std", 134 | "xcm-builder/std", 135 | "xcm-executor/std", 136 | ] 137 | 138 | # Make contract callable functions marked as __unstable__ available. Do not enable 139 | # on live chains as those are subject to change. 140 | contracts-unstable-interface = [ 141 | "pallet-contracts/unstable-interface" 142 | ] 143 | 144 | runtime-benchmarks = [ 145 | 'hex-literal', 146 | 'sp-runtime/runtime-benchmarks', 147 | 'xcm-builder/runtime-benchmarks', 148 | "frame-benchmarking/runtime-benchmarks", 149 | 'frame-system-benchmarking', 150 | 'frame-support/runtime-benchmarks', 151 | 'frame-system/runtime-benchmarks', 152 | 'pallet-balances/runtime-benchmarks', 153 | 'pallet-timestamp/runtime-benchmarks', 154 | 'pallet-xcm/runtime-benchmarks', 155 | 'pallet-collator-selection/runtime-benchmarks', 156 | 'cumulus-pallet-session-benchmarking/runtime-benchmarks', 157 | ] 158 | 159 | try-runtime = [ 160 | "frame-try-runtime", 161 | "frame-executive/try-runtime", 162 | ] 163 | -------------------------------------------------------------------------------- /runtime/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | use substrate_wasm_builder::WasmBuilder; 18 | 19 | fn main() { 20 | WasmBuilder::new() 21 | .with_current_project() 22 | .export_heap_base() 23 | .import_memory() 24 | .build() 25 | } 26 | -------------------------------------------------------------------------------- /runtime/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018-2021 Annie Lai. 2 | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #![cfg_attr(not(feature = "std"), no_std)] 18 | // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. 19 | #![recursion_limit = "256"] 20 | 21 | // Make the WASM binary available. 22 | #[cfg(feature = "std")] 23 | include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); 24 | 25 | use pallet_contracts::weights::WeightInfo; 26 | use smallvec::smallvec; 27 | use sp_api::impl_runtime_apis; 28 | use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; 29 | use sp_runtime::{ 30 | create_runtime_str, generic, impl_opaque_keys, 31 | traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, Verify}, 32 | transaction_validity::{TransactionSource, TransactionValidity}, 33 | ApplyExtrinsicResult, MultiSignature, 34 | }; 35 | 36 | use sp_std::prelude::*; 37 | #[cfg(feature = "std")] 38 | use sp_version::NativeVersion; 39 | use sp_version::RuntimeVersion; 40 | 41 | use frame_support::{ 42 | construct_runtime, match_type, parameter_types, 43 | traits::{EnsureOneOf, Everything}, 44 | weights::{ 45 | constants::{BlockExecutionWeight, ExtrinsicBaseWeight, WEIGHT_PER_SECOND}, 46 | DispatchClass, IdentityFee, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, 47 | WeightToFeePolynomial, 48 | }, 49 | PalletId, 50 | }; 51 | use frame_system::{ 52 | limits::{BlockLength, BlockWeights}, 53 | EnsureRoot, 54 | }; 55 | pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; 56 | pub use sp_runtime::{MultiAddress, Perbill, Permill}; 57 | 58 | #[cfg(any(feature = "std", test))] 59 | pub use sp_runtime::BuildStorage; 60 | 61 | // Polkadot Imports 62 | use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; 63 | use polkadot_parachain::primitives::Sibling; 64 | use polkadot_runtime_common::{BlockHashCount, RocksDbWeight, SlowAdjustingFeeUpdate}; 65 | 66 | // XCM Imports 67 | use xcm::latest::prelude::*; 68 | use xcm_builder::{ 69 | AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, 70 | EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, ParentIsPreset, 71 | RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, 72 | SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, 73 | }; 74 | use xcm_executor::{Config, XcmExecutor}; 75 | 76 | /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. 77 | pub type Signature = MultiSignature; 78 | 79 | /// Some way of identifying an account on the chain. We intentionally make it equivalent 80 | /// to the public key of our transaction signing scheme. 81 | pub type AccountId = <::Signer as IdentifyAccount>::AccountId; 82 | 83 | /// Balance of an account. 84 | pub type Balance = u128; 85 | 86 | /// Index of a transaction in the chain. 87 | pub type Index = u32; 88 | 89 | /// A hash of some data used by the chain. 90 | pub type Hash = sp_core::H256; 91 | 92 | /// An index to a block. 93 | pub type BlockNumber = u32; 94 | 95 | /// The address format for describing accounts. 96 | pub type Address = MultiAddress; 97 | 98 | /// Block header type as expected by this runtime. 99 | pub type Header = generic::Header; 100 | 101 | /// Block type as expected by this runtime. 102 | pub type Block = generic::Block; 103 | 104 | /// A Block signed with a Justification 105 | pub type SignedBlock = generic::SignedBlock; 106 | 107 | /// BlockId type as expected by this runtime. 108 | pub type BlockId = generic::BlockId; 109 | 110 | /// The SignedExtension to the basic transaction logic. 111 | pub type SignedExtra = ( 112 | frame_system::CheckSpecVersion, 113 | frame_system::CheckTxVersion, 114 | frame_system::CheckGenesis, 115 | frame_system::CheckEra, 116 | frame_system::CheckNonce, 117 | frame_system::CheckWeight, 118 | pallet_transaction_payment::ChargeTransactionPayment, 119 | ); 120 | 121 | /// Unchecked extrinsic type as expected by this runtime. 122 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; 123 | 124 | /// Extrinsic type that has already been checked. 125 | pub type CheckedExtrinsic = generic::CheckedExtrinsic; 126 | 127 | /// Executive: handles dispatch to the various modules. 128 | pub type Executive = frame_executive::Executive< 129 | Runtime, 130 | Block, 131 | frame_system::ChainContext, 132 | Runtime, 133 | AllPalletsWithSystem, 134 | >; 135 | 136 | /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the 137 | /// node's balance type. 138 | /// 139 | /// This should typically create a mapping between the following ranges: 140 | /// - `[0, MAXIMUM_BLOCK_WEIGHT]` 141 | /// - `[Balance::min, Balance::max]` 142 | /// 143 | /// Yet, it can be used for any other sort of change to weight-fee. Some examples being: 144 | /// - Setting it to `0` will essentially disable the weight fee. 145 | /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. 146 | pub struct WeightToFee; 147 | impl WeightToFeePolynomial for WeightToFee { 148 | type Balance = Balance; 149 | fn polynomial() -> WeightToFeeCoefficients { 150 | // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLIUNIT: 151 | // in Thippy, we map to 1/10 of that, or 1/10 MILLIUNIT 152 | let p = MILLIUNIT / 10; 153 | let q = 100 * Balance::from(ExtrinsicBaseWeight::get()); 154 | smallvec![WeightToFeeCoefficient { 155 | degree: 1, 156 | negative: false, 157 | coeff_frac: Perbill::from_rational(p % q, q), 158 | coeff_integer: p / q, 159 | }] 160 | } 161 | } 162 | 163 | /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know 164 | /// the specifics of the runtime. They can then be made to be agnostic over specific formats 165 | /// of data like extrinsics, allowing for them to continue syncing the network through upgrades 166 | /// to even the core data structures. 167 | pub mod opaque { 168 | use super::*; 169 | use sp_runtime::{generic, traits::BlakeTwo256}; 170 | 171 | pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; 172 | /// Opaque block header type. 173 | pub type Header = generic::Header; 174 | /// Opaque block type. 175 | pub type Block = generic::Block; 176 | /// Opaque block identifier type. 177 | pub type BlockId = generic::BlockId; 178 | } 179 | 180 | impl_opaque_keys! { 181 | pub struct SessionKeys { 182 | pub aura: Aura, 183 | } 184 | } 185 | 186 | #[sp_version::runtime_version] 187 | pub const VERSION: RuntimeVersion = RuntimeVersion { 188 | spec_name: create_runtime_str!("thippy"), 189 | impl_name: create_runtime_str!("thippy"), 190 | authoring_version: 1, 191 | spec_version: 15, 192 | impl_version: 1, 193 | apis: RUNTIME_API_VERSIONS, 194 | transaction_version: 1, 195 | // Since Thippy is a "live" chain (on Rococo anyways), we need to set this to `0` until a 196 | // migration path to `state_version = 1` is ready. 197 | // 198 | // See the following PRs for more details: 199 | // - https://github.com/ng8eke/substrate/pull/9732 200 | // - https://github.com/ng8eke/substrate/pull/10073 201 | state_version: 0, 202 | }; 203 | 204 | /// This determines the average expected block time that we are targeting. 205 | /// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. 206 | /// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked 207 | /// up by `pallet_aura` to implement `fn slot_duration()`. 208 | /// 209 | /// Change this to adjust the block time. 210 | pub const MILLISECS_PER_BLOCK: u64 = 12000; 211 | 212 | // NOTE: Currently it is not possible to change the slot duration after the chain has started. 213 | // Attempting to do so will brick block production. 214 | pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; 215 | 216 | // Time is measured by number of blocks. 217 | pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); 218 | pub const HOURS: BlockNumber = MINUTES * 60; 219 | pub const DAYS: BlockNumber = HOURS * 24; 220 | 221 | // Prints debug output of the `contracts` pallet to stdout if the node is 222 | // started with `-lruntime::contracts=debug`. 223 | pub const CONTRACTS_DEBUG_OUTPUT: bool = true; 224 | 225 | // Unit = the base number of indivisible units for balances 226 | pub const UNIT: Balance = 1_000_000_000_000; 227 | pub const MILLIUNIT: Balance = 1_000_000_000; 228 | pub const MICROUNIT: Balance = 1_000_000; 229 | 230 | /// The existential deposit. Set to 1/10 of the Connected Relay Chain. 231 | pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT; 232 | 233 | const fn deposit(items: u32, bytes: u32) -> Balance { 234 | // This is a 1/10 of the deposit on the Rococo Relay Chain 235 | (items as Balance * UNIT + (bytes as Balance) * (5 * MILLIUNIT / 100)) / 10 236 | } 237 | 238 | /// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is 239 | /// used to limit the maximal weight of a single extrinsic. 240 | const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); 241 | 242 | /// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by 243 | /// `Operational` extrinsics. 244 | const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); 245 | 246 | /// We allow for 0.5 of a second of compute with a 12 second average block time. 247 | const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2; 248 | 249 | /// The version information used to identify this runtime when compiled natively. 250 | #[cfg(feature = "std")] 251 | pub fn native_version() -> NativeVersion { 252 | NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } 253 | } 254 | 255 | parameter_types! { 256 | pub const Version: RuntimeVersion = VERSION; 257 | 258 | // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. 259 | // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the 260 | // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize 261 | // the lazy contract deletion. 262 | pub RuntimeBlockLength: BlockLength = 263 | BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); 264 | pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() 265 | .base_block(BlockExecutionWeight::get()) 266 | .for_class(DispatchClass::all(), |weights| { 267 | weights.base_extrinsic = ExtrinsicBaseWeight::get(); 268 | }) 269 | .for_class(DispatchClass::Normal, |weights| { 270 | weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); 271 | }) 272 | .for_class(DispatchClass::Operational, |weights| { 273 | weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); 274 | // Operational transactions have some extra reserved space, so that they 275 | // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. 276 | weights.reserved = Some( 277 | MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT 278 | ); 279 | }) 280 | .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) 281 | .build_or_panic(); 282 | pub const SS58Prefix: u16 = 42; 283 | } 284 | 285 | // Configure FRAME pallets to include in runtime. 286 | 287 | impl frame_system::Config for Runtime { 288 | /// The identifier used to distinguish between accounts. 289 | type AccountId = AccountId; 290 | /// The aggregated dispatch type that is available for extrinsics. 291 | type Call = Call; 292 | /// The lookup mechanism to get account ID from whatever is passed in dispatchers. 293 | type Lookup = AccountIdLookup; 294 | /// The index type for storing how many extrinsics an account has signed. 295 | type Index = Index; 296 | /// The index type for blocks. 297 | type BlockNumber = BlockNumber; 298 | /// The type for hashing blocks and tries. 299 | type Hash = Hash; 300 | /// The hashing algorithm used. 301 | type Hashing = BlakeTwo256; 302 | /// The header type. 303 | type Header = generic::Header; 304 | /// The ubiquitous event type. 305 | type Event = Event; 306 | /// The ubiquitous origin type. 307 | type Origin = Origin; 308 | /// Maximum number of block number to block hash mappings to keep (oldest pruned first). 309 | type BlockHashCount = BlockHashCount; 310 | /// Runtime version. 311 | type Version = Version; 312 | /// Converts a module to an index of this module in the runtime. 313 | type PalletInfo = PalletInfo; 314 | /// The data to be stored in an account. 315 | type AccountData = pallet_balances::AccountData; 316 | /// What to do if a new account is created. 317 | type OnNewAccount = (); 318 | /// What to do if an account is fully reaped from the system. 319 | type OnKilledAccount = (); 320 | /// The weight of database operations that the runtime can invoke. 321 | type DbWeight = RocksDbWeight; 322 | /// The basic call filter to use in dispatchable. 323 | type BaseCallFilter = Everything; 324 | /// Weight information for the extrinsics of this pallet. 325 | type SystemWeightInfo = (); 326 | /// Block & extrinsics weights: base values and limits. 327 | type BlockWeights = RuntimeBlockWeights; 328 | /// The maximum length of a block (in bytes). 329 | type BlockLength = RuntimeBlockLength; 330 | /// This is used as an identifier of the chain. 42 is the generic substrate prefix. 331 | type SS58Prefix = SS58Prefix; 332 | /// The action to take on a Runtime Upgrade 333 | type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; 334 | /// The maximum number of consumers (e.g locks) system accounts can have. 335 | type MaxConsumers = frame_support::traits::ConstU32<16>; 336 | } 337 | 338 | parameter_types! { 339 | pub const MinimumPeriod: u64 = SLOT_DURATION / 2; 340 | } 341 | 342 | impl pallet_timestamp::Config for Runtime { 343 | /// A timestamp: milliseconds since the unix epoch. 344 | type Moment = u64; 345 | type OnTimestampSet = (); 346 | type MinimumPeriod = MinimumPeriod; 347 | type WeightInfo = (); // TODO: Add benchmarked weights. 348 | } 349 | 350 | parameter_types! { 351 | pub const UncleGenerations: u32 = 0; 352 | } 353 | 354 | impl pallet_authorship::Config for Runtime { 355 | type FindAuthor = pallet_session::FindAccountFromAuthorIndex; 356 | type UncleGenerations = UncleGenerations; 357 | type FilterUncle = (); 358 | type EventHandler = (CollatorSelection,); 359 | } 360 | 361 | parameter_types! { 362 | pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; 363 | pub const MaxLocks: u32 = 50; 364 | pub const MaxReserves: u32 = 50; 365 | } 366 | 367 | impl pallet_balances::Config for Runtime { 368 | type MaxLocks = MaxLocks; 369 | /// The type for recording an account's balance. 370 | type Balance = Balance; 371 | /// The ubiquitous event type. 372 | type Event = Event; 373 | type DustRemoval = (); 374 | type ExistentialDeposit = ExistentialDeposit; 375 | type AccountStore = System; 376 | type WeightInfo = pallet_balances::weights::SubstrateWeight; 377 | type MaxReserves = MaxReserves; 378 | type ReserveIdentifier = [u8; 8]; 379 | } 380 | 381 | parameter_types! { 382 | /// Relay Chain `TransactionByteFee` / 10 383 | pub const TransactionByteFee: Balance = 10 * MICROUNIT; 384 | pub const OperationalFeeMultiplier: u8 = 5; 385 | } 386 | 387 | impl pallet_transaction_payment::Config for Runtime { 388 | type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; 389 | type TransactionByteFee = TransactionByteFee; 390 | type WeightToFee = WeightToFee; 391 | type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; 392 | type OperationalFeeMultiplier = OperationalFeeMultiplier; 393 | } 394 | 395 | parameter_types! { 396 | pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4; 397 | pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4; 398 | } 399 | 400 | impl cumulus_pallet_parachain_system::Config for Runtime { 401 | type Event = Event; 402 | type OnSystemEvent = (); 403 | type SelfParaId = parachain_info::Pallet; 404 | type DmpMessageHandler = DmpQueue; 405 | type ReservedDmpWeight = ReservedDmpWeight; 406 | type OutboundXcmpMessageSource = XcmpQueue; 407 | type XcmpMessageHandler = XcmpQueue; 408 | type ReservedXcmpWeight = ReservedXcmpWeight; 409 | } 410 | 411 | parameter_types! { 412 | pub const DepositPerItem: Balance = deposit(1, 0); 413 | pub const DepositPerByte: Balance = deposit(0, 1); 414 | // The lazy deletion runs inside on_initialize. 415 | pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO * 416 | RuntimeBlockWeights::get().max_block; 417 | // The weight needed for decoding the queue should be less or equal than a fifth 418 | // of the overall weight dedicated to the lazy deletion. 419 | pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / ( 420 | ::WeightInfo::on_initialize_per_queue_item(1) - 421 | ::WeightInfo::on_initialize_per_queue_item(0) 422 | )) / 5) as u32; 423 | pub Schedule: pallet_contracts::Schedule = Default::default(); 424 | } 425 | 426 | impl pallet_contracts::Config for Runtime { 427 | type Time = Timestamp; 428 | type Randomness = RandomnessCollectiveFlip; 429 | type Currency = Balances; 430 | type Event = Event; 431 | type Call = Call; 432 | /// The safest default is to allow no calls at all. 433 | /// 434 | /// Runtimes should whitelist dispatchables that are allowed to be called from contracts 435 | /// and make sure they are stable. Dispatchables exposed to contracts are not allowed to 436 | /// change because that would break already deployed contracts. The `Call` structure itself 437 | /// is not allowed to change the indices of existing pallets, too. 438 | type CallFilter = frame_support::traits::Nothing; 439 | type DepositPerItem = DepositPerItem; 440 | type DepositPerByte = DepositPerByte; 441 | type WeightPrice = pallet_transaction_payment::Pallet; 442 | type WeightInfo = pallet_contracts::weights::SubstrateWeight; 443 | type ChainExtension = (); 444 | type DeletionQueueDepth = DeletionQueueDepth; 445 | type DeletionWeightLimit = DeletionWeightLimit; 446 | type Schedule = Schedule; 447 | type CallStack = [pallet_contracts::Frame; 31]; 448 | type AddressGenerator = pallet_contracts::DefaultAddressGenerator; 449 | } 450 | 451 | impl pallet_randomness_collective_flip::Config for Runtime {} 452 | 453 | impl parachain_info::Config for Runtime {} 454 | 455 | impl cumulus_pallet_aura_ext::Config for Runtime {} 456 | 457 | parameter_types! { 458 | pub const RelayLocation: MultiLocation = MultiLocation::parent(); 459 | pub const RelayNetwork: NetworkId = NetworkId::Any; 460 | pub RelayChainOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into(); 461 | pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); 462 | } 463 | 464 | /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used 465 | /// when determining ownership of accounts for asset transacting and when attempting to use XCM 466 | /// `Transact` in order to determine the dispatch Origin. 467 | pub type LocationToAccountId = ( 468 | // The parent (Relay-chain) origin converts to the parent `AccountId`. 469 | ParentIsPreset, 470 | // Sibling parachain origins convert to AccountId via the `ParaId::into`. 471 | SiblingParachainConvertsVia, 472 | // Straight up local `AccountId32` origins just alias directly to `AccountId`. 473 | AccountId32Aliases, 474 | ); 475 | 476 | /// Means for transacting assets on this chain. 477 | pub type LocalAssetTransactor = CurrencyAdapter< 478 | // Use this currency: 479 | Balances, 480 | // Use this currency when it is a fungible asset matching the given location or name: 481 | IsConcrete, 482 | // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: 483 | LocationToAccountId, 484 | // Our chain's account ID type (we can't get away without mentioning it explicitly): 485 | AccountId, 486 | // We don't track any teleports. 487 | (), 488 | >; 489 | 490 | /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, 491 | /// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can 492 | /// biases the kind of local `Origin` it will become. 493 | pub type XcmOriginToTransactDispatchOrigin = ( 494 | // Sovereign account converter; this attempts to derive an `AccountId` from the origin location 495 | // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for 496 | // foreign chains who want to have a local sovereign account on this chain which they control. 497 | SovereignSignedViaLocation, 498 | // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when 499 | // recognized. 500 | RelayChainAsNative, 501 | // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when 502 | // recognized. 503 | SiblingParachainAsNative, 504 | // Native signed account converter; this just converts an `AccountId32` origin into a normal 505 | // `Origin::Signed` origin of the same 32-byte value. 506 | SignedAccountId32AsNative, 507 | // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. 508 | XcmPassthrough, 509 | ); 510 | 511 | parameter_types! { 512 | // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. 513 | pub UnitWeightCost: Weight = 1_000_000_000; 514 | pub const MaxInstructions: u32 = 100; 515 | } 516 | 517 | match_type! { 518 | pub type ParentOrParentsExecutivePlurality: impl Contains = { 519 | MultiLocation { parents: 1, interior: Here } | 520 | MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Executive, .. }) } 521 | }; 522 | } 523 | 524 | pub type Barrier = ( 525 | TakeWeightCredit, 526 | AllowTopLevelPaidExecutionFrom, 527 | AllowUnpaidExecutionFrom, 528 | // ^^^ Parent and its exec plurality get free execution 529 | ); 530 | 531 | pub struct XcmConfig; 532 | impl Config for XcmConfig { 533 | type Call = Call; 534 | type XcmSender = XcmRouter; 535 | // How to withdraw and deposit an asset. 536 | type AssetTransactor = LocalAssetTransactor; 537 | type OriginConverter = XcmOriginToTransactDispatchOrigin; 538 | type IsReserve = NativeAsset; 539 | type IsTeleporter = NativeAsset; // Should be enough to allow teleportation of ROC 540 | type LocationInverter = LocationInverter; 541 | type Barrier = Barrier; 542 | type Weigher = FixedWeightBounds; 543 | type Trader = UsingComponents, RelayLocation, AccountId, Balances, ()>; 544 | type ResponseHandler = PolkadotXcm; 545 | type AssetTrap = PolkadotXcm; 546 | type AssetClaims = PolkadotXcm; 547 | type SubscriptionService = PolkadotXcm; 548 | } 549 | 550 | parameter_types! { 551 | pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10; 552 | } 553 | 554 | /// No local origins on this chain are allowed to dispatch XCM sends/executions. 555 | pub type LocalOriginToLocation = (); 556 | 557 | /// The means for routing XCM messages which are not for local execution into the right message 558 | /// queues. 559 | pub type XcmRouter = ( 560 | // Two routers - use UMP to communicate with the relay chain: 561 | cumulus_primitives_utility::ParentAsUmp, 562 | // ..and XCMP to communicate with the sibling chains. 563 | XcmpQueue, 564 | ); 565 | 566 | impl pallet_xcm::Config for Runtime { 567 | type Event = Event; 568 | type SendXcmOrigin = EnsureXcmOrigin; 569 | type XcmRouter = XcmRouter; 570 | type ExecuteXcmOrigin = EnsureXcmOrigin; 571 | type XcmExecuteFilter = Everything; 572 | type XcmExecutor = XcmExecutor; 573 | type XcmTeleportFilter = Everything; 574 | type XcmReserveTransferFilter = Everything; 575 | type Weigher = FixedWeightBounds; 576 | type LocationInverter = LocationInverter; 577 | type Origin = Origin; 578 | type Call = Call; 579 | 580 | const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; 581 | // ^ Override for AdvertisedXcmVersion default 582 | type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; 583 | } 584 | 585 | impl cumulus_pallet_xcm::Config for Runtime { 586 | type Event = Event; 587 | type XcmExecutor = XcmExecutor; 588 | } 589 | 590 | impl cumulus_pallet_xcmp_queue::Config for Runtime { 591 | type Event = Event; 592 | type XcmExecutor = XcmExecutor; 593 | type ChannelInfo = ParachainSystem; 594 | type VersionWrapper = (); 595 | type ExecuteOverweightOrigin = EnsureRoot; 596 | type ControllerOrigin = EnsureOneOf< 597 | EnsureRoot, 598 | EnsureXcm>, 599 | >; 600 | type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; 601 | } 602 | 603 | impl cumulus_pallet_dmp_queue::Config for Runtime { 604 | type Event = Event; 605 | type XcmExecutor = XcmExecutor; 606 | type ExecuteOverweightOrigin = EnsureRoot; 607 | } 608 | 609 | parameter_types! { 610 | pub const Period: u32 = 6 * HOURS; 611 | pub const Offset: u32 = 0; 612 | pub const MaxAuthorities: u32 = 100_000; 613 | } 614 | 615 | impl pallet_session::Config for Runtime { 616 | type Event = Event; 617 | type ValidatorId = ::AccountId; 618 | // we don't have stash and controller, thus we don't need the convert as well. 619 | type ValidatorIdOf = pallet_collator_selection::IdentityCollator; 620 | type ShouldEndSession = pallet_session::PeriodicSessions; 621 | type NextSessionRotation = pallet_session::PeriodicSessions; 622 | type SessionManager = CollatorSelection; 623 | // Essentially just Aura, but lets be pedantic. 624 | type SessionHandler = ::KeyTypeIdProviders; 625 | type Keys = SessionKeys; 626 | type WeightInfo = (); // TODO: Add benchmarked weights. 627 | } 628 | 629 | impl pallet_aura::Config for Runtime { 630 | type AuthorityId = AuraId; 631 | type DisabledValidators = (); 632 | type MaxAuthorities = MaxAuthorities; 633 | } 634 | 635 | parameter_types! { 636 | pub const PotId: PalletId = PalletId(*b"PotStake"); 637 | pub const MaxCandidates: u32 = 1000; 638 | pub const MinCandidates: u32 = 5; 639 | pub const SessionLength: BlockNumber = 6 * HOURS; 640 | pub const MaxInvulnerables: u32 = 100; 641 | pub const ExecutiveBody: BodyId = BodyId::Executive; 642 | } 643 | 644 | // We allow root and the Relay Chain council to execute privileged collator selection operations. 645 | pub type CollatorSelectionUpdateOrigin = 646 | EnsureOneOf, EnsureXcm>>; 647 | 648 | impl pallet_collator_selection::Config for Runtime { 649 | type Event = Event; 650 | type Currency = Balances; 651 | type UpdateOrigin = CollatorSelectionUpdateOrigin; 652 | type PotId = PotId; 653 | type MaxCandidates = MaxCandidates; 654 | type MinCandidates = MinCandidates; 655 | type MaxInvulnerables = MaxInvulnerables; 656 | // should be a multiple of session or things will get inconsistent 657 | type KickThreshold = Period; 658 | type ValidatorId = ::AccountId; 659 | type ValidatorIdOf = pallet_collator_selection::IdentityCollator; 660 | type ValidatorRegistration = Session; 661 | type WeightInfo = (); // TODO: Add benchmarked weights. 662 | } 663 | 664 | // Create the runtime by composing the FRAME pallets that were previously configured. 665 | construct_runtime!( 666 | pub enum Runtime where 667 | Block = Block, 668 | NodeBlock = opaque::Block, 669 | UncheckedExtrinsic = UncheckedExtrinsic, 670 | { 671 | // System support stuff. 672 | System: frame_system::{Pallet, Call, Config, Storage, Event} = 0, 673 | ParachainSystem: cumulus_pallet_parachain_system::{ 674 | Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, 675 | } = 1, 676 | RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 2, 677 | Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, 678 | ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, 679 | 680 | // Monetary stuff. 681 | Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, 682 | TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 11, 683 | 684 | // Collator support. The order of these 4 are important and shall not change. 685 | Authorship: pallet_authorship::{Pallet, Call, Storage} = 20, 686 | CollatorSelection: pallet_collator_selection::{Pallet, Call, Storage, Event, Config} = 21, 687 | Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 22, 688 | Aura: pallet_aura::{Pallet, Storage, Config} = 23, 689 | AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 24, 690 | 691 | // XCM helpers. 692 | XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 30, 693 | PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, 694 | CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, 695 | DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, 696 | 697 | // Smart Contracts. 698 | Contracts: pallet_contracts::{Pallet, Call, Storage, Event} = 40, 699 | } 700 | ); 701 | 702 | impl_runtime_apis! { 703 | impl sp_consensus_aura::AuraApi for Runtime { 704 | fn slot_duration() -> sp_consensus_aura::SlotDuration { 705 | sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) 706 | } 707 | 708 | fn authorities() -> Vec { 709 | Aura::authorities().into_inner() 710 | } 711 | } 712 | 713 | impl sp_api::Core for Runtime { 714 | fn version() -> RuntimeVersion { 715 | VERSION 716 | } 717 | 718 | fn execute_block(block: Block) { 719 | Executive::execute_block(block) 720 | } 721 | 722 | fn initialize_block(header: &::Header) { 723 | Executive::initialize_block(header) 724 | } 725 | } 726 | 727 | impl sp_api::Metadata for Runtime { 728 | fn metadata() -> OpaqueMetadata { 729 | OpaqueMetadata::new(Runtime::metadata().into()) 730 | } 731 | } 732 | 733 | impl sp_block_builder::BlockBuilder for Runtime { 734 | fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { 735 | Executive::apply_extrinsic(extrinsic) 736 | } 737 | 738 | fn finalize_block() -> ::Header { 739 | Executive::finalize_block() 740 | } 741 | 742 | fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { 743 | data.create_extrinsics() 744 | } 745 | 746 | fn check_inherents( 747 | block: Block, 748 | data: sp_inherents::InherentData, 749 | ) -> sp_inherents::CheckInherentsResult { 750 | data.check_extrinsics(&block) 751 | } 752 | } 753 | 754 | impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { 755 | fn validate_transaction( 756 | source: TransactionSource, 757 | tx: ::Extrinsic, 758 | block_hash: ::Hash, 759 | ) -> TransactionValidity { 760 | Executive::validate_transaction(source, tx, block_hash) 761 | } 762 | } 763 | 764 | impl sp_offchain::OffchainWorkerApi for Runtime { 765 | fn offchain_worker(header: &::Header) { 766 | Executive::offchain_worker(header) 767 | } 768 | } 769 | 770 | impl sp_session::SessionKeys for Runtime { 771 | fn generate_session_keys(seed: Option>) -> Vec { 772 | SessionKeys::generate(seed) 773 | } 774 | 775 | fn decode_session_keys( 776 | encoded: Vec, 777 | ) -> Option, KeyTypeId)>> { 778 | SessionKeys::decode_into_raw_public_keys(&encoded) 779 | } 780 | } 781 | 782 | impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { 783 | fn account_nonce(account: AccountId) -> Index { 784 | System::account_nonce(account) 785 | } 786 | } 787 | 788 | impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { 789 | fn query_info( 790 | uxt: ::Extrinsic, 791 | len: u32, 792 | ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { 793 | TransactionPayment::query_info(uxt, len) 794 | } 795 | fn query_fee_details( 796 | uxt: ::Extrinsic, 797 | len: u32, 798 | ) -> pallet_transaction_payment::FeeDetails { 799 | TransactionPayment::query_fee_details(uxt, len) 800 | } 801 | } 802 | 803 | impl cumulus_primitives_core::CollectCollationInfo for Runtime { 804 | fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { 805 | ParachainSystem::collect_collation_info(header) 806 | } 807 | } 808 | 809 | impl pallet_contracts_rpc_runtime_api::ContractsApi 810 | for Runtime 811 | { 812 | fn call( 813 | origin: AccountId, 814 | dest: AccountId, 815 | value: Balance, 816 | gas_limit: u64, 817 | storage_deposit_limit: Option, 818 | input_data: Vec, 819 | ) -> pallet_contracts_primitives::ContractExecResult { 820 | Contracts::bare_call(origin, dest, value, gas_limit, storage_deposit_limit, input_data, CONTRACTS_DEBUG_OUTPUT) 821 | } 822 | 823 | fn instantiate( 824 | origin: AccountId, 825 | value: Balance, 826 | gas_limit: u64, 827 | storage_deposit_limit: Option, 828 | code: pallet_contracts_primitives::Code, 829 | data: Vec, 830 | salt: Vec, 831 | ) -> pallet_contracts_primitives::ContractInstantiateResult 832 | { 833 | Contracts::bare_instantiate(origin, value, gas_limit, storage_deposit_limit, code, data, salt, CONTRACTS_DEBUG_OUTPUT) 834 | } 835 | 836 | fn upload_code( 837 | origin: AccountId, 838 | code: Vec, 839 | storage_deposit_limit: Option, 840 | ) -> pallet_contracts_primitives::CodeUploadResult 841 | { 842 | Contracts::bare_upload_code(origin, code, storage_deposit_limit) 843 | } 844 | 845 | fn get_storage( 846 | address: AccountId, 847 | key: [u8; 32], 848 | ) -> pallet_contracts_primitives::GetStorageResult { 849 | Contracts::get_storage(address, key) 850 | } 851 | } 852 | 853 | #[cfg(feature = "try-runtime")] 854 | impl frame_try_runtime::TryRuntime for Runtime { 855 | fn on_runtime_upgrade() -> (Weight, Weight) { 856 | log::info!("try-runtime::on_runtime_upgrade thippy-parachain"); 857 | let weight = Executive::try_runtime_upgrade().unwrap(); 858 | (weight, RuntimeBlockWeights::get().max_block) 859 | } 860 | 861 | fn execute_block_no_check(block: Block) -> Weight { 862 | Executive::execute_block_no_check(block) 863 | } 864 | } 865 | 866 | #[cfg(feature = "runtime-benchmarks")] 867 | impl frame_benchmarking::Benchmark for Runtime { 868 | fn benchmark_metadata(extra: bool) -> ( 869 | Vec, 870 | Vec, 871 | ) { 872 | use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList}; 873 | use frame_support::traits::StorageInfoTrait; 874 | use frame_system_benchmarking::Pallet as SystemBench; 875 | use cumulus_pallet_session_benchmarking::Pallet as SessionBench; 876 | 877 | let mut list = Vec::::new(); 878 | 879 | list_benchmark!(list, extra, frame_system, SystemBench::); 880 | list_benchmark!(list, extra, pallet_balances, Balances); 881 | list_benchmark!(list, extra, pallet_timestamp, Timestamp); 882 | list_benchmark!(list, extra, pallet_collator_selection, CollatorSelection); 883 | 884 | let storage_info = AllPalletsWithSystem::storage_info(); 885 | 886 | return (list, storage_info) 887 | } 888 | 889 | fn dispatch_benchmark( 890 | config: frame_benchmarking::BenchmarkConfig 891 | ) -> Result, sp_runtime::RuntimeString> { 892 | use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; 893 | 894 | use frame_system_benchmarking::Pallet as SystemBench; 895 | impl frame_system_benchmarking::Config for Runtime {} 896 | 897 | use cumulus_pallet_session_benchmarking::Pallet as SessionBench; 898 | impl cumulus_pallet_session_benchmarking::Config for Runtime {} 899 | 900 | let whitelist: Vec = vec![ 901 | // Block Number 902 | hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), 903 | // Total Issuance 904 | hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), 905 | // Execution Phase 906 | hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), 907 | // Event Count 908 | hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), 909 | // System Events 910 | hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), 911 | ]; 912 | 913 | let mut batches = Vec::::new(); 914 | let params = (&config, &whitelist); 915 | 916 | add_benchmark!(params, batches, frame_system, SystemBench::); 917 | add_benchmark!(params, batches, pallet_balances, Balances); 918 | add_benchmark!(params, batches, pallet_session, SessionBench::); 919 | add_benchmark!(params, batches, pallet_timestamp, Timestamp); 920 | add_benchmark!(params, batches, pallet_collator_selection, CollatorSelection); 921 | 922 | if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } 923 | Ok(batches) 924 | } 925 | } 926 | } 927 | 928 | struct CheckInherents; 929 | 930 | impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { 931 | fn check_inherents( 932 | block: &Block, 933 | relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, 934 | ) -> sp_inherents::CheckInherentsResult { 935 | let relay_chain_slot = relay_state_proof 936 | .read_slot() 937 | .expect("Could not read the relay chain slot from the proof"); 938 | 939 | let inherent_data = 940 | cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( 941 | relay_chain_slot, 942 | sp_std::time::Duration::from_secs(6), 943 | ) 944 | .create_inherent_data() 945 | .expect("Could not create the timestamp inherent data"); 946 | 947 | inherent_data.check_extrinsics(block) 948 | } 949 | } 950 | 951 | cumulus_pallet_parachain_system::register_validate_block! { 952 | Runtime = Runtime, 953 | BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, 954 | CheckInherents = CheckInherents, 955 | } 956 | -------------------------------------------------------------------------------- /scripts/ci/pre_cache.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -u 4 | 5 | # if there is no directory for this $CI_COMMIT_REF_NAME/$CI_JOB_NAME 6 | # create such directory and 7 | # copy recursively all the files from the newest dir which has $CI_JOB_NAME, if it exists 8 | 9 | # cache lives in /ci-cache/${CI_PROJECT_NAME}/${2}/${CI_COMMIT_REF_NAME}/${CI_JOB_NAME} 10 | 11 | function prepopulate { 12 | if [[ ! -d $1 ]]; then 13 | mkdir -p "/ci-cache/$CI_PROJECT_NAME/$2/$CI_COMMIT_REF_NAME"; 14 | FRESH_CACHE=$(find "/ci-cache/$CI_PROJECT_NAME/$2" -mindepth 2 -maxdepth 2 \ 15 | -type d -name "$CI_JOB_NAME" -exec stat --printf="%Y\t%n\n" {} \; |sort -n -r |head -1 |cut -f2); 16 | if [[ -d $FRESH_CACHE ]]; then 17 | echo "____Using" "$FRESH_CACHE" "to prepopulate the cache____"; 18 | time cp -r "$FRESH_CACHE" "$1"; 19 | else 20 | echo "_____No such $2 dir, proceeding from scratch_____"; 21 | fi 22 | else 23 | echo "____No need to prepopulate $2 cache____"; 24 | fi 25 | } 26 | 27 | # CARGO_HOME cache is still broken so would be handled some other way. 28 | prepopulate "$CARGO_TARGET_DIR" targets 29 | -------------------------------------------------------------------------------- /scripts/dockerfiles/thippy_injected.Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile to build thippy docker image. Uses binary that was build externally. 2 | FROM docker.io/library/ubuntu:20.04 3 | 4 | # metadata 5 | ARG VCS_REF 6 | ARG BUILD_DATE 7 | ARG VERSION 8 | 9 | LABEL io.parity.image.title="thippy" \ 10 | io.parity.image.description="Thippy - A Smart Contracts Parachain" \ 11 | io.parity.image.source="https://github.com/ng8eke/thippy/blob/${VCS_REF}/scripts/dockerfiles/thippy_injected.Dockerfile" \ 12 | io.parity.image.url="https://github.com/ng8eke/thippy/blob/${VCS_REF}/scripts/dockerfiles/thippy_injected.Dockerfile" \ 13 | io.parity.image.documentation="https://github.com/ng8eke/thippy/blob/${VCS_REF}/README.md" \ 14 | io.parity.image.created="${BUILD_DATE}" \ 15 | io.parity.image.version="${VERSION}" \ 16 | io.parity.image.revision="${VCS_REF}" \ 17 | io.parity.image.authors="devops-team@parity.io" \ 18 | io.parity.image.vendor="Annie Lai" \ 19 | io.parity.image.licenses="GPL-3.0 License" 20 | 21 | # show backtraces 22 | ENV RUST_BACKTRACE 1 23 | ENV DEBIAN_FRONTEND=noninteractive 24 | 25 | # add non-root user 26 | RUN groupadd -g 1000 user && \ 27 | useradd -u 1000 -g user -s /bin/sh -m user 28 | 29 | # switch to non-root user 30 | USER user 31 | 32 | COPY --chown=root:root ./thippy /usr/local/bin/ 33 | 34 | # check if executable works in this container 35 | RUN /usr/local/bin/thippy --version 36 | 37 | EXPOSE 30333 9933 9944 38 | ENTRYPOINT ["/usr/local/bin/thippy"] 39 | -------------------------------------------------------------------------------- /scripts/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | echo "*** Initializing WASM build environment" 6 | 7 | if [ -z $CI_PROJECT_NAME ] ; then 8 | rustup update nightly 9 | rustup update stable 10 | fi 11 | 12 | rustup target add wasm32-unknown-unknown --toolchain nightly 13 | -------------------------------------------------------------------------------- /scripts/prepare-test-net.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # the script has been copied from https://github.com/ng8eke/polkadot/blob/master/scripts/prepare-test-net.sh. 5 | # the only changes were to remove unneeded `generate_address_and_account_id` calls. 6 | 7 | if [ "$#" -ne 1 ]; then 8 | echo "Please provide the number of initial validators!" 9 | exit 1 10 | fi 11 | 12 | generate_account_id() { 13 | subkey inspect ${3:-} ${4:-} "$SECRET//$1//$2" | grep "Account ID" | awk '{ print $3 }' 14 | } 15 | 16 | generate_address() { 17 | subkey inspect ${3:-} ${4:-} "$SECRET//$1//$2" | grep "SS58 Address" | awk '{ print $3 }' 18 | } 19 | 20 | generate_public_key() { 21 | subkey inspect ${3:-} ${4:-} "$SECRET//$1//$2" | grep "Public" | awk '{ print $4 }' 22 | } 23 | 24 | generate_address_and_public_key() { 25 | ADDRESS=$(generate_address $1 $2 $3) 26 | PUBLIC_KEY=$(generate_public_key $1 $2 $3) 27 | 28 | printf "//$ADDRESS\nhex![\"${PUBLIC_KEY#'0x'}\"].unchecked_into()," 29 | } 30 | 31 | generate_address_and_account_id() { 32 | ACCOUNT=$(generate_account_id $1 $2 $3) 33 | ADDRESS=$(generate_address $1 $2 $3) 34 | if ${4:-false}; then 35 | INTO="unchecked_into" 36 | else 37 | INTO="into" 38 | fi 39 | 40 | printf "//$ADDRESS\nhex![\"${ACCOUNT#'0x'}\"].$INTO()," 41 | } 42 | 43 | V_NUM=$1 44 | 45 | AUTHORITIES="" 46 | 47 | for i in $(seq 1 $V_NUM); do 48 | AUTHORITIES+="(\n" 49 | AUTHORITIES+="$(generate_address_and_account_id $i stash)\n" 50 | AUTHORITIES+="$(generate_address_and_account_id $i controller)\n" 51 | AUTHORITIES+="$(generate_address_and_account_id $i aura '--scheme sr25519' true)\n" 52 | AUTHORITIES+="),\n" 53 | done 54 | 55 | printf "$AUTHORITIES" 56 | -------------------------------------------------------------------------------- /scripts/substrate-diff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Helper script which outputs the diff to Substrate's `node-template`. 4 | # 5 | # Invoke with `SUBSTRATE_DIR=/path/to/substrate scripts/substrate-diff.sh`. 6 | 7 | SUBSTRATE_DIR=${SUBSTRATE_DIR:-~/projects/substrate} 8 | echo "Comparing with Substrate in directory $SUBSTRATE_DIR" 9 | 10 | for FILE in `fd -e rs -e toml --search-path node/ --search-path runtime/`; 11 | do 12 | DIFF=`diff $FILE $SUBSTRATE_DIR/bin/node-template/$FILE` 13 | EXIT_CODE=$? 14 | if [[ $EXIT_CODE -ne 0 ]]; then 15 | echo "Difference in: $FILE"; 16 | echo "$DIFF" 17 | fi 18 | done 19 | -------------------------------------------------------------------------------- /src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | use sp_core::{Pair, Public, sr25519}; 2 | use paracon_runtime::{ 3 | AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, 4 | SudoConfig, SystemConfig, WASM_BINARY, Signature, 5 | ContractsConfig, MILLICENTS, 6 | }; 7 | use sp_consensus_aura::sr25519::{AuthorityId as AuraId}; 8 | use grandpa_primitives::{AuthorityId as GrandpaId}; 9 | use sc_service; 10 | use sp_runtime::traits::{Verify, IdentifyAccount}; 11 | use hex_literal::hex; 12 | 13 | // Note this is the URL for the telemetry server 14 | //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; 15 | 16 | /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. 17 | pub type ChainSpec = sc_service::ChainSpec; 18 | 19 | /// The chain specification option. This is expected to come in from the CLI and 20 | /// is little more than one of a number of alternatives which can easily be converted 21 | /// from a string (`--chain=...`) into a `ChainSpec`. 22 | #[derive(Clone, Debug)] 23 | pub enum Alternative { 24 | /// Whatever the current runtime is, with just Alice as an auth. 25 | Development, 26 | /// Paracon Test net 1 27 | TestNet1, 28 | } 29 | 30 | /// Helper function to generate a crypto pair from seed 31 | pub fn get_from_seed(seed: &str) -> ::Public { 32 | TPublic::Pair::from_string(&format!("//{}", seed), None) 33 | .expect("static values are valid; qed") 34 | .public() 35 | } 36 | 37 | type AccountPublic = ::Signer; 38 | 39 | /// Helper function to generate an account ID from seed 40 | pub fn get_account_id_from_seed(seed: &str) -> AccountId where 41 | AccountPublic: From<::Public> 42 | { 43 | AccountPublic::from(get_from_seed::(seed)).into_account() 44 | } 45 | 46 | /// Helper function to generate an authority key for Aura 47 | pub fn get_authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { 48 | ( 49 | get_from_seed::(s), 50 | get_from_seed::(s), 51 | ) 52 | } 53 | 54 | pub fn testnet_authorities() -> Vec<(AuraId, GrandpaId)> { 55 | use sp_core::crypto::UncheckedInto; 56 | vec![ 57 | ( 58 | hex!("74608217b1709e1d3a4fe65b132db5c3f321e625026080833189661aa5e20712").unchecked_into(), 59 | hex!("a5abc21ac95ae63dd6e61e5bec263ab46d1efe16d3dcc085d0de297318cb662d").unchecked_into(), 60 | ), 61 | ( 62 | hex!("44f3876fe4f653533c65e79461a476b8d6a107fb71b6ec0f3485bb53b4e7b842").unchecked_into(), 63 | hex!("281be34a71b661b257153e1145522fd0820cfff6a3601b40e7f85d3bc155240d").unchecked_into(), 64 | ), 65 | ] 66 | } 67 | 68 | pub fn testnet_root() -> AccountId { 69 | hex!("baa78c7154c7f82d6d377177e20bcab65d327eca0086513f9964f5a0f6bdad56").into() 70 | } 71 | 72 | impl Alternative { 73 | /// Get an actual chain config from one of the alternatives. 74 | pub(crate) fn load(self) -> Result { 75 | Ok(match self { 76 | Alternative::Development => ChainSpec::from_genesis( 77 | "Development", 78 | "dev", 79 | || testnet_genesis(vec![ 80 | get_authority_keys_from_seed("Alice"), 81 | ], 82 | get_account_id_from_seed::("Alice"), 83 | vec![ 84 | get_account_id_from_seed::("Alice"), 85 | get_account_id_from_seed::("Bob"), 86 | get_account_id_from_seed::("Alice//stash"), 87 | get_account_id_from_seed::("Bob//stash"), 88 | ], 89 | true), 90 | vec![], 91 | None, 92 | None, 93 | None, 94 | None 95 | ), 96 | Alternative::TestNet1 => ChainSpec::from_genesis( 97 | "Paracon Testnet 1", 98 | "paracon_testnet1", 99 | || testnet_genesis( 100 | testnet_authorities(), 101 | testnet_root(), 102 | vec![testnet_root()], 103 | true, 104 | ), 105 | vec![ 106 | "/ip4/35.233.19.96/tcp/30333/p2p/QmNvYhAZSBtahCqCXznYiq8e24Yes1GraPFYCc3DyA5f3z".to_string(), 107 | "/ip4/35.205.110.21/tcp/30333/p2p/QmPKFc9B2oeQFc5oxbNsRENwSYibzzafKmcHs9wBZCJH4U".to_string(), 108 | ], 109 | None, 110 | Some("prc"), 111 | None, 112 | None 113 | ), 114 | }) 115 | } 116 | 117 | pub(crate) fn from(s: &str) -> Option { 118 | match s { 119 | "dev" => Some(Alternative::Development), 120 | "" | "local" => Some(Alternative::TestNet1), 121 | _ => None, 122 | } 123 | } 124 | } 125 | 126 | fn testnet_genesis( 127 | initial_authorities: Vec<(AuraId, GrandpaId)>, 128 | root_key: AccountId, 129 | endowed_accounts: Vec, 130 | enable_println: bool 131 | ) -> GenesisConfig { 132 | let mut contracts_config = ContractsConfig { 133 | current_schedule: Default::default(), 134 | gas_price: 1 * MILLICENTS, 135 | }; 136 | contracts_config.current_schedule.enable_println = enable_println; 137 | 138 | GenesisConfig { 139 | system: Some(SystemConfig { 140 | code: WASM_BINARY.to_vec(), 141 | changes_trie_config: Default::default(), 142 | }), 143 | balances: Some(BalancesConfig { 144 | balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(), 145 | }), 146 | sudo: Some(SudoConfig { 147 | key: root_key, 148 | }), 149 | aura: Some(AuraConfig { 150 | authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(), 151 | }), 152 | grandpa: Some(GrandpaConfig { 153 | authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(), 154 | }), 155 | contracts: Some(contracts_config), 156 | } 157 | } 158 | 159 | pub fn load_spec(id: &str) -> Result, String> { 160 | Ok(match Alternative::from(id) { 161 | Some(spec) => Some(spec.load()?), 162 | None => None, 163 | }) 164 | } 165 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use sc_cli::{RunCmd, Subcommand}; 2 | use structopt::StructOpt; 3 | 4 | #[derive(Debug, StructOpt)] 5 | pub struct Cli { 6 | #[structopt(subcommand)] 7 | pub subcommand: Option, 8 | 9 | #[structopt(flatten)] 10 | pub run: RunCmd, 11 | } 12 | -------------------------------------------------------------------------------- /src/command.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2020 Annie Lai. 2 | // This file is part of Substrate. 3 | 4 | // Substrate is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // Substrate is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with Substrate. If not, see . 16 | 17 | use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair}; 18 | use sc_cli::VersionInfo; 19 | use crate::service; 20 | use crate::chain_spec; 21 | use crate::cli::Cli; 22 | 23 | /// Parse and run command line arguments 24 | pub fn run(version: VersionInfo) -> sc_cli::Result<()> { 25 | let opt = sc_cli::from_args::(&version); 26 | 27 | let mut config = sc_service::Configuration::from_version(&version); 28 | 29 | match opt.subcommand { 30 | Some(subcommand) => { 31 | subcommand.init(&version)?; 32 | subcommand.update_config(&mut config, chain_spec::load_spec, &version)?; 33 | subcommand.run( 34 | config, 35 | |config: _| Ok(new_full_start!(config).0), 36 | ) 37 | }, 38 | None => { 39 | opt.run.init(&version)?; 40 | opt.run.update_config(&mut config, chain_spec::load_spec, &version)?; 41 | opt.run.run( 42 | config, 43 | service::new_light, 44 | service::new_full, 45 | &version, 46 | ) 47 | }, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | //! Substrate Node Template CLI library. 2 | #![warn(missing_docs)] 3 | 4 | mod chain_spec; 5 | #[macro_use] 6 | mod service; 7 | mod cli; 8 | mod command; 9 | 10 | pub use sc_cli::VersionInfo; 11 | 12 | fn main() -> sc_cli::Result<()> { 13 | let version = VersionInfo { 14 | name: "paracon", 15 | commit: env!("VERGEN_SHA_SHORT"), 16 | version: env!("CARGO_PKG_VERSION"), 17 | executable_name: "paracon", 18 | author: "Parity Team ", 19 | description: "Paracon Smart Contracts Chain Client Node", 20 | support_url: "https://github.com/ng8eke/paracon-node/issues/new", 21 | copyright_start_year: 2020, 22 | }; 23 | 24 | command::run(version) 25 | } 26 | -------------------------------------------------------------------------------- /src/service.rs: -------------------------------------------------------------------------------- 1 | //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. 2 | 3 | use std::sync::Arc; 4 | use std::time::Duration; 5 | use sc_client::LongestChain; 6 | use paracon_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi}; 7 | use sc_service::{error::{Error as ServiceError}, AbstractService, Configuration, ServiceBuilder}; 8 | use sp_inherents::InherentDataProviders; 9 | use sc_executor::native_executor_instance; 10 | pub use sc_executor::NativeExecutor; 11 | use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair}; 12 | use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; 13 | 14 | // Our native executor instance. 15 | native_executor_instance!( 16 | pub Executor, 17 | paracon_runtime::api::dispatch, 18 | paracon_runtime::native_version, 19 | ); 20 | 21 | /// Starts a `ServiceBuilder` for a full service. 22 | /// 23 | /// Use this macro if you don't actually need the full service, but just the builder in order to 24 | /// be able to perform chain operations. 25 | macro_rules! new_full_start { 26 | ($config:expr) => {{ 27 | use jsonrpc_core::IoHandler; 28 | 29 | let mut import_setup = None; 30 | let inherent_data_providers = sp_inherents::InherentDataProviders::new(); 31 | 32 | let builder = sc_service::ServiceBuilder::new_full::< 33 | paracon_runtime::opaque::Block, paracon_runtime::RuntimeApi, crate::service::Executor 34 | >($config)? 35 | .with_select_chain(|_config, backend| { 36 | Ok(sc_client::LongestChain::new(backend.clone())) 37 | })? 38 | .with_transaction_pool(|config, client, _fetcher| { 39 | let pool_api = sc_transaction_pool::FullChainApi::new(client.clone()); 40 | Ok(sc_transaction_pool::BasicPool::new(config, std::sync::Arc::new(pool_api))) 41 | })? 42 | .with_import_queue(|_config, client, mut select_chain, _transaction_pool| { 43 | let select_chain = select_chain.take() 44 | .ok_or_else(|| sc_service::Error::SelectChainRequired)?; 45 | 46 | let (grandpa_block_import, grandpa_link) = 47 | grandpa::block_import(client.clone(), &*client, select_chain)?; 48 | 49 | let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new( 50 | grandpa_block_import.clone(), client.clone(), 51 | ); 52 | 53 | let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair>( 54 | sc_consensus_aura::slot_duration(&*client)?, 55 | aura_block_import, 56 | Some(Box::new(grandpa_block_import.clone())), 57 | None, 58 | client, 59 | inherent_data_providers.clone(), 60 | )?; 61 | 62 | import_setup = Some((grandpa_block_import, grandpa_link)); 63 | 64 | Ok(import_queue) 65 | })? 66 | .with_rpc_extensions(|builder| -> Result, _> { 67 | let handler = contracts_rpc::Contracts::new(builder.client().clone()); 68 | let delegate = contracts_rpc::ContractsApi::to_delegate(handler); 69 | 70 | let mut io = IoHandler::default(); 71 | io.extend_with(delegate); 72 | Ok(io) 73 | })?; 74 | 75 | (builder, import_setup, inherent_data_providers) 76 | }} 77 | } 78 | 79 | /// Builds a new service for a full client. 80 | pub fn new_full(config: Configuration) 81 | -> Result 82 | { 83 | let is_authority = config.roles.is_authority(); 84 | let force_authoring = config.force_authoring; 85 | let name = config.name.clone(); 86 | let disable_grandpa = config.disable_grandpa; 87 | 88 | // sentry nodes announce themselves as authorities to the network 89 | // and should run the same protocols authorities do, but it should 90 | // never actively participate in any consensus process. 91 | let participates_in_consensus = is_authority && !config.sentry_mode; 92 | 93 | let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config); 94 | 95 | let (block_import, grandpa_link) = 96 | import_setup.take() 97 | .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); 98 | 99 | let service = builder 100 | .with_finality_proof_provider(|client, backend| 101 | Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _) 102 | )? 103 | .build()?; 104 | 105 | if participates_in_consensus { 106 | let proposer = sc_basic_authorship::ProposerFactory::new( 107 | service.client(), 108 | service.transaction_pool() 109 | ); 110 | 111 | let client = service.client(); 112 | let select_chain = service.select_chain() 113 | .ok_or(ServiceError::SelectChainRequired)?; 114 | 115 | let can_author_with = 116 | sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); 117 | 118 | let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _>( 119 | sc_consensus_aura::slot_duration(&*client)?, 120 | client, 121 | select_chain, 122 | block_import, 123 | proposer, 124 | service.network(), 125 | inherent_data_providers.clone(), 126 | force_authoring, 127 | service.keystore(), 128 | can_author_with, 129 | )?; 130 | 131 | // the AURA authoring task is considered essential, i.e. if it 132 | // fails we take down the service with it. 133 | service.spawn_essential_task("aura", aura); 134 | } 135 | 136 | // if the node isn't actively participating in consensus then it doesn't 137 | // need a keystore, regardless of which protocol we use below. 138 | let keystore = if participates_in_consensus { 139 | Some(service.keystore()) 140 | } else { 141 | None 142 | }; 143 | 144 | let grandpa_config = grandpa::Config { 145 | // FIXME #1578 make this available through chainspec 146 | gossip_duration: Duration::from_millis(333), 147 | justification_period: 512, 148 | name: Some(name), 149 | observer_enabled: false, 150 | keystore, 151 | is_authority, 152 | }; 153 | 154 | let enable_grandpa = !disable_grandpa; 155 | if enable_grandpa { 156 | // start the full GRANDPA voter 157 | // NOTE: non-authorities could run the GRANDPA observer protocol, but at 158 | // this point the full voter should provide better guarantees of block 159 | // and vote data availability than the observer. The observer has not 160 | // been tested extensively yet and having most nodes in a network run it 161 | // could lead to finality stalls. 162 | let grandpa_config = grandpa::GrandpaParams { 163 | config: grandpa_config, 164 | link: grandpa_link, 165 | network: service.network(), 166 | inherent_data_providers: inherent_data_providers.clone(), 167 | on_exit: service.on_exit(), 168 | telemetry_on_connect: Some(service.telemetry_on_connect_stream()), 169 | voting_rule: grandpa::VotingRulesBuilder::default().build(), 170 | }; 171 | 172 | // the GRANDPA voter task is considered infallible, i.e. 173 | // if it fails we take down the service with it. 174 | service.spawn_essential_task( 175 | "grandpa-voter", 176 | grandpa::run_grandpa_voter(grandpa_config)? 177 | ); 178 | } else { 179 | grandpa::setup_disabled_grandpa( 180 | service.client(), 181 | &inherent_data_providers, 182 | service.network(), 183 | )?; 184 | } 185 | 186 | Ok(service) 187 | } 188 | 189 | /// Builds a new service for a light client. 190 | pub fn new_light(config: Configuration) 191 | -> Result 192 | { 193 | let inherent_data_providers = InherentDataProviders::new(); 194 | 195 | ServiceBuilder::new_light::(config)? 196 | .with_select_chain(|_config, backend| { 197 | Ok(LongestChain::new(backend.clone())) 198 | })? 199 | .with_transaction_pool(|config, client, fetcher| { 200 | let fetcher = fetcher 201 | .ok_or_else(|| "Trying to start light transaction pool without active fetcher")?; 202 | 203 | let pool_api = sc_transaction_pool::LightChainApi::new(client.clone(), fetcher.clone()); 204 | let pool = sc_transaction_pool::BasicPool::with_revalidation_type( 205 | config, Arc::new(pool_api), sc_transaction_pool::RevalidationType::Light, 206 | ); 207 | Ok(pool) 208 | })? 209 | .with_import_queue_and_fprb(|_config, client, backend, fetcher, _select_chain, _tx_pool| { 210 | let fetch_checker = fetcher 211 | .map(|fetcher| fetcher.checker().clone()) 212 | .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; 213 | let grandpa_block_import = grandpa::light_block_import( 214 | client.clone(), backend, &*client.clone(), Arc::new(fetch_checker), 215 | )?; 216 | let finality_proof_import = grandpa_block_import.clone(); 217 | let finality_proof_request_builder = 218 | finality_proof_import.create_finality_proof_request_builder(); 219 | 220 | let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair>( 221 | sc_consensus_aura::slot_duration(&*client)?, 222 | grandpa_block_import, 223 | None, 224 | Some(Box::new(finality_proof_import)), 225 | client, 226 | inherent_data_providers.clone(), 227 | )?; 228 | 229 | Ok((import_queue, finality_proof_request_builder)) 230 | })? 231 | .with_finality_proof_provider(|client, backend| 232 | Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _) 233 | )? 234 | .build() 235 | } 236 | --------------------------------------------------------------------------------