From 4760f5e5ebb9b102489c0b130b71bda772239aff Mon Sep 17 00:00:00 2001 From: lzw <657434763@qq.com> Date: Thu, 13 Jan 2022 16:02:34 +0800 Subject: [PATCH] first add --- .gitignore | 2 + Cargo.toml | 10 + Dockerfile | 14 + README.md | 217 ++++- dockerize.sh | 7 + docs/rust-setup.md | 81 ++ node/Cargo.toml | 273 ++++++ node/build.rs | 7 + node/src/chain_spec.rs | 344 ++++++++ node/src/cli.rs | 41 + node/src/command.rs | 139 +++ node/src/lib.rs | 3 + node/src/main.rs | 13 + node/src/rpc.rs | 215 +++++ node/src/service.rs | 602 +++++++++++++ pallets/provider/Cargo.toml | 93 ++ pallets/provider/src/lib.rs | 416 +++++++++ pallets/resource-order/Cargo.toml | 100 +++ pallets/resource-order/src/benchmarking.rs | 29 + pallets/resource-order/src/lib.rs | 933 +++++++++++++++++++++ pallets/template/Cargo.toml | 92 ++ pallets/template/README.md | 1 + pallets/template/src/benchmarking.rs | 40 + pallets/template/src/lib.rs | 183 ++++ pallets/template/src/mock.rs | 62 ++ pallets/template/src/tests.rs | 23 + pallets/template/src/weights.rs | 99 +++ primitives/Cargo.toml | 78 ++ primitives/src/constants.rs | 30 + primitives/src/lib.rs | 32 + primitives/src/p_provider.rs | 197 +++++ primitives/src/p_resource_order.rs | 339 ++++++++ runtime/Cargo.toml | 325 +++++++ runtime/build.rs | 9 + runtime/src/lib.rs | 880 +++++++++++++++++++ scripts/docker_run.sh | 12 + scripts/init.sh | 12 + shell.nix | 35 + 38 files changed, 5986 insertions(+), 2 deletions(-) create mode 100644 Cargo.toml create mode 100644 Dockerfile create mode 100644 dockerize.sh create mode 100644 docs/rust-setup.md create mode 100644 node/Cargo.toml create mode 100644 node/build.rs create mode 100644 node/src/chain_spec.rs create mode 100644 node/src/cli.rs create mode 100644 node/src/command.rs create mode 100644 node/src/lib.rs create mode 100644 node/src/main.rs create mode 100644 node/src/rpc.rs create mode 100644 node/src/service.rs create mode 100644 pallets/provider/Cargo.toml create mode 100644 pallets/provider/src/lib.rs create mode 100644 pallets/resource-order/Cargo.toml create mode 100644 pallets/resource-order/src/benchmarking.rs create mode 100644 pallets/resource-order/src/lib.rs create mode 100644 pallets/template/Cargo.toml create mode 100644 pallets/template/README.md create mode 100644 pallets/template/src/benchmarking.rs create mode 100644 pallets/template/src/lib.rs create mode 100644 pallets/template/src/mock.rs create mode 100644 pallets/template/src/tests.rs create mode 100644 pallets/template/src/weights.rs create mode 100644 primitives/Cargo.toml create mode 100644 primitives/src/constants.rs create mode 100644 primitives/src/lib.rs create mode 100644 primitives/src/p_provider.rs create mode 100644 primitives/src/p_resource_order.rs create mode 100644 runtime/Cargo.toml create mode 100644 runtime/build.rs create mode 100644 runtime/src/lib.rs create mode 100644 scripts/docker_run.sh create mode 100755 scripts/init.sh create mode 100644 shell.nix diff --git a/.gitignore b/.gitignore index 088ba6ba7d..a453f2bdf2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + +/.idea \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..3d578c5779 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] +members = [ + 'node', + 'pallets/template', + 'pallets/resource-order', + 'runtime', + 'primitives' +] +[profile.release] +panic = 'unwind' diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..113505296d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +## ImageBuild +FROM debian:11 + +RUN apt-get update && \ + apt-get install -y openssl && \ + rm /var/lib/apt/ -rf && \ + rm /var/cache/apt/ -rf + +WORKDIR /opt/ttchain/ + +#COPY ./docker/run.sh /opt/run.sh +ADD ./target/release/node-template /opt/ttchain/node-template + +#CMD /opt/run.sh diff --git a/README.md b/README.md index 05530802d9..9809f3c621 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,215 @@ -# hamster -Blockchain Implementation of hamster share +# Substrate Node Template + +[![Try on playground](https://img.shields.io/badge/Playground-Node_Template-brightgreen?logo=Parity%20Substrate)](https://playground.substrate.dev/?deploy=node-template) + +A fresh FRAME-based [Substrate](https://www.substrate.io/) node, ready for hacking :rocket: + +## Getting Started + +Follow the steps below to get started with the Node Template, or get it up and running right from your browser +in just a few clicks Using [Playground](https://playground.substrate.dev/) :hammer_and_wrench: + +### Using Nix + +Install [nix](https://nixos.org/) and optionally [direnv](https://github.com/direnv/direnv) and [lorri](https://github.com/target/lorri) for a fully plug +and play experience for setting up the development environment. To get all the correct dependencies activate direnv `direnv allow` and lorri `lorri shell`. + +### Rust Setup + +First, complete the [basic Rust setup instructions](./docs/rust-setup.md). + +### Run + +Use Rust's native `cargo` command to build and launch the template node: + +```sh +cargo run --release -- --dev --tmp +``` + +### Build + +The `cargo run` command will perform an initial build. Use the following command to build the node +without launching it: + +```sh +cargo build --release +``` + +### Embedded Docs + +Once the project has been built, the following command can be used to explore all parameters and +subcommands: + +```sh +./target/release/node-template -h +``` + +## Run + +The provided `cargo run` command will launch a temporary node and its state will be discarded after +you terminate the process. After the project has been built, there are other ways to launch the +node. + +### Single-Node Development Chain + +This command will start the single-node development chain with persistent state: + +```bash +./target/release/node-template --dev +``` + +Purge the development chain's state: + +```bash +./target/release/node-template purge-chain --dev +``` + +Start the development chain with detailed logging: + +```bash +RUST_LOG=debug RUST_BACKTRACE=1 ./target/release/node-template -lruntime=debug --dev +``` + +### Connect with Polkadot-JS Apps Front-end + +Once the node template is running locally, you can connect it with **Polkadot-JS Apps** front-end +to interact with your chain. [Click here](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944) connecting the Apps to your local node template. + +### Multi-Node Local Testnet + +If you want to see the multi-node consensus algorithm in action, refer to +[our Start a Private Network tutorial](https://substrate.dev/docs/en/tutorials/start-a-private-network/). + +## Template Structure + +A Substrate project such as this consists of a number of components that are spread across a few +directories. + +### Node + +A blockchain node is an application that allows users to participate in a blockchain network. +Substrate-based blockchain nodes expose a number of capabilities: + +- Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking stack to allow the + nodes in the network to communicate with one another. +- Consensus: Blockchains must have a way to come to + [consensus](https://substrate.dev/docs/en/knowledgebase/advanced/consensus) on the state of the + network. Substrate makes it possible to supply custom consensus engines and also ships with + several consensus mechanisms that have been built on top of + [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). +- RPC Server: A remote procedure call (RPC) server is used to interact with Substrate nodes. + +There are several files in the `node` directory - take special note of the following: + +- [`chain_spec.rs`](./node/src/chain_spec.rs): A + [chain specification](https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec) is a + source code file that defines a Substrate chain's initial (genesis) state. Chain specifications + are useful for development and testing, and critical when architecting the launch of a + production chain. Take note of the `development_config` and `testnet_genesis` functions, which + are used to define the genesis state for the local development chain configuration. These + functions identify some + [well-known accounts](https://substrate.dev/docs/en/knowledgebase/integrate/subkey#well-known-keys) + and use them to configure the blockchain's initial state. +- [`service.rs`](./node/src/service.rs): This file defines the node implementation. Take note of + the libraries that this file imports and the names of the functions it invokes. In particular, + there are references to consensus-related topics, such as the + [longest chain rule](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#longest-chain-rule), + the [Aura](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#aura) block authoring + mechanism and the + [GRANDPA](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#grandpa) finality + gadget. + +After the node has been [built](#build), refer to the embedded documentation to learn more about the +capabilities and configuration parameters that it exposes: + +```shell +./target/release/node-template --help +``` + +### Runtime + +In Substrate, the terms +"[runtime](https://substrate.dev/docs/en/knowledgebase/getting-started/glossary#runtime)" and +"[state transition function](https://substrate.dev/docs/en/knowledgebase/getting-started/glossary#stf-state-transition-function)" +are analogous - they refer to the core logic of the blockchain that is responsible for validating +blocks and executing the state changes they define. The Substrate project in this repository uses +the [FRAME](https://substrate.dev/docs/en/knowledgebase/runtime/frame) framework to construct a +blockchain runtime. FRAME allows runtime developers to declare domain-specific logic in modules +called "pallets". At the heart of FRAME is a helpful +[macro language](https://substrate.dev/docs/en/knowledgebase/runtime/macros) that makes it easy to +create pallets and flexibly compose them to create blockchains that can address +[a variety of needs](https://www.substrate.io/substrate-users/). + +Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this template and note +the following: + +- This file configures several pallets to include in the runtime. Each pallet configuration is + defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`. +- The pallets are composed into a single runtime by way of the + [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) + macro, which is part of the core + [FRAME Support](https://substrate.dev/docs/en/knowledgebase/runtime/frame#support-library) + library. + +### Pallets + +The runtime in this project is constructed Using many FRAME pallets that ship with the +[core Substrate repository](https://github.com/paritytech/substrate/tree/master/frame) and a +template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory. + +A FRAME pallet is compromised of a number of blockchain primitives: + +- Storage: FRAME defines a rich set of powerful + [storage abstractions](https://substrate.dev/docs/en/knowledgebase/runtime/storage) that makes + it easy to use Substrate's efficient key-value database to manage the evolving state of a + blockchain. +- Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) + from outside of the runtime in order to update its state. +- Events: Substrate uses [events](https://substrate.dev/docs/en/knowledgebase/runtime/events) to + notify users of important changes in the runtime. +- Errors: When a dispatchable fails, it returns an error. +- Config: The `Config` configuration interface is used to define the types and parameters upon + which a FRAME pallet depends. + +### Run in Docker + +First, install [Docker](https://docs.docker.com/get-docker/) and +[Docker Compose](https://docs.docker.com/compose/install/). + +Then run the following command to start a single node development chain. + +```bash +./scripts/docker_run.sh +``` + +This command will firstly compile your code, and then start a local development network. You can +also replace the default command (`cargo build --release && ./target/release/node-template --dev --ws-external`) +by appending your own. A few useful ones are as follow. + +```bash +# Run Substrate node without re-compiling +./scripts/docker_run.sh ./target/release/node-template --dev --ws-external + +# Purge the local dev chain +./scripts/docker_run.sh ./target/release/node-template purge-chain --dev + +# Check whether the code is compilable +./scripts/docker_run.sh cargo check +``` + +### CodeStructure +├── docs docs +├── node substrate node module package +│   └── src substrate nodesource package +├── pallets substrate pallets package +│   ├── provider computing provides contract packages +│   │   └── src Computing provides contract implementation source code +│   ├── resource-order resource order contract package +│   │   └── src resource order contract implementation template +│   └── template substrate pallet template +│   └── src substrate pallet template hello-world case +├── primitives public object package +│   └── src public object source package +├── runtime substrate runtime package +│   └── src substrate runtime implementation package +└── scripts substrate run tool script directory diff --git a/dockerize.sh b/dockerize.sh new file mode 100644 index 0000000000..d610b22c43 --- /dev/null +++ b/dockerize.sh @@ -0,0 +1,7 @@ +#!/bin/bash +REGISTRY="registry.onecloud.newtouch.com" +PACKAGE_VERSION=1.0.0 +IMAGEID="$REGISTRY/ttc/ttchain:$PACKAGE_VERSION" +echo "Building $REGISTRY/ttc/ttchain:$PACKAGE_VERSION ..." +docker run -it --rm -v $PWD:/app -w /app -v $PWD/.cargo/config:/root/.cargo/config paritytech/ci-linux:363245ca-20210706 cargo build --release +docker build -t $IMAGEID . diff --git a/docs/rust-setup.md b/docs/rust-setup.md new file mode 100644 index 0000000000..34f6e43e7f --- /dev/null +++ b/docs/rust-setup.md @@ -0,0 +1,81 @@ +--- +title: Installation +--- + +This page will guide you through the steps needed to prepare a computer for development with the +Substrate Node Template. Since Substrate is built with +[the Rust programming language](https://www.rust-lang.org/), the first thing you will need to do is +prepare the computer for Rust development - these steps will vary based on the computer's operating +system. Once Rust is configured, you will use its toolchains to interact with Rust projects; the +commands for Rust's toolchains will be the same for all supported, Unix-based operating systems. + +## Unix-Based Operating Systems + +Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples +in the Substrate [Tutorials](https://substrate.dev/tutorials) and [Recipes](https://substrate.dev/recipes/) +use Unix-style terminals to demonstrate how to interact with Substrate from the command line. + +### macOS + +Open the Terminal application and execute the following commands: + +```bash +# Install Homebrew if necessary https://brew.sh/ +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + +# Make sure Homebrew is up-to-date, install openssl and cmake +brew update +brew install openssl cmake +``` + +### Ubuntu/Debian + +Use a terminal shell to execute the following commands: + +```bash +sudo apt update +# May prompt for location information +sudo apt install -y cmake pkg-config libssl-dev git build-essential clang libclang-dev curl +``` + +### Arch Linux + +Run these commands from a terminal: + +```bash +pacman -Syu --needed --noconfirm cmake gcc openssl-1.0 pkgconf git clang +export OPENSSL_LIB_DIR="/usr/lib/openssl-1.0" +export OPENSSL_INCLUDE_DIR="/usr/include/openssl-1.0" +``` + +### Fedora/RHEL/CentOS + +Use a terminal to run the following commands: + +```bash +# Update +sudo dnf update +# Install packages +sudo dnf install cmake pkgconfig rocksdb rocksdb-devel llvm git libcurl libcurl-devel curl-devel clang +``` + +## Rust Developer Environment + +This project uses [`rustup`](https://rustup.rs/) to help manage the Rust toolchain. First install +and configure `rustup`: + +```bash +# Install +curl https://sh.rustup.rs -sSf | sh +# Configure +source ~/.cargo/env +``` + +Finally, configure the Rust toolchain: + +```bash +rustup default stable +rustup update nightly +rustup update stable +rustup target add wasm32-unknown-unknown --toolchain nightly +``` diff --git a/node/Cargo.toml b/node/Cargo.toml new file mode 100644 index 0000000000..2b14a3d443 --- /dev/null +++ b/node/Cargo.toml @@ -0,0 +1,273 @@ +[features] +default = [] +runtime-benchmarks = ['node-template-runtime/runtime-benchmarks'] + +[build-dependencies.substrate-build-script-utils] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[package] +authors = ['Substrate DevHub '] +build = 'build.rs' +description = 'A fresh FRAME-based Substrate node, ready for hacking.' +edition = '2018' +homepage = 'https://substrate.dev' +license = 'Unlicense' +name = 'node-template' +repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' +version = '3.0.0' +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + +[dependencies] +jsonrpc-core = '15.1.0' +structopt = '0.3.8' +futures = "0.3.9" +hex-literal = "0.3.1" + +[dependencies.frame-benchmarking] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.1.0' + +[dependencies.frame-benchmarking-cli] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.node-template-runtime] +path = '../runtime' +version = '3.0.0' + + + +[dependencies.pallet-transaction-payment-rpc] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sc-basic-authorship] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-cli] +features = ['wasmtime'] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-client-api] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sc-consensus] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-consensus-aura] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-consensus-babe] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-executor] +features = ['wasmtime'] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-finality-grandpa] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-keystore] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sc-rpc] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sc-rpc-api] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-service] +features = ['wasmtime'] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-telemetry] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sc-transaction-pool] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-api] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-block-builder] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-blockchain] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-consensus] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sp-keystore] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sp-consensus-aura] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sp-consensus-babe] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sp-core] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-authorship] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + + + + +[dependencies.sp-finality-grandpa] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-inherents] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-runtime] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-timestamp] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-transaction-pool] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.substrate-frame-rpc-system] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-contracts-rpc] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-mmr-rpc] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sc-consensus-babe-rpc] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-finality-grandpa-rpc] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-sync-state-rpc] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-consensus-epochs] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-network] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-consensus-slots] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-consensus-uncles] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sc-chain-spec] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sc-authority-discovery] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sp-authority-discovery] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sc-finality-grandpa-warp-sync] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.pallet-staking] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + + +[[bin]] +name = 'node-template' diff --git a/node/build.rs b/node/build.rs new file mode 100644 index 0000000000..e3bfe3116b --- /dev/null +++ b/node/build.rs @@ -0,0 +1,7 @@ +use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; + +fn main() { + generate_cargo_keys(); + + rerun_if_git_head_changed(); +} diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs new file mode 100644 index 0000000000..06b2cb32be --- /dev/null +++ b/node/src/chain_spec.rs @@ -0,0 +1,344 @@ +use sp_core::{Pair, Public, sr25519, crypto::UncheckedInto}; + +use node_template_runtime::{ + AccountId, AuthorityDiscoveryConfig ,BabeConfig, BalancesConfig, GenesisConfig, GrandpaConfig, + SudoConfig, SystemConfig, SessionConfig, StakingConfig, opaque::SessionKeys, + StakerStatus, Balance, WASM_BINARY, Signature,currency::DOLLARS +}; +use sp_consensus_babe::AuthorityId as BabeId; +use sp_finality_grandpa::AuthorityId as GrandpaId; +use sp_runtime::{Perbill, traits::{Verify, IdentifyAccount}}; +use hex_literal::hex; + + +use sc_service::ChainType; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; + +// The URL for the telemetry server. +// const STAGING_TELEMETRzY_URL: &str = "wss://telemetry.polkadot.io/submit/"; + +/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. +pub type ChainSpec = sc_service::GenericChainSpec; + +/// Generate a crypto pair from seed. +pub fn get_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public() +} + +type AccountPublic = ::Signer; + +/// Generate an account ID from seed. +pub fn get_account_id_from_seed(seed: &str) -> AccountId where + AccountPublic: From<::Public> +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} + +/// Generate an Aura authority key. +pub fn authority_keys_from_seed(s: &str) -> (AccountId, AccountId, BabeId, GrandpaId,AuthorityDiscoveryId) { + ( + get_account_id_from_seed::(&format!("{}//stash", s)), + get_account_id_from_seed::(s), + get_from_seed::(s), + get_from_seed::(s), + get_from_seed::(s), + ) +} + +pub fn development_config() -> Result { + let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; + + Ok(ChainSpec::from_genesis( + // Name + "Development", + // ID + "dev", + ChainType::Development, + move || testnet_genesis( + wasm_binary, + vec![ + authority_keys_from_seed("Alice") + ], + get_account_id_from_seed::("Alice"), + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + true, + ), + // Bootnodes + vec![], + // Telemetry + None, + // Protocol ID + None, + // Properties + None, + // Extensions + None, + )) +} + + +pub fn local_testnet_config() -> Result { + let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; + + Ok(ChainSpec::from_genesis( + // Name + "Local Testnet", + // ID + "local_testnet", + ChainType::Local, + move || testnet_genesis( + wasm_binary, + // Initial PoA authorities + vec![ + authority_keys_from_seed("Alice"), + authority_keys_from_seed("Bob"), + authority_keys_from_seed("Dave"), + ], + // Sudo account + get_account_id_from_seed::("Alice"), + // Pre-funded accounts + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + true, + ), + // Bootnodes + vec![], + // Telemetry + None, + // Protocol ID + None, + // Properties + None, + // Extensions + None, + )) +} + + + +///ttc +pub fn ttc_testnet_config() -> Result { + let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; + + Ok(ChainSpec::from_genesis( + // Name + "ttchain", + // ID + "ttchain", + ChainType::Live, + move || testnet_genesis( + wasm_binary, + // Initial PoA authorities + vec![ + // node1 + ( + // 5D4T7ZMy6fBaoL4yt4oFqTbXwHyrizUhxysPsPBQWUMFWhYN + hex!["2c0a9a68ee2376df7360cd41a5dce338a0a7115d459ac09e97f36e572a191654"].into(), + // 5CeuRCA42VFtNMF3nYZJkeLye2pWiYxmnzYMh2EASyMDKauE + hex!["1a1542c0d312242c2f9045bfd98bb73076950b4665baa8d460e4b9b9d9dc043a"].into(), + // 5CeuRCA42VFtNMF3nYZJkeLye2pWiYxmnzYMh2EASyMDKauE + hex!["1a1542c0d312242c2f9045bfd98bb73076950b4665baa8d460e4b9b9d9dc043a"].unchecked_into(), + // 5ETMKYmxmb3YpJwzR5yjHJHY5CnTJJR2Na2oJd2ZhHqBrWBL + hex!["69bdfaa01ce33ac3a659bedb201d6552c15bfa48682078bc7f0f0e10a5163aa4"].unchecked_into(), + // 5CeuRCA42VFtNMF3nYZJkeLye2pWiYxmnzYMh2EASyMDKauE + hex!["1a1542c0d312242c2f9045bfd98bb73076950b4665baa8d460e4b9b9d9dc043a"].unchecked_into(), + ), + // node2 + ( + // 5HVYYi4UynHdMD4Y4W6JANro5hg5kMuUrioeMvLv1kXL6vJQ + hex!["f01ef69992c22cc26b98efeae07d3176936da1737b8fe624441f898bd0c74355"].into(), + // 5GWyTHcZNrYPQ2zv1yzrUGtEtzCkNcCNFpHjHjVN9W76DU3C + hex!["c4f9d16d2cf83956648843419db272ee3507a860fef203d5016ef0d0ce0d9a29"].into(), + // 5GWyTHcZNrYPQ2zv1yzrUGtEtzCkNcCNFpHjHjVN9W76DU3C + hex!["c4f9d16d2cf83956648843419db272ee3507a860fef203d5016ef0d0ce0d9a29"].unchecked_into(), + // 5CJo2EmCwRq3SETR9mbxuWek95w5jxCav2esrrM5xN3zUYeS + hex!["0abed2937ad6101f2a611b2240ad45cf3909be66d8044df926213970170efbdc"].unchecked_into(), + // 5GWyTHcZNrYPQ2zv1yzrUGtEtzCkNcCNFpHjHjVN9W76DU3C + hex!["c4f9d16d2cf83956648843419db272ee3507a860fef203d5016ef0d0ce0d9a29"].unchecked_into(), + ), + // node3 + ( + // 5Fe16PvhNmRcyLgw7z25JapzYRhveA3CGAcaWMbheqFwwCiK + hex!["9e19d291982a538eb67521f809dffeb7695d1791f49fac4e95f1d1bafe67014f"].into(), + // 5HHPKrFJhZF7fHvtagfZT25q7wsha3gUXx5CBvzWtoTpP6KF + hex!["e6d8f9b41bc64362176fae74b510ff16de998a252a311f12f7d4f63c2c1b3f05"].into(), + // 5HHPKrFJhZF7fHvtagfZT25q7wsha3gUXx5CBvzWtoTpP6KF + hex!["e6d8f9b41bc64362176fae74b510ff16de998a252a311f12f7d4f63c2c1b3f05"].unchecked_into(), + // 5FqMa9rE2oshxVuxfarWo3Mti4s97k6gGZcudejDv3JH9nbk + hex!["a6c275817f9960e3d7f67ccdf7468713e1b6b8e2d6c55b3ddc4ee84316718049"].unchecked_into(), + // 5HHPKrFJhZF7fHvtagfZT25q7wsha3gUXx5CBvzWtoTpP6KF + hex!["e6d8f9b41bc64362176fae74b510ff16de998a252a311f12f7d4f63c2c1b3f05"].unchecked_into(), + ), + // node4 + ( + // 5GRUt6kTUoyuhApormJeGKM3VN6Q3z3ep3ugPpwG1xVivm6w + hex!["c0c968916113fddd793b4e0ac628ae30cc5eaeceedf1e701088eae5e28ec2f24"].into(), + // 5EfFzDjNEY1UKq9Qoke3e7QfWx89EQk2k2EwK3HwgVKgJJbg + hex!["72d2f875b9bd92d77eae95f62242a97445290be989c5baf4e163a73f13be520a"].into(), + // 5EfFzDjNEY1UKq9Qoke3e7QfWx89EQk2k2EwK3HwgVKgJJbg + hex!["72d2f875b9bd92d77eae95f62242a97445290be989c5baf4e163a73f13be520a"].unchecked_into(), + // 5GVQoMXm9Dcm4GaunqgcgkW35fyUfn4BnqcVgb6mvRGi6NXC + hex!["c3c8a644374a2715a43fafd38e5111637add46ef9e62304a819c3100819bed12"].unchecked_into(), + // 5EfFzDjNEY1UKq9Qoke3e7QfWx89EQk2k2EwK3HwgVKgJJbg + hex!["72d2f875b9bd92d77eae95f62242a97445290be989c5baf4e163a73f13be520a"].unchecked_into(), + ), + // node5 + ( + // 5GHHX7bKePF2LYYDvavPZjZbamjDxEUdYxXv7HvksXe18wCS + hex!["ba8932ac626da0836b968bf37581d779ca645595e67e63190a08892ad182bb69"].into(), + // 5HgcLrfVHas21iktJHftztkasBh8fskMS4t7Hmyq3TCEJsDs + hex!["f88f70a7f267f79b3bfd66a5f791aea08805da61bb07ac4b56ab6acff074354e"].into(), + // 5HgcLrfVHas21iktJHftztkasBh8fskMS4t7Hmyq3TCEJsDs + hex!["f88f70a7f267f79b3bfd66a5f791aea08805da61bb07ac4b56ab6acff074354e"].unchecked_into(), + // 5DwyufeSCAaoH5V9p8LqmnExFVMpGCxU38YS4nYGAHEM1nVP + hex!["5357c8adb7bdafb2620122d38247b65667a086eacb251c7a73357d8ee40fbf62"].unchecked_into(), + // 5HgcLrfVHas21iktJHftztkasBh8fskMS4t7Hmyq3TCEJsDs + hex!["f88f70a7f267f79b3bfd66a5f791aea08805da61bb07ac4b56ab6acff074354e"].unchecked_into(), + ) + ], + // Sudo account + hex!["1a1542c0d312242c2f9045bfd98bb73076950b4665baa8d460e4b9b9d9dc043a"].into(), + // Pre-funded accounts + vec![ + // 5CeuRCA42VFtNMF3nYZJkeLye2pWiYxmnzYMh2EASyMDKauE + hex!["1a1542c0d312242c2f9045bfd98bb73076950b4665baa8d460e4b9b9d9dc043a"].into(), + // 5GWyTHcZNrYPQ2zv1yzrUGtEtzCkNcCNFpHjHjVN9W76DU3C + hex!["c4f9d16d2cf83956648843419db272ee3507a860fef203d5016ef0d0ce0d9a29"].into(), + // 5D4T7ZMy6fBaoL4yt4oFqTbXwHyrizUhxysPsPBQWUMFWhYN + hex!["2c0a9a68ee2376df7360cd41a5dce338a0a7115d459ac09e97f36e572a191654"].into(), + // 5HVYYi4UynHdMD4Y4W6JANro5hg5kMuUrioeMvLv1kXL6vJQ + hex!["f01ef69992c22cc26b98efeae07d3176936da1737b8fe624441f898bd0c74355"].into(), + // 5Fe16PvhNmRcyLgw7z25JapzYRhveA3CGAcaWMbheqFwwCiK + hex!["9e19d291982a538eb67521f809dffeb7695d1791f49fac4e95f1d1bafe67014f"].into(), + // 5HHPKrFJhZF7fHvtagfZT25q7wsha3gUXx5CBvzWtoTpP6KF + hex!["e6d8f9b41bc64362176fae74b510ff16de998a252a311f12f7d4f63c2c1b3f05"].into(), + // 5GRUt6kTUoyuhApormJeGKM3VN6Q3z3ep3ugPpwG1xVivm6w + hex!["c0c968916113fddd793b4e0ac628ae30cc5eaeceedf1e701088eae5e28ec2f24"].into(), + // 5EfFzDjNEY1UKq9Qoke3e7QfWx89EQk2k2EwK3HwgVKgJJbg + hex!["72d2f875b9bd92d77eae95f62242a97445290be989c5baf4e163a73f13be520a"].into(), + // 5GHHX7bKePF2LYYDvavPZjZbamjDxEUdYxXv7HvksXe18wCS + hex!["ba8932ac626da0836b968bf37581d779ca645595e67e63190a08892ad182bb69"].into(), + // 5HgcLrfVHas21iktJHftztkasBh8fskMS4t7Hmyq3TCEJsDs + hex!["f88f70a7f267f79b3bfd66a5f791aea08805da61bb07ac4b56ab6acff074354e"].into(), + // ttc initial account + // 5CDkYj2QVm2VkMiAwC3P5dMoCuNyHm1gx2wvrmGdbxQdTCbu + hex!["06e6441fe8e2809044fe6850739b4a5584f78f1425ab7403f8737337f8d6ab7e"].into(), + ], + true, + ), + // Bootnodes + vec![], + // Telemetry + None, + // Protocol ID + None, + // Properties + None, + // Extensions + None, + )) +} + + + +fn session_keys( + babe: BabeId, + grandpa: GrandpaId, + authority_discovery: AuthorityDiscoveryId, +) -> SessionKeys { + SessionKeys { grandpa, babe , authority_discovery} +} + + +/// Configure initial storage state for FRAME modules. +fn testnet_genesis( + wasm_binary: &[u8], + initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId,AuthorityDiscoveryId)>, + root_key: AccountId, + endowed_accounts: Vec, + _enable_println: bool, +) -> GenesisConfig { + const STASH: Balance = 100 * DOLLARS; + GenesisConfig { + system: SystemConfig { + // Add Wasm runtime to storage. + code: wasm_binary.to_vec(), + changes_trie_config: Default::default(), + }, + balances: BalancesConfig { + // Configure endowed accounts with initial balance of 1 << 60. + balances: + endowed_accounts.iter().cloned().map(|k| + if k != hex!["06e6441fe8e2809044fe6850739b4a5584f78f1425ab7403f8737337f8d6ab7e"].into() { + (k,2000_000_000_000_000) + }else { + (k,20_000_000_000_000_000_000) + }).collect(), + }, + babe: BabeConfig { + authorities: vec![], + epoch_config: Some(node_template_runtime::BABE_GENESIS_EPOCH_CONFIG), + }, + grandpa: GrandpaConfig { + authorities: vec![], + }, + + sudo: SudoConfig { + // Assign network admin rights. + key: root_key, + }, + session: SessionConfig { + keys: initial_authorities.iter().map(|x| { + (x.0.clone(), x.0.clone(), session_keys( + x.2.clone(), + x.3.clone(), + x.4.clone(), + )) + }).collect::>(), + }, + staking: StakingConfig { + validator_count: initial_authorities.len() as u32 * 2, + minimum_validator_count: initial_authorities.len() as u32, + stakers: initial_authorities.iter().map(|x| { + (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator) + }).collect(), + invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), + slash_reward_fraction: Perbill::from_percent(10), + .. Default::default() + }, + authority_discovery: AuthorityDiscoveryConfig { keys: vec![] }, + + } +} + + + + + diff --git a/node/src/cli.rs b/node/src/cli.rs new file mode 100644 index 0000000000..947123a6bb --- /dev/null +++ b/node/src/cli.rs @@ -0,0 +1,41 @@ +use structopt::StructOpt; +use sc_cli::RunCmd; + +#[derive(Debug, StructOpt)] +pub struct Cli { + #[structopt(subcommand)] + pub subcommand: Option, + + #[structopt(flatten)] + pub run: RunCmd, +} + +#[derive(Debug, StructOpt)] +pub enum Subcommand { + /// Key management cli utilities + Key(sc_cli::KeySubcommand), + /// Build a chain specification. + BuildSpec(sc_cli::BuildSpecCmd), + + /// Validate blocks. + CheckBlock(sc_cli::CheckBlockCmd), + + /// Export blocks. + ExportBlocks(sc_cli::ExportBlocksCmd), + + /// Export the state of a given block into a chain spec. + ExportState(sc_cli::ExportStateCmd), + + /// Import blocks. + ImportBlocks(sc_cli::ImportBlocksCmd), + + /// Remove the whole chain. + PurgeChain(sc_cli::PurgeChainCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), + + /// The custom benchmark subcommmand benchmarking runtime pallets. + #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), +} diff --git a/node/src/command.rs b/node/src/command.rs new file mode 100644 index 0000000000..e26600837e --- /dev/null +++ b/node/src/command.rs @@ -0,0 +1,139 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{chain_spec, service}; +use crate::cli::{Cli, Subcommand}; +use sc_cli::{SubstrateCli, RuntimeVersion, Role, ChainSpec}; +use sc_service::PartialComponents; +use node_template_runtime::Block; + +impl SubstrateCli for Cli { + fn impl_name() -> String { + "Substrate Node".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + env!("CARGO_PKG_DESCRIPTION").into() + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "support.anonymous.an".into() + } + + fn copyright_start_year() -> i32 { + 2017 + } + + fn load_spec(&self, id: &str) -> Result, String> { + Ok(match id { + "dev" => Box::new(chain_spec::development_config()?), + "" | "local" => Box::new(chain_spec::local_testnet_config()?), + "ttc" => Box::new(chain_spec::ttc_testnet_config()?), + path => Box::new(chain_spec::ChainSpec::from_json_file( + std::path::PathBuf::from(path), + )?), + }) + } + + fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { + &node_template_runtime::VERSION + } +} + +/// Parse and run command line arguments +pub fn run() -> sc_cli::Result<()> { + let cli = Cli::from_args(); + + match &cli.subcommand { + Some(Subcommand::Key(cmd)) => cmd.run(&cli), + Some(Subcommand::BuildSpec(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) + }, + Some(Subcommand::CheckBlock(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, import_queue, ..} + = service::new_partial(&config)?; + Ok((cmd.run(client, import_queue), task_manager)) + }) + }, + Some(Subcommand::ExportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, ..} + = service::new_partial(&config)?; + Ok((cmd.run(client, config.database), task_manager)) + }) + }, + Some(Subcommand::ExportState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, ..} + = service::new_partial(&config)?; + Ok((cmd.run(client, config.chain_spec), task_manager)) + }) + }, + Some(Subcommand::ImportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, import_queue, ..} + = service::new_partial(&config)?; + Ok((cmd.run(client, import_queue), task_manager)) + }) + }, + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.database)) + }, + Some(Subcommand::Revert(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, backend, ..} + = service::new_partial(&config)?; + Ok((cmd.run(client, backend), task_manager)) + }) + }, + Some(Subcommand::Benchmark(cmd)) => { + if cfg!(feature = "runtime-benchmarks") { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| cmd.run::(config)) + } else { + Err("Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`.".into()) + } + }, + None => { + let runner = cli.create_runner(&cli.run)?; + runner.run_node_until_exit(|config| async move { + match config.role { + Role::Light => service::new_light(config), + _ => service::new_full(config), + }.map_err(sc_cli::Error::Service) + }) + } + } +} diff --git a/node/src/lib.rs b/node/src/lib.rs new file mode 100644 index 0000000000..777c4f0a77 --- /dev/null +++ b/node/src/lib.rs @@ -0,0 +1,3 @@ +pub mod chain_spec; +pub mod service; +pub mod rpc; diff --git a/node/src/main.rs b/node/src/main.rs new file mode 100644 index 0000000000..4449d28b9f --- /dev/null +++ b/node/src/main.rs @@ -0,0 +1,13 @@ +//! Substrate Node Template CLI library. +#![warn(missing_docs)] + +mod chain_spec; +#[macro_use] +mod service; +mod cli; +mod command; +mod rpc; + +fn main() -> sc_cli::Result<()> { + command::run() +} diff --git a/node/src/rpc.rs b/node/src/rpc.rs new file mode 100644 index 0000000000..75ed7047ea --- /dev/null +++ b/node/src/rpc.rs @@ -0,0 +1,215 @@ +//! A collection of node-specific RPC methods. +//! Substrate provides the `sc-rpc` crate, which defines the core RPC layer +//! used by Substrate nodes. This file extends those RPC definitions with +//! capabilities that are specific to this project's runtime configuration. + +#![warn(missing_docs)] + +use std::sync::Arc; + +use sp_keystore::SyncCryptoStorePtr; +use sc_consensus_babe::{Config, Epoch}; +use sc_consensus_babe_rpc::BabeRpcHandler; +use sc_consensus_epochs::SharedEpochChanges; +use sc_finality_grandpa::{ + SharedVoterState, SharedAuthoritySet, FinalityProofProvider, GrandpaJustificationStream +}; +use sc_finality_grandpa_rpc::GrandpaRpcHandler; +pub use sc_rpc_api::DenyUnsafe; +use sp_api::ProvideRuntimeApi; +use sp_block_builder::BlockBuilder; +use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend}; +use sp_consensus::SelectChain; +use sp_consensus_babe::BabeApi; +use sc_rpc::SubscriptionTaskExecutor; +use sp_transaction_pool::TransactionPool; +use node_template_runtime::{opaque::Block, AccountId, Balance, Index, BlockNumber,Hash}; + + +/// Light client extra dependencies. +pub struct LightDeps { + /// The client instance to use. + pub client: Arc, + /// Transaction pool instance. + pub pool: Arc

, + /// Remote access to the blockchain (async). + pub remote_blockchain: Arc>, + /// Fetcher instance. + pub fetcher: Arc, +} + +/// Extra dependencies for BABE. +pub struct BabeDeps { + /// BABE protocol config. + pub babe_config: Config, + /// BABE pending epoch changes. + pub shared_epoch_changes: SharedEpochChanges, + /// The keystore that manages the keys of the substrate. + pub keystore: SyncCryptoStorePtr, +} + +/// Extra dependencies for GRANDPA +pub struct GrandpaDeps { + /// Voting round info. + pub shared_voter_state: SharedVoterState, + /// Authority set info. + pub shared_authority_set: SharedAuthoritySet, + /// Receives notifications about justification events from Grandpa. + pub justification_stream: GrandpaJustificationStream, + /// Executor to drive the subscription manager in the Grandpa RPC handler. + pub subscription_executor: SubscriptionTaskExecutor, + /// Finality proof provider. + pub finality_provider: Arc>, +} + +/// Full client dependencies. +pub struct FullDeps { + /// The client instance to use. + pub client: Arc, + /// Transaction pool instance. + pub pool: Arc

, + /// The SelectChain Strategy + pub select_chain: SC, + /// A copy of the chain spec. + pub chain_spec: Box, + /// Whether to deny unsafe calls + pub deny_unsafe: DenyUnsafe, + /// BABE specific dependencies. + pub babe: BabeDeps, + /// GRANDPA specific dependencies. + pub grandpa: GrandpaDeps, +} + +/// A IO handler that uses all Full RPC extensions. +pub type IoHandler = jsonrpc_core::IoHandler; + + +/// Instantiate all full RPC extensions. +pub fn create_full( + deps: FullDeps, +) -> jsonrpc_core::IoHandler where + C: ProvideRuntimeApi, + C: HeaderBackend + HeaderMetadata + 'static, + C: Send + Sync + 'static, + C::Api: substrate_frame_rpc_system::AccountNonceApi, + C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, + C::Api: BlockBuilder, + C::Api: BabeApi, + P: TransactionPool + 'static, + SC: SelectChain +'static, + B: sc_client_api::Backend + Send + Sync + 'static, + B::State: sc_client_api::backend::StateBackend>, +{ + use substrate_frame_rpc_system::{FullSystem, SystemApi}; + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; + + let mut io = jsonrpc_core::IoHandler::default(); + let FullDeps { + client, + pool, + select_chain, + chain_spec:_, + deny_unsafe, + babe, + grandpa, + } = deps; + let BabeDeps { + keystore, + babe_config, + shared_epoch_changes, + } = babe; + let GrandpaDeps { + shared_voter_state, + shared_authority_set, + justification_stream, + subscription_executor, + finality_provider, + } = grandpa; + + io.extend_with( + SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)) + ); + + // io.extend_with( + // ContractsApi::to_delegate(Contracts::new(client.clone())) + // ); + + // io.extend_with( + // MmrApi::to_delegate(Mmr::new(client.clone())) + // ); + + io.extend_with( + TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())) + ); + + io.extend_with( + sc_consensus_babe_rpc::BabeApi::to_delegate( + BabeRpcHandler::new( + client.clone(), + shared_epoch_changes.clone(), + keystore, + babe_config, + select_chain, + deny_unsafe, + ), + ) + ); + io.extend_with( + sc_finality_grandpa_rpc::GrandpaApi::to_delegate( + GrandpaRpcHandler::new( + shared_authority_set.clone(), + shared_voter_state, + justification_stream, + subscription_executor, + finality_provider, + ) + ) + ); + + // io.extend_with( + // sc_sync_state_rpc::SyncStateRpcApi::to_delegate( + // sc_sync_state_rpc::SyncStateRpcHandler::new( + // chain_spec, + // client, + // shared_authority_set, + // shared_epoch_changes, + // deny_unsafe, + // ) + // ) + // ); + + + // Extend this RPC with a custom API by Using the following syntax. + // `YourRpcStruct` should have a reference to a client, which is needed + // to call into the runtime. + // `io.extend_with(YourRpcTrait::to_delegate(YourRpcStruct::new(ReferenceToClient, ...)));` + + io +} + + +/// Instantiate all Light RPC extensions. +pub fn create_light( + deps: LightDeps, +) -> jsonrpc_core::IoHandler where + C: sp_blockchain::HeaderBackend, + C: Send + Sync + 'static, + F: sc_client_api::light::Fetcher + 'static, + P: TransactionPool + 'static, + M: jsonrpc_core::Metadata + Default, +{ + use substrate_frame_rpc_system::{LightSystem, SystemApi}; + + let LightDeps { + client, + pool, + remote_blockchain, + fetcher + } = deps; + let mut io = jsonrpc_core::IoHandler::default(); + io.extend_with( + SystemApi::::to_delegate(LightSystem::new(client, remote_blockchain, fetcher, pool)) + ); + + io +} diff --git a/node/src/service.rs b/node/src/service.rs new file mode 100644 index 0000000000..89d5d04ed2 --- /dev/null +++ b/node/src/service.rs @@ -0,0 +1,602 @@ +//! Service and ServiceFactory implementation. Specialized wrapper over substrate service. + +use std::sync::Arc; +use sc_client_api::{ExecutorProvider, RemoteBackend}; +use node_template_runtime::{self, opaque::Block, RuntimeApi}; +use sc_service::{ + config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager, +}; +use sc_executor::native_executor_instance; +pub use sc_executor::NativeExecutor; + + +use sc_telemetry::{Telemetry, TelemetryWorker}; +pub use sc_rpc_api::DenyUnsafe; +use sp_authorship; +use sp_runtime::traits::Block as BlockT; +use sc_network::{Event, NetworkService}; +use futures::prelude::*; +use sc_consensus_babe::SlotProportion; + +// Our native executor instance. +native_executor_instance!( + pub Executor, + node_template_runtime::api::dispatch, + node_template_runtime::native_version, + frame_benchmarking::benchmarking::HostFunctions, +); + +type FullClient = sc_service::TFullClient; +type FullBackend = sc_service::TFullBackend; +type FullSelectChain = sc_consensus::LongestChain; +type FullGrandpaBlockImport = +sc_finality_grandpa::GrandpaBlockImport; + + type LightClient = sc_service::TLightClient; + + + +pub fn new_partial(config: &Configuration) -> Result, + sc_transaction_pool::FullPool, + ( + impl Fn( + DenyUnsafe, + sc_rpc::SubscriptionTaskExecutor, + ) -> super::rpc::IoHandler, + ( + sc_consensus_babe::BabeBlockImport, + sc_finality_grandpa::LinkHalf, + sc_consensus_babe::BabeLink, + ), + sc_finality_grandpa::SharedVoterState, + Option, + ) +>, ServiceError> { + if config.keystore_remote.is_some() { + return Err(ServiceError::Other( + format!("Remote Keystores are not supported."))) + } + + let telemetry = config.telemetry_endpoints.clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + let worker = TelemetryWorker::new(16)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let (client, backend, keystore_container, task_manager) = + sc_service::new_full_parts::( + &config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + )?; + let client = Arc::new(client); + + let telemetry = telemetry + .map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", worker.run()); + telemetry + }); + + let select_chain = sc_consensus::LongestChain::new(backend.clone()); + + let transaction_pool = sc_transaction_pool::BasicPool::new_full( + config.transaction_pool.clone(), + config.role.is_authority().into(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + ); + + let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import( + client.clone(), + &(client.clone() as Arc<_>), + select_chain.clone(), + telemetry.as_ref().map(|x| x.handle()), + )?; + let justification_import = grandpa_block_import.clone(); + + let (block_import, babe_link) = sc_consensus_babe::block_import( + sc_consensus_babe::Config::get_or_compute(&*client)?, + grandpa_block_import, + client.clone(), + )?; + + let slot_duration = babe_link.config().slot_duration(); + let import_queue = sc_consensus_babe::import_queue( + babe_link.clone(), + block_import.clone(), + Some(Box::new(justification_import)), + client.clone(), + select_chain.clone(), + move |_, ()| { + async move { + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration( + *timestamp, + slot_duration, + ); + + let uncles = + sp_authorship::InherentDataProvider::<::Header>::check_inherents(); + + Ok((timestamp, slot, uncles)) + } + }, + &task_manager.spawn_essential_handle(), + config.prometheus_registry(), + sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()), + telemetry.as_ref().map(|x| x.handle()), + )?; + + let import_setup = (block_import, grandpa_link, babe_link); + + let (rpc_extensions_builder, rpc_setup) = { + let (_, grandpa_link, babe_link) = &import_setup; + + let justification_stream = grandpa_link.justification_stream(); + let shared_authority_set = grandpa_link.shared_authority_set().clone(); + let shared_voter_state = sc_finality_grandpa::SharedVoterState::empty(); + let rpc_setup = shared_voter_state.clone(); + + let finality_proof_provider = sc_finality_grandpa::FinalityProofProvider::new_for_service( + backend.clone(), + Some(shared_authority_set.clone()), + ); + + let babe_config = babe_link.config().clone(); + let shared_epoch_changes = babe_link.epoch_changes().clone(); + + let client = client.clone(); + let pool = transaction_pool.clone(); + let select_chain = select_chain.clone(); + let keystore = keystore_container.sync_keystore(); + let chain_spec = config.chain_spec.cloned_box(); + + let rpc_extensions_builder = move |deny_unsafe, subscription_executor| { + let deps = self::super::rpc::FullDeps { + + client: client.clone(), + pool: pool.clone(), + select_chain: select_chain.clone(), + chain_spec: chain_spec.cloned_box(), + deny_unsafe, + babe: self::super::rpc::BabeDeps { + babe_config: babe_config.clone(), + shared_epoch_changes: shared_epoch_changes.clone(), + keystore: keystore.clone(), + }, + grandpa: self::super::rpc::GrandpaDeps { + shared_voter_state: shared_voter_state.clone(), + shared_authority_set: shared_authority_set.clone(), + justification_stream: justification_stream.clone(), + subscription_executor, + finality_provider: finality_proof_provider.clone(), + }, + }; + + self::super::rpc::create_full(deps) + }; + + (rpc_extensions_builder, rpc_setup) + }; + + Ok(sc_service::PartialComponents { + client, + backend, + task_manager, + import_queue, + keystore_container, + select_chain, + transaction_pool, + other: (rpc_extensions_builder, import_setup, rpc_setup, telemetry), + }) +} + + +pub struct NewFullBase { + pub task_manager: TaskManager, + pub client: Arc, + pub network: Arc::Hash>>, + pub transaction_pool: Arc>, +} + + +/// Creates a full service from the configuration. +pub fn new_full_base( + mut config: Configuration, + with_startup_data: impl FnOnce( + &sc_consensus_babe::BabeBlockImport, + &sc_consensus_babe::BabeLink, + ) +) -> Result { + let sc_service::PartialComponents { + client, + backend, + mut task_manager, + import_queue, + keystore_container, + select_chain, + transaction_pool, + other: (rpc_extensions_builder, import_setup, rpc_setup, mut telemetry), + } = new_partial(&config)?; + + let shared_voter_state = rpc_setup; + let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht; + + config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config()); + + // #[cfg(feature = "cli")] + // config.network.request_response_protocols.push( + // sc_finality_grandpa_warp_sync::request_response_config_for_chain( + // &config, + // task_manager.spawn_handle(), + // backend.clone(), + // import_setup.1.shared_authority_set().clone(), + // ) + // ); + + let (network, system_rpc_tx, network_starter) = + sc_service::build_network(sc_service::BuildNetworkParams { + config: &config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + spawn_handle: task_manager.spawn_handle(), + import_queue, + on_demand: None, + block_announce_validator_builder: None, + })?; + + if config.offchain_worker.enabled { + sc_service::build_offchain_workers( + &config, task_manager.spawn_handle(), client.clone(), network.clone(), + ); + } + + let role = config.role.clone(); + let force_authoring = config.force_authoring; + let backoff_authoring_blocks = + Some(sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default()); + let name = config.network.node_name.clone(); + let enable_grandpa = !config.disable_grandpa; + let prometheus_registry = config.prometheus_registry().cloned(); + + let _rpc_handlers = sc_service::spawn_tasks( + sc_service::SpawnTasksParams { + config, + backend: backend.clone(), + client: client.clone(), + keystore: keystore_container.sync_keystore(), + network: network.clone(), + rpc_extensions_builder: Box::new(rpc_extensions_builder), + transaction_pool: transaction_pool.clone(), + task_manager: &mut task_manager, + on_demand: None, + remote_blockchain: None, + system_rpc_tx, + telemetry: telemetry.as_mut(), + }, + )?; + + let (block_import, grandpa_link, babe_link) = import_setup; + + (with_startup_data)(&block_import, &babe_link); + + if let sc_service::config::Role::Authority { .. } = &role { + let proposer = sc_basic_authorship::ProposerFactory::new( + task_manager.spawn_handle(), + client.clone(), + transaction_pool.clone(), + prometheus_registry.as_ref(), + telemetry.as_ref().map(|x| x.handle()), + ); + + let can_author_with = + sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); + + let client_clone = client.clone(); + let slot_duration = babe_link.config().slot_duration(); + let babe_config = sc_consensus_babe::BabeParams { + keystore: keystore_container.sync_keystore(), + client: client.clone(), + select_chain, + env: proposer, + block_import, + sync_oracle: network.clone(), + justification_sync_link: network.clone(), + create_inherent_data_providers: move |parent, ()| { + let client_clone = client_clone.clone(); + async move { + let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider( + &*client_clone, + parent, + )?; + + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration( + *timestamp, + slot_duration, + ); + + Ok((timestamp, slot, uncles)) + } + }, + force_authoring, + backoff_authoring_blocks, + babe_link, + can_author_with, + block_proposal_slot_portion: SlotProportion::new(0.5), + max_block_proposal_slot_portion: None, + telemetry: telemetry.as_ref().map(|x| x.handle()), + }; + + let babe = sc_consensus_babe::start_babe(babe_config)?; + task_manager.spawn_essential_handle().spawn_blocking("babe-proposer", babe); + } + + //Spawn authority discovery module. + if role.is_authority() { + let authority_discovery_role = + sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore()); + let dht_event_stream = + network.event_stream("authority-discovery").filter_map(|e| async move { + match e { + Event::Dht(e) => Some(e), + _ => None, + } + }); + let (authority_discovery_worker, _service) = + sc_authority_discovery::new_worker_and_service_with_config( + sc_authority_discovery::WorkerConfig { + publish_non_global_ips: auth_disc_publish_non_global_ips, + ..Default::default() + }, + client.clone(), + network.clone(), + Box::pin(dht_event_stream), + authority_discovery_role, + prometheus_registry.clone(), + ); + + task_manager + .spawn_handle() + .spawn("authority-discovery-worker", authority_discovery_worker.run()); + } + + // if the newtouch isn't actively participating in consensus then it doesn't + // need a keystore, regardless of which protocol we use below. + let keystore = if role.is_authority() { + Some(keystore_container.sync_keystore()) + } else { + None + }; + + let config = sc_finality_grandpa::Config { + // FIXME #1578 make this available through chainspec + gossip_duration: std::time::Duration::from_millis(333), + justification_period: 512, + name: Some(name), + observer_enabled: false, + keystore, + local_role: role, + telemetry: telemetry.as_ref().map(|x| x.handle()), + }; + + if enable_grandpa { + // start the full GRANDPA voter + // NOTE: non-authorities could run the GRANDPA observer protocol, but at + // this point the full voter should provide better guarantees of block + // and vote data availability than the observer. The observer has not + // been tested extensively yet and having most nodes in a network run it + // could lead to finality stalls. + let grandpa_config = sc_finality_grandpa::GrandpaParams { + config, + link: grandpa_link, + network: network.clone(), + telemetry: telemetry.as_ref().map(|x| x.handle()), + voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(), + prometheus_registry, + shared_voter_state, + }; + + // the GRANDPA voter task is considered infallible, i.e. + // if it fails we take down the service with it. + task_manager.spawn_essential_handle().spawn_blocking( + "grandpa-voter", + sc_finality_grandpa::run_grandpa_voter(grandpa_config)? + ); + } + + network_starter.start_network(); + Ok(NewFullBase { + task_manager, + client, + network, + transaction_pool, + }) +} + +/// Builds a new service for a full client. +pub fn new_full( + config: Configuration, +) -> Result { + new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| { + task_manager + }) +} + + +/// Builds a new service for a light client. +pub fn new_light_base( + mut config: Configuration, +) -> Result<( + TaskManager, + RpcHandlers, + Arc, + Arc::Hash>>, + Arc>> +), ServiceError> { + let telemetry = config.telemetry_endpoints.clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + + let transport = None; + let worker = TelemetryWorker::with_transport(16, transport)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let (client, backend, keystore_container, mut task_manager, on_demand) = + sc_service::new_light_parts::( + &config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + )?; + + let mut telemetry = telemetry + .map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", worker.run()); + telemetry + }); + + config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config()); + + let select_chain = sc_consensus::LongestChain::new(backend.clone()); + + let transaction_pool = Arc::new(sc_transaction_pool::BasicPool::new_light( + config.transaction_pool.clone(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + on_demand.clone(), + )); + + let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import( + client.clone(), + &(client.clone() as Arc<_>), + select_chain.clone(), + telemetry.as_ref().map(|x| x.handle()), + )?; + let justification_import = grandpa_block_import.clone(); + + let (babe_block_import, babe_link) = sc_consensus_babe::block_import( + sc_consensus_babe::Config::get_or_compute(&*client)?, + grandpa_block_import, + client.clone(), + )?; + + let slot_duration = babe_link.config().slot_duration(); + let import_queue = sc_consensus_babe::import_queue( + babe_link, + babe_block_import, + Some(Box::new(justification_import)), + client.clone(), + select_chain.clone(), + move |_, ()| async move { + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration( + *timestamp, + slot_duration, + ); + + let uncles = + sp_authorship::InherentDataProvider::<::Header>::check_inherents(); + + Ok((timestamp, slot, uncles)) + }, + &task_manager.spawn_essential_handle(), + config.prometheus_registry(), + sp_consensus::NeverCanAuthor, + telemetry.as_ref().map(|x| x.handle()), + )?; + + let (network, system_rpc_tx, network_starter) = + sc_service::build_network(sc_service::BuildNetworkParams { + config: &config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + spawn_handle: task_manager.spawn_handle(), + import_queue, + on_demand: Some(on_demand.clone()), + block_announce_validator_builder: None, + })?; + + let enable_grandpa = !config.disable_grandpa; + if enable_grandpa { + let name = config.network.node_name.clone(); + + let config = sc_finality_grandpa::Config { + gossip_duration: std::time::Duration::from_millis(333), + justification_period: 512, + name: Some(name), + observer_enabled: false, + keystore: None, + local_role: config.role.clone(), + telemetry: telemetry.as_ref().map(|x| x.handle()), + }; + + task_manager.spawn_handle().spawn_blocking( + "grandpa-observer", + sc_finality_grandpa::run_grandpa_observer(config, grandpa_link, network.clone())?, + ); + } + + if config.offchain_worker.enabled { + sc_service::build_offchain_workers( + &config, + task_manager.spawn_handle(), + client.clone(), + network.clone(), + ); + } + + let light_deps = super::rpc::LightDeps { + remote_blockchain: backend.remote_blockchain(), + fetcher: on_demand.clone(), + client: client.clone(), + pool: transaction_pool.clone(), + }; + + let rpc_extensions = super::rpc::create_light(light_deps); + + let rpc_handlers = + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + on_demand: Some(on_demand), + remote_blockchain: Some(backend.remote_blockchain()), + rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)), + client: client.clone(), + transaction_pool: transaction_pool.clone(), + keystore: keystore_container.sync_keystore(), + config, backend, system_rpc_tx, + network: network.clone(), + task_manager: &mut task_manager, + telemetry: telemetry.as_mut(), + })?; + + network_starter.start_network(); + Ok(( + task_manager, + rpc_handlers, + client, + network, + transaction_pool, + )) +} + +/// Builds a new service for a light client. +pub fn new_light( + config: Configuration, +) -> Result { + new_light_base(config).map(|(task_manager, _, _, _, _)| { + task_manager + }) +} \ No newline at end of file diff --git a/pallets/provider/Cargo.toml b/pallets/provider/Cargo.toml new file mode 100644 index 0000000000..410796ca26 --- /dev/null +++ b/pallets/provider/Cargo.toml @@ -0,0 +1,93 @@ +[package] +authors = ['Substrate DevHub '] +description = 'FRAME pallet template for defining custom runtime logic.' +edition = '2018' +homepage = 'https://substrate.dev' +license = 'Unlicense' +name = 'pallet-provider' +readme = 'README.md' +repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' +version = '3.0.0' +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] +[dev-dependencies.serde] +version = '1.0.119' + +[dev-dependencies.sp-core] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dev-dependencies.sp-io] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-runtime] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[features] +default = ['std'] +runtime-benchmarks = ['frame-benchmarking'] +std = [ + 'codec/std', + 'frame-support/std', + 'frame-system/std', + 'frame-benchmarking/std', + 'sp-runtime/std', + 'sp-std/std', + 'log/std', + 'primitives/std', + 'sp-core/std', +] +try-runtime = ['frame-support/try-runtime'] +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '2.0.0' + +[dependencies.frame-benchmarking] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +optional = true +tag = 'monthly-2021-07' +version = '3.1.0' + +[dependencies.frame-support] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-system] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-std] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.primitives] +default-features = false +package="ttc-primitives" +path = '../../primitives' +version = '3.0.0' + +[dependencies.sp-core] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies] +log = { version = "0.4.14", default-features = false } \ No newline at end of file diff --git a/pallets/provider/src/lib.rs b/pallets/provider/src/lib.rs new file mode 100644 index 0000000000..a4ae3ca1a1 --- /dev/null +++ b/pallets/provider/src/lib.rs @@ -0,0 +1,416 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::{dispatch::DispatchResult, + pallet_prelude::*, traits::{Currency}}; +use frame_support::sp_runtime::traits::Convert; +use frame_system::pallet_prelude::*; +use sp_std::convert::TryInto; +use sp_std::vec::Vec; + + +/// Edit this file to define custom logic or remove it if it is not needed. +/// Learn more about FRAME and the core library of Substrate FRAME pallets: +/// + +pub use pallet::*; +pub use primitives::p_resource_order::*; +pub use primitives::p_provider::*; + +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; + + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use primitives::Balance; + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type Event: From> + IsType<::Event>; + + /// currency to pay fees and hold balances + type Currency: Currency; + + /// amount converted to numbers + type BalanceToNumber: Convert, u128>; + + /// resource expiration polling interval + type ResourceInterval: Get; + } + + #[pallet::pallet] + #[pallet::generate_store(pub (super) trait Store)] + pub struct Pallet(_); + + /// resource information + #[pallet::storage] + #[pallet::getter(fn resource)] + pub(super) type Resources = StorageMap<_, Twox64Concat, u64, ComputingResource, OptionQuery>; + + + /// resource index + #[pallet::storage] + #[pallet::getter(fn resource_index)] + pub(super) type ResourceIndex = StorageValue<_, u64, ValueQuery>; + + /// number of resources + #[pallet::storage] + #[pallet::getter(fn resource_count)] + pub(super) type ResourceCount = StorageValue<_, u64, ValueQuery>; + + /// Association between future block numbers and expired resource indexes + #[pallet::storage] + #[pallet::getter(fn future_expired_resource)] + pub(super) type FutureExpiredResource = StorageMap<_, Twox64Concat, T::BlockNumber, Vec, OptionQuery>; + + + /// resource provider and resource association + #[pallet::storage] + #[pallet::getter(fn provider)] + pub(super) type Provider = StorageMap<_, Twox64Concat, T::AccountId, Vec, OptionQuery>; + + // Pallets use events to inform users when important changes are made. + // https://substrate.dev/docs/en/knowledgebase/runtime/events + #[pallet::event] + #[pallet::metadata(T::AccountId = "AccountId")] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + /// successfully registered resources + /// [accountId, index, peerId, cpu, memory, system, cpu_model, price_hour, rent_duration_hour] + RegisterResourceSuccess(T::AccountId, u64, Vec, u64, u64, Vec, Vec, Balance, u32), + /// modify the resource unit price successfully [accountId, index, balance] + ModifyResourceUnitPrice(T::AccountId, u64, u128), + /// successfully added resource rental duration + AddingResourceDurationSuccess(T::AccountId, u32), + /// successfully deleted + RemoveSuccess(T::AccountId, u64), + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(now: T::BlockNumber) -> Weight { + //Determine whether there is a current block in the block association information + if FutureExpiredResource::::contains_key(now) { + let option = FutureExpiredResource::::get(now); + //Determine whether the expired resource corresponding to the current block is empty + match option{ + Some(t) => { + t.into_iter().for_each(|resource_index| { + // Determine whether there is a resource in the Vec of an expired resource + if Resources::::contains_key(resource_index) { + //get the resource corresponding to the index + let resource_option = Resources::::get(resource_index); + if resource_option.is_some() { + let account_id = resource_option.unwrap().account_id; + // delete associated resource + if Provider::::contains_key(&account_id) { + let account_resources = Provider::::get(&account_id); + if account_resources.is_some() { + let resource: Vec = + account_resources.unwrap() + .into_iter().filter(|x| *x != resource_index.clone()).collect(); + Provider::::insert(account_id, resource); + } + } + + //remove resource + Resources::::remove(resource_index); + // reduce count + let count = ResourceCount::::get(); + ResourceCount::::set(count - 1); + } + } + }); + + // delete expired resource mappings + FutureExpiredResource::::remove(now); + }, + None => () + } + } + 0 + } + } + + // Errors inform users that something went wrong. + #[pallet::error] + pub enum Error { + /// resource does not exist + ResourceNotFound, + /// illegal request + IllegalRequest, + /// cannot be deleted + CannotBeDeleted, + /// retry + TryAgain, + /// current unmodifiable state + UnmodifiableStatusNow, + /// resource expired + ResourcesExpired, + } + + // Dispatchable functions allows users to interact with the pallet and invoke state changes. + // These functions materialize as "extrinsics", which are often compared to transactions. + // Dispatchable functions must be annotated with a weight and must return a DispatchResult. + #[pallet::call] + impl Pallet { + /// register resources + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn register_resource( + account_id: OriginFor, + peer_id: Vec, + cpu: u64, + memory: u64, + system: Vec, + cpu_model: Vec, + price: BalanceOf, + rent_duration_hour: u32, + ) -> DispatchResult { + let who = ensure_signed(account_id)?; + let index = ResourceIndex::::get(); + + let resource_config = + ResourceConfig::new(cpu.clone(), memory.clone(), + system.clone(), cpu_model.clone()); + + let statistics = + ResourceRentalStatistics::new(0, 0, 0, 0); + + // get the current block height + let block_number = >::block_number(); + // calculate persistent blocks + let rent_blocks = + TryInto::::try_into(&rent_duration_hour * 600).ok().unwrap(); + // the block number at which the calculation ends + let end_of_block = block_number + rent_blocks; + + let resource_rental_info = + ResourceRentalInfo::new(T::BalanceToNumber::convert(price.clone()), + rent_blocks, end_of_block); + + let computing_resource = ComputingResource::new( + index, who.clone(), peer_id.clone(), resource_config, + statistics, resource_rental_info, + ResourceStatus::Unused, + ); + + //Associate the block number and the resource id to expire + if !FutureExpiredResource::::contains_key(end_of_block) { + // init + let vec: Vec = Vec::new(); + FutureExpiredResource::::insert(end_of_block, vec); + } + + let mut expired_resource = FutureExpiredResource::::get(end_of_block).unwrap(); + + // determine whether to associate too many resources + ensure!(expired_resource.len() < 400, Error::::TryAgain); + + expired_resource.push(index); + FutureExpiredResource::::insert(end_of_block, expired_resource); + // increase resources + Resources::::insert(index, computing_resource.clone()); + // increase the total + let count = ResourceCount::::get(); + ResourceCount::::set(count + 1); + // index auto increment + ResourceIndex::::set(index + 1); + // update publisher associated resource + if !Provider::::contains_key(who.clone()) { + // Initialize + let vec: Vec = Vec::new(); + Provider::::insert(who.clone(), vec); + } + let mut resources = Provider::::get(who.clone()).unwrap(); + resources.push(index); + Provider::::insert(who.clone(), resources); + + Self::deposit_event(Event::RegisterResourceSuccess(who, index, peer_id, cpu, memory, system, cpu_model, T::BalanceToNumber::convert(price), rent_duration_hour)); + + Ok(()) + } + + /// modify resource unit price + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn modify_resource_price( + account_id: OriginFor, + index: u64, + unit_price: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(account_id)?; + + // query and modify + ensure!(Resources::::contains_key(index),Error::::ResourceNotFound); + let mut resource = + Self::get_computing_resource_info(index.clone()).unwrap(); + + ensure!(resource.account_id == who.clone(), Error::::IllegalRequest); + + resource.update_resource_price(T::BalanceToNumber::convert(unit_price.clone())); + Resources::::insert(&index, resource); + + Self::deposit_event(Event::ModifyResourceUnitPrice(who, index, T::BalanceToNumber::convert(unit_price))); + + Ok(()) + } + + /// add resource rental time + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn add_resource_duration( + account_id: OriginFor, + index: u64, + duration: u32, + ) -> DispatchResult { + let who = ensure_signed(account_id)?; + + // query and modify + ensure!(Resources::::contains_key(index),Error::::ResourceNotFound); + let mut resource = + Self::get_computing_resource_info(index.clone()).unwrap(); + // get current block + let block_number = >::block_number(); + ensure!(resource.rental_info.end_of_rent > block_number,Error::::ResourcesExpired); + + ensure!(resource.account_id == who.clone(), Error::::IllegalRequest); + + let duration_add = + TryInto::::try_into(duration * 600).ok().unwrap(); + + // Delete the resource associated with the previous expired block + let option = FutureExpiredResource::::get(resource.rental_info.end_of_rent.clone()); + if option.is_some() { + let resource_list: Vec = + option.unwrap() + .into_iter().filter(|x| *x != resource.index.clone()).collect(); + FutureExpiredResource::::insert(resource.rental_info.end_of_rent.clone(),resource_list); + } + + resource.add_resource_duration(duration_add); + Resources::::insert(&index, resource); + // get the modified resource + let changed_resource = + Self::get_computing_resource_info(index.clone()).unwrap(); + let rent_block = changed_resource.rental_info.end_of_rent; + // add_new_expired_block_associated_resource + if !FutureExpiredResource::::contains_key(rent_block) { + // init + let vec: Vec = Vec::new(); + FutureExpiredResource::::insert(rent_block, vec); + } + let mut expired_resource = FutureExpiredResource::::get(rent_block).unwrap(); + // determine whether to associate too many resources + ensure!(expired_resource.len() < 400, Error::::TryAgain); + expired_resource.push(changed_resource.index.clone()); + FutureExpiredResource::::insert(rent_block, expired_resource); + + Self::deposit_event(Event::AddingResourceDurationSuccess(who, duration)); + + Ok(()) + } + + /// delete resource + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn remove_resource( + account_id: OriginFor, + index: u64, + ) -> DispatchResult { + let who = ensure_signed(account_id)?; + ensure!(Resources::::contains_key(index),Error::::ResourceNotFound); + let resource = + Self::get_computing_resource_info(index.clone()).unwrap(); + + ensure!(resource.account_id == who.clone(), Error::::IllegalRequest); + + ensure!(resource.status == ResourceStatus::Unused || resource.status == ResourceStatus::Offline, Error::::CannotBeDeleted); + + // delete associated resource + if Provider::::contains_key(who.clone()) { + let option = Provider::::get(who.clone()); + if option.is_some() { + let resource_vec: Vec = + option.unwrap() + .into_iter().filter(|x| *x != index.clone()).collect(); + Provider::::insert(who.clone(), resource_vec); + } + } + + // reduce count + let count = ResourceCount::::get(); + ResourceCount::::set(count - 1); + + // Delete resources associated with future expirations + let end_of_rent = resource.rental_info.end_of_rent; + if FutureExpiredResource::::contains_key(&end_of_rent) { + let option1 = FutureExpiredResource::::get(&end_of_rent); + if option1.is_some() { + let new_resource: Vec = option1.unwrap() + .into_iter().filter(|x| *x != index.clone()).collect(); + FutureExpiredResource::::insert(end_of_rent, new_resource); + } + } + + //delete resource + Resources::::remove(&index); + + Self::deposit_event(Event::RemoveSuccess(who, index)); + + Ok(()) + } + + + /// change resource status to unused + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn change_resource_status(account_id: OriginFor, + index: u64) -> DispatchResult { + let who = ensure_signed(account_id)?; + ensure!(Resources::::contains_key(index),Error::::ResourceNotFound); + let mut resource = + Self::get_computing_resource_info(index.clone()).unwrap(); + + ensure!(resource.account_id == who.clone(), Error::::IllegalRequest); + ensure!(resource.status == ResourceStatus::Offline, Error::::UnmodifiableStatusNow); + resource.status = ResourceStatus::Unused; + + Self::update_computing_resource(index, resource).ok(); + + Ok(()) + } + } +} + + +impl Pallet { + /// query resources based on index + fn get_computing_resource_info(index: u64) -> Result, Error> { + ensure!(Resources::::contains_key(index),Error::::ResourceNotFound); + let res = Resources::::get(index).unwrap(); + Ok(res) + } + + /// modify resources + fn update_computing_resource(index: u64, + resource: ComputingResource, + ) -> Result<(), Error> { + ensure!(Resources::::contains_key(index),Error::::ResourceNotFound); + + Resources::::insert(index, resource); + Ok(()) + } +} + +impl OrderInterface for Pallet { + type AccountId = T::AccountId; + type BlockNumber = T::BlockNumber; + + + fn get_computing_resource_info(index: u64) -> Option> { + Resources::::get(index) + } + + fn update_computing_resource(index: u64, resource_info: ComputingResource) { + Self::update_computing_resource(index, resource_info).ok(); + } +} + diff --git a/pallets/resource-order/Cargo.toml b/pallets/resource-order/Cargo.toml new file mode 100644 index 0000000000..50e70e454d --- /dev/null +++ b/pallets/resource-order/Cargo.toml @@ -0,0 +1,100 @@ +[package] +authors = ['Substrate DevHub '] +description = 'FRAME pallet template for defining custom runtime logic.' +edition = '2018' +homepage = 'https://substrate.dev' +license = 'Unlicense' +name = 'pallet-resource-order' +readme = 'README.md' +repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' +version = '3.0.0' +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] +[dev-dependencies.serde] +version = '1.0.119' + +[dev-dependencies.sp-core] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dev-dependencies.sp-io] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-runtime] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[features] +default = ['std'] +runtime-benchmarks = ['frame-benchmarking'] +std = [ + 'codec/std', + 'frame-support/std', + 'frame-system/std', + 'frame-benchmarking/std', + 'sp-runtime/std', + 'sp-std/std', + 'log/std', + 'primitives/std', + 'sp-core/std', +] +try-runtime = ['frame-support/try-runtime'] +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '2.0.0' + +[dependencies.frame-benchmarking] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +optional = true +tag = 'monthly-2021-07' +version = '3.1.0' + +[dependencies.frame-support] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-system] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-std] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.primitives] +default-features = false +package="ttc-primitives" +path = '../../primitives' +version = '3.0.0' + +[dependencies.sp-core] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-balances] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies] +log = { version = "0.4.14", default-features = false } + diff --git a/pallets/resource-order/src/benchmarking.rs b/pallets/resource-order/src/benchmarking.rs new file mode 100644 index 0000000000..d62eb48d37 --- /dev/null +++ b/pallets/resource-order/src/benchmarking.rs @@ -0,0 +1,29 @@ +//! Benchmarking setup for pallet-template + + +use super::*; + +use frame_system::RawOrigin; +use frame_benchmarking::{benchmarks, whitelisted_caller, impl_benchmark_test_suite}; +#[allow(unused)] +use crate::Pallet as Template; +use sp_core::Bytes; +use frame_benchmarking::vec; + + +benchmarks! { + create_order_info { + let caller: T::AccountId = whitelisted_caller(); + + let resource_index:u64 = 0; + let rent_duration:u32 = 100; + let public_key = Bytes(vec![1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]); + }: _(RawOrigin::Signed(caller), resource_index,rent_duration,public_key) + +} + +impl_benchmark_test_suite!( + Template, + crate::mock::new_test_ext(), + crate::mock::Test, +); \ No newline at end of file diff --git a/pallets/resource-order/src/lib.rs b/pallets/resource-order/src/lib.rs new file mode 100644 index 0000000000..c5dd3708de --- /dev/null +++ b/pallets/resource-order/src/lib.rs @@ -0,0 +1,933 @@ +#![cfg_attr(not(feature = "std"), no_std)] + + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + + +use frame_support::{dispatch::DispatchResult, + pallet_prelude::*, PalletId, traits::{Currency, ExistenceRequirement}}; +use frame_support::sp_runtime::traits::Convert; +use frame_support::traits::UnixTime; +use frame_system::pallet_prelude::*; +use sp_core::Bytes; +use sp_runtime::traits::AccountIdConversion; +use sp_runtime::traits::Zero; +use sp_std::convert::TryInto; +use sp_std::vec::Vec; + +/// Edit this file to define custom logic or remove it if it is not needed. +/// Learn more about FRAME and the core library of Substrate FRAME pallets: +/// + +pub use pallet::*; +pub use primitives::p_provider::*; +pub use primitives::p_resource_order::*; + +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; + +const PALLET_ID: PalletId = PalletId(*b"ttchain!"); + + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event + type Event: From> + IsType<::Event>; + + /// currency to pay fees and hold balances + type Currency: Currency; + + /// order fee interface + type OrderInterface: OrderInterface; + + /// block height to number + type BlockNumberToNumber: Convert + Convert; + + /// digital transfer amount + type NumberToBalance: Convert>; + /// amount converted to numbers + type BalanceToNumber: Convert, u128>; + + /// health check interval + #[pallet::constant] + type HealthCheckInterval: Get; + + /// time + type UnixTime: UnixTime; + } + + #[pallet::pallet] + #[pallet::generate_store(pub (super) trait Store)] + pub struct Pallet(_); + + /// order index + #[pallet::storage] + #[pallet::getter(fn order_index)] + pub(super) type OrderIndex = StorageValue<_, u64, ValueQuery>; + + /// resource order information + #[pallet::storage] + #[pallet::getter(fn resource_orders)] + pub(super) type ResourceOrders = StorageMap<_, Twox64Concat, u64, ResourceOrder, OptionQuery>; + + /// lease agreement index + #[pallet::storage] + #[pallet::getter(fn agreement_index)] + pub(super) type AgreementIndex = StorageValue<_, u64, ValueQuery>; + + /// rental agreement information + #[pallet::storage] + #[pallet::getter(fn rental_agreements)] + pub(super) type RentalAgreements = StorageMap<_, Twox64Concat, u64, RentalAgreement, OptionQuery>; + + /// List of agreements corresponding to the lessor + #[pallet::storage] + #[pallet::getter(fn user_agreements)] + pub(super) type UserAgreements = StorageMap<_, Twox64Concat, T::AccountId, Vec, ValueQuery>; + + /// protocol list corresponding to provider + #[pallet::storage] + #[pallet::getter(fn provider_agreements)] + pub(super) type ProviderAgreements = StorageMap<_, Twox64Concat, T::AccountId, Vec, ValueQuery>; + + /// staking + #[pallet::storage] + #[pallet::getter(fn staking)] + pub(super) type Staking = StorageMap<_, Twox64Concat, T::AccountId, StakingAmount, OptionQuery>; + + /// The protocol corresponding to the block [block number, protocol number] + #[pallet::storage] + #[pallet::getter(fn block_agreement)] + pub(super) type BlockWithAgreement = StorageMap<_, Twox64Concat, T::BlockNumber, Vec, ValueQuery>; + + /// the order number corresponding to the user + #[pallet::storage] + #[pallet::getter(fn user_orders)] + pub(super) type UserOrders = StorageMap<_, Twox64Concat, T::AccountId, Vec, ValueQuery>; + + // Pallets use events to inform users when important changes are made. + // https://substrate.dev/docs/en/knowledgebase/runtime/events + #[pallet::event] + #[pallet::metadata(T::AccountId = "AccountId")] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + /// created order successfully + /// [account, order number, rental resource number, rental duration (h), user public key] + CreateOrderSuccess(T::AccountId, u64, u64, u32, Bytes), + + /// order renewal successful + /// [account, order number, rental resource number, rental duration (h)] + ReNewOrderSuccess(T::AccountId, u64, u64, u32), + + /// order executed successfully + /// [account, order number, rental resource number, rental agreement number] + OrderExecSuccess(T::AccountId, u64, u64, u64), + + /// health check reported successfully + /// [account, agreement number, block number of the reported agreement] + HealthCheckSuccess(T::AccountId, u64, T::BlockNumber), + + /// the pledge amount is successful + StakingSuccess(T::AccountId, BalanceOf), + + /// successfully retrieved the pledge amount + WithdrawStakingSuccess(T::AccountId, BalanceOf), + + /// successfully retrieve the rental reward amount + /// account agreement number amount + WithdrawRentalAmountSuccess(T::AccountId, u64, BalanceOf), + + /// retrieve the penalty amount successfully + /// account agreement number amount + WithdrawFaultExcutionSuccess(T::AccountId, u64, BalanceOf), + + /// The amount of the unstarted order was successfully recovered + /// account order number amount + WithdrawLockedOrderPriceSuccess(T::AccountId, u64, BalanceOf), + + /// agreement deleted successfully + /// agreement number + AgreementDeletedSuccess(u64), + + /// expired resource status updated successfully + /// [resource index] + ExpiredResourceStatusUpdatedSuccess(u64), + + /// penalty agreement executed successfully + PenaltyAgreementExcutionSuccess(u64), + + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(now: T::BlockNumber) -> Weight { + // check for expired agreements + Self::agreement_check(now); + + // health examination + if (now % T::HealthCheckInterval::get()).is_zero() { + Self::do_health_check(now).ok(); + } + + 0 + } + + fn on_finalize(now: BlockNumberFor) { + // delete + BlockWithAgreement::::remove(now); + } + } + + // Errors inform users that something went wrong. + #[pallet::error] + pub enum Error { + /// insufficient user balance + InsufficientCurrency, + /// the resource has been leased + ResourceHasBeenRented, + /// resource does not exist + ResourceNotExist, + /// exceeded rental period + ExceedTheRentableTime, + /// the owner of the order is not me + OrderNotOwnedByYou, + /// the owner of the agreement is not me + ProtocolNotOwnedByYou, + /// order does not exist + OrderDoesNotExist, + /// wrong order status + OrderStatusError, + /// agreement does not exist + ProtocolDoesNotExist, + /// agreement has been punished + AgreementHasBeenPunished, + /// insufficient pledge amount + InsufficientStaking, + /// pledge does not exist + StakingNotExist, + /// insufficient time to rent resources + InsufficientTimeForResource, + /// failed to claim + FailedToWithdraw, + /// The protocol under the current block exceeds the maximum number + ExceedsMaximumQuantity, + } + + // Dispatchable functions allows users to interact with the pallet and invoke state changes. + // These functions materialize as "extrinsics", which are often compared to transactions. + // Dispatchable functions must be annotated with a weight and must return a DispatchResult. + #[pallet::call] + impl Pallet { + /// create order + /// [Resource number, lease duration (hours), public key] + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn create_order_info( + origin: OriginFor, + resource_index: u64, + rent_duration: u32, + public_key: Bytes, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // get resource information + let mut resource_info = match T::OrderInterface::get_computing_resource_info(resource_index) { + Some(x) => x, + None => Err(Error::::ResourceNotExist)? + }; + // determine if the resource is leased + ensure!(resource_info.status == ResourceStatus::Unused, Error::::ResourceHasBeenRented); + + // get the current block height + let block_number = >::block_number(); + // calculate persistent blocks + let rent_blocks = TryInto::::try_into(rent_duration * 600).ok().unwrap(); + // determine whether the rental period is exceeded + ensure!(block_number + rent_blocks < resource_info.rental_info.end_of_rent,Error::::ExceedTheRentableTime); + + // get order length + let order_index = OrderIndex::::get(); + // get order price + let price = resource_info.rental_info.rent_unit_price; + // calculate order price + let order_price = price * rent_duration as u128; + // create a tenant + let customer = TenantInfo::new(who.clone(), public_key.clone()); + // get the current time + let now = T::UnixTime::now(); + // create order + let order = ResourceOrder::new( + order_index, + customer, + order_price, + resource_index, + block_number, + rent_blocks, + now, + ); + + // transfer to the fund pool + T::Currency::transfer(&who.clone(), &Self::order_pool(), T::NumberToBalance::convert(order_price), ExistenceRequirement::AllowDeath)?; + + // resource status changed from unused to locked + resource_info.update_status(ResourceStatus::Locked); + + + // save resource state + T::OrderInterface::update_computing_resource(resource_index, resource_info); + // add order to order collection + ResourceOrders::::insert(order_index, order.clone()); + // order length+1 + OrderIndex::::put(order_index + 1); + // save the order corresponding to the user + Self::do_insert_user_orders(who.clone(),order_index); + + Self::deposit_event(Event::CreateOrderSuccess(who, order_index, resource_index, rent_duration, public_key)); + Ok(()) + } + + + /// order execution + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn order_exec( + origin: OriginFor, + order_index: u64, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // check if an order exists + ensure!(ResourceOrders::::contains_key(order_index),Error::::OrderDoesNotExist); + // get order details + let mut order = ResourceOrders::::get(order_index).unwrap(); + + // determine order status + ensure!(order.status == OrderStatus::Pending,Error::::OrderStatusError); + // get resource information + let mut resource_info = match T::OrderInterface::get_computing_resource_info(order.resource_index) { + Some(x) => x, + None => Err(Error::::ResourceNotExist)? + }; + // determine whether it is me + ensure!(who.clone() == resource_info.account_id,Error::::OrderNotOwnedByYou); + + + // get order amount + let order_price = order.price; + // get pledge information + ensure!(Staking::::contains_key(who.clone()),Error::::InsufficientStaking); + let mut staking_info = Staking::::get(who.clone()).unwrap(); + // determine whether the pledge deposit is sufficient,and lock the amount + ensure!(&staking_info.lock_amount(order_price),Error::::InsufficientStaking); + + // get the current block height + let block_number = >::block_number(); + // get resource number + let resource_index = order.resource_index; + + // whether it is a renewal order + if order.clone().is_renew_order() { + // query resource agreement number + let agreement_index = order.agreement_index.unwrap(); + // query protocol + let mut agreement = RentalAgreements::::get(agreement_index).unwrap(); + // get order duration + let duration = order.rent_duration; + // get the end block of the old order + let old_end = agreement.end.clone(); + + // agreement renewal + agreement.renew(order_price, duration, resource_info.clone()); + // order status changes to completed + order.finish_order(); + // increase usage time + resource_info.rental_statistics.add_rental_duration(T::BlockNumberToNumber::convert(order.rent_duration) as u32 / 600); + // Remove the corresponding protocol number from the original block + let new_vec = BlockWithAgreement::::get(old_end) + .into_iter() + .filter(|x| { + if x == &agreement_index { + false + } else { + true + } + }) + .collect::>(); + + // If the protocol number is deleted, vec is not empty + if !new_vec.is_empty() { + BlockWithAgreement::::mutate(old_end, |vec| { + *vec = new_vec; + }); + } else { + BlockWithAgreement::::remove(old_end); + } + + + // Save the new block number and the corresponding expiring agreement number + Self::do_insert_block_with_agreement(agreement.end, agreement_index).ok(); + // save resource state + T::OrderInterface::update_computing_resource(resource_index, resource_info.clone()); + // Add the agreement to the lease agreement collection + RentalAgreements::::insert(agreement_index, agreement.clone()); + // save order + ResourceOrders::::insert(order_index, order.clone()); + // save the pledge + Staking::::insert(who.clone(), staking_info); + + Self::deposit_event(Event::OrderExecSuccess(who.clone(), order_index, resource_index, agreement_index)); + } else { + // get agreement number + let agreement_index = AgreementIndex::::get(); + // determine if the resource is locked + ensure!(resource_info.status == ResourceStatus::Locked, Error::::ResourceHasBeenRented); + // get peer id + let peer_id = resource_info.peer_id.clone(); + // end block + let end = block_number + order.rent_duration; + // get the current time + let now = T::UnixTime::now(); + // create a rental agreement + let agreement = RentalAgreement::new( + agreement_index, + who.clone(), + order.clone().tenant_info, + peer_id, + resource_index, + resource_info.config.clone(), + resource_info.rental_info.clone(), + order_price, + order.price, + 0, + 0, + block_number, + end, + block_number, + now, + ); + + + // order status changes to completed + order.finish_order(); + // resource status changed from locked to in use + resource_info.update_status(ResourceStatus::Inuse); + // usage count+1 + resource_info.rental_statistics.add_rental_count(); + // increase usage time + resource_info.rental_statistics.add_rental_duration(T::BlockNumberToNumber::convert(order.rent_duration) as u32 / 600); + + + // Add protocol expiration block number and protocol number + Self::do_insert_block_with_agreement(end, agreement_index).ok(); + // associate user and protocol number + Self::do_insert_user_agreements(agreement.tenant_info.account_id.clone(), agreement_index); + // associate provider and agreement number + Self::do_insert_provider_agreements(agreement.provider.clone(), agreement_index); + // agreement number+1 + AgreementIndex::::put(agreement_index + 1); + // Add the agreement to the lease agreement collection + RentalAgreements::::insert(agreement_index, agreement.clone()); + // save order + ResourceOrders::::insert(order_index, order.clone()); + // save the pledge + Staking::::insert(who.clone(), staking_info); + // save resource state + T::OrderInterface::update_computing_resource(resource_index, resource_info.clone()); + + + Self::deposit_event(Event::OrderExecSuccess(who.clone(), order_index, resource_index, agreement_index)); + } + + Ok(()) + } + + /// protocol resource heartbeat report + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn heartbeat( + origin: OriginFor, + agreement_index: u64, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // get agreement + ensure!(RentalAgreements::::contains_key(agreement_index),Error::::ProtocolDoesNotExist); + let mut agreement = RentalAgreements::::get(agreement_index).unwrap(); + // determine whether it is me + ensure!(who.clone() == agreement.provider,Error::::ProtocolNotOwnedByYou); + // get the current block height + let block_number = >::block_number(); + + // Execution Agreement, Current Release Amount + ensure!(agreement.execution(&block_number),Error::::AgreementHasBeenPunished); + + // save the agreement + RentalAgreements::::insert(agreement_index, agreement.clone()); + + Self::deposit_event(Event::HealthCheckSuccess(who.clone(), agreement_index, block_number)); + Ok(()) + } + + /// staking + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn staking_amount( + origin: OriginFor, + bond_price: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // transfer + T::Currency::transfer(&who.clone(), &Self::staking_pool(), bond_price, ExistenceRequirement::AllowDeath)?; + + // if there is a pledge + if Staking::::contains_key(&who) { + // get pledge details + let mut staking_info = Staking::::get(who.clone()).unwrap(); + // calculate the new total pledge amount + let price = T::BalanceToNumber::convert(bond_price); + // pledge amount + staking_info.staking_amount(price); + // save pledge details + Staking::::insert(who.clone(), staking_info); + } else { + // add pledge details + Staking::::insert(who.clone(), StakingAmount { + amount: T::BalanceToNumber::convert(bond_price), + active_amount: T::BalanceToNumber::convert(bond_price), + lock_amount: 0, + }); + } + + Self::deposit_event(Event::StakingSuccess(who.clone(), bond_price)); + Ok(()) + } + + + /// get back the pledge + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn withdraw_amount( + origin: OriginFor, + price: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + // determine whether there is a pledge + ensure!(Staking::::contains_key(who.clone()),Error::::StakingNotExist); + + let mut staking = Staking::::get(who.clone()).unwrap(); + + // get back the amount + ensure!(&staking.withdraw_amount(T::BalanceToNumber::convert(price)),Error::::InsufficientStaking); + // transfer + T::Currency::transfer(&Self::staking_pool(), &who.clone(), price, ExistenceRequirement::AllowDeath)?; + + // save the pledge + Staking::::insert(who.clone(), staking); + + Self::deposit_event(Event::WithdrawStakingSuccess(who.clone(), price)); + + Ok(()) + } + + + /// get back rental bonus amount + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn withdraw_rental_amount( + origin: OriginFor, + agreement_index: u64, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // get agreement + ensure!(RentalAgreements::::contains_key(agreement_index),Error::::ProtocolDoesNotExist); + let mut agreement = RentalAgreements::::get(agreement_index).unwrap(); + // determine whether it is me + ensure!(who.clone() == agreement.provider.clone(),Error::::ProtocolNotOwnedByYou); + // get the amount you can claim + let price = T::NumberToBalance::convert(agreement.withdraw()); + // transfer and receive amount + T::Currency::transfer(&Self::order_pool(), &who.clone(), price, ExistenceRequirement::AllowDeath)?; + + // Whether the settlement of the agreement is completed + if agreement.clone().is_finished() { + // delete agreement + Self::delete_agreement(agreement_index, agreement.provider.clone(),agreement.tenant_info.account_id.clone()); + } else { + // save the agreement + RentalAgreements::::insert(agreement_index, agreement.clone()); + } + + Self::deposit_event(Event::WithdrawRentalAmountSuccess(who.clone(), agreement_index, price)); + Ok(()) + } + + /// the penalty amount for the withdrawal agreement + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn withdraw_fault_excution( + origin: OriginFor, + agreement_index: u64, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // get agreement + ensure!(RentalAgreements::::contains_key(agreement_index),Error::::ProtocolDoesNotExist); + let mut agreement = RentalAgreements::::get(agreement_index).unwrap(); + // determine whether it is a user + ensure!(who.clone() == agreement.tenant_info.account_id,Error::::ProtocolNotOwnedByYou); + // get the amount you can claim + let price = T::NumberToBalance::convert(agreement.withdraw_penalty()); + // transfer and receive amount + T::Currency::transfer(&Self::order_pool(), &who.clone(), price, ExistenceRequirement::AllowDeath)?; + + + // whether the agreement is completed + if agreement.clone().is_finished() { + // delete agreement + Self::delete_agreement(agreement_index, agreement.provider.clone(),agreement.tenant_info.account_id.clone()); + } else { + // save the agreement + RentalAgreements::::insert(agreement_index, agreement.clone()); + } + + Self::deposit_event(Event::WithdrawFaultExcutionSuccess(who.clone(), agreement_index, price)); + Ok(()) + } + + + /// cancel order + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn cancel_order( + origin: OriginFor, + order_index: u64, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + // check if an order exists + ensure!(ResourceOrders::::contains_key(order_index),Error::::OrderDoesNotExist); + // get an order + let mut order = ResourceOrders::::get(order_index).unwrap(); + // determine whether it is a user + ensure!(who.clone() == order.tenant_info.account_id,Error::::OrderNotOwnedByYou); + // get resource information + let mut resource = match T::OrderInterface::get_computing_resource_info(order.resource_index) { + Some(x) => x, + None => Err(Error::::ResourceNotExist)? + }; + // get order amount + let price = T::NumberToBalance::convert(order.price); + + // check order status + if order.clone().is_renew_order() && order.status == OrderStatus::Pending { + // cancel order + order.cancel_order(); + // get back the amount + T::Currency::transfer(&Self::order_pool(), &who.clone(), price, ExistenceRequirement::AllowDeath)?; + // save order + ResourceOrders::::insert(order_index, order); + Self::deposit_event(Event::WithdrawLockedOrderPriceSuccess(who.clone(), order_index, price)); + } else if !order.clone().is_renew_order() && order.status == OrderStatus::Pending { + + // cancel order + order.cancel_order(); + // change the resource state to unused + resource.status = ResourceStatus::Unused; + // get back the amount + T::Currency::transfer(&Self::order_pool(), &who.clone(), price, ExistenceRequirement::AllowDeath)?; + + // save order + ResourceOrders::::insert(order_index, order); + // save resource state + T::OrderInterface::update_computing_resource(resource.index, resource); + + Self::deposit_event(Event::WithdrawLockedOrderPriceSuccess(who.clone(), order_index, price)); + } else { + return Err(Error::::FailedToWithdraw)?; + } + + Ok(()) + } + + /// agreement renewal + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn renew_agreement( + origin: OriginFor, + agreement_index: u64, + duration: u32, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // get agreement + ensure!(RentalAgreements::::contains_key(agreement_index),Error::::ProtocolDoesNotExist); + let agreement = RentalAgreements::::get(agreement_index).unwrap(); + + // get resource number + let resource_index = agreement.resource_index; + // get resource information + let resource_info = match T::OrderInterface::get_computing_resource_info(resource_index) { + Some(x) => x, + None => Err(Error::::ResourceNotExist)? + }; + // get the current block height + let block_number = >::block_number(); + // get resource end time + let end_resource = resource_info.rental_info.end_of_rent; + // get rental block + let rent_duration = T::BlockNumberToNumber::convert(duration * 600); + ensure!(rent_duration + block_number < end_resource,Error::::InsufficientTimeForResource); + // calculate new order price + let price = resource_info.rental_info.rent_unit_price * duration as u128; + + // get order length + let order_index = OrderIndex::::get(); + // get the current time + let now = T::UnixTime::now(); + + let order = ResourceOrder::renew( + order_index, + agreement.tenant_info.clone(), + price, + resource_index, + block_number, + rent_duration, + now, + Some(agreement_index), + ); + + // transfer to the fund pool + T::Currency::transfer(&who.clone(), &Self::order_pool(), T::NumberToBalance::convert(price), ExistenceRequirement::AllowDeath)?; + + ResourceOrders::::insert(order_index, order.clone()); + OrderIndex::::put(order_index + 1); + // save the order corresponding to the user + Self::do_insert_user_orders(who.clone(),order_index); + + Self::deposit_event(Event::ReNewOrderSuccess(who.clone(), order_index, resource_index, duration)); + Ok(()) + } + } +} + + +impl Pallet { + /// StakingPod + pub fn staking_pool() -> T::AccountId { PALLET_ID.into_sub_account(b"staking") } + /// StoragePod + pub fn order_pool() -> T::AccountId { PALLET_ID.into_sub_account(b"order") } + + // associate user and protocol number + pub fn do_insert_user_agreements(who: T::AccountId, agreement_count: u64) { + // detects the existence of a user s protocol + if !UserAgreements::::contains_key(who.clone()) { + let mut vec = Vec::new(); + vec.push(agreement_count); + + UserAgreements::::insert(who.clone(), vec); + }else { + UserAgreements::::mutate(&who, |vec| { + vec.push(agreement_count); + }); + } + } + + // associate provider and agreement number + pub fn do_insert_provider_agreements(who: T::AccountId, agreement_count: u64) { + // detects the existence of a user s protocol + if !ProviderAgreements::::contains_key(who.clone()) { + let mut vec = Vec::new(); + vec.push(agreement_count); + + ProviderAgreements::::insert(who.clone(), vec); + }else { + ProviderAgreements::::mutate(&who, |vec| { + vec.push(agreement_count); + }); + } + } + + + + // Associate the block number with the protocol number + pub fn do_insert_block_with_agreement(end: T::BlockNumber, agreement_index: u64) -> DispatchResult { + if BlockWithAgreement::::contains_key(end) { + // the maximum number of protocols in a block is 2000 + ensure!(BlockWithAgreement::::get(end).len() > 2000, Error::::ExceedsMaximumQuantity); + + BlockWithAgreement::::mutate(end, |vec| { + vec.push(agreement_index); + }); + } else { + let mut vec = Vec::new(); + vec.push(agreement_index); + BlockWithAgreement::::insert(end, vec); + } + + Ok(()) + } + + // associate user and order number + pub fn do_insert_user_orders(who: T::AccountId, order_index: u64) { + + if UserOrders::::contains_key(who.clone()) { + UserOrders::::mutate(who,|vec|{ + vec.push(order_index) + }) + }else { + let mut vec = Vec::new(); + vec.push(order_index); + UserOrders::::insert(who.clone(),vec); + } + + } + + // delete agreement + pub fn delete_agreement(agreement_index: u64, provider: T::AccountId,user: T::AccountId) { + let new_vec = UserAgreements::::get(user.clone()) + .into_iter() + .filter(|x| { + if x == &agreement_index { + false + } else { + true + } + }).collect::>(); + + UserAgreements::::mutate(user.clone(), |vec| { + *vec = new_vec; + }); + + let new_vec = ProviderAgreements::::get(provider.clone()) + .into_iter() + .filter(|x| { + if x == &agreement_index { + false + } else { + true + } + }).collect::>(); + + ProviderAgreements::::mutate(provider.clone(), |vec| { + *vec = new_vec; + }); + + // delete agreement + RentalAgreements::::remove(agreement_index); + } + + // delete the protocol corresponding to the block + pub fn delete_block_with_agreement(agreement_index: u64, end: T::BlockNumber) { + + // Remove the corresponding protocol number from the original block + let new_vec = BlockWithAgreement::::get(end.clone()) + .into_iter() + .filter(|x| { + if x == &agreement_index { + false + } else { + true + } + }) + .collect::>(); + + // If the protocol number is deleted, vec is not empty + if !new_vec.is_empty() { + BlockWithAgreement::::mutate(end, |vec| { + *vec = new_vec; + }); + } else { + BlockWithAgreement::::remove(end); + } + } + + + // health examination + pub fn do_health_check(now: T::BlockNumber) -> DispatchResult { + // get a list of protocols + let agreements = RentalAgreements::::iter(); + + for (i, mut agreement) in agreements { + + if agreement.status == AgreementStatus::Using { + // get resource number + let resource_index = agreement.resource_index; + // get resource information + let mut resource = match T::OrderInterface::get_computing_resource_info(resource_index) { + Some(x) => x, + None => Err(Error::::ResourceNotExist)? + }; + + // get the interval from the last report + let duration = now - agreement.calculation; + + // check whether the protocol reports a health check + if duration > T::HealthCheckInterval::get() { + // Execute the penalty agreement and get the remaining amount of the order + let price = agreement.fault_excution(); + + // get pledge + let mut staking = Staking::::get(agreement.provider.clone()).unwrap(); + staking.penalty_amount(price); + + T::Currency::transfer(&Self::staking_pool(), &agreement.tenant_info.account_id, T::NumberToBalance::convert(price), ExistenceRequirement::AllowDeath)?; + + // number of resource failures+1 + resource.rental_statistics.add_fault_count(); + // resource set to unused + resource.update_status(ResourceStatus::Offline); + // protocol is set to penalized + agreement.change_status(AgreementStatus::Punished); + + + // Delete the protocol number in the corresponding block + Self::delete_block_with_agreement(i,agreement.end.clone()); + // save the pledge + Staking::::insert(agreement.provider.clone(), staking); + // save the agreement + RentalAgreements::::insert(i, agreement); + // save resources + T::OrderInterface::update_computing_resource(resource_index, resource); + + Self::deposit_event(Event::PenaltyAgreementExcutionSuccess(i)); + } + } + + } + + Ok(()) + } + + // check for expired agreements + pub fn agreement_check(now: T::BlockNumber) { + // find if the current block has expired protocols + let agreements_index = BlockWithAgreement::::get(now); + + for i in agreements_index { + // get agreement + let mut agreement = RentalAgreements::::get(i).unwrap(); + // get resource number + let resource_index = agreement.resource_index; + // get resource information + let mut resource = T::OrderInterface::get_computing_resource_info(resource_index).unwrap(); + // get pledge + let mut staking = Staking::::get(agreement.provider.clone()).unwrap(); + + // unlock pledge + staking.unlock_amount(agreement.price); + + + // set resource to unused + resource.update_status(ResourceStatus::Unused); + // set the agreement as done + agreement.change_status(AgreementStatus::Finished); + + // save resource state + T::OrderInterface::update_computing_resource(resource_index, resource); + // save the agreement + RentalAgreements::::insert(i,agreement.clone()); + // save the pledge + Staking::::insert(agreement.provider, staking); + Self::deposit_event(Event::ExpiredResourceStatusUpdatedSuccess(resource_index)); + } + } +} + + diff --git a/pallets/template/Cargo.toml b/pallets/template/Cargo.toml new file mode 100644 index 0000000000..239dd85b1e --- /dev/null +++ b/pallets/template/Cargo.toml @@ -0,0 +1,92 @@ +[package] +authors = ['Substrate DevHub '] +description = 'FRAME pallet template for defining custom runtime logic.' +edition = '2018' +homepage = 'https://substrate.dev' +license = 'Unlicense' +name = 'pallet-template' +readme = 'README.md' +repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' +version = '3.0.0' +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] +[dev-dependencies.serde] +version = '1.0.119' + +[dev-dependencies.sp-io] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dev-dependencies.sp-runtime] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[features] +default = ['std'] +runtime-benchmarks = ['frame-benchmarking'] +std = [ + 'codec/std', + 'frame-support/std', + 'frame-system/std', + 'frame-benchmarking/std', + 'primitives/std', + 'sp-core/std', + 'sp-runtime/std', + 'sp-std/std', +] +try-runtime = ['frame-support/try-runtime'] +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '2.0.0' + +[dependencies.frame-benchmarking] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +optional = true +tag = 'monthly-2021-07' +version = '3.1.0' + +[dependencies.frame-support] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-system] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-std] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.primitives] +default-features = false +package="ttc-primitives" +path = '../../primitives' +version = '3.0.0' + +[dependencies.sp-core] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-runtime] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies] +hex-literal = "0.3.1" diff --git a/pallets/template/README.md b/pallets/template/README.md new file mode 100644 index 0000000000..8d751a4220 --- /dev/null +++ b/pallets/template/README.md @@ -0,0 +1 @@ +License: Unlicense \ No newline at end of file diff --git a/pallets/template/src/benchmarking.rs b/pallets/template/src/benchmarking.rs new file mode 100644 index 0000000000..0a98f4988b --- /dev/null +++ b/pallets/template/src/benchmarking.rs @@ -0,0 +1,40 @@ +//! Benchmarking setup for pallet-template + +use super::*; + +use frame_system::RawOrigin; +use frame_benchmarking::{benchmarks, whitelisted_caller, impl_benchmark_test_suite}; +#[allow(unused)] +use crate::Pallet as Template; + +benchmarks! { + //This will measure the execution time of `do_something` for b in the range [1..100]. + do_something { + let s in 0 .. 100; + let caller: T::AccountId = whitelisted_caller(); + }: _(RawOrigin::Signed(caller), s) + verify { + assert_eq!(Something::::get(), Some(s)); + } + + set_dummy_benchmark { + // This is the benchmark setup phase + let b in 1 .. 1000; + }: set_dummy(RawOrigin::Root, b.into()) + verify { + // This is an optional benchmarking phase that tests certain states. + assert_eq!(Pallet::::dummy(), Some(b.into())) + } + + accumulate_dummy { + let b in 1 .. 1000; + // The caller account is whitelisted for database read and write by the benchmark macro. + let caller: T::AccountId = whitelisted_caller(); + }: _(RawOrigin::Signed(caller), b.into()) +} + +impl_benchmark_test_suite!( + Template, + crate::mock::new_test_ext(), + crate::mock::Test, +); diff --git a/pallets/template/src/lib.rs b/pallets/template/src/lib.rs new file mode 100644 index 0000000000..eb012997d9 --- /dev/null +++ b/pallets/template/src/lib.rs @@ -0,0 +1,183 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::sp_runtime::traits::Convert; + + +/// Edit this file to define custom logic or remove it if it is not needed. +/// Learn more about FRAME and the core library of Substrate FRAME pallets: +/// + +pub use pallet::*; +pub use primitives::p_provider::*; +pub use primitives::p_resource_order::*; +pub use weights::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +mod weights; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + + use super::*; + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type Event: From> + IsType<::Event>; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + + /// block height to number + type BlockNumberToNumber: Convert + Convert; + } + + #[pallet::pallet] + #[pallet::generate_store(pub (super) trait Store)] + pub struct Pallet(_); + + // The pallet's runtime storage items. + // https://substrate.dev/docs/en/knowledgebase/runtime/storage + #[pallet::storage] + #[pallet::getter(fn something)] + // Learn more about declaring storage items: + // https://substrate.dev/docs/en/knowledgebase/runtime/storage#declaring-storage-items + pub type Something = StorageValue<_, u32>; + + #[pallet::storage] + #[pallet::getter(fn dummy)] + pub(super) type Dummy = StorageValue<_, u32>; + + + // Pallets use events to inform users when important changes are made. + // https://substrate.dev/docs/en/knowledgebase/runtime/events + #[pallet::event] + #[pallet::metadata(T::AccountId = "AccountId")] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + /// Event documentation should end with an array that provides descriptive names for event + /// parameters. [something, who] + SomethingStored(u32, T::AccountId), + AccumulateDummy(u32), + SetDummy(u32), + } + + // Errors inform users that something went wrong. + #[pallet::error] + pub enum Error { + /// Error names should be descriptive. + NoneValue, + /// Errors should have helpful documentation associated with them. + StorageOverflow, + } + + // Dispatchable functions allows users to interact with the pallet and invoke state changes. + // These functions materialize as "extrinsics", which are often compared to transactions. + // Dispatchable functions must be annotated with a weight and must return a DispatchResult. + #[pallet::call] + impl Pallet { + /// An example dispatchable that takes a singles value as a parameter, writes the value to + /// storage and emits an event. This function must be dispatched by a signed extrinsic. + #[pallet::weight(T::WeightInfo::do_something(* something))] + pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { + // Check that the extrinsic was signed and get the signer. + // This function will return an error if the extrinsic is not signed. + // https://substrate.dev/docs/en/knowledgebase/runtime/origin + let who = ensure_signed(origin)?; + + // Update storage. + >::put(something); + + // Emit an event. + Self::deposit_event(Event::SomethingStored(something, who)); + // Return a successful DispatchResultWithPostInfo + Ok(()) + } + + /// An example dispatchable that may throw a custom error. + #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1, 1))] + pub fn cause_error(origin: OriginFor) -> DispatchResult { + let _who = ensure_signed(origin)?; + + // Read a value from storage. + match >::get() { + // Return an error if the value has not been set. + None => Err(Error::::NoneValue)?, + Some(old) => { + // Increment the value read from storage; will error in the event of overflow. + let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; + // Update the value in storage with the incremented result. + >::put(new); + Ok(()) + } + } + } + + + #[pallet::weight(T::WeightInfo::set_dummy_benchmark(* new_value))] + pub fn set_dummy( + origin: OriginFor, + #[pallet::compact] new_value: u32, + ) -> DispatchResult { + let _sender = ensure_signed(origin)?; + + // Print out log or debug message in the console via log::{error, warn, info, debug, + // trace}, accepting format strings similar to `println!`. + // https://paritytech.github.io/substrate/master/sp_io/logging/fn.log.html + // https://paritytech.github.io/substrate/master/frame_support/constant.LOG_TARGET.html + + // Put the new value into storage. + >::put(new_value); + + Self::deposit_event(Event::SetDummy(new_value)); + + // All good, no refund. + Ok(()) + } + + + #[pallet::weight(T::WeightInfo::accumulate_dummy(* increase_by))] + pub fn accumulate_dummy(origin: OriginFor, increase_by: u32) -> DispatchResult { + // This is a public call, so we ensure that the origin is some signed account. + let _sender = ensure_signed(origin)?; + + // Read the value of dummy from storage. + // let dummy = Self::dummy(); + // Will also work Using the `::get` on the storage item type itself: + // let dummy = >::get(); + + // Calculate the new value. + // let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); + + // Put the new value into storage. + // >::put(new_dummy); + // Will also work with a reference: + // >::put(&new_dummy); + + // Here's the new one of read and then modify the value. + >::mutate(|dummy| { + // Using `saturating_add` instead of a regular `+` to avoid overflowing + let new_dummy = dummy.map_or(increase_by, |d| d.saturating_add(increase_by)); + *dummy = Some(new_dummy); + }); + + // Let's deposit an event to let the outside world know this happened. + Self::deposit_event(Event::AccumulateDummy(increase_by)); + + // All good, no refund. + Ok(()) + } + } +} + diff --git a/pallets/template/src/mock.rs b/pallets/template/src/mock.rs new file mode 100644 index 0000000000..8719bcb4df --- /dev/null +++ b/pallets/template/src/mock.rs @@ -0,0 +1,62 @@ +use crate as pallet_template; +use sp_core::H256; +use frame_support::parameter_types; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, testing::Header, +}; +use frame_system as system; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + TemplateModule: pallet_template::{Pallet, Call, Storage, Event}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +impl system::Config for Test { + type BaseCallFilter = (); + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); +} + +impl pallet_template::Config for Test { + type Event = Event; +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + system::GenesisConfig::default().build_storage::().unwrap().into() +} diff --git a/pallets/template/src/tests.rs b/pallets/template/src/tests.rs new file mode 100644 index 0000000000..3356b29ff3 --- /dev/null +++ b/pallets/template/src/tests.rs @@ -0,0 +1,23 @@ +use crate::{Error, mock::*}; +use frame_support::{assert_ok, assert_noop}; + +#[test] +fn it_works_for_default_value() { + new_test_ext().execute_with(|| { + // Dispatch a signed extrinsic. + assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); + // Read pallet storage and assert an expected result. + assert_eq!(TemplateModule::something(), Some(42)); + }); +} + +#[test] +fn correct_error_for_none_value() { + new_test_ext().execute_with(|| { + // Ensure the expected error is thrown when no value is present. + assert_noop!( + TemplateModule::cause_error(Origin::signed(1)), + Error::::NoneValue + ); + }); +} diff --git a/pallets/template/src/weights.rs b/pallets/template/src/weights.rs new file mode 100644 index 0000000000..c5c0b45410 --- /dev/null +++ b/pallets/template/src/weights.rs @@ -0,0 +1,99 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_template +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 +//! DATE: 2021-11-15, STEPS: `[20, ]`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// ./target/release/node-template +// benchmark +// --chain +// dev +// --execution +// wasm +// --wasm-execution +// compiled +// --pallet +// pallet_template +// --extrinsic +// * +// --steps +// 20 +// --repeat +// 10 +// --raw +// --output +// ./pallets/template/src/weights.rs +// --template +// ./.maintain/frame-weight-template.hbs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_core::sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_template. +pub trait WeightInfo { + fn do_something(s: u32, ) -> Weight; + fn set_dummy_benchmark(b: u32, ) -> Weight; + fn accumulate_dummy(b: u32, ) -> Weight; +} + +/// Weights for pallet_template Using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn do_something(_s: u32, ) -> Weight { + (14_738_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn set_dummy_benchmark(_b: u32, ) -> Weight { + (12_979_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn accumulate_dummy(b: u32, ) -> Weight { + (15_725_000 as Weight) + // Standard Error: 2_000 + .saturating_add((4_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn do_something(_s: u32, ) -> Weight { + (14_738_000 as Weight) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn set_dummy_benchmark(_b: u32, ) -> Weight { + (12_979_000 as Weight) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn accumulate_dummy(b: u32, ) -> Weight { + (15_725_000 as Weight) + // Standard Error: 2_000 + .saturating_add((4_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } +} diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml new file mode 100644 index 0000000000..084fdf9964 --- /dev/null +++ b/primitives/Cargo.toml @@ -0,0 +1,78 @@ +[package] +authors = ['Substrate DevHub '] +description = 'FRAME pallet template for defining custom runtime logic.' +edition = '2018' +homepage = 'https://substrate.dev' +license = 'Unlicense' +name = 'ttc-primitives' +readme = 'README.md' +repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' +version = '3.0.0' +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + + +[features] +default = ['std'] +std = [ + 'serde', + 'codec/std', + 'sp-debug-derive/std', + "sp-core/std", + 'frame-system/std', + 'sp-std/std', + 'sp-runtime/std', + "frame-support/std" +] + +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '2.0.0' + +[dependencies.sp-debug-derive] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-system] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-std] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-runtime] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.serde] +optional = true +version = "1.0.101" + +[dependencies.sp-core] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-support] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies] +serde_json = "1.0.59" + + + diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs new file mode 100644 index 0000000000..b2a0796086 --- /dev/null +++ b/primitives/src/constants.rs @@ -0,0 +1,30 @@ +/// Time and blocks. +pub mod time { + use crate::{BlockNumber}; + + /// This determines the average expected block time that we are targeting. + /// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. + /// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked + /// up by `pallet_aura` to implement `fn slot_duration()`. + /// + /// Change this to adjust the block time. + pub const MILLISECS_PER_BLOCK: u64 = 6000; + + // NOTE: Currently it is not possible to change the slot duration after the chain has started. + // Attempting to do so will brick block production. + pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + + // Time is measured by number of blocks. + pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); + pub const HOURS: BlockNumber = MINUTES * 60; + pub const DAYS: BlockNumber = HOURS * 24; + + pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * HOURS; + + pub const EPOCH_DURATION_IN_SLOTS: u64 = { + const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64; + + (EPOCH_DURATION_IN_BLOCKS as f64 * SLOT_FILL_RATE) as u64 + }; + pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); +} diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs new file mode 100644 index 0000000000..d0d20f84ee --- /dev/null +++ b/primitives/src/lib.rs @@ -0,0 +1,32 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod p_resource_order; +pub mod p_provider; +pub mod constants; + +use sp_runtime::{ + traits::{IdentifyAccount, Verify}, + MultiSignature, +}; + +/// An index to a block. +pub type BlockNumber = u32; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Balance of an account. +pub type Balance = u128; + +/// Index of a transaction in the chain. +pub type Index = u32; + +/// A hash of some data used by the chain. +pub type Hash = sp_core::H256; + +/// Counter for the number of eras that have passed. +pub type EraIndex = u32; diff --git a/primitives/src/p_provider.rs b/primitives/src/p_provider.rs new file mode 100644 index 0000000000..00e27daf03 --- /dev/null +++ b/primitives/src/p_provider.rs @@ -0,0 +1,197 @@ +use codec::{Decode, Encode}; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_debug_derive::RuntimeDebug; +use sp_std::vec::Vec; +use frame_support::Parameter; +use sp_runtime::traits::AtLeast32BitUnsigned; + + +/// ComputingResources +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct ComputingResource + where BlockNumber: Parameter + AtLeast32BitUnsigned { + /// computing power resource index + pub index: u64, + /// provider account + pub account_id: AccountId, + /// computing resource link id + pub peer_id: Vec, + /// resource configuration + pub config: ResourceConfig, + /// resource rental statistics + pub rental_statistics: ResourceRentalStatistics, + /// resource rental information + pub rental_info: ResourceRentalInfo, + /// resource lease status + pub status: ResourceStatus, + +} + +impl ComputingResource + where BlockNumber: Parameter + AtLeast32BitUnsigned +{ + pub fn new(index: u64, + account_id: AccountId, + peer_id: Vec, + config: ResourceConfig, + rental_statistics: ResourceRentalStatistics, + rental_info: ResourceRentalInfo, + status: ResourceStatus) -> Self { + ComputingResource { + index, + account_id, + peer_id, + config, + rental_statistics, + rental_info, + status, + } + } + + /// update unit price + pub fn update_resource_price(&mut self, rent_unit_price: u128) { + self.rental_info.set_rent_unit_price(rent_unit_price); + } + + /// increase rental time + pub fn add_resource_duration(&mut self,duration:BlockNumber) { + self.rental_info.rent_duration += duration.clone(); + self.rental_info.end_of_rent += duration; + } + + /// update status + pub fn update_status(&mut self, status: ResourceStatus) { + self.status = status + } +} + + +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum ResourceStatus { + /// using + Inuse, + /// Locked + Locked, + /// Unused + Unused, + /// Disconnected + Offline, +} + + +/// resource configuration +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct ResourceConfig { + pub cpu: u64, + pub memory: u64, + pub system: Vec, + pub cpu_model: Vec, +} + +impl ResourceConfig { + pub fn new(cpu: u64, memory: u64, system: Vec, cpu_model: Vec) -> Self { + Self { + cpu, + memory, + system, + cpu_model, + } + } +} + + +/// resource statistics +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct ResourceRentalStatistics { + /// number of leases + pub rental_count: u32, + /// rental duration + pub rental_duration: u32, + /// number of failures + pub fault_count: u32, + /// failure time + pub fault_duration: u32, +} + +impl ResourceRentalStatistics { + pub fn new( + rental_count: u32, + rental_duration: u32, + fault_count: u32, + fault_duration: u32, + ) -> Self { + ResourceRentalStatistics { + rental_count, + rental_duration, + fault_count, + fault_duration, + } + } + + + /// increase the number of leases + pub fn add_rental_count(&mut self) { + self.rental_count = self.rental_count + 1; + } + + /// increase rental duration + pub fn add_rental_duration(&mut self, rental_duration: u32) { + self.rental_duration = self.rental_duration + rental_duration; + } + + /// increase the number of failures + pub fn add_fault_count(&mut self) { + self.fault_count = self.fault_count + 1; + } + + /// increase failure time + pub fn add_fault_duration(&mut self, fault_duration: u32) { + self.fault_duration = self.fault_duration + fault_duration; + } +} + + +/// resource rental information +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct ResourceRentalInfo { + /// rental unit price + pub rent_unit_price: u128, + /// provide rental time + pub rent_duration: BlockNumber, + /// end rental block + pub end_of_rent: BlockNumber, +} + +impl ResourceRentalInfo { + pub fn new(rent_unit_price: u128, + rent_duration: BlockNumber, + end_of_rent: BlockNumber, + ) -> Self { + ResourceRentalInfo { + rent_unit_price, + rent_duration, + end_of_rent, + } + } + + /// set rental unit price + pub fn set_rent_unit_price(&mut self, rent_unit_price: u128) -> &mut ResourceRentalInfo { + self.rent_unit_price = rent_unit_price; + self + } +} + +pub trait ProviderInterface { + type BlockNumber: Parameter + AtLeast32BitUnsigned; + type AccountId; + + /// get computing resource information + fn get_computing_resource_info(index: u64) -> ComputingResource; + + /// update computing resource information + fn update_computing_resource + (index: u64, resource: ComputingResource); +} + diff --git a/primitives/src/p_resource_order.rs b/primitives/src/p_resource_order.rs new file mode 100644 index 0000000000..21c08f2013 --- /dev/null +++ b/primitives/src/p_resource_order.rs @@ -0,0 +1,339 @@ +use codec::{Decode, Encode}; +use frame_support::Parameter; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_core::Bytes; +use sp_debug_derive::RuntimeDebug; +use sp_runtime::traits::AtLeast32BitUnsigned; +use sp_std::convert::TryInto; +use sp_std::vec::Vec; + +use crate::p_provider::{ComputingResource, ResourceConfig, ResourceRentalInfo}; +use sp_core::sp_std::time::Duration; + +/// resourceOrder +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct ResourceOrder { + /// OrderIdIndex + pub index: u64, + /// TenantInformation + pub tenant_info: TenantInfo, + /// OrderAmount + pub price: u128, + /// ResourceIndex + pub resource_index: u64, + /// BlockAtCreationTime + pub create: BlockNumber, + /// RentalDuration + pub rent_duration: BlockNumber, + /// Timestamp + pub time: Duration, + /// OrderStatus + pub status: OrderStatus, + /// AgreementNumber + pub agreement_index: Option, +} + +/// TenantInformation +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct TenantInfo { + /// TenantInformation + pub account_id: AccountId, + /// RenterPublicKey + pub public_key: Bytes, +} + +/// LeaseAgreement +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct RentalAgreement + where BlockNumber: Parameter + AtLeast32BitUnsigned +{ + /// ProtocolIdIndex + pub index: u64, + /// Lessor + pub provider: AccountId, + /// TenantInformation + pub tenant_info: TenantInfo, + /// ComputingResourceLinkID + pub peer_id: Vec, + /// ResourceIndex + pub resource_index: u64, + /// ResourceConfiguration + pub config: ResourceConfig, + /// ResourceRentalInformation + pub rental_info: ResourceRentalInfo, + /// RentalAmount + pub price: u128, + /// LockedAmount + pub lock_price: u128, + /// PenaltyAmount + pub penalty_amount: u128, + /// ReceiveAmount + pub receive_amount: u128, + /// StartBlock + pub start: BlockNumber, + /// AgreementExpirationBlock + pub end: BlockNumber, + /// ComputingBlock + pub calculation: BlockNumber, + /// Timestamp + pub time: Duration, + /// Status + pub status: AgreementStatus, +} + +/// StakingAmount +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct StakingAmount { + /// StakingAmount + pub amount: u128, + /// ActiveAmount + pub active_amount: u128, + /// LockedAmount + pub lock_amount: u128, +} + + +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum OrderStatus { + /// Pending + Pending, + /// Finished + Finished, + /// Canceled + Canceled, +} + +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum AgreementStatus { + /// Using + Using, + /// Finished + Finished, + /// Punished + Punished, +} + +impl ResourceOrder { + /// CreateANewResourceOrder + pub fn new(index: u64, tenant_info: TenantInfo, price: u128, resource_index: u64, create: BlockNumber, rent_duration: BlockNumber,time:Duration) -> Self { + ResourceOrder { + index, + tenant_info, + price, + resource_index, + create, + rent_duration, + time, + status: OrderStatus::Pending, + agreement_index: None + } + } + + /// CreateARenewalOrder + pub fn renew(index: u64, tenant_info: TenantInfo, price: u128, resource_index: u64, create: BlockNumber, rent_duration: BlockNumber,time:Duration,agreement_index:Option) -> Self { + ResourceOrder { + index, + tenant_info, + price, + resource_index, + create, + rent_duration, + time, + status: OrderStatus::Pending, + agreement_index, + } + } + + /// WhetherItIsARenewalOrder + pub fn is_renew_order(self) -> bool{ + match self.agreement_index { + Some(_) => true, + None => false + } + } + + /// OrderCompleted + pub fn finish_order(&mut self) { self.status = OrderStatus::Finished } + + /// CancelOrder + pub fn cancel_order(&mut self) { self.status = OrderStatus::Canceled } +} + +impl RentalAgreement + where BlockNumber: Parameter + AtLeast32BitUnsigned +{ + pub fn new(index: u64, provider: AccountId, tenant_info: TenantInfo, peer_id: Vec, resource_index: u64, config: ResourceConfig, rental_info: ResourceRentalInfo, price: u128, lock_price: u128, penalty_amount: u128, receive_amount: u128, start: BlockNumber, end: BlockNumber, calculation: BlockNumber,time:Duration) -> Self { + RentalAgreement { + index, + provider, + tenant_info, + peer_id, + resource_index, + config, + rental_info, + price, + lock_price, + penalty_amount, + receive_amount, + start, + end, + calculation, + time, + status: AgreementStatus::Using + } + } + + /// ExecuteTheAgreement + pub fn execution(&mut self, block_number: &BlockNumber) -> bool { + // determine whether the agreement is punished + if self.status != AgreementStatus::Using { + return false + } + + // get order duration + let duration = TryInto::::try_into(self.end.clone() - self.start.clone()).ok().unwrap(); + //if the current block protocol has not ended + if block_number < &self.end { + // (The current block - the last reported block) The total block duration of the protocol Order Amount = Amount obtained during this period + let this_block = block_number.clone() - self.calculation.clone(); + // calculate the number of blocks + let this_block = TryInto::::try_into(this_block).ok().unwrap(); + // calculate the amount earned during this period + let price = (this_block * self.price.clone()) / duration; + + self.lock_price = self.lock_price - price; + self.receive_amount = self.receive_amount + price; + self.calculation = block_number.clone(); + } else { + // end of current agreement + self.receive_amount += self.lock_price; + self.lock_price = 0; + self.calculation = self.end.clone(); + } + + true + } + + /// FaultExecutionProtocol + pub fn fault_excution(&mut self) -> u128{ + // get the remaining amount of the order + let price = self.lock_price; + + // Transfer all the locked amount to the penalty amount + self.penalty_amount += self.lock_price; + // the locked amount is set to 0 + self.lock_price = 0; + + price + } + + /// GetBackTheAmount + pub fn withdraw(&mut self) -> u128{ + let price = self.receive_amount; + self.receive_amount = 0; + price + } + + /// GetBackThePenaltyAmount + pub fn withdraw_penalty(&mut self) -> u128 { + let price = self.penalty_amount; + self.penalty_amount = 0; + price + } + + /// Renewal + pub fn renew(&mut self,price:u128,duration:BlockNumber,resource_config:ComputingResource) { + // negotiated price increase + self.price += price; + self.lock_price += price; + // agreement end deadline increased + self.end += duration; + // update protocol resource snapshot + self.rental_info = resource_config.rental_info; + self.config = resource_config.config; + } + + /// determine whether the agreement is complete + pub fn is_finished(self) -> bool { + if self.status != AgreementStatus::Using && self.lock_price == 0 && self.penalty_amount == 0 && self.receive_amount == 0 { + return true + } + + false + } + + /// change state + pub fn change_status(&mut self,sta:AgreementStatus) { + self.status = sta + } +} + +impl TenantInfo { + pub fn new(account_id: AccountId, public_key: Bytes) -> Self { + TenantInfo { + account_id, + public_key, + } + } +} + +impl StakingAmount { + /// StakingAmount + pub fn staking_amount(&mut self, price: u128) { + self.amount += price; + self.active_amount += price; + } + + /// LockedAmount + pub fn lock_amount(&mut self, price: u128) -> bool { + if self.active_amount < price { + return false; + } + self.active_amount -= price; + self.lock_amount += price; + true + } + + /// UnlockAmount + pub fn unlock_amount(&mut self, price: u128) -> bool { + if self.lock_amount < price { + return false; + } + self.active_amount += price; + self.lock_amount -= price; + + true + } + + /// GetBackTheAmount + pub fn withdraw_amount(&mut self,price:u128) -> bool { + if self.active_amount < price { + return false; + } + + self.amount -= price; + self.active_amount -= price; + true + } + + /// PenaltyAmount + pub fn penalty_amount(&mut self, price:u128) { + self.amount -= price; + self.active_amount = self.active_amount + self.lock_amount - price; + self.lock_amount = 0 ; + } +} + + +pub trait OrderInterface { + type AccountId; + type BlockNumber: Parameter + AtLeast32BitUnsigned; + /// get computing resource information + fn get_computing_resource_info(index: u64) -> Option> ; + + /// update resource interface + fn update_computing_resource(index: u64, resource_info: ComputingResource); +} diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml new file mode 100644 index 0000000000..747f61fa2b --- /dev/null +++ b/runtime/Cargo.toml @@ -0,0 +1,325 @@ +[build-dependencies.substrate-wasm-builder] +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '4.0.0' + +[package] +authors = ['Substrate DevHub '] +edition = '2018' +homepage = 'https://substrate.dev' +license = 'Unlicense' +name = 'node-template-runtime' +repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' +version = '3.0.0' +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + +[features] +default = ['std'] +runtime-benchmarks = [ + 'frame-benchmarking', + 'frame-support/runtime-benchmarks', + 'frame-system-benchmarking', + 'frame-system/runtime-benchmarks', + 'hex-literal', + 'pallet-balances/runtime-benchmarks', + 'pallet-template/runtime-benchmarks', + 'pallet-timestamp/runtime-benchmarks', + 'pallet-resource-order/runtime-benchmarks', + 'sp-runtime/runtime-benchmarks', +] +std = [ + "sp-authority-discovery/std", + "pallet-authority-discovery/std", + "pallet-authorship/std", + "sp-consensus-babe/std", + "pallet-babe/std", + "pallet-balances/std", + "sp-block-builder/std", + "codec/std", + "frame-executive/std", + "pallet-grandpa/std", + "sp-inherents/std", + "sp-offchain/std", + "sp-core/std", + "pallet-randomness-collective-flip/std", + "sp-std/std", + "pallet-session/std", + "sp-api/std", + "sp-runtime/std", + "sp-staking/std", + "pallet-staking/std", + "sp-session/std", + "pallet-sudo/std", + "frame-support/std", + "frame-benchmarking/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "pallet-election-provider-multi-phase/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-npos-elections/std", + "pallet-offences/std", + "pallet-scheduler/std", + "pallet-utility/std", + "pallet-resource-order/std", + "pallet-provider/std" +] +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '2.0.0' + +[dependencies.frame-benchmarking] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +optional = true +tag = 'monthly-2021-07' +version = '3.1.0' + +[dependencies.frame-executive] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-support] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-system] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-system-benchmarking] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +optional = true +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-system-rpc-runtime-api] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.hex-literal] +optional = true +version = '0.3.1' + +[dependencies.pallet-babe] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-balances] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-grandpa] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.1.0' + +[dependencies.pallet-randomness-collective-flip] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-sudo] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-template] +default-features = false +path = '../pallets/template' +version = '3.0.0' + +[dependencies.pallet-timestamp] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-transaction-payment] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-transaction-payment-rpc-runtime-api] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-api] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-block-builder] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-consensus-babe] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '0.9.0' + +[dependencies.sp-core] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-inherents] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-offchain] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-runtime] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-session] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-std] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-transaction-pool] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-version] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-staking] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-staking-reward-curve] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-session] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + + +[dependencies.pallet-staking] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.frame-election-provider-support] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-election-provider-multi-phase] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-npos-elections] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.sp-authority-discovery] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-authority-discovery] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-authorship] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-offences] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-scheduler] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-utility] +default-features = false +git = 'https://gitee.com/mohaijiang/substrate.git' +tag = 'monthly-2021-07' +version = '3.0.0' + +[dependencies.pallet-resource-order] +default-features = false +path = '../pallets/resource-order' +version = '3.0.0' + +[dependencies.pallet-provider] +default-features = false +path = '../pallets/provider' +version = '3.0.0' \ No newline at end of file diff --git a/runtime/build.rs b/runtime/build.rs new file mode 100644 index 0000000000..9b53d2457d --- /dev/null +++ b/runtime/build.rs @@ -0,0 +1,9 @@ +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs new file mode 100644 index 0000000000..6b45882eb1 --- /dev/null +++ b/runtime/src/lib.rs @@ -0,0 +1,880 @@ +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit="256"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use sp_std::prelude::*; +use sp_core::{ + crypto::KeyTypeId, + OpaqueMetadata, +}; +use sp_runtime::{ + ApplyExtrinsicResult, generic, create_runtime_str, impl_opaque_keys, MultiSignature, + transaction_validity::{TransactionValidity, TransactionSource, TransactionPriority}, +}; +use sp_runtime::traits::{ + BlakeTwo256, Block as BlockT, AccountIdLookup, Verify, IdentifyAccount, NumberFor, + OpaqueKeys,ConvertInto +}; +use sp_api::impl_runtime_apis; +use sp_consensus_babe; +use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; +use pallet_grandpa::fg_primitives; +use sp_version::RuntimeVersion; +#[cfg(feature = "std")] +use sp_version::NativeVersion; + +// A few exports that help ease life for downstream crates. +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; +pub use pallet_timestamp::Call as TimestampCall; +pub use pallet_balances::Call as BalancesCall; +pub use pallet_balances; +pub use sp_runtime::{Permill, Perbill}; +pub use frame_support::{ + construct_runtime, parameter_types, StorageValue, + traits::{KeyOwnerProofSystem, Randomness,Currency, Imbalance, OnUnbalanced, LockIdentifier, + U128CurrencyToVote, MaxEncodedLen,}, + weights::{ + Weight, IdentityFee, + constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, + DispatchClass, + }, + debug,RuntimeDebug, +}; +use pallet_transaction_payment::CurrencyAdapter; +use sp_runtime::curve::PiecewiseLinear; +use pallet_session::{historical as pallet_session_historical}; +pub use pallet_staking::StakerStatus; +use frame_election_provider_support::onchain; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, +}; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; + + +/// Import the template pallet. +pub use pallet_template; + +use pallet_authority_discovery; + +/// An index to a block. +pub type BlockNumber = u32; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Balance of an account. +pub type Balance = u128; + +/// Index of a transaction in the chain. +pub type Index = u32; + +/// A hash of some data used by the chain. +pub type Hash = sp_core::H256; + +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core data structures. +pub mod opaque { + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + + /// Opaque block header type. + pub type Header = generic::Header; + /// Opaque block type. + pub type Block = generic::Block; + /// Opaque block identifier type. + pub type BlockId = generic::BlockId; + + impl_opaque_keys! { + pub struct SessionKeys { + pub babe: Babe, + pub grandpa: Grandpa, + pub authority_discovery: AuthorityDiscovery, + } + } +} +/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. +/// This is used to limit the maximal weight of a single extrinsic. +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); +/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used +/// by Operational extrinsics. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +/// We allow for 2 seconds of compute with a 6 second average block time. +const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND; + +pub mod currency { + use super::Balance; + pub const TTC: Balance = 1_000_000_000_000; //10^12 + pub const DOLLARS: Balance = TTC; + pub const CENTS: Balance = TTC / 100; //10^10 + pub const MILLICENTS: Balance = CENTS / 1_000; //10^7 + + + pub const MILLI: Balance = TTC / 1000; //10^9 + pub const MICRO: Balance = MILLI / 1000; //10^6 + pub const NANO: Balance = MICRO / 1000; //10^3 + pub const PICO: Balance = 1; //1 +} +pub use currency::*; +// To learn more about runtime versioning and what each of the following value means: +// https://substrate.dev/docs/en/knowledgebase/runtime/upgrades#runtime-versioning +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("node-template"), + impl_name: create_runtime_str!("node-template"), + authoring_version: 1, + // The version of the runtime specification. A full node will not attempt to use its native + // runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`, + // `spec_version`, and `authoring_version` are the same between Wasm and native. + // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use + // the compatible custom types. + spec_version: 102, + impl_version: 1, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, +}; + +/// This determines the average expected block time that we are targeting. +/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. +/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked +/// up by `pallet_aura` to implement `fn slot_duration()`. +/// +/// Change this to adjust the block time. +pub const MILLISECS_PER_BLOCK: u64 = 6000; + +// NOTE: Currently it is not possible to change the slot duration after the chain has started. +// Attempting to do so will brick block production. +pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + +// Time is measured by number of blocks. +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + + + +parameter_types! { + pub const BlockHashCount: BlockNumber = 2400; + pub const Version: RuntimeVersion = VERSION; + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + // Operational transactions have some extra reserved space, so that they + // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); + + pub const SS58Prefix: u16 = 42; +} + +// Configure FRAME pallets to include in runtime. + +impl frame_system::Config for Runtime { + /// The basic call filter to use in dispatchable. + type BaseCallFilter = (); + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = RuntimeBlockLength; + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type Call = Call; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = AccountIdLookup; + /// The index type for storing how many extrinsics an account has signed. + type Index = Index; + /// The index type for blocks. + type BlockNumber = BlockNumber; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The header type. + type Header = generic::Header; + /// The ubiquitous event type. + type Event = Event; + /// The ubiquitous origin type. + type Origin = Origin; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; + /// Version of the runtime. + type Version = Version; + /// Converts a module to the index of the module in `construct_runtime!`. + /// + /// This type is being generated by `construct_runtime!`. + type PalletInfo = PalletInfo; + /// What to do if a new account is created. + type OnNewAccount = (); + /// What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = SS58Prefix; + /// The set code logic, just the default since we're not a parachain. + type OnSetCode = (); +} + +impl pallet_utility::Config for Runtime { + type Event = Event; + type Call = Call; + type WeightInfo = pallet_utility::weights::SubstrateWeight; +} + +impl pallet_randomness_collective_flip::Config for Runtime {} + +// impl pallet_aura::Config for Runtime { +// type AuthorityId = AuraId; +// } + +pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; +pub const EPOCH_DURATION_IN_SLOTS: u64 = { + const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64; + + (EPOCH_DURATION_IN_BLOCKS as f64 * SLOT_FILL_RATE) as u64 +}; +pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); +pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration = + sp_consensus_babe::BabeEpochConfiguration { + c: PRIMARY_PROBABILITY, + allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots + }; + +parameter_types! { + pub const EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS; + pub const ExpectedBlockTime: u64 = MILLISECS_PER_BLOCK; +} + +impl pallet_babe::Config for Runtime { + type EpochDuration = EpochDuration; + type ExpectedBlockTime = ExpectedBlockTime; + type EpochChangeTrigger = pallet_babe::ExternalTrigger; + + type KeyOwnerProofSystem = Historical; + + type KeyOwnerProof = >::Proof; + + type KeyOwnerIdentification = >::IdentificationTuple; + + type HandleEquivocation = (); + + type WeightInfo = (); + +} + +impl pallet_grandpa::Config for Runtime { + type Event = Event; + type Call = Call; + + type KeyOwnerProofSystem = Historical; + + type KeyOwnerProof = + >::Proof; + + type KeyOwnerIdentification = >::IdentificationTuple; + + type HandleEquivocation = (); + + type WeightInfo = (); +} + +parameter_types! { + pub const MinimumPeriod: u64 = SLOT_DURATION / 2; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = Babe; + type MinimumPeriod = MinimumPeriod; + type WeightInfo = pallet_timestamp::weights::SubstrateWeight; +} + +parameter_types! { + pub const ExistentialDeposit: u128 = 500; + pub const MaxLocks: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight; +} + +parameter_types! { + pub const TransactionByteFee: Balance = 1; +} + +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = CurrencyAdapter; + type TransactionByteFee = TransactionByteFee; + type WeightToFee = IdentityFee; + type FeeMultiplierUpdate = (); +} + +impl pallet_sudo::Config for Runtime { + type Event = Event; + type Call = Call; +} + +/// Configure the pallet-template in pallets/template. +impl pallet_template::Config for Runtime { + type Event = Event; + type WeightInfo = pallet_template::SubstrateWeight; + type BlockNumberToNumber = ConvertInto; +} + +parameter_types! { + pub const UncleGenerations: BlockNumber = 5; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * + RuntimeBlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 50; +} + +/// scheduler Runtime config +impl pallet_scheduler::Config for Runtime { + type Event = Event; + type Origin = Origin; + type PalletsOrigin = OriginCaller; + type Call = Call; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type WeightInfo = pallet_scheduler::weights::SubstrateWeight; +} + +/// authorship Runtime config +impl pallet_authorship::Config for Runtime { + type FindAuthor = pallet_session::FindAccountFromAuthorIndex; + type UncleGenerations = UncleGenerations; + type FilterUncle = (); + type EventHandler = Staking; +} + +parameter_types! { + pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17); +} + +///session Runtime config +impl pallet_session::Config for Runtime { + type Event = Event; + type ValidatorId = ::AccountId; + type ValidatorIdOf = pallet_staking::StashOf; + type ShouldEndSession = Babe; + type NextSessionRotation = Babe; + type SessionManager = pallet_session::historical::NoteHistoricalRoot; + type SessionHandler = ::KeyTypeIdProviders; + type Keys = opaque::SessionKeys; + type DisabledValidatorsThreshold = DisabledValidatorsThreshold; + type WeightInfo = pallet_session::weights::SubstrateWeight; +} + +impl pallet_session::historical::Config for Runtime { + type FullIdentification = pallet_staking::Exposure; + type FullIdentificationOf = pallet_staking::ExposureOf; +} + +pallet_staking_reward_curve::build! { + const REWARD_CURVE: PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + + +parameter_types! { + /// We prioritize im-online heartbeats over election solution submission. + pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime where + Call: From, +{ + type Extrinsic = UncheckedExtrinsic; + type OverarchingCall = Call; +} + +parameter_types! { + pub const SessionsPerEra: sp_staking::SessionIndex = 6; + pub const BondingDuration: pallet_staking::EraIndex = 24 * 28; + pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. + pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; + pub const MaxNominatorRewardedPerValidator: u32 = 256; + pub OffchainRepeat: BlockNumber = 5; +} + +/// staking Runtime config +impl pallet_staking::Config for Runtime { + const MAX_NOMINATIONS: u32 = 30; + type Currency = Balances; + type UnixTime = Timestamp; + type CurrencyToVote = U128CurrencyToVote; + type RewardRemainder = (); + type Event = Event; + type Slash = (); + type Reward = (); // rewards are minted from the void + type SessionsPerEra = SessionsPerEra; + type BondingDuration = BondingDuration; + type SlashDeferDuration = SlashDeferDuration; + /// A super-majority of the council can cancel the slash. + type SlashCancelOrigin = frame_system::EnsureRoot; + type SessionInterface = Self; + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = Session; + type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type ElectionProvider = ElectionProviderMultiPhase; + type WeightInfo = pallet_staking::weights::SubstrateWeight; + type GenesisElectionProvider = onchain::OnChainSequentialPhragmen< + pallet_election_provider_multi_phase::OnChainConfig, + >; +} + +parameter_types! { + // phase durations. 1/4 of the last session for each. + pub const SignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 4; + pub const UnsignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 4; + + // signed config + pub const SignedMaxSubmissions: u32 = 10; + pub const SignedRewardBase: Balance = 100 * DOLLARS; + pub const SignedDepositBase: Balance = 100 * DOLLARS; + pub const SignedDepositByte: Balance = 1 * DOLLARS; + + // fallback: no on-chain fallback. + pub const Fallback: pallet_election_provider_multi_phase::FallbackStrategy = + pallet_election_provider_multi_phase::FallbackStrategy::OnChain; + + pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(1u32, 10_000); + + // miner configs + pub const MultiPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64; + pub const MinerMaxIterations: u32 = 10; + pub MinerMaxWeight: Weight = RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_extrinsic.expect("Normal extrinsics have a weight limit configured; qed") + .saturating_sub(BlockExecutionWeight::get()); + // Solution can occupy 90% of normal block size + pub MinerMaxLength: u32 = Perbill::from_rational(9u32, 10) * + *RuntimeBlockLength::get() + .max + .get(DispatchClass::Normal); +} + +sp_npos_elections::generate_solution_type!( + #[compact] + pub struct NposCompactSolution16::< + VoterIndex = u32, + TargetIndex = u16, + Accuracy = sp_runtime::PerU16, + >(16) +); + +pub const MAX_NOMINATIONS: u32 = + ::LIMIT as u32; + +///election_provider_multi_phase Runtime config +impl pallet_election_provider_multi_phase::Config for Runtime { + type Event = Event; + type Currency = Balances; + type SignedPhase = SignedPhase; + type UnsignedPhase = UnsignedPhase; + type SolutionImprovementThreshold = SolutionImprovementThreshold; + type OffchainRepeat = OffchainRepeat; + type MinerMaxIterations = MinerMaxIterations; + type MinerMaxWeight = MinerMaxWeight; + type MinerMaxLength = MinerMaxLength; + type MinerTxPriority = MultiPhaseUnsignedPriority; + type SignedMaxSubmissions = SignedMaxSubmissions; + type SignedRewardBase = SignedRewardBase; + type SignedDepositBase = SignedDepositBase; + type SignedDepositByte = SignedDepositByte; + type SignedDepositWeight = (); + type SignedMaxWeight = MinerMaxWeight; + type SlashHandler = (); // burn slashes + type RewardHandler = (); // nothing to do upon rewards + type DataProvider = Staking; + type OnChainAccuracy = Perbill; + type CompactSolution = NposCompactSolution16; + type Fallback = Fallback; + type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; + type ForceOrigin = frame_system::EnsureRoot; + type BenchmarkingConfig = (); +} + +///authority discovery Runtime config +impl pallet_authority_discovery::Config for Runtime {} + +parameter_types! { + // polling interval + pub const ResourceInterval: BlockNumber = 3 * HOURS; + // health check interval + pub const HealthCheckInterval: BlockNumber = 10 * MINUTES; +} + +/// ResourceOrder +impl pallet_resource_order::Config for Runtime{ + type Event = Event; + type Currency = Balances; + type OrderInterface = Provider; + type BlockNumberToNumber = ConvertInto; + type NumberToBalance = ConvertInto; + type BalanceToNumber = ConvertInto; + type HealthCheckInterval = HealthCheckInterval; + type UnixTime = Timestamp; +} + +impl pallet_provider::Config for Runtime { + type Event = Event; + type Currency = Balances; + type BalanceToNumber = ConvertInto; + type ResourceInterval = ResourceInterval; +} + +parameter_types! { + pub const OrderWaitingTime: BlockNumber = 30 * MINUTES; +} + +// Create the runtime by composing the FRAME pallets that were previously configured. +construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = opaque::Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Utility: pallet_utility::{Pallet, Call, Event}, + RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + //Aura: pallet_aura::{Pallet, Config}, + Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event}, + // Include the custom logic from the pallet-template in the runtime. + TemplateModule: pallet_template::{Pallet, Call, Storage, Event}, + Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned}, + Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + Historical: pallet_session_historical::{Pallet}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, + ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event, ValidateUnsigned}, + AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config}, + Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, + Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event}, + ResourceOrder: pallet_resource_order::{Pallet, Call, Storage, Event}, + Provider: pallet_provider::{Pallet, Call, Storage, Event}, + + + } +); + +/// The address format for describing accounts. +pub type Address = sp_runtime::MultiAddress; +/// Block header type as expected by this runtime. +pub type Header = generic::Header; +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPallets, +>; + +impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block); + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + Runtime::metadata().into() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: sp_inherents::InherentData, + ) -> sp_inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + // impl sp_consensus_aura::AuraApi for Runtime { + // fn slot_duration() -> sp_consensus_aura::SlotDuration { + // sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) + // } + // + // fn authorities() -> Vec { + // Aura::authorities() + // } + // } + impl sp_authority_discovery::AuthorityDiscoveryApi for Runtime { + fn authorities() -> Vec { + AuthorityDiscovery::authorities() + } + } + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + opaque::SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + opaque::SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl fg_primitives::GrandpaApi for Runtime { + fn grandpa_authorities() -> GrandpaAuthorityList { + Grandpa::grandpa_authorities() + } + + fn submit_report_equivocation_unsigned_extrinsic( + _equivocation_proof: fg_primitives::EquivocationProof< + ::Hash, + NumberFor, + >, + _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, + ) -> Option<()> { + None + } + + fn generate_key_ownership_proof( + _set_id: fg_primitives::SetId, + _authority_id: GrandpaId, + ) -> Option { + // NOTE: this is the only implementation possible since we've + // defined our key owner proof type as a bottom type (i.e. a type + // with no values). + None + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime {} + + let whitelist: Vec = vec![ + // Block Number + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), + // Total Issuance + hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), + // Execution Phase + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), + // Event Count + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), + // System Events + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + + + add_benchmark!(params, batches, frame_system, SystemBench::); + add_benchmark!(params, batches, pallet_balances, Balances); + add_benchmark!(params, batches, pallet_timestamp, Timestamp); + add_benchmark!(params, batches, pallet_template, TemplateModule); + add_benchmark!(params, batches, pallet_resource_order, ResourceOrder); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } + + impl sp_consensus_babe::BabeApi for Runtime { + fn configuration() -> sp_consensus_babe::BabeGenesisConfiguration { + // The choice of `c` parameter (where `1 - c` represents the + // probability of a slot being empty), is done in accordance to the + // slot duration and expected target block time, for safely + // resisting network delays of maximum two seconds. + // + sp_consensus_babe::BabeGenesisConfiguration { + slot_duration: Babe::slot_duration(), + epoch_length: EpochDuration::get(), + c: BABE_GENESIS_EPOCH_CONFIG.c, + genesis_authorities: Babe::authorities(), + randomness: Babe::randomness(), + allowed_slots: BABE_GENESIS_EPOCH_CONFIG.allowed_slots, + } + } + + fn current_epoch_start() -> sp_consensus_babe::Slot { + Babe::current_epoch_start() + } + + fn current_epoch() -> sp_consensus_babe::Epoch { + Babe::current_epoch() + } + + fn next_epoch() -> sp_consensus_babe::Epoch { + Babe::next_epoch() + } + + fn generate_key_ownership_proof( + _slot: sp_consensus_babe::Slot, + authority_id: sp_consensus_babe::AuthorityId, + ) -> Option { + use codec::Encode; + Historical::prove((sp_consensus_babe::KEY_TYPE, authority_id)) + .map(|p| p.encode()) + .map(sp_consensus_babe::OpaqueKeyOwnershipProof::new) + } + + fn submit_report_equivocation_unsigned_extrinsic( + equivocation_proof: sp_consensus_babe::EquivocationProof<::Header>, + key_owner_proof: sp_consensus_babe::OpaqueKeyOwnershipProof, + ) -> Option<()> { + let key_owner_proof = key_owner_proof.decode()?; + + Babe::submit_unsigned_equivocation_report( + equivocation_proof, + key_owner_proof, + ) + } + + } +} diff --git a/scripts/docker_run.sh b/scripts/docker_run.sh new file mode 100644 index 0000000000..53a907178d --- /dev/null +++ b/scripts/docker_run.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# This script is meant to be run on Unix/Linux based systems +set -e + +echo "*** Start Substrate node template ***" + +cd $(dirname ${BASH_SOURCE[0]})/.. + +mkdir -p ./.local + +docker-compose down --remove-orphans +docker-compose run --rm --service-ports dev $@ diff --git a/scripts/init.sh b/scripts/init.sh new file mode 100755 index 0000000000..f976f7235d --- /dev/null +++ b/scripts/init.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# This script is meant to be run on Unix/Linux based systems +set -e + +echo "*** Initializing WASM build environment" + +if [ -z $CI_PROJECT_NAME ] ; then + rustup update nightly + rustup update stable +fi + +rustup target add wasm32-unknown-unknown --toolchain nightly diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000000..9f3f56301d --- /dev/null +++ b/shell.nix @@ -0,0 +1,35 @@ +let + mozillaOverlay = + import (builtins.fetchGit { + url = "https://github.com/mozilla/nixpkgs-mozilla.git"; + rev = "57c8084c7ef41366993909c20491e359bbb90f54"; + }); + pinned = builtins.fetchGit { + # Descriptive name to make the store path easier to identify + url = "https://github.com/nixos/nixpkgs/"; + # Commit hash for nixos-unstable as of 2020-04-26 + # `git ls-remote https://github.com/nixos/nixpkgs nixos-unstable` + ref = "refs/heads/nixos-unstable"; + rev = "1fe6ed37fd9beb92afe90671c0c2a662a03463dd"; + }; + nixpkgs = import pinned { overlays = [ mozillaOverlay ]; }; + toolchain = with nixpkgs; (rustChannelOf { date = "2021-03-01"; channel = "nightly"; }); + rust-wasm = toolchain.rust.override { + targets = [ "wasm32-unknown-unknown" ]; + }; +in +with nixpkgs; pkgs.mkShell { + buildInputs = [ + clang + pkg-config + rust-wasm + ] ++ stdenv.lib.optionals stdenv.isDarwin [ + darwin.apple_sdk.frameworks.Security + ]; + + LIBCLANG_PATH = "${llvmPackages.libclang}/lib"; + PROTOC = "${protobuf}/bin/protoc"; + RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library/"; + ROCKSDB_LIB_DIR = "${rocksdb}/lib"; + +}