├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── backlog-item.md │ ├── bug_report.md │ └── feature-request-or-epic.md └── pull_request_template.md ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── 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 ├── runtime ├── Cargo.toml ├── build.rs └── src │ └── lib.rs └── scripts ├── ci.sh ├── ci_docker.sh └── init.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | **/target/ -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/backlog-item.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Template For Internal Use 3 | about: Speccing out the details of development for specific features/epics 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## Implementation details 13 | 14 | 15 | ## Testing details 16 | 17 | 18 | ## Acceptance Criteria 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## Expected Behavior 13 | 14 | 15 | 16 | ## Current Behavior 17 | 18 | 19 | 20 | ## Possible Solution 21 | 22 | 23 | 24 | ## Steps to Reproduce (for bugs) 25 | 26 | 27 | 1. 28 | 2. 29 | 3. 30 | 4. 31 | 32 | ## Versions 33 | ChainBridge commit (or docker tag): 34 | chainbridge-solidity version: 35 | chainbridge-substrate version: 36 | Go version: 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request-or-epic.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request or epic 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Story 11 | As a 12 | I want 13 | So that I can 14 | 15 | ## Background 16 | 17 | 18 | ## Details 19 | 20 | 21 | ## Scenarios 22 | Scenario: 23 | Given I am 24 | When 25 | And 26 | Then 27 | 28 | ## Implementation details 29 | 30 | 31 | ## Testing details 32 | 33 | 34 | ## Acceptance criteria 35 | 36 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Related Issue Or Context 7 | 8 | 9 | 10 | 11 | Closes: # 12 | 13 | ## How Has This Been Tested? Testing details. 14 | 15 | 16 | 17 | 18 | ## Types of changes 19 | 20 | - [ ] Bug fix (non-breaking change which fixes an issue) 21 | - [ ] New feature (non-breaking change which adds functionality) 22 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 23 | - [ ] Documentation 24 | 25 | ## Checklist: 26 | 27 | 28 | - [ ] I have commented my code, particularly in hard-to-understand areas. 29 | - [ ] I have ensured that all acceptance criteria (or expected behavior) from issue are met 30 | - [ ] I have updated the documentation locally and in chainbridge-docs. 31 | - [ ] I have added tests to cover my changes. 32 | - [ ] I have ensured that all the checks are passing and green, I've signed the CLA bot 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | **/target/ 4 | # These are backup files generated by rustfmt 5 | **/*.rs.bk 6 | 7 | .DS_Store 8 | .idea/ -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [profile.release] 2 | panic = 'unwind' 3 | 4 | [workspace] 5 | members = [ 6 | 'node', 7 | 'runtime', 8 | ] 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Adapted from github.com/centrifuge/centrifuge-chain 2 | 3 | # Note: We don't use Alpine and its packaged Rust/Cargo because they're too often out of date, 4 | # preventing them from being used to build Substrate/Polkadot. 5 | 6 | FROM phusion/baseimage:0.10.2 as builder 7 | LABEL maintainer="david@chainsafe.io" 8 | LABEL description="This is the build stage for the node. Here the binary is created." 9 | 10 | ENV DEBIAN_FRONTEND=noninteractive 11 | ENV RUST_TOOLCHAIN=nightly-2020-08-16 12 | 13 | ARG PROFILE=release 14 | WORKDIR /chainbridge-substrate-chain 15 | 16 | COPY . /chainbridge-substrate-chain 17 | 18 | RUN apt-get update && \ 19 | apt-get dist-upgrade -y -o Dpkg::Options::="--force-confold" && \ 20 | apt-get install -y cmake pkg-config libssl-dev git clang 21 | 22 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \ 23 | export PATH="$PATH:$HOME/.cargo/bin" && \ 24 | rustup toolchain install $RUST_TOOLCHAIN && \ 25 | rustup target add wasm32-unknown-unknown --toolchain $RUST_TOOLCHAIN && \ 26 | rustup default $RUST_TOOLCHAIN && \ 27 | rustup default stable && \ 28 | cargo build "--$PROFILE" 29 | 30 | # ===== SECOND STAGE ====== 31 | 32 | FROM phusion/baseimage:0.10.2 33 | LABEL maintainer="david@chainsafe.io" 34 | LABEL description="This is the 2nd stage: a very small image that contains the chainbridge-substrate-chain binary and will be used by users." 35 | ARG PROFILE=release 36 | 37 | RUN mv /usr/share/ca* /tmp && \ 38 | rm -rf /usr/share/* && \ 39 | mv /tmp/ca-certificates /usr/share/ && \ 40 | mkdir -p /root/.local/share/chainbridge-substrate-chain && \ 41 | ln -s /root/.local/share/chainbridge-substrate-chain /data 42 | 43 | COPY --from=builder /chainbridge-substrate-chain/target/$PROFILE/chainbridge-substrate-chain /usr/local/bin 44 | 45 | # checks 46 | RUN ldd /usr/local/bin/chainbridge-substrate-chain && \ 47 | /usr/local/bin/chainbridge-substrate-chain --version 48 | 49 | # Shrinking 50 | RUN rm -rf /usr/lib/python* && \ 51 | rm -rf /usr/bin /usr/sbin /usr/share/man 52 | 53 | ## Add chain resources to image 54 | #COPY res /resources/ 55 | 56 | # USER chainbridge-substrate-chain # see above 57 | EXPOSE 30333 9933 9944 58 | VOLUME ["/data"] 59 | 60 | CMD ["/usr/local/bin/chainbridge-substrate-chain"] 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Archiving notice: 2 | 3 | This library is no longer in use and maintenance. All further development related to chainbridge will happen in the **[new](https://github.com/ChainSafe/chainbridge-core)** repo. More detailed information about chainbridge-core you can find in its readme or [Discussions](https://github.com/ChainSafe/chainbridge-core/discussions). 4 | 5 | If you already running an old ChainBridge version please consider checking **[chainbridge-migration](https://github.com/ChainSafe/chainbridge-migration)** scripts that allow migrating to a newer version of chainbridge. 6 | 7 | # chainbridge-substrate-chain 8 | 9 | A simple substrate chain for testing and demo purposes. 10 | 11 | This chain is based off the [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template) and includes `chainbridge` and `example-pallet` from [chainbridge-substrate](https://github.com/ChainSafe/chainbridge-substrate). 12 | 13 | ## Polkadot JS Apps 14 | 15 | You can interact with a local node by visiting https://polkadot.js.org/apps/. 16 | 17 | You will need to add these definitions to the developer settings: 18 | 19 | ```json 20 | { 21 | "chainbridge::ChainId": "u8", 22 | "ChainId": "u8", 23 | "ResourceId": "[u8; 32]", 24 | "DepositNonce": "u64", 25 | "ProposalVotes": { 26 | "votes_for": "Vec", 27 | "votes_against": "Vec", 28 | "status": "enum" 29 | }, 30 | "Erc721Token": { 31 | "id": "TokenId", 32 | "metadata": "Vec" 33 | }, 34 | "TokenId": "U256", 35 | "Address": "AccountId", 36 | "LookupSource": "AccountId" 37 | } 38 | ``` 39 | 40 | # ChainSafe Security Policy 41 | 42 | ## Reporting a Security Bug 43 | 44 | We take all security issues seriously, if you believe you have found a security issue within a ChainSafe 45 | project please notify us immediately. If an issue is confirmed, we will take all necessary precautions 46 | to ensure a statement and patch release is made in a timely manner. 47 | 48 | Please email us a description of the flaw and any related information (e.g. reproduction steps, version) to 49 | [security at chainsafe dot io](mailto:security@chainsafe.io). 50 | -------------------------------------------------------------------------------- /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 | authors = ['david@chainsafe.io'] 3 | build = 'build.rs' 4 | edition = '2018' 5 | homepage = 'https://substrate.dev' 6 | license = 'Unlicense' 7 | name = 'chainbridge-substrate-chain' 8 | repository = 'https://github.com/ChainSafe/chainbridge-substrate-chain' 9 | version = '2.0.0' 10 | 11 | [[bin]] 12 | name = 'chainbridge-substrate-chain' 13 | 14 | [package.metadata.docs.rs] 15 | targets = ['x86_64-unknown-linux-gnu'] 16 | 17 | [build-dependencies] 18 | substrate-build-script-utils = '2.0.0' 19 | 20 | [dependencies] 21 | jsonrpc-core = '15.0.0' 22 | structopt = '0.3.8' 23 | 24 | # local dependencies 25 | chainbridge-substrate-chain-runtime = { path = '../runtime', version = '2.0.0' } 26 | 27 | # Substrate dependencies 28 | frame-benchmarking = '2.0.0' 29 | frame-benchmarking-cli = '2.0.0' 30 | pallet-transaction-payment-rpc = '2.0.0' 31 | sc-basic-authorship = '0.8.0' 32 | sc-cli = { features = ['wasmtime'], version = '0.8.0' } 33 | sc-client-api = '2.0.0' 34 | sc-consensus = '0.8.0' 35 | sc-consensus-aura = '0.8.0' 36 | sc-executor = { features = ['wasmtime'], version = '0.8.0' } 37 | sc-finality-grandpa = '0.8.0' 38 | sc-rpc = '2.0.0' 39 | sc-rpc-api = '0.8.0' 40 | sc-service = { features = ['wasmtime'], version = '0.8.0' } 41 | sc-transaction-pool = '2.0.0' 42 | sp-api = '2.0.0' 43 | sp-block-builder = '2.0.0' 44 | sp-blockchain = '2.0.0' 45 | sp-consensus = '0.8.0' 46 | sp-consensus-aura = '0.8.0' 47 | sp-core = '2.0.0' 48 | sp-finality-grandpa = '2.0.0' 49 | sp-inherents = '2.0.0' 50 | sp-runtime = '2.0.0' 51 | sp-transaction-pool = '2.0.0' 52 | substrate-frame-rpc-system = '2.0.0' 53 | 54 | [features] 55 | default = [] 56 | runtime-benchmarks = ['chainbridge-substrate-chain-runtime/runtime-benchmarks'] -------------------------------------------------------------------------------- /node/build.rs: -------------------------------------------------------------------------------- 1 | use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; 2 | 3 | fn main() { 4 | generate_cargo_keys(); 5 | 6 | rerun_if_git_head_changed(); 7 | } 8 | -------------------------------------------------------------------------------- /node/src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | use sp_core::{Pair, Public, sr25519}; 2 | use chainbridge_substrate_chain_runtime::{ 3 | AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, 4 | SudoConfig, SystemConfig, WASM_BINARY, Signature 5 | }; 6 | use sp_consensus_aura::sr25519::AuthorityId as AuraId; 7 | use sp_finality_grandpa::AuthorityId as GrandpaId; 8 | use sp_runtime::traits::{Verify, IdentifyAccount, AccountIdConversion}; 9 | use sp_runtime::ModuleId; 10 | use sc_service::ChainType; 11 | 12 | // The URL for the telemetry server. 13 | // const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; 14 | 15 | /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. 16 | pub type ChainSpec = sc_service::GenericChainSpec; 17 | 18 | /// Generate a crypto pair from seed. 19 | pub fn get_from_seed(seed: &str) -> ::Public { 20 | TPublic::Pair::from_string(&format!("//{}", seed), None) 21 | .expect("static values are valid; qed") 22 | .public() 23 | } 24 | 25 | type AccountPublic = ::Signer; 26 | 27 | /// Generate an account ID from seed. 28 | pub fn get_account_id_from_seed(seed: &str) -> AccountId where 29 | AccountPublic: From<::Public> 30 | { 31 | AccountPublic::from(get_from_seed::(seed)).into_account() 32 | } 33 | 34 | /// Generate an Aura authority key. 35 | pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { 36 | ( 37 | get_from_seed::(s), 38 | get_from_seed::(s), 39 | ) 40 | } 41 | 42 | pub fn development_config() -> Result { 43 | let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?; 44 | 45 | Ok(ChainSpec::from_genesis( 46 | // Name 47 | "Development", 48 | // ID 49 | "dev", 50 | ChainType::Development, 51 | move || testnet_genesis( 52 | wasm_binary, 53 | // Initial PoA authorities 54 | vec![ 55 | authority_keys_from_seed("Alice"), 56 | ], 57 | // Sudo account 58 | get_account_id_from_seed::("Alice"), 59 | // Pre-funded accounts 60 | vec![ 61 | get_account_id_from_seed::("Alice"), 62 | get_account_id_from_seed::("Bob"), 63 | get_account_id_from_seed::("Charlie"), 64 | get_account_id_from_seed::("Dave"), 65 | get_account_id_from_seed::("Eve"), 66 | get_account_id_from_seed::("Ferdie"), 67 | get_account_id_from_seed::("Alice//stash"), 68 | get_account_id_from_seed::("Bob//stash"), 69 | get_account_id_from_seed::("Charlie//stash"), 70 | get_account_id_from_seed::("Dave//stash"), 71 | get_account_id_from_seed::("Eve//stash"), 72 | get_account_id_from_seed::("Ferdie//stash"), 73 | ModuleId(*b"cb/bridg").into_account(), 74 | ], 75 | true, 76 | ), 77 | // Bootnodes 78 | vec![], 79 | // Telemetry 80 | None, 81 | // Protocol ID 82 | None, 83 | // Properties 84 | None, 85 | // Extensions 86 | None, 87 | )) 88 | } 89 | 90 | pub fn local_testnet_config() -> Result { 91 | let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?; 92 | 93 | Ok(ChainSpec::from_genesis( 94 | // Name 95 | "Local Testnet", 96 | // ID 97 | "local_testnet", 98 | ChainType::Local, 99 | move || testnet_genesis( 100 | wasm_binary, 101 | // Initial PoA authorities 102 | vec![ 103 | authority_keys_from_seed("Alice"), 104 | authority_keys_from_seed("Bob"), 105 | ], 106 | // Sudo account 107 | get_account_id_from_seed::("Alice"), 108 | // Pre-funded accounts 109 | vec![ 110 | get_account_id_from_seed::("Alice"), 111 | get_account_id_from_seed::("Bob"), 112 | get_account_id_from_seed::("Charlie"), 113 | get_account_id_from_seed::("Dave"), 114 | get_account_id_from_seed::("Eve"), 115 | get_account_id_from_seed::("Ferdie"), 116 | get_account_id_from_seed::("Alice//stash"), 117 | get_account_id_from_seed::("Bob//stash"), 118 | get_account_id_from_seed::("Charlie//stash"), 119 | get_account_id_from_seed::("Dave//stash"), 120 | get_account_id_from_seed::("Eve//stash"), 121 | get_account_id_from_seed::("Ferdie//stash"), 122 | ModuleId(*b"cb/bridg").into_account(), 123 | ], 124 | true, 125 | ), 126 | // Bootnodes 127 | vec![], 128 | // Telemetry 129 | None, 130 | // Protocol ID 131 | None, 132 | // Properties 133 | None, 134 | // Extensions 135 | None, 136 | )) 137 | } 138 | 139 | /// Configure initial storage state for FRAME modules. 140 | fn testnet_genesis( 141 | wasm_binary: &[u8], 142 | initial_authorities: Vec<(AuraId, GrandpaId)>, 143 | root_key: AccountId, 144 | endowed_accounts: Vec, 145 | _enable_println: bool, 146 | ) -> GenesisConfig { 147 | GenesisConfig { 148 | frame_system: Some(SystemConfig { 149 | // Add Wasm runtime to storage. 150 | code: wasm_binary.to_vec(), 151 | changes_trie_config: Default::default(), 152 | }), 153 | pallet_balances: Some(BalancesConfig { 154 | // Configure endowed accounts with initial balance of 1 << 60. 155 | balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(), 156 | }), 157 | pallet_aura: Some(AuraConfig { 158 | authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(), 159 | }), 160 | pallet_grandpa: Some(GrandpaConfig { 161 | authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(), 162 | }), 163 | pallet_sudo: Some(SudoConfig { 164 | // Assign network admin rights. 165 | key: root_key, 166 | }), 167 | } 168 | } 169 | 170 | -------------------------------------------------------------------------------- /node/src/cli.rs: -------------------------------------------------------------------------------- 1 | use structopt::StructOpt; 2 | use sc_cli::RunCmd; 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 | 13 | #[derive(Debug, StructOpt)] 14 | pub enum Subcommand { 15 | /// Build a chain specification. 16 | BuildSpec(sc_cli::BuildSpecCmd), 17 | 18 | /// Validate blocks. 19 | CheckBlock(sc_cli::CheckBlockCmd), 20 | 21 | /// Export blocks. 22 | ExportBlocks(sc_cli::ExportBlocksCmd), 23 | 24 | /// Export the state of a given block into a chain spec. 25 | ExportState(sc_cli::ExportStateCmd), 26 | 27 | /// Import blocks. 28 | ImportBlocks(sc_cli::ImportBlocksCmd), 29 | 30 | /// Remove the whole chain. 31 | PurgeChain(sc_cli::PurgeChainCmd), 32 | 33 | /// Revert the chain to a previous state. 34 | Revert(sc_cli::RevertCmd), 35 | 36 | /// The custom benchmark subcommmand benchmarking runtime pallets. 37 | #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] 38 | Benchmark(frame_benchmarking_cli::BenchmarkCmd), 39 | } 40 | -------------------------------------------------------------------------------- /node/src/command.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Substrate. 2 | 3 | // Copyright (C) 2017-2020 Parity Technologies (UK) Ltd. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | use crate::{chain_spec, service}; 19 | use crate::cli::{Cli, Subcommand}; 20 | use sc_cli::{SubstrateCli, RuntimeVersion, Role, ChainSpec}; 21 | use sc_service::PartialComponents; 22 | use chainbridge_substrate_chain_runtime::Block; 23 | 24 | impl SubstrateCli for Cli { 25 | fn impl_name() -> String { 26 | "Substrate Node".into() 27 | } 28 | 29 | fn impl_version() -> String { 30 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 31 | } 32 | 33 | fn description() -> String { 34 | env!("CARGO_PKG_DESCRIPTION").into() 35 | } 36 | 37 | fn author() -> String { 38 | env!("CARGO_PKG_AUTHORS").into() 39 | } 40 | 41 | fn support_url() -> String { 42 | "support.anonymous.an".into() 43 | } 44 | 45 | fn copyright_start_year() -> i32 { 46 | 2017 47 | } 48 | 49 | fn load_spec(&self, id: &str) -> Result, String> { 50 | Ok(match id { 51 | "dev" => Box::new(chain_spec::development_config()?), 52 | "" | "local" => Box::new(chain_spec::local_testnet_config()?), 53 | path => Box::new(chain_spec::ChainSpec::from_json_file( 54 | std::path::PathBuf::from(path), 55 | )?), 56 | }) 57 | } 58 | 59 | fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { 60 | &chainbridge_substrate_chain_runtime::VERSION 61 | } 62 | } 63 | 64 | /// Parse and run command line arguments 65 | pub fn run() -> sc_cli::Result<()> { 66 | let cli = Cli::from_args(); 67 | 68 | match &cli.subcommand { 69 | Some(Subcommand::BuildSpec(cmd)) => { 70 | let runner = cli.create_runner(cmd)?; 71 | runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) 72 | }, 73 | Some(Subcommand::CheckBlock(cmd)) => { 74 | let runner = cli.create_runner(cmd)?; 75 | runner.async_run(|config| { 76 | let PartialComponents { client, task_manager, import_queue, ..} 77 | = service::new_partial(&config)?; 78 | Ok((cmd.run(client, import_queue), task_manager)) 79 | }) 80 | }, 81 | Some(Subcommand::ExportBlocks(cmd)) => { 82 | let runner = cli.create_runner(cmd)?; 83 | runner.async_run(|config| { 84 | let PartialComponents { client, task_manager, ..} 85 | = service::new_partial(&config)?; 86 | Ok((cmd.run(client, config.database), task_manager)) 87 | }) 88 | }, 89 | Some(Subcommand::ExportState(cmd)) => { 90 | let runner = cli.create_runner(cmd)?; 91 | runner.async_run(|config| { 92 | let PartialComponents { client, task_manager, ..} 93 | = service::new_partial(&config)?; 94 | Ok((cmd.run(client, config.chain_spec), task_manager)) 95 | }) 96 | }, 97 | Some(Subcommand::ImportBlocks(cmd)) => { 98 | let runner = cli.create_runner(cmd)?; 99 | runner.async_run(|config| { 100 | let PartialComponents { client, task_manager, import_queue, ..} 101 | = service::new_partial(&config)?; 102 | Ok((cmd.run(client, import_queue), task_manager)) 103 | }) 104 | }, 105 | Some(Subcommand::PurgeChain(cmd)) => { 106 | let runner = cli.create_runner(cmd)?; 107 | runner.sync_run(|config| cmd.run(config.database)) 108 | }, 109 | Some(Subcommand::Revert(cmd)) => { 110 | let runner = cli.create_runner(cmd)?; 111 | runner.async_run(|config| { 112 | let PartialComponents { client, task_manager, backend, ..} 113 | = service::new_partial(&config)?; 114 | Ok((cmd.run(client, backend), task_manager)) 115 | }) 116 | }, 117 | Some(Subcommand::Benchmark(cmd)) => { 118 | if cfg!(feature = "runtime-benchmarks") { 119 | let runner = cli.create_runner(cmd)?; 120 | 121 | runner.sync_run(|config| cmd.run::(config)) 122 | } else { 123 | Err("Benchmarking wasn't enabled when building the node. \ 124 | You can enable it with `--features runtime-benchmarks`.".into()) 125 | } 126 | }, 127 | None => { 128 | let runner = cli.create_runner(&cli.run)?; 129 | runner.run_node_until_exit(|config| match config.role { 130 | Role::Light => service::new_light(config), 131 | _ => service::new_full(config), 132 | }) 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /node/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod chain_spec; 2 | pub mod service; 3 | pub mod rpc; 4 | -------------------------------------------------------------------------------- /node/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 | mod rpc; 10 | 11 | fn main() -> sc_cli::Result<()> { 12 | command::run() 13 | } 14 | -------------------------------------------------------------------------------- /node/src/rpc.rs: -------------------------------------------------------------------------------- 1 | //! A collection of node-specific RPC methods. 2 | //! Substrate provides the `sc-rpc` crate, which defines the core RPC layer 3 | //! used by Substrate nodes. This file extends those RPC definitions with 4 | //! capabilities that are specific to this project's runtime configuration. 5 | 6 | #![warn(missing_docs)] 7 | 8 | use std::sync::Arc; 9 | 10 | use chainbridge_substrate_chain_runtime::{opaque::Block, AccountId, Balance, Index}; 11 | use sp_api::ProvideRuntimeApi; 12 | use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend}; 13 | use sp_block_builder::BlockBuilder; 14 | pub use sc_rpc_api::DenyUnsafe; 15 | use sp_transaction_pool::TransactionPool; 16 | 17 | 18 | /// Full client dependencies. 19 | pub struct FullDeps { 20 | /// The client instance to use. 21 | pub client: Arc, 22 | /// Transaction pool instance. 23 | pub pool: Arc

, 24 | /// Whether to deny unsafe calls 25 | pub deny_unsafe: DenyUnsafe, 26 | } 27 | 28 | /// Instantiate all full RPC extensions. 29 | pub fn create_full( 30 | deps: FullDeps, 31 | ) -> jsonrpc_core::IoHandler where 32 | C: ProvideRuntimeApi, 33 | C: HeaderBackend + HeaderMetadata + 'static, 34 | C: Send + Sync + 'static, 35 | C::Api: substrate_frame_rpc_system::AccountNonceApi, 36 | C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, 37 | C::Api: BlockBuilder, 38 | P: TransactionPool + 'static, 39 | { 40 | use substrate_frame_rpc_system::{FullSystem, SystemApi}; 41 | use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; 42 | 43 | let mut io = jsonrpc_core::IoHandler::default(); 44 | let FullDeps { 45 | client, 46 | pool, 47 | deny_unsafe, 48 | } = deps; 49 | 50 | io.extend_with( 51 | SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)) 52 | ); 53 | 54 | io.extend_with( 55 | TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())) 56 | ); 57 | 58 | // Extend this RPC with a custom API by using the following syntax. 59 | // `YourRpcStruct` should have a reference to a client, which is needed 60 | // to call into the runtime. 61 | // `io.extend_with(YourRpcTrait::to_delegate(YourRpcStruct::new(ReferenceToClient, ...)));` 62 | 63 | io 64 | } 65 | -------------------------------------------------------------------------------- /node/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_api::{ExecutorProvider, RemoteBackend}; 6 | use chainbridge_substrate_chain_runtime::{self, opaque::Block, RuntimeApi}; 7 | use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; 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 sc_finality_grandpa::{FinalityProofProvider as GrandpaFinalityProofProvider, SharedVoterState}; 13 | 14 | // Our native executor instance. 15 | native_executor_instance!( 16 | pub Executor, 17 | chainbridge_substrate_chain_runtime::api::dispatch, 18 | chainbridge_substrate_chain_runtime::native_version, 19 | frame_benchmarking::benchmarking::HostFunctions, 20 | ); 21 | 22 | type FullClient = sc_service::TFullClient; 23 | type FullBackend = sc_service::TFullBackend; 24 | type FullSelectChain = sc_consensus::LongestChain; 25 | 26 | pub fn new_partial(config: &Configuration) -> Result, 29 | sc_transaction_pool::FullPool, 30 | ( 31 | sc_consensus_aura::AuraBlockImport< 32 | Block, 33 | FullClient, 34 | sc_finality_grandpa::GrandpaBlockImport, 35 | AuraPair 36 | >, 37 | sc_finality_grandpa::LinkHalf 38 | ) 39 | >, ServiceError> { 40 | let inherent_data_providers = sp_inherents::InherentDataProviders::new(); 41 | 42 | let (client, backend, keystore, task_manager) = 43 | sc_service::new_full_parts::(&config)?; 44 | let client = Arc::new(client); 45 | 46 | let select_chain = sc_consensus::LongestChain::new(backend.clone()); 47 | 48 | let transaction_pool = sc_transaction_pool::BasicPool::new_full( 49 | config.transaction_pool.clone(), 50 | config.prometheus_registry(), 51 | task_manager.spawn_handle(), 52 | client.clone(), 53 | ); 54 | 55 | let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import( 56 | client.clone(), &(client.clone() as Arc<_>), select_chain.clone(), 57 | )?; 58 | 59 | let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new( 60 | grandpa_block_import.clone(), client.clone(), 61 | ); 62 | 63 | let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _, _>( 64 | sc_consensus_aura::slot_duration(&*client)?, 65 | aura_block_import.clone(), 66 | Some(Box::new(grandpa_block_import.clone())), 67 | None, 68 | client.clone(), 69 | inherent_data_providers.clone(), 70 | &task_manager.spawn_handle(), 71 | config.prometheus_registry(), 72 | sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()), 73 | )?; 74 | 75 | Ok(sc_service::PartialComponents { 76 | client, backend, task_manager, import_queue, keystore, select_chain, transaction_pool, 77 | inherent_data_providers, 78 | other: (aura_block_import, grandpa_link), 79 | }) 80 | } 81 | 82 | /// Builds a new service for a full client. 83 | pub fn new_full(config: Configuration) -> Result { 84 | let sc_service::PartialComponents { 85 | client, backend, mut task_manager, import_queue, keystore, select_chain, transaction_pool, 86 | inherent_data_providers, 87 | other: (block_import, grandpa_link), 88 | } = new_partial(&config)?; 89 | 90 | let finality_proof_provider = 91 | GrandpaFinalityProofProvider::new_for_service(backend.clone(), client.clone()); 92 | 93 | let (network, network_status_sinks, system_rpc_tx, network_starter) = 94 | sc_service::build_network(sc_service::BuildNetworkParams { 95 | config: &config, 96 | client: client.clone(), 97 | transaction_pool: transaction_pool.clone(), 98 | spawn_handle: task_manager.spawn_handle(), 99 | import_queue, 100 | on_demand: None, 101 | block_announce_validator_builder: None, 102 | finality_proof_request_builder: None, 103 | finality_proof_provider: Some(finality_proof_provider.clone()), 104 | })?; 105 | 106 | if config.offchain_worker.enabled { 107 | sc_service::build_offchain_workers( 108 | &config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(), 109 | ); 110 | } 111 | 112 | let role = config.role.clone(); 113 | let force_authoring = config.force_authoring; 114 | let name = config.network.node_name.clone(); 115 | let enable_grandpa = !config.disable_grandpa; 116 | let prometheus_registry = config.prometheus_registry().cloned(); 117 | let telemetry_connection_sinks = sc_service::TelemetryConnectionSinks::default(); 118 | 119 | let rpc_extensions_builder = { 120 | let client = client.clone(); 121 | let pool = transaction_pool.clone(); 122 | 123 | Box::new(move |deny_unsafe, _| { 124 | let deps = crate::rpc::FullDeps { 125 | client: client.clone(), 126 | pool: pool.clone(), 127 | deny_unsafe, 128 | }; 129 | 130 | crate::rpc::create_full(deps) 131 | }) 132 | }; 133 | 134 | sc_service::spawn_tasks(sc_service::SpawnTasksParams { 135 | network: network.clone(), 136 | client: client.clone(), 137 | keystore: keystore.clone(), 138 | task_manager: &mut task_manager, 139 | transaction_pool: transaction_pool.clone(), 140 | telemetry_connection_sinks: telemetry_connection_sinks.clone(), 141 | rpc_extensions_builder: rpc_extensions_builder, 142 | on_demand: None, 143 | remote_blockchain: None, 144 | backend, network_status_sinks, system_rpc_tx, config, 145 | })?; 146 | 147 | if role.is_authority() { 148 | let proposer = sc_basic_authorship::ProposerFactory::new( 149 | client.clone(), 150 | transaction_pool, 151 | prometheus_registry.as_ref(), 152 | ); 153 | 154 | let can_author_with = 155 | sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); 156 | 157 | let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _>( 158 | sc_consensus_aura::slot_duration(&*client)?, 159 | client.clone(), 160 | select_chain, 161 | block_import, 162 | proposer, 163 | network.clone(), 164 | inherent_data_providers.clone(), 165 | force_authoring, 166 | keystore.clone(), 167 | can_author_with, 168 | )?; 169 | 170 | // the AURA authoring task is considered essential, i.e. if it 171 | // fails we take down the service with it. 172 | task_manager.spawn_essential_handle().spawn_blocking("aura", aura); 173 | } 174 | 175 | // if the node isn't actively participating in consensus then it doesn't 176 | // need a keystore, regardless of which protocol we use below. 177 | let keystore = if role.is_authority() { 178 | Some(keystore as sp_core::traits::BareCryptoStorePtr) 179 | } else { 180 | None 181 | }; 182 | 183 | let grandpa_config = sc_finality_grandpa::Config { 184 | // FIXME #1578 make this available through chainspec 185 | gossip_duration: Duration::from_millis(333), 186 | justification_period: 512, 187 | name: Some(name), 188 | observer_enabled: false, 189 | keystore, 190 | is_authority: role.is_network_authority(), 191 | }; 192 | 193 | if enable_grandpa { 194 | // start the full GRANDPA voter 195 | // NOTE: non-authorities could run the GRANDPA observer protocol, but at 196 | // this point the full voter should provide better guarantees of block 197 | // and vote data availability than the observer. The observer has not 198 | // been tested extensively yet and having most nodes in a network run it 199 | // could lead to finality stalls. 200 | let grandpa_config = sc_finality_grandpa::GrandpaParams { 201 | config: grandpa_config, 202 | link: grandpa_link, 203 | network, 204 | inherent_data_providers, 205 | telemetry_on_connect: Some(telemetry_connection_sinks.on_connect_stream()), 206 | voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(), 207 | prometheus_registry, 208 | shared_voter_state: SharedVoterState::empty(), 209 | }; 210 | 211 | // the GRANDPA voter task is considered infallible, i.e. 212 | // if it fails we take down the service with it. 213 | task_manager.spawn_essential_handle().spawn_blocking( 214 | "grandpa-voter", 215 | sc_finality_grandpa::run_grandpa_voter(grandpa_config)? 216 | ); 217 | } else { 218 | sc_finality_grandpa::setup_disabled_grandpa( 219 | client, 220 | &inherent_data_providers, 221 | network, 222 | )?; 223 | } 224 | 225 | network_starter.start_network(); 226 | Ok(task_manager) 227 | } 228 | 229 | /// Builds a new service for a light client. 230 | pub fn new_light(config: Configuration) -> Result { 231 | let (client, backend, keystore, mut task_manager, on_demand) = 232 | sc_service::new_light_parts::(&config)?; 233 | 234 | let transaction_pool = Arc::new(sc_transaction_pool::BasicPool::new_light( 235 | config.transaction_pool.clone(), 236 | config.prometheus_registry(), 237 | task_manager.spawn_handle(), 238 | client.clone(), 239 | on_demand.clone(), 240 | )); 241 | 242 | let grandpa_block_import = sc_finality_grandpa::light_block_import( 243 | client.clone(), backend.clone(), &(client.clone() as Arc<_>), 244 | Arc::new(on_demand.checker().clone()) as Arc<_>, 245 | )?; 246 | let finality_proof_import = grandpa_block_import.clone(); 247 | let finality_proof_request_builder = 248 | finality_proof_import.create_finality_proof_request_builder(); 249 | 250 | let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _, _>( 251 | sc_consensus_aura::slot_duration(&*client)?, 252 | grandpa_block_import, 253 | None, 254 | Some(Box::new(finality_proof_import)), 255 | client.clone(), 256 | InherentDataProviders::new(), 257 | &task_manager.spawn_handle(), 258 | config.prometheus_registry(), 259 | sp_consensus::NeverCanAuthor, 260 | )?; 261 | 262 | let finality_proof_provider = 263 | GrandpaFinalityProofProvider::new_for_service(backend.clone(), client.clone()); 264 | 265 | let (network, network_status_sinks, system_rpc_tx, network_starter) = 266 | sc_service::build_network(sc_service::BuildNetworkParams { 267 | config: &config, 268 | client: client.clone(), 269 | transaction_pool: transaction_pool.clone(), 270 | spawn_handle: task_manager.spawn_handle(), 271 | import_queue, 272 | on_demand: Some(on_demand.clone()), 273 | block_announce_validator_builder: None, 274 | finality_proof_request_builder: Some(finality_proof_request_builder), 275 | finality_proof_provider: Some(finality_proof_provider), 276 | })?; 277 | 278 | if config.offchain_worker.enabled { 279 | sc_service::build_offchain_workers( 280 | &config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(), 281 | ); 282 | } 283 | 284 | sc_service::spawn_tasks(sc_service::SpawnTasksParams { 285 | remote_blockchain: Some(backend.remote_blockchain()), 286 | transaction_pool, 287 | task_manager: &mut task_manager, 288 | on_demand: Some(on_demand), 289 | rpc_extensions_builder: Box::new(|_, _| ()), 290 | telemetry_connection_sinks: sc_service::TelemetryConnectionSinks::default(), 291 | config, 292 | client, 293 | keystore, 294 | backend, 295 | network, 296 | network_status_sinks, 297 | system_rpc_tx, 298 | })?; 299 | 300 | network_starter.start_network(); 301 | 302 | Ok(task_manager) 303 | } 304 | -------------------------------------------------------------------------------- /runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['Substrate DevHub '] 3 | edition = '2018' 4 | homepage = 'https://substrate.dev' 5 | license = 'Unlicense' 6 | name = 'chainbridge-substrate-chain-runtime' 7 | repository = 'https://github.com/ChainSafe/chainbridge-substrate-chain' 8 | version = '2.0.0' 9 | 10 | [package.metadata.docs.rs] 11 | targets = ['x86_64-unknown-linux-gnu'] 12 | 13 | [build-dependencies] 14 | wasm-builder-runner = { package = 'substrate-wasm-builder-runner', version = '2.0.0' } 15 | 16 | # alias "parity-scale-code" to "codec" 17 | [dependencies.codec] 18 | default-features = false 19 | features = ['derive'] 20 | package = 'parity-scale-codec' 21 | version = '1.3.4' 22 | 23 | [dependencies] 24 | hex-literal = { optional = true, version = '0.3.1' } 25 | serde = { features = ['derive'], optional = true, version = '1.0.101' } 26 | 27 | # Substrate dependencies 28 | frame-benchmarking = { default-features = false, optional = true, version = '2.0.0' } 29 | frame-executive = { default-features = false, version = '2.0.0' } 30 | frame-support = { default-features = false, version = '2.0.0' } 31 | frame-system = { default-features = false, version = '2.0.0' } 32 | frame-system-benchmarking = { default-features = false, optional = true, version = '2.0.0' } 33 | frame-system-rpc-runtime-api = { default-features = false, version = '2.0.0' } 34 | pallet-aura = { default-features = false, version = '2.0.0' } 35 | pallet-balances = { default-features = false, version = '2.0.0' } 36 | pallet-grandpa = { default-features = false, version = '2.0.0' } 37 | pallet-randomness-collective-flip = { default-features = false, version = '2.0.0' } 38 | pallet-sudo = { default-features = false, version = '2.0.0' } 39 | pallet-timestamp = { default-features = false, version = '2.0.0' } 40 | pallet-transaction-payment = { default-features = false, version = '2.0.0' } 41 | pallet-transaction-payment-rpc-runtime-api = { default-features = false, version = '2.0.0' } 42 | sp-api = { default-features = false, version = '2.0.0' } 43 | sp-block-builder = { default-features = false, version = '2.0.0' } 44 | sp-consensus-aura = { default-features = false, version = '0.8.0' } 45 | sp-core = { default-features = false, version = '2.0.0' } 46 | sp-inherents = { default-features = false, version = '2.0.0' } 47 | sp-io = { default-features = false, version = '2.0.0' } 48 | sp-offchain = { default-features = false, version = '2.0.0' } 49 | sp-runtime = { default-features = false, version = '2.0.0' } 50 | sp-session = { default-features = false, version = '2.0.0' } 51 | sp-std = { default-features = false, version = '2.0.0' } 52 | sp-transaction-pool = { default-features = false, version = '2.0.0' } 53 | sp-version = { default-features = false, version = '2.0.0' } 54 | 55 | [dependencies.chainbridge] 56 | default-features = false 57 | git = 'https://github.com/ChainSafe/chainbridge-substrate' 58 | package = 'chainbridge' 59 | tag = 'v1.3.0' 60 | 61 | [dependencies.example] 62 | default-features = false 63 | git = 'https://github.com/ChainSafe/chainbridge-substrate' 64 | package = 'example-pallet' 65 | tag = 'v1.3.0' 66 | 67 | [dependencies.erc721] 68 | default-features = false 69 | git = 'https://github.com/ChainSafe/chainbridge-substrate' 70 | package = 'example-erc721' 71 | tag = 'v1.3.0' 72 | 73 | [features] 74 | default = ['std'] 75 | runtime-benchmarks = [ 76 | 'hex-literal', 77 | 'frame-benchmarking', 78 | 'frame-support/runtime-benchmarks', 79 | 'frame-system-benchmarking', 80 | 'frame-system/runtime-benchmarks', 81 | 'pallet-balances/runtime-benchmarks', 82 | 'pallet-timestamp/runtime-benchmarks', 83 | 'sp-runtime/runtime-benchmarks', 84 | ] 85 | std = [ 86 | 'codec/std', 87 | 'serde', 88 | 'frame-executive/std', 89 | 'frame-support/std', 90 | 'frame-system/std', 91 | 'frame-system-rpc-runtime-api/std', 92 | 'pallet-aura/std', 93 | 'pallet-balances/std', 94 | 'pallet-grandpa/std', 95 | 'pallet-randomness-collective-flip/std', 96 | 'pallet-sudo/std', 97 | 'pallet-timestamp/std', 98 | 'pallet-transaction-payment/std', 99 | 'pallet-transaction-payment-rpc-runtime-api/std', 100 | 'sp-api/std', 101 | 'sp-block-builder/std', 102 | 'sp-consensus-aura/std', 103 | 'sp-core/std', 104 | 'sp-inherents/std', 105 | 'sp-io/std', 106 | 'sp-offchain/std', 107 | 'sp-runtime/std', 108 | 'sp-session/std', 109 | 'sp-std/std', 110 | 'sp-transaction-pool/std', 111 | 'sp-version/std', 112 | 'chainbridge/std', 113 | 'erc721/std', 114 | 'example/std', 115 | ] 116 | 117 | -------------------------------------------------------------------------------- /runtime/build.rs: -------------------------------------------------------------------------------- 1 | use wasm_builder_runner::WasmBuilder; 2 | 3 | fn main() { 4 | WasmBuilder::new() 5 | .with_current_project() 6 | .with_wasm_builder_from_crates("2.0.0") 7 | .export_heap_base() 8 | .import_memory() 9 | .build() 10 | } 11 | -------------------------------------------------------------------------------- /runtime/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. 3 | #![recursion_limit="256"] 4 | 5 | // Make the WASM binary available. 6 | #[cfg(feature = "std")] 7 | include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); 8 | 9 | use sp_std::prelude::*; 10 | use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; 11 | use sp_io::hashing::blake2_128; 12 | use sp_runtime::{ 13 | ApplyExtrinsicResult, generic, create_runtime_str, impl_opaque_keys, MultiSignature, 14 | transaction_validity::{TransactionValidity, TransactionSource}, 15 | }; 16 | use sp_runtime::traits::{ 17 | BlakeTwo256, Block as BlockT, IdentityLookup, Verify, IdentifyAccount, NumberFor, Saturating, 18 | }; 19 | use sp_api::impl_runtime_apis; 20 | use sp_consensus_aura::sr25519::AuthorityId as AuraId; 21 | use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; 22 | use pallet_grandpa::fg_primitives; 23 | use sp_version::RuntimeVersion; 24 | #[cfg(feature = "std")] 25 | use sp_version::NativeVersion; 26 | 27 | // A few exports that help ease life for downstream crates. 28 | #[cfg(any(feature = "std", test))] 29 | pub use sp_runtime::BuildStorage; 30 | pub use pallet_timestamp::Call as TimestampCall; 31 | pub use pallet_balances::Call as BalancesCall; 32 | pub use sp_runtime::{Permill, Perbill}; 33 | pub use frame_support::{ 34 | construct_runtime, parameter_types, StorageValue, 35 | traits::{KeyOwnerProofSystem, Randomness}, 36 | weights::{ 37 | Weight, IdentityFee, 38 | constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, 39 | }, 40 | }; 41 | 42 | /// An index to a block. 43 | pub type BlockNumber = u32; 44 | 45 | /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. 46 | pub type Signature = MultiSignature; 47 | 48 | /// Some way of identifying an account on the chain. We intentionally make it equivalent 49 | /// to the public key of our transaction signing scheme. 50 | pub type AccountId = <::Signer as IdentifyAccount>::AccountId; 51 | 52 | /// The type for looking up accounts. We don't expect more than 4 billion of them, but you 53 | /// never know... 54 | pub type AccountIndex = u32; 55 | 56 | /// Balance of an account. 57 | pub type Balance = u128; 58 | 59 | /// Index of a transaction in the chain. 60 | pub type Index = u32; 61 | 62 | /// A hash of some data used by the chain. 63 | pub type Hash = sp_core::H256; 64 | 65 | /// Digest item type. 66 | pub type DigestItem = generic::DigestItem; 67 | 68 | /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know 69 | /// the specifics of the runtime. They can then be made to be agnostic over specific formats 70 | /// of data like extrinsics, allowing for them to continue syncing the network through upgrades 71 | /// to even the core data structures. 72 | pub mod opaque { 73 | use super::*; 74 | 75 | pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; 76 | 77 | /// Opaque block header type. 78 | pub type Header = generic::Header; 79 | /// Opaque block type. 80 | pub type Block = generic::Block; 81 | /// Opaque block identifier type. 82 | pub type BlockId = generic::BlockId; 83 | 84 | impl_opaque_keys! { 85 | pub struct SessionKeys { 86 | pub aura: Aura, 87 | pub grandpa: Grandpa, 88 | } 89 | } 90 | } 91 | 92 | pub const VERSION: RuntimeVersion = RuntimeVersion { 93 | spec_name: create_runtime_str!("chainbridge-substrate-chain"), 94 | impl_name: create_runtime_str!("chainbridge-substrate-chain"), 95 | authoring_version: 1, 96 | spec_version: 1, 97 | impl_version: 1, 98 | apis: RUNTIME_API_VERSIONS, 99 | transaction_version: 1, 100 | }; 101 | 102 | pub const MILLISECS_PER_BLOCK: u64 = 6000; 103 | 104 | pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; 105 | 106 | // Time is measured by number of blocks. 107 | pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); 108 | pub const HOURS: BlockNumber = MINUTES * 60; 109 | pub const DAYS: BlockNumber = HOURS * 24; 110 | 111 | /// The version information used to identify this runtime when compiled natively. 112 | #[cfg(feature = "std")] 113 | pub fn native_version() -> NativeVersion { 114 | NativeVersion { 115 | runtime_version: VERSION, 116 | can_author_with: Default::default(), 117 | } 118 | } 119 | 120 | parameter_types! { 121 | pub const BlockHashCount: BlockNumber = 2400; 122 | /// We allow for 2 seconds of compute with a 6 second average block time. 123 | pub const MaximumBlockWeight: Weight = 2 * WEIGHT_PER_SECOND; 124 | pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); 125 | /// Assume 10% of weight for average on_initialize calls. 126 | pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get() 127 | .saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get(); 128 | pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; 129 | pub const Version: RuntimeVersion = VERSION; 130 | } 131 | 132 | // Configure FRAME pallets to include in runtime. 133 | 134 | impl frame_system::Trait for Runtime { 135 | /// The basic call filter to use in dispatchable. 136 | type BaseCallFilter = (); 137 | /// The identifier used to distinguish between accounts. 138 | type AccountId = AccountId; 139 | /// The aggregated dispatch type that is available for extrinsics. 140 | type Call = Call; 141 | /// The lookup mechanism to get account ID from whatever is passed in dispatchers. 142 | type Lookup = IdentityLookup; 143 | /// The index type for storing how many extrinsics an account has signed. 144 | type Index = Index; 145 | /// The index type for blocks. 146 | type BlockNumber = BlockNumber; 147 | /// The type for hashing blocks and tries. 148 | type Hash = Hash; 149 | /// The hashing algorithm used. 150 | type Hashing = BlakeTwo256; 151 | /// The header type. 152 | type Header = generic::Header; 153 | /// The ubiquitous event type. 154 | type Event = Event; 155 | /// The ubiquitous origin type. 156 | type Origin = Origin; 157 | /// Maximum number of block number to block hash mappings to keep (oldest pruned first). 158 | type BlockHashCount = BlockHashCount; 159 | /// Maximum weight of each block. 160 | type MaximumBlockWeight = MaximumBlockWeight; 161 | /// The weight of database operations that the runtime can invoke. 162 | type DbWeight = RocksDbWeight; 163 | /// The weight of the overhead invoked on the block import process, independent of the 164 | /// extrinsics included in that block. 165 | type BlockExecutionWeight = BlockExecutionWeight; 166 | /// The base weight of any extrinsic processed by the runtime, independent of the 167 | /// logic of that extrinsic. (Signature verification, nonce increment, fee, etc...) 168 | type ExtrinsicBaseWeight = ExtrinsicBaseWeight; 169 | /// The maximum weight that a single extrinsic of `Normal` dispatch class can have, 170 | /// idependent of the logic of that extrinsics. (Roughly max block weight - average on 171 | /// initialize cost). 172 | type MaximumExtrinsicWeight = MaximumExtrinsicWeight; 173 | /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. 174 | type MaximumBlockLength = MaximumBlockLength; 175 | /// Portion of the block weight that is available to all normal transactions. 176 | type AvailableBlockRatio = AvailableBlockRatio; 177 | /// Version of the runtime. 178 | type Version = Version; 179 | /// Converts a module to the index of the module in `construct_runtime!`. 180 | /// 181 | /// This type is being generated by `construct_runtime!`. 182 | type PalletInfo = PalletInfo; 183 | /// What to do if a new account is created. 184 | type OnNewAccount = (); 185 | /// What to do if an account is fully reaped from the system. 186 | type OnKilledAccount = (); 187 | /// The data to be stored in an account. 188 | type AccountData = pallet_balances::AccountData; 189 | /// Weight information for the extrinsics of this pallet. 190 | type SystemWeightInfo = (); 191 | } 192 | 193 | impl pallet_aura::Trait for Runtime { 194 | type AuthorityId = AuraId; 195 | } 196 | 197 | impl pallet_grandpa::Trait for Runtime { 198 | type Event = Event; 199 | type Call = Call; 200 | 201 | type KeyOwnerProofSystem = (); 202 | 203 | type KeyOwnerProof = 204 | >::Proof; 205 | 206 | type KeyOwnerIdentification = >::IdentificationTuple; 210 | 211 | type HandleEquivocation = (); 212 | 213 | type WeightInfo = (); 214 | } 215 | 216 | parameter_types! { 217 | pub const MinimumPeriod: u64 = SLOT_DURATION / 2; 218 | } 219 | 220 | impl pallet_timestamp::Trait for Runtime { 221 | /// A timestamp: milliseconds since the unix epoch. 222 | type Moment = u64; 223 | type OnTimestampSet = Aura; 224 | type MinimumPeriod = MinimumPeriod; 225 | type WeightInfo = (); 226 | } 227 | 228 | parameter_types! { 229 | pub const ExistentialDeposit: u128 = 500; 230 | pub const MaxLocks: u32 = 50; 231 | } 232 | 233 | impl pallet_balances::Trait for Runtime { 234 | type MaxLocks = MaxLocks; 235 | /// The type for recording an account's balance. 236 | type Balance = Balance; 237 | /// The ubiquitous event type. 238 | type Event = Event; 239 | type DustRemoval = (); 240 | type ExistentialDeposit = ExistentialDeposit; 241 | type AccountStore = System; 242 | type WeightInfo = (); 243 | } 244 | 245 | parameter_types! { 246 | pub const TransactionByteFee: Balance = 1; 247 | } 248 | 249 | impl pallet_transaction_payment::Trait for Runtime { 250 | type Currency = Balances; 251 | type OnTransactionPayment = (); 252 | type TransactionByteFee = TransactionByteFee; 253 | type WeightToFee = IdentityFee; 254 | type FeeMultiplierUpdate = (); 255 | } 256 | 257 | impl pallet_sudo::Trait for Runtime { 258 | type Event = Event; 259 | type Call = Call; 260 | } 261 | 262 | parameter_types! { 263 | pub const ChainId: u8 = 1; 264 | pub const ProposalLifetime: BlockNumber = 1000; 265 | } 266 | 267 | impl chainbridge::Trait for Runtime { 268 | type Event = Event; 269 | type AdminOrigin = frame_system::EnsureRoot; 270 | type Proposal = Call; 271 | type ChainId = ChainId; 272 | type ProposalLifetime = ProposalLifetime; 273 | } 274 | 275 | parameter_types! { 276 | pub HashId: chainbridge::ResourceId = chainbridge::derive_resource_id(1, &blake2_128(b"hash")); 277 | // Note: Chain ID is 0 indicating this is native to another chain 278 | pub NativeTokenId: chainbridge::ResourceId = chainbridge::derive_resource_id(0, &blake2_128(b"DAV")); 279 | 280 | pub NFTTokenId: chainbridge::ResourceId = chainbridge::derive_resource_id(1, &blake2_128(b"NFT")); 281 | } 282 | 283 | impl erc721::Trait for Runtime { 284 | type Event = Event; 285 | type Identifier = NFTTokenId; 286 | } 287 | 288 | impl example::Trait for Runtime { 289 | type Event = Event; 290 | type BridgeOrigin = chainbridge::EnsureBridge; 291 | type Currency = pallet_balances::Module; 292 | type HashId = HashId; 293 | type NativeTokenId = NativeTokenId; 294 | type Erc721Id = NFTTokenId; 295 | } 296 | 297 | // Create the runtime by composing the FRAME pallets that were previously configured. 298 | construct_runtime!( 299 | pub enum Runtime where 300 | Block = Block, 301 | NodeBlock = opaque::Block, 302 | UncheckedExtrinsic = UncheckedExtrinsic 303 | { 304 | System: frame_system::{Module, Call, Config, Storage, Event}, 305 | RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage}, 306 | Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent}, 307 | Aura: pallet_aura::{Module, Config, Inherent}, 308 | Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event}, 309 | Balances: pallet_balances::{Module, Call, Storage, Config, Event}, 310 | TransactionPayment: pallet_transaction_payment::{Module, Storage}, 311 | Sudo: pallet_sudo::{Module, Call, Config, Storage, Event}, 312 | ChainBridge: chainbridge::{Module, Call, Storage, Event}, 313 | Example: example::{Module, Call, Event}, 314 | Erc721: erc721::{Module, Call, Storage, Event}, 315 | } 316 | ); 317 | 318 | /// The address format for describing accounts. 319 | pub type Address = AccountId; 320 | /// Block header type as expected by this runtime. 321 | pub type Header = generic::Header; 322 | /// Block type as expected by this runtime. 323 | pub type Block = generic::Block; 324 | /// A Block signed with a Justification 325 | pub type SignedBlock = generic::SignedBlock; 326 | /// BlockId type as expected by this runtime. 327 | pub type BlockId = generic::BlockId; 328 | /// The SignedExtension to the basic transaction logic. 329 | pub type SignedExtra = ( 330 | frame_system::CheckSpecVersion, 331 | frame_system::CheckTxVersion, 332 | frame_system::CheckGenesis, 333 | frame_system::CheckEra, 334 | frame_system::CheckNonce, 335 | frame_system::CheckWeight, 336 | pallet_transaction_payment::ChargeTransactionPayment 337 | ); 338 | /// Unchecked extrinsic type as expected by this runtime. 339 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; 340 | /// Extrinsic type that has already been checked. 341 | pub type CheckedExtrinsic = generic::CheckedExtrinsic; 342 | /// Executive: handles dispatch to the various modules. 343 | pub type Executive = frame_executive::Executive< 344 | Runtime, 345 | Block, 346 | frame_system::ChainContext, 347 | Runtime, 348 | AllModules, 349 | >; 350 | 351 | impl_runtime_apis! { 352 | impl sp_api::Core for Runtime { 353 | fn version() -> RuntimeVersion { 354 | VERSION 355 | } 356 | 357 | fn execute_block(block: Block) { 358 | Executive::execute_block(block) 359 | } 360 | 361 | fn initialize_block(header: &::Header) { 362 | Executive::initialize_block(header) 363 | } 364 | } 365 | 366 | impl sp_api::Metadata for Runtime { 367 | fn metadata() -> OpaqueMetadata { 368 | Runtime::metadata().into() 369 | } 370 | } 371 | 372 | impl sp_block_builder::BlockBuilder for Runtime { 373 | fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { 374 | Executive::apply_extrinsic(extrinsic) 375 | } 376 | 377 | fn finalize_block() -> ::Header { 378 | Executive::finalize_block() 379 | } 380 | 381 | fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { 382 | data.create_extrinsics() 383 | } 384 | 385 | fn check_inherents( 386 | block: Block, 387 | data: sp_inherents::InherentData, 388 | ) -> sp_inherents::CheckInherentsResult { 389 | data.check_extrinsics(&block) 390 | } 391 | 392 | fn random_seed() -> ::Hash { 393 | RandomnessCollectiveFlip::random_seed() 394 | } 395 | } 396 | 397 | impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { 398 | fn validate_transaction( 399 | source: TransactionSource, 400 | tx: ::Extrinsic, 401 | ) -> TransactionValidity { 402 | Executive::validate_transaction(source, tx) 403 | } 404 | } 405 | 406 | impl sp_offchain::OffchainWorkerApi for Runtime { 407 | fn offchain_worker(header: &::Header) { 408 | Executive::offchain_worker(header) 409 | } 410 | } 411 | 412 | impl sp_consensus_aura::AuraApi for Runtime { 413 | fn slot_duration() -> u64 { 414 | Aura::slot_duration() 415 | } 416 | 417 | fn authorities() -> Vec { 418 | Aura::authorities() 419 | } 420 | } 421 | 422 | impl sp_session::SessionKeys for Runtime { 423 | fn generate_session_keys(seed: Option>) -> Vec { 424 | opaque::SessionKeys::generate(seed) 425 | } 426 | 427 | fn decode_session_keys( 428 | encoded: Vec, 429 | ) -> Option, KeyTypeId)>> { 430 | opaque::SessionKeys::decode_into_raw_public_keys(&encoded) 431 | } 432 | } 433 | 434 | impl fg_primitives::GrandpaApi for Runtime { 435 | fn grandpa_authorities() -> GrandpaAuthorityList { 436 | Grandpa::grandpa_authorities() 437 | } 438 | 439 | fn submit_report_equivocation_unsigned_extrinsic( 440 | _equivocation_proof: fg_primitives::EquivocationProof< 441 | ::Hash, 442 | NumberFor, 443 | >, 444 | _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, 445 | ) -> Option<()> { 446 | None 447 | } 448 | 449 | fn generate_key_ownership_proof( 450 | _set_id: fg_primitives::SetId, 451 | _authority_id: GrandpaId, 452 | ) -> Option { 453 | // NOTE: this is the only implementation possible since we've 454 | // defined our key owner proof type as a bottom type (i.e. a type 455 | // with no values). 456 | None 457 | } 458 | } 459 | 460 | impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { 461 | fn account_nonce(account: AccountId) -> Index { 462 | System::account_nonce(account) 463 | } 464 | } 465 | 466 | impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { 467 | fn query_info( 468 | uxt: ::Extrinsic, 469 | len: u32, 470 | ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { 471 | TransactionPayment::query_info(uxt, len) 472 | } 473 | } 474 | } 475 | -------------------------------------------------------------------------------- /scripts/ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | RUST_TOOLCHAIN="${RUST_TOOLCHAIN:-nightly}" 6 | 7 | # Enable warnings about unused extern crates 8 | export RUSTFLAGS=" -W unused-extern-crates" 9 | 10 | # Install rustup and the specified rust toolchain. 11 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y 12 | rustup toolchain install $RUST_TOOLCHAIN --allow-downgrade --profile minimal --component clippy 13 | 14 | # Load cargo environment. Specifically, put cargo into PATH. 15 | source ~/.cargo/env 16 | 17 | sudo apt-get -y update 18 | sudo apt-get install -y cmake pkg-config libssl-dev 19 | 20 | rustup target add wasm32-unknown-unknown --toolchain $RUST_TOOLCHAIN 21 | 22 | rustc --version 23 | rustup --version 24 | cargo --version 25 | 26 | case $TARGET in 27 | "build-client") 28 | cargo build --release --locked "$@" 29 | ;; 30 | 31 | "runtime-test") 32 | cargo test -p chainbridge-substrate-chain 33 | ;; 34 | esac 35 | -------------------------------------------------------------------------------- /scripts/ci_docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | GIT_SHORT_COMMIT=`git rev-parse --short HEAD` 4 | TIMESTAMP=`date -u +%Y%m%d%H%M%S` 5 | IMAGE_NAME="chainsafe/chainbridge-substrate-chain" 6 | TAG=${TAG:-"${TIMESTAMP}-${GIT_SHORT_COMMIT}"} 7 | 8 | 9 | case $TARGET in 10 | "default") 11 | echo "Pushing image with tag $TAG" 12 | docker tag ${IMAGE_NAME}:latest ${IMAGE_NAME}:${TAG} 13 | echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin 14 | docker push ${IMAGE_NAME}:${TAG} 15 | ;; 16 | 17 | "release") 18 | echo "Pushing image with tag $TAG" 19 | docker tag ${IMAGE_NAME}:latest ${IMAGE_NAME}:${TAG} 20 | echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin 21 | docker push ${IMAGE_NAME}:${TAG} 22 | ;; 23 | esac 24 | 25 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------