mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Merge remote-tracking branch 'origin/master' into gav-xcm-v3
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
---
|
||||
name: Release issue template
|
||||
about: Tracking issue for new releases
|
||||
title: Cumulus {{ env.VERSION }} Release checklist
|
||||
---
|
||||
# Release Checklist
|
||||
|
||||
### Runtime Releases
|
||||
|
||||
These checks should be performed on the codebase.
|
||||
|
||||
- [ ] Verify [`spec_version`](#spec-version) has been incremented since the
|
||||
last release for any native runtimes from any existing use on public
|
||||
(non-private/test) networks.
|
||||
- [ ] Verify previously [completed migrations](#old-migrations-removed) are
|
||||
removed for any public (non-private/test) networks.
|
||||
- No migrations added in the last release that would need to be removed.
|
||||
- [ ] Verify pallet and [extrinsic ordering](#extrinsic-ordering) as well as `SignedExtension`s have stayed
|
||||
the same. Bump `transaction_version` if not.
|
||||
- [ ] Verify new extrinsics have been correctly whitelisted/blacklisted for
|
||||
[proxy filters](#proxy-filtering).
|
||||
- No new extrinsics.
|
||||
- [ ] Verify [benchmarks](#benchmarks) have been updated for any modified
|
||||
runtime logic.
|
||||
- [ ] Verify the weights are up-to-date.
|
||||
- [ ] Verify that the various pieces of XCM config are sane.
|
||||
|
||||
The following checks can be performed after we have forked off to the release-
|
||||
candidate branch or started an additional release candidate branch (rc-2, rc-3, etc)
|
||||
|
||||
- [ ] Verify [new migrations](#new-migrations) complete successfully, and the
|
||||
runtime state is correctly updated for any public (non-private/test)
|
||||
networks.
|
||||
- [ ] Run integration tests.
|
||||
- [ ] Teleport Relay -> Statemin* and back.
|
||||
- [ ] Create asset (if applicable), mint and transfer
|
||||
- [ ] Push runtime upgrade to Westmint and verify network stability.
|
||||
|
||||
|
||||
### All Releases
|
||||
|
||||
- [ ] Check that the new polkadot-collator versions have [run on the network](#burn-in)
|
||||
without issue.
|
||||
- [ ] Check that a draft release has been created at
|
||||
https://github.com/paritytech/cumulus/releases with relevant [release
|
||||
notes](#release-notes).
|
||||
- [ ] Check that [build artifacts](#build-artifacts) have been added to the
|
||||
draft-release.
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
### Burn In
|
||||
|
||||
Ensure that Parity DevOps has run the new release on Westmint and Statemine collators for 12h prior to publishing the release.
|
||||
|
||||
### Build Artifacts
|
||||
|
||||
Add any necessary assets to the release. They should include:
|
||||
|
||||
- Linux binary
|
||||
- GPG signature of the Linux binary
|
||||
- SHA256 of binary
|
||||
- Source code
|
||||
- Wasm binaries of any runtimes
|
||||
|
||||
### Release notes
|
||||
|
||||
The release notes should list:
|
||||
|
||||
- The priority of the release (i.e., how quickly users should upgrade) - this is
|
||||
based on the max priority of any *client* changes.
|
||||
- Which native runtimes and their versions are included
|
||||
- The proposal hashes of the runtimes as built with
|
||||
[srtool](https://github.com/paritytech/srtool)
|
||||
- Any changes in this release that are still awaiting audit
|
||||
|
||||
The release notes may also list:
|
||||
|
||||
- Free text at the beginning of the notes mentioning anything important
|
||||
regarding this release
|
||||
- Notable changes separated into sections.
|
||||
|
||||
### Spec Version
|
||||
|
||||
A runtime upgrade must bump the spec number. This may follow a pattern with the
|
||||
client release (e.g. runtime v12 corresponds to v0.8.12, even if the current
|
||||
runtime is not v11).
|
||||
|
||||
### Runtime version bump between RCs
|
||||
|
||||
The clients need to be aware of runtime changes. However, we do not want to bump the
|
||||
`spec_version` for every single release candidate. Instead, we can bump the `impl` field of the version
|
||||
to signal the change to the client.
|
||||
|
||||
### Old Migrations Removed
|
||||
|
||||
Previous `on_runtime_upgrade` functions from old upgrades should be removed.
|
||||
|
||||
### New Migrations
|
||||
|
||||
Ensure that any migrations that are required due to storage or logic changes
|
||||
are included in the `on_runtime_upgrade` function of the appropriate pallets.
|
||||
|
||||
### Extrinsic Ordering & Storage
|
||||
|
||||
Offline signing libraries depend on a consistent ordering of call indices and
|
||||
functions. Compare the metadata of the current and new runtimes and ensure that
|
||||
the `module index, call index` tuples map to the same set of functions. It also checks if there have been any changes in `storage`. In case of a breaking change, increase `transaction_version`.
|
||||
|
||||
To verify the order has not changed, manually start the following [Github Action](https://github.com/paritytech/cumulus/actions/workflows/extrinsic-ordering-check-from-bin.yml). It takes around a minute to run and will produce the report as artifact you need to manually check.
|
||||
|
||||
To run it, in the _Run Workflow_ dropdown:
|
||||
1. **Use workflow from**: to ignore, leave `master` as default
|
||||
2. **The WebSocket url of the reference node**:
|
||||
- Statemine: `wss://kusama-statemine-rpc.paritytech.net`
|
||||
- Westmint: `wss://westmint-rpc.polkadot.io`
|
||||
3. **A url to a Linux binary for the node containing the runtime to test**: Paste the URL of the latest release-candidate binary from the draft-release on Github. The binary has to previously be uploaded to S3 (Github url link to the binary is constantly changing)
|
||||
- https://releases.parity.io/cumulus/statemine-v6.0.0-rc1/polkadot-collator
|
||||
4. **The name of the chain under test. Usually, you would pass a local chain**:
|
||||
- Statemine: `statemine-local`
|
||||
- Westmint: `westmint-local`
|
||||
5. Click **Run workflow**
|
||||
|
||||
When the workflow is done, click on it and download the zip artifact, inside you'll find an `output.txt` file. The things to look for in the output are lines like:
|
||||
|
||||
- `[Identity] idx 28 -> 25 (calls 15)` - indicates the index for Identity has changed
|
||||
- `[+] Society, Recovery` - indicates the new version includes 2 additional modules/pallets.
|
||||
- If no indices have changed, every modules line should look something like `[Identity] idx 25 (calls 15)`
|
||||
|
||||
**Note**: Adding new functions to the runtime does not constitute a breaking change
|
||||
as long as the indexes did not change.
|
||||
|
||||
**Note**: Extrinsic function signatures changes (adding/removing & ordering arguments) are not caught by the job, so those changes should be reviewed "manually"
|
||||
|
||||
### Proxy Filtering
|
||||
|
||||
The runtime contains proxy filters that map proxy types to allowable calls. If
|
||||
the new runtime contains any new calls, verify that the proxy filters are up to
|
||||
date to include them.
|
||||
|
||||
### Benchmarks
|
||||
|
||||
Until #631 is done, running the benchmarks is a manual process:
|
||||
1. Connect to the bechmarking machine
|
||||
2. Make sure no one else is using the machine with `htop check`
|
||||
3. Pull in the branch of Cumulus that has the version of Statemine you want to release
|
||||
4. Recompile `cargo build --release --features runtime-benchmarks`
|
||||
5. From the root directory run `nohup ./scripts/benchmarks.sh &` (it will take quite a few hours)
|
||||
6. Checkout in your local machine to the branch of cumulus that has the version of Statemine you want to release
|
||||
7. `scp` from the host to your local machine the weights for Statemine, Westmint and Statemint you'll find in:
|
||||
- `/polkadot-parachains/statemine/src/weights`
|
||||
- `/polkadot-parachains/westmint/src/weights`
|
||||
- `/polkadot-parachains/statemint/src/weights`
|
||||
8. Commit the changes in your local and create a PR
|
||||
@@ -0,0 +1,23 @@
|
||||
name: Check labels
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled, opened, synchronize, unlabeled]
|
||||
|
||||
jobs:
|
||||
check-labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
- name: Check labels
|
||||
run: bash ${{ github.workspace }}/scripts/github/check_labels.sh
|
||||
env:
|
||||
GITHUB_PR: ${{ github.event.pull_request.number }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
@@ -0,0 +1,63 @@
|
||||
name: Release-candidate automation
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release-**v[0-9]+.[0-9]+.[0-9]+
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
tag_rc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- id: compute_tag
|
||||
name: Compute next rc tag
|
||||
shell: bash
|
||||
run: |
|
||||
# Get last rc tag if exists, else set it to {version}-rc1
|
||||
version=${GITHUB_REF#refs/heads/release-}
|
||||
echo "$version"
|
||||
echo "::set-output name=version::$version"
|
||||
git tag -l
|
||||
last_rc=$(git tag -l "$version-rc*" | sort -V | tail -n 1)
|
||||
if [ -n "$last_rc" ]; then
|
||||
suffix=$(echo "$last_rc" | grep -Eo '[0-9]+$')
|
||||
echo $suffix
|
||||
((suffix++))
|
||||
echo $suffix
|
||||
echo "::set-output name=new_tag::$version-rc$suffix"
|
||||
echo "::set-output name=first_rc::false"
|
||||
else
|
||||
echo "::set-output name=new_tag::$version-rc1"
|
||||
echo "::set-output name=first_rc::true"
|
||||
fi
|
||||
- name: Apply new tag
|
||||
uses: tvdias/github-tagger@v0.0.2
|
||||
with:
|
||||
# We can't use the normal GITHUB_TOKEN for the following reason:
|
||||
# https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token
|
||||
# RELEASE_BRANCH_TOKEN requires public_repo OAuth scope
|
||||
repo-token: "${{ secrets.RELEASE_BRANCH_TOKEN }}"
|
||||
tag: ${{ steps.compute_tag.outputs.new_tag }}
|
||||
- id: create-issue
|
||||
uses: JasonEtco/create-an-issue@v2
|
||||
# Only create the issue if it's the first release candidate
|
||||
if: steps.compute_tag.outputs.first_rc == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION: ${{ steps.compute_tag.outputs.version }}
|
||||
with:
|
||||
filename: .github/ISSUE_TEMPLATE/release.md
|
||||
- name: Send Matrix message
|
||||
uses: s3krit/matrix-message-action@v0.0.3
|
||||
if: steps.create-issue.outputs.url != ''
|
||||
with:
|
||||
room_id: ${{ secrets.INTERNAL_CUMULUS_MATRIX_ROOM_ID }}
|
||||
access_token: ${{ secrets.MATRIX_ACCESS_TOKEN }}
|
||||
server: "matrix.parity.io"
|
||||
message: |
|
||||
Release process for Cumulus ${{ steps.compute_tag.outputs.version }} has been started.
|
||||
Tracking issue: ${{ steps.create-issue.outputs.url }}"
|
||||
@@ -0,0 +1,221 @@
|
||||
name: Release - Create draft
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref1:
|
||||
description: The 'from' tag to use for the diff
|
||||
default: statemine-v5.0.0
|
||||
required: true
|
||||
ref2:
|
||||
description: The 'to' tag to use for the diff
|
||||
default: release-statemine-v6
|
||||
required: true
|
||||
pre_release:
|
||||
description: For pre-releases
|
||||
default: "true"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
get-rust-versions:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: paritytech/ci-linux:production
|
||||
outputs:
|
||||
rustc-stable: ${{ steps.get-rust-versions.outputs.stable }}
|
||||
rustc-nightly: ${{ steps.get-rust-versions.outputs.nightly }}
|
||||
steps:
|
||||
- id: get-rust-versions
|
||||
run: |
|
||||
echo "::set-output name=stable::$(rustc +stable --version)"
|
||||
echo "::set-output name=nightly::$(rustc +nightly --version)"
|
||||
|
||||
build-runtimes:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
runtime: ["shell", "statemine", "statemint", "westmint", "rococo-parachain"]
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.ref2 }}
|
||||
|
||||
- name: Cache target dir
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: "${{ github.workspace }}/runtime/${{ matrix.runtime }}/target"
|
||||
key: srtool-target-${{ matrix.runtime }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
srtool-target-${{ matrix.runtime }}-
|
||||
srtool-target-
|
||||
|
||||
- name: Build ${{ matrix.runtime }} runtime
|
||||
id: srtool_build
|
||||
uses: chevdor/srtool-actions@v0.3.0
|
||||
with:
|
||||
image: paritytech/srtool
|
||||
chain: ${{ matrix.runtime }}
|
||||
runtime_dir: polkadot-parachains/${{ matrix.runtime }}
|
||||
|
||||
- name: Store srtool digest to disk
|
||||
run: |
|
||||
echo '${{ steps.srtool_build.outputs.json }}' | \
|
||||
jq > ${{ matrix.runtime }}_srtool_output.json
|
||||
|
||||
- name: Upload ${{ matrix.runtime }} srtool json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.runtime }}-srtool-json
|
||||
path: ${{ matrix.runtime }}_srtool_output.json
|
||||
|
||||
- name: Upload ${{ matrix.runtime }} runtime
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.runtime }}-runtime
|
||||
path: |
|
||||
${{ steps.srtool_build.outputs.wasm_compressed }}
|
||||
|
||||
publish-draft-release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: ["get-rust-versions", "build-runtimes"]
|
||||
outputs:
|
||||
release_url: ${{ steps.create-release.outputs.html_url }}
|
||||
asset_upload_url: ${{ steps.create-release.outputs.upload_url }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
path: cumulus
|
||||
ref: ${{ github.event.inputs.ref2 }}
|
||||
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.0.0
|
||||
|
||||
- name: Download srtool json output
|
||||
uses: actions/download-artifact@v2
|
||||
|
||||
- name: Prepare tooling
|
||||
run: |
|
||||
cd cumulus/scripts/changelog
|
||||
gem install bundler changelogerator
|
||||
bundle install
|
||||
changelogerator --help
|
||||
|
||||
URL=https://github.com/chevdor/tera-cli/releases/download/v0.2.1/tera-cli_linux_amd64.deb
|
||||
wget $URL -O tera.deb
|
||||
sudo dpkg -i tera.deb
|
||||
tera --version
|
||||
|
||||
- name: Generate release notes
|
||||
env:
|
||||
RUSTC_STABLE: ${{ needs.get-rust-versions.outputs.rustc-stable }}
|
||||
RUSTC_NIGHTLY: ${{ needs.get-rust-versions.outputs.rustc-nightly }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NO_CACHE: 1
|
||||
DEBUG: 1
|
||||
SHELL_DIGEST: ${{ github.workspace}}/shell-srtool-json/shell_srtool_output.json
|
||||
WESTMINT_DIGEST: ${{ github.workspace}}/westmint-srtool-json/westmint_srtool_output.json
|
||||
STATEMINE_DIGEST: ${{ github.workspace}}/statemine-srtool-json/statemine_srtool_output.json
|
||||
STATEMINT_DIGEST: ${{ github.workspace}}/statemint-srtool-json/statemint_srtool_output.json
|
||||
ROCOCO_DIGEST: ${{ github.workspace}}/rococo-parachain-srtool-json/rococo-parachain_srtool_output.json
|
||||
REF1: ${{ github.event.inputs.ref1 }}
|
||||
REF2: ${{ github.event.inputs.ref2 }}
|
||||
PRE_RELEASE: ${{ github.event.inputs.pre_release }}
|
||||
HIDE_SRTOOL_ROCOCO: false
|
||||
HIDE_SRTOOL_SHELL: false
|
||||
run: |
|
||||
find ${{env.GITHUB_WORKSPACE}} -type f -name "*_srtool_output.json"
|
||||
ls -al $SHELL_DIGEST
|
||||
ls -al $WESTMINT_DIGEST
|
||||
ls -al $STATEMINE_DIGEST
|
||||
ls -al $STATEMINT_DIGEST
|
||||
ls -al $ROCOCO_DIGEST
|
||||
|
||||
echo "The diff will be computed from $REF1 to $REF2"
|
||||
cd cumulus/scripts/changelog
|
||||
./bin/changelog $REF1 $REF2 release-notes.md
|
||||
ls -al release-notes.md
|
||||
ls -al context.json
|
||||
|
||||
- name: Archive artifact context.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: release-notes-context
|
||||
path: |
|
||||
context.json
|
||||
**/*_srtool_output.json
|
||||
|
||||
- name: Create draft release
|
||||
id: create-release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: parachains-${{ github.ref }}
|
||||
release_name: Parachains ${{ github.ref }}
|
||||
body_path: ./cumulus/scripts/changelog/release-notes.md
|
||||
draft: true
|
||||
|
||||
publish-runtimes:
|
||||
runs-on: ubuntu-latest
|
||||
needs: ["publish-draft-release"]
|
||||
env:
|
||||
RUNTIME_DIR: polkadot-parachains
|
||||
strategy:
|
||||
matrix:
|
||||
runtime: ["shell", "statemine", "statemint", "westmint", "rococo-parachain"]
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.ref2 }}
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.0.0
|
||||
|
||||
- name: Get runtime version for ${{ matrix.runtime }}
|
||||
id: get-runtime-ver
|
||||
run: |
|
||||
echo "require './scripts/github/runtime-version.rb'" > script.rb
|
||||
echo "puts get_runtime(runtime: \"${{ matrix.runtime }}\", runtime_dir: \"$RUNTIME_DIR\")" >> script.rb
|
||||
|
||||
echo "Current folder: $PWD"
|
||||
ls "$RUNTIME_DIR/${{ matrix.runtime }}"
|
||||
runtime_ver=$(ruby script.rb)
|
||||
echo "Found version: >$runtime_ver<"
|
||||
echo "::set-output name=runtime_ver::$runtime_ver"
|
||||
|
||||
- name: Upload compressed ${{ matrix.runtime }} wasm
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.publish-draft-release.outputs.asset_upload_url }}
|
||||
asset_path: "${{ matrix.runtime }}-runtime/${{ matrix.runtime }}_runtime.compact.compressed.wasm"
|
||||
asset_name: ${{ matrix.runtime }}_runtime-v${{ steps.get-runtime-ver.outputs.runtime_ver }}.compact.compressed.wasm
|
||||
asset_content_type: application/wasm
|
||||
|
||||
post_to_matrix:
|
||||
runs-on: ubuntu-latest
|
||||
needs: publish-draft-release
|
||||
steps:
|
||||
- name: Internal polkadot channel
|
||||
uses: s3krit/matrix-message-action@v0.0.3
|
||||
with:
|
||||
room_id: ${{ secrets.INTERNAL_CUMULUS_MATRIX_ROOM_ID }}
|
||||
access_token: ${{ secrets.MATRIX_ACCESS_TOKEN }}
|
||||
message: |
|
||||
**New draft for ${{ github.repository }}**: ${{ github.ref }}<br/>
|
||||
|
||||
Draft release created: [draft](${{ needs.publish-draft-release.outputs.release_url }})
|
||||
|
||||
NOTE: The link above will no longer be valid if the draft is edited. You can then use the following link:
|
||||
[${{ github.server_url }}/${{ github.repository }}/releases](${{ github.server_url }}/${{ github.repository }}/releases)
|
||||
server: "matrix.parity.io"
|
||||
@@ -0,0 +1,121 @@
|
||||
name: Release - Docker
|
||||
|
||||
# This workflow listens to pubished releases.
|
||||
# It includes releases and pre-releases.
|
||||
# It fetches the binaries, checks sha256 and GPG
|
||||
# signatures, then builds an injected docker
|
||||
# image and publishes it.
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
docker_build_publish:
|
||||
env:
|
||||
BINARY: polkadot-collator
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name }}
|
||||
|
||||
- name: Fetch files from release
|
||||
run: |
|
||||
echo Repo: ${{ github.event.repository.full_name }}
|
||||
|
||||
echo Name: ${{ github.event.release.name }}
|
||||
echo Tag: ${{ github.event.release.tag_name }}
|
||||
echo Draft: ${{ github.event.release.draft }}
|
||||
echo Prerelease: ${{ github.event.release.prerelease }}
|
||||
echo Assets: ${{ github.event.release.assets }}
|
||||
|
||||
for f in $BINARY $BINARY.asc $BINARY.sha256; do
|
||||
URL="https://github.com/${{ github.event.repository.full_name }}/releases/download/${{ github.event.release.tag_name }}/$f"
|
||||
echo " - Fetching $f from $URL"
|
||||
wget $URL -O $f
|
||||
done
|
||||
chmod a+x $BINARY
|
||||
ls -al
|
||||
|
||||
- name: Check files
|
||||
run: |
|
||||
ls -al *collator*
|
||||
shasum -a 256 -c $BINARY.sha256
|
||||
sha_result=$?
|
||||
|
||||
KEY_PARITY_SEC=9D4B2B6EB8F97156D19669A9FF0812D491B96798
|
||||
KEY_CHEVDOR=2835EAF92072BC01D188AF2C4A092B93E97CE1E2
|
||||
|
||||
gpg --receive-keys $KEY_PARITY_SEC
|
||||
if [[ ${{ github.event.release.prerelease }} == "true" ]]; then
|
||||
gpg --receive-keys $KEY_CHEVDOR
|
||||
fi
|
||||
|
||||
gpg --verify $BINARY.asc
|
||||
gpg_result=$?
|
||||
|
||||
echo sha_result: $sha_result
|
||||
echo gpg_result: $gpg_result
|
||||
|
||||
# If it fails, it would fail earlier but a second check
|
||||
# does not hurt in case of refactoring...
|
||||
if [[ $sha_result -ne 0 || $gpg_result -ne 0 ]]; then
|
||||
echo "Check failed, exiting with error"
|
||||
exit 1
|
||||
else
|
||||
echo "Checks passed"
|
||||
fi
|
||||
|
||||
- name: Build injected image
|
||||
env:
|
||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
run: |
|
||||
export OWNER=$DOCKERHUB_USERNAME
|
||||
mkdir -p target/release
|
||||
cp -f $BINARY* target/release/
|
||||
./docker/scripts/build-injected-image.sh
|
||||
|
||||
- name: Login to Dockerhub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Tag and Publish
|
||||
env:
|
||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
run: |
|
||||
docker run --pull never --rm $DOCKERHUB_USERNAME/$BINARY --version
|
||||
VERSION=$(docker run --pull never --rm $DOCKERHUB_USERNAME/$BINARY --version | awk '{ print $2 }' )
|
||||
SEMVER=$( echo $VERSION | cut -f1 -d- )
|
||||
GITREF=$( echo $VERSION | cut -f2 -d- )
|
||||
PRE=${{ github.event.release.prerelease }}
|
||||
PRE_STR=""
|
||||
|
||||
echo "SEMVER=$SEMVER"
|
||||
echo "GITREF=$GITREF"
|
||||
echo "PRE=$PRE"
|
||||
|
||||
# Build a tag such as:
|
||||
# 1.2.3-8a1201273 or
|
||||
# 1.2.3-pre-8a1201273 for pre-releases
|
||||
[[ $PRE == "true" ]] && PRE_STR="-pre"
|
||||
TAG=${SEMVER}${PRE_STR}-${GITREF}
|
||||
echo "PRE_STR=$PRE_STR"
|
||||
echo "TAG=$TAG"
|
||||
|
||||
docker tag $DOCKERHUB_USERNAME/$BINARY $DOCKERHUB_USERNAME/$BINARY:$TAG
|
||||
docker push $DOCKERHUB_USERNAME/$BINARY:$TAG
|
||||
|
||||
if [[ $PRE != "true" ]]; then
|
||||
docker tag $DOCKERHUB_USERNAME/$BINARY $DOCKERHUB_USERNAME/$BINARY:latest
|
||||
docker tag $DOCKERHUB_USERNAME/$BINARY $DOCKERHUB_USERNAME/$BINARY:$SEMVER
|
||||
|
||||
docker push $DOCKERHUB_USERNAME/$BINARY:latest
|
||||
docker push $DOCKERHUB_USERNAME/$BINARY:$SEMVER
|
||||
fi
|
||||
|
||||
docker images | grep $DOCKERHUB_USERNAME/$BINARY
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Pushes release notes to a Matrix room
|
||||
name: Release - Pushes release notes to a Matrix room
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
@@ -1,7 +1,7 @@
|
||||
name: Srtool build
|
||||
|
||||
env:
|
||||
SUBWASM_VERSION: 0.14.1
|
||||
SUBWASM_VERSION: 0.15.0
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -14,6 +14,10 @@ on:
|
||||
- "scripts"
|
||||
- "test"
|
||||
|
||||
branches:
|
||||
- "release*"
|
||||
- "master"
|
||||
|
||||
schedule:
|
||||
- cron: "00 02 * * 1" # 2AM weekly on monday
|
||||
|
||||
@@ -24,7 +28,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
chain: ["statemine", "westmint", "statemint", "rococo", "shell"]
|
||||
chain: ["statemine", "westmint", "statemint", "rococo-parachain", "shell"]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
|
||||
@@ -107,6 +107,29 @@ test-linux-stable:
|
||||
fi
|
||||
- sccache -s
|
||||
|
||||
check-runtime-benchmarks:
|
||||
stage: test
|
||||
<<: *docker-env
|
||||
script:
|
||||
# Check that the node will compile with `runtime-benchmarks` feature flag.
|
||||
- time cargo check --all --features runtime-benchmarks
|
||||
- sccache -s
|
||||
|
||||
cargo-check-try-runtime:
|
||||
stage: test
|
||||
<<: *docker-env
|
||||
script:
|
||||
# Check that the node will compile with `try-runtime` feature flag.
|
||||
- time cargo check --all --features try-runtime
|
||||
- sccache -s
|
||||
|
||||
cargo-check-benches:
|
||||
stage: test
|
||||
<<: *docker-env
|
||||
script:
|
||||
- time cargo check --all --benches
|
||||
- sccache -s
|
||||
|
||||
#### stage: publish
|
||||
|
||||
publish-s3:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Basic
|
||||
edition = "2021"
|
||||
hard_tabs = true
|
||||
max_width = 100
|
||||
use_small_heuristics = "Max"
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# Lists some code owners.
|
||||
#
|
||||
# A codeowner just oversees some part of the codebase. If an owned file is changed then the
|
||||
# corresponding codeowner receives a review request. An approval of the codeowner might be
|
||||
# required for merging a PR (depends on repository settings).
|
||||
#
|
||||
# For details about syntax, see:
|
||||
# https://help.github.com/en/articles/about-code-owners
|
||||
# But here are some important notes:
|
||||
#
|
||||
# - Glob syntax is git-like, e.g. `/core` means the core directory in the root, unlike `core`
|
||||
# which can be everywhere.
|
||||
# - Multiple owners are supported.
|
||||
# - Either handle (e.g, @github_user or @github/team) or email can be used. Keep in mind,
|
||||
# that handles might work better because they are more recognizable on GitHub,
|
||||
# eyou can use them for mentioning unlike an email.
|
||||
# - The latest matching rule, if multiple, takes precedence.
|
||||
|
||||
# CI
|
||||
/.github/ @paritytech/ci @chevdor
|
||||
/.gitlab-ci.yml @paritytech/ci
|
||||
/scripts/ci/ @paritytech/ci
|
||||
/scripts/github/ @paritytech/ci @chevdor
|
||||
/scripts/extrinsic-ordering-filter.sh @paritytech/ci @chevdor
|
||||
|
||||
# CHANGELOG
|
||||
/scripts/changelog/ @chevdor
|
||||
Generated
+1927
-1738
File diff suppressed because it is too large
Load Diff
+2
-3
@@ -7,7 +7,7 @@ members = [
|
||||
"client/network",
|
||||
"client/pov-recovery",
|
||||
"client/service",
|
||||
"pallets/asset-tx-payment",
|
||||
"client/relay-chain-interface",
|
||||
"pallets/aura-ext",
|
||||
"pallets/collator-selection",
|
||||
"pallets/dmp-queue",
|
||||
@@ -25,7 +25,7 @@ members = [
|
||||
"polkadot-parachains/",
|
||||
"polkadot-parachains/pallets/parachain-info",
|
||||
"polkadot-parachains/pallets/ping",
|
||||
"polkadot-parachains/rococo",
|
||||
"polkadot-parachains/rococo-parachain",
|
||||
"polkadot-parachains/shell",
|
||||
"polkadot-parachains/parachains-common",
|
||||
"polkadot-parachains/statemint",
|
||||
@@ -35,7 +35,6 @@ members = [
|
||||
"test/relay-sproof-builder",
|
||||
"test/relay-validation-worker-provider",
|
||||
"test/runtime",
|
||||
"test/runtime-upgrade",
|
||||
"test/service",
|
||||
]
|
||||
|
||||
|
||||
@@ -41,13 +41,13 @@ Statemint is a common good parachain providing an asset store for the Polkadot e
|
||||
To run a Statemine or Westmint node (Statemint is not deployed, yet) you will need to compile the
|
||||
`polkadot-collator` binary:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
cargo build --release --locked -p polkadot-collator
|
||||
```
|
||||
|
||||
Once the executable is built, launch the parachain node via:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
CHAIN=westmint # or statemine
|
||||
./target/release/polkadot-collator --chain $CHAIN
|
||||
```
|
||||
@@ -56,15 +56,10 @@ Refer to the [setup instructions below](#local-setup) to run a local network for
|
||||
|
||||
# Rococo :crown:
|
||||
|
||||
[Rococo](https://polkadot.js.org/apps/?rpc=wss://rococo-rpc.polkadot.io) is the testnet for
|
||||
parachains. It currently runs the parachains
|
||||
[Tick](https://polkadot.js.org/apps/?rpc=wss://tick-rpc.polkadot.io),
|
||||
[Trick](https://polkadot.js.org/apps/?rpc=wss://trick-rpc.polkadot.io) and
|
||||
[Track](https://polkadot.js.org/apps/?rpc=wss://track-rpc.polkadot.io).
|
||||
[Rococo](https://polkadot.js.org/apps/?rpc=wss://rococo-rpc.polkadot.io) is becoming a [Community Parachain Testbed](https://polkadot.network/blog/rococo-revamp-becoming-a-community-parachain-testbed/) for parachain teams in the Polkadot ecosystem. It supports multiple parachains with the differentiation of long-term connections and recurring short-term connections, to see which parachains are currently connected and how long they will be connected for [see here](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-rpc.polkadot.io#/parachains).
|
||||
|
||||
Rococo is an elaborate style of design and the name describes the painstaking effort that has gone
|
||||
into this project. Tick, Trick and Track are the German names for the cartoon ducks known to English
|
||||
speakers as Huey, Dewey and Louie.
|
||||
into this project.
|
||||
|
||||
## Build & Launch Rococo Collators
|
||||
|
||||
@@ -73,7 +68,7 @@ eventually be included by the relay chain for a parachain.
|
||||
|
||||
To run a Rococo collator you will need to compile the following binary:
|
||||
|
||||
```
|
||||
```bash
|
||||
cargo build --release --locked -p polkadot-collator
|
||||
```
|
||||
|
||||
@@ -93,18 +88,13 @@ If you want to reproduce other steps of CI process you can use the following
|
||||
Once the executable is built, launch collators for each parachain (repeat once each for chain
|
||||
`tick`, `trick`, `track`):
|
||||
|
||||
```
|
||||
```bash
|
||||
./target/release/polkadot-collator --chain $CHAIN --validator
|
||||
```
|
||||
|
||||
## Parachains
|
||||
|
||||
The parachains of Rococo all use the same runtime code. The only difference between them is the
|
||||
parachain ID used for registration with the relay chain:
|
||||
|
||||
- Tick: 100
|
||||
- Trick: 110
|
||||
- Track: 120
|
||||
- [Canvas - WASM Smart Contract](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frococo-canvas-rpc.polkadot.io#/explorer)
|
||||
|
||||
The network uses horizontal message passing (HRMP) to enable communication between parachains and
|
||||
the relay chain and, in turn, between parachains. This means that every message is sent to the relay
|
||||
@@ -154,19 +144,27 @@ cargo build --release
|
||||
# Parachain Full Node 1
|
||||
./target/release/polkadot-collator --tmp --parachain-id <parachain_id_u32_type_range> --port 40337 --ws-port 9948 -- --execution wasm --chain ../polkadot/rococo-local-cfde.json --port 30337
|
||||
```
|
||||
|
||||
### Register the parachain
|
||||
|
||||

|
||||
|
||||
## Build the docker image
|
||||
## Containerize
|
||||
|
||||
After building `polkadot-collator` with cargo or with Parity docker image as documented in [this chapter](#build--launch-rococo-collators), the following will allow producting a new docker image where the compiled binary is injected:
|
||||
After building `polkadot-collator` with cargo or with Parity CI image as documented in [this chapter](#build--launch-rococo-collators),
|
||||
the following will allow producing a new docker image where the compiled binary is injected:
|
||||
|
||||
```
|
||||
```bash
|
||||
./docker/scripts/build-injected-image.sh
|
||||
```
|
||||
|
||||
You may then start a new contaier:
|
||||
Alternatively, you can build an image with a builder pattern:
|
||||
|
||||
```
|
||||
```bash
|
||||
docker build --tag $OWNER/$IMAGE_NAME --file ./docker/polkadot-collator_builder.Containerfile .
|
||||
|
||||
You may then run your new container:
|
||||
|
||||
```bash
|
||||
docker run --rm -it $OWNER/$IMAGE_NAME --collator --tmp --parachain-id 1000 --execution wasm --chain /specs/westmint.json
|
||||
```
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "cumulus-client-cli"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
structopt = "0.3.3"
|
||||
|
||||
+5
-10
@@ -30,7 +30,7 @@ use std::{
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
|
||||
/// The `purge-chain` command used to remove the whole chain: the parachain and the relaychain.
|
||||
/// The `purge-chain` command used to remove the whole chain: the parachain and the relay chain.
|
||||
#[derive(Debug, StructOpt)]
|
||||
pub struct PurgeChainCmd {
|
||||
/// The base struct of the purge-chain command.
|
||||
@@ -125,10 +125,6 @@ pub struct RunCmd {
|
||||
#[structopt(flatten)]
|
||||
pub base: sc_cli::RunCmd,
|
||||
|
||||
/// Id of the parachain this collator collates for.
|
||||
#[structopt(long)]
|
||||
pub parachain_id: Option<u32>,
|
||||
|
||||
/// Run node as collator.
|
||||
///
|
||||
/// Note that this is the same as running with `--validator`.
|
||||
@@ -137,13 +133,11 @@ pub struct RunCmd {
|
||||
}
|
||||
|
||||
/// A non-redundant version of the `RunCmd` that sets the `validator` field when the
|
||||
/// original `RunCmd` had the `colaltor` field.
|
||||
/// original `RunCmd` had the `collator` field.
|
||||
/// This is how we make `--collator` imply `--validator`.
|
||||
pub struct NormalizedRunCmd {
|
||||
/// The cumulus RunCmd inherents from sc_cli's
|
||||
pub base: sc_cli::RunCmd,
|
||||
/// Id of the parachain this collator collates for.
|
||||
pub parachain_id: Option<u32>,
|
||||
}
|
||||
|
||||
impl RunCmd {
|
||||
@@ -153,7 +147,7 @@ impl RunCmd {
|
||||
|
||||
new_base.validator = self.base.validator || self.collator;
|
||||
|
||||
NormalizedRunCmd { base: new_base, parachain_id: self.parachain_id }
|
||||
NormalizedRunCmd { base: new_base }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,8 +198,9 @@ impl sc_cli::CliConfiguration for NormalizedRunCmd {
|
||||
fn prometheus_config(
|
||||
&self,
|
||||
default_listen_port: u16,
|
||||
chain_spec: &Box<dyn sc_cli::ChainSpec>,
|
||||
) -> sc_cli::Result<Option<PrometheusConfig>> {
|
||||
self.base.prometheus_config(default_listen_port)
|
||||
self.base.prometheus_config(default_listen_port, chain_spec)
|
||||
}
|
||||
|
||||
fn disable_grandpa(&self) -> sc_cli::Result<bool> {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "cumulus-client-collator"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Substrate dependencies
|
||||
@@ -22,6 +22,7 @@ polkadot-node-subsystem = { git = "https://github.com/paritytech/polkadot", bran
|
||||
cumulus-client-network = { path = "../network" }
|
||||
cumulus-client-consensus-common = { path = "../consensus/common" }
|
||||
cumulus-primitives-core = { path = "../../primitives/core" }
|
||||
cumulus-relay-chain-interface = { path = "../relay-chain-interface" }
|
||||
|
||||
# Other dependencies
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] }
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
//! Cumulus Collator implementation for Substrate.
|
||||
|
||||
use cumulus_client_network::WaitToAnnounce;
|
||||
use cumulus_primitives_core::{CollectCollationInfo, ParachainBlockData, PersistedValidationData};
|
||||
use cumulus_primitives_core::{
|
||||
relay_chain::Hash as PHash, CollectCollationInfo, ParachainBlockData, PersistedValidationData,
|
||||
};
|
||||
|
||||
use sc_client_api::BlockBackend;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
@@ -34,7 +36,7 @@ use polkadot_node_primitives::{
|
||||
};
|
||||
use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProtocolMessage};
|
||||
use polkadot_overseer::Handle as OverseerHandle;
|
||||
use polkadot_primitives::v1::{CollatorPair, Hash as PHash, HeadData, Id as ParaId};
|
||||
use polkadot_primitives::v1::{CollatorPair, HeadData, Id as ParaId};
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use futures::{channel::oneshot, FutureExt};
|
||||
@@ -390,7 +392,7 @@ mod tests {
|
||||
.build()
|
||||
.expect("Builds overseer");
|
||||
|
||||
spawner.spawn("overseer", overseer.run().then(|_| async { () }).boxed());
|
||||
spawner.spawn("overseer", None, overseer.run().then(|_| async { () }).boxed());
|
||||
|
||||
let collator_start = start_collator(StartCollatorParams {
|
||||
runtime_api: client.clone(),
|
||||
@@ -428,8 +430,8 @@ mod tests {
|
||||
assert_eq!(1, *block.header().number());
|
||||
|
||||
// Ensure that we did not include `:code` in the proof.
|
||||
let db = block
|
||||
.storage_proof()
|
||||
let proof = block.storage_proof();
|
||||
let db = proof
|
||||
.to_storage_proof::<BlakeTwo256>(Some(header.state_root()))
|
||||
.unwrap()
|
||||
.0
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "cumulus-client-consensus-aura"
|
||||
description = "AURA consensus algorithm for parachains"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Substrate dependencies
|
||||
@@ -24,9 +24,6 @@ sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "mast
|
||||
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
# Polkadot dependencies
|
||||
polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
# Cumulus dependencies
|
||||
cumulus-client-consensus-common = { path = "../common" }
|
||||
cumulus-primitives-core = { path = "../../../primitives/core" }
|
||||
|
||||
@@ -24,12 +24,12 @@ use sc_consensus_slots::InherentDataProviderExt;
|
||||
use sc_telemetry::TelemetryHandle;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_block_builder::BlockBuilder as BlockBuilderApi;
|
||||
use sp_blockchain::{HeaderBackend, ProvideCache};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::{CanAuthorWith, Error as ConsensusError};
|
||||
use sp_consensus_aura::{digests::CompatibleDigestItem, AuraApi};
|
||||
use sp_consensus_aura::AuraApi;
|
||||
use sp_core::crypto::Pair;
|
||||
use sp_inherents::CreateInherentDataProviders;
|
||||
use sp_runtime::traits::{Block as BlockT, DigestItemFor};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use std::{fmt::Debug, hash::Hash, sync::Arc};
|
||||
use substrate_prometheus_endpoint::Registry;
|
||||
|
||||
@@ -69,7 +69,6 @@ where
|
||||
C: 'static
|
||||
+ ProvideRuntimeApi<Block>
|
||||
+ BlockOf
|
||||
+ ProvideCache<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ AuxStore
|
||||
@@ -79,7 +78,6 @@ where
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
DigestItemFor<Block>: CompatibleDigestItem<P::Signature>,
|
||||
P: Pair + Send + Sync + 'static,
|
||||
P::Public: Clone + Eq + Send + Sync + Hash + Debug + Codec,
|
||||
P::Signature: Codec,
|
||||
|
||||
@@ -26,19 +26,16 @@ use codec::{Decode, Encode};
|
||||
use cumulus_client_consensus_common::{
|
||||
ParachainBlockImport, ParachainCandidate, ParachainConsensus,
|
||||
};
|
||||
use cumulus_primitives_core::{
|
||||
relay_chain::v1::{Block as PBlock, Hash as PHash, ParachainHost},
|
||||
PersistedValidationData,
|
||||
};
|
||||
use cumulus_primitives_core::{relay_chain::v1::Hash as PHash, PersistedValidationData};
|
||||
|
||||
use futures::lock::Mutex;
|
||||
use polkadot_client::ClientHandle;
|
||||
use sc_client_api::{backend::AuxStore, Backend, BlockOf};
|
||||
use sc_client_api::{backend::AuxStore, BlockOf};
|
||||
use sc_consensus::BlockImport;
|
||||
use sc_consensus_slots::{BackoffAuthoringBlocksStrategy, SlotInfo};
|
||||
use sc_telemetry::TelemetryHandle;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_application_crypto::AppPublic;
|
||||
use sp_blockchain::{HeaderBackend, ProvideCache};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::{
|
||||
EnableProofRecording, Environment, ProofRecording, Proposer, SlotData, SyncOracle,
|
||||
};
|
||||
@@ -46,8 +43,8 @@ use sp_consensus_aura::AuraApi;
|
||||
use sp_core::crypto::Pair;
|
||||
use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider};
|
||||
use sp_keystore::SyncCryptoStorePtr;
|
||||
use sp_runtime::traits::{Block as BlockT, HashFor, Header as HeaderT, Member, NumberFor};
|
||||
use std::{convert::TryFrom, hash::Hash, marker::PhantomData, sync::Arc};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member, NumberFor};
|
||||
use std::{convert::TryFrom, hash::Hash, sync::Arc};
|
||||
|
||||
mod import_queue;
|
||||
|
||||
@@ -60,10 +57,8 @@ pub use sc_consensus_slots::InherentDataProviderExt;
|
||||
const LOG_TARGET: &str = "aura::cumulus";
|
||||
|
||||
/// The implementation of the AURA consensus for parachains.
|
||||
pub struct AuraConsensus<B, RClient, RBackend, CIDP> {
|
||||
pub struct AuraConsensus<B, CIDP> {
|
||||
create_inherent_data_providers: Arc<CIDP>,
|
||||
relay_chain_client: Arc<RClient>,
|
||||
relay_chain_backend: Arc<RBackend>,
|
||||
aura_worker: Arc<
|
||||
Mutex<
|
||||
dyn sc_consensus_slots::SlotWorker<B, <EnableProofRecording as ProofRecording>::Proof>
|
||||
@@ -74,53 +69,42 @@ pub struct AuraConsensus<B, RClient, RBackend, CIDP> {
|
||||
slot_duration: SlotDuration,
|
||||
}
|
||||
|
||||
impl<B, RClient, RBackend, CIDP> Clone for AuraConsensus<B, RClient, RBackend, CIDP> {
|
||||
impl<B, CIDP> Clone for AuraConsensus<B, CIDP> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
create_inherent_data_providers: self.create_inherent_data_providers.clone(),
|
||||
relay_chain_backend: self.relay_chain_backend.clone(),
|
||||
relay_chain_client: self.relay_chain_client.clone(),
|
||||
aura_worker: self.aura_worker.clone(),
|
||||
slot_duration: self.slot_duration,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, RClient, RBackend, CIDP> AuraConsensus<B, RClient, RBackend, CIDP>
|
||||
impl<B, CIDP> AuraConsensus<B, CIDP>
|
||||
where
|
||||
B: BlockT,
|
||||
RClient: ProvideRuntimeApi<PBlock>,
|
||||
RClient::Api: ParachainHost<PBlock>,
|
||||
RBackend: Backend<PBlock>,
|
||||
CIDP: CreateInherentDataProviders<B, (PHash, PersistedValidationData)>,
|
||||
CIDP: CreateInherentDataProviders<B, (PHash, PersistedValidationData)> + 'static,
|
||||
CIDP::InherentDataProviders: InherentDataProviderExt,
|
||||
{
|
||||
/// Create a new instance of AURA consensus.
|
||||
pub fn new<P, Client, BI, SO, PF, BS, Error>(
|
||||
para_client: Arc<Client>,
|
||||
block_import: BI,
|
||||
sync_oracle: SO,
|
||||
proposer_factory: PF,
|
||||
force_authoring: bool,
|
||||
backoff_authoring_blocks: Option<BS>,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
create_inherent_data_providers: CIDP,
|
||||
polkadot_client: Arc<RClient>,
|
||||
polkadot_backend: Arc<RBackend>,
|
||||
slot_duration: SlotDuration,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
block_proposal_slot_portion: SlotProportion,
|
||||
max_block_proposal_slot_portion: Option<SlotProportion>,
|
||||
) -> Self
|
||||
/// Create a new boxed instance of AURA consensus.
|
||||
pub fn build<P, Client, BI, SO, PF, BS, Error>(
|
||||
BuildAuraConsensusParams {
|
||||
proposer_factory,
|
||||
create_inherent_data_providers,
|
||||
block_import,
|
||||
para_client,
|
||||
backoff_authoring_blocks,
|
||||
sync_oracle,
|
||||
keystore,
|
||||
force_authoring,
|
||||
slot_duration,
|
||||
telemetry,
|
||||
block_proposal_slot_portion,
|
||||
max_block_proposal_slot_portion,
|
||||
}: BuildAuraConsensusParams<PF, BI, CIDP, Client, BS, SO>,
|
||||
) -> Box<dyn ParachainConsensus<B>>
|
||||
where
|
||||
Client: ProvideRuntimeApi<B>
|
||||
+ BlockOf
|
||||
+ ProvideCache<B>
|
||||
+ AuxStore
|
||||
+ HeaderBackend<B>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
Client:
|
||||
ProvideRuntimeApi<B> + BlockOf + AuxStore + HeaderBackend<B> + Send + Sync + 'static,
|
||||
Client::Api: AuraApi<B, P::Public>,
|
||||
BI: BlockImport<B, Transaction = sp_api::TransactionFor<Client, B>> + Send + Sync + 'static,
|
||||
SO: SyncOracle + Send + Sync + Clone + 'static,
|
||||
@@ -154,13 +138,11 @@ where
|
||||
},
|
||||
);
|
||||
|
||||
Self {
|
||||
Box::new(Self {
|
||||
create_inherent_data_providers: Arc::new(create_inherent_data_providers),
|
||||
relay_chain_backend: polkadot_backend,
|
||||
relay_chain_client: polkadot_client,
|
||||
aura_worker: Arc::new(Mutex::new(worker)),
|
||||
slot_duration,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Create the inherent data.
|
||||
@@ -200,13 +182,10 @@ where
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<B, RClient, RBackend, CIDP> ParachainConsensus<B> for AuraConsensus<B, RClient, RBackend, CIDP>
|
||||
impl<B, CIDP> ParachainConsensus<B> for AuraConsensus<B, CIDP>
|
||||
where
|
||||
B: BlockT,
|
||||
RClient: ProvideRuntimeApi<PBlock> + Send + Sync,
|
||||
RClient::Api: ParachainHost<PBlock>,
|
||||
RBackend: Backend<PBlock>,
|
||||
CIDP: CreateInherentDataProviders<B, (PHash, PersistedValidationData)> + Send + Sync,
|
||||
CIDP: CreateInherentDataProviders<B, (PHash, PersistedValidationData)> + Send + Sync + 'static,
|
||||
CIDP::InherentDataProviders: InherentDataProviderExt + Send,
|
||||
{
|
||||
async fn produce_candidate(
|
||||
@@ -238,12 +217,10 @@ where
|
||||
}
|
||||
|
||||
/// Paramaters of [`build_aura_consensus`].
|
||||
pub struct BuildAuraConsensusParams<PF, BI, RBackend, CIDP, Client, BS, SO> {
|
||||
pub struct BuildAuraConsensusParams<PF, BI, CIDP, Client, BS, SO> {
|
||||
pub proposer_factory: PF,
|
||||
pub create_inherent_data_providers: CIDP,
|
||||
pub block_import: BI,
|
||||
pub relay_chain_client: polkadot_client::Client,
|
||||
pub relay_chain_backend: Arc<RBackend>,
|
||||
pub para_client: Arc<Client>,
|
||||
pub backoff_authoring_blocks: Option<BS>,
|
||||
pub sync_oracle: SO,
|
||||
@@ -254,250 +231,3 @@ pub struct BuildAuraConsensusParams<PF, BI, RBackend, CIDP, Client, BS, SO> {
|
||||
pub block_proposal_slot_portion: SlotProportion,
|
||||
pub max_block_proposal_slot_portion: Option<SlotProportion>,
|
||||
}
|
||||
|
||||
/// Build the [`AuraConsensus`].
|
||||
///
|
||||
/// Returns a boxed [`ParachainConsensus`].
|
||||
pub fn build_aura_consensus<P, Block, PF, BI, RBackend, CIDP, Client, SO, BS, Error>(
|
||||
BuildAuraConsensusParams {
|
||||
proposer_factory,
|
||||
create_inherent_data_providers,
|
||||
block_import,
|
||||
relay_chain_client,
|
||||
relay_chain_backend,
|
||||
para_client,
|
||||
backoff_authoring_blocks,
|
||||
sync_oracle,
|
||||
keystore,
|
||||
force_authoring,
|
||||
slot_duration,
|
||||
telemetry,
|
||||
block_proposal_slot_portion,
|
||||
max_block_proposal_slot_portion,
|
||||
}: BuildAuraConsensusParams<PF, BI, RBackend, CIDP, Client, BS, SO>,
|
||||
) -> Box<dyn ParachainConsensus<Block>>
|
||||
where
|
||||
Block: BlockT,
|
||||
RBackend: Backend<PBlock> + 'static,
|
||||
CIDP: CreateInherentDataProviders<Block, (PHash, PersistedValidationData)>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
CIDP::InherentDataProviders: InherentDataProviderExt + Send,
|
||||
Client: ProvideRuntimeApi<Block>
|
||||
+ BlockOf
|
||||
+ ProvideCache<Block>
|
||||
+ AuxStore
|
||||
+ HeaderBackend<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
Client::Api: AuraApi<Block, P::Public>,
|
||||
BI: BlockImport<Block, Transaction = sp_api::TransactionFor<Client, Block>>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
SO: SyncOracle + Send + Sync + Clone + 'static,
|
||||
BS: BackoffAuthoringBlocksStrategy<NumberFor<Block>> + Send + Sync + 'static,
|
||||
PF: Environment<Block, Error = Error> + Send + Sync + 'static,
|
||||
PF::Proposer: Proposer<
|
||||
Block,
|
||||
Error = Error,
|
||||
Transaction = sp_api::TransactionFor<Client, Block>,
|
||||
ProofRecording = EnableProofRecording,
|
||||
Proof = <EnableProofRecording as ProofRecording>::Proof,
|
||||
>,
|
||||
Error: std::error::Error + Send + From<sp_consensus::Error> + 'static,
|
||||
P: Pair + Send + Sync,
|
||||
P::Public: AppPublic + Hash + Member + Encode + Decode,
|
||||
P::Signature: TryFrom<Vec<u8>> + Hash + Member + Encode + Decode,
|
||||
{
|
||||
AuraConsensusBuilder::<P, _, _, _, _, _, _, _, _, _>::new(
|
||||
proposer_factory,
|
||||
block_import,
|
||||
create_inherent_data_providers,
|
||||
relay_chain_client,
|
||||
relay_chain_backend,
|
||||
para_client,
|
||||
backoff_authoring_blocks,
|
||||
sync_oracle,
|
||||
force_authoring,
|
||||
keystore,
|
||||
slot_duration,
|
||||
telemetry,
|
||||
block_proposal_slot_portion,
|
||||
max_block_proposal_slot_portion,
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
/// Aura consensus builder.
|
||||
///
|
||||
/// Builds a [`AuraConsensus`] for a parachain. As this requires
|
||||
/// a concrete relay chain client instance, the builder takes a [`polkadot_client::Client`]
|
||||
/// that wraps this concrete instance. By using [`polkadot_client::ExecuteWithClient`]
|
||||
/// the builder gets access to this concrete instance.
|
||||
struct AuraConsensusBuilder<P, Block, PF, BI, RBackend, CIDP, Client, SO, BS, Error> {
|
||||
_phantom: PhantomData<(Block, Error, P)>,
|
||||
proposer_factory: PF,
|
||||
create_inherent_data_providers: CIDP,
|
||||
block_import: BI,
|
||||
relay_chain_backend: Arc<RBackend>,
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
para_client: Arc<Client>,
|
||||
backoff_authoring_blocks: Option<BS>,
|
||||
sync_oracle: SO,
|
||||
force_authoring: bool,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
slot_duration: SlotDuration,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
block_proposal_slot_portion: SlotProportion,
|
||||
max_block_proposal_slot_portion: Option<SlotProportion>,
|
||||
}
|
||||
|
||||
impl<Block, PF, BI, RBackend, CIDP, Client, SO, BS, P, Error>
|
||||
AuraConsensusBuilder<P, Block, PF, BI, RBackend, CIDP, Client, SO, BS, Error>
|
||||
where
|
||||
Block: BlockT,
|
||||
RBackend: Backend<PBlock> + 'static,
|
||||
CIDP: CreateInherentDataProviders<Block, (PHash, PersistedValidationData)>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
CIDP::InherentDataProviders: InherentDataProviderExt + Send,
|
||||
Client: ProvideRuntimeApi<Block>
|
||||
+ BlockOf
|
||||
+ ProvideCache<Block>
|
||||
+ AuxStore
|
||||
+ HeaderBackend<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
Client::Api: AuraApi<Block, P::Public>,
|
||||
BI: BlockImport<Block, Transaction = sp_api::TransactionFor<Client, Block>>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
SO: SyncOracle + Send + Sync + Clone + 'static,
|
||||
BS: BackoffAuthoringBlocksStrategy<NumberFor<Block>> + Send + Sync + 'static,
|
||||
PF: Environment<Block, Error = Error> + Send + Sync + 'static,
|
||||
PF::Proposer: Proposer<
|
||||
Block,
|
||||
Error = Error,
|
||||
Transaction = sp_api::TransactionFor<Client, Block>,
|
||||
ProofRecording = EnableProofRecording,
|
||||
Proof = <EnableProofRecording as ProofRecording>::Proof,
|
||||
>,
|
||||
Error: std::error::Error + Send + From<sp_consensus::Error> + 'static,
|
||||
P: Pair + Send + Sync,
|
||||
P::Public: AppPublic + Hash + Member + Encode + Decode,
|
||||
P::Signature: TryFrom<Vec<u8>> + Hash + Member + Encode + Decode,
|
||||
{
|
||||
/// Create a new instance of the builder.
|
||||
fn new(
|
||||
proposer_factory: PF,
|
||||
block_import: BI,
|
||||
create_inherent_data_providers: CIDP,
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
relay_chain_backend: Arc<RBackend>,
|
||||
para_client: Arc<Client>,
|
||||
backoff_authoring_blocks: Option<BS>,
|
||||
sync_oracle: SO,
|
||||
force_authoring: bool,
|
||||
keystore: SyncCryptoStorePtr,
|
||||
slot_duration: SlotDuration,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
block_proposal_slot_portion: SlotProportion,
|
||||
max_block_proposal_slot_portion: Option<SlotProportion>,
|
||||
) -> Self {
|
||||
Self {
|
||||
_phantom: PhantomData,
|
||||
proposer_factory,
|
||||
block_import,
|
||||
create_inherent_data_providers,
|
||||
relay_chain_backend,
|
||||
relay_chain_client,
|
||||
para_client,
|
||||
backoff_authoring_blocks,
|
||||
sync_oracle,
|
||||
force_authoring,
|
||||
keystore,
|
||||
slot_duration,
|
||||
telemetry,
|
||||
block_proposal_slot_portion,
|
||||
max_block_proposal_slot_portion,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the relay chain consensus.
|
||||
fn build(self) -> Box<dyn ParachainConsensus<Block>> {
|
||||
self.relay_chain_client.clone().execute_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block, PF, BI, RBackend, CIDP, Client, SO, BS, P, Error> polkadot_client::ExecuteWithClient
|
||||
for AuraConsensusBuilder<P, Block, PF, BI, RBackend, CIDP, Client, SO, BS, Error>
|
||||
where
|
||||
Block: BlockT,
|
||||
RBackend: Backend<PBlock> + 'static,
|
||||
CIDP: CreateInherentDataProviders<Block, (PHash, PersistedValidationData)>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
CIDP::InherentDataProviders: InherentDataProviderExt + Send,
|
||||
Client: ProvideRuntimeApi<Block>
|
||||
+ BlockOf
|
||||
+ ProvideCache<Block>
|
||||
+ AuxStore
|
||||
+ HeaderBackend<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
Client::Api: AuraApi<Block, P::Public>,
|
||||
BI: BlockImport<Block, Transaction = sp_api::TransactionFor<Client, Block>>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
SO: SyncOracle + Send + Sync + Clone + 'static,
|
||||
BS: BackoffAuthoringBlocksStrategy<NumberFor<Block>> + Send + Sync + 'static,
|
||||
PF: Environment<Block, Error = Error> + Send + Sync + 'static,
|
||||
PF::Proposer: Proposer<
|
||||
Block,
|
||||
Error = Error,
|
||||
Transaction = sp_api::TransactionFor<Client, Block>,
|
||||
ProofRecording = EnableProofRecording,
|
||||
Proof = <EnableProofRecording as ProofRecording>::Proof,
|
||||
>,
|
||||
Error: std::error::Error + Send + From<sp_consensus::Error> + 'static,
|
||||
P: Pair + Send + Sync,
|
||||
P::Public: AppPublic + Hash + Member + Encode + Decode,
|
||||
P::Signature: TryFrom<Vec<u8>> + Hash + Member + Encode + Decode,
|
||||
{
|
||||
type Output = Box<dyn ParachainConsensus<Block>>;
|
||||
|
||||
fn execute_with_client<PClient, Api, PBackend>(self, client: Arc<PClient>) -> Self::Output
|
||||
where
|
||||
<Api as sp_api::ApiExt<PBlock>>::StateBackend: sp_api::StateBackend<HashFor<PBlock>>,
|
||||
PBackend: Backend<PBlock>,
|
||||
PBackend::State: sp_api::StateBackend<sp_runtime::traits::BlakeTwo256>,
|
||||
Api: polkadot_client::RuntimeApiCollection<StateBackend = PBackend::State>,
|
||||
PClient: polkadot_client::AbstractClient<PBlock, PBackend, Api = Api> + 'static,
|
||||
{
|
||||
Box::new(AuraConsensus::new::<P, _, _, _, _, _, _>(
|
||||
self.para_client,
|
||||
self.block_import,
|
||||
self.sync_oracle,
|
||||
self.proposer_factory,
|
||||
self.force_authoring,
|
||||
self.backoff_authoring_blocks,
|
||||
self.keystore,
|
||||
self.create_inherent_data_providers,
|
||||
client.clone(),
|
||||
self.relay_chain_backend,
|
||||
self.slot_duration,
|
||||
self.telemetry,
|
||||
self.block_proposal_slot_portion,
|
||||
self.max_block_proposal_slot_portion,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "cumulus-client-consensus-common"
|
||||
description = "Cumulus specific common consensus implementations"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Substrate deps
|
||||
@@ -18,6 +18,9 @@ sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
# Polkadot deps
|
||||
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
# Cumulus deps
|
||||
cumulus-relay-chain-interface = { path = "../../relay-chain-interface" }
|
||||
|
||||
# Other deps
|
||||
futures = { version = "0.3.8", features = ["compat"] }
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] }
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use cumulus_relay_chain_interface::RelayChainInterface;
|
||||
use sc_client_api::{
|
||||
Backend, BlockBackend, BlockImportNotification, BlockchainEvents, Finalizer, UsageProvider,
|
||||
};
|
||||
use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
||||
use sp_consensus::{BlockOrigin, BlockStatus};
|
||||
use sp_runtime::{
|
||||
@@ -26,9 +26,7 @@ use sp_runtime::{
|
||||
traits::{Block as BlockT, Header as HeaderT},
|
||||
};
|
||||
|
||||
use polkadot_primitives::v1::{
|
||||
Block as PBlock, Id as ParaId, OccupiedCoreAssumption, ParachainHost,
|
||||
};
|
||||
use polkadot_primitives::v1::{Block as PBlock, Id as ParaId, OccupiedCoreAssumption};
|
||||
|
||||
use codec::Decode;
|
||||
use futures::{future, select, FutureExt, Stream, StreamExt};
|
||||
@@ -370,10 +368,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RelaychainClient for Arc<T>
|
||||
impl<RCInterface> RelaychainClient for RCInterface
|
||||
where
|
||||
T: sc_client_api::BlockchainEvents<PBlock> + ProvideRuntimeApi<PBlock> + 'static + Send + Sync,
|
||||
<T as ProvideRuntimeApi<PBlock>>::Api: ParachainHost<PBlock>,
|
||||
RCInterface: RelayChainInterface + Clone + 'static,
|
||||
{
|
||||
type Error = ClientError;
|
||||
|
||||
@@ -410,8 +407,7 @@ where
|
||||
at: &BlockId<PBlock>,
|
||||
para_id: ParaId,
|
||||
) -> ClientResult<Option<Vec<u8>>> {
|
||||
self.runtime_api()
|
||||
.persisted_validation_data(at, para_id, OccupiedCoreAssumption::TimedOut)
|
||||
self.persisted_validation_data(at, para_id, OccupiedCoreAssumption::TimedOut)
|
||||
.map(|s| s.map(|s| s.parent_head.0))
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "cumulus-client-consensus-relay-chain"
|
||||
description = "The relay-chain provided consensus algorithm"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Substrate deps
|
||||
@@ -19,11 +19,11 @@ sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "mast
|
||||
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
# Polkadot dependencies
|
||||
polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
# Cumulus dependencies
|
||||
cumulus-client-consensus-common = { path = "../common" }
|
||||
cumulus-primitives-core = { path = "../../../primitives/core" }
|
||||
cumulus-relay-chain-interface = { path = "../../relay-chain-interface" }
|
||||
|
||||
# Other deps
|
||||
futures = { version = "0.3.8", features = ["compat"] }
|
||||
|
||||
@@ -36,20 +36,16 @@
|
||||
use cumulus_client_consensus_common::{
|
||||
ParachainBlockImport, ParachainCandidate, ParachainConsensus,
|
||||
};
|
||||
use cumulus_primitives_core::{
|
||||
relay_chain::v1::{Block as PBlock, Hash as PHash, ParachainHost},
|
||||
ParaId, PersistedValidationData,
|
||||
};
|
||||
use cumulus_primitives_core::{relay_chain::v1::Hash as PHash, ParaId, PersistedValidationData};
|
||||
use cumulus_relay_chain_interface::RelayChainInterface;
|
||||
use parking_lot::Mutex;
|
||||
use polkadot_client::ClientHandle;
|
||||
use sc_client_api::Backend;
|
||||
|
||||
use sc_consensus::{BlockImport, BlockImportParams};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_consensus::{
|
||||
BlockOrigin, EnableProofRecording, Environment, ProofRecording, Proposal, Proposer,
|
||||
};
|
||||
use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider};
|
||||
use sp_runtime::traits::{Block as BlockT, HashFor, Header as HeaderT};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||
use std::{marker::PhantomData, sync::Arc, time::Duration};
|
||||
|
||||
mod import_queue;
|
||||
@@ -58,18 +54,18 @@ pub use import_queue::{import_queue, Verifier};
|
||||
const LOG_TARGET: &str = "cumulus-consensus-relay-chain";
|
||||
|
||||
/// The implementation of the relay-chain provided consensus for parachains.
|
||||
pub struct RelayChainConsensus<B, PF, BI, RClient, RBackend, CIDP> {
|
||||
pub struct RelayChainConsensus<B, PF, BI, RCInterface, CIDP> {
|
||||
para_id: ParaId,
|
||||
_phantom: PhantomData<B>,
|
||||
proposer_factory: Arc<Mutex<PF>>,
|
||||
create_inherent_data_providers: Arc<CIDP>,
|
||||
block_import: Arc<futures::lock::Mutex<ParachainBlockImport<BI>>>,
|
||||
relay_chain_client: Arc<RClient>,
|
||||
relay_chain_backend: Arc<RBackend>,
|
||||
relay_chain_interface: RCInterface,
|
||||
}
|
||||
|
||||
impl<B, PF, BI, RClient, RBackend, CIDP> Clone
|
||||
for RelayChainConsensus<B, PF, BI, RClient, RBackend, CIDP>
|
||||
impl<B, PF, BI, RCInterface, CIDP> Clone for RelayChainConsensus<B, PF, BI, RCInterface, CIDP>
|
||||
where
|
||||
RCInterface: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
@@ -78,18 +74,15 @@ impl<B, PF, BI, RClient, RBackend, CIDP> Clone
|
||||
proposer_factory: self.proposer_factory.clone(),
|
||||
create_inherent_data_providers: self.create_inherent_data_providers.clone(),
|
||||
block_import: self.block_import.clone(),
|
||||
relay_chain_backend: self.relay_chain_backend.clone(),
|
||||
relay_chain_client: self.relay_chain_client.clone(),
|
||||
relay_chain_interface: self.relay_chain_interface.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, PF, BI, RClient, RBackend, CIDP> RelayChainConsensus<B, PF, BI, RClient, RBackend, CIDP>
|
||||
impl<B, PF, BI, RCInterface, CIDP> RelayChainConsensus<B, PF, BI, RCInterface, CIDP>
|
||||
where
|
||||
B: BlockT,
|
||||
RClient: ProvideRuntimeApi<PBlock>,
|
||||
RClient::Api: ParachainHost<PBlock>,
|
||||
RBackend: Backend<PBlock>,
|
||||
RCInterface: RelayChainInterface,
|
||||
CIDP: CreateInherentDataProviders<B, (PHash, PersistedValidationData)>,
|
||||
{
|
||||
/// Create a new instance of relay-chain provided consensus.
|
||||
@@ -98,8 +91,7 @@ where
|
||||
proposer_factory: PF,
|
||||
create_inherent_data_providers: CIDP,
|
||||
block_import: BI,
|
||||
polkadot_client: Arc<RClient>,
|
||||
polkadot_backend: Arc<RBackend>,
|
||||
relay_chain_interface: RCInterface,
|
||||
) -> Self {
|
||||
Self {
|
||||
para_id,
|
||||
@@ -108,8 +100,7 @@ where
|
||||
block_import: Arc::new(futures::lock::Mutex::new(ParachainBlockImport::new(
|
||||
block_import,
|
||||
))),
|
||||
relay_chain_backend: polkadot_backend,
|
||||
relay_chain_client: polkadot_client,
|
||||
relay_chain_interface,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -148,13 +139,11 @@ where
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<B, PF, BI, RClient, RBackend, CIDP> ParachainConsensus<B>
|
||||
for RelayChainConsensus<B, PF, BI, RClient, RBackend, CIDP>
|
||||
impl<B, PF, BI, RCInterface, CIDP> ParachainConsensus<B>
|
||||
for RelayChainConsensus<B, PF, BI, RCInterface, CIDP>
|
||||
where
|
||||
B: BlockT,
|
||||
RClient: ProvideRuntimeApi<PBlock> + Send + Sync,
|
||||
RClient::Api: ParachainHost<PBlock>,
|
||||
RBackend: Backend<PBlock>,
|
||||
RCInterface: RelayChainInterface + Clone,
|
||||
BI: BlockImport<B> + Send + Sync,
|
||||
PF: Environment<B> + Send + Sync,
|
||||
PF::Proposer: Proposer<
|
||||
@@ -229,27 +218,25 @@ where
|
||||
}
|
||||
|
||||
/// Paramaters of [`build_relay_chain_consensus`].
|
||||
pub struct BuildRelayChainConsensusParams<PF, BI, RBackend, CIDP> {
|
||||
pub struct BuildRelayChainConsensusParams<PF, BI, CIDP, RCInterface> {
|
||||
pub para_id: ParaId,
|
||||
pub proposer_factory: PF,
|
||||
pub create_inherent_data_providers: CIDP,
|
||||
pub block_import: BI,
|
||||
pub relay_chain_client: polkadot_client::Client,
|
||||
pub relay_chain_backend: Arc<RBackend>,
|
||||
pub relay_chain_interface: RCInterface,
|
||||
}
|
||||
|
||||
/// Build the [`RelayChainConsensus`].
|
||||
///
|
||||
/// Returns a boxed [`ParachainConsensus`].
|
||||
pub fn build_relay_chain_consensus<Block, PF, BI, RBackend, CIDP>(
|
||||
pub fn build_relay_chain_consensus<Block, PF, BI, CIDP, RCInterface>(
|
||||
BuildRelayChainConsensusParams {
|
||||
para_id,
|
||||
proposer_factory,
|
||||
create_inherent_data_providers,
|
||||
block_import,
|
||||
relay_chain_client,
|
||||
relay_chain_backend,
|
||||
}: BuildRelayChainConsensusParams<PF, BI, RBackend, CIDP>,
|
||||
relay_chain_interface,
|
||||
}: BuildRelayChainConsensusParams<PF, BI, CIDP, RCInterface>,
|
||||
) -> Box<dyn ParachainConsensus<Block>>
|
||||
where
|
||||
Block: BlockT,
|
||||
@@ -261,108 +248,14 @@ where
|
||||
Proof = <EnableProofRecording as ProofRecording>::Proof,
|
||||
>,
|
||||
BI: BlockImport<Block> + Send + Sync + 'static,
|
||||
RBackend: Backend<PBlock> + 'static,
|
||||
CIDP: CreateInherentDataProviders<Block, (PHash, PersistedValidationData)> + 'static,
|
||||
RCInterface: RelayChainInterface + Clone + 'static,
|
||||
{
|
||||
RelayChainConsensusBuilder::new(
|
||||
Box::new(RelayChainConsensus::new(
|
||||
para_id,
|
||||
proposer_factory,
|
||||
block_import,
|
||||
create_inherent_data_providers,
|
||||
relay_chain_client,
|
||||
relay_chain_backend,
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
/// Relay chain consensus builder.
|
||||
///
|
||||
/// Builds a [`RelayChainConsensus`] for a parachain. As this requires
|
||||
/// a concrete relay chain client instance, the builder takes a [`polkadot_client::Client`]
|
||||
/// that wraps this concrete instanace. By using [`polkadot_client::ExecuteWithClient`]
|
||||
/// the builder gets access to this concrete instance.
|
||||
struct RelayChainConsensusBuilder<Block, PF, BI, RBackend, CIDP> {
|
||||
para_id: ParaId,
|
||||
_phantom: PhantomData<Block>,
|
||||
proposer_factory: PF,
|
||||
create_inherent_data_providers: CIDP,
|
||||
block_import: BI,
|
||||
relay_chain_backend: Arc<RBackend>,
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
}
|
||||
|
||||
impl<Block, PF, BI, RBackend, CIDP> RelayChainConsensusBuilder<Block, PF, BI, RBackend, CIDP>
|
||||
where
|
||||
Block: BlockT,
|
||||
PF: Environment<Block> + Send + Sync + 'static,
|
||||
PF::Proposer: Proposer<
|
||||
Block,
|
||||
Transaction = BI::Transaction,
|
||||
ProofRecording = EnableProofRecording,
|
||||
Proof = <EnableProofRecording as ProofRecording>::Proof,
|
||||
>,
|
||||
BI: BlockImport<Block> + Send + Sync + 'static,
|
||||
RBackend: Backend<PBlock> + 'static,
|
||||
CIDP: CreateInherentDataProviders<Block, (PHash, PersistedValidationData)> + 'static,
|
||||
{
|
||||
/// Create a new instance of the builder.
|
||||
fn new(
|
||||
para_id: ParaId,
|
||||
proposer_factory: PF,
|
||||
block_import: BI,
|
||||
create_inherent_data_providers: CIDP,
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
relay_chain_backend: Arc<RBackend>,
|
||||
) -> Self {
|
||||
Self {
|
||||
para_id,
|
||||
_phantom: PhantomData,
|
||||
proposer_factory,
|
||||
block_import,
|
||||
create_inherent_data_providers,
|
||||
relay_chain_backend,
|
||||
relay_chain_client,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the relay chain consensus.
|
||||
fn build(self) -> Box<dyn ParachainConsensus<Block>> {
|
||||
self.relay_chain_client.clone().execute_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block, PF, BI, RBackend, CIDP> polkadot_client::ExecuteWithClient
|
||||
for RelayChainConsensusBuilder<Block, PF, BI, RBackend, CIDP>
|
||||
where
|
||||
Block: BlockT,
|
||||
PF: Environment<Block> + Send + Sync + 'static,
|
||||
PF::Proposer: Proposer<
|
||||
Block,
|
||||
Transaction = BI::Transaction,
|
||||
ProofRecording = EnableProofRecording,
|
||||
Proof = <EnableProofRecording as ProofRecording>::Proof,
|
||||
>,
|
||||
BI: BlockImport<Block> + Send + Sync + 'static,
|
||||
RBackend: Backend<PBlock> + 'static,
|
||||
CIDP: CreateInherentDataProviders<Block, (PHash, PersistedValidationData)> + 'static,
|
||||
{
|
||||
type Output = Box<dyn ParachainConsensus<Block>>;
|
||||
|
||||
fn execute_with_client<PClient, Api, PBackend>(self, client: Arc<PClient>) -> Self::Output
|
||||
where
|
||||
<Api as sp_api::ApiExt<PBlock>>::StateBackend: sp_api::StateBackend<HashFor<PBlock>>,
|
||||
PBackend: Backend<PBlock>,
|
||||
PBackend::State: sp_api::StateBackend<sp_runtime::traits::BlakeTwo256>,
|
||||
Api: polkadot_client::RuntimeApiCollection<StateBackend = PBackend::State>,
|
||||
PClient: polkadot_client::AbstractClient<PBlock, PBackend, Api = Api> + 'static,
|
||||
{
|
||||
Box::new(RelayChainConsensus::new(
|
||||
self.para_id,
|
||||
self.proposer_factory,
|
||||
self.create_inherent_data_providers,
|
||||
self.block_import,
|
||||
client.clone(),
|
||||
self.relay_chain_backend,
|
||||
))
|
||||
}
|
||||
block_import,
|
||||
relay_chain_interface,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "cumulus-client-network"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Cumulus-specific networking protocol"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Substrate deps
|
||||
@@ -13,20 +13,23 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
# Polkadot deps
|
||||
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-node-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
cumulus-relay-chain-interface = { path = "../relay-chain-interface" }
|
||||
|
||||
# other deps
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] }
|
||||
futures = { version = "0.3.1", features = ["compat"] }
|
||||
futures-timer = "3.0.2"
|
||||
tracing = "0.1.22"
|
||||
parking_lot = "0.10.2"
|
||||
parking_lot = "0.11.1"
|
||||
derive_more = "0.99.2"
|
||||
async-trait = "0.1.52"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.10", features = ["macros"] }
|
||||
@@ -34,9 +37,12 @@ tokio = { version = "1.10", features = ["macros"] }
|
||||
# Cumulus deps
|
||||
cumulus-test-service = { path = "../../test/service" }
|
||||
cumulus-primitives-core = { path = "../../primitives/core" }
|
||||
cumulus-relay-chain-local = { path = "../relay-chain-local" }
|
||||
|
||||
# Polkadot deps
|
||||
polkadot-test-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
# substrate deps
|
||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
+38
-153
@@ -20,12 +20,8 @@
|
||||
//! that use the relay chain provided consensus. See [`BlockAnnounceValidator`]
|
||||
//! and [`WaitToAnnounce`] for more information about this implementation.
|
||||
|
||||
use sc_client_api::{Backend, BlockchainEvents};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::{
|
||||
block_validation::{BlockAnnounceValidator as BlockAnnounceValidatorT, Validation},
|
||||
SyncOracle,
|
||||
use sp_consensus::block_validation::{
|
||||
BlockAnnounceValidator as BlockAnnounceValidatorT, Validation,
|
||||
};
|
||||
use sp_core::traits::SpawnNamed;
|
||||
use sp_runtime::{
|
||||
@@ -33,12 +29,12 @@ use sp_runtime::{
|
||||
traits::{Block as BlockT, Header as HeaderT},
|
||||
};
|
||||
|
||||
use polkadot_client::ClientHandle;
|
||||
use cumulus_relay_chain_interface::RelayChainInterface;
|
||||
use polkadot_node_primitives::{CollationSecondedSignal, Statement};
|
||||
use polkadot_parachain::primitives::HeadData;
|
||||
use polkadot_primitives::v1::{
|
||||
Block as PBlock, CandidateReceipt, CompactStatement, Hash as PHash, Id as ParaId,
|
||||
OccupiedCoreAssumption, ParachainHost, SigningContext, UncheckedSigned,
|
||||
OccupiedCoreAssumption, SigningContext, UncheckedSigned,
|
||||
};
|
||||
|
||||
use codec::{Decode, DecodeAll, Encode};
|
||||
@@ -50,11 +46,8 @@ use futures::{
|
||||
|
||||
use std::{convert::TryFrom, fmt, marker::PhantomData, pin::Pin, sync::Arc};
|
||||
|
||||
use wait_on_relay_chain_block::WaitOnRelayChainBlock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod wait_on_relay_chain_block;
|
||||
|
||||
const LOG_TARGET: &str = "sync::cumulus";
|
||||
|
||||
@@ -135,19 +128,18 @@ impl BlockAnnounceData {
|
||||
/// Check the signature of the statement.
|
||||
///
|
||||
/// Returns an `Err(_)` if it failed.
|
||||
fn check_signature<P>(
|
||||
fn check_signature<RCInterface>(
|
||||
self,
|
||||
relay_chain_client: &Arc<P>,
|
||||
relay_chain_client: &RCInterface,
|
||||
) -> Result<Validation, BlockAnnounceError>
|
||||
where
|
||||
P: ProvideRuntimeApi<PBlock> + Send + Sync + 'static,
|
||||
P::Api: ParachainHost<PBlock>,
|
||||
RCInterface: RelayChainInterface + 'static,
|
||||
{
|
||||
let runtime_api = relay_chain_client.runtime_api();
|
||||
let validator_index = self.statement.unchecked_validator_index();
|
||||
|
||||
let runtime_api_block_id = BlockId::Hash(self.relay_parent);
|
||||
let session_index = match runtime_api.session_index_for_child(&runtime_api_block_id) {
|
||||
let session_index = match relay_chain_client.session_index_for_child(&runtime_api_block_id)
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))),
|
||||
};
|
||||
@@ -155,7 +147,7 @@ impl BlockAnnounceData {
|
||||
let signing_context = SigningContext { parent_hash: self.relay_parent, session_index };
|
||||
|
||||
// Check that the signer is a legit validator.
|
||||
let authorities = match runtime_api.validators(&runtime_api_block_id) {
|
||||
let authorities = match relay_chain_client.validators(&runtime_api_block_id) {
|
||||
Ok(r) => r,
|
||||
Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))),
|
||||
};
|
||||
@@ -230,52 +222,37 @@ impl TryFrom<&'_ CollationSecondedSignal> for BlockAnnounceData {
|
||||
/// chain. If it is at the tip, it is required to provide a justification or otherwise we reject
|
||||
/// it. However, if the announcement is for a block below the tip the announcement is accepted
|
||||
/// as it probably comes from a node that is currently syncing the chain.
|
||||
pub struct BlockAnnounceValidator<Block, R, B, BCE> {
|
||||
pub struct BlockAnnounceValidator<Block, RCInterface> {
|
||||
phantom: PhantomData<Block>,
|
||||
relay_chain_client: Arc<R>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
relay_chain_interface: RCInterface,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
wait_on_relay_chain_block: WaitOnRelayChainBlock<B, BCE>,
|
||||
}
|
||||
|
||||
impl<Block, R, B, BCE> BlockAnnounceValidator<Block, R, B, BCE> {
|
||||
impl<Block, RCInterface> BlockAnnounceValidator<Block, RCInterface>
|
||||
where
|
||||
RCInterface: Clone,
|
||||
{
|
||||
/// Create a new [`BlockAnnounceValidator`].
|
||||
pub fn new(
|
||||
relay_chain_client: Arc<R>,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
relay_chain_blockchain_events: Arc<BCE>,
|
||||
) -> Self {
|
||||
pub fn new(relay_chain_interface: RCInterface, para_id: ParaId) -> Self {
|
||||
Self {
|
||||
phantom: Default::default(),
|
||||
relay_chain_client,
|
||||
relay_chain_interface: relay_chain_interface.clone(),
|
||||
para_id,
|
||||
relay_chain_sync_oracle,
|
||||
relay_chain_backend: relay_chain_backend.clone(),
|
||||
wait_on_relay_chain_block: WaitOnRelayChainBlock::new(
|
||||
relay_chain_backend,
|
||||
relay_chain_blockchain_events,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT, R, B, BCE> BlockAnnounceValidator<Block, R, B, BCE>
|
||||
impl<Block: BlockT, RCInterface> BlockAnnounceValidator<Block, RCInterface>
|
||||
where
|
||||
R: ProvideRuntimeApi<PBlock> + Send + Sync + 'static,
|
||||
R::Api: ParachainHost<PBlock>,
|
||||
B: Backend<PBlock> + 'static,
|
||||
RCInterface: RelayChainInterface + Clone,
|
||||
{
|
||||
/// Get the included block of the given parachain in the relay chain.
|
||||
fn included_block(
|
||||
relay_chain_client: &R,
|
||||
relay_chain_interface: &RCInterface,
|
||||
block_id: &BlockId<PBlock>,
|
||||
para_id: ParaId,
|
||||
) -> Result<Block::Header, BoxedError> {
|
||||
let validation_data = relay_chain_client
|
||||
.runtime_api()
|
||||
let validation_data = relay_chain_interface
|
||||
.persisted_validation_data(block_id, para_id, OccupiedCoreAssumption::TimedOut)
|
||||
.map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?
|
||||
.ok_or_else(|| {
|
||||
@@ -293,12 +270,11 @@ where
|
||||
|
||||
/// Get the backed block hash of the given parachain in the relay chain.
|
||||
fn backed_block_hash(
|
||||
relay_chain_client: &R,
|
||||
relay_chain_interface: &RCInterface,
|
||||
block_id: &BlockId<PBlock>,
|
||||
para_id: ParaId,
|
||||
) -> Result<Option<PHash>, BoxedError> {
|
||||
let candidate_receipt = relay_chain_client
|
||||
.runtime_api()
|
||||
let candidate_receipt = relay_chain_interface
|
||||
.candidate_pending_availability(block_id, para_id)
|
||||
.map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?;
|
||||
|
||||
@@ -310,21 +286,20 @@ where
|
||||
&self,
|
||||
header: Block::Header,
|
||||
) -> impl Future<Output = Result<Validation, BoxedError>> {
|
||||
let relay_chain_client = self.relay_chain_client.clone();
|
||||
let relay_chain_backend = self.relay_chain_backend.clone();
|
||||
let relay_chain_interface = self.relay_chain_interface.clone();
|
||||
let para_id = self.para_id;
|
||||
|
||||
async move {
|
||||
// Check if block is equal or higher than best (this requires a justification)
|
||||
let relay_chain_info = relay_chain_backend.blockchain().info();
|
||||
let runtime_api_block_id = BlockId::Hash(relay_chain_info.best_hash);
|
||||
let relay_chain_best_hash = relay_chain_interface.best_block_hash();
|
||||
let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash);
|
||||
let block_number = header.number();
|
||||
|
||||
let best_head =
|
||||
Self::included_block(&*relay_chain_client, &runtime_api_block_id, para_id)?;
|
||||
Self::included_block(&relay_chain_interface, &runtime_api_block_id, para_id)?;
|
||||
let known_best_number = best_head.number();
|
||||
let backed_block =
|
||||
|| Self::backed_block_hash(&*relay_chain_client, &runtime_api_block_id, para_id);
|
||||
|| Self::backed_block_hash(&relay_chain_interface, &runtime_api_block_id, para_id);
|
||||
|
||||
if best_head == header {
|
||||
tracing::debug!(target: LOG_TARGET, "Announced block matches best block.",);
|
||||
@@ -348,20 +323,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT, P, B, BCE> BlockAnnounceValidatorT<Block>
|
||||
for BlockAnnounceValidator<Block, P, B, BCE>
|
||||
impl<Block: BlockT, RCInterface> BlockAnnounceValidatorT<Block>
|
||||
for BlockAnnounceValidator<Block, RCInterface>
|
||||
where
|
||||
P: ProvideRuntimeApi<PBlock> + Send + Sync + 'static,
|
||||
P::Api: ParachainHost<PBlock>,
|
||||
B: Backend<PBlock> + 'static,
|
||||
BCE: BlockchainEvents<PBlock> + 'static + Send + Sync,
|
||||
RCInterface: RelayChainInterface + Clone + 'static,
|
||||
{
|
||||
fn validate(
|
||||
&mut self,
|
||||
header: &Block::Header,
|
||||
mut data: &[u8],
|
||||
) -> Pin<Box<dyn Future<Output = Result<Validation, BoxedError>> + Send>> {
|
||||
if self.relay_chain_sync_oracle.is_major_syncing() {
|
||||
if self.relay_chain_interface.is_major_syncing() {
|
||||
return ready(Ok(Validation::Success { is_new_best: false })).boxed()
|
||||
}
|
||||
|
||||
@@ -381,9 +353,8 @@ where
|
||||
.boxed(),
|
||||
};
|
||||
|
||||
let relay_chain_client = self.relay_chain_client.clone();
|
||||
let relay_chain_interface = self.relay_chain_interface.clone();
|
||||
let header_encoded = header.encode();
|
||||
let wait_on_relay_chain_block = self.wait_on_relay_chain_block.clone();
|
||||
|
||||
async move {
|
||||
if let Err(e) = block_announce_data.validate(header_encoded) {
|
||||
@@ -392,106 +363,19 @@ where
|
||||
|
||||
let relay_parent = block_announce_data.receipt.descriptor.relay_parent;
|
||||
|
||||
wait_on_relay_chain_block
|
||||
.wait_on_relay_chain_block(relay_parent)
|
||||
relay_chain_interface
|
||||
.wait_for_block(relay_parent)
|
||||
.await
|
||||
.map_err(|e| Box::new(BlockAnnounceError(e.to_string())) as Box<_>)?;
|
||||
|
||||
block_announce_data
|
||||
.check_signature(&relay_chain_client)
|
||||
.check_signature(&relay_chain_interface)
|
||||
.map_err(|e| Box::new(e) as Box<_>)
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a block announce validator instance.
|
||||
///
|
||||
/// Returns a boxed [`BlockAnnounceValidator`].
|
||||
pub fn build_block_announce_validator<Block: BlockT, B>(
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
) -> Box<dyn BlockAnnounceValidatorT<Block> + Send>
|
||||
where
|
||||
B: Backend<PBlock> + Send + 'static,
|
||||
{
|
||||
BlockAnnounceValidatorBuilder::new(
|
||||
relay_chain_client,
|
||||
para_id,
|
||||
relay_chain_sync_oracle,
|
||||
relay_chain_backend,
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
/// Block announce validator builder.
|
||||
///
|
||||
/// Builds a [`BlockAnnounceValidator`] for a parachain. As this requires
|
||||
/// a concrete relay chain client instance, the builder takes a [`polkadot_client::Client`]
|
||||
/// that wraps this concrete instanace. By using [`polkadot_client::ExecuteWithClient`]
|
||||
/// the builder gets access to this concrete instance.
|
||||
struct BlockAnnounceValidatorBuilder<Block, B> {
|
||||
phantom: PhantomData<Block>,
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT, B> BlockAnnounceValidatorBuilder<Block, B>
|
||||
where
|
||||
B: Backend<PBlock> + Send + 'static,
|
||||
{
|
||||
/// Create a new instance of the builder.
|
||||
fn new(
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
) -> Self {
|
||||
Self {
|
||||
relay_chain_client,
|
||||
para_id,
|
||||
relay_chain_sync_oracle,
|
||||
relay_chain_backend,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the block announce validator.
|
||||
fn build(self) -> Box<dyn BlockAnnounceValidatorT<Block> + Send> {
|
||||
self.relay_chain_client.clone().execute_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT, B> polkadot_client::ExecuteWithClient
|
||||
for BlockAnnounceValidatorBuilder<Block, B>
|
||||
where
|
||||
B: Backend<PBlock> + Send + 'static,
|
||||
{
|
||||
type Output = Box<dyn BlockAnnounceValidatorT<Block> + Send>;
|
||||
|
||||
fn execute_with_client<PClient, Api, PBackend>(self, client: Arc<PClient>) -> Self::Output
|
||||
where
|
||||
<Api as sp_api::ApiExt<PBlock>>::StateBackend:
|
||||
sp_api::StateBackend<sp_runtime::traits::BlakeTwo256>,
|
||||
PBackend: Backend<PBlock>,
|
||||
PBackend::State: sp_api::StateBackend<sp_runtime::traits::BlakeTwo256>,
|
||||
Api: polkadot_client::RuntimeApiCollection<StateBackend = PBackend::State>,
|
||||
PClient: polkadot_client::AbstractClient<PBlock, PBackend, Api = Api> + 'static,
|
||||
{
|
||||
Box::new(BlockAnnounceValidator::new(
|
||||
client.clone(),
|
||||
self.para_id,
|
||||
self.relay_chain_sync_oracle,
|
||||
self.relay_chain_backend,
|
||||
client,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait before announcing a block that a candidate message has been received for this block, then
|
||||
/// add this message as justification for the block announcement.
|
||||
///
|
||||
@@ -522,6 +406,7 @@ impl<Block: BlockT> WaitToAnnounce<Block> {
|
||||
|
||||
self.spawner.spawn(
|
||||
"cumulus-wait-to-announce",
|
||||
None,
|
||||
async move {
|
||||
tracing::debug!(
|
||||
target: "cumulus-network",
|
||||
|
||||
+215
-156
@@ -15,29 +15,33 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
use async_trait::async_trait;
|
||||
use cumulus_relay_chain_interface::WaitError;
|
||||
use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus};
|
||||
use cumulus_test_service::runtime::{Block, Hash, Header};
|
||||
use futures::{executor::block_on, poll, task::Poll};
|
||||
use futures::{executor::block_on, poll, task::Poll, FutureExt, StreamExt};
|
||||
use parking_lot::Mutex;
|
||||
use polkadot_node_primitives::{SignedFullStatement, Statement};
|
||||
use polkadot_primitives::v1::{
|
||||
Block as PBlock, BlockNumber, CandidateCommitments, CandidateDescriptor, CandidateEvent,
|
||||
CommittedCandidateReceipt, CoreState, GroupRotationInfo, Hash as PHash, HeadData, Id as ParaId,
|
||||
InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, ParachainHost,
|
||||
PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, SigningContext,
|
||||
ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex,
|
||||
Block as PBlock, CandidateCommitments, CandidateDescriptor, CollatorPair,
|
||||
CommittedCandidateReceipt, Hash as PHash, HeadData, Id as ParaId, InboundDownwardMessage,
|
||||
InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, SessionIndex,
|
||||
SigningContext, ValidationCodeHash, ValidatorId,
|
||||
};
|
||||
use polkadot_service::Handle;
|
||||
use polkadot_test_client::{
|
||||
Client as PClient, ClientBlockImportExt, DefaultTestClientBuilderExt, FullBackend as PBackend,
|
||||
InitPolkadotBlockBuilder, TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
use sp_api::{ApiRef, ProvideRuntimeApi};
|
||||
use sc_client_api::{Backend, BlockchainEvents};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_core::H256;
|
||||
use sp_core::{Pair, H256};
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr};
|
||||
use sp_runtime::RuntimeAppPublic;
|
||||
use std::collections::BTreeMap;
|
||||
use sp_state_machine::StorageValue;
|
||||
use std::{collections::BTreeMap, time::Duration};
|
||||
|
||||
fn check_error(error: crate::BoxedError, check_error: impl Fn(&BlockAnnounceError) -> bool) {
|
||||
let error = *error
|
||||
@@ -49,31 +53,190 @@ fn check_error(error: crate::BoxedError, check_error: impl Fn(&BlockAnnounceErro
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct DummyCollatorNetwork;
|
||||
struct DummyRelayChainInterface {
|
||||
data: Arc<Mutex<ApiData>>,
|
||||
relay_client: Arc<PClient>,
|
||||
relay_backend: Arc<PBackend>,
|
||||
}
|
||||
|
||||
impl SyncOracle for DummyCollatorNetwork {
|
||||
fn is_major_syncing(&mut self) -> bool {
|
||||
impl DummyRelayChainInterface {
|
||||
fn new() -> Self {
|
||||
let builder = TestClientBuilder::new();
|
||||
let relay_backend = builder.backend();
|
||||
|
||||
Self {
|
||||
data: Arc::new(Mutex::new(ApiData {
|
||||
validators: vec![Sr25519Keyring::Alice.public().into()],
|
||||
has_pending_availability: false,
|
||||
})),
|
||||
relay_client: Arc::new(builder.build()),
|
||||
relay_backend,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl RelayChainInterface for DummyRelayChainInterface {
|
||||
fn validators(
|
||||
&self,
|
||||
_: &cumulus_primitives_core::relay_chain::BlockId,
|
||||
) -> Result<Vec<ValidatorId>, sp_api::ApiError> {
|
||||
Ok(self.data.lock().validators.clone())
|
||||
}
|
||||
|
||||
fn block_status(
|
||||
&self,
|
||||
block_id: cumulus_primitives_core::relay_chain::BlockId,
|
||||
) -> Result<sp_blockchain::BlockStatus, sp_blockchain::Error> {
|
||||
self.relay_backend.blockchain().status(block_id)
|
||||
}
|
||||
|
||||
fn best_block_hash(&self) -> PHash {
|
||||
self.relay_backend.blockchain().info().best_hash
|
||||
}
|
||||
|
||||
fn retrieve_dmq_contents(&self, _: ParaId, _: PHash) -> Option<Vec<InboundDownwardMessage>> {
|
||||
unimplemented!("Not needed for test")
|
||||
}
|
||||
|
||||
fn retrieve_all_inbound_hrmp_channel_contents(
|
||||
&self,
|
||||
_: ParaId,
|
||||
_: PHash,
|
||||
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
|
||||
Some(BTreeMap::new())
|
||||
}
|
||||
|
||||
fn persisted_validation_data(
|
||||
&self,
|
||||
_: &cumulus_primitives_core::relay_chain::BlockId,
|
||||
_: ParaId,
|
||||
_: OccupiedCoreAssumption,
|
||||
) -> Result<Option<PersistedValidationData>, sp_api::ApiError> {
|
||||
Ok(Some(PersistedValidationData {
|
||||
parent_head: HeadData(default_header().encode()),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
|
||||
fn candidate_pending_availability(
|
||||
&self,
|
||||
_: &cumulus_primitives_core::relay_chain::BlockId,
|
||||
_: ParaId,
|
||||
) -> Result<Option<CommittedCandidateReceipt>, sp_api::ApiError> {
|
||||
if self.data.lock().has_pending_availability {
|
||||
Ok(Some(CommittedCandidateReceipt {
|
||||
descriptor: CandidateDescriptor {
|
||||
para_head: polkadot_parachain::primitives::HeadData(default_header().encode())
|
||||
.hash(),
|
||||
para_id: 0u32.into(),
|
||||
relay_parent: PHash::random(),
|
||||
collator: CollatorPair::generate().0.public(),
|
||||
persisted_validation_data_hash: PHash::random().into(),
|
||||
pov_hash: PHash::random(),
|
||||
erasure_root: PHash::random(),
|
||||
signature: sp_core::sr25519::Signature([0u8; 64]).into(),
|
||||
validation_code_hash: ValidationCodeHash::from(PHash::random()),
|
||||
},
|
||||
commitments: CandidateCommitments {
|
||||
upward_messages: Vec::new(),
|
||||
horizontal_messages: Vec::new(),
|
||||
new_validation_code: None,
|
||||
head_data: HeadData(Vec::new()),
|
||||
processed_downward_messages: 0,
|
||||
hrmp_watermark: 0,
|
||||
},
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn session_index_for_child(
|
||||
&self,
|
||||
_: &cumulus_primitives_core::relay_chain::BlockId,
|
||||
) -> Result<SessionIndex, sp_api::ApiError> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn import_notification_stream(&self) -> sc_client_api::ImportNotifications<PBlock> {
|
||||
self.relay_client.import_notification_stream()
|
||||
}
|
||||
|
||||
fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications<PBlock> {
|
||||
self.relay_client.finality_notification_stream()
|
||||
}
|
||||
|
||||
fn storage_changes_notification_stream(
|
||||
&self,
|
||||
filter_keys: Option<&[sc_client_api::StorageKey]>,
|
||||
child_filter_keys: Option<
|
||||
&[(sc_client_api::StorageKey, Option<Vec<sc_client_api::StorageKey>>)],
|
||||
>,
|
||||
) -> sc_client_api::blockchain::Result<sc_client_api::StorageEventStream<PHash>> {
|
||||
self.relay_client
|
||||
.storage_changes_notification_stream(filter_keys, child_filter_keys)
|
||||
}
|
||||
|
||||
fn is_major_syncing(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn is_offline(&mut self) -> bool {
|
||||
unimplemented!("Not required in tests")
|
||||
fn overseer_handle(&self) -> Option<Handle> {
|
||||
unimplemented!("Not needed for test")
|
||||
}
|
||||
|
||||
fn get_storage_by_key(
|
||||
&self,
|
||||
_: &polkadot_service::BlockId,
|
||||
_: &[u8],
|
||||
) -> Result<Option<StorageValue>, sp_blockchain::Error> {
|
||||
unimplemented!("Not needed for test")
|
||||
}
|
||||
|
||||
fn prove_read(
|
||||
&self,
|
||||
_: &polkadot_service::BlockId,
|
||||
_: &Vec<Vec<u8>>,
|
||||
) -> Result<Option<sc_client_api::StorageProof>, Box<dyn sp_state_machine::Error>> {
|
||||
unimplemented!("Not needed for test")
|
||||
}
|
||||
|
||||
async fn wait_for_block(
|
||||
&self,
|
||||
hash: PHash,
|
||||
) -> Result<(), cumulus_relay_chain_interface::WaitError> {
|
||||
let mut listener = match check_block_in_chain(
|
||||
self.relay_backend.clone(),
|
||||
self.relay_client.clone(),
|
||||
hash,
|
||||
)? {
|
||||
BlockCheckStatus::InChain => return Ok(()),
|
||||
BlockCheckStatus::Unknown(listener) => listener,
|
||||
};
|
||||
|
||||
let mut timeout = futures_timer::Delay::new(Duration::from_secs(10)).fuse();
|
||||
|
||||
loop {
|
||||
futures::select! {
|
||||
_ = timeout => return Err(WaitError::Timeout(hash)),
|
||||
evt = listener.next() => match evt {
|
||||
Some(evt) if evt.hash == hash => return Ok(()),
|
||||
// Not the event we waited on.
|
||||
Some(_) => continue,
|
||||
None => return Err(WaitError::ImportListenerClosed(hash)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_validator_and_api(
|
||||
) -> (BlockAnnounceValidator<Block, TestApi, PBackend, PClient>, Arc<TestApi>) {
|
||||
let api = Arc::new(TestApi::new());
|
||||
|
||||
) -> (BlockAnnounceValidator<Block, Arc<DummyRelayChainInterface>>, Arc<DummyRelayChainInterface>) {
|
||||
let relay_chain_interface = Arc::new(DummyRelayChainInterface::new());
|
||||
(
|
||||
BlockAnnounceValidator::new(
|
||||
api.clone(),
|
||||
ParaId::from(56),
|
||||
Box::new(DummyCollatorNetwork),
|
||||
api.relay_backend.clone(),
|
||||
api.relay_client.clone(),
|
||||
),
|
||||
api,
|
||||
BlockAnnounceValidator::new(relay_chain_interface.clone(), ParaId::from(56)),
|
||||
relay_chain_interface,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -89,7 +252,7 @@ fn default_header() -> Header {
|
||||
|
||||
/// Same as [`make_gossip_message_and_header`], but using the genesis header as relay parent.
|
||||
async fn make_gossip_message_and_header_using_genesis(
|
||||
api: Arc<TestApi>,
|
||||
api: Arc<DummyRelayChainInterface>,
|
||||
validator_index: u32,
|
||||
) -> (CollationSecondedSignal, Header) {
|
||||
let relay_parent = api.relay_client.hash(0).ok().flatten().expect("Genesis hash exists");
|
||||
@@ -98,7 +261,7 @@ async fn make_gossip_message_and_header_using_genesis(
|
||||
}
|
||||
|
||||
async fn make_gossip_message_and_header(
|
||||
api: Arc<TestApi>,
|
||||
relay_chain_interface: Arc<DummyRelayChainInterface>,
|
||||
relay_parent: H256,
|
||||
validator_index: u32,
|
||||
) -> (CollationSecondedSignal, Header) {
|
||||
@@ -109,8 +272,9 @@ async fn make_gossip_message_and_header(
|
||||
Some(&Sr25519Keyring::Alice.to_seed()),
|
||||
)
|
||||
.unwrap();
|
||||
let session_index =
|
||||
api.runtime_api().session_index_for_child(&BlockId::Hash(relay_parent)).unwrap();
|
||||
let session_index = relay_chain_interface
|
||||
.session_index_for_child(&BlockId::Hash(relay_parent))
|
||||
.unwrap();
|
||||
let signing_context = SigningContext { parent_hash: relay_parent, session_index };
|
||||
|
||||
let header = default_header();
|
||||
@@ -120,9 +284,15 @@ async fn make_gossip_message_and_header(
|
||||
..Default::default()
|
||||
},
|
||||
descriptor: CandidateDescriptor {
|
||||
para_id: 0u32.into(),
|
||||
relay_parent,
|
||||
collator: CollatorPair::generate().0.public(),
|
||||
persisted_validation_data_hash: PHash::random().into(),
|
||||
pov_hash: PHash::random(),
|
||||
erasure_root: PHash::random(),
|
||||
signature: sp_core::sr25519::Signature([0u8; 64]).into(),
|
||||
para_head: polkadot_parachain::primitives::HeadData(header.encode()).hash(),
|
||||
..Default::default()
|
||||
validation_code_hash: ValidationCodeHash::from(PHash::random()),
|
||||
},
|
||||
};
|
||||
let statement = Statement::Seconded(candidate_receipt);
|
||||
@@ -285,8 +455,7 @@ fn check_statement_seconded() {
|
||||
Some(&Sr25519Keyring::Alice.to_seed()),
|
||||
)
|
||||
.unwrap();
|
||||
let session_index =
|
||||
api.runtime_api().session_index_for_child(&BlockId::Hash(relay_parent)).unwrap();
|
||||
let session_index = api.session_index_for_child(&BlockId::Hash(relay_parent)).unwrap();
|
||||
let signing_context = SigningContext { parent_hash: relay_parent, session_index };
|
||||
|
||||
let statement = Statement::Valid(Default::default());
|
||||
@@ -303,7 +472,20 @@ fn check_statement_seconded() {
|
||||
.expect("Signs statement");
|
||||
|
||||
let data = BlockAnnounceData {
|
||||
receipt: Default::default(),
|
||||
receipt: CandidateReceipt {
|
||||
commitments_hash: PHash::random(),
|
||||
descriptor: CandidateDescriptor {
|
||||
para_head: HeadData(Vec::new()).hash(),
|
||||
para_id: 0u32.into(),
|
||||
relay_parent: PHash::random(),
|
||||
collator: CollatorPair::generate().0.public(),
|
||||
persisted_validation_data_hash: PHash::random().into(),
|
||||
pov_hash: PHash::random(),
|
||||
erasure_root: PHash::random(),
|
||||
signature: sp_core::sr25519::Signature([0u8; 64]).into(),
|
||||
validation_code_hash: ValidationCodeHash::from(PHash::random()),
|
||||
},
|
||||
},
|
||||
statement: signed_statement.convert_payload().into(),
|
||||
relay_parent,
|
||||
}
|
||||
@@ -377,126 +559,3 @@ struct ApiData {
|
||||
validators: Vec<ValidatorId>,
|
||||
has_pending_availability: bool,
|
||||
}
|
||||
|
||||
struct TestApi {
|
||||
data: Arc<Mutex<ApiData>>,
|
||||
relay_client: Arc<PClient>,
|
||||
relay_backend: Arc<PBackend>,
|
||||
}
|
||||
|
||||
impl TestApi {
|
||||
fn new() -> Self {
|
||||
let builder = TestClientBuilder::new();
|
||||
let relay_backend = builder.backend();
|
||||
|
||||
Self {
|
||||
data: Arc::new(Mutex::new(ApiData {
|
||||
validators: vec![Sr25519Keyring::Alice.public().into()],
|
||||
has_pending_availability: false,
|
||||
})),
|
||||
relay_client: Arc::new(builder.build()),
|
||||
relay_backend,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct RuntimeApi {
|
||||
data: Arc<Mutex<ApiData>>,
|
||||
}
|
||||
|
||||
impl ProvideRuntimeApi<PBlock> for TestApi {
|
||||
type Api = RuntimeApi;
|
||||
|
||||
fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> {
|
||||
RuntimeApi { data: self.data.clone() }.into()
|
||||
}
|
||||
}
|
||||
|
||||
sp_api::mock_impl_runtime_apis! {
|
||||
impl ParachainHost<PBlock> for RuntimeApi {
|
||||
fn validators(&self) -> Vec<ValidatorId> {
|
||||
self.data.lock().validators.clone()
|
||||
}
|
||||
|
||||
fn validator_groups(&self) -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo<BlockNumber>) {
|
||||
(Vec::new(), GroupRotationInfo { session_start_block: 0, group_rotation_frequency: 0, now: 0 })
|
||||
}
|
||||
|
||||
fn availability_cores(&self) -> Vec<CoreState<PHash>> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn persisted_validation_data(
|
||||
&self,
|
||||
_: ParaId,
|
||||
_: OccupiedCoreAssumption,
|
||||
) -> Option<PersistedValidationData<PHash, BlockNumber>> {
|
||||
Some(PersistedValidationData {
|
||||
parent_head: HeadData(default_header().encode()),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn session_index_for_child(&self) -> SessionIndex {
|
||||
0
|
||||
}
|
||||
|
||||
fn validation_code(&self, _: ParaId, _: OccupiedCoreAssumption) -> Option<ValidationCode> {
|
||||
None
|
||||
}
|
||||
|
||||
fn candidate_pending_availability(&self, _: ParaId) -> Option<CommittedCandidateReceipt<PHash>> {
|
||||
if self.data.lock().has_pending_availability {
|
||||
Some(CommittedCandidateReceipt {
|
||||
descriptor: CandidateDescriptor {
|
||||
para_head: polkadot_parachain::primitives::HeadData(
|
||||
default_header().encode(),
|
||||
).hash(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn candidate_events(&self) -> Vec<CandidateEvent<PHash>> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn session_info(_: SessionIndex) -> Option<SessionInfo> {
|
||||
None
|
||||
}
|
||||
|
||||
fn check_validation_outputs(_: ParaId, _: CandidateCommitments) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn dmq_contents(_: ParaId) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn inbound_hrmp_channels_contents(
|
||||
_: ParaId,
|
||||
) -> BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>> {
|
||||
BTreeMap::new()
|
||||
}
|
||||
|
||||
fn assumed_validation_data(
|
||||
_: ParaId,
|
||||
_: Hash,
|
||||
) -> Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)> {
|
||||
None
|
||||
}
|
||||
|
||||
fn validation_code_by_hash(_: ValidationCodeHash) -> Option<ValidationCode> {
|
||||
None
|
||||
}
|
||||
|
||||
fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Provides the [`WaitOnRelayChainBlock`] type.
|
||||
|
||||
use futures::{future::ready, Future, FutureExt, StreamExt};
|
||||
use polkadot_primitives::v1::{Block as PBlock, Hash as PHash};
|
||||
use sc_client_api::{
|
||||
blockchain::{self, BlockStatus, HeaderBackend},
|
||||
Backend, BlockchainEvents,
|
||||
};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
/// The timeout in seconds after that the waiting for a block should be aborted.
|
||||
const TIMEOUT_IN_SECONDS: u64 = 6;
|
||||
|
||||
/// Custom error type used by [`WaitOnRelayChainBlock`].
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum Error {
|
||||
#[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)]
|
||||
Timeout(PHash),
|
||||
#[display(
|
||||
fmt = "Import listener closed while waiting for relay-chain block `{}` to be imported.",
|
||||
_0
|
||||
)]
|
||||
ImportListenerClosed(PHash),
|
||||
#[display(
|
||||
fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}",
|
||||
_0,
|
||||
_1
|
||||
)]
|
||||
BlockchainError(PHash, blockchain::Error),
|
||||
}
|
||||
|
||||
/// A helper to wait for a given relay chain block in an async way.
|
||||
///
|
||||
/// The caller needs to pass the hash of a block it waits for and the function will return when the
|
||||
/// block is available or an error occurred.
|
||||
///
|
||||
/// The waiting for the block is implemented as follows:
|
||||
///
|
||||
/// 1. Get a read lock on the import lock from the backend.
|
||||
///
|
||||
/// 2. Check if the block is already imported. If yes, return from the function.
|
||||
///
|
||||
/// 3. If the block isn't imported yet, add an import notification listener.
|
||||
///
|
||||
/// 4. Poll the import notification listener until the block is imported or the timeout is fired.
|
||||
///
|
||||
/// The timeout is set to 6 seconds. This should be enough time to import the block in the current
|
||||
/// round and if not, the new round of the relay chain already started anyway.
|
||||
pub struct WaitOnRelayChainBlock<B, BCE> {
|
||||
block_chain_events: Arc<BCE>,
|
||||
backend: Arc<B>,
|
||||
}
|
||||
|
||||
impl<B, BCE> Clone for WaitOnRelayChainBlock<B, BCE> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { backend: self.backend.clone(), block_chain_events: self.block_chain_events.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, BCE> WaitOnRelayChainBlock<B, BCE> {
|
||||
/// Creates a new instance of `Self`.
|
||||
pub fn new(backend: Arc<B>, block_chain_events: Arc<BCE>) -> Self {
|
||||
Self { backend, block_chain_events }
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, BCE> WaitOnRelayChainBlock<B, BCE>
|
||||
where
|
||||
B: Backend<PBlock>,
|
||||
BCE: BlockchainEvents<PBlock>,
|
||||
{
|
||||
pub fn wait_on_relay_chain_block(
|
||||
&self,
|
||||
hash: PHash,
|
||||
) -> impl Future<Output = Result<(), Error>> {
|
||||
let _lock = self.backend.get_import_lock().read();
|
||||
match self.backend.blockchain().status(BlockId::Hash(hash)) {
|
||||
Ok(BlockStatus::InChain) => return ready(Ok(())).boxed(),
|
||||
Err(err) => return ready(Err(Error::BlockchainError(hash, err))).boxed(),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
let mut listener = self.block_chain_events.import_notification_stream();
|
||||
// Now it is safe to drop the lock, even when the block is now imported, it should show
|
||||
// up in our registered listener.
|
||||
drop(_lock);
|
||||
|
||||
let mut timeout = futures_timer::Delay::new(Duration::from_secs(TIMEOUT_IN_SECONDS)).fuse();
|
||||
|
||||
async move {
|
||||
loop {
|
||||
futures::select! {
|
||||
_ = timeout => return Err(Error::Timeout(hash)),
|
||||
evt = listener.next() => match evt {
|
||||
Some(evt) if evt.hash == hash => return Ok(()),
|
||||
// Not the event we waited on.
|
||||
Some(_) => continue,
|
||||
None => return Err(Error::ImportListenerClosed(hash)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use polkadot_test_client::{
|
||||
construct_transfer_extrinsic, BlockBuilderExt, Client, ClientBlockImportExt,
|
||||
DefaultTestClientBuilderExt, ExecutionStrategy, FullBackend, InitPolkadotBlockBuilder,
|
||||
TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
|
||||
use futures::{executor::block_on, poll, task::Poll};
|
||||
|
||||
fn build_client_backend_and_block() -> (Arc<Client>, Arc<FullBackend>, PBlock) {
|
||||
let builder =
|
||||
TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::NativeWhenPossible);
|
||||
let backend = builder.backend();
|
||||
let client = Arc::new(builder.build());
|
||||
|
||||
let block_builder = client.init_polkadot_block_builder();
|
||||
let block = block_builder.build().expect("Finalizes the block").block;
|
||||
|
||||
(client, backend, block)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_directly_for_available_block() {
|
||||
let (mut client, backend, block) = build_client_backend_and_block();
|
||||
let hash = block.hash();
|
||||
|
||||
block_on(client.import(BlockOrigin::Own, block)).expect("Imports the block");
|
||||
|
||||
let wait = WaitOnRelayChainBlock::new(backend, client);
|
||||
|
||||
block_on(async move {
|
||||
// Should be ready on the first poll
|
||||
assert!(matches!(poll!(wait.wait_on_relay_chain_block(hash)), Poll::Ready(Ok(()))));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_after_block_import_notification_was_received() {
|
||||
let (mut client, backend, block) = build_client_backend_and_block();
|
||||
let hash = block.hash();
|
||||
|
||||
let wait = WaitOnRelayChainBlock::new(backend, client.clone());
|
||||
|
||||
block_on(async move {
|
||||
let mut future = wait.wait_on_relay_chain_block(hash);
|
||||
// As the block is not yet imported, the first poll should return `Pending`
|
||||
assert!(poll!(&mut future).is_pending());
|
||||
|
||||
// Import the block that should fire the notification
|
||||
client.import(BlockOrigin::Own, block).await.expect("Imports the block");
|
||||
|
||||
// Now it should have received the notification and report that the block was imported
|
||||
assert!(matches!(poll!(future), Poll::Ready(Ok(()))));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wait_for_block_time_out_when_block_is_not_imported() {
|
||||
let (client, backend, block) = build_client_backend_and_block();
|
||||
let hash = block.hash();
|
||||
|
||||
let wait = WaitOnRelayChainBlock::new(backend, client.clone());
|
||||
|
||||
assert!(matches!(block_on(wait.wait_on_relay_chain_block(hash)), Err(Error::Timeout(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn do_not_resolve_after_different_block_import_notification_was_received() {
|
||||
let (mut client, backend, block) = build_client_backend_and_block();
|
||||
let hash = block.hash();
|
||||
|
||||
let ext = construct_transfer_extrinsic(
|
||||
&*client,
|
||||
sp_keyring::Sr25519Keyring::Alice,
|
||||
sp_keyring::Sr25519Keyring::Bob,
|
||||
1000,
|
||||
);
|
||||
let mut block_builder = client.init_polkadot_block_builder();
|
||||
// Push an extrinsic to get a different block hash.
|
||||
block_builder.push_polkadot_extrinsic(ext).expect("Push extrinsic");
|
||||
let block2 = block_builder.build().expect("Build second block").block;
|
||||
let hash2 = block2.hash();
|
||||
|
||||
let wait = WaitOnRelayChainBlock::new(backend, client.clone());
|
||||
|
||||
block_on(async move {
|
||||
let mut future = wait.wait_on_relay_chain_block(hash);
|
||||
let mut future2 = wait.wait_on_relay_chain_block(hash2);
|
||||
// As the block is not yet imported, the first poll should return `Pending`
|
||||
assert!(poll!(&mut future).is_pending());
|
||||
assert!(poll!(&mut future2).is_pending());
|
||||
|
||||
// Import the block that should fire the notification
|
||||
client.import(BlockOrigin::Own, block2).await.expect("Imports the second block");
|
||||
|
||||
// The import notification of the second block should not make this one finish
|
||||
assert!(poll!(&mut future).is_pending());
|
||||
// Now it should have received the notification and report that the block was imported
|
||||
assert!(matches!(poll!(future2), Poll::Ready(Ok(()))));
|
||||
|
||||
client.import(BlockOrigin::Own, block).await.expect("Imports the first block");
|
||||
|
||||
// Now it should be ready
|
||||
assert!(matches!(poll!(future), Poll::Ready(Ok(()))));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
use cumulus_primitives_core::ParaId;
|
||||
use cumulus_test_service::{initial_head_data, run_relay_chain_validator_node, Keyring::*};
|
||||
use futures::join;
|
||||
|
||||
#[substrate_test_utils::test]
|
||||
#[ignore]
|
||||
@@ -29,7 +28,7 @@ async fn sync_blocks_from_tip_without_being_connected_to_a_collator() {
|
||||
let tokio_handle = tokio::runtime::Handle::current();
|
||||
|
||||
// start alice
|
||||
let alice = run_relay_chain_validator_node(tokio_handle.clone(), Alice, || {}, vec![]);
|
||||
let alice = run_relay_chain_validator_node(tokio_handle.clone(), Alice, || {}, Vec::new());
|
||||
|
||||
// start bob
|
||||
let bob =
|
||||
@@ -71,12 +70,4 @@ async fn sync_blocks_from_tip_without_being_connected_to_a_collator() {
|
||||
.await;
|
||||
|
||||
eve.wait_for_blocks(7).await;
|
||||
|
||||
join!(
|
||||
alice.task_manager.clean_shutdown(),
|
||||
bob.task_manager.clean_shutdown(),
|
||||
charlie.task_manager.clean_shutdown(),
|
||||
dave.task_manager.clean_shutdown(),
|
||||
eve.task_manager.clean_shutdown(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "cumulus-client-pov-recovery"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Cumulus-specific networking protocol"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Substrate deps
|
||||
@@ -22,6 +22,7 @@ polkadot-node-subsystem = { git = "https://github.com/paritytech/polkadot", bran
|
||||
|
||||
# Cumulus deps
|
||||
cumulus-primitives-core = { path = "../../primitives/core" }
|
||||
cumulus-relay-chain-interface = {path = "../relay-chain-interface"}
|
||||
|
||||
# other deps
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] }
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
|
||||
use sc_client_api::{BlockBackend, BlockchainEvents, UsageProvider};
|
||||
use sc_consensus::import_queue::{ImportQueue, IncomingBlock};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_consensus::{BlockOrigin, BlockStatus};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
@@ -54,11 +53,11 @@ use sp_runtime::{
|
||||
use polkadot_node_primitives::{AvailableData, POV_BOMB_LIMIT};
|
||||
use polkadot_overseer::Handle as OverseerHandle;
|
||||
use polkadot_primitives::v1::{
|
||||
Block as PBlock, CandidateReceipt, CommittedCandidateReceipt, Id as ParaId, ParachainHost,
|
||||
SessionIndex,
|
||||
CandidateReceipt, CommittedCandidateReceipt, Id as ParaId, SessionIndex,
|
||||
};
|
||||
|
||||
use cumulus_primitives_core::ParachainBlockData;
|
||||
use cumulus_relay_chain_interface::RelayChainInterface;
|
||||
|
||||
use codec::Decode;
|
||||
use futures::{select, stream::FuturesUnordered, Future, FutureExt, Stream, StreamExt};
|
||||
@@ -102,15 +101,14 @@ pub struct PoVRecovery<Block: BlockT, PC, IQ, RC> {
|
||||
relay_chain_slot_duration: Duration,
|
||||
parachain_client: Arc<PC>,
|
||||
parachain_import_queue: IQ,
|
||||
relay_chain_client: Arc<RC>,
|
||||
relay_chain_interface: RC,
|
||||
para_id: ParaId,
|
||||
}
|
||||
|
||||
impl<Block: BlockT, PC, IQ, RC> PoVRecovery<Block, PC, IQ, RC>
|
||||
impl<Block: BlockT, PC, IQ, RCInterface> PoVRecovery<Block, PC, IQ, RCInterface>
|
||||
where
|
||||
PC: BlockBackend<Block> + BlockchainEvents<Block> + UsageProvider<Block>,
|
||||
RC: ProvideRuntimeApi<PBlock> + BlockchainEvents<PBlock>,
|
||||
RC::Api: ParachainHost<PBlock>,
|
||||
RCInterface: RelayChainInterface + Clone,
|
||||
IQ: ImportQueue<Block>,
|
||||
{
|
||||
/// Create a new instance.
|
||||
@@ -119,7 +117,7 @@ where
|
||||
relay_chain_slot_duration: Duration,
|
||||
parachain_client: Arc<PC>,
|
||||
parachain_import_queue: IQ,
|
||||
relay_chain_client: Arc<RC>,
|
||||
relay_chain_interface: RCInterface,
|
||||
para_id: ParaId,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -130,7 +128,7 @@ where
|
||||
waiting_for_parent: HashMap::new(),
|
||||
parachain_client,
|
||||
parachain_import_queue,
|
||||
relay_chain_client,
|
||||
relay_chain_interface,
|
||||
para_id,
|
||||
}
|
||||
}
|
||||
@@ -365,7 +363,7 @@ where
|
||||
let mut imported_blocks = self.parachain_client.import_notification_stream().fuse();
|
||||
let mut finalized_blocks = self.parachain_client.finality_notification_stream().fuse();
|
||||
let pending_candidates =
|
||||
pending_candidates(self.relay_chain_client.clone(), self.para_id).fuse();
|
||||
pending_candidates(self.relay_chain_interface.clone(), self.para_id).fuse();
|
||||
futures::pin_mut!(pending_candidates);
|
||||
|
||||
loop {
|
||||
@@ -419,20 +417,15 @@ where
|
||||
}
|
||||
|
||||
/// Returns a stream over pending candidates for the parachain corresponding to `para_id`.
|
||||
fn pending_candidates<RC>(
|
||||
relay_chain_client: Arc<RC>,
|
||||
fn pending_candidates(
|
||||
relay_chain_client: impl RelayChainInterface,
|
||||
para_id: ParaId,
|
||||
) -> impl Stream<Item = (CommittedCandidateReceipt, SessionIndex)>
|
||||
where
|
||||
RC: ProvideRuntimeApi<PBlock> + BlockchainEvents<PBlock>,
|
||||
RC::Api: ParachainHost<PBlock>,
|
||||
{
|
||||
) -> impl Stream<Item = (CommittedCandidateReceipt, SessionIndex)> {
|
||||
relay_chain_client.import_notification_stream().filter_map(move |n| {
|
||||
let runtime_api = relay_chain_client.runtime_api();
|
||||
let res = runtime_api
|
||||
let res = relay_chain_client
|
||||
.candidate_pending_availability(&BlockId::hash(n.hash), para_id)
|
||||
.and_then(|pa| {
|
||||
runtime_api
|
||||
relay_chain_client
|
||||
.session_index_for_child(&BlockId::hash(n.hash))
|
||||
.map(|v| pa.map(|pa| (pa, v)))
|
||||
})
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
use cumulus_primitives_core::ParaId;
|
||||
use cumulus_test_service::{initial_head_data, Keyring::*};
|
||||
use futures::join;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Tests the PoV recovery.
|
||||
@@ -39,7 +38,7 @@ async fn pov_recovery() {
|
||||
tokio_handle.clone(),
|
||||
Alice,
|
||||
|| {},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
);
|
||||
|
||||
// Start bob
|
||||
@@ -86,11 +85,4 @@ async fn pov_recovery() {
|
||||
.await;
|
||||
|
||||
dave.wait_for_blocks(7).await;
|
||||
|
||||
join!(
|
||||
alice.task_manager.clean_shutdown(),
|
||||
bob.task_manager.clean_shutdown(),
|
||||
charlie.task_manager.clean_shutdown(),
|
||||
dave.task_manager.clean_shutdown(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
name = "cumulus-relay-chain-interface"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
cumulus-primitives-core = { path = "../../primitives/core" }
|
||||
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
parking_lot = "0.11.1"
|
||||
derive_more = "0.99.2"
|
||||
async-trait = "0.1.52"
|
||||
@@ -0,0 +1,248 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Cumulus.
|
||||
|
||||
// Cumulus is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Cumulus is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
use cumulus_primitives_core::{
|
||||
relay_chain::{
|
||||
v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId},
|
||||
Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage,
|
||||
},
|
||||
InboundDownwardMessage, ParaId, PersistedValidationData,
|
||||
};
|
||||
use polkadot_overseer::Handle as OverseerHandle;
|
||||
use sc_client_api::{blockchain::BlockStatus, StorageProof};
|
||||
|
||||
use sp_api::ApiError;
|
||||
use sp_state_machine::StorageValue;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum WaitError {
|
||||
#[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)]
|
||||
Timeout(PHash),
|
||||
#[display(
|
||||
fmt = "Import listener closed while waiting for relay-chain block `{}` to be imported.",
|
||||
_0
|
||||
)]
|
||||
ImportListenerClosed(PHash),
|
||||
#[display(
|
||||
fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}",
|
||||
_0,
|
||||
_1
|
||||
)]
|
||||
BlockchainError(PHash, sp_blockchain::Error),
|
||||
}
|
||||
|
||||
/// Trait that provides all necessary methods for interaction between collator and relay chain.
|
||||
#[async_trait]
|
||||
pub trait RelayChainInterface: Send + Sync {
|
||||
/// Fetch a storage item by key.
|
||||
fn get_storage_by_key(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
key: &[u8],
|
||||
) -> Result<Option<StorageValue>, sp_blockchain::Error>;
|
||||
|
||||
/// Fetch a vector of current validators.
|
||||
fn validators(&self, block_id: &BlockId) -> Result<Vec<ValidatorId>, ApiError>;
|
||||
|
||||
/// Get the status of a given block.
|
||||
fn block_status(&self, block_id: BlockId) -> Result<BlockStatus, sp_blockchain::Error>;
|
||||
|
||||
/// Get the hash of the current best block.
|
||||
fn best_block_hash(&self) -> PHash;
|
||||
|
||||
/// Returns the whole contents of the downward message queue for the parachain we are collating
|
||||
/// for.
|
||||
///
|
||||
/// Returns `None` in case of an error.
|
||||
fn retrieve_dmq_contents(
|
||||
&self,
|
||||
para_id: ParaId,
|
||||
relay_parent: PHash,
|
||||
) -> Option<Vec<InboundDownwardMessage>>;
|
||||
|
||||
/// Returns channels contents for each inbound HRMP channel addressed to the parachain we are
|
||||
/// collating for.
|
||||
///
|
||||
/// Empty channels are also included.
|
||||
fn retrieve_all_inbound_hrmp_channel_contents(
|
||||
&self,
|
||||
para_id: ParaId,
|
||||
relay_parent: PHash,
|
||||
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>>;
|
||||
|
||||
/// Yields the persisted validation data for the given `ParaId` along with an assumption that
|
||||
/// should be used if the para currently occupies a core.
|
||||
///
|
||||
/// Returns `None` if either the para is not registered or the assumption is `Freed`
|
||||
/// and the para already occupies a core.
|
||||
fn persisted_validation_data(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
para_id: ParaId,
|
||||
_: OccupiedCoreAssumption,
|
||||
) -> Result<Option<PersistedValidationData>, ApiError>;
|
||||
|
||||
/// Get the receipt of a candidate pending availability. This returns `Some` for any paras
|
||||
/// assigned to occupied cores in `availability_cores` and `None` otherwise.
|
||||
fn candidate_pending_availability(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
para_id: ParaId,
|
||||
) -> Result<Option<CommittedCandidateReceipt>, ApiError>;
|
||||
|
||||
/// Returns the session index expected at a child of the block.
|
||||
fn session_index_for_child(&self, block_id: &BlockId) -> Result<SessionIndex, ApiError>;
|
||||
|
||||
/// Get a stream of import block notifications.
|
||||
fn import_notification_stream(&self) -> sc_client_api::ImportNotifications<PBlock>;
|
||||
|
||||
/// Wait for a block with a given hash in the relay chain.
|
||||
///
|
||||
/// This method returns immediately on error or if the block is already
|
||||
/// reported to be in chain. Otherwise, it waits for the block to arrive.
|
||||
async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError>;
|
||||
|
||||
/// Get a stream of finality notifications.
|
||||
fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications<PBlock>;
|
||||
|
||||
/// Get a stream of storage change notifications.
|
||||
fn storage_changes_notification_stream(
|
||||
&self,
|
||||
filter_keys: Option<&[sc_client_api::StorageKey]>,
|
||||
child_filter_keys: Option<
|
||||
&[(sc_client_api::StorageKey, Option<Vec<sc_client_api::StorageKey>>)],
|
||||
>,
|
||||
) -> sc_client_api::blockchain::Result<sc_client_api::StorageEventStream<PHash>>;
|
||||
|
||||
/// Whether the synchronization service is undergoing major sync.
|
||||
/// Returns true if so.
|
||||
fn is_major_syncing(&self) -> bool;
|
||||
|
||||
/// Get a handle to the overseer.
|
||||
fn overseer_handle(&self) -> Option<OverseerHandle>;
|
||||
|
||||
/// Generate a storage read proof.
|
||||
fn prove_read(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
relevant_keys: &Vec<Vec<u8>>,
|
||||
) -> Result<Option<StorageProof>, Box<dyn sp_state_machine::Error>>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> RelayChainInterface for Arc<T>
|
||||
where
|
||||
T: RelayChainInterface + ?Sized,
|
||||
{
|
||||
fn retrieve_dmq_contents(
|
||||
&self,
|
||||
para_id: ParaId,
|
||||
relay_parent: PHash,
|
||||
) -> Option<Vec<InboundDownwardMessage>> {
|
||||
(**self).retrieve_dmq_contents(para_id, relay_parent)
|
||||
}
|
||||
|
||||
fn retrieve_all_inbound_hrmp_channel_contents(
|
||||
&self,
|
||||
para_id: ParaId,
|
||||
relay_parent: PHash,
|
||||
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
|
||||
(**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent)
|
||||
}
|
||||
|
||||
fn persisted_validation_data(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
para_id: ParaId,
|
||||
occupied_core_assumption: OccupiedCoreAssumption,
|
||||
) -> Result<Option<PersistedValidationData>, ApiError> {
|
||||
(**self).persisted_validation_data(block_id, para_id, occupied_core_assumption)
|
||||
}
|
||||
|
||||
fn candidate_pending_availability(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
para_id: ParaId,
|
||||
) -> Result<Option<CommittedCandidateReceipt>, ApiError> {
|
||||
(**self).candidate_pending_availability(block_id, para_id)
|
||||
}
|
||||
|
||||
fn session_index_for_child(&self, block_id: &BlockId) -> Result<SessionIndex, ApiError> {
|
||||
(**self).session_index_for_child(block_id)
|
||||
}
|
||||
|
||||
fn validators(&self, block_id: &BlockId) -> Result<Vec<ValidatorId>, ApiError> {
|
||||
(**self).validators(block_id)
|
||||
}
|
||||
|
||||
fn import_notification_stream(&self) -> sc_client_api::ImportNotifications<PBlock> {
|
||||
(**self).import_notification_stream()
|
||||
}
|
||||
|
||||
fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications<PBlock> {
|
||||
(**self).finality_notification_stream()
|
||||
}
|
||||
|
||||
fn storage_changes_notification_stream(
|
||||
&self,
|
||||
filter_keys: Option<&[sc_client_api::StorageKey]>,
|
||||
child_filter_keys: Option<
|
||||
&[(sc_client_api::StorageKey, Option<Vec<sc_client_api::StorageKey>>)],
|
||||
>,
|
||||
) -> sc_client_api::blockchain::Result<sc_client_api::StorageEventStream<PHash>> {
|
||||
(**self).storage_changes_notification_stream(filter_keys, child_filter_keys)
|
||||
}
|
||||
|
||||
fn best_block_hash(&self) -> PHash {
|
||||
(**self).best_block_hash()
|
||||
}
|
||||
|
||||
fn block_status(&self, block_id: BlockId) -> Result<BlockStatus, sp_blockchain::Error> {
|
||||
(**self).block_status(block_id)
|
||||
}
|
||||
|
||||
fn is_major_syncing(&self) -> bool {
|
||||
(**self).is_major_syncing()
|
||||
}
|
||||
|
||||
fn overseer_handle(&self) -> Option<OverseerHandle> {
|
||||
(**self).overseer_handle()
|
||||
}
|
||||
|
||||
fn get_storage_by_key(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
key: &[u8],
|
||||
) -> Result<Option<StorageValue>, sp_blockchain::Error> {
|
||||
(**self).get_storage_by_key(block_id, key)
|
||||
}
|
||||
|
||||
fn prove_read(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
relevant_keys: &Vec<Vec<u8>>,
|
||||
) -> Result<Option<StorageProof>, Box<dyn sp_state_machine::Error>> {
|
||||
(**self).prove_read(block_id, relevant_keys)
|
||||
}
|
||||
|
||||
async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> {
|
||||
(**self).wait_for_block(hash).await
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
[package]
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
name = "cumulus-relay-chain-local"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
cumulus-primitives-core = { path = "../../primitives/core" }
|
||||
cumulus-relay-chain-interface = { path = "../relay-chain-interface" }
|
||||
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
parking_lot = "0.11.1"
|
||||
tracing = "0.1.25"
|
||||
async-trait = "0.1.52"
|
||||
futures = { version = "0.3.1", features = ["compat"] }
|
||||
futures-timer = "3.0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
# Cumulus deps
|
||||
cumulus-test-service = { path = "../../test/service" }
|
||||
|
||||
# Polkadot deps
|
||||
polkadot-test-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
# substrate deps
|
||||
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -0,0 +1,540 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Cumulus.
|
||||
|
||||
// Cumulus is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Cumulus is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cumulus_primitives_core::{
|
||||
relay_chain::{
|
||||
v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId},
|
||||
v2::ParachainHost,
|
||||
Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage,
|
||||
},
|
||||
InboundDownwardMessage, ParaId, PersistedValidationData,
|
||||
};
|
||||
use cumulus_relay_chain_interface::{RelayChainInterface, WaitError};
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use parking_lot::Mutex;
|
||||
use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend};
|
||||
use polkadot_service::{
|
||||
AuxStore, BabeApi, CollatorPair, Configuration, Handle, NewFull, Role, TaskManager,
|
||||
};
|
||||
use sc_client_api::{
|
||||
blockchain::BlockStatus, Backend, BlockchainEvents, HeaderBackend, ImportNotifications,
|
||||
StorageProof, UsageProvider,
|
||||
};
|
||||
use sc_telemetry::TelemetryWorkerHandle;
|
||||
use sp_api::{ApiError, ProvideRuntimeApi};
|
||||
use sp_consensus::SyncOracle;
|
||||
use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair};
|
||||
use sp_state_machine::{Backend as StateBackend, StorageValue};
|
||||
|
||||
const LOG_TARGET: &str = "relay-chain-local";
|
||||
/// The timeout in seconds after that the waiting for a block should be aborted.
|
||||
const TIMEOUT_IN_SECONDS: u64 = 6;
|
||||
|
||||
/// Provides an implementation of the [`RelayChainInterface`] using a local in-process relay chain node.
|
||||
pub struct RelayChainLocal<Client> {
|
||||
full_client: Arc<Client>,
|
||||
backend: Arc<FullBackend>,
|
||||
sync_oracle: Arc<Mutex<Box<dyn SyncOracle + Send + Sync>>>,
|
||||
overseer_handle: Option<Handle>,
|
||||
}
|
||||
|
||||
impl<Client> RelayChainLocal<Client> {
|
||||
/// Create a new instance of [`RelayChainLocal`]
|
||||
pub fn new(
|
||||
full_client: Arc<Client>,
|
||||
backend: Arc<FullBackend>,
|
||||
sync_oracle: Arc<Mutex<Box<dyn SyncOracle + Send + Sync>>>,
|
||||
overseer_handle: Option<Handle>,
|
||||
) -> Self {
|
||||
Self { full_client, backend, sync_oracle, overseer_handle }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for RelayChainLocal<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
full_client: self.full_client.clone(),
|
||||
backend: self.backend.clone(),
|
||||
sync_oracle: self.sync_oracle.clone(),
|
||||
overseer_handle: self.overseer_handle.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Client> RelayChainInterface for RelayChainLocal<Client>
|
||||
where
|
||||
Client: ProvideRuntimeApi<PBlock>
|
||||
+ BlockchainEvents<PBlock>
|
||||
+ AuxStore
|
||||
+ UsageProvider<PBlock>
|
||||
+ Sync
|
||||
+ Send,
|
||||
Client::Api: ParachainHost<PBlock> + BabeApi<PBlock>,
|
||||
{
|
||||
fn retrieve_dmq_contents(
|
||||
&self,
|
||||
para_id: ParaId,
|
||||
relay_parent: PHash,
|
||||
) -> Option<Vec<InboundDownwardMessage>> {
|
||||
self.full_client
|
||||
.runtime_api()
|
||||
.dmq_contents_with_context(
|
||||
&BlockId::hash(relay_parent),
|
||||
sp_core::ExecutionContext::Importing,
|
||||
para_id,
|
||||
)
|
||||
.map_err(|e| {
|
||||
tracing::error!(
|
||||
target: LOG_TARGET,
|
||||
relay_parent = ?relay_parent,
|
||||
error = ?e,
|
||||
"An error occured during requesting the downward messages.",
|
||||
);
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
fn retrieve_all_inbound_hrmp_channel_contents(
|
||||
&self,
|
||||
para_id: ParaId,
|
||||
relay_parent: PHash,
|
||||
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
|
||||
self.full_client
|
||||
.runtime_api()
|
||||
.inbound_hrmp_channels_contents_with_context(
|
||||
&BlockId::hash(relay_parent),
|
||||
sp_core::ExecutionContext::Importing,
|
||||
para_id,
|
||||
)
|
||||
.map_err(|e| {
|
||||
tracing::error!(
|
||||
target: LOG_TARGET,
|
||||
relay_parent = ?relay_parent,
|
||||
error = ?e,
|
||||
"An error occured during requesting the inbound HRMP messages.",
|
||||
);
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
fn persisted_validation_data(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
para_id: ParaId,
|
||||
occupied_core_assumption: OccupiedCoreAssumption,
|
||||
) -> Result<Option<PersistedValidationData>, ApiError> {
|
||||
self.full_client.runtime_api().persisted_validation_data(
|
||||
block_id,
|
||||
para_id,
|
||||
occupied_core_assumption,
|
||||
)
|
||||
}
|
||||
|
||||
fn candidate_pending_availability(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
para_id: ParaId,
|
||||
) -> Result<Option<CommittedCandidateReceipt>, ApiError> {
|
||||
self.full_client.runtime_api().candidate_pending_availability(block_id, para_id)
|
||||
}
|
||||
|
||||
fn session_index_for_child(&self, block_id: &BlockId) -> Result<SessionIndex, ApiError> {
|
||||
self.full_client.runtime_api().session_index_for_child(block_id)
|
||||
}
|
||||
|
||||
fn validators(&self, block_id: &BlockId) -> Result<Vec<ValidatorId>, ApiError> {
|
||||
self.full_client.runtime_api().validators(block_id)
|
||||
}
|
||||
|
||||
fn import_notification_stream(&self) -> sc_client_api::ImportNotifications<PBlock> {
|
||||
self.full_client.import_notification_stream()
|
||||
}
|
||||
|
||||
fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications<PBlock> {
|
||||
self.full_client.finality_notification_stream()
|
||||
}
|
||||
|
||||
fn storage_changes_notification_stream(
|
||||
&self,
|
||||
filter_keys: Option<&[sc_client_api::StorageKey]>,
|
||||
child_filter_keys: Option<
|
||||
&[(sc_client_api::StorageKey, Option<Vec<sc_client_api::StorageKey>>)],
|
||||
>,
|
||||
) -> sc_client_api::blockchain::Result<sc_client_api::StorageEventStream<PHash>> {
|
||||
self.full_client
|
||||
.storage_changes_notification_stream(filter_keys, child_filter_keys)
|
||||
}
|
||||
|
||||
fn best_block_hash(&self) -> PHash {
|
||||
self.backend.blockchain().info().best_hash
|
||||
}
|
||||
|
||||
fn block_status(&self, block_id: BlockId) -> Result<BlockStatus, sp_blockchain::Error> {
|
||||
self.backend.blockchain().status(block_id)
|
||||
}
|
||||
|
||||
fn is_major_syncing(&self) -> bool {
|
||||
let mut network = self.sync_oracle.lock();
|
||||
network.is_major_syncing()
|
||||
}
|
||||
|
||||
fn overseer_handle(&self) -> Option<Handle> {
|
||||
self.overseer_handle.clone()
|
||||
}
|
||||
|
||||
fn get_storage_by_key(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
key: &[u8],
|
||||
) -> Result<Option<StorageValue>, sp_blockchain::Error> {
|
||||
let state = self.backend.state_at(*block_id)?;
|
||||
state.storage(key).map_err(sp_blockchain::Error::Storage)
|
||||
}
|
||||
|
||||
fn prove_read(
|
||||
&self,
|
||||
block_id: &BlockId,
|
||||
relevant_keys: &Vec<Vec<u8>>,
|
||||
) -> Result<Option<StorageProof>, Box<dyn sp_state_machine::Error>> {
|
||||
let state_backend = self
|
||||
.backend
|
||||
.state_at(*block_id)
|
||||
.map_err(|e| {
|
||||
tracing::error!(
|
||||
target: LOG_TARGET,
|
||||
relay_parent = ?block_id,
|
||||
error = ?e,
|
||||
"Cannot obtain the state of the relay chain.",
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
|
||||
match state_backend {
|
||||
Some(state) => sp_state_machine::prove_read(state, relevant_keys)
|
||||
.map_err(|e| {
|
||||
tracing::error!(
|
||||
target: LOG_TARGET,
|
||||
relay_parent = ?block_id,
|
||||
error = ?e,
|
||||
"Failed to collect required relay chain state storage proof.",
|
||||
);
|
||||
e
|
||||
})
|
||||
.map(Some),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait for a given relay chain block in an async way.
|
||||
///
|
||||
/// The caller needs to pass the hash of a block it waits for and the function will return when the
|
||||
/// block is available or an error occurred.
|
||||
///
|
||||
/// The waiting for the block is implemented as follows:
|
||||
///
|
||||
/// 1. Get a read lock on the import lock from the backend.
|
||||
///
|
||||
/// 2. Check if the block is already imported. If yes, return from the function.
|
||||
///
|
||||
/// 3. If the block isn't imported yet, add an import notification listener.
|
||||
///
|
||||
/// 4. Poll the import notification listener until the block is imported or the timeout is fired.
|
||||
///
|
||||
/// The timeout is set to 6 seconds. This should be enough time to import the block in the current
|
||||
/// round and if not, the new round of the relay chain already started anyway.
|
||||
async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> {
|
||||
let mut listener =
|
||||
match check_block_in_chain(self.backend.clone(), self.full_client.clone(), hash)? {
|
||||
BlockCheckStatus::InChain => return Ok(()),
|
||||
BlockCheckStatus::Unknown(listener) => listener,
|
||||
};
|
||||
|
||||
let mut timeout = futures_timer::Delay::new(Duration::from_secs(TIMEOUT_IN_SECONDS)).fuse();
|
||||
|
||||
loop {
|
||||
futures::select! {
|
||||
_ = timeout => return Err(WaitError::Timeout(hash)),
|
||||
evt = listener.next() => match evt {
|
||||
Some(evt) if evt.hash == hash => return Ok(()),
|
||||
// Not the event we waited on.
|
||||
Some(_) => continue,
|
||||
None => return Err(WaitError::ImportListenerClosed(hash)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum BlockCheckStatus {
|
||||
/// Block is in chain
|
||||
InChain,
|
||||
/// Block status is unknown, listener can be used to wait for notification
|
||||
Unknown(ImportNotifications<PBlock>),
|
||||
}
|
||||
|
||||
// Helper function to check if a block is in chain.
|
||||
pub fn check_block_in_chain<Client>(
|
||||
backend: Arc<FullBackend>,
|
||||
client: Arc<Client>,
|
||||
hash: PHash,
|
||||
) -> Result<BlockCheckStatus, WaitError>
|
||||
where
|
||||
Client: BlockchainEvents<PBlock>,
|
||||
{
|
||||
let _lock = backend.get_import_lock().read();
|
||||
|
||||
let block_id = BlockId::Hash(hash);
|
||||
match backend.blockchain().status(block_id) {
|
||||
Ok(BlockStatus::InChain) => return Ok(BlockCheckStatus::InChain),
|
||||
Err(err) => return Err(WaitError::BlockchainError(hash, err)),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
let listener = client.import_notification_stream();
|
||||
|
||||
Ok(BlockCheckStatus::Unknown(listener))
|
||||
}
|
||||
|
||||
/// Builder for a concrete relay chain interface, created from a full node. Builds
|
||||
/// a [`RelayChainLocal`] to access relay chain data necessary for parachain operation.
|
||||
///
|
||||
/// The builder takes a [`polkadot_client::Client`]
|
||||
/// that wraps a concrete instance. By using [`polkadot_client::ExecuteWithClient`]
|
||||
/// the builder gets access to this concrete instance and instantiates a [`RelayChainLocal`] with it.
|
||||
struct RelayChainLocalBuilder {
|
||||
polkadot_client: polkadot_client::Client,
|
||||
backend: Arc<FullBackend>,
|
||||
sync_oracle: Arc<Mutex<Box<dyn SyncOracle + Send + Sync>>>,
|
||||
overseer_handle: Option<Handle>,
|
||||
}
|
||||
|
||||
impl RelayChainLocalBuilder {
|
||||
pub fn build(self) -> Arc<dyn RelayChainInterface> {
|
||||
self.polkadot_client.clone().execute_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExecuteWithClient for RelayChainLocalBuilder {
|
||||
type Output = Arc<dyn RelayChainInterface>;
|
||||
|
||||
fn execute_with_client<Client, Api, Backend>(self, client: Arc<Client>) -> Self::Output
|
||||
where
|
||||
Client: ProvideRuntimeApi<PBlock>
|
||||
+ BlockchainEvents<PBlock>
|
||||
+ AuxStore
|
||||
+ UsageProvider<PBlock>
|
||||
+ 'static
|
||||
+ Sync
|
||||
+ Send,
|
||||
Client::Api: ParachainHost<PBlock> + BabeApi<PBlock>,
|
||||
{
|
||||
Arc::new(RelayChainLocal::new(client, self.backend, self.sync_oracle, self.overseer_handle))
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the Polkadot full node using the given `config`.
|
||||
#[sc_tracing::logging::prefix_logs_with("Relaychain")]
|
||||
fn build_polkadot_full_node(
|
||||
config: Configuration,
|
||||
telemetry_worker_handle: Option<TelemetryWorkerHandle>,
|
||||
) -> Result<(NewFull<polkadot_client::Client>, CollatorPair), polkadot_service::Error> {
|
||||
let is_light = matches!(config.role, Role::Light);
|
||||
if is_light {
|
||||
Err(polkadot_service::Error::Sub("Light client not supported.".into()))
|
||||
} else {
|
||||
let collator_key = CollatorPair::generate().0;
|
||||
|
||||
let relay_chain_full_node = polkadot_service::build_full(
|
||||
config,
|
||||
polkadot_service::IsCollator::Yes(collator_key.clone()),
|
||||
None,
|
||||
true,
|
||||
None,
|
||||
telemetry_worker_handle,
|
||||
polkadot_service::RealOverseerGen,
|
||||
)?;
|
||||
|
||||
Ok((relay_chain_full_node, collator_key))
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a relay chain interface by constructing a full relay chain node
|
||||
pub fn build_relay_chain_interface(
|
||||
polkadot_config: Configuration,
|
||||
telemetry_worker_handle: Option<TelemetryWorkerHandle>,
|
||||
task_manager: &mut TaskManager,
|
||||
) -> Result<(Arc<(dyn RelayChainInterface + 'static)>, CollatorPair), polkadot_service::Error> {
|
||||
let (full_node, collator_key) =
|
||||
build_polkadot_full_node(polkadot_config, telemetry_worker_handle).map_err(
|
||||
|e| match e {
|
||||
polkadot_service::Error::Sub(x) => x,
|
||||
s => format!("{}", s).into(),
|
||||
},
|
||||
)?;
|
||||
|
||||
let sync_oracle: Box<dyn SyncOracle + Send + Sync> = Box::new(full_node.network.clone());
|
||||
let sync_oracle = Arc::new(Mutex::new(sync_oracle));
|
||||
let relay_chain_interface_builder = RelayChainLocalBuilder {
|
||||
polkadot_client: full_node.client.clone(),
|
||||
backend: full_node.backend.clone(),
|
||||
sync_oracle,
|
||||
overseer_handle: full_node.overseer_handle.clone(),
|
||||
};
|
||||
task_manager.add_child(full_node.task_manager);
|
||||
|
||||
Ok((relay_chain_interface_builder.build(), collator_key))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use super::*;
|
||||
|
||||
use polkadot_primitives::v1::Block as PBlock;
|
||||
use polkadot_test_client::{
|
||||
construct_transfer_extrinsic, BlockBuilderExt, Client, ClientBlockImportExt,
|
||||
DefaultTestClientBuilderExt, ExecutionStrategy, InitPolkadotBlockBuilder,
|
||||
TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
use sc_service::Arc;
|
||||
use sp_consensus::{BlockOrigin, SyncOracle};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
|
||||
use futures::{executor::block_on, poll, task::Poll};
|
||||
|
||||
struct DummyNetwork {}
|
||||
|
||||
impl SyncOracle for DummyNetwork {
|
||||
fn is_major_syncing(&mut self) -> bool {
|
||||
unimplemented!("Not needed for test")
|
||||
}
|
||||
|
||||
fn is_offline(&mut self) -> bool {
|
||||
unimplemented!("Not needed for test")
|
||||
}
|
||||
}
|
||||
|
||||
fn build_client_backend_and_block() -> (Arc<Client>, PBlock, RelayChainLocal<Client>) {
|
||||
let builder =
|
||||
TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::NativeWhenPossible);
|
||||
let backend = builder.backend();
|
||||
let client = Arc::new(builder.build());
|
||||
|
||||
let block_builder = client.init_polkadot_block_builder();
|
||||
let block = block_builder.build().expect("Finalizes the block").block;
|
||||
let dummy_network: Box<dyn SyncOracle + Sync + Send> = Box::new(DummyNetwork {});
|
||||
|
||||
(
|
||||
client.clone(),
|
||||
block,
|
||||
RelayChainLocal::new(
|
||||
client,
|
||||
backend.clone(),
|
||||
Arc::new(Mutex::new(dummy_network)),
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_directly_for_available_block() {
|
||||
let (mut client, block, relay_chain_interface) = build_client_backend_and_block();
|
||||
let hash = block.hash();
|
||||
|
||||
block_on(client.import(BlockOrigin::Own, block)).expect("Imports the block");
|
||||
|
||||
block_on(async move {
|
||||
// Should be ready on the first poll
|
||||
assert!(matches!(
|
||||
poll!(relay_chain_interface.wait_for_block(hash)),
|
||||
Poll::Ready(Ok(()))
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_after_block_import_notification_was_received() {
|
||||
let (mut client, block, relay_chain_interface) = build_client_backend_and_block();
|
||||
let hash = block.hash();
|
||||
|
||||
block_on(async move {
|
||||
let mut future = relay_chain_interface.wait_for_block(hash);
|
||||
// As the block is not yet imported, the first poll should return `Pending`
|
||||
assert!(poll!(&mut future).is_pending());
|
||||
|
||||
// Import the block that should fire the notification
|
||||
client.import(BlockOrigin::Own, block).await.expect("Imports the block");
|
||||
|
||||
// Now it should have received the notification and report that the block was imported
|
||||
assert!(matches!(poll!(future), Poll::Ready(Ok(()))));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wait_for_block_time_out_when_block_is_not_imported() {
|
||||
let (_, block, relay_chain_interface) = build_client_backend_and_block();
|
||||
let hash = block.hash();
|
||||
|
||||
assert!(matches!(
|
||||
block_on(relay_chain_interface.wait_for_block(hash)),
|
||||
Err(WaitError::Timeout(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn do_not_resolve_after_different_block_import_notification_was_received() {
|
||||
let (mut client, block, relay_chain_interface) = build_client_backend_and_block();
|
||||
let hash = block.hash();
|
||||
|
||||
let ext = construct_transfer_extrinsic(
|
||||
&*client,
|
||||
sp_keyring::Sr25519Keyring::Alice,
|
||||
sp_keyring::Sr25519Keyring::Bob,
|
||||
1000,
|
||||
);
|
||||
let mut block_builder = client.init_polkadot_block_builder();
|
||||
// Push an extrinsic to get a different block hash.
|
||||
block_builder.push_polkadot_extrinsic(ext).expect("Push extrinsic");
|
||||
let block2 = block_builder.build().expect("Build second block").block;
|
||||
let hash2 = block2.hash();
|
||||
|
||||
block_on(async move {
|
||||
let mut future = relay_chain_interface.wait_for_block(hash);
|
||||
let mut future2 = relay_chain_interface.wait_for_block(hash2);
|
||||
// As the block is not yet imported, the first poll should return `Pending`
|
||||
assert!(poll!(&mut future).is_pending());
|
||||
assert!(poll!(&mut future2).is_pending());
|
||||
|
||||
// Import the block that should fire the notification
|
||||
client.import(BlockOrigin::Own, block2).await.expect("Imports the second block");
|
||||
|
||||
// The import notification of the second block should not make this one finish
|
||||
assert!(poll!(&mut future).is_pending());
|
||||
// Now it should have received the notification and report that the block was imported
|
||||
assert!(matches!(poll!(future2), Poll::Ready(Ok(()))));
|
||||
|
||||
client.import(BlockOrigin::Own, block).await.expect("Imports the first block");
|
||||
|
||||
// Now it should be ready
|
||||
assert!(matches!(poll!(future), Poll::Ready(Ok(()))));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,14 @@
|
||||
name = "cumulus-client-service"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Cumulus dependencies
|
||||
cumulus-client-consensus-common = { path = "../consensus/common" }
|
||||
cumulus-client-collator = { path = "../collator" }
|
||||
cumulus-client-pov-recovery = { path = "../pov-recovery" }
|
||||
cumulus-relay-chain-interface = { path = "../relay-chain-interface" }
|
||||
cumulus-primitives-core = { path = "../../primitives/core" }
|
||||
|
||||
# Substrate dependencies
|
||||
@@ -27,7 +28,6 @@ sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "mas
|
||||
|
||||
# Polkadot dependencies
|
||||
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
# Other deps
|
||||
|
||||
@@ -21,21 +21,26 @@ use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero
|
||||
/// Generate the genesis block from a given ChainSpec.
|
||||
pub fn generate_genesis_block<Block: BlockT>(
|
||||
chain_spec: &Box<dyn ChainSpec>,
|
||||
genesis_state_version: sp_runtime::StateVersion,
|
||||
) -> Result<Block, String> {
|
||||
let storage = chain_spec.build_storage()?;
|
||||
|
||||
let child_roots = storage.children_default.iter().map(|(sk, child_content)| {
|
||||
let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
child_content.data.clone().into_iter().collect(),
|
||||
genesis_state_version,
|
||||
);
|
||||
(sk.clone(), state_root.encode())
|
||||
});
|
||||
let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
storage.top.clone().into_iter().chain(child_roots).collect(),
|
||||
genesis_state_version,
|
||||
);
|
||||
|
||||
let extrinsics_root =
|
||||
<<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(Vec::new());
|
||||
let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
Vec::new(),
|
||||
sp_runtime::StateVersion::V0,
|
||||
);
|
||||
|
||||
Ok(Block::new(
|
||||
<<Block as BlockT>::Header as HeaderT>::new(
|
||||
|
||||
+55
-182
@@ -20,9 +20,8 @@
|
||||
|
||||
use cumulus_client_consensus_common::ParachainConsensus;
|
||||
use cumulus_primitives_core::{CollectCollationInfo, ParaId};
|
||||
use polkadot_overseer::Handle as OverseerHandle;
|
||||
use polkadot_primitives::v1::{Block as PBlock, CollatorPair};
|
||||
use polkadot_service::{AbstractClient, Client as PClient, ClientHandle, RuntimeApiCollection};
|
||||
use cumulus_relay_chain_interface::RelayChainInterface;
|
||||
use polkadot_primitives::v1::CollatorPair;
|
||||
use sc_client_api::{
|
||||
Backend as BackendT, BlockBackend, BlockchainEvents, Finalizer, UsageProvider,
|
||||
};
|
||||
@@ -30,47 +29,32 @@ use sc_consensus::{
|
||||
import_queue::{ImportQueue, IncomingBlock, Link, Origin},
|
||||
BlockImport,
|
||||
};
|
||||
use sc_service::{Configuration, Role, TaskManager};
|
||||
use sc_telemetry::TelemetryWorkerHandle;
|
||||
use sc_service::{Configuration, TaskManager};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_core::{traits::SpawnNamed, Pair};
|
||||
use sp_core::traits::SpawnNamed;
|
||||
use sp_runtime::{
|
||||
traits::{BlakeTwo256, Block as BlockT, NumberFor},
|
||||
traits::{Block as BlockT, NumberFor},
|
||||
Justifications,
|
||||
};
|
||||
use std::{marker::PhantomData, ops::Deref, sync::Arc};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
pub mod genesis;
|
||||
|
||||
/// The relay chain full node handle.
|
||||
pub struct RFullNode<C> {
|
||||
/// The relay chain full node handles.
|
||||
pub relay_chain_full_node: polkadot_service::NewFull<C>,
|
||||
/// The collator key used by the node.
|
||||
pub collator_key: CollatorPair,
|
||||
}
|
||||
|
||||
impl<C> Deref for RFullNode<C> {
|
||||
type Target = polkadot_service::NewFull<C>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.relay_chain_full_node
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters given to [`start_collator`].
|
||||
pub struct StartCollatorParams<'a, Block: BlockT, BS, Client, Spawner, RClient, IQ> {
|
||||
pub struct StartCollatorParams<'a, Block: BlockT, BS, Client, RCInterface, Spawner, IQ> {
|
||||
pub block_status: Arc<BS>,
|
||||
pub client: Arc<Client>,
|
||||
pub announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||
pub spawner: Spawner,
|
||||
pub para_id: ParaId,
|
||||
pub relay_chain_full_node: RFullNode<RClient>,
|
||||
pub relay_chain_interface: RCInterface,
|
||||
pub task_manager: &'a mut TaskManager,
|
||||
pub parachain_consensus: Box<dyn ParachainConsensus<Block>>,
|
||||
pub import_queue: IQ,
|
||||
pub collator_key: CollatorPair,
|
||||
pub slot_duration: Duration,
|
||||
}
|
||||
|
||||
/// Start a collator node for a parachain.
|
||||
@@ -78,7 +62,7 @@ pub struct StartCollatorParams<'a, Block: BlockT, BS, Client, Spawner, RClient,
|
||||
/// A collator is similar to a validator in a normal blockchain.
|
||||
/// It is responsible for producing blocks and sending the blocks to a
|
||||
/// parachain validator for validation and inclusion into the relay chain.
|
||||
pub async fn start_collator<'a, Block, BS, Client, Backend, Spawner, RClient, IQ>(
|
||||
pub async fn start_collator<'a, Block, BS, Client, Backend, RCInterface, Spawner, IQ>(
|
||||
StartCollatorParams {
|
||||
block_status,
|
||||
client,
|
||||
@@ -86,10 +70,12 @@ pub async fn start_collator<'a, Block, BS, Client, Backend, Spawner, RClient, IQ
|
||||
spawner,
|
||||
para_id,
|
||||
task_manager,
|
||||
relay_chain_full_node,
|
||||
relay_chain_interface,
|
||||
parachain_consensus,
|
||||
import_queue,
|
||||
}: StartCollatorParams<'a, Block, BS, Client, Spawner, RClient, IQ>,
|
||||
collator_key,
|
||||
slot_duration,
|
||||
}: StartCollatorParams<'a, Block, BS, Client, RCInterface, Spawner, IQ>,
|
||||
) -> sc_service::error::Result<()>
|
||||
where
|
||||
Block: BlockT,
|
||||
@@ -106,55 +92,58 @@ where
|
||||
Client::Api: CollectCollationInfo<Block>,
|
||||
for<'b> &'b Client: BlockImport<Block>,
|
||||
Spawner: SpawnNamed + Clone + Send + Sync + 'static,
|
||||
RClient: ClientHandle,
|
||||
RCInterface: RelayChainInterface + Clone + 'static,
|
||||
Backend: BackendT<Block> + 'static,
|
||||
IQ: ImportQueue<Block> + 'static,
|
||||
{
|
||||
relay_chain_full_node.client.execute_with(StartConsensus {
|
||||
let consensus = cumulus_client_consensus_common::run_parachain_consensus(
|
||||
para_id,
|
||||
announce_block: announce_block.clone(),
|
||||
client: client.clone(),
|
||||
task_manager,
|
||||
_phantom: PhantomData,
|
||||
});
|
||||
client.clone(),
|
||||
relay_chain_interface.clone(),
|
||||
announce_block.clone(),
|
||||
);
|
||||
|
||||
relay_chain_full_node.client.execute_with(StartPoVRecovery {
|
||||
para_id,
|
||||
client: client.clone(),
|
||||
import_queue,
|
||||
task_manager,
|
||||
overseer_handle: relay_chain_full_node
|
||||
.overseer_handle
|
||||
.clone()
|
||||
task_manager
|
||||
.spawn_essential_handle()
|
||||
.spawn("cumulus-consensus", None, consensus);
|
||||
|
||||
let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new(
|
||||
relay_chain_interface
|
||||
.overseer_handle()
|
||||
.ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?,
|
||||
_phantom: PhantomData,
|
||||
})?;
|
||||
slot_duration,
|
||||
client.clone(),
|
||||
import_queue,
|
||||
relay_chain_interface.clone(),
|
||||
para_id,
|
||||
);
|
||||
|
||||
task_manager
|
||||
.spawn_essential_handle()
|
||||
.spawn("cumulus-pov-recovery", None, pov_recovery.run());
|
||||
|
||||
cumulus_client_collator::start_collator(cumulus_client_collator::StartCollatorParams {
|
||||
runtime_api: client.clone(),
|
||||
block_status,
|
||||
announce_block,
|
||||
overseer_handle: relay_chain_full_node
|
||||
.overseer_handle
|
||||
.clone()
|
||||
overseer_handle: relay_chain_interface
|
||||
.overseer_handle()
|
||||
.ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?,
|
||||
spawner,
|
||||
para_id,
|
||||
key: relay_chain_full_node.collator_key.clone(),
|
||||
key: collator_key,
|
||||
parachain_consensus,
|
||||
})
|
||||
.await;
|
||||
|
||||
task_manager.add_child(relay_chain_full_node.relay_chain_full_node.task_manager);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parameters given to [`start_full_node`].
|
||||
pub struct StartFullNodeParams<'a, Block: BlockT, Client, PClient> {
|
||||
pub struct StartFullNodeParams<'a, Block: BlockT, Client, RCInterface> {
|
||||
pub para_id: ParaId,
|
||||
pub client: Arc<Client>,
|
||||
pub relay_chain_full_node: RFullNode<PClient>,
|
||||
pub relay_chain_interface: RCInterface,
|
||||
pub task_manager: &'a mut TaskManager,
|
||||
pub announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||
}
|
||||
@@ -163,14 +152,14 @@ pub struct StartFullNodeParams<'a, Block: BlockT, Client, PClient> {
|
||||
///
|
||||
/// A full node will only sync the given parachain and will follow the
|
||||
/// tip of the chain.
|
||||
pub fn start_full_node<Block, Client, Backend, PClient>(
|
||||
pub fn start_full_node<Block, Client, Backend, RCInterface>(
|
||||
StartFullNodeParams {
|
||||
client,
|
||||
announce_block,
|
||||
task_manager,
|
||||
relay_chain_full_node,
|
||||
relay_chain_interface,
|
||||
para_id,
|
||||
}: StartFullNodeParams<Block, Client, PClient>,
|
||||
}: StartFullNodeParams<Block, Client, RCInterface>,
|
||||
) -> sc_service::error::Result<()>
|
||||
where
|
||||
Block: BlockT,
|
||||
@@ -183,112 +172,22 @@ where
|
||||
+ 'static,
|
||||
for<'a> &'a Client: BlockImport<Block>,
|
||||
Backend: BackendT<Block> + 'static,
|
||||
PClient: ClientHandle,
|
||||
RCInterface: RelayChainInterface + Clone + 'static,
|
||||
{
|
||||
relay_chain_full_node.client.execute_with(StartConsensus {
|
||||
announce_block,
|
||||
let consensus = cumulus_client_consensus_common::run_parachain_consensus(
|
||||
para_id,
|
||||
client,
|
||||
task_manager,
|
||||
_phantom: PhantomData,
|
||||
});
|
||||
client.clone(),
|
||||
relay_chain_interface.clone(),
|
||||
announce_block,
|
||||
);
|
||||
|
||||
task_manager.add_child(relay_chain_full_node.relay_chain_full_node.task_manager);
|
||||
task_manager
|
||||
.spawn_essential_handle()
|
||||
.spawn("cumulus-consensus", None, consensus);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct StartConsensus<'a, Block: BlockT, Client, Backend> {
|
||||
para_id: ParaId,
|
||||
announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||
client: Arc<Client>,
|
||||
task_manager: &'a mut TaskManager,
|
||||
_phantom: PhantomData<Backend>,
|
||||
}
|
||||
|
||||
impl<'a, Block, Client, Backend> polkadot_service::ExecuteWithClient
|
||||
for StartConsensus<'a, Block, Client, Backend>
|
||||
where
|
||||
Block: BlockT,
|
||||
Client: Finalizer<Block, Backend>
|
||||
+ UsageProvider<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ BlockBackend<Block>
|
||||
+ BlockchainEvents<Block>
|
||||
+ 'static,
|
||||
for<'b> &'b Client: BlockImport<Block>,
|
||||
Backend: BackendT<Block> + 'static,
|
||||
{
|
||||
type Output = ();
|
||||
|
||||
fn execute_with_client<PClient, Api, PBackend>(self, client: Arc<PClient>) -> Self::Output
|
||||
where
|
||||
<Api as sp_api::ApiExt<PBlock>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
|
||||
PBackend: sc_client_api::Backend<PBlock>,
|
||||
PBackend::State: sp_api::StateBackend<BlakeTwo256>,
|
||||
Api: RuntimeApiCollection<StateBackend = PBackend::State>,
|
||||
PClient: AbstractClient<PBlock, PBackend, Api = Api> + 'static,
|
||||
{
|
||||
let consensus = cumulus_client_consensus_common::run_parachain_consensus(
|
||||
self.para_id,
|
||||
self.client.clone(),
|
||||
client.clone(),
|
||||
self.announce_block,
|
||||
);
|
||||
|
||||
self.task_manager.spawn_essential_handle().spawn("cumulus-consensus", consensus);
|
||||
}
|
||||
}
|
||||
|
||||
struct StartPoVRecovery<'a, Block: BlockT, Client, IQ> {
|
||||
para_id: ParaId,
|
||||
client: Arc<Client>,
|
||||
task_manager: &'a mut TaskManager,
|
||||
overseer_handle: OverseerHandle,
|
||||
import_queue: IQ,
|
||||
_phantom: PhantomData<Block>,
|
||||
}
|
||||
|
||||
impl<'a, Block, Client, IQ> polkadot_service::ExecuteWithClient
|
||||
for StartPoVRecovery<'a, Block, Client, IQ>
|
||||
where
|
||||
Block: BlockT,
|
||||
Client: UsageProvider<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ BlockBackend<Block>
|
||||
+ BlockchainEvents<Block>
|
||||
+ 'static,
|
||||
IQ: ImportQueue<Block> + 'static,
|
||||
{
|
||||
type Output = sc_service::error::Result<()>;
|
||||
|
||||
fn execute_with_client<PClient, Api, PBackend>(self, client: Arc<PClient>) -> Self::Output
|
||||
where
|
||||
<Api as sp_api::ApiExt<PBlock>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
|
||||
PBackend: sc_client_api::Backend<PBlock>,
|
||||
PBackend::State: sp_api::StateBackend<BlakeTwo256>,
|
||||
Api: RuntimeApiCollection<StateBackend = PBackend::State>,
|
||||
PClient: AbstractClient<PBlock, PBackend, Api = Api> + 'static,
|
||||
{
|
||||
let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new(
|
||||
self.overseer_handle,
|
||||
sc_consensus_babe::Config::get_or_compute(&*client)?.slot_duration(),
|
||||
self.client,
|
||||
self.import_queue,
|
||||
client,
|
||||
self.para_id,
|
||||
);
|
||||
|
||||
self.task_manager
|
||||
.spawn_essential_handle()
|
||||
.spawn("cumulus-pov-recovery", pov_recovery.run());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare the parachain's node condifugration
|
||||
///
|
||||
/// This function will disable the default announcement of Substrate for the parachain in favor
|
||||
@@ -299,32 +198,6 @@ pub fn prepare_node_config(mut parachain_config: Configuration) -> Configuration
|
||||
parachain_config
|
||||
}
|
||||
|
||||
/// Build the Polkadot full node using the given `config`.
|
||||
#[sc_tracing::logging::prefix_logs_with("Relaychain")]
|
||||
pub fn build_polkadot_full_node(
|
||||
config: Configuration,
|
||||
telemetry_worker_handle: Option<TelemetryWorkerHandle>,
|
||||
) -> Result<RFullNode<PClient>, polkadot_service::Error> {
|
||||
let is_light = matches!(config.role, Role::Light);
|
||||
if is_light {
|
||||
Err(polkadot_service::Error::Sub("Light client not supported.".into()))
|
||||
} else {
|
||||
let collator_key = CollatorPair::generate().0;
|
||||
|
||||
let relay_chain_full_node = polkadot_service::build_full(
|
||||
config,
|
||||
polkadot_service::IsCollator::Yes(collator_key.clone()),
|
||||
None,
|
||||
true,
|
||||
None,
|
||||
telemetry_worker_handle,
|
||||
polkadot_service::RealOverseerGen,
|
||||
)?;
|
||||
|
||||
Ok(RFullNode { relay_chain_full_node, collator_key })
|
||||
}
|
||||
}
|
||||
|
||||
/// A shared import queue
|
||||
///
|
||||
/// This is basically a hack until the Substrate side is implemented properly.
|
||||
|
||||
@@ -36,6 +36,8 @@ RUN apt-get update && \
|
||||
|
||||
# add polkadot-collator binary to the docker image
|
||||
COPY ./target/release/polkadot-collator /usr/local/bin
|
||||
COPY ./target/release/polkadot-collator.asc /usr/local/bin
|
||||
COPY ./target/release/polkadot-collator.sha256 /usr/local/bin
|
||||
COPY ./polkadot-parachains/res/*.json /specs/
|
||||
|
||||
USER polkadot
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# This file is sourced from https://github.com/paritytech/polkadot/blob/master/scripts/dockerfiles/polkadot/polkadot_builder.Dockerfile
|
||||
# This is the build stage for Polkadot-collator. Here we create the binary in a temporary image.
|
||||
FROM docker.io/paritytech/ci-linux:production as builder
|
||||
|
||||
WORKDIR /cumulus
|
||||
COPY . /cumulus
|
||||
|
||||
RUN cargo build --release --locked -p polkadot-collator
|
||||
|
||||
# This is the 2nd stage: a very small image where we copy the Polkadot binary."
|
||||
FROM docker.io/library/ubuntu:20.04
|
||||
|
||||
LABEL io.parity.image.type="builder" \
|
||||
io.parity.image.authors="devops-team@parity.io" \
|
||||
io.parity.image.vendor="Parity Technologies" \
|
||||
io.parity.image.description="Multistage Docker image for Polkadot-collator" \
|
||||
io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/docker/test-parachain-collator.dockerfile" \
|
||||
io.parity.image.documentation="https://github.com/paritytech/cumulus"
|
||||
|
||||
COPY --from=builder /cumulus/target/release/polkadot-collator /usr/local/bin
|
||||
|
||||
RUN useradd -m -u 1000 -U -s /bin/sh -d /cumulus polkadot-collator && \
|
||||
mkdir -p /data /cumulus/.local/share && \
|
||||
chown -R polkadot-collator:polkadot-collator /data && \
|
||||
ln -s /data /cumulus/.local/share/polkadot-collator && \
|
||||
# unclutter and minimize the attack surface
|
||||
rm -rf /usr/bin /usr/sbin && \
|
||||
# check if executable works in this container
|
||||
/usr/local/bin/polkadot-collator --version
|
||||
|
||||
USER polkadot-collator
|
||||
|
||||
EXPOSE 30333 9933 9944 9615
|
||||
VOLUME ["/data"]
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/polkadot-collator"]
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
OWNER=parity
|
||||
IMAGE_NAME=polkadot-collator
|
||||
OWNER=${OWNER:-parity}
|
||||
IMAGE_NAME=${IMAGE_NAME:-polkadot-collator}
|
||||
docker build --no-cache --build-arg IMAGE_NAME=$IMAGE_NAME -t $OWNER/$IMAGE_NAME -f ./docker/injected.Dockerfile .
|
||||
docker images | grep $IMAGE_NAME
|
||||
|
||||
@@ -1,23 +1,8 @@
|
||||
FROM rust:buster as builder
|
||||
# This file is sourced from https://github.com/paritytech/polkadot/blob/master/scripts/dockerfiles/polkadot/polkadot_builder.Dockerfile
|
||||
FROM docker.io/paritytech/ci-linux:production as builder
|
||||
|
||||
RUN apt-get update && apt-get install time clang libclang-dev llvm -y
|
||||
RUN rustup toolchain install nightly
|
||||
RUN rustup target add wasm32-unknown-unknown --toolchain nightly
|
||||
RUN command -v wasm-gc || cargo +nightly install --git https://github.com/alexcrichton/wasm-gc --force
|
||||
|
||||
WORKDIR /paritytech/cumulus
|
||||
|
||||
# Ideally, we could just do something like `COPY . .`, but that doesn't work:
|
||||
# it busts the cache every time non-source files like inject_bootnodes.sh change,
|
||||
# as well as when non-`.dockerignore`'d transient files (*.log and friends)
|
||||
# show up. There is no way to exclude particular files, or write a negative
|
||||
# rule, using Docker's COPY syntax, which derives from go's filepath.Match rules.
|
||||
#
|
||||
# We can't combine these into a single big COPY operation like
|
||||
# `COPY collator consensus network runtime test Cargo.* .`, because in that case
|
||||
# docker will copy the _contents_ of each directory into the image workdir,
|
||||
# not the actual directory. We're stuck just enumerating them.
|
||||
COPY . .
|
||||
WORKDIR /cumulus
|
||||
COPY . /cumulus
|
||||
|
||||
RUN cargo build --release --locked -p polkadot-collator
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
[package]
|
||||
name = "pallet-asset-tx-payment"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://substrate.io"
|
||||
repository = "https://github.com/paritytech/cumulus/"
|
||||
description = "pallet to manage transaction payments in assets"
|
||||
readme = "README.md"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
# Substrate dependencies
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
# Other dependencies
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.101", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
smallvec = "1.4.1"
|
||||
serde_json = "1.0.41"
|
||||
|
||||
pallet-assets = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"serde",
|
||||
"codec/std",
|
||||
"sp-std/std",
|
||||
"sp-runtime/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"sp-io/std",
|
||||
"sp-core/std",
|
||||
"pallet-transaction-payment/std",
|
||||
]
|
||||
try-runtime = ["frame-support/try-runtime"]
|
||||
@@ -1,21 +0,0 @@
|
||||
# pallet-asset-tx-payment
|
||||
|
||||
## Asset Transaction Payment Pallet
|
||||
|
||||
This pallet allows runtimes that include it to pay for transactions in assets other than the
|
||||
native token of the chain.
|
||||
|
||||
### Overview
|
||||
It does this by extending transactions to include an optional `AssetId` that specifies the asset
|
||||
to be used for payment (defaulting to the native token on `None`). It expects an
|
||||
[`OnChargeAssetTransaction`] implementation analogously to [`pallet-transaction-payment`]. The
|
||||
included [`FungiblesAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the fee
|
||||
amount by converting the fee calculated by [`pallet-transaction-payment`] into the desired
|
||||
asset.
|
||||
|
||||
### Integration
|
||||
This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means
|
||||
you should include both pallets in your `construct_runtime` macro, but only include this
|
||||
pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]).
|
||||
|
||||
License: Apache-2.0
|
||||
@@ -1,295 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//! # Asset Transaction Payment Pallet
|
||||
//!
|
||||
//! This pallet allows runtimes that include it to pay for transactions in assets other than the
|
||||
//! main token of the chain.
|
||||
//!
|
||||
//! ## Overview
|
||||
//! It does this by extending transactions to include an optional `AssetId` that specifies the asset
|
||||
//! to be used for payment (defaulting to the native token on `None`). It expects an
|
||||
//! [`OnChargeAssetTransaction`] implementation analogously to [`pallet-transaction-payment`]. The
|
||||
//! included [`FungiblesAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the fee
|
||||
//! amount by converting the fee calculated by [`pallet-transaction-payment`] into the desired
|
||||
//! asset.
|
||||
//!
|
||||
//! ## Integration
|
||||
//! This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means
|
||||
//! you should include both pallets in your `construct_runtime` macro, but only include this
|
||||
//! pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]).
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use sp_std::prelude::*;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{
|
||||
dispatch::DispatchResult,
|
||||
traits::{
|
||||
tokens::{
|
||||
fungibles::{Balanced, CreditOf, Inspect},
|
||||
WithdrawConsequence,
|
||||
},
|
||||
IsType,
|
||||
},
|
||||
weights::{DispatchInfo, PostDispatchInfo},
|
||||
DefaultNoBound,
|
||||
};
|
||||
use pallet_transaction_payment::OnChargeTransaction;
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{
|
||||
traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero},
|
||||
transaction_validity::{
|
||||
InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,
|
||||
},
|
||||
FixedPointOperand,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
mod payment;
|
||||
pub use payment::*;
|
||||
|
||||
// Type aliases used for interaction with `OnChargeTransaction`.
|
||||
pub(crate) type OnChargeTransactionOf<T> =
|
||||
<T as pallet_transaction_payment::Config>::OnChargeTransaction;
|
||||
// Balance type alias.
|
||||
pub(crate) type BalanceOf<T> = <OnChargeTransactionOf<T> as OnChargeTransaction<T>>::Balance;
|
||||
// Liquity info type alias.
|
||||
pub(crate) type LiquidityInfoOf<T> =
|
||||
<OnChargeTransactionOf<T> as OnChargeTransaction<T>>::LiquidityInfo;
|
||||
|
||||
// Type alias used for interaction with fungibles (assets).
|
||||
// Balance type alias.
|
||||
pub(crate) type AssetBalanceOf<T> =
|
||||
<<T as Config>::Fungibles as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
|
||||
/// Asset id type alias.
|
||||
pub(crate) type AssetIdOf<T> =
|
||||
<<T as Config>::Fungibles as Inspect<<T as frame_system::Config>::AccountId>>::AssetId;
|
||||
|
||||
// Type aliases used for interaction with `OnChargeAssetTransaction`.
|
||||
// Balance type alias.
|
||||
pub(crate) type ChargeAssetBalanceOf<T> =
|
||||
<<T as Config>::OnChargeAssetTransaction as OnChargeAssetTransaction<T>>::Balance;
|
||||
// Asset id type alias.
|
||||
pub(crate) type ChargeAssetIdOf<T> =
|
||||
<<T as Config>::OnChargeAssetTransaction as OnChargeAssetTransaction<T>>::AssetId;
|
||||
// Liquity info type alias.
|
||||
pub(crate) type ChargeAssetLiquidityOf<T> =
|
||||
<<T as Config>::OnChargeAssetTransaction as OnChargeAssetTransaction<T>>::LiquidityInfo;
|
||||
|
||||
/// Used to pass the initial payment info from pre- to post-dispatch.
|
||||
#[derive(Encode, Decode, DefaultNoBound, TypeInfo)]
|
||||
pub enum InitialPayment<T: Config> {
|
||||
/// No initial fee was payed.
|
||||
Nothing,
|
||||
/// The initial fee was payed in the native currency.
|
||||
Native(LiquidityInfoOf<T>),
|
||||
/// The initial fee was payed in an asset.
|
||||
Asset(CreditOf<T::AccountId, T::Fungibles>),
|
||||
}
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config + pallet_transaction_payment::Config {
|
||||
/// The fungibles instance used to pay for transactions in assets.
|
||||
type Fungibles: Balanced<Self::AccountId>;
|
||||
/// The actual transaction charging logic that charges the fees.
|
||||
type OnChargeAssetTransaction: OnChargeAssetTransaction<Self>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {}
|
||||
}
|
||||
|
||||
/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
|
||||
/// in the queue. Allows paying via both `Currency` as well as `fungibles::Balanced`.
|
||||
///
|
||||
/// Wraps the transaction logic in [`pallet_transaction_payment`] and extends it with assets.
|
||||
/// An asset id of `None` falls back to the underlying transaction payment via the native currency.
|
||||
#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct ChargeAssetTxPayment<T: Config> {
|
||||
#[codec(compact)]
|
||||
tip: BalanceOf<T>,
|
||||
asset_id: Option<ChargeAssetIdOf<T>>,
|
||||
}
|
||||
|
||||
impl<T: Config> ChargeAssetTxPayment<T>
|
||||
where
|
||||
T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
|
||||
AssetBalanceOf<T>: Send + Sync + FixedPointOperand,
|
||||
BalanceOf<T>: Send + Sync + FixedPointOperand + IsType<ChargeAssetBalanceOf<T>>,
|
||||
ChargeAssetIdOf<T>: Send + Sync,
|
||||
CreditOf<T::AccountId, T::Fungibles>: IsType<ChargeAssetLiquidityOf<T>>,
|
||||
{
|
||||
/// utility constructor. Used only in client/factory code.
|
||||
pub fn from(tip: BalanceOf<T>, asset_id: Option<ChargeAssetIdOf<T>>) -> Self {
|
||||
Self { tip, asset_id }
|
||||
}
|
||||
|
||||
/// Fee withdrawal logic that dispatches to either `OnChargeAssetTransaction` or `OnChargeTransaction`.
|
||||
fn withdraw_fee(
|
||||
&self,
|
||||
who: &T::AccountId,
|
||||
call: &T::Call,
|
||||
info: &DispatchInfoOf<T::Call>,
|
||||
len: usize,
|
||||
) -> Result<(BalanceOf<T>, InitialPayment<T>), TransactionValidityError> {
|
||||
let fee = pallet_transaction_payment::Pallet::<T>::compute_fee(len as u32, info, self.tip);
|
||||
debug_assert!(self.tip <= fee, "tip should be included in the computed fee");
|
||||
if fee.is_zero() {
|
||||
Ok((fee, InitialPayment::Nothing))
|
||||
} else if let Some(asset_id) = self.asset_id {
|
||||
T::OnChargeAssetTransaction::withdraw_fee(
|
||||
who,
|
||||
call,
|
||||
info,
|
||||
asset_id,
|
||||
fee.into(),
|
||||
self.tip.into(),
|
||||
)
|
||||
.map(|i| (fee, InitialPayment::Asset(i.into())))
|
||||
} else {
|
||||
<OnChargeTransactionOf<T> as OnChargeTransaction<T>>::withdraw_fee(
|
||||
who, call, info, fee, self.tip,
|
||||
)
|
||||
.map(|i| (fee, InitialPayment::Native(i)))
|
||||
.map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> sp_std::fmt::Debug for ChargeAssetTxPayment<T> {
|
||||
#[cfg(feature = "std")]
|
||||
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
|
||||
write!(f, "ChargeAssetTxPayment<{:?}, {:?}>", self.tip, self.asset_id.encode())
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> SignedExtension for ChargeAssetTxPayment<T>
|
||||
where
|
||||
T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
|
||||
AssetBalanceOf<T>: Send + Sync + FixedPointOperand,
|
||||
BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand + IsType<ChargeAssetBalanceOf<T>>,
|
||||
ChargeAssetIdOf<T>: Send + Sync,
|
||||
CreditOf<T::AccountId, T::Fungibles>: IsType<ChargeAssetLiquidityOf<T>>,
|
||||
{
|
||||
const IDENTIFIER: &'static str = "ChargeAssetTxPayment";
|
||||
type AccountId = T::AccountId;
|
||||
type Call = T::Call;
|
||||
type AdditionalSigned = ();
|
||||
type Pre = (
|
||||
// tip
|
||||
BalanceOf<T>,
|
||||
// who paid the fee
|
||||
Self::AccountId,
|
||||
// imbalance resulting from withdrawing the fee
|
||||
InitialPayment<T>,
|
||||
);
|
||||
|
||||
fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate(
|
||||
&self,
|
||||
who: &Self::AccountId,
|
||||
call: &Self::Call,
|
||||
info: &DispatchInfoOf<Self::Call>,
|
||||
len: usize,
|
||||
) -> TransactionValidity {
|
||||
use pallet_transaction_payment::ChargeTransactionPayment;
|
||||
let (fee, _) = self.withdraw_fee(who, call, info, len)?;
|
||||
let priority = ChargeTransactionPayment::<T>::get_priority(info, len, self.tip, fee);
|
||||
Ok(ValidTransaction { priority, ..Default::default() })
|
||||
}
|
||||
|
||||
fn pre_dispatch(
|
||||
self,
|
||||
who: &Self::AccountId,
|
||||
call: &Self::Call,
|
||||
info: &DispatchInfoOf<Self::Call>,
|
||||
len: usize,
|
||||
) -> Result<Self::Pre, TransactionValidityError> {
|
||||
let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?;
|
||||
Ok((self.tip, who.clone(), initial_payment))
|
||||
}
|
||||
|
||||
fn post_dispatch(
|
||||
pre: Self::Pre,
|
||||
info: &DispatchInfoOf<Self::Call>,
|
||||
post_info: &PostDispatchInfoOf<Self::Call>,
|
||||
len: usize,
|
||||
_result: &DispatchResult,
|
||||
) -> Result<(), TransactionValidityError> {
|
||||
let (tip, who, initial_payment) = pre;
|
||||
let actual_fee = pallet_transaction_payment::Pallet::<T>::compute_actual_fee(
|
||||
len as u32, info, post_info, tip,
|
||||
);
|
||||
match initial_payment {
|
||||
InitialPayment::Native(already_withdrawn) => {
|
||||
<OnChargeTransactionOf<T> as OnChargeTransaction<T>>::correct_and_deposit_fee(
|
||||
&who,
|
||||
info,
|
||||
post_info,
|
||||
actual_fee,
|
||||
tip,
|
||||
already_withdrawn,
|
||||
)?;
|
||||
},
|
||||
InitialPayment::Asset(already_withdrawn) => {
|
||||
T::OnChargeAssetTransaction::correct_and_deposit_fee(
|
||||
&who,
|
||||
info,
|
||||
post_info,
|
||||
actual_fee.into(),
|
||||
tip.into(),
|
||||
already_withdrawn.into(),
|
||||
)?;
|
||||
},
|
||||
InitialPayment::Nothing => {
|
||||
debug_assert!(
|
||||
actual_fee.is_zero(),
|
||||
"actual fee should be zero if initial fee was zero."
|
||||
);
|
||||
debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero.");
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
// 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.
|
||||
|
||||
///! Traits and default implementation for paying transaction fees in assets.
|
||||
use super::*;
|
||||
use crate::Config;
|
||||
|
||||
use codec::FullCodec;
|
||||
use frame_support::{
|
||||
traits::{
|
||||
fungibles::{Balanced, CreditOf, Inspect},
|
||||
tokens::BalanceConversion,
|
||||
},
|
||||
unsigned::TransactionValidityError,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{
|
||||
traits::{
|
||||
AtLeast32BitUnsigned, DispatchInfoOf, MaybeSerializeDeserialize, One, PostDispatchInfoOf,
|
||||
},
|
||||
transaction_validity::InvalidTransaction,
|
||||
};
|
||||
use sp_std::{fmt::Debug, marker::PhantomData};
|
||||
|
||||
/// Handle withdrawing, refunding and depositing of transaction fees.
|
||||
pub trait OnChargeAssetTransaction<T: Config> {
|
||||
/// The underlying integer type in which fees are calculated.
|
||||
type Balance: AtLeast32BitUnsigned
|
||||
+ FullCodec
|
||||
+ Copy
|
||||
+ MaybeSerializeDeserialize
|
||||
+ Debug
|
||||
+ Default
|
||||
+ TypeInfo;
|
||||
/// The type used to identify the assets used for transaction payment.
|
||||
type AssetId: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo;
|
||||
/// The type used to store the intermediate values between pre- and post-dispatch.
|
||||
type LiquidityInfo;
|
||||
|
||||
/// Before the transaction is executed the payment of the transaction fees needs to be secured.
|
||||
///
|
||||
/// Note: The `fee` already includes the `tip`.
|
||||
fn withdraw_fee(
|
||||
who: &T::AccountId,
|
||||
call: &T::Call,
|
||||
dispatch_info: &DispatchInfoOf<T::Call>,
|
||||
asset_id: Self::AssetId,
|
||||
fee: Self::Balance,
|
||||
tip: Self::Balance,
|
||||
) -> Result<Self::LiquidityInfo, TransactionValidityError>;
|
||||
|
||||
/// After the transaction was executed the actual fee can be calculated.
|
||||
/// This function should refund any overpaid fees and optionally deposit
|
||||
/// the corrected amount.
|
||||
///
|
||||
/// Note: The `fee` already includes the `tip`.
|
||||
fn correct_and_deposit_fee(
|
||||
who: &T::AccountId,
|
||||
dispatch_info: &DispatchInfoOf<T::Call>,
|
||||
post_info: &PostDispatchInfoOf<T::Call>,
|
||||
corrected_fee: Self::Balance,
|
||||
tip: Self::Balance,
|
||||
already_withdrawn: Self::LiquidityInfo,
|
||||
) -> Result<(), TransactionValidityError>;
|
||||
}
|
||||
|
||||
/// Allows specifying what to do with the withdrawn asset fees.
|
||||
pub trait HandleCredit<AccountId, B: Balanced<AccountId>> {
|
||||
/// Implement to determine what to do with the withdrawn asset fees.
|
||||
/// Default for `CreditOf` from the assets pallet is to burn and
|
||||
/// decrease total issuance.
|
||||
fn handle_credit(credit: CreditOf<AccountId, B>);
|
||||
}
|
||||
|
||||
/// Default implementation that just drops the credit according to the `OnDrop` in the underlying
|
||||
/// imbalance type.
|
||||
impl<A, B: Balanced<A>> HandleCredit<A, B> for () {
|
||||
fn handle_credit(_credit: CreditOf<A, B>) {}
|
||||
}
|
||||
|
||||
/// Implements the asset transaction for a balance to asset converter (implementing
|
||||
/// [`BalanceConversion`]) and a credit handler (implementing [`HandleCredit`]).
|
||||
///
|
||||
/// The credit handler is given the complete fee in terms of the asset used for the transaction.
|
||||
pub struct FungiblesAdapter<CON, HC>(PhantomData<(CON, HC)>);
|
||||
|
||||
/// Default implementation for a runtime instantiating this pallet, a balance to asset converter and
|
||||
/// a credit handler.
|
||||
impl<T, CON, HC> OnChargeAssetTransaction<T> for FungiblesAdapter<CON, HC>
|
||||
where
|
||||
T: Config,
|
||||
CON: BalanceConversion<BalanceOf<T>, AssetIdOf<T>, AssetBalanceOf<T>>,
|
||||
HC: HandleCredit<T::AccountId, T::Fungibles>,
|
||||
AssetIdOf<T>: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo,
|
||||
{
|
||||
type Balance = BalanceOf<T>;
|
||||
type AssetId = AssetIdOf<T>;
|
||||
type LiquidityInfo = CreditOf<T::AccountId, T::Fungibles>;
|
||||
|
||||
/// Withdraw the predicted fee from the transaction origin.
|
||||
///
|
||||
/// Note: The `fee` already includes the `tip`.
|
||||
fn withdraw_fee(
|
||||
who: &T::AccountId,
|
||||
_call: &T::Call,
|
||||
_info: &DispatchInfoOf<T::Call>,
|
||||
asset_id: Self::AssetId,
|
||||
fee: Self::Balance,
|
||||
_tip: Self::Balance,
|
||||
) -> Result<Self::LiquidityInfo, TransactionValidityError> {
|
||||
// We don't know the precision of the underlying asset. Because the converted fee could be
|
||||
// less than one (e.g. 0.5) but gets rounded down by integer division we introduce a minimum
|
||||
// fee.
|
||||
let min_converted_fee = if fee.is_zero() { Zero::zero() } else { One::one() };
|
||||
let converted_fee = CON::to_asset_balance(fee, asset_id)
|
||||
.map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))?
|
||||
.max(min_converted_fee);
|
||||
let can_withdraw = <T::Fungibles as Inspect<T::AccountId>>::can_withdraw(
|
||||
asset_id.into(),
|
||||
who,
|
||||
converted_fee,
|
||||
);
|
||||
if !matches!(can_withdraw, WithdrawConsequence::Success) {
|
||||
return Err(InvalidTransaction::Payment.into())
|
||||
}
|
||||
<T::Fungibles as Balanced<T::AccountId>>::withdraw(asset_id.into(), who, converted_fee)
|
||||
.map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))
|
||||
}
|
||||
|
||||
/// Hand the fee and the tip over to the `[HandleCredit]` implementation.
|
||||
/// Since the predicted fee might have been too high, parts of the fee may be refunded.
|
||||
///
|
||||
/// Note: The `corrected_fee` already includes the `tip`.
|
||||
fn correct_and_deposit_fee(
|
||||
who: &T::AccountId,
|
||||
_dispatch_info: &DispatchInfoOf<T::Call>,
|
||||
_post_info: &PostDispatchInfoOf<T::Call>,
|
||||
corrected_fee: Self::Balance,
|
||||
_tip: Self::Balance,
|
||||
paid: Self::LiquidityInfo,
|
||||
) -> Result<(), TransactionValidityError> {
|
||||
let min_converted_fee = if corrected_fee.is_zero() { Zero::zero() } else { One::one() };
|
||||
// Convert the corrected fee into the asset used for payment.
|
||||
let converted_fee = CON::to_asset_balance(corrected_fee, paid.asset().into())
|
||||
.map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })?
|
||||
.max(min_converted_fee);
|
||||
// Calculate how much refund we should return.
|
||||
let (final_fee, refund) = paid.split(converted_fee);
|
||||
// Refund to the account that paid the fees. If this fails, the account might have dropped
|
||||
// below the existential balance. In that case we don't refund anything.
|
||||
let _ = <T::Fungibles as Balanced<T::AccountId>>::resolve(who, refund);
|
||||
// Handle the final fee, e.g. by transferring to the block author or burning.
|
||||
HC::handle_credit(final_fee);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,636 +0,0 @@
|
||||
// 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.
|
||||
|
||||
use super::*;
|
||||
use crate as pallet_asset_tx_payment;
|
||||
|
||||
use frame_support::{
|
||||
assert_ok,
|
||||
pallet_prelude::*,
|
||||
parameter_types,
|
||||
traits::{fungibles::Mutate, FindAuthor},
|
||||
weights::{
|
||||
DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFeeCoefficient,
|
||||
WeightToFeeCoefficients, WeightToFeePolynomial,
|
||||
},
|
||||
ConsensusEngineId,
|
||||
};
|
||||
use frame_system as system;
|
||||
use frame_system::EnsureRoot;
|
||||
use pallet_balances::Call as BalancesCall;
|
||||
use pallet_transaction_payment::CurrencyAdapter;
|
||||
use smallvec::smallvec;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
traits::{BlakeTwo256, ConvertInto, IdentityLookup, StaticLookup},
|
||||
Perbill,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
|
||||
type Block = frame_system::mocking::MockBlock<Runtime>;
|
||||
type Balance = u64;
|
||||
type AccountId = u64;
|
||||
|
||||
frame_support::construct_runtime!(
|
||||
pub enum Runtime where
|
||||
Block = Block,
|
||||
NodeBlock = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||
{
|
||||
System: system::{Pallet, Call, Config, Storage, Event<T>},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
|
||||
Assets: pallet_assets::{Pallet, Call, Storage, Event<T>},
|
||||
Authorship: pallet_authorship::{Pallet, Call, Storage},
|
||||
AssetTxPayment: pallet_asset_tx_payment::{Pallet},
|
||||
}
|
||||
);
|
||||
|
||||
const CALL: &<Runtime as frame_system::Config>::Call =
|
||||
&Call::Balances(BalancesCall::transfer { dest: 2, value: 69 });
|
||||
|
||||
thread_local! {
|
||||
static EXTRINSIC_BASE_WEIGHT: RefCell<u64> = RefCell::new(0);
|
||||
}
|
||||
|
||||
pub struct BlockWeights;
|
||||
impl Get<frame_system::limits::BlockWeights> for BlockWeights {
|
||||
fn get() -> frame_system::limits::BlockWeights {
|
||||
frame_system::limits::BlockWeights::builder()
|
||||
.base_block(0)
|
||||
.for_class(DispatchClass::all(), |weights| {
|
||||
weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into();
|
||||
})
|
||||
.for_class(DispatchClass::non_mandatory(), |weights| {
|
||||
weights.max_total = 1024.into();
|
||||
})
|
||||
.build_or_panic()
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
pub static TransactionByteFee: u64 = 1;
|
||||
pub static WeightToFee: u64 = 1;
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
type Call = Call;
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Header = Header;
|
||||
type Event = Event;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = pallet_balances::AccountData<u64>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const ExistentialDeposit: u64 = 10;
|
||||
pub const MaxReserves: u32 = 50;
|
||||
}
|
||||
|
||||
impl pallet_balances::Config for Runtime {
|
||||
type Balance = Balance;
|
||||
type Event = Event;
|
||||
type DustRemoval = ();
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
type MaxLocks = ();
|
||||
type WeightInfo = ();
|
||||
type MaxReserves = MaxReserves;
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
}
|
||||
|
||||
impl WeightToFeePolynomial for WeightToFee {
|
||||
type Balance = u64;
|
||||
|
||||
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
|
||||
smallvec![WeightToFeeCoefficient {
|
||||
degree: 1,
|
||||
coeff_frac: Perbill::zero(),
|
||||
coeff_integer: WEIGHT_TO_FEE.with(|v| *v.borrow()),
|
||||
negative: false,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const OperationalFeeMultiplier: u8 = 5;
|
||||
}
|
||||
|
||||
impl pallet_transaction_payment::Config for Runtime {
|
||||
type OnChargeTransaction = CurrencyAdapter<Balances, ()>;
|
||||
type TransactionByteFee = TransactionByteFee;
|
||||
type WeightToFee = WeightToFee;
|
||||
type FeeMultiplierUpdate = ();
|
||||
type OperationalFeeMultiplier = OperationalFeeMultiplier;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const AssetDeposit: u64 = 2;
|
||||
pub const MetadataDeposit: u64 = 0;
|
||||
pub const StringLimit: u32 = 20;
|
||||
}
|
||||
|
||||
impl pallet_assets::Config for Runtime {
|
||||
type Event = Event;
|
||||
type Balance = Balance;
|
||||
type AssetId = u32;
|
||||
type Currency = Balances;
|
||||
type ForceOrigin = EnsureRoot<AccountId>;
|
||||
type AssetDeposit = AssetDeposit;
|
||||
type MetadataDepositBase = MetadataDeposit;
|
||||
type MetadataDepositPerByte = MetadataDeposit;
|
||||
type ApprovalDeposit = MetadataDeposit;
|
||||
type StringLimit = StringLimit;
|
||||
type Freezer = ();
|
||||
type Extra = ();
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
pub struct HardcodedAuthor;
|
||||
const BLOCK_AUTHOR: AccountId = 1234;
|
||||
impl FindAuthor<AccountId> for HardcodedAuthor {
|
||||
fn find_author<'a, I>(_: I) -> Option<AccountId>
|
||||
where
|
||||
I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
|
||||
{
|
||||
Some(BLOCK_AUTHOR)
|
||||
}
|
||||
}
|
||||
|
||||
impl pallet_authorship::Config for Runtime {
|
||||
type FindAuthor = HardcodedAuthor;
|
||||
type UncleGenerations = ();
|
||||
type FilterUncle = ();
|
||||
type EventHandler = ();
|
||||
}
|
||||
|
||||
pub struct CreditToBlockAuthor;
|
||||
impl HandleCredit<AccountId, Assets> for CreditToBlockAuthor {
|
||||
fn handle_credit(credit: CreditOf<AccountId, Assets>) {
|
||||
let author = pallet_authorship::Pallet::<Runtime>::author();
|
||||
// TODO: what to do in case paying the author fails (e.g. because `fee < min_balance`)
|
||||
// default: drop the result which will trigger the `OnDrop` of the imbalance.
|
||||
let _ = <Assets as Balanced<AccountId>>::resolve(&author, credit);
|
||||
}
|
||||
}
|
||||
|
||||
impl Config for Runtime {
|
||||
type Fungibles = Assets;
|
||||
type OnChargeAssetTransaction = FungiblesAdapter<
|
||||
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
|
||||
CreditToBlockAuthor,
|
||||
>;
|
||||
}
|
||||
|
||||
pub struct ExtBuilder {
|
||||
balance_factor: u64,
|
||||
base_weight: u64,
|
||||
byte_fee: u64,
|
||||
weight_to_fee: u64,
|
||||
}
|
||||
|
||||
impl Default for ExtBuilder {
|
||||
fn default() -> Self {
|
||||
Self { balance_factor: 1, base_weight: 0, byte_fee: 1, weight_to_fee: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtBuilder {
|
||||
pub fn base_weight(mut self, base_weight: u64) -> Self {
|
||||
self.base_weight = base_weight;
|
||||
self
|
||||
}
|
||||
pub fn balance_factor(mut self, factor: u64) -> Self {
|
||||
self.balance_factor = factor;
|
||||
self
|
||||
}
|
||||
fn set_constants(&self) {
|
||||
EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight);
|
||||
TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee);
|
||||
WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee);
|
||||
}
|
||||
pub fn build(self) -> sp_io::TestExternalities {
|
||||
self.set_constants();
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
|
||||
pallet_balances::GenesisConfig::<Runtime> {
|
||||
balances: if self.balance_factor > 0 {
|
||||
vec![
|
||||
(1, 10 * self.balance_factor),
|
||||
(2, 20 * self.balance_factor),
|
||||
(3, 30 * self.balance_factor),
|
||||
(4, 40 * self.balance_factor),
|
||||
(5, 50 * self.balance_factor),
|
||||
(6, 60 * self.balance_factor),
|
||||
]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
t.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// create a transaction info struct from weight. Handy to avoid building the whole struct.
|
||||
pub fn info_from_weight(w: Weight) -> DispatchInfo {
|
||||
// pays_fee: Pays::Yes -- class: DispatchClass::Normal
|
||||
DispatchInfo { weight: w, ..Default::default() }
|
||||
}
|
||||
|
||||
fn post_info_from_weight(w: Weight) -> PostDispatchInfo {
|
||||
PostDispatchInfo { actual_weight: Some(w), pays_fee: Default::default() }
|
||||
}
|
||||
|
||||
fn info_from_pays(p: Pays) -> DispatchInfo {
|
||||
DispatchInfo { pays_fee: p, ..Default::default() }
|
||||
}
|
||||
|
||||
fn post_info_from_pays(p: Pays) -> PostDispatchInfo {
|
||||
PostDispatchInfo { actual_weight: None, pays_fee: p }
|
||||
}
|
||||
|
||||
fn default_post_info() -> PostDispatchInfo {
|
||||
PostDispatchInfo { actual_weight: None, pays_fee: Default::default() }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_payment_in_native_possible() {
|
||||
let balance_factor = 100;
|
||||
ExtBuilder::default()
|
||||
.balance_factor(balance_factor)
|
||||
.base_weight(5)
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
let len = 10;
|
||||
let pre = ChargeAssetTxPayment::<Runtime>::from(0, None)
|
||||
.pre_dispatch(&1, CALL, &info_from_weight(5), len)
|
||||
.unwrap();
|
||||
let initial_balance = 10 * balance_factor;
|
||||
assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10);
|
||||
|
||||
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
|
||||
pre,
|
||||
&info_from_weight(5),
|
||||
&default_post_info(),
|
||||
len,
|
||||
&Ok(())
|
||||
));
|
||||
assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10);
|
||||
|
||||
let pre = ChargeAssetTxPayment::<Runtime>::from(5 /* tipped */, None)
|
||||
.pre_dispatch(&2, CALL, &info_from_weight(100), len)
|
||||
.unwrap();
|
||||
let initial_balance_for_2 = 20 * balance_factor;
|
||||
assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5);
|
||||
|
||||
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
|
||||
pre,
|
||||
&info_from_weight(100),
|
||||
&post_info_from_weight(50),
|
||||
len,
|
||||
&Ok(())
|
||||
));
|
||||
assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_payment_in_asset_possible() {
|
||||
let base_weight = 5;
|
||||
let balance_factor = 100;
|
||||
ExtBuilder::default()
|
||||
.balance_factor(balance_factor)
|
||||
.base_weight(base_weight)
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
// create the asset
|
||||
let asset_id = 1;
|
||||
let min_balance = 2;
|
||||
assert_ok!(Assets::force_create(
|
||||
Origin::root(),
|
||||
asset_id,
|
||||
42, /* owner */
|
||||
true, /* is_sufficient */
|
||||
min_balance
|
||||
));
|
||||
|
||||
// mint into the caller account
|
||||
let caller = 1;
|
||||
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
|
||||
let balance = 100;
|
||||
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance);
|
||||
let weight = 5;
|
||||
let len = 10;
|
||||
// we convert the from weight to fee based on the ratio between asset min balance and
|
||||
// existential deposit
|
||||
let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get();
|
||||
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
|
||||
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
|
||||
.unwrap();
|
||||
// assert that native balance is not used
|
||||
assert_eq!(Balances::free_balance(caller), 10 * balance_factor);
|
||||
// check that fee was charged in the given asset
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
|
||||
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0);
|
||||
|
||||
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
|
||||
pre,
|
||||
&info_from_weight(weight),
|
||||
&default_post_info(),
|
||||
len,
|
||||
&Ok(())
|
||||
));
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
|
||||
// check that the block author gets rewarded
|
||||
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), fee);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_payment_without_fee() {
|
||||
let base_weight = 5;
|
||||
let balance_factor = 100;
|
||||
ExtBuilder::default()
|
||||
.balance_factor(balance_factor)
|
||||
.base_weight(base_weight)
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
// create the asset
|
||||
let asset_id = 1;
|
||||
let min_balance = 2;
|
||||
assert_ok!(Assets::force_create(
|
||||
Origin::root(),
|
||||
asset_id,
|
||||
42, /* owner */
|
||||
true, /* is_sufficient */
|
||||
min_balance
|
||||
));
|
||||
|
||||
// mint into the caller account
|
||||
let caller = 1;
|
||||
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
|
||||
let balance = 100;
|
||||
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance);
|
||||
let weight = 5;
|
||||
let len = 10;
|
||||
// we convert the from weight to fee based on the ratio between asset min balance and
|
||||
// existential deposit
|
||||
let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get();
|
||||
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
|
||||
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
|
||||
.unwrap();
|
||||
// assert that native balance is not used
|
||||
assert_eq!(Balances::free_balance(caller), 10 * balance_factor);
|
||||
// check that fee was charged in the given asset
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
|
||||
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0);
|
||||
|
||||
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
|
||||
pre,
|
||||
&info_from_weight(weight),
|
||||
&post_info_from_pays(Pays::No),
|
||||
len,
|
||||
&Ok(())
|
||||
));
|
||||
// caller should be refunded
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance);
|
||||
// check that the block author did not get rewarded
|
||||
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn asset_transaction_payment_with_tip_and_refund() {
|
||||
let base_weight = 5;
|
||||
ExtBuilder::default()
|
||||
.balance_factor(100)
|
||||
.base_weight(base_weight)
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
// create the asset
|
||||
let asset_id = 1;
|
||||
let min_balance = 2;
|
||||
assert_ok!(Assets::force_create(
|
||||
Origin::root(),
|
||||
asset_id,
|
||||
42, /* owner */
|
||||
true, /* is_sufficient */
|
||||
min_balance
|
||||
));
|
||||
|
||||
// mint into the caller account
|
||||
let caller = 2;
|
||||
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
|
||||
let balance = 1000;
|
||||
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance);
|
||||
let weight = 100;
|
||||
let tip = 5;
|
||||
let len = 10;
|
||||
// we convert the from weight to fee based on the ratio between asset min balance and
|
||||
// existential deposit
|
||||
let fee_with_tip =
|
||||
(base_weight + weight + len as u64 + tip) * min_balance / ExistentialDeposit::get();
|
||||
let pre = ChargeAssetTxPayment::<Runtime>::from(tip, Some(asset_id))
|
||||
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
|
||||
.unwrap();
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip);
|
||||
|
||||
let final_weight = 50;
|
||||
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
|
||||
pre,
|
||||
&info_from_weight(weight),
|
||||
&post_info_from_weight(final_weight),
|
||||
len,
|
||||
&Ok(())
|
||||
));
|
||||
let final_fee =
|
||||
fee_with_tip - (weight - final_weight) * min_balance / ExistentialDeposit::get();
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance - (final_fee));
|
||||
assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), final_fee);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn payment_from_account_with_only_assets() {
|
||||
let base_weight = 5;
|
||||
ExtBuilder::default()
|
||||
.balance_factor(100)
|
||||
.base_weight(base_weight)
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
// create the asset
|
||||
let asset_id = 1;
|
||||
let min_balance = 2;
|
||||
assert_ok!(Assets::force_create(
|
||||
Origin::root(),
|
||||
asset_id,
|
||||
42, /* owner */
|
||||
true, /* is_sufficient */
|
||||
min_balance
|
||||
));
|
||||
|
||||
// mint into the caller account
|
||||
let caller = 333;
|
||||
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
|
||||
let balance = 100;
|
||||
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance);
|
||||
// assert that native balance is not necessary
|
||||
assert_eq!(Balances::free_balance(caller), 0);
|
||||
let weight = 5;
|
||||
let len = 10;
|
||||
// we convert the from weight to fee based on the ratio between asset min balance and
|
||||
// existential deposit
|
||||
let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get();
|
||||
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
|
||||
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
|
||||
.unwrap();
|
||||
assert_eq!(Balances::free_balance(caller), 0);
|
||||
// check that fee was charged in the given asset
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
|
||||
|
||||
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
|
||||
pre,
|
||||
&info_from_weight(weight),
|
||||
&default_post_info(),
|
||||
len,
|
||||
&Ok(())
|
||||
));
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance - fee);
|
||||
assert_eq!(Balances::free_balance(caller), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn payment_only_with_existing_sufficient_asset() {
|
||||
let base_weight = 5;
|
||||
ExtBuilder::default()
|
||||
.balance_factor(100)
|
||||
.base_weight(base_weight)
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
let asset_id = 1;
|
||||
let caller = 1;
|
||||
let weight = 5;
|
||||
let len = 10;
|
||||
// pre_dispatch fails for non-existent asset
|
||||
assert!(ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
|
||||
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
|
||||
.is_err());
|
||||
|
||||
// create the non-sufficient asset
|
||||
let min_balance = 2;
|
||||
assert_ok!(Assets::force_create(
|
||||
Origin::root(),
|
||||
asset_id,
|
||||
42, /* owner */
|
||||
false, /* is_sufficient */
|
||||
min_balance
|
||||
));
|
||||
// pre_dispatch fails for non-sufficient asset
|
||||
assert!(ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
|
||||
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
|
||||
.is_err());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converted_fee_is_never_zero_if_input_fee_is_not() {
|
||||
let base_weight = 1;
|
||||
ExtBuilder::default()
|
||||
.balance_factor(100)
|
||||
.base_weight(base_weight)
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
// create the asset
|
||||
let asset_id = 1;
|
||||
let min_balance = 1;
|
||||
assert_ok!(Assets::force_create(
|
||||
Origin::root(),
|
||||
asset_id,
|
||||
42, /* owner */
|
||||
true, /* is_sufficient */
|
||||
min_balance
|
||||
));
|
||||
|
||||
// mint into the caller account
|
||||
let caller = 333;
|
||||
let beneficiary = <Runtime as system::Config>::Lookup::unlookup(caller);
|
||||
let balance = 100;
|
||||
assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance));
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance);
|
||||
let weight = 1;
|
||||
let len = 1;
|
||||
// we convert the from weight to fee based on the ratio between asset min balance and
|
||||
// existential deposit
|
||||
let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get();
|
||||
// naive fee calculation would round down to zero
|
||||
assert_eq!(fee, 0);
|
||||
{
|
||||
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
|
||||
.pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len)
|
||||
.unwrap();
|
||||
// `Pays::No` still implies no fees
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance);
|
||||
|
||||
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
|
||||
pre,
|
||||
&info_from_pays(Pays::No),
|
||||
&post_info_from_pays(Pays::No),
|
||||
len,
|
||||
&Ok(())
|
||||
));
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance);
|
||||
}
|
||||
let pre = ChargeAssetTxPayment::<Runtime>::from(0, Some(asset_id))
|
||||
.pre_dispatch(&caller, CALL, &info_from_weight(weight), len)
|
||||
.unwrap();
|
||||
// check that at least one coin was charged in the given asset
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance - 1);
|
||||
|
||||
assert_ok!(ChargeAssetTxPayment::<Runtime>::post_dispatch(
|
||||
pre,
|
||||
&info_from_weight(weight),
|
||||
&default_post_info(),
|
||||
len,
|
||||
&Ok(())
|
||||
));
|
||||
assert_eq!(Assets::balance(asset_id, caller), balance - 1);
|
||||
});
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "cumulus-pallet-aura-ext"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "AURA consensus extension pallet for parachains"
|
||||
|
||||
[dependencies]
|
||||
@@ -19,7 +19,7 @@ sp-application-crypto = { git = "https://github.com/paritytech/substrate", defau
|
||||
# Other Dependencies
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"]}
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
||||
serde = { version = "1.0.132", optional = true, features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
cumulus-pallet-parachain-system = { path = "../parachain-system" }
|
||||
|
||||
@@ -1,62 +1,64 @@
|
||||
[package]
|
||||
authors = ['Anonymous']
|
||||
description = 'Simple staking pallet with a fixed stake.'
|
||||
edition = '2018'
|
||||
homepage = 'https://substrate.io'
|
||||
license = 'Apache-2.0'
|
||||
name = 'pallet-collator-selection'
|
||||
readme = 'README.md'
|
||||
repository = 'https://github.com/paritytech/cumulus/'
|
||||
version = '3.0.0'
|
||||
authors = ["Anonymous"]
|
||||
description = "Simple staking pallet with a fixed stake."
|
||||
edition = "2021"
|
||||
homepage = "https://substrate.io"
|
||||
license = "Apache-2.0"
|
||||
name = "pallet-collator-selection"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/paritytech/cumulus/"
|
||||
version = "3.0.0"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ['x86_64-unknown-linux-gnu']
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
log = { version = "0.4.0", default-features = false }
|
||||
codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '2.3.0' }
|
||||
codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "2.3.0" }
|
||||
rand = { version = "0.7.2", default-features = false }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.119", default-features = false }
|
||||
serde = { version = "1.0.132", default-features = false }
|
||||
|
||||
sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-staking = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
pallet-authorship = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
pallet-session = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-staking = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-authorship = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-session = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-core = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-io = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-tracing = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
pallet-timestamp = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-consensus-aura = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
pallet-aura = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[features]
|
||||
default = ['std']
|
||||
default = ["std"]
|
||||
runtime-benchmarks = [
|
||||
'frame-benchmarking',
|
||||
'frame-support/runtime-benchmarks',
|
||||
'frame-system/runtime-benchmarks',
|
||||
"frame-benchmarking/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
]
|
||||
std = [
|
||||
'codec/std',
|
||||
'log/std',
|
||||
'scale-info/std',
|
||||
'rand/std',
|
||||
'sp-runtime/std',
|
||||
'sp-staking/std',
|
||||
'sp-std/std',
|
||||
'frame-support/std',
|
||||
'frame-system/std',
|
||||
'frame-benchmarking/std',
|
||||
'pallet-authorship/std',
|
||||
'pallet-session/std',
|
||||
"codec/std",
|
||||
"log/std",
|
||||
"scale-info/std",
|
||||
"rand/std",
|
||||
"sp-runtime/std",
|
||||
"sp-staking/std",
|
||||
"sp-std/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"frame-benchmarking/std",
|
||||
"pallet-authorship/std",
|
||||
"pallet-session/std",
|
||||
]
|
||||
|
||||
try-runtime = [ "frame-support/try-runtime" ]
|
||||
|
||||
@@ -88,7 +88,7 @@ fn register_validators<T: Config + session::Config>(count: u32) {
|
||||
let validators = (0..count).map(|c| validator::<T>(c)).collect::<Vec<_>>();
|
||||
|
||||
for (who, keys) in validators {
|
||||
<session::Module<T>>::set_keys(RawOrigin::Signed(who).into(), keys, vec![]).unwrap();
|
||||
<session::Pallet<T>>::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,10 +157,10 @@ benchmarks! {
|
||||
let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into();
|
||||
T::Currency::make_free_balance_be(&caller, bond.clone());
|
||||
|
||||
<session::Module<T>>::set_keys(
|
||||
<session::Pallet<T>>::set_keys(
|
||||
RawOrigin::Signed(caller.clone()).into(),
|
||||
keys::<T>(c + 1),
|
||||
vec![]
|
||||
Vec::new()
|
||||
).unwrap();
|
||||
|
||||
}: _(RawOrigin::Signed(caller.clone()))
|
||||
|
||||
@@ -78,6 +78,7 @@ impl system::Config for Test {
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = SS58Prefix;
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -145,7 +146,7 @@ impl From<UintAuthorityId> for MockSessionKeys {
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub static SessionHandlerCollators: Vec<u64> = vec![];
|
||||
pub static SessionHandlerCollators: Vec<u64> = Vec::new();
|
||||
pub static SessionChangeBlock: u64 = 0;
|
||||
}
|
||||
|
||||
@@ -224,21 +225,21 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
sp_tracing::try_init_simple();
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
|
||||
let invulnerables = vec![1, 2];
|
||||
let keys = invulnerables
|
||||
.iter()
|
||||
.map(|i| (*i, *i, MockSessionKeys { aura: UintAuthorityId(*i) }))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let balances = pallet_balances::GenesisConfig::<Test> {
|
||||
balances: vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)],
|
||||
};
|
||||
let balances = vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)];
|
||||
let keys = balances
|
||||
.iter()
|
||||
.map(|&(i, _)| (i, i, MockSessionKeys { aura: UintAuthorityId(i) }))
|
||||
.collect::<Vec<_>>();
|
||||
let collator_selection = collator_selection::GenesisConfig::<Test> {
|
||||
desired_candidates: 2,
|
||||
candidacy_bond: 10,
|
||||
invulnerables,
|
||||
};
|
||||
let session = pallet_session::GenesisConfig::<Test> { keys };
|
||||
balances.assimilate_storage(&mut t).unwrap();
|
||||
pallet_balances::GenesisConfig::<Test> { balances }
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
// collator selection must be initialized before session.
|
||||
collator_selection.assimilate_storage(&mut t).unwrap();
|
||||
session.assimilate_storage(&mut t).unwrap();
|
||||
@@ -249,6 +250,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
pub fn initialize_to_block(n: u64) {
|
||||
for i in System::block_number() + 1..=n {
|
||||
System::set_block_number(i);
|
||||
<AllPallets as frame_support::traits::OnInitialize<u64>>::on_initialize(i);
|
||||
<AllPalletsWithSystem as frame_support::traits::OnInitialize<u64>>::on_initialize(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ fn register_as_candidate_works() {
|
||||
// given
|
||||
assert_eq!(CollatorSelection::desired_candidates(), 2);
|
||||
assert_eq!(CollatorSelection::candidacy_bond(), 10);
|
||||
assert_eq!(CollatorSelection::candidates(), vec![]);
|
||||
assert_eq!(CollatorSelection::candidates(), Vec::new());
|
||||
assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);
|
||||
|
||||
// take two endowed, non-invulnerables accounts.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "cumulus-pallet-dmp-queue"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Other dependencies
|
||||
|
||||
@@ -307,7 +307,7 @@ pub mod pallet {
|
||||
id, remaining, required,
|
||||
));
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
// Cannot be an `else` here since the `maybe_enqueue_page` may have changed.
|
||||
@@ -371,6 +371,7 @@ mod tests {
|
||||
impl_version: 1,
|
||||
apis: sp_version::create_apis_vec!([]),
|
||||
transaction_version: 1,
|
||||
state_version: 1,
|
||||
};
|
||||
pub const ParachainId: ParaId = ParaId::new(200);
|
||||
pub const ReservedXcmpWeight: Weight = 0;
|
||||
@@ -403,6 +404,7 @@ mod tests {
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
@@ -475,7 +477,7 @@ mod tests {
|
||||
Xcm(vec![Transact {
|
||||
origin_kind: OriginKind::Native,
|
||||
require_weight_at_most: weight,
|
||||
call: vec![].into(),
|
||||
call: Vec::new().into(),
|
||||
}])
|
||||
}
|
||||
|
||||
@@ -506,7 +508,7 @@ mod tests {
|
||||
new_test_ext().execute_with(|| {
|
||||
let weight_used = handle_messages(&[], 1000);
|
||||
assert_eq!(weight_used, 0);
|
||||
assert_eq!(take_trace(), vec![]);
|
||||
assert_eq!(take_trace(), Vec::new());
|
||||
assert!(queue_is_empty());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "cumulus-pallet-parachain-system"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "Base pallet for cumulus-based parachains"
|
||||
|
||||
[dependencies]
|
||||
@@ -32,7 +32,7 @@ sp-externalities = { git = "https://github.com/paritytech/substrate", default-fe
|
||||
# Other Dependencies
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"]}
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
||||
serde = { version = "1.0.132", optional = true, features = ["derive"] }
|
||||
log = { version = "0.4.14", default-features = false }
|
||||
environmental = { version = "1.1.2", default-features = false }
|
||||
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
name = "cumulus-pallet-parachain-system-proc-macro"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "Proc macros provided by the parachain-system pallet"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "1.0.73"
|
||||
proc-macro2 = "1.0.27"
|
||||
syn = "1.0.81"
|
||||
proc-macro2 = "1.0.36"
|
||||
quote = "1.0.9"
|
||||
proc-macro-crate = "1.0.0"
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ use cumulus_primitives_core::{
|
||||
OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender,
|
||||
XcmpMessageHandler, XcmpMessageSource,
|
||||
};
|
||||
use cumulus_primitives_parachain_inherent::ParachainInherentData;
|
||||
use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData};
|
||||
use frame_support::{
|
||||
dispatch::{DispatchError, DispatchResult},
|
||||
ensure,
|
||||
@@ -46,7 +46,7 @@ use frame_system::{ensure_none, ensure_root};
|
||||
use polkadot_parachain::primitives::RelayChainBlockNumber;
|
||||
use relay_state_snapshot::MessagingStateSnapshot;
|
||||
use sp_runtime::{
|
||||
traits::{BlakeTwo256, Block as BlockT, BlockNumberProvider, Hash},
|
||||
traits::{Block as BlockT, BlockNumberProvider, Hash},
|
||||
transaction_validity::{
|
||||
InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity,
|
||||
ValidTransaction,
|
||||
@@ -236,8 +236,9 @@ pub mod pallet {
|
||||
HrmpWatermark::<T>::kill();
|
||||
UpwardMessages::<T>::kill();
|
||||
HrmpOutboundMessages::<T>::kill();
|
||||
CustomValidationHeadData::<T>::kill();
|
||||
|
||||
weight += T::DbWeight::get().writes(5);
|
||||
weight += T::DbWeight::get().writes(6);
|
||||
|
||||
// Here, in `on_initialize` we must report the weight for both `on_initialize` and
|
||||
// `on_finalize`.
|
||||
@@ -567,6 +568,12 @@ pub mod pallet {
|
||||
#[pallet::storage]
|
||||
pub(super) type AuthorizedUpgrade<T: Config> = StorageValue<_, T::Hash>;
|
||||
|
||||
/// A custom head data that should be returned as result of `validate_block`.
|
||||
///
|
||||
/// See [`Pallet::set_custom_validation_head_data`] for more information.
|
||||
#[pallet::storage]
|
||||
pub(super) type CustomValidationHeadData<T: Config> = StorageValue<_, Vec<u8>, OptionQuery>;
|
||||
|
||||
#[pallet::inherent]
|
||||
impl<T: Config> ProvideInherent for Pallet<T> {
|
||||
type Call = Call<T>;
|
||||
@@ -609,7 +616,7 @@ pub mod pallet {
|
||||
if let Ok(hash) = Self::validate_authorized_upgrade(code) {
|
||||
return Ok(ValidTransaction {
|
||||
priority: 100,
|
||||
requires: vec![],
|
||||
requires: Vec::new(),
|
||||
provides: vec![hash.as_ref().to_vec()],
|
||||
longevity: TransactionLongevity::max_value(),
|
||||
propagate: true,
|
||||
@@ -692,6 +699,9 @@ impl<T: Config> Pallet<T> {
|
||||
/// import, this is a no-op.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics while validating the `PoV` on the relay chain if the [`PersistedValidationData`]
|
||||
/// passed by the block author was incorrect.
|
||||
fn validate_validation_data(validation_data: &PersistedValidationData) {
|
||||
validate_block::with_validation_params(|params| {
|
||||
assert_eq!(
|
||||
@@ -714,8 +724,10 @@ impl<T: Config> Pallet<T> {
|
||||
/// Checks if the sequence of the messages is valid, dispatches them and communicates the
|
||||
/// number of processed messages to the collator via a storage update.
|
||||
///
|
||||
/// **Panics** if it turns out that after processing all messages the Message Queue Chain
|
||||
/// hash doesn't match the expected.
|
||||
/// # Panics
|
||||
///
|
||||
/// If it turns out that after processing all messages the Message Queue Chain
|
||||
/// hash doesn't match the expected.
|
||||
fn process_inbound_downward_messages(
|
||||
expected_dmq_mqc_head: relay_chain::Hash,
|
||||
downward_messages: Vec<InboundDownwardMessage>,
|
||||
@@ -738,7 +750,7 @@ impl<T: Config> Pallet<T> {
|
||||
weight_used += T::DmpMessageHandler::handle_dmp_messages(message_iter, max_weight);
|
||||
<LastDmqMqcHead<T>>::put(&dmq_head);
|
||||
|
||||
Self::deposit_event(Event::DownwardMessagesProcessed(weight_used, dmq_head.0));
|
||||
Self::deposit_event(Event::DownwardMessagesProcessed(weight_used, dmq_head.head()));
|
||||
}
|
||||
|
||||
// After hashing each message in the message queue chain submitted by the collator, we
|
||||
@@ -746,7 +758,7 @@ impl<T: Config> Pallet<T> {
|
||||
//
|
||||
// A mismatch means that at least some of the submitted messages were altered, omitted or
|
||||
// added improperly.
|
||||
assert_eq!(dmq_head.0, expected_dmq_mqc_head);
|
||||
assert_eq!(dmq_head.head(), expected_dmq_mqc_head);
|
||||
|
||||
ProcessedDownwardMessages::<T>::put(dm_count);
|
||||
|
||||
@@ -907,6 +919,22 @@ impl<T: Config> Pallet<T> {
|
||||
new_validation_code: NewValidationCode::<T>::get().map(Into::into),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a custom head data that should be returned as result of `validate_block`.
|
||||
///
|
||||
/// This will overwrite the head data that is returned as result of `validate_block` while
|
||||
/// validating a `PoV` on the relay chain. Normally the head data that is being returned
|
||||
/// by `validate_block` is the header of the block that is validated, thus it can be
|
||||
/// enacted as the new best block. However, for features like forking it can be useful
|
||||
/// to overwrite the head data with a custom header.
|
||||
///
|
||||
/// # Attention
|
||||
///
|
||||
/// This should only be used when you are sure what you are doing as this can brick
|
||||
/// your Parachain.
|
||||
pub fn set_custom_validation_head_data(head_data: Vec<u8>) {
|
||||
CustomValidationHeadData::<T>::put(head_data);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ParachainSetCode<T>(sp_std::marker::PhantomData<T>);
|
||||
@@ -917,43 +945,6 @@ impl<T: Config> frame_system::SetCode<T> for ParachainSetCode<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct provides ability to extend a message queue chain (MQC) and compute a new head.
|
||||
///
|
||||
/// MQC is an instance of a [hash chain] applied to a message queue. Using a hash chain it's
|
||||
/// possible to represent a sequence of messages using only a single hash.
|
||||
///
|
||||
/// A head for an empty chain is agreed to be a zero hash.
|
||||
///
|
||||
/// [hash chain]: https://en.wikipedia.org/wiki/Hash_chain
|
||||
#[derive(Default, Clone, codec::Encode, codec::Decode, scale_info::TypeInfo)]
|
||||
struct MessageQueueChain(relay_chain::Hash);
|
||||
|
||||
impl MessageQueueChain {
|
||||
fn extend_hrmp(&mut self, horizontal_message: &InboundHrmpMessage) -> &mut Self {
|
||||
let prev_head = self.0;
|
||||
self.0 = BlakeTwo256::hash_of(&(
|
||||
prev_head,
|
||||
horizontal_message.sent_at,
|
||||
BlakeTwo256::hash_of(&horizontal_message.data),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
fn extend_downward(&mut self, downward_message: &InboundDownwardMessage) -> &mut Self {
|
||||
let prev_head = self.0;
|
||||
self.0 = BlakeTwo256::hash_of(&(
|
||||
prev_head,
|
||||
downward_message.sent_at,
|
||||
BlakeTwo256::hash_of(&downward_message.msg),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
fn head(&self) -> relay_chain::Hash {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn send_upward_message(message: UpwardMessage) -> Result<u32, MessageSendError> {
|
||||
// Check if the message fits into the relay-chain constraints.
|
||||
@@ -1008,7 +999,7 @@ pub trait CheckInherents<Block: BlockT> {
|
||||
) -> frame_support::inherent::CheckInherentsResult;
|
||||
}
|
||||
|
||||
/// Implements [`BlockNumberProvider`] that returns relaychain block number fetched from
|
||||
/// Implements [`BlockNumberProvider`] that returns relay chain block number fetched from
|
||||
/// validation data.
|
||||
/// NTOE: When validation data is not available (e.g. within on_initialize), 0 will be returned.
|
||||
pub struct RelaychainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
|
||||
|
||||
@@ -33,7 +33,10 @@ use frame_system::{InitKind, RawOrigin};
|
||||
use hex_literal::hex;
|
||||
use relay_chain::v1::HrmpChannelId;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{testing::Header, traits::IdentityLookup};
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
traits::{BlakeTwo256, IdentityLookup},
|
||||
};
|
||||
use sp_version::RuntimeVersion;
|
||||
use std::cell::RefCell;
|
||||
|
||||
@@ -63,6 +66,7 @@ parameter_types! {
|
||||
impl_version: 1,
|
||||
apis: sp_version::create_apis_vec!([]),
|
||||
transaction_version: 1,
|
||||
state_version: 1,
|
||||
};
|
||||
pub const ParachainId: ParaId = ParaId::new(200);
|
||||
pub const ReservedXcmpWeight: Weight = 0;
|
||||
@@ -92,6 +96,7 @@ impl frame_system::Config for Test {
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ParachainSetCode<Self>;
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
impl Config for Test {
|
||||
type Event = Event;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! The actual implementation of the validate block functionality.
|
||||
|
||||
use frame_support::traits::{ExecuteBlock, ExtrinsicCall, Get, IsSubType};
|
||||
use sp_runtime::traits::{Block as BlockT, Extrinsic, HashFor, Header as HeaderT, NumberFor};
|
||||
use sp_runtime::traits::{Block as BlockT, Extrinsic, HashFor, Header as HeaderT};
|
||||
|
||||
use sp_io::KillStorageResult;
|
||||
use sp_std::prelude::*;
|
||||
@@ -26,13 +26,13 @@ use polkadot_parachain::primitives::{HeadData, ValidationParams, ValidationResul
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
use sp_core::storage::ChildInfo;
|
||||
use sp_core::storage::{ChildInfo, StateVersion};
|
||||
use sp_externalities::{set_and_run_with_externalities, Externalities};
|
||||
use sp_trie::MemoryDB;
|
||||
|
||||
type TrieBackend<B> = sp_state_machine::TrieBackend<MemoryDB<HashFor<B>>, HashFor<B>>;
|
||||
|
||||
type Ext<'a, B> = sp_state_machine::Ext<'a, HashFor<B>, NumberFor<B>, TrieBackend<B>>;
|
||||
type Ext<'a, B> = sp_state_machine::Ext<'a, HashFor<B>, TrieBackend<B>>;
|
||||
|
||||
fn with_externalities<F: FnOnce(&mut dyn Externalities) -> R, R>(f: F) -> R {
|
||||
sp_externalities::with_externalities(f).expect("Environmental externalities not set.")
|
||||
@@ -68,7 +68,7 @@ where
|
||||
|
||||
// Uncompress
|
||||
let mut db = MemoryDB::default();
|
||||
let root = match sp_trie::decode_compact::<sp_trie::Layout<HashFor<B>>, _, _>(
|
||||
let root = match sp_trie::decode_compact::<sp_trie::LayoutV1<HashFor<B>>, _, _>(
|
||||
&mut db,
|
||||
storage_proof.iter_compact_encoded_nodes(),
|
||||
Some(parent_head.state_root()),
|
||||
@@ -89,7 +89,6 @@ where
|
||||
sp_io::storage::host_clear.replace_implementation(host_storage_clear),
|
||||
sp_io::storage::host_root.replace_implementation(host_storage_root),
|
||||
sp_io::storage::host_clear_prefix.replace_implementation(host_storage_clear_prefix),
|
||||
sp_io::storage::host_changes_root.replace_implementation(host_storage_changes_root),
|
||||
sp_io::storage::host_append.replace_implementation(host_storage_append),
|
||||
sp_io::storage::host_next_key.replace_implementation(host_storage_next_key),
|
||||
sp_io::storage::host_start_transaction
|
||||
@@ -162,6 +161,13 @@ where
|
||||
let horizontal_messages = crate::HrmpOutboundMessages::<PSC>::get();
|
||||
let hrmp_watermark = crate::HrmpWatermark::<PSC>::get();
|
||||
|
||||
let head_data =
|
||||
if let Some(custom_head_data) = crate::CustomValidationHeadData::<PSC>::get() {
|
||||
HeadData(custom_head_data)
|
||||
} else {
|
||||
head_data
|
||||
};
|
||||
|
||||
ValidationResult {
|
||||
head_data,
|
||||
new_validation_code: new_validation_code.map(Into::into),
|
||||
@@ -215,8 +221,8 @@ fn host_storage_clear(key: &[u8]) {
|
||||
with_externalities(|ext| ext.place_storage(key.to_vec(), None))
|
||||
}
|
||||
|
||||
fn host_storage_root() -> Vec<u8> {
|
||||
with_externalities(|ext| ext.storage_root())
|
||||
fn host_storage_root(version: StateVersion) -> Vec<u8> {
|
||||
with_externalities(|ext| ext.storage_root(version))
|
||||
}
|
||||
|
||||
fn host_storage_clear_prefix(prefix: &[u8], limit: Option<u32>) -> KillStorageResult {
|
||||
@@ -229,10 +235,6 @@ fn host_storage_clear_prefix(prefix: &[u8], limit: Option<u32>) -> KillStorageRe
|
||||
})
|
||||
}
|
||||
|
||||
fn host_storage_changes_root(parent_hash: &[u8]) -> Option<Vec<u8>> {
|
||||
with_externalities(|ext| ext.storage_changes_root(parent_hash).ok().flatten())
|
||||
}
|
||||
|
||||
fn host_storage_append(key: &[u8], value: Vec<u8>) {
|
||||
with_externalities(|ext| ext.storage_append(key.to_vec(), value))
|
||||
}
|
||||
@@ -325,9 +327,9 @@ fn host_default_child_storage_clear_prefix(
|
||||
})
|
||||
}
|
||||
|
||||
fn host_default_child_storage_root(storage_key: &[u8]) -> Vec<u8> {
|
||||
fn host_default_child_storage_root(storage_key: &[u8], version: StateVersion) -> Vec<u8> {
|
||||
let child_info = ChildInfo::new_default(storage_key);
|
||||
with_externalities(|ext| ext.child_storage_root(&child_info))
|
||||
with_externalities(|ext| ext.child_storage_root(&child_info, version))
|
||||
}
|
||||
|
||||
fn host_default_child_storage_next_key(storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
use codec::{Decode, Encode};
|
||||
use cumulus_primitives_core::{ParachainBlockData, PersistedValidationData};
|
||||
use cumulus_test_client::{
|
||||
runtime::{Block, Hash, Header, UncheckedExtrinsic, WASM_BINARY},
|
||||
generate_extrinsic,
|
||||
runtime::{Block, Hash, Header, TestPalletCall, UncheckedExtrinsic, WASM_BINARY},
|
||||
transfer, BlockData, BuildParachainBlockData, Client, DefaultTestClientBuilderExt, HeadData,
|
||||
InitBlockBuilder, TestClientBuilder, TestClientBuilderExt, ValidationParams,
|
||||
};
|
||||
@@ -26,11 +27,11 @@ use sp_keyring::AccountKeyring::*;
|
||||
use sp_runtime::{generic::BlockId, traits::Header as HeaderT};
|
||||
use std::{env, process::Command};
|
||||
|
||||
fn call_validate_block(
|
||||
fn call_validate_block_encoded_header(
|
||||
parent_head: Header,
|
||||
block_data: ParachainBlockData<Block>,
|
||||
relay_parent_storage_root: Hash,
|
||||
) -> cumulus_test_client::ExecutorResult<Header> {
|
||||
) -> cumulus_test_client::ExecutorResult<Vec<u8>> {
|
||||
cumulus_test_client::validate_block(
|
||||
ValidationParams {
|
||||
block_data: BlockData(block_data.encode()),
|
||||
@@ -40,7 +41,16 @@ fn call_validate_block(
|
||||
},
|
||||
&WASM_BINARY.expect("You need to build the WASM binaries to run the tests!"),
|
||||
)
|
||||
.map(|v| Header::decode(&mut &v.head_data.0[..]).expect("Decodes `Header`."))
|
||||
.map(|v| v.head_data.0)
|
||||
}
|
||||
|
||||
fn call_validate_block(
|
||||
parent_head: Header,
|
||||
block_data: ParachainBlockData<Block>,
|
||||
relay_parent_storage_root: Hash,
|
||||
) -> cumulus_test_client::ExecutorResult<Header> {
|
||||
call_validate_block_encoded_header(parent_head, block_data, relay_parent_storage_root)
|
||||
.map(|v| Header::decode(&mut &v[..]).expect("Decodes `Header`."))
|
||||
}
|
||||
|
||||
fn create_test_client() -> (Client, Header) {
|
||||
@@ -92,7 +102,7 @@ fn validate_block_no_extra_extrinsics() {
|
||||
|
||||
let (client, parent_head) = create_test_client();
|
||||
let TestBlockData { block, validation_data } =
|
||||
build_block_with_witness(&client, vec![], parent_head.clone(), Default::default());
|
||||
build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default());
|
||||
let header = block.header().clone();
|
||||
|
||||
let res_header =
|
||||
@@ -126,6 +136,43 @@ fn validate_block_with_extra_extrinsics() {
|
||||
assert_eq!(header, res_header);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_block_returns_custom_head_data() {
|
||||
sp_tracing::try_init_simple();
|
||||
|
||||
let expected_header = vec![1, 3, 3, 7, 4, 5, 6];
|
||||
|
||||
let (client, parent_head) = create_test_client();
|
||||
let extra_extrinsics = vec![
|
||||
transfer(&client, Alice, Bob, 69),
|
||||
generate_extrinsic(
|
||||
&client,
|
||||
Charlie,
|
||||
TestPalletCall::set_custom_validation_head_data {
|
||||
custom_header: expected_header.clone(),
|
||||
},
|
||||
),
|
||||
transfer(&client, Bob, Charlie, 100),
|
||||
];
|
||||
|
||||
let TestBlockData { block, validation_data } = build_block_with_witness(
|
||||
&client,
|
||||
extra_extrinsics,
|
||||
parent_head.clone(),
|
||||
Default::default(),
|
||||
);
|
||||
let header = block.header().clone();
|
||||
assert_ne!(expected_header, header.encode());
|
||||
|
||||
let res_header = call_validate_block_encoded_header(
|
||||
parent_head,
|
||||
block,
|
||||
validation_data.relay_parent_storage_root,
|
||||
)
|
||||
.expect("Calls `validate_block`");
|
||||
assert_eq!(expected_header, res_header);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_block_invalid_parent_hash() {
|
||||
sp_tracing::try_init_simple();
|
||||
@@ -133,7 +180,7 @@ fn validate_block_invalid_parent_hash() {
|
||||
if env::var("RUN_TEST").is_ok() {
|
||||
let (client, parent_head) = create_test_client();
|
||||
let TestBlockData { block, validation_data } =
|
||||
build_block_with_witness(&client, vec![], parent_head.clone(), Default::default());
|
||||
build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default());
|
||||
let (mut header, extrinsics, witness) = block.deconstruct();
|
||||
header.set_parent_hash(Hash::from_low_u64_be(1));
|
||||
|
||||
@@ -159,7 +206,7 @@ fn validate_block_fails_on_invalid_validation_data() {
|
||||
if env::var("RUN_TEST").is_ok() {
|
||||
let (client, parent_head) = create_test_client();
|
||||
let TestBlockData { block, .. } =
|
||||
build_block_with_witness(&client, vec![], parent_head.clone(), Default::default());
|
||||
build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default());
|
||||
|
||||
call_validate_block(parent_head, block, Hash::random()).unwrap_err();
|
||||
} else {
|
||||
@@ -184,7 +231,7 @@ fn check_inherent_fails_on_validate_block_as_expected() {
|
||||
|
||||
let TestBlockData { block, validation_data } = build_block_with_witness(
|
||||
&client,
|
||||
vec![],
|
||||
Vec::new(),
|
||||
parent_head.clone(),
|
||||
RelayStateSproofBuilder { current_slot: 1337.into(), ..Default::default() },
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "cumulus-pallet-session-benchmarking"
|
||||
version = "3.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://substrate.io"
|
||||
repository = "https://github.com/paritytech/cumulus/"
|
||||
@@ -13,21 +13,23 @@ readme = "README.md"
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
pallet-session = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
parity-scale-codec = { version = "2.3.1", default-features = false }
|
||||
sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-session = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
runtime-benchmarks = [
|
||||
'frame-benchmarking',
|
||||
'frame-support/runtime-benchmarks',
|
||||
'frame-system/runtime-benchmarks',
|
||||
"frame-benchmarking/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
]
|
||||
std = [
|
||||
"parity-scale-codec/std",
|
||||
"sp-std/std",
|
||||
"sp-runtime/std",
|
||||
"frame-system/std",
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
use sp_std::{prelude::*, vec};
|
||||
|
||||
use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller};
|
||||
use frame_benchmarking::{benchmarks, whitelisted_caller};
|
||||
use frame_system::RawOrigin;
|
||||
use pallet_session::*;
|
||||
use parity_scale_codec::Decode;
|
||||
pub struct Pallet<T: Config>(pallet_session::Pallet<T>);
|
||||
pub trait Config: pallet_session::Config {}
|
||||
|
||||
@@ -28,17 +29,15 @@ benchmarks! {
|
||||
set_keys {
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
frame_system::Pallet::<T>::inc_providers(&caller);
|
||||
let keys = T::Keys::default();
|
||||
let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap();
|
||||
let proof: Vec<u8> = vec![0,1,2,3];
|
||||
}: _(RawOrigin::Signed(caller), keys, proof)
|
||||
|
||||
purge_keys {
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
frame_system::Pallet::<T>::inc_providers(&caller);
|
||||
let keys = T::Keys::default();
|
||||
let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap();
|
||||
let proof: Vec<u8> = vec![0,1,2,3];
|
||||
let _t = pallet_session::Pallet::<T>::set_keys(RawOrigin::Signed(caller.clone()).into(), keys, proof);
|
||||
}: _(RawOrigin::Signed(caller))
|
||||
|
||||
}
|
||||
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test, extra = false,);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
name = "cumulus-pallet-xcm"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
||||
serde = { version = "1.0.132", optional = true, features = ["derive"] }
|
||||
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "cumulus-pallet-xcmp-queue"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Other dependencies
|
||||
@@ -25,11 +25,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
|
||||
cumulus-primitives-core = { path = "../../primitives/core", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-core = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-io = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
cumulus-pallet-parachain-system = { path = "../parachain-system" }
|
||||
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[features]
|
||||
default = [ "std" ]
|
||||
|
||||
+256
-75
@@ -25,6 +25,8 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub mod migration;
|
||||
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
|
||||
@@ -36,7 +38,7 @@ use cumulus_primitives_core::{
|
||||
relay_chain::BlockNumber as RelayBlockNumber, ChannelStatus, GetChannelInfo, MessageSendError,
|
||||
ParaId, XcmpMessageFormat, XcmpMessageHandler, XcmpMessageSource,
|
||||
};
|
||||
use frame_support::weights::Weight;
|
||||
use frame_support::weights::{constants::WEIGHT_PER_MILLIS, Weight};
|
||||
use rand_chacha::{
|
||||
rand_core::{RngCore, SeedableRng},
|
||||
ChaChaRng,
|
||||
@@ -48,6 +50,11 @@ use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH};
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
/// Index used to identify overweight XCMs.
|
||||
pub type OverweightIndex = u64;
|
||||
|
||||
const LOG_TARGET: &str = "xcmp_queue";
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
@@ -56,6 +63,7 @@ pub mod pallet {
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
#[pallet::storage_version(migration::STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
@@ -70,22 +78,17 @@ pub mod pallet {
|
||||
|
||||
/// Means of converting an `Xcm` into a `VersionedXcm`.
|
||||
type VersionWrapper: WrapVersion;
|
||||
}
|
||||
|
||||
impl Default for QueueConfigData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
suspend_threshold: 2,
|
||||
drop_threshold: 5,
|
||||
resume_threshold: 1,
|
||||
threshold_weight: 100_000,
|
||||
weight_restrict_decay: 2,
|
||||
}
|
||||
}
|
||||
/// The origin that is allowed to execute overweight messages.
|
||||
type ExecuteOverweightOrigin: EnsureOrigin<Self::Origin>;
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
migration::migrate_to_latest::<T>()
|
||||
}
|
||||
|
||||
fn on_idle(_now: T::BlockNumber, max_weight: Weight) -> Weight {
|
||||
// on_idle processes additional messages with any remaining block weight.
|
||||
Self::service_xcmp_queue(max_weight)
|
||||
@@ -93,7 +96,40 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {}
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Services a single overweight XCM.
|
||||
///
|
||||
/// - `origin`: Must pass `ExecuteOverweightOrigin`.
|
||||
/// - `index`: The index of the overweight XCM to service
|
||||
/// - `weight_limit`: The amount of weight that XCM execution may take.
|
||||
///
|
||||
/// Errors:
|
||||
/// - `BadOverweightIndex`: XCM under `index` is not found in the `Overweight` storage map.
|
||||
/// - `BadXcm`: XCM under `index` cannot be properly decoded into a valid XCM format.
|
||||
/// - `WeightOverLimit`: XCM execution may use greater `weight_limit`.
|
||||
///
|
||||
/// Events:
|
||||
/// - `OverweightServiced`: On success.
|
||||
#[pallet::weight(weight_limit.saturating_add(1_000_000))]
|
||||
pub fn service_overweight(
|
||||
origin: OriginFor<T>,
|
||||
index: OverweightIndex,
|
||||
weight_limit: Weight,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
T::ExecuteOverweightOrigin::ensure_origin(origin)?;
|
||||
|
||||
let (sender, sent_at, data) =
|
||||
Overweight::<T>::get(index).ok_or(Error::<T>::BadOverweightIndex)?;
|
||||
let xcm =
|
||||
VersionedXcm::<T::Call>::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, &data)
|
||||
.map_err(|_| Error::<T>::BadXcm)?;
|
||||
let used = Self::handle_xcm_message(sender, sent_at, xcm, weight_limit)
|
||||
.map_err(|_| Error::<T>::WeightOverLimit)?;
|
||||
Overweight::<T>::remove(index);
|
||||
Self::deposit_event(Event::OverweightServiced(index, used));
|
||||
Ok(Some(used.saturating_add(1_000_000)).into())
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
@@ -110,6 +146,10 @@ pub mod pallet {
|
||||
UpwardMessageSent(Option<T::Hash>),
|
||||
/// An HRMP message was sent to a sibling parachain.
|
||||
XcmpMessageSent(Option<T::Hash>),
|
||||
/// An XCM exceeded the individual message weight budget.
|
||||
OverweightEnqueued(ParaId, RelayBlockNumber, OverweightIndex, Weight),
|
||||
/// An XCM from the overweight queue was executed with the given actual weight used.
|
||||
OverweightServiced(OverweightIndex, Weight),
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
@@ -120,15 +160,16 @@ pub mod pallet {
|
||||
BadXcmOrigin,
|
||||
/// Bad XCM data.
|
||||
BadXcm,
|
||||
/// Bad overweight index.
|
||||
BadOverweightIndex,
|
||||
/// Provided weight is possibly not enough to execute the message.
|
||||
WeightOverLimit,
|
||||
}
|
||||
|
||||
/// Status of the inbound XCMP channels.
|
||||
#[pallet::storage]
|
||||
pub(super) type InboundXcmpStatus<T: Config> = StorageValue<
|
||||
_,
|
||||
Vec<(ParaId, InboundStatus, Vec<(RelayBlockNumber, XcmpMessageFormat)>)>,
|
||||
ValueQuery,
|
||||
>;
|
||||
pub(super) type InboundXcmpStatus<T: Config> =
|
||||
StorageValue<_, Vec<InboundChannelDetails>, ValueQuery>;
|
||||
|
||||
/// Inbound aggregate XCMP messages. It can only be one per ParaId/block.
|
||||
#[pallet::storage]
|
||||
@@ -150,7 +191,7 @@ pub mod pallet {
|
||||
/// The bool is true if there is a signal message waiting to be sent.
|
||||
#[pallet::storage]
|
||||
pub(super) type OutboundXcmpStatus<T: Config> =
|
||||
StorageValue<_, Vec<(ParaId, OutboundStatus, bool, u16, u16)>, ValueQuery>;
|
||||
StorageValue<_, Vec<OutboundChannelDetails>, ValueQuery>;
|
||||
|
||||
// The new way of doing it:
|
||||
/// The messages outbound in a given XCMP channel.
|
||||
@@ -166,20 +207,84 @@ pub mod pallet {
|
||||
/// The configuration which controls the dynamics of the outbound queue.
|
||||
#[pallet::storage]
|
||||
pub(super) type QueueConfig<T: Config> = StorageValue<_, QueueConfigData, ValueQuery>;
|
||||
|
||||
/// The messages that exceeded max individual message weight budget.
|
||||
///
|
||||
/// These message stay in this storage map until they are manually dispatched via
|
||||
/// `service_overweight`.
|
||||
#[pallet::storage]
|
||||
pub(super) type Overweight<T: Config> =
|
||||
StorageMap<_, Twox64Concat, OverweightIndex, (ParaId, RelayBlockNumber, Vec<u8>)>;
|
||||
|
||||
/// The number of overweight messages ever recorded in `Overweight`. Also doubles as the next
|
||||
/// available free overweight index.
|
||||
#[pallet::storage]
|
||||
pub(super) type OverweightCount<T: Config> = StorageValue<_, OverweightIndex, ValueQuery>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo)]
|
||||
pub enum InboundStatus {
|
||||
pub enum InboundState {
|
||||
Ok,
|
||||
Suspended,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
|
||||
pub enum OutboundStatus {
|
||||
pub enum OutboundState {
|
||||
Ok,
|
||||
Suspended,
|
||||
}
|
||||
|
||||
/// Struct containing detailed information about the inbound channel.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
pub struct InboundChannelDetails {
|
||||
/// The `ParaId` of the parachain that this channel is connected with.
|
||||
sender: ParaId,
|
||||
/// The state of the channel.
|
||||
state: InboundState,
|
||||
/// The ordered metadata of each inbound message.
|
||||
///
|
||||
/// Contains info about the relay block number that the message was sent at, and the format
|
||||
/// of the incoming message.
|
||||
message_metadata: Vec<(RelayBlockNumber, XcmpMessageFormat)>,
|
||||
}
|
||||
|
||||
/// Struct containing detailed information about the outbound channel.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct OutboundChannelDetails {
|
||||
/// The `ParaId` of the parachain that this channel is connected with.
|
||||
recipient: ParaId,
|
||||
/// The state of the channel.
|
||||
state: OutboundState,
|
||||
/// Whether or not any signals exist in this channel.
|
||||
signals_exist: bool,
|
||||
/// The index of the first outbound message.
|
||||
first_index: u16,
|
||||
/// The index of the last outbound message.
|
||||
last_index: u16,
|
||||
}
|
||||
|
||||
impl OutboundChannelDetails {
|
||||
pub fn new(recipient: ParaId) -> OutboundChannelDetails {
|
||||
OutboundChannelDetails {
|
||||
recipient,
|
||||
state: OutboundState::Ok,
|
||||
signals_exist: false,
|
||||
first_index: 0,
|
||||
last_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_signals(mut self) -> OutboundChannelDetails {
|
||||
self.signals_exist = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_suspended_state(mut self) -> OutboundChannelDetails {
|
||||
self.state = OutboundState::Suspended;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
|
||||
pub struct QueueConfigData {
|
||||
/// The number of pages of messages which must be in the queue for the other side to be told to
|
||||
@@ -196,6 +301,22 @@ pub struct QueueConfigData {
|
||||
/// The speed to which the available weight approaches the maximum weight. A lower number
|
||||
/// results in a faster progression. A value of 1 makes the entire weight available initially.
|
||||
weight_restrict_decay: Weight,
|
||||
/// The maximum amount of weight any individual message may consume. Messages above this weight
|
||||
/// go into the overweight queue and may only be serviced explicitly.
|
||||
xcmp_max_individual_weight: Weight,
|
||||
}
|
||||
|
||||
impl Default for QueueConfigData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
suspend_threshold: 2,
|
||||
drop_threshold: 5,
|
||||
resume_threshold: 1,
|
||||
threshold_weight: 100_000,
|
||||
weight_restrict_decay: 2,
|
||||
xcmp_max_individual_weight: 20 * WEIGHT_PER_MILLIS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, TypeInfo)]
|
||||
@@ -242,13 +363,13 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
|
||||
let mut s = <OutboundXcmpStatus<T>>::get();
|
||||
let index = s.iter().position(|item| item.0 == recipient).unwrap_or_else(|| {
|
||||
s.push((recipient, OutboundStatus::Ok, false, 0, 0));
|
||||
let index = s.iter().position(|item| item.recipient == recipient).unwrap_or_else(|| {
|
||||
s.push(OutboundChannelDetails::new(recipient));
|
||||
s.len() - 1
|
||||
});
|
||||
let have_active = s[index].4 > s[index].3;
|
||||
let have_active = s[index].last_index > s[index].first_index;
|
||||
let appended = have_active &&
|
||||
<OutboundXcmpMessages<T>>::mutate(recipient, s[index].4 - 1, |s| {
|
||||
<OutboundXcmpMessages<T>>::mutate(recipient, s[index].last_index - 1, |s| {
|
||||
if XcmpMessageFormat::decode_and_advance_with_depth_limit(
|
||||
MAX_XCM_DECODE_DEPTH,
|
||||
&mut &s[..],
|
||||
@@ -263,15 +384,15 @@ impl<T: Config> Pallet<T> {
|
||||
return true
|
||||
});
|
||||
if appended {
|
||||
Ok((s[index].4 - s[index].3 - 1) as u32)
|
||||
Ok((s[index].last_index - s[index].first_index - 1) as u32)
|
||||
} else {
|
||||
// Need to add a new page.
|
||||
let page_index = s[index].4;
|
||||
s[index].4 += 1;
|
||||
let page_index = s[index].last_index;
|
||||
s[index].last_index += 1;
|
||||
let mut new_page = format.encode();
|
||||
new_page.extend_from_slice(&data[..]);
|
||||
<OutboundXcmpMessages<T>>::insert(recipient, page_index, new_page);
|
||||
let r = (s[index].4 - s[index].3 - 1) as u32;
|
||||
let r = (s[index].last_index - s[index].first_index - 1) as u32;
|
||||
<OutboundXcmpStatus<T>>::put(s);
|
||||
Ok(r)
|
||||
}
|
||||
@@ -281,10 +402,10 @@ impl<T: Config> Pallet<T> {
|
||||
/// block.
|
||||
fn send_signal(dest: ParaId, signal: ChannelSignal) -> Result<(), ()> {
|
||||
let mut s = <OutboundXcmpStatus<T>>::get();
|
||||
if let Some(index) = s.iter().position(|item| item.0 == dest) {
|
||||
s[index].2 = true;
|
||||
if let Some(index) = s.iter().position(|item| item.recipient == dest) {
|
||||
s[index].signals_exist = true;
|
||||
} else {
|
||||
s.push((dest, OutboundStatus::Ok, true, 0, 0));
|
||||
s.push(OutboundChannelDetails::new(dest).with_signals());
|
||||
}
|
||||
<SignalMessages<T>>::mutate(dest, |page| {
|
||||
if page.is_empty() {
|
||||
@@ -366,6 +487,7 @@ impl<T: Config> Pallet<T> {
|
||||
sender: ParaId,
|
||||
(sent_at, format): (RelayBlockNumber, XcmpMessageFormat),
|
||||
max_weight: Weight,
|
||||
max_individual_weight: Weight,
|
||||
) -> (Weight, bool) {
|
||||
let data = <InboundXcmpMessages<T>>::get(sender, sent_at);
|
||||
let mut last_remaining_fragments;
|
||||
@@ -382,7 +504,22 @@ impl<T: Config> Pallet<T> {
|
||||
let weight = max_weight - weight_used;
|
||||
match Self::handle_xcm_message(sender, sent_at, xcm, weight) {
|
||||
Ok(used) => weight_used = weight_used.saturating_add(used),
|
||||
Err(XcmError::TooMuchWeightRequired) => {
|
||||
Err(XcmError::WeightLimitReached(required))
|
||||
if required > max_individual_weight =>
|
||||
{
|
||||
// overweight - add to overweight queue and continue with message
|
||||
// execution consuming the message.
|
||||
let msg_len = last_remaining_fragments
|
||||
.len()
|
||||
.saturating_sub(remaining_fragments.len());
|
||||
let overweight_xcm = last_remaining_fragments[..msg_len].to_vec();
|
||||
let index = Self::stash_overweight(sender, sent_at, overweight_xcm);
|
||||
let e = Event::OverweightEnqueued(sender, sent_at, index, required);
|
||||
Self::deposit_event(e);
|
||||
},
|
||||
Err(XcmError::WeightLimitReached(required))
|
||||
if required <= max_weight =>
|
||||
{
|
||||
// That message didn't get processed this time because of being
|
||||
// too heavy. We leave it around for next time and bail.
|
||||
remaining_fragments = last_remaining_fragments;
|
||||
@@ -438,6 +575,22 @@ impl<T: Config> Pallet<T> {
|
||||
(weight_used, is_empty)
|
||||
}
|
||||
|
||||
/// Puts a given XCM into the list of overweight messages, allowing it to be executed later.
|
||||
fn stash_overweight(
|
||||
sender: ParaId,
|
||||
sent_at: RelayBlockNumber,
|
||||
xcm: Vec<u8>,
|
||||
) -> OverweightIndex {
|
||||
let index = <Self as Store>::OverweightCount::mutate(|count| {
|
||||
let index = *count;
|
||||
*count += 1;
|
||||
index
|
||||
});
|
||||
|
||||
<Self as Store>::Overweight::insert(index, (sender, sent_at, xcm));
|
||||
index
|
||||
}
|
||||
|
||||
/// Service the incoming XCMP message queue attempting to execute up to `max_weight` execution
|
||||
/// weight of messages.
|
||||
///
|
||||
@@ -471,8 +624,13 @@ impl<T: Config> Pallet<T> {
|
||||
return 0
|
||||
}
|
||||
|
||||
let QueueConfigData { resume_threshold, threshold_weight, weight_restrict_decay, .. } =
|
||||
<QueueConfig<T>>::get();
|
||||
let QueueConfigData {
|
||||
resume_threshold,
|
||||
threshold_weight,
|
||||
weight_restrict_decay,
|
||||
xcmp_max_individual_weight,
|
||||
..
|
||||
} = <QueueConfig<T>>::get();
|
||||
|
||||
let mut shuffled = Self::create_shuffle(status.len());
|
||||
let mut weight_used = 0;
|
||||
@@ -491,7 +649,7 @@ impl<T: Config> Pallet<T> {
|
||||
max_weight.saturating_sub(weight_used) >= threshold_weight
|
||||
{
|
||||
let index = shuffled[shuffle_index];
|
||||
let sender = status[index].0;
|
||||
let sender = status[index].sender;
|
||||
|
||||
if weight_available != max_weight {
|
||||
// Get incrementally closer to freeing up max_weight for message execution over the
|
||||
@@ -508,34 +666,38 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
let weight_processed = if status[index].2.is_empty() {
|
||||
let weight_processed = if status[index].message_metadata.is_empty() {
|
||||
debug_assert!(false, "channel exists in status; there must be messages; qed");
|
||||
0
|
||||
} else {
|
||||
// Process up to one block's worth for now.
|
||||
let weight_remaining = weight_available.saturating_sub(weight_used);
|
||||
let (weight_processed, is_empty) =
|
||||
Self::process_xcmp_message(sender, status[index].2[0], weight_remaining);
|
||||
let (weight_processed, is_empty) = Self::process_xcmp_message(
|
||||
sender,
|
||||
status[index].message_metadata[0],
|
||||
weight_remaining,
|
||||
xcmp_max_individual_weight,
|
||||
);
|
||||
if is_empty {
|
||||
status[index].2.remove(0);
|
||||
status[index].message_metadata.remove(0);
|
||||
}
|
||||
weight_processed
|
||||
};
|
||||
weight_used += weight_processed;
|
||||
|
||||
if status[index].2.len() as u32 <= resume_threshold &&
|
||||
status[index].1 == InboundStatus::Suspended
|
||||
if status[index].message_metadata.len() as u32 <= resume_threshold &&
|
||||
status[index].state == InboundState::Suspended
|
||||
{
|
||||
// Resume
|
||||
let r = Self::send_signal(sender, ChannelSignal::Resume);
|
||||
debug_assert!(r.is_ok(), "WARNING: Failed sending resume into suspended channel");
|
||||
status[index].1 = InboundStatus::Ok;
|
||||
status[index].state = InboundState::Ok;
|
||||
}
|
||||
|
||||
// If there are more and we're making progress, we process them after we've given the
|
||||
// other channels a look in. If we've still not unlocked all weight, then we set them
|
||||
// up for processing a second time anyway.
|
||||
if !status[index].2.is_empty() &&
|
||||
if !status[index].message_metadata.is_empty() &&
|
||||
(weight_processed > 0 || weight_available != max_weight)
|
||||
{
|
||||
if shuffle_index + 1 == shuffled.len() {
|
||||
@@ -548,7 +710,7 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
|
||||
// Only retain the senders that have non-empty queues.
|
||||
status.retain(|item| !item.2.is_empty());
|
||||
status.retain(|item| !item.message_metadata.is_empty());
|
||||
|
||||
<InboundXcmpStatus<T>>::put(status);
|
||||
weight_used
|
||||
@@ -556,28 +718,28 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
fn suspend_channel(target: ParaId) {
|
||||
<OutboundXcmpStatus<T>>::mutate(|s| {
|
||||
if let Some(index) = s.iter().position(|item| item.0 == target) {
|
||||
let ok = s[index].1 == OutboundStatus::Ok;
|
||||
if let Some(index) = s.iter().position(|item| item.recipient == target) {
|
||||
let ok = s[index].state == OutboundState::Ok;
|
||||
debug_assert!(ok, "WARNING: Attempt to suspend channel that was not Ok.");
|
||||
s[index].1 = OutboundStatus::Suspended;
|
||||
s[index].state = OutboundState::Suspended;
|
||||
} else {
|
||||
s.push((target, OutboundStatus::Suspended, false, 0, 0));
|
||||
s.push(OutboundChannelDetails::new(target).with_suspended_state());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn resume_channel(target: ParaId) {
|
||||
<OutboundXcmpStatus<T>>::mutate(|s| {
|
||||
if let Some(index) = s.iter().position(|item| item.0 == target) {
|
||||
let suspended = s[index].1 == OutboundStatus::Suspended;
|
||||
if let Some(index) = s.iter().position(|item| item.recipient == target) {
|
||||
let suspended = s[index].state == OutboundState::Suspended;
|
||||
debug_assert!(
|
||||
suspended,
|
||||
"WARNING: Attempt to resume channel that was not suspended."
|
||||
);
|
||||
if s[index].3 == s[index].4 {
|
||||
if s[index].first_index == s[index].last_index {
|
||||
s.remove(index);
|
||||
} else {
|
||||
s[index].1 = OutboundStatus::Ok;
|
||||
s[index].state = OutboundState::Ok;
|
||||
}
|
||||
} else {
|
||||
debug_assert!(false, "WARNING: Attempt to resume channel that was not suspended.");
|
||||
@@ -619,11 +781,12 @@ impl<T: Config> XcmpMessageHandler for Pallet<T> {
|
||||
}
|
||||
} else {
|
||||
// Record the fact we received it.
|
||||
match status.binary_search_by_key(&sender, |item| item.0) {
|
||||
match status.binary_search_by_key(&sender, |item| item.sender) {
|
||||
Ok(i) => {
|
||||
let count = status[i].2.len();
|
||||
if count as u32 >= suspend_threshold && status[i].1 == InboundStatus::Ok {
|
||||
status[i].1 = InboundStatus::Suspended;
|
||||
let count = status[i].message_metadata.len();
|
||||
if count as u32 >= suspend_threshold && status[i].state == InboundState::Ok
|
||||
{
|
||||
status[i].state = InboundState::Suspended;
|
||||
let r = Self::send_signal(sender, ChannelSignal::Suspend);
|
||||
if r.is_err() {
|
||||
log::warn!(
|
||||
@@ -632,7 +795,7 @@ impl<T: Config> XcmpMessageHandler for Pallet<T> {
|
||||
}
|
||||
}
|
||||
if (count as u32) < drop_threshold {
|
||||
status[i].2.push((sent_at, format));
|
||||
status[i].message_metadata.push((sent_at, format));
|
||||
} else {
|
||||
debug_assert!(
|
||||
false,
|
||||
@@ -640,7 +803,11 @@ impl<T: Config> XcmpMessageHandler for Pallet<T> {
|
||||
);
|
||||
}
|
||||
},
|
||||
Err(_) => status.push((sender, InboundStatus::Ok, vec![(sent_at, format)])),
|
||||
Err(_) => status.push(InboundChannelDetails {
|
||||
sender,
|
||||
state: InboundState::Ok,
|
||||
message_metadata: vec![(sent_at, format)],
|
||||
}),
|
||||
}
|
||||
// Queue the payload for later execution.
|
||||
<InboundXcmpMessages<T>>::insert(sender, sent_at, data_ref);
|
||||
@@ -664,47 +831,53 @@ impl<T: Config> XcmpMessageSource for Pallet<T> {
|
||||
let mut result = Vec::with_capacity(max_message_count);
|
||||
|
||||
for status in statuses.iter_mut() {
|
||||
let (para_id, outbound_status, mut signalling, mut begin, mut end) = *status;
|
||||
let OutboundChannelDetails {
|
||||
recipient: para_id,
|
||||
state: outbound_state,
|
||||
mut signals_exist,
|
||||
mut first_index,
|
||||
mut last_index,
|
||||
} = *status;
|
||||
|
||||
if result.len() == max_message_count {
|
||||
// We check this condition in the beginning of the loop so that we don't include
|
||||
// a message where the limit is 0.
|
||||
break
|
||||
}
|
||||
if outbound_status == OutboundStatus::Suspended {
|
||||
if outbound_state == OutboundState::Suspended {
|
||||
continue
|
||||
}
|
||||
let (max_size_now, max_size_ever) = match T::ChannelInfo::get_channel_status(para_id) {
|
||||
ChannelStatus::Closed => {
|
||||
// This means that there is no such channel anymore. Nothing to be done but
|
||||
// swallow the messages and discard the status.
|
||||
for i in begin..end {
|
||||
for i in first_index..last_index {
|
||||
<OutboundXcmpMessages<T>>::remove(para_id, i);
|
||||
}
|
||||
if signalling {
|
||||
if signals_exist {
|
||||
<SignalMessages<T>>::remove(para_id);
|
||||
}
|
||||
*status = (para_id, OutboundStatus::Ok, false, 0, 0);
|
||||
*status = OutboundChannelDetails::new(para_id);
|
||||
continue
|
||||
},
|
||||
ChannelStatus::Full => continue,
|
||||
ChannelStatus::Ready(n, e) => (n, e),
|
||||
};
|
||||
|
||||
let page = if signalling {
|
||||
let page = if signals_exist {
|
||||
let page = <SignalMessages<T>>::get(para_id);
|
||||
if page.len() < max_size_now {
|
||||
<SignalMessages<T>>::remove(para_id);
|
||||
signalling = false;
|
||||
signals_exist = false;
|
||||
page
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else if end > begin {
|
||||
let page = <OutboundXcmpMessages<T>>::get(para_id, begin);
|
||||
} else if last_index > first_index {
|
||||
let page = <OutboundXcmpMessages<T>>::get(para_id, first_index);
|
||||
if page.len() < max_size_now {
|
||||
<OutboundXcmpMessages<T>>::remove(para_id, begin);
|
||||
begin += 1;
|
||||
<OutboundXcmpMessages<T>>::remove(para_id, first_index);
|
||||
first_index += 1;
|
||||
page
|
||||
} else {
|
||||
continue
|
||||
@@ -712,9 +885,9 @@ impl<T: Config> XcmpMessageSource for Pallet<T> {
|
||||
} else {
|
||||
continue
|
||||
};
|
||||
if begin == end {
|
||||
begin = 0;
|
||||
end = 0;
|
||||
if first_index == last_index {
|
||||
first_index = 0;
|
||||
last_index = 0;
|
||||
}
|
||||
|
||||
if page.len() > max_size_ever {
|
||||
@@ -726,7 +899,13 @@ impl<T: Config> XcmpMessageSource for Pallet<T> {
|
||||
result.push((para_id, page));
|
||||
}
|
||||
|
||||
*status = (para_id, outbound_status, signalling, begin, end);
|
||||
*status = OutboundChannelDetails {
|
||||
recipient: para_id,
|
||||
state: outbound_state,
|
||||
signals_exist,
|
||||
first_index,
|
||||
last_index,
|
||||
};
|
||||
}
|
||||
|
||||
// Sort the outbound messages by ascending recipient para id to satisfy the acceptance
|
||||
@@ -741,7 +920,9 @@ impl<T: Config> XcmpMessageSource for Pallet<T> {
|
||||
//
|
||||
// To mitigate this we shift all processed elements towards the end of the vector using
|
||||
// `rotate_left`. To get intuition how it works see the examples in its rustdoc.
|
||||
statuses.retain(|x| x.1 == OutboundStatus::Suspended || x.2 || x.3 < x.4);
|
||||
statuses.retain(|x| {
|
||||
x.state == OutboundState::Suspended || x.signals_exist || x.first_index < x.last_index
|
||||
});
|
||||
|
||||
// old_status_len must be >= status.len() since we never add anything to status.
|
||||
let pruned = old_statuses_len - statuses.len();
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! A module that is responsible for migration of storage.
|
||||
|
||||
use crate::{Config, Pallet, Store};
|
||||
use frame_support::{pallet_prelude::*, traits::StorageVersion, weights::Weight};
|
||||
|
||||
/// The current storage version.
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
/// Migrates the pallet storage to the most recent version, checking and setting the
|
||||
/// `StorageVersion`.
|
||||
pub fn migrate_to_latest<T: Config>() -> Weight {
|
||||
let mut weight = 0;
|
||||
|
||||
if StorageVersion::get::<Pallet<T>>() == 0 {
|
||||
weight += migrate_to_v1::<T>();
|
||||
StorageVersion::new(1).put::<Pallet<T>>();
|
||||
}
|
||||
|
||||
weight
|
||||
}
|
||||
|
||||
mod v0 {
|
||||
use super::*;
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub struct QueueConfigData {
|
||||
pub suspend_threshold: u32,
|
||||
pub drop_threshold: u32,
|
||||
pub resume_threshold: u32,
|
||||
pub threshold_weight: Weight,
|
||||
pub weight_restrict_decay: Weight,
|
||||
}
|
||||
|
||||
impl Default for QueueConfigData {
|
||||
fn default() -> Self {
|
||||
QueueConfigData {
|
||||
suspend_threshold: 2,
|
||||
drop_threshold: 5,
|
||||
resume_threshold: 1,
|
||||
threshold_weight: 100_000,
|
||||
weight_restrict_decay: 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Migrates `QueueConfigData` from v0 (without the `xcmp_max_individual_weight` field) to v1 (with
|
||||
/// max individual weight).
|
||||
/// Uses the `Default` implementation of `QueueConfigData` to choose a value for
|
||||
/// `xcmp_max_individual_weight`.
|
||||
///
|
||||
/// NOTE: Only use this function if you know what you're doing. Default to using
|
||||
/// `migrate_to_latest`.
|
||||
pub fn migrate_to_v1<T: Config>() -> Weight {
|
||||
let translate = |pre: v0::QueueConfigData| -> super::QueueConfigData {
|
||||
super::QueueConfigData {
|
||||
suspend_threshold: pre.suspend_threshold,
|
||||
drop_threshold: pre.drop_threshold,
|
||||
resume_threshold: pre.resume_threshold,
|
||||
threshold_weight: pre.threshold_weight,
|
||||
weight_restrict_decay: pre.weight_restrict_decay,
|
||||
xcmp_max_individual_weight: super::QueueConfigData::default()
|
||||
.xcmp_max_individual_weight,
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(_) = <Pallet<T> as Store>::QueueConfig::translate(|pre| pre.map(translate)) {
|
||||
log::error!(
|
||||
target: super::LOG_TARGET,
|
||||
"unexpected error when performing translation of the QueueConfig type during storage upgrade to v1"
|
||||
);
|
||||
}
|
||||
|
||||
T::DbWeight::get().reads_writes(1, 1)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{new_test_ext, Test};
|
||||
|
||||
#[test]
|
||||
fn test_migration_to_v1() {
|
||||
let v0 = v0::QueueConfigData {
|
||||
suspend_threshold: 5,
|
||||
drop_threshold: 12,
|
||||
resume_threshold: 3,
|
||||
threshold_weight: 333_333,
|
||||
weight_restrict_decay: 1,
|
||||
};
|
||||
|
||||
new_test_ext().execute_with(|| {
|
||||
// Put the v0 version in the state
|
||||
frame_support::storage::unhashed::put_raw(
|
||||
&crate::QueueConfig::<Test>::hashed_key(),
|
||||
&v0.encode(),
|
||||
);
|
||||
|
||||
migrate_to_v1::<Test>();
|
||||
|
||||
let v1 = crate::QueueConfig::<Test>::get();
|
||||
|
||||
assert_eq!(v0.suspend_threshold, v1.suspend_threshold);
|
||||
assert_eq!(v0.drop_threshold, v1.drop_threshold);
|
||||
assert_eq!(v0.resume_threshold, v1.resume_threshold);
|
||||
assert_eq!(v0.threshold_weight, v1.threshold_weight);
|
||||
assert_eq!(v0.weight_restrict_decay, v1.weight_restrict_decay);
|
||||
assert_eq!(v1.xcmp_max_individual_weight, 20_000_000_000);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
use super::*;
|
||||
use crate as xcmp_queue;
|
||||
use frame_support::parameter_types;
|
||||
use frame_system::EnsureRoot;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
@@ -75,6 +76,7 @@ impl frame_system::Config for Test {
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = SS58Prefix;
|
||||
type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Test>;
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -160,6 +162,7 @@ impl Config for Test {
|
||||
type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
|
||||
type ChannelInfo = ParachainSystem;
|
||||
type VersionWrapper = ();
|
||||
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
|
||||
}
|
||||
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
|
||||
use super::*;
|
||||
use cumulus_primitives_core::XcmpMessageHandler;
|
||||
use mock::{new_test_ext, Test, XcmpQueue};
|
||||
use frame_support::assert_noop;
|
||||
use mock::{new_test_ext, Origin, Test, XcmpQueue};
|
||||
|
||||
#[test]
|
||||
fn one_message_does_not_panic() {
|
||||
@@ -30,6 +31,7 @@ fn one_message_does_not_panic() {
|
||||
|
||||
#[test]
|
||||
#[should_panic = "Invalid incoming blob message data"]
|
||||
#[cfg(debug_assertions)]
|
||||
fn bad_message_is_handled() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let bad_data = vec![
|
||||
@@ -40,12 +42,13 @@ fn bad_message_is_handled() {
|
||||
InboundXcmpMessages::<Test>::insert(ParaId::from(1000), 1, bad_data);
|
||||
let format = XcmpMessageFormat::ConcatenatedEncodedBlob;
|
||||
// This should exit with an error.
|
||||
XcmpQueue::process_xcmp_message(1000.into(), (1, format), 10_000_000_000);
|
||||
XcmpQueue::process_xcmp_message(1000.into(), (1, format), 10_000_000_000, 10_000_000_000);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic = "Invalid incoming blob message data"]
|
||||
#[cfg(debug_assertions)]
|
||||
fn other_bad_message_is_handled() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let bad_data = vec![
|
||||
@@ -56,6 +59,26 @@ fn other_bad_message_is_handled() {
|
||||
InboundXcmpMessages::<Test>::insert(ParaId::from(1000), 1, bad_data);
|
||||
let format = XcmpMessageFormat::ConcatenatedEncodedBlob;
|
||||
// This should exit with an error.
|
||||
XcmpQueue::process_xcmp_message(1000.into(), (1, format), 10_000_000_000);
|
||||
XcmpQueue::process_xcmp_message(1000.into(), (1, format), 10_000_000_000, 10_000_000_000);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn service_overweight_unknown() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_noop!(
|
||||
XcmpQueue::service_overweight(Origin::root(), 0, 1000),
|
||||
Error::<Test>::BadOverweightIndex,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn service_overweight_bad_xcm_format() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let bad_xcm = vec![255];
|
||||
Overweight::<Test>::insert(0, (ParaId::from(1000), 0, bad_xcm));
|
||||
|
||||
assert_noop!(XcmpQueue::service_overweight(Origin::root(), 0, 1000), Error::<Test>::BadXcm);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,13 +2,21 @@
|
||||
|
||||
A new [Cumulus](https://github.com/paritytech/cumulus/)-based Substrate node, ready for hacking ☁️..
|
||||
|
||||
This project is a fork of the [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template)
|
||||
This project is originally a fork of the
|
||||
[Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template)
|
||||
modified to include dependencies required for registering this node as a **parathread** or
|
||||
**parachain** to the Rococo **relay chain**.
|
||||
Rococo is [Polkadot's parachain testnet](https://polkadot.network/blog/introducing-rococo-polkadots-parachain-testnet/) 👑.
|
||||
**parachain** to a **relay chain**.
|
||||
|
||||
The stand-alone version of this template is hosted on the
|
||||
[Substrate Devhub Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template/)
|
||||
for each release of Polkadot. It is generated directly to the upstream
|
||||
[Parachain Template in Cumulus](https://github.com/paritytech/cumulus/tree/master/parachain-template)
|
||||
at each release branch using the
|
||||
[Substrate Template Generator](https://github.com/paritytech/substrate-template-generator/).
|
||||
|
||||
👉 Learn more about parachains [here](https://wiki.polkadot.network/docs/learn-parachains), and
|
||||
parathreads [here](https://wiki.polkadot.network/docs/learn-parathreads).
|
||||
|
||||
To learn about how to actually use the template to hack together your own parachain check out the
|
||||
`README` from the [`substrate-parachain-template` repository](https://github.com/substrate-developer-hub/substrate-parachain-template/).
|
||||
|
||||
🧙 Learn about how to use this template and run your own parachain testnet for it in the
|
||||
[Devhub Cumulus Tutorial](https://docs.substrate.io/tutorials/v3/cumulus/start-relay/).
|
||||
@@ -6,7 +6,7 @@ description = "A new Cumulus FRAME-based Substrate Node, ready for hacking toget
|
||||
license = "Unlicense"
|
||||
homepage = "https://substrate.io"
|
||||
repository = "https://github.com/paritytech/cumulus/"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
@@ -21,13 +21,14 @@ path = "src/main.rs"
|
||||
|
||||
[features]
|
||||
runtime-benchmarks = ["parachain-template-runtime/runtime-benchmarks"]
|
||||
try-runtime = [ "parachain-template-runtime/try-runtime" ]
|
||||
|
||||
[dependencies]
|
||||
derive_more = "0.99.2"
|
||||
log = "0.4.14"
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
||||
structopt = "0.3.8"
|
||||
serde = { version = "1.0.119", features = ["derive"] }
|
||||
serde = { version = "1.0.132", features = ["derive"] }
|
||||
hex-literal = "0.3.1"
|
||||
|
||||
# RPC related Dependencies
|
||||
@@ -39,6 +40,7 @@ parachain-template-runtime = { path = "../runtime" }
|
||||
# Substrate Dependencies
|
||||
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
try-runtime-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
@@ -86,10 +88,12 @@ cumulus-client-network = { path = "../../client/network" }
|
||||
cumulus-client-service = { path = "../../client/service" }
|
||||
cumulus-primitives-core = { path = "../../primitives/core" }
|
||||
cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" }
|
||||
cumulus-relay-chain-interface = { path = "../../client/relay-chain-interface" }
|
||||
cumulus-relay-chain-local = { path = "../../client/relay-chain-local" }
|
||||
|
||||
# Polkadot dependencies
|
||||
polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
polkadot-test-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ pub type ChainSpec =
|
||||
sc_service::GenericChainSpec<parachain_template_runtime::GenesisConfig, Extensions>;
|
||||
|
||||
/// Helper function to generate a crypto pair from seed
|
||||
pub fn get_pair_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
|
||||
pub fn get_public_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
|
||||
TPublic::Pair::from_string(&format!("//{}", seed), None)
|
||||
.expect("static values are valid; qed")
|
||||
.public()
|
||||
@@ -40,7 +40,7 @@ type AccountPublic = <Signature as Verify>::Signer;
|
||||
///
|
||||
/// This function's return type must always match the session keys of the chain in tuple format.
|
||||
pub fn get_collator_keys_from_seed(seed: &str) -> AuraId {
|
||||
get_pair_from_seed::<AuraId>(seed)
|
||||
get_public_from_seed::<AuraId>(seed)
|
||||
}
|
||||
|
||||
/// Helper function to generate an account ID from seed
|
||||
@@ -48,7 +48,7 @@ pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
|
||||
where
|
||||
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
|
||||
{
|
||||
AccountPublic::from(get_pair_from_seed::<TPublic>(seed)).into_account()
|
||||
AccountPublic::from(get_public_from_seed::<TPublic>(seed)).into_account()
|
||||
}
|
||||
|
||||
/// Generate the session keys from individual elements.
|
||||
@@ -58,10 +58,10 @@ pub fn template_session_keys(keys: AuraId) -> parachain_template_runtime::Sessio
|
||||
parachain_template_runtime::SessionKeys { aura: keys }
|
||||
}
|
||||
|
||||
pub fn development_config(id: ParaId) -> ChainSpec {
|
||||
pub fn development_config() -> ChainSpec {
|
||||
// Give your base currency a unit name and decimal places
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("tokenSymbol".into(), "ROC".into());
|
||||
properties.insert("tokenSymbol".into(), "UNIT".into());
|
||||
properties.insert("tokenDecimals".into(), 12.into());
|
||||
properties.insert("ss58Format".into(), 42.into());
|
||||
|
||||
@@ -98,24 +98,24 @@ pub fn development_config(id: ParaId) -> ChainSpec {
|
||||
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||
],
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Extensions {
|
||||
relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
|
||||
para_id: id.into(),
|
||||
para_id: 1000,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn local_testnet_config(id: ParaId) -> ChainSpec {
|
||||
pub fn local_testnet_config() -> ChainSpec {
|
||||
// Give your base currency a unit name and decimal places
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("tokenSymbol".into(), "ROC".into());
|
||||
properties.insert("tokenSymbol".into(), "UNIT".into());
|
||||
properties.insert("tokenDecimals".into(), 12.into());
|
||||
properties.insert("ss58Format".into(), 42.into());
|
||||
|
||||
@@ -152,11 +152,11 @@ pub fn local_testnet_config(id: ParaId) -> ChainSpec {
|
||||
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||
],
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
// Bootnodes
|
||||
vec![],
|
||||
Vec::new(),
|
||||
// Telemetry
|
||||
None,
|
||||
// Protocol ID
|
||||
@@ -166,7 +166,7 @@ pub fn local_testnet_config(id: ParaId) -> ChainSpec {
|
||||
// Extensions
|
||||
Extensions {
|
||||
relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
|
||||
para_id: id.into(),
|
||||
para_id: 1000,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -181,7 +181,6 @@ fn testnet_genesis(
|
||||
code: parachain_template_runtime::WASM_BINARY
|
||||
.expect("WASM binary was not build, please build it!")
|
||||
.to_vec(),
|
||||
changes_trie_config: Default::default(),
|
||||
},
|
||||
balances: parachain_template_runtime::BalancesConfig {
|
||||
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
|
||||
@@ -194,8 +193,7 @@ fn testnet_genesis(
|
||||
},
|
||||
session: parachain_template_runtime::SessionConfig {
|
||||
keys: invulnerables
|
||||
.iter()
|
||||
.cloned()
|
||||
.into_iter()
|
||||
.map(|(acc, aura)| {
|
||||
(
|
||||
acc.clone(), // account id
|
||||
|
||||
@@ -37,6 +37,9 @@ pub enum Subcommand {
|
||||
/// The custom benchmark subcommmand benchmarking runtime pallets.
|
||||
#[structopt(name = "benchmark", about = "Benchmark runtime pallets.")]
|
||||
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
|
||||
|
||||
/// Try some testing command against a specified runtime state.
|
||||
TryRuntime(try_runtime_cli::TryRuntimeCmd),
|
||||
}
|
||||
|
||||
/// Command for exporting the genesis state of the parachain
|
||||
@@ -46,18 +49,12 @@ pub struct ExportGenesisStateCommand {
|
||||
#[structopt(parse(from_os_str))]
|
||||
pub output: Option<PathBuf>,
|
||||
|
||||
/// Id of the parachain this state is for.
|
||||
///
|
||||
/// Default: 100
|
||||
#[structopt(long, conflicts_with = "chain")]
|
||||
pub parachain_id: Option<u32>,
|
||||
|
||||
/// Write output in binary. Default is to write in hex.
|
||||
#[structopt(short, long)]
|
||||
pub raw: bool,
|
||||
|
||||
/// The name of the chain for that the genesis state should be exported.
|
||||
#[structopt(long, conflicts_with = "parachain-id")]
|
||||
#[structopt(long)]
|
||||
pub chain: Option<String>,
|
||||
}
|
||||
|
||||
@@ -90,9 +87,9 @@ pub struct Cli {
|
||||
#[structopt(flatten)]
|
||||
pub run: cumulus_client_cli::RunCmd,
|
||||
|
||||
/// Relaychain arguments
|
||||
/// Relay chain arguments
|
||||
#[structopt(raw = true)]
|
||||
pub relaychain_args: Vec<String>,
|
||||
pub relay_chain_args: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -13,19 +13,19 @@ use sc_cli::{
|
||||
ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
|
||||
NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,
|
||||
};
|
||||
use sc_service::config::{BasePath, PrometheusConfig};
|
||||
use sc_service::{
|
||||
config::{BasePath, PrometheusConfig},
|
||||
TaskManager,
|
||||
};
|
||||
use sp_core::hexdisplay::HexDisplay;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use std::{io::Write, net::SocketAddr};
|
||||
|
||||
fn load_spec(
|
||||
id: &str,
|
||||
para_id: ParaId,
|
||||
) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
|
||||
fn load_spec(id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
|
||||
Ok(match id {
|
||||
"dev" => Box::new(chain_spec::development_config(para_id)),
|
||||
"template-rococo" => Box::new(chain_spec::local_testnet_config(para_id)),
|
||||
"" | "local" => Box::new(chain_spec::local_testnet_config(para_id)),
|
||||
"dev" => Box::new(chain_spec::development_config()),
|
||||
"template-rococo" => Box::new(chain_spec::local_testnet_config()),
|
||||
"" | "local" => Box::new(chain_spec::local_testnet_config()),
|
||||
path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
|
||||
})
|
||||
}
|
||||
@@ -40,13 +40,11 @@ impl SubstrateCli for Cli {
|
||||
}
|
||||
|
||||
fn description() -> String {
|
||||
format!(
|
||||
"Parachain Collator Template\n\nThe command-line arguments provided first will be \
|
||||
"Parachain Collator Template\n\nThe command-line arguments provided first will be \
|
||||
passed to the parachain node, while the arguments provided after -- will be passed \
|
||||
to the relaychain node.\n\n\
|
||||
{} [parachain-args] -- [relaychain-args]",
|
||||
Self::executable_name()
|
||||
)
|
||||
to the relay chain node.\n\n\
|
||||
parachain-collator <parachain-args> -- <relay-chain-args>"
|
||||
.into()
|
||||
}
|
||||
|
||||
fn author() -> String {
|
||||
@@ -62,7 +60,7 @@ impl SubstrateCli for Cli {
|
||||
}
|
||||
|
||||
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
|
||||
load_spec(id, self.run.parachain_id.unwrap_or(2000).into())
|
||||
load_spec(id)
|
||||
}
|
||||
|
||||
fn native_runtime_version(_: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {
|
||||
@@ -82,8 +80,8 @@ impl SubstrateCli for RelayChainCli {
|
||||
fn description() -> String {
|
||||
"Parachain Collator Template\n\nThe command-line arguments provided first will be \
|
||||
passed to the parachain node, while the arguments provided after -- will be passed \
|
||||
to the relaychain node.\n\n\
|
||||
parachain-collator [parachain-args] -- [relaychain-args]"
|
||||
to the relay chain node.\n\n\
|
||||
parachain-collator <parachain-args> -- <relay-chain-args>"
|
||||
.into()
|
||||
}
|
||||
|
||||
@@ -171,7 +169,7 @@ pub fn run() -> Result<()> {
|
||||
runner.sync_run(|config| {
|
||||
let polkadot_cli = RelayChainCli::new(
|
||||
&config,
|
||||
[RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()),
|
||||
[RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()),
|
||||
);
|
||||
|
||||
let polkadot_config = SubstrateCli::create_configuration(
|
||||
@@ -194,10 +192,9 @@ pub fn run() -> Result<()> {
|
||||
builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
|
||||
let _ = builder.init();
|
||||
|
||||
let block: Block = generate_genesis_block(&load_spec(
|
||||
¶ms.chain.clone().unwrap_or_default(),
|
||||
params.parachain_id.unwrap_or(2000).into(),
|
||||
)?)?;
|
||||
let spec = load_spec(¶ms.chain.clone().unwrap_or_default())?;
|
||||
let state_version = Cli::native_runtime_version(&spec).state_version();
|
||||
let block: Block = generate_genesis_block(&spec, state_version)?;
|
||||
let raw_header = block.header().encode();
|
||||
let output_buf = if params.raw {
|
||||
raw_header
|
||||
@@ -244,25 +241,44 @@ pub fn run() -> Result<()> {
|
||||
You can enable it with `--features runtime-benchmarks`."
|
||||
.into())
|
||||
},
|
||||
Some(Subcommand::TryRuntime(cmd)) =>
|
||||
if cfg!(feature = "try-runtime") {
|
||||
let runner = cli.create_runner(cmd)?;
|
||||
|
||||
// grab the task manager.
|
||||
let registry = &runner.config().prometheus_config.as_ref().map(|cfg| &cfg.registry);
|
||||
let task_manager =
|
||||
TaskManager::new(runner.config().tokio_handle.clone(), *registry)
|
||||
.map_err(|e| format!("Error: {:?}", e))?;
|
||||
|
||||
runner.async_run(|config| {
|
||||
Ok((cmd.run::<Block, TemplateRuntimeExecutor>(config), task_manager))
|
||||
})
|
||||
} else {
|
||||
Err("Try-runtime must be enabled by `--features try-runtime`.".into())
|
||||
},
|
||||
None => {
|
||||
let runner = cli.create_runner(&cli.run.normalize())?;
|
||||
|
||||
runner.run_node_until_exit(|config| async move {
|
||||
let para_id =
|
||||
chain_spec::Extensions::try_get(&*config.chain_spec).map(|e| e.para_id);
|
||||
let para_id = chain_spec::Extensions::try_get(&*config.chain_spec)
|
||||
.map(|e| e.para_id)
|
||||
.ok_or_else(|| "Could not find parachain ID in chain-spec.")?;
|
||||
|
||||
let polkadot_cli = RelayChainCli::new(
|
||||
&config,
|
||||
[RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()),
|
||||
[RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()),
|
||||
);
|
||||
|
||||
let id = ParaId::from(cli.run.parachain_id.or(para_id).unwrap_or(2000));
|
||||
let id = ParaId::from(para_id);
|
||||
|
||||
let parachain_account =
|
||||
AccountIdConversion::<polkadot_primitives::v0::AccountId>::into_account(&id);
|
||||
|
||||
let block: Block =
|
||||
generate_genesis_block(&config.chain_spec).map_err(|e| format!("{:?}", e))?;
|
||||
let state_version =
|
||||
RelayChainCli::native_runtime_version(&config.chain_spec).state_version();
|
||||
let block: Block = generate_genesis_block(&config.chain_spec, state_version)
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode()));
|
||||
|
||||
let tokio_handle = config.tokio_handle.clone();
|
||||
@@ -338,11 +354,24 @@ impl CliConfiguration<Self> for RelayChainCli {
|
||||
self.base.base.rpc_ws(default_listen_port)
|
||||
}
|
||||
|
||||
fn prometheus_config(&self, default_listen_port: u16) -> Result<Option<PrometheusConfig>> {
|
||||
self.base.base.prometheus_config(default_listen_port)
|
||||
fn prometheus_config(
|
||||
&self,
|
||||
default_listen_port: u16,
|
||||
chain_spec: &Box<dyn ChainSpec>,
|
||||
) -> Result<Option<PrometheusConfig>> {
|
||||
self.base.base.prometheus_config(default_listen_port, chain_spec)
|
||||
}
|
||||
|
||||
fn init<C: SubstrateCli>(&self) -> Result<()> {
|
||||
fn init<F>(
|
||||
&self,
|
||||
_support_url: &String,
|
||||
_impl_version: &String,
|
||||
_logger_hook: F,
|
||||
_config: &sc_service::Configuration,
|
||||
) -> Result<()>
|
||||
where
|
||||
F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration),
|
||||
{
|
||||
unreachable!("PolkadotCli is never initialized; qed");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Substrate Node CLI library.
|
||||
//! Substrate Parachain Node Template CLI
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
|
||||
|
||||
// std
|
||||
use std::sync::Arc;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
// Local Runtime Types
|
||||
use parachain_template_runtime::{
|
||||
@@ -9,15 +9,15 @@ use parachain_template_runtime::{
|
||||
};
|
||||
|
||||
// Cumulus Imports
|
||||
use cumulus_client_consensus_aura::{
|
||||
build_aura_consensus, BuildAuraConsensusParams, SlotProportion,
|
||||
};
|
||||
use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion};
|
||||
use cumulus_client_consensus_common::ParachainConsensus;
|
||||
use cumulus_client_network::build_block_announce_validator;
|
||||
use cumulus_client_network::BlockAnnounceValidator;
|
||||
use cumulus_client_service::{
|
||||
prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams,
|
||||
};
|
||||
use cumulus_primitives_core::ParaId;
|
||||
use cumulus_relay_chain_interface::RelayChainInterface;
|
||||
use cumulus_relay_chain_local::build_relay_chain_interface;
|
||||
|
||||
// Substrate Imports
|
||||
use sc_client_api::ExecutorProvider;
|
||||
@@ -114,6 +114,7 @@ where
|
||||
config.wasm_method,
|
||||
config.default_heap_pages,
|
||||
config.max_runtime_instances,
|
||||
config.runtime_cache_size,
|
||||
);
|
||||
|
||||
let (client, backend, keystore_container, task_manager) =
|
||||
@@ -127,7 +128,7 @@ where
|
||||
let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle());
|
||||
|
||||
let telemetry = telemetry.map(|(worker, telemetry)| {
|
||||
task_manager.spawn_handle().spawn("telemetry", worker.run());
|
||||
task_manager.spawn_handle().spawn("telemetry", None, worker.run());
|
||||
telemetry
|
||||
});
|
||||
|
||||
@@ -215,7 +216,7 @@ where
|
||||
Option<&Registry>,
|
||||
Option<TelemetryHandle>,
|
||||
&TaskManager,
|
||||
&polkadot_service::NewFull<polkadot_service::Client>,
|
||||
Arc<dyn RelayChainInterface>,
|
||||
Arc<
|
||||
sc_transaction_pool::FullPool<
|
||||
Block,
|
||||
@@ -236,27 +237,23 @@ where
|
||||
let params = new_partial::<RuntimeApi, Executor, BIQ>(¶chain_config, build_import_queue)?;
|
||||
let (mut telemetry, telemetry_worker_handle) = params.other;
|
||||
|
||||
let relay_chain_full_node =
|
||||
cumulus_client_service::build_polkadot_full_node(polkadot_config, telemetry_worker_handle)
|
||||
let client = params.client.clone();
|
||||
let backend = params.backend.clone();
|
||||
let mut task_manager = params.task_manager;
|
||||
|
||||
let (relay_chain_interface, collator_key) =
|
||||
build_relay_chain_interface(polkadot_config, telemetry_worker_handle, &mut task_manager)
|
||||
.map_err(|e| match e {
|
||||
polkadot_service::Error::Sub(x) => x,
|
||||
s => format!("{}", s).into(),
|
||||
})?;
|
||||
|
||||
let client = params.client.clone();
|
||||
let backend = params.backend.clone();
|
||||
let block_announce_validator = build_block_announce_validator(
|
||||
relay_chain_full_node.client.clone(),
|
||||
id,
|
||||
Box::new(relay_chain_full_node.network.clone()),
|
||||
relay_chain_full_node.backend.clone(),
|
||||
);
|
||||
let block_announce_validator = BlockAnnounceValidator::new(relay_chain_interface.clone(), id);
|
||||
|
||||
let force_authoring = parachain_config.force_authoring;
|
||||
let validator = parachain_config.role.is_authority();
|
||||
let prometheus_registry = parachain_config.prometheus_registry().cloned();
|
||||
let transaction_pool = params.transaction_pool.clone();
|
||||
let mut task_manager = params.task_manager;
|
||||
let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue);
|
||||
let (network, system_rpc_tx, start_network) =
|
||||
sc_service::build_network(sc_service::BuildNetworkParams {
|
||||
@@ -265,8 +262,9 @@ where
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
spawn_handle: task_manager.spawn_handle(),
|
||||
import_queue: import_queue.clone(),
|
||||
on_demand: None,
|
||||
block_announce_validator_builder: Some(Box::new(|_| block_announce_validator)),
|
||||
block_announce_validator_builder: Some(Box::new(|_| {
|
||||
Box::new(block_announce_validator)
|
||||
})),
|
||||
warp_sync: None,
|
||||
})?;
|
||||
|
||||
@@ -286,8 +284,6 @@ where
|
||||
};
|
||||
|
||||
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||
on_demand: None,
|
||||
remote_blockchain: None,
|
||||
rpc_extensions_builder,
|
||||
client: client.clone(),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
@@ -311,7 +307,7 @@ where
|
||||
prometheus_registry.as_ref(),
|
||||
telemetry.as_ref().map(|t| t.handle()),
|
||||
&task_manager,
|
||||
&relay_chain_full_node,
|
||||
relay_chain_interface.clone(),
|
||||
transaction_pool,
|
||||
network,
|
||||
params.keystore_container.sync_keystore(),
|
||||
@@ -326,10 +322,12 @@ where
|
||||
announce_block,
|
||||
client: client.clone(),
|
||||
task_manager: &mut task_manager,
|
||||
relay_chain_full_node,
|
||||
relay_chain_interface,
|
||||
spawner,
|
||||
parachain_consensus,
|
||||
import_queue,
|
||||
collator_key,
|
||||
slot_duration: Duration::from_secs(6),
|
||||
};
|
||||
|
||||
start_collator(params).await?;
|
||||
@@ -339,7 +337,7 @@ where
|
||||
announce_block,
|
||||
task_manager: &mut task_manager,
|
||||
para_id: id,
|
||||
relay_chain_full_node,
|
||||
relay_chain_interface,
|
||||
};
|
||||
|
||||
start_full_node(params)?;
|
||||
@@ -415,7 +413,7 @@ pub async fn start_parachain_node(
|
||||
prometheus_registry,
|
||||
telemetry,
|
||||
task_manager,
|
||||
relay_chain_node,
|
||||
relay_chain_interface,
|
||||
transaction_pool,
|
||||
sync_oracle,
|
||||
keystore,
|
||||
@@ -430,62 +428,48 @@ pub async fn start_parachain_node(
|
||||
telemetry.clone(),
|
||||
);
|
||||
|
||||
let relay_chain_backend = relay_chain_node.backend.clone();
|
||||
let relay_chain_client = relay_chain_node.client.clone();
|
||||
Ok(build_aura_consensus::<
|
||||
sp_consensus_aura::sr25519::AuthorityPair,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
>(BuildAuraConsensusParams {
|
||||
proposer_factory,
|
||||
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
|
||||
let parachain_inherent =
|
||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client(
|
||||
relay_parent,
|
||||
&relay_chain_client,
|
||||
&*relay_chain_backend,
|
||||
&validation_data,
|
||||
id,
|
||||
);
|
||||
async move {
|
||||
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
Ok(AuraConsensus::build::<sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _>(
|
||||
BuildAuraConsensusParams {
|
||||
proposer_factory,
|
||||
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
|
||||
let parachain_inherent =
|
||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
||||
relay_parent,
|
||||
&relay_chain_interface,
|
||||
&validation_data,
|
||||
id,
|
||||
);
|
||||
async move {
|
||||
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
|
||||
let slot =
|
||||
let slot =
|
||||
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
|
||||
*time,
|
||||
slot_duration.slot_duration(),
|
||||
);
|
||||
|
||||
let parachain_inherent = parachain_inherent.ok_or_else(|| {
|
||||
Box::<dyn std::error::Error + Send + Sync>::from(
|
||||
"Failed to create parachain inherent",
|
||||
)
|
||||
})?;
|
||||
Ok((time, slot, parachain_inherent))
|
||||
}
|
||||
let parachain_inherent = parachain_inherent.ok_or_else(|| {
|
||||
Box::<dyn std::error::Error + Send + Sync>::from(
|
||||
"Failed to create parachain inherent",
|
||||
)
|
||||
})?;
|
||||
Ok((time, slot, parachain_inherent))
|
||||
}
|
||||
},
|
||||
block_import: client.clone(),
|
||||
para_client: client,
|
||||
backoff_authoring_blocks: Option::<()>::None,
|
||||
sync_oracle,
|
||||
keystore,
|
||||
force_authoring,
|
||||
slot_duration,
|
||||
// We got around 500ms for proposing
|
||||
block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32),
|
||||
// And a maximum of 750ms if slots are skipped
|
||||
max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)),
|
||||
telemetry,
|
||||
},
|
||||
block_import: client.clone(),
|
||||
relay_chain_client: relay_chain_node.client.clone(),
|
||||
relay_chain_backend: relay_chain_node.backend.clone(),
|
||||
para_client: client,
|
||||
backoff_authoring_blocks: Option::<()>::None,
|
||||
sync_oracle,
|
||||
keystore,
|
||||
force_authoring,
|
||||
slot_duration,
|
||||
// We got around 500ms for proposing
|
||||
block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32),
|
||||
// And a maximum of 750ms if slots are skipped
|
||||
max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)),
|
||||
telemetry,
|
||||
}))
|
||||
))
|
||||
},
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -6,7 +6,7 @@ version = "0.1.0"
|
||||
license = "Unlicense"
|
||||
homepage = "https://substrate.io"
|
||||
repository = "https://github.com/paritytech/substrate/"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
@@ -15,19 +15,19 @@ targets = ["x86_64-unknown-linux-gnu"]
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"], default-features = false }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
|
||||
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0.119" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
serde = { version = "1.0.132" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
runtime-benchmarks = ["frame-benchmarking"]
|
||||
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"scale-info/std",
|
||||
@@ -35,3 +35,4 @@ std = [
|
||||
"frame-system/std",
|
||||
"frame-benchmarking/std",
|
||||
]
|
||||
try-runtime = [ "frame-support/try-runtime" ]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use super::*;
|
||||
|
||||
#[allow(unused)]
|
||||
use crate::Module as Template;
|
||||
use crate::Pallet as Template;
|
||||
use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller};
|
||||
use frame_system::RawOrigin;
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ impl system::Config for Test {
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = SS58Prefix;
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
impl pallet_template::Config for Test {
|
||||
|
||||
@@ -6,7 +6,7 @@ description = "A new Cumulus FRAME-based Substrate Runtime, ready for hacking to
|
||||
license = "Unlicense"
|
||||
homepage = "https://substrate.io"
|
||||
repository = "https://github.com/paritytech/cumulus/"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
@@ -15,10 +15,11 @@ targets = ["x86_64-unknown-linux-gnu"]
|
||||
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[dependencies]
|
||||
hex-literal = { version = "0.3.1", optional = true }
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"]}
|
||||
log = { version = "0.4.14", default-features = false }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.119", optional = true, features = ["derive"] }
|
||||
serde = { version = "1.0.132", optional = true, features = ["derive"] }
|
||||
smallvec = "1.6.1"
|
||||
|
||||
# Local Dependencies
|
||||
@@ -41,6 +42,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features
|
||||
|
||||
## Substrate FRAME Dependencies
|
||||
frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" }
|
||||
frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" }
|
||||
frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
@@ -51,7 +53,6 @@ frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate"
|
||||
pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
@@ -69,6 +70,7 @@ cumulus-primitives-timestamp = { path = "../../primitives/timestamp", default-fe
|
||||
cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false }
|
||||
pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false }
|
||||
parachain-info = { path = "../../polkadot-parachains/pallets/parachain-info", default-features = false }
|
||||
cumulus-pallet-session-benchmarking = {path = "../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
|
||||
|
||||
# Polkadot Dependencies
|
||||
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
|
||||
@@ -106,7 +108,6 @@ std = [
|
||||
"pallet-authorship/std",
|
||||
"pallet-balances/std",
|
||||
"pallet-collator-selection/std",
|
||||
"pallet-randomness-collective-flip/std",
|
||||
"pallet-session/std",
|
||||
"pallet-sudo/std",
|
||||
"pallet-template/std",
|
||||
@@ -130,9 +131,10 @@ std = [
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
"hex-literal",
|
||||
"sp-runtime/runtime-benchmarks",
|
||||
"xcm-builder/runtime-benchmarks",
|
||||
"frame-benchmarking",
|
||||
"frame-benchmarking/runtime-benchmarks",
|
||||
"frame-system-benchmarking",
|
||||
"frame-support/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
@@ -141,4 +143,10 @@ runtime-benchmarks = [
|
||||
"pallet-template/runtime-benchmarks",
|
||||
"pallet-timestamp/runtime-benchmarks",
|
||||
"pallet-xcm/runtime-benchmarks",
|
||||
"cumulus-pallet-session-benchmarking/runtime-benchmarks",
|
||||
]
|
||||
|
||||
try-runtime = [
|
||||
"frame-try-runtime",
|
||||
"frame-executive/try-runtime",
|
||||
]
|
||||
|
||||
@@ -23,7 +23,7 @@ use sp_version::RuntimeVersion;
|
||||
|
||||
use frame_support::{
|
||||
construct_runtime, match_type, parameter_types,
|
||||
traits::Everything,
|
||||
traits::{Everything, Nothing},
|
||||
weights::{
|
||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, WEIGHT_PER_SECOND},
|
||||
DispatchClass, IdentityFee, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients,
|
||||
@@ -33,7 +33,7 @@ use frame_support::{
|
||||
};
|
||||
use frame_system::{
|
||||
limits::{BlockLength, BlockWeights},
|
||||
EnsureOneOf, EnsureRoot,
|
||||
EnsureRoot,
|
||||
};
|
||||
pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||
pub use sp_runtime::{MultiAddress, Perbill, Permill};
|
||||
@@ -42,7 +42,7 @@ pub use sp_runtime::{MultiAddress, Perbill, Permill};
|
||||
pub use sp_runtime::BuildStorage;
|
||||
|
||||
// Polkadot Imports
|
||||
use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough};
|
||||
use pallet_xcm::XcmPassthrough;
|
||||
use polkadot_parachain::primitives::Sibling;
|
||||
use polkadot_runtime_common::{BlockHashCount, RocksDbWeight, SlowAdjustingFeeUpdate};
|
||||
|
||||
@@ -50,10 +50,10 @@ use polkadot_runtime_common::{BlockHashCount, RocksDbWeight, SlowAdjustingFeeUpd
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
|
||||
EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset,
|
||||
ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative,
|
||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation,
|
||||
TakeWeightCredit, UsingComponents,
|
||||
EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, ParentIsDefault,
|
||||
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
|
||||
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
||||
UsingComponents,
|
||||
};
|
||||
use xcm_executor::{Config, XcmExecutor};
|
||||
|
||||
@@ -96,6 +96,7 @@ pub type BlockId = generic::BlockId<Block>;
|
||||
|
||||
/// The SignedExtension to the basic transaction logic.
|
||||
pub type SignedExtra = (
|
||||
frame_system::CheckNonZeroSender<Runtime>,
|
||||
frame_system::CheckSpecVersion<Runtime>,
|
||||
frame_system::CheckTxVersion<Runtime>,
|
||||
frame_system::CheckGenesis<Runtime>,
|
||||
@@ -117,19 +118,9 @@ pub type Executive = frame_executive::Executive<
|
||||
Block,
|
||||
frame_system::ChainContext<Runtime>,
|
||||
Runtime,
|
||||
AllPallets,
|
||||
OnRuntimeUpgrade,
|
||||
AllPalletsWithSystem,
|
||||
>;
|
||||
|
||||
pub struct OnRuntimeUpgrade;
|
||||
impl frame_support::traits::OnRuntimeUpgrade for OnRuntimeUpgrade {
|
||||
fn on_runtime_upgrade() -> u64 {
|
||||
frame_support::migrations::migrate_from_pallet_version_to_storage_version::<
|
||||
AllPalletsWithSystem,
|
||||
>(&RocksDbWeight::get())
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the
|
||||
/// node's balance type.
|
||||
///
|
||||
@@ -189,6 +180,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 1,
|
||||
state_version: 1,
|
||||
};
|
||||
|
||||
/// This determines the average expected block time that we are targeting.
|
||||
@@ -213,12 +205,9 @@ pub const UNIT: Balance = 1_000_000_000_000;
|
||||
pub const MILLIUNIT: Balance = 1_000_000_000;
|
||||
pub const MICROUNIT: Balance = 1_000_000;
|
||||
|
||||
/// The existential deposit. Set to 1/10 of the Rococo Relay Chain.
|
||||
/// The existential deposit. Set to 1/10 of the Connected Relay Chain.
|
||||
pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT;
|
||||
|
||||
// 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks.
|
||||
pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
|
||||
|
||||
/// We assume that ~5% 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(5);
|
||||
@@ -315,6 +304,7 @@ impl frame_system::Config for Runtime {
|
||||
type SS58Prefix = SS58Prefix;
|
||||
/// The action to take on a Runtime Upgrade
|
||||
type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -390,14 +380,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
|
||||
type ReservedXcmpWeight = ReservedXcmpWeight;
|
||||
}
|
||||
|
||||
impl pallet_randomness_collective_flip::Config for Runtime {}
|
||||
|
||||
impl parachain_info::Config for Runtime {}
|
||||
|
||||
impl cumulus_pallet_aura_ext::Config for Runtime {}
|
||||
|
||||
parameter_types! {
|
||||
pub const RocLocation: MultiLocation = MultiLocation::parent();
|
||||
pub const RelayLocation: MultiLocation = MultiLocation::parent();
|
||||
pub const RelayNetwork: NetworkId = NetworkId::Any;
|
||||
pub RelayChainOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
|
||||
pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
|
||||
@@ -420,7 +408,7 @@ pub type LocalAssetTransactor = CurrencyAdapter<
|
||||
// Use this currency:
|
||||
Balances,
|
||||
// Use this currency when it is a fungible asset matching the given location or name:
|
||||
IsConcrete<RocLocation>,
|
||||
IsConcrete<RelayLocation>,
|
||||
// Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
|
||||
LocationToAccountId,
|
||||
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||
@@ -438,14 +426,11 @@ pub type XcmOriginToTransactDispatchOrigin = (
|
||||
// foreign chains who want to have a local sovereign account on this chain which they control.
|
||||
SovereignSignedViaLocation<LocationToAccountId, Origin>,
|
||||
// Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
|
||||
// recognised.
|
||||
// recognized.
|
||||
RelayChainAsNative<RelayChainOrigin, Origin>,
|
||||
// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
|
||||
// recognised.
|
||||
// recognized.
|
||||
SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
|
||||
// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
|
||||
// transaction from the Root origin.
|
||||
ParentAsSuperuser<Origin>,
|
||||
// Native signed account converter; this just converts an `AccountId32` origin into a normal
|
||||
// `Origin::Signed` origin of the same 32-byte value.
|
||||
SignedAccountId32AsNative<RelayNetwork, Origin>,
|
||||
@@ -482,11 +467,11 @@ impl Config for XcmConfig {
|
||||
type AssetTransactor = LocalAssetTransactor;
|
||||
type OriginConverter = XcmOriginToTransactDispatchOrigin;
|
||||
type IsReserve = NativeAsset;
|
||||
type IsTeleporter = NativeAsset; // Should be enough to allow teleportation of ROC
|
||||
type IsTeleporter = (); // Teleporting is disabled.
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type Barrier = Barrier;
|
||||
type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
|
||||
type Trader = UsingComponents<IdentityFee<Balance>, RocLocation, AccountId, Balances, ()>;
|
||||
type Trader = UsingComponents<IdentityFee<Balance>, RelayLocation, AccountId, Balances, ()>;
|
||||
type ResponseHandler = PolkadotXcm;
|
||||
type AssetTrap = PolkadotXcm;
|
||||
type AssetClaims = PolkadotXcm;
|
||||
@@ -500,7 +485,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
/// No local origins on this chain are allowed to dispatch XCM sends/executions.
|
||||
pub type LocalOriginToLocation = ();
|
||||
pub type LocalOriginToLocation = SignedToAccountId32<Origin, AccountId, RelayNetwork>;
|
||||
|
||||
/// The means for routing XCM messages which are not for local execution into the right message
|
||||
/// queues.
|
||||
@@ -516,16 +501,19 @@ impl pallet_xcm::Config for Runtime {
|
||||
type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
|
||||
type XcmRouter = XcmRouter;
|
||||
type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
|
||||
type XcmExecuteFilter = Everything;
|
||||
type XcmExecuteFilter = Nothing;
|
||||
// ^ Disable dispatchable execute on the XCM pallet.
|
||||
// Needs to be `Everything` for local testing.
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = Everything;
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type XcmReserveTransferFilter = Nothing;
|
||||
type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type Origin = Origin;
|
||||
type Call = Call;
|
||||
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
// ^ Override for AdvertisedXcmVersion default
|
||||
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
|
||||
}
|
||||
|
||||
@@ -539,6 +527,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type ChannelInfo = ParachainSystem;
|
||||
type VersionWrapper = ();
|
||||
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
|
||||
}
|
||||
|
||||
impl cumulus_pallet_dmp_queue::Config for Runtime {
|
||||
@@ -582,12 +571,8 @@ parameter_types! {
|
||||
pub const ExecutiveBody: BodyId = BodyId::Executive;
|
||||
}
|
||||
|
||||
// We allow root and the Relay Chain council to execute privileged collator selection operations.
|
||||
pub type CollatorSelectionUpdateOrigin = EnsureOneOf<
|
||||
AccountId,
|
||||
EnsureRoot<AccountId>,
|
||||
EnsureXcm<IsMajorityOfBody<RocLocation, ExecutiveBody>>,
|
||||
>;
|
||||
// We allow root only to execute privileged collator selection operations.
|
||||
pub type CollatorSelectionUpdateOrigin = EnsureRoot<AccountId>;
|
||||
|
||||
impl pallet_collator_selection::Config for Runtime {
|
||||
type Event = Event;
|
||||
@@ -622,9 +607,8 @@ construct_runtime!(
|
||||
ParachainSystem: cumulus_pallet_parachain_system::{
|
||||
Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned,
|
||||
} = 1,
|
||||
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 2,
|
||||
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3,
|
||||
ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4,
|
||||
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 2,
|
||||
ParachainInfo: parachain_info::{Pallet, Storage, Config} = 3,
|
||||
|
||||
// Monetary stuff.
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 10,
|
||||
@@ -755,6 +739,18 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
impl frame_try_runtime::TryRuntime<Block> for Runtime {
|
||||
fn on_runtime_upgrade() -> (Weight, Weight) {
|
||||
log::info!("try-runtime::on_runtime_upgrade parachain-template.");
|
||||
let weight = Executive::try_runtime_upgrade().unwrap();
|
||||
(weight, RuntimeBlockWeights::get().max_block)
|
||||
}
|
||||
|
||||
fn execute_block_no_check(block: Block) -> Weight {
|
||||
Executive::execute_block_no_check(block)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
impl frame_benchmarking::Benchmark<Block> for Runtime {
|
||||
@@ -771,6 +767,7 @@ impl_runtime_apis! {
|
||||
|
||||
list_benchmark!(list, extra, frame_system, SystemBench::<Runtime>);
|
||||
list_benchmark!(list, extra, pallet_balances, Balances);
|
||||
list_benchmark!(list, extra, pallet_session, SessionBench::<Runtime>);
|
||||
list_benchmark!(list, extra, pallet_timestamp, Timestamp);
|
||||
list_benchmark!(list, extra, pallet_collator_selection, CollatorSelection);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[package]
|
||||
name = "polkadot-collator"
|
||||
version = "4.0.0"
|
||||
version = "5.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "polkadot-collator"
|
||||
@@ -14,21 +14,22 @@ futures = { version = "0.3.1", features = ["compat"] }
|
||||
log = "0.4.8"
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0" }
|
||||
structopt = "0.3.3"
|
||||
serde = { version = "1.0.101", features = ["derive"] }
|
||||
serde = { version = "1.0.132", features = ["derive"] }
|
||||
hex-literal = "0.2.1"
|
||||
async-trait = "0.1.42"
|
||||
|
||||
# Parachain runtimes
|
||||
rococo-parachain-runtime = { package = "rococo-runtime", path = "rococo" }
|
||||
rococo-parachain-runtime = { path = "rococo-parachain" }
|
||||
shell-runtime = { path = "shell" }
|
||||
seedling-runtime = { path = "seedling" }
|
||||
statemint-runtime = { path = "statemint" }
|
||||
statemine-runtime = { path = "statemine" }
|
||||
westmint-runtime = { path = "westmint" }
|
||||
parachains-common = { path = "parachains-common" }
|
||||
|
||||
# Substrate dependencies
|
||||
frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
frame-benchmarking-cli = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -57,6 +58,9 @@ sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
# try-runtime stuff.
|
||||
try-runtime-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
# RPC related dependencies
|
||||
jsonrpc-core = "18.0.0"
|
||||
sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -72,6 +76,8 @@ cumulus-client-service = { path = "../client/service" }
|
||||
cumulus-client-network = { path = "../client/network" }
|
||||
cumulus-primitives-core = { path = "../primitives/core" }
|
||||
cumulus-primitives-parachain-inherent = { path = "../primitives/parachain-inherent" }
|
||||
cumulus-relay-chain-interface = { path = "../client/relay-chain-interface" }
|
||||
cumulus-relay-chain-local = { path = "../client/relay-chain-local" }
|
||||
|
||||
# Polkadot dependencies
|
||||
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||
@@ -90,8 +96,14 @@ tempfile = "3.2.0"
|
||||
[features]
|
||||
default = []
|
||||
runtime-benchmarks = [
|
||||
'polkadot-service/runtime-benchmarks',
|
||||
'statemint-runtime/runtime-benchmarks',
|
||||
'statemine-runtime/runtime-benchmarks',
|
||||
'westmint-runtime/runtime-benchmarks',
|
||||
"polkadot-service/runtime-benchmarks",
|
||||
"statemint-runtime/runtime-benchmarks",
|
||||
"statemine-runtime/runtime-benchmarks",
|
||||
"westmint-runtime/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
'statemint-runtime/try-runtime',
|
||||
'statemine-runtime/try-runtime',
|
||||
'westmint-runtime/try-runtime',
|
||||
'shell-runtime/try-runtime',
|
||||
]
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
name = "parachain-info"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
||||
serde = { version = "1.0.132", optional = true, features = ["derive"] }
|
||||
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
name = "cumulus-ping"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
||||
serde = { version = "1.0.132", optional = true, features = ["derive"] }
|
||||
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
|
||||
@@ -2,63 +2,63 @@
|
||||
name = "parachains-common"
|
||||
version = "1.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
description = "Logic which is common to all parachain runtimes"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ['x86_64-unknown-linux-gnu']
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
# External dependencies
|
||||
codec = { package = 'parity-scale-codec', version = '2.3.0', features = ['derive'], default-features = false }
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", features = ["derive"], default-features = false }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
|
||||
# Substrate dependencies
|
||||
sp-consensus-aura = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
sp-std = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
sp-io = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
frame-executive = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
frame-support = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
frame-system = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
pallet-assets = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
pallet-authorship = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
sp-core = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-asset-tx-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-assets = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
# Polkadot dependencies
|
||||
polkadot-runtime-common = { git = 'https://github.com/paritytech/polkadot', branch = "master", default-features = false }
|
||||
polkadot-primitives = { git = 'https://github.com/paritytech/polkadot', branch = "master", default-features = false }
|
||||
xcm = { git = 'https://github.com/paritytech/polkadot', branch = "master", default-features = false }
|
||||
xcm-executor = { git = 'https://github.com/paritytech/polkadot', branch = "master", default-features = false }
|
||||
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
|
||||
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
|
||||
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
|
||||
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
|
||||
|
||||
# Local dependencies
|
||||
pallet-asset-tx-payment = { path = '../../pallets/asset-tx-payment', default-features = false }
|
||||
pallet-collator-selection = { path = '../../pallets/collator-selection', default-features = false }
|
||||
pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-io = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
pallet-authorship = { git = 'https://github.com/paritytech/substrate', branch = "master", default-features = false }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" }
|
||||
|
||||
[build-dependencies]
|
||||
substrate-wasm-builder = { git = 'https://github.com/paritytech/substrate', branch = "master" }
|
||||
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
'codec/std',
|
||||
'scale-info/std',
|
||||
'sp-consensus-aura/std',
|
||||
'sp-std/std',
|
||||
'sp-io/std',
|
||||
'frame-support/std',
|
||||
'frame-executive/std',
|
||||
'frame-system/std',
|
||||
'pallet-asset-tx-payment/std',
|
||||
'pallet-collator-selection/std',
|
||||
'pallet-assets/std',
|
||||
'pallet-authorship/std',
|
||||
'pallet-balances/std',
|
||||
'polkadot-runtime-common/std',
|
||||
'polkadot-primitives/std',
|
||||
"codec/std",
|
||||
"scale-info/std",
|
||||
"sp-consensus-aura/std",
|
||||
"sp-std/std",
|
||||
"sp-io/std",
|
||||
"frame-support/std",
|
||||
"frame-executive/std",
|
||||
"frame-system/std",
|
||||
"pallet-asset-tx-payment/std",
|
||||
"pallet-collator-selection/std",
|
||||
"pallet-assets/std",
|
||||
"pallet-authorship/std",
|
||||
"pallet-balances/std",
|
||||
"polkadot-runtime-common/std",
|
||||
"polkadot-primitives/std",
|
||||
]
|
||||
|
||||
@@ -47,10 +47,10 @@ where
|
||||
let numeric_amount = amount.peek();
|
||||
let staking_pot = <pallet_collator_selection::Pallet<R>>::account_id();
|
||||
<pallet_balances::Pallet<R>>::resolve_creating(&staking_pot, amount);
|
||||
<frame_system::Pallet<R>>::deposit_event(pallet_balances::Event::Deposit(
|
||||
staking_pot,
|
||||
numeric_amount,
|
||||
));
|
||||
<frame_system::Pallet<R>>::deposit_event(pallet_balances::Event::Deposit {
|
||||
who: staking_pot,
|
||||
amount: numeric_amount,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +84,10 @@ where
|
||||
From<polkadot_primitives::v1::AccountId> + Into<polkadot_primitives::v1::AccountId>,
|
||||
{
|
||||
fn handle_credit(credit: CreditOf<AccountIdOf<R>, pallet_assets::Pallet<R>>) {
|
||||
let author = pallet_authorship::Pallet::<R>::author();
|
||||
// In case of error: Will drop the result triggering the `OnDrop` of the imbalance.
|
||||
let _ = pallet_assets::Pallet::<R>::resolve(&author, credit);
|
||||
if let Some(author) = pallet_authorship::Pallet::<R>::author() {
|
||||
// In case of error: Will drop the result triggering the `OnDrop` of the imbalance.
|
||||
let _ = pallet_assets::Pallet::<R>::resolve(&author, credit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +179,7 @@ mod tests {
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
impl pallet_balances::Config for Test {
|
||||
|
||||
@@ -47,7 +47,7 @@ mod types {
|
||||
pub type Hash = sp_core::H256;
|
||||
|
||||
/// Digest item type.
|
||||
pub type DigestItem = sp_runtime::generic::DigestItem<Hash>;
|
||||
pub type DigestItem = sp_runtime::generic::DigestItem;
|
||||
|
||||
// Aura consensus authority.
|
||||
pub type AuraId = sp_consensus_aura::sr25519::AuthorityId;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0x000000000000000000000000000000000000000000000000000000000000000000c1ef26b567de07159e4ecd415fbbb0340c56a09c4d72c82516d0f3bc2b782c8003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131400
|
||||
File diff suppressed because one or more lines are too long
@@ -10,6 +10,7 @@
|
||||
"telemetryEndpoints": null,
|
||||
"protocolId": null,
|
||||
"properties": {
|
||||
"ss58Format": 2,
|
||||
"tokenDecimals": 12,
|
||||
"tokenSymbol": "KSM"
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"telemetryEndpoints": null,
|
||||
"protocolId": null,
|
||||
"properties": {
|
||||
"ss58Format": 2,
|
||||
"tokenDecimals": 12,
|
||||
"tokenSymbol": "KSM"
|
||||
},
|
||||
|
||||
+4
-6
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = 'rococo-runtime'
|
||||
version = '0.1.0'
|
||||
name = "rococo-parachain-runtime"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = '2018'
|
||||
edition = "2021"
|
||||
description = "Simple runtime used by the rococo parachain(s)"
|
||||
|
||||
[dependencies]
|
||||
@@ -10,7 +10,7 @@ codec = { package = "parity-scale-codec", version = "2.3.0", default-features =
|
||||
log = { version = "0.4.14", default-features = false }
|
||||
parachain-info = { path = "../pallets/parachain-info", default-features = false }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
||||
serde = { version = "1.0.132", optional = true, features = ["derive"] }
|
||||
|
||||
# Substrate dependencies
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
@@ -32,7 +32,6 @@ frame-system = { git = "https://github.com/paritytech/substrate", default-featur
|
||||
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
@@ -85,7 +84,6 @@ std = [
|
||||
"frame-system/std",
|
||||
"pallet-assets/std",
|
||||
"pallet-balances/std",
|
||||
"pallet-randomness-collective-flip/std",
|
||||
"pallet-timestamp/std",
|
||||
"pallet-sudo/std",
|
||||
"pallet-transaction-payment/std",
|
||||
+39
-17
@@ -38,7 +38,7 @@ use sp_version::RuntimeVersion;
|
||||
// A few exports that help ease life for downstream crates.
|
||||
pub use frame_support::{
|
||||
construct_runtime, match_type, parameter_types,
|
||||
traits::{Everything, IsInVec, Randomness},
|
||||
traits::{EnsureOneOf, Everything, IsInVec, Randomness},
|
||||
weights::{
|
||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
||||
DispatchClass, IdentityFee, Weight,
|
||||
@@ -47,7 +47,7 @@ pub use frame_support::{
|
||||
};
|
||||
use frame_system::{
|
||||
limits::{BlockLength, BlockWeights},
|
||||
EnsureOneOf, EnsureRoot,
|
||||
EnsureRoot,
|
||||
};
|
||||
pub use pallet_balances::Call as BalancesCall;
|
||||
pub use pallet_timestamp::Call as TimestampCall;
|
||||
@@ -60,7 +60,10 @@ use parachains_common::{
|
||||
impls::{AssetsFrom, NonZeroIssuance},
|
||||
AssetId,
|
||||
};
|
||||
use xcm_builder::{AsPrefixedGeneralIndex, ConvertedConcreteAssetId, FungiblesAdapter};
|
||||
use xcm_builder::{
|
||||
AllowKnownQueryResponses, AllowSubscriptionsFrom, AsPrefixedGeneralIndex,
|
||||
ConvertedConcreteAssetId, FungiblesAdapter,
|
||||
};
|
||||
use xcm_executor::traits::JustTry;
|
||||
|
||||
// XCM imports
|
||||
@@ -94,6 +97,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 1,
|
||||
state_version: 0,
|
||||
};
|
||||
|
||||
pub const MILLISECS_PER_BLOCK: u64 = 12000;
|
||||
@@ -185,13 +189,14 @@ impl frame_system::Config for Runtime {
|
||||
type AccountData = pallet_balances::AccountData<Balance>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type DbWeight = ();
|
||||
type DbWeight = RocksDbWeight;
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type SystemWeightInfo = ();
|
||||
type BlockWeights = RuntimeBlockWeights;
|
||||
type BlockLength = RuntimeBlockLength;
|
||||
type SS58Prefix = SS58Prefix;
|
||||
type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -229,8 +234,6 @@ impl pallet_balances::Config for Runtime {
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
}
|
||||
|
||||
impl pallet_randomness_collective_flip::Config for Runtime {}
|
||||
|
||||
parameter_types! {
|
||||
pub const OperationalFeeMultiplier: u8 = 5;
|
||||
}
|
||||
@@ -310,7 +313,7 @@ pub type FungiblesTransactor = FungiblesAdapter<
|
||||
ConvertedConcreteAssetId<
|
||||
AssetId,
|
||||
u64,
|
||||
AsPrefixedGeneralIndex<StatemintLocation, AssetId, JustTry>,
|
||||
AsPrefixedGeneralIndex<StatemintAssetsPalletLocation, AssetId, JustTry>,
|
||||
JustTry,
|
||||
>,
|
||||
// Convert an XCM MultiLocation into a local account id:
|
||||
@@ -351,8 +354,8 @@ pub type XcmOriginToTransactDispatchOrigin = (
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
// One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
|
||||
pub UnitWeightCost: Weight = 1_000_000;
|
||||
// One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate.
|
||||
pub UnitWeightCost: Weight = 1_000_000_000;
|
||||
// One ROC buys 1 second of weight.
|
||||
pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), ROC);
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
@@ -376,11 +379,19 @@ pub type Barrier = (
|
||||
AllowUnpaidExecutionFrom<ParentOrParentsUnitPlurality>,
|
||||
// ^^^ Parent & its unit plurality gets free execution
|
||||
AllowUnpaidExecutionFrom<Statemint>,
|
||||
// Expected responses are OK.
|
||||
AllowKnownQueryResponses<PolkadotXcm>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<Everything>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub StatemintLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000)));
|
||||
pub MaxAssetsIntoHolding: u32 = 64;
|
||||
pub StatemintLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000)));
|
||||
// ALWAYS ensure that the index in PalletInstance stays up-to-date with
|
||||
// Statemint's Assets pallet index
|
||||
pub StatemintAssetsPalletLocation: MultiLocation =
|
||||
MultiLocation::new(1, X2(Parachain(1000), PalletInstance(50)));
|
||||
}
|
||||
|
||||
pub type Reserves = (NativeAsset, AssetsFrom<StatemintLocation>);
|
||||
@@ -445,6 +456,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type ChannelInfo = ParachainSystem;
|
||||
type VersionWrapper = ();
|
||||
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
|
||||
}
|
||||
|
||||
impl cumulus_pallet_dmp_queue::Config for Runtime {
|
||||
@@ -462,6 +474,7 @@ impl cumulus_ping::Config for Runtime {
|
||||
|
||||
parameter_types! {
|
||||
pub const AssetDeposit: Balance = 1 * ROC;
|
||||
pub const AssetAccountDeposit: Balance = 1 * ROC;
|
||||
pub const ApprovalDeposit: Balance = 100 * MILLIROC;
|
||||
pub const AssetsStringLimit: u32 = 50;
|
||||
pub const MetadataDepositBase: Balance = 1 * ROC;
|
||||
@@ -471,11 +484,8 @@ parameter_types! {
|
||||
}
|
||||
|
||||
/// A majority of the Unit body from Rococo over XCM is our required administration origin.
|
||||
pub type AdminOrigin = EnsureOneOf<
|
||||
AccountId,
|
||||
EnsureRoot<AccountId>,
|
||||
EnsureXcm<IsMajorityOfBody<RocLocation, UnitBody>>,
|
||||
>;
|
||||
pub type AdminOrigin =
|
||||
EnsureOneOf<EnsureRoot<AccountId>, EnsureXcm<IsMajorityOfBody<RocLocation, UnitBody>>>;
|
||||
|
||||
impl pallet_assets::Config for Runtime {
|
||||
type Event = Event;
|
||||
@@ -491,6 +501,7 @@ impl pallet_assets::Config for Runtime {
|
||||
type Freezer = ();
|
||||
type Extra = ();
|
||||
type WeightInfo = pallet_assets::weights::SubstrateWeight<Runtime>;
|
||||
type AssetAccountDeposit = AssetAccountDeposit;
|
||||
}
|
||||
|
||||
impl pallet_aura::Config for Runtime {
|
||||
@@ -508,7 +519,6 @@ construct_runtime! {
|
||||
System: frame_system::{Pallet, Call, Storage, Config, Event<T>},
|
||||
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
|
||||
Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},
|
||||
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
|
||||
|
||||
ParachainSystem: cumulus_pallet_parachain_system::{
|
||||
@@ -557,6 +567,7 @@ pub type SignedBlock = generic::SignedBlock<Block>;
|
||||
pub type BlockId = generic::BlockId<Block>;
|
||||
/// The SignedExtension to the basic transaction logic.
|
||||
pub type SignedExtra = (
|
||||
frame_system::CheckNonZeroSender<Runtime>,
|
||||
frame_system::CheckSpecVersion<Runtime>,
|
||||
frame_system::CheckGenesis<Runtime>,
|
||||
frame_system::CheckEra<Runtime>,
|
||||
@@ -574,9 +585,20 @@ pub type Executive = frame_executive::Executive<
|
||||
Block,
|
||||
frame_system::ChainContext<Runtime>,
|
||||
Runtime,
|
||||
AllPallets,
|
||||
AllPalletsWithSystem,
|
||||
RemoveCollectiveFlip,
|
||||
>;
|
||||
|
||||
pub struct RemoveCollectiveFlip;
|
||||
impl frame_support::traits::OnRuntimeUpgrade for RemoveCollectiveFlip {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
use frame_support::storage::migration;
|
||||
// Remove the storage value `RandomMaterial` from removed pallet `RandomnessCollectiveFlip`
|
||||
migration::remove_storage_prefix(b"RandomnessCollectiveFlip", b"RandomMaterial", b"");
|
||||
<Runtime as frame_system::Config>::DbWeight::get().writes(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl_runtime_apis! {
|
||||
impl sp_api::Core<Block> for Runtime {
|
||||
fn version() -> RuntimeVersion {
|
||||
@@ -1,70 +1,66 @@
|
||||
[package]
|
||||
name = "cumulus-test-runtime-upgrade"
|
||||
version = "0.1.0"
|
||||
name = 'seedling-runtime'
|
||||
version = '0.1.0'
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] }
|
||||
log = { version = "0.4.14", default-features = false }
|
||||
parachain-info = { path = "../pallets/parachain-info", default-features = false }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
||||
serde = { version = "1.0.132", optional = true, features = ["derive"] }
|
||||
|
||||
# Substrate dependencies
|
||||
frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-version = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
|
||||
# Cumulus dependencies
|
||||
cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false }
|
||||
cumulus-primitives-core = { path = "../../primitives/core", default-features = false }
|
||||
cumulus-primitives-timestamp = { path = "../../primitives/timestamp", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[features]
|
||||
default = [ "std", "upgrade" ]
|
||||
default = [ "std" ]
|
||||
std = [
|
||||
"codec/std",
|
||||
"scale-info/std",
|
||||
"serde",
|
||||
"log/std",
|
||||
"sp-api/std",
|
||||
"sp-std/std",
|
||||
"sp-io/std",
|
||||
"sp-core/std",
|
||||
"sp-runtime/std",
|
||||
"sp-version/std",
|
||||
"sp-offchain/std",
|
||||
"sp-session/std",
|
||||
"sp-block-builder/std",
|
||||
"sp-transaction-pool/std",
|
||||
"sp-inherents/std",
|
||||
"frame-support/std",
|
||||
"frame-executive/std",
|
||||
"frame-system/std",
|
||||
"pallet-sudo/std",
|
||||
"pallet-balances/std",
|
||||
"parachain-info/std",
|
||||
"cumulus-pallet-parachain-system/std",
|
||||
"cumulus-primitives-core/std",
|
||||
"cumulus-primitives-timestamp/std",
|
||||
"frame-executive/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"pallet-balances/std",
|
||||
"pallet-randomness-collective-flip/std",
|
||||
"pallet-sudo/std",
|
||||
"pallet-timestamp/std",
|
||||
"pallet-transaction-payment/std",
|
||||
"serde",
|
||||
"sp-api/std",
|
||||
"sp-block-builder/std",
|
||||
"sp-core/std",
|
||||
"sp-inherents/std",
|
||||
"sp-io/std",
|
||||
"sp-offchain/std",
|
||||
"sp-runtime/std",
|
||||
"sp-session/std",
|
||||
"sp-std/std",
|
||||
"sp-transaction-pool/std",
|
||||
"sp-version/std",
|
||||
]
|
||||
upgrade = []
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Cumulus.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use substrate_wasm_builder::WasmBuilder;
|
||||
|
||||
fn main() {
|
||||
WasmBuilder::new()
|
||||
.with_current_project()
|
||||
.export_heap_base()
|
||||
.import_memory()
|
||||
.build()
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Cumulus.
|
||||
|
||||
// Cumulus is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Cumulus is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#![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_api::impl_runtime_apis;
|
||||
use sp_core::OpaqueMetadata;
|
||||
use sp_runtime::{
|
||||
create_runtime_str, generic,
|
||||
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT},
|
||||
transaction_validity::{TransactionSource, TransactionValidity},
|
||||
ApplyExtrinsicResult,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
#[cfg(feature = "std")]
|
||||
use sp_version::NativeVersion;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
// A few exports that help ease life for downstream crates.
|
||||
pub use frame_support::{
|
||||
construct_runtime, match_type, parameter_types,
|
||||
traits::{Contains, IsInVec, Randomness},
|
||||
weights::{
|
||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
||||
DispatchClass, IdentityFee, Weight,
|
||||
},
|
||||
StorageValue,
|
||||
};
|
||||
use frame_system::limits::{BlockLength, BlockWeights};
|
||||
#[cfg(any(feature = "std", test))]
|
||||
pub use sp_runtime::BuildStorage;
|
||||
pub use sp_runtime::{Perbill, Permill};
|
||||
|
||||
/// This runtime version.
|
||||
#[sp_version::runtime_version]
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: create_runtime_str!("seedling"),
|
||||
impl_name: create_runtime_str!("seedling"),
|
||||
authoring_version: 1,
|
||||
spec_version: 1,
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 1,
|
||||
state_version: 0,
|
||||
};
|
||||
|
||||
/// 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() }
|
||||
}
|
||||
|
||||
/// 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 .5 seconds of compute with a 12 second average block time.
|
||||
const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2;
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: BlockNumber = 250;
|
||||
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: u8 = 42;
|
||||
}
|
||||
|
||||
pub struct BaseFilter;
|
||||
impl Contains<Call> for BaseFilter {
|
||||
fn contains(c: &Call) -> bool {
|
||||
// Disallow everything that is not set_validation_data or set_code
|
||||
match c {
|
||||
Call::ParachainSystem(cumulus_pallet_parachain_system::Call::set_validation_data {
|
||||
..
|
||||
}) => true,
|
||||
Call::Sudo(pallet_sudo::Call::sudo_unchecked_weight { call: ref x, .. }) => {
|
||||
matches!(x.as_ref(), &Call::System(frame_system::Call::set_code { .. }))
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
/// 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<AccountId, ()>;
|
||||
/// 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<BlockNumber, BlakeTwo256>;
|
||||
/// 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;
|
||||
/// Runtime version.
|
||||
type Version = Version;
|
||||
/// Converts a module to an index of this module in the runtime.
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = pallet_balances::AccountData<u128>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type DbWeight = ();
|
||||
type BaseCallFilter = BaseFilter;
|
||||
type SystemWeightInfo = ();
|
||||
type BlockWeights = RuntimeBlockWeights;
|
||||
type BlockLength = RuntimeBlockLength;
|
||||
type SS58Prefix = SS58Prefix;
|
||||
type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
impl pallet_sudo::Config for Runtime {
|
||||
type Call = Call;
|
||||
type Event = Event;
|
||||
}
|
||||
|
||||
impl cumulus_pallet_parachain_system::Config for Runtime {
|
||||
type Event = Event;
|
||||
type OnValidationData = ();
|
||||
type SelfParaId = parachain_info::Pallet<Runtime>;
|
||||
type OutboundXcmpMessageSource = ();
|
||||
type DmpMessageHandler = ();
|
||||
type ReservedDmpWeight = ();
|
||||
type XcmpMessageHandler = ();
|
||||
type ReservedXcmpWeight = ();
|
||||
}
|
||||
|
||||
impl parachain_info::Config for Runtime {}
|
||||
|
||||
construct_runtime! {
|
||||
pub enum Runtime where
|
||||
Block = Block,
|
||||
NodeBlock = generic::Block<Header, sp_runtime::OpaqueExtrinsic>,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Storage, Config, Event<T>},
|
||||
Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
ParachainSystem: cumulus_pallet_parachain_system::{
|
||||
Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned,
|
||||
},
|
||||
ParachainInfo: parachain_info::{Pallet, Storage, Config},
|
||||
}
|
||||
}
|
||||
|
||||
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
|
||||
pub type Signature = sp_runtime::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 = <<Signature as sp_runtime::traits::Verify>::Signer as sp_runtime::traits::IdentifyAccount>::AccountId;
|
||||
/// 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;
|
||||
/// An index to a block.
|
||||
pub type BlockNumber = u32;
|
||||
/// The address format for describing accounts.
|
||||
pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
|
||||
/// Block header type as expected by this runtime.
|
||||
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||
/// Block type as expected by this runtime.
|
||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
/// A Block signed with a Justification
|
||||
pub type SignedBlock = generic::SignedBlock<Block>;
|
||||
/// BlockId type as expected by this runtime.
|
||||
pub type BlockId = generic::BlockId<Block>;
|
||||
/// The SignedExtension to the basic transaction logic.
|
||||
pub type SignedExtra = (
|
||||
frame_system::CheckSpecVersion<Runtime>,
|
||||
frame_system::CheckTxVersion<Runtime>,
|
||||
frame_system::CheckGenesis<Runtime>,
|
||||
frame_system::CheckEra<Runtime>,
|
||||
frame_system::CheckNonce<Runtime>,
|
||||
);
|
||||
/// Unchecked extrinsic type as expected by this runtime.
|
||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
|
||||
/// Extrinsic type that has already been checked.
|
||||
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;
|
||||
/// Executive: handles dispatch to the various modules.
|
||||
pub type Executive = frame_executive::Executive<
|
||||
Runtime,
|
||||
Block,
|
||||
frame_system::ChainContext<Runtime>,
|
||||
Runtime,
|
||||
AllPalletsWithSystem,
|
||||
>;
|
||||
|
||||
impl_runtime_apis! {
|
||||
impl sp_api::Core<Block> for Runtime {
|
||||
fn version() -> RuntimeVersion {
|
||||
VERSION
|
||||
}
|
||||
|
||||
fn execute_block(block: Block) {
|
||||
Executive::execute_block(block)
|
||||
}
|
||||
|
||||
fn initialize_block(header: &<Block as BlockT>::Header) {
|
||||
Executive::initialize_block(header)
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_api::Metadata<Block> for Runtime {
|
||||
fn metadata() -> OpaqueMetadata {
|
||||
OpaqueMetadata::new(Runtime::metadata().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_block_builder::BlockBuilder<Block> for Runtime {
|
||||
fn apply_extrinsic(
|
||||
extrinsic: <Block as BlockT>::Extrinsic,
|
||||
) -> ApplyExtrinsicResult {
|
||||
Executive::apply_extrinsic(extrinsic)
|
||||
}
|
||||
|
||||
fn finalize_block() -> <Block as BlockT>::Header {
|
||||
Executive::finalize_block()
|
||||
}
|
||||
|
||||
fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::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<Block> for Runtime {
|
||||
fn validate_transaction(
|
||||
source: TransactionSource,
|
||||
tx: <Block as BlockT>::Extrinsic,
|
||||
block_hash: <Block as BlockT>::Hash,
|
||||
) -> TransactionValidity {
|
||||
Executive::validate_transaction(source, tx, block_hash)
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
|
||||
fn offchain_worker(header: &<Block as BlockT>::Header) {
|
||||
Executive::offchain_worker(header)
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_session::SessionKeys<Block> for Runtime {
|
||||
fn decode_session_keys(_: Vec<u8>) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
|
||||
Some(Vec::new())
|
||||
}
|
||||
|
||||
fn generate_session_keys(_: Option<Vec<u8>>) -> Vec<u8> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
|
||||
fn collect_collation_info() -> cumulus_primitives_core::CollationInfo {
|
||||
ParachainSystem::collect_collation_info()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CheckInherents;
|
||||
|
||||
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
|
||||
fn check_inherents(
|
||||
_: &Block,
|
||||
_: &cumulus_pallet_parachain_system::RelayChainStateProof,
|
||||
) -> sp_inherents::CheckInherentsResult {
|
||||
sp_inherents::CheckInherentsResult::new()
|
||||
}
|
||||
}
|
||||
|
||||
cumulus_pallet_parachain_system::register_validate_block! {
|
||||
Runtime = Runtime,
|
||||
BlockExecutor = Executive,
|
||||
CheckInherents = CheckInherents,
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
[package]
|
||||
name = 'shell-runtime'
|
||||
version = '0.1.0'
|
||||
name = "shell-runtime"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = '2018'
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive"] }
|
||||
log = { version = "0.4.14", default-features = false }
|
||||
parachain-info = { path = "../pallets/parachain-info", default-features = false }
|
||||
scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
||||
serde = { version = "1.0.132", optional = true, features = ["derive"] }
|
||||
|
||||
# Substrate dependencies
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
@@ -28,6 +28,9 @@ frame-support = { git = "https://github.com/paritytech/substrate", default-featu
|
||||
frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
|
||||
# try-runtime stuff.
|
||||
frame-try-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
|
||||
|
||||
# Cumulus dependencies
|
||||
cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false }
|
||||
cumulus-primitives-core = { path = "../../primitives/core", default-features = false }
|
||||
@@ -72,3 +75,7 @@ std = [
|
||||
"xcm-builder/std",
|
||||
"xcm-executor/std",
|
||||
]
|
||||
try-runtime = [
|
||||
"frame-try-runtime",
|
||||
"frame-executive/try-runtime",
|
||||
]
|
||||
|
||||
@@ -23,12 +23,13 @@
|
||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::unsigned::TransactionValidityError;
|
||||
use scale_info::TypeInfo;
|
||||
use sp_api::impl_runtime_apis;
|
||||
use sp_core::OpaqueMetadata;
|
||||
use sp_runtime::{
|
||||
create_runtime_str, generic,
|
||||
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT},
|
||||
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf},
|
||||
transaction_validity::{TransactionSource, TransactionValidity},
|
||||
ApplyExtrinsicResult,
|
||||
};
|
||||
@@ -70,6 +71,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 1,
|
||||
state_version: 0,
|
||||
};
|
||||
|
||||
/// The version information used to identify this runtime when compiled natively.
|
||||
@@ -150,6 +152,7 @@ impl frame_system::Config for Runtime {
|
||||
type BlockLength = RuntimeBlockLength;
|
||||
type SS58Prefix = SS58Prefix;
|
||||
type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -194,8 +197,8 @@ match_type! {
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
// One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
|
||||
pub UnitWeightCost: Weight = 1_000_000;
|
||||
// One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate.
|
||||
pub UnitWeightCost: Weight = 1_000_000_000;
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
}
|
||||
@@ -256,6 +259,15 @@ impl sp_runtime::traits::SignedExtension for DisallowSigned {
|
||||
) -> sp_std::result::Result<(), sp_runtime::transaction_validity::TransactionValidityError> {
|
||||
Ok(())
|
||||
}
|
||||
fn pre_dispatch(
|
||||
self,
|
||||
who: &Self::AccountId,
|
||||
call: &Self::Call,
|
||||
info: &DispatchInfoOf<Self::Call>,
|
||||
len: usize,
|
||||
) -> Result<Self::Pre, TransactionValidityError> {
|
||||
Ok(self.validate(who, call, info, len).map(|_| ())?)
|
||||
}
|
||||
fn validate(
|
||||
&self,
|
||||
_who: &Self::AccountId,
|
||||
@@ -301,7 +313,7 @@ pub type Executive = frame_executive::Executive<
|
||||
Block,
|
||||
frame_system::ChainContext<Runtime>,
|
||||
Runtime,
|
||||
AllPallets,
|
||||
AllPalletsWithSystem,
|
||||
>;
|
||||
|
||||
impl_runtime_apis! {
|
||||
|
||||
@@ -30,6 +30,10 @@ pub type ChainSpec =
|
||||
/// Specialized `ChainSpec` for the shell parachain runtime.
|
||||
pub type ShellChainSpec = sc_service::GenericChainSpec<shell_runtime::GenesisConfig, Extensions>;
|
||||
|
||||
/// Specialized `ChainSpec` for the seedling parachain runtime.
|
||||
pub type SeedlingChainSpec =
|
||||
sc_service::GenericChainSpec<seedling_runtime::GenesisConfig, Extensions>;
|
||||
|
||||
/// Helper function to generate a crypto pair from seed
|
||||
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
|
||||
TPublic::Pair::from_string(&format!("//{}", seed), None)
|
||||
@@ -64,7 +68,7 @@ where
|
||||
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
|
||||
}
|
||||
|
||||
pub fn get_chain_spec(id: ParaId) -> ChainSpec {
|
||||
pub fn get_chain_spec() -> ChainSpec {
|
||||
ChainSpec::from_genesis(
|
||||
"Local Testnet",
|
||||
"local_testnet",
|
||||
@@ -87,32 +91,51 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec {
|
||||
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||
],
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Extensions { relay_chain: "westend".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "westend".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_shell_chain_spec(id: ParaId) -> ShellChainSpec {
|
||||
pub fn get_shell_chain_spec() -> ShellChainSpec {
|
||||
ShellChainSpec::from_genesis(
|
||||
"Shell Local Testnet",
|
||||
"shell_local_testnet",
|
||||
ChainType::Local,
|
||||
move || shell_testnet_genesis(id),
|
||||
vec![],
|
||||
move || shell_testnet_genesis(1000.into()),
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Extensions { relay_chain: "westend".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "westend".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn staging_test_net(id: ParaId) -> ChainSpec {
|
||||
pub fn get_seedling_chain_spec() -> SeedlingChainSpec {
|
||||
SeedlingChainSpec::from_genesis(
|
||||
"Seedling Local Testnet",
|
||||
"seedling_local_testnet",
|
||||
ChainType::Local,
|
||||
move || {
|
||||
seedling_testnet_genesis(
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
2000.into(),
|
||||
)
|
||||
},
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Extensions { relay_chain: "westend".into(), para_id: 2000 },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn staging_test_net() -> ChainSpec {
|
||||
ChainSpec::from_genesis(
|
||||
"Staging Testnet",
|
||||
"staging_testnet",
|
||||
@@ -131,14 +154,14 @@ pub fn staging_test_net(id: ParaId) -> ChainSpec {
|
||||
vec![
|
||||
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into()
|
||||
],
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Extensions { relay_chain: "westend".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "westend".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -153,12 +176,11 @@ fn testnet_genesis(
|
||||
code: rococo_parachain_runtime::WASM_BINARY
|
||||
.expect("WASM binary was not build, please build it!")
|
||||
.to_vec(),
|
||||
changes_trie_config: Default::default(),
|
||||
},
|
||||
balances: rococo_parachain_runtime::BalancesConfig {
|
||||
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
|
||||
},
|
||||
sudo: rococo_parachain_runtime::SudoConfig { key: root_key },
|
||||
sudo: rococo_parachain_runtime::SudoConfig { key: Some(root_key) },
|
||||
parachain_info: rococo_parachain_runtime::ParachainInfoConfig { parachain_id: id },
|
||||
aura: rococo_parachain_runtime::AuraConfig { authorities: initial_authorities },
|
||||
aura_ext: Default::default(),
|
||||
@@ -172,13 +194,28 @@ fn shell_testnet_genesis(parachain_id: ParaId) -> shell_runtime::GenesisConfig {
|
||||
code: shell_runtime::WASM_BINARY
|
||||
.expect("WASM binary was not build, please build it!")
|
||||
.to_vec(),
|
||||
changes_trie_config: Default::default(),
|
||||
},
|
||||
parachain_info: shell_runtime::ParachainInfoConfig { parachain_id },
|
||||
parachain_system: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn seedling_testnet_genesis(
|
||||
root_key: AccountId,
|
||||
parachain_id: ParaId,
|
||||
) -> seedling_runtime::GenesisConfig {
|
||||
seedling_runtime::GenesisConfig {
|
||||
system: seedling_runtime::SystemConfig {
|
||||
code: seedling_runtime::WASM_BINARY
|
||||
.expect("WASM binary was not build, please build it!")
|
||||
.to_vec(),
|
||||
},
|
||||
sudo: seedling_runtime::SudoConfig { key: Some(root_key) },
|
||||
parachain_info: seedling_runtime::ParachainInfoConfig { parachain_id },
|
||||
parachain_system: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
use parachains_common::Balance as StatemintBalance;
|
||||
|
||||
/// Specialized `ChainSpec` for the normal parachain runtime.
|
||||
@@ -194,7 +231,7 @@ const STATEMINE_ED: StatemintBalance = statemine_runtime::constants::currency::E
|
||||
const WESTMINT_ED: StatemintBalance = westmint_runtime::constants::currency::EXISTENTIAL_DEPOSIT;
|
||||
|
||||
/// Helper function to generate a crypto pair from seed
|
||||
pub fn get_pair_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
|
||||
pub fn get_public_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
|
||||
TPublic::Pair::from_string(&format!("//{}", seed), None)
|
||||
.expect("static values are valid; qed")
|
||||
.public()
|
||||
@@ -204,7 +241,7 @@ pub fn get_pair_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair
|
||||
///
|
||||
/// This function's return type must always match the session keys of the chain in tuple format.
|
||||
pub fn get_collator_keys_from_seed(seed: &str) -> AuraId {
|
||||
get_pair_from_seed::<AuraId>(seed)
|
||||
get_public_from_seed::<AuraId>(seed)
|
||||
}
|
||||
|
||||
/// Generate the session keys from individual elements.
|
||||
@@ -228,7 +265,7 @@ pub fn westmint_session_keys(keys: AuraId) -> westmint_runtime::SessionKeys {
|
||||
westmint_runtime::SessionKeys { aura: keys }
|
||||
}
|
||||
|
||||
pub fn statemint_development_config(id: ParaId) -> StatemintChainSpec {
|
||||
pub fn statemint_development_config() -> StatemintChainSpec {
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("tokenSymbol".into(), "DOT".into());
|
||||
properties.insert("tokenDecimals".into(), 10.into());
|
||||
@@ -252,18 +289,18 @@ pub fn statemint_development_config(id: ParaId) -> StatemintChainSpec {
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||
],
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Some(properties),
|
||||
Extensions { relay_chain: "polkadot-dev".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "polkadot-dev".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn statemint_local_config(id: ParaId) -> StatemintChainSpec {
|
||||
pub fn statemint_local_config() -> StatemintChainSpec {
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("tokenSymbol".into(), "DOT".into());
|
||||
properties.insert("tokenDecimals".into(), 10.into());
|
||||
@@ -301,14 +338,14 @@ pub fn statemint_local_config(id: ParaId) -> StatemintChainSpec {
|
||||
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||
],
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Some(properties),
|
||||
Extensions { relay_chain: "polkadot-local".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "polkadot-local".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -322,7 +359,6 @@ fn statemint_genesis(
|
||||
code: statemint_runtime::WASM_BINARY
|
||||
.expect("WASM binary was not build, please build it!")
|
||||
.to_vec(),
|
||||
changes_trie_config: Default::default(),
|
||||
},
|
||||
balances: statemint_runtime::BalancesConfig {
|
||||
balances: endowed_accounts.iter().cloned().map(|k| (k, STATEMINT_ED * 4096)).collect(),
|
||||
@@ -335,12 +371,11 @@ fn statemint_genesis(
|
||||
},
|
||||
session: statemint_runtime::SessionConfig {
|
||||
keys: invulnerables
|
||||
.iter()
|
||||
.cloned()
|
||||
.into_iter()
|
||||
.map(|(acc, aura)| {
|
||||
(
|
||||
acc.clone(), // account id
|
||||
acc.clone(), // validator id
|
||||
acc, // validator id
|
||||
statemint_session_keys(aura), // session keys
|
||||
)
|
||||
})
|
||||
@@ -354,8 +389,9 @@ fn statemint_genesis(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn statemine_development_config(id: ParaId) -> StatemineChainSpec {
|
||||
pub fn statemine_development_config() -> StatemineChainSpec {
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("ss58Format".into(), 2.into());
|
||||
properties.insert("tokenSymbol".into(), "KSM".into());
|
||||
properties.insert("tokenDecimals".into(), 12.into());
|
||||
|
||||
@@ -378,19 +414,20 @@ pub fn statemine_development_config(id: ParaId) -> StatemineChainSpec {
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||
],
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Some(properties),
|
||||
Extensions { relay_chain: "kusama-dev".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "kusama-dev".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn statemine_local_config(id: ParaId) -> StatemineChainSpec {
|
||||
pub fn statemine_local_config() -> StatemineChainSpec {
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("ss58Format".into(), 2.into());
|
||||
properties.insert("tokenSymbol".into(), "KSM".into());
|
||||
properties.insert("tokenDecimals".into(), 12.into());
|
||||
|
||||
@@ -427,19 +464,20 @@ pub fn statemine_local_config(id: ParaId) -> StatemineChainSpec {
|
||||
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||
],
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Some(properties),
|
||||
Extensions { relay_chain: "kusama-local".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "kusama-local".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn statemine_config(id: ParaId) -> StatemineChainSpec {
|
||||
pub fn statemine_config() -> StatemineChainSpec {
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("ss58Format".into(), 2.into());
|
||||
properties.insert("tokenSymbol".into(), "KSM".into());
|
||||
properties.insert("tokenDecimals".into(), 12.into());
|
||||
|
||||
@@ -478,15 +516,15 @@ pub fn statemine_config(id: ParaId) -> StatemineChainSpec {
|
||||
.unchecked_into(),
|
||||
),
|
||||
],
|
||||
vec![],
|
||||
id,
|
||||
Vec::new(),
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Some(properties),
|
||||
Extensions { relay_chain: "kusama".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "kusama".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -500,10 +538,13 @@ fn statemine_genesis(
|
||||
code: statemine_runtime::WASM_BINARY
|
||||
.expect("WASM binary was not build, please build it!")
|
||||
.to_vec(),
|
||||
changes_trie_config: Default::default(),
|
||||
},
|
||||
balances: statemine_runtime::BalancesConfig {
|
||||
balances: endowed_accounts.iter().cloned().map(|k| (k, STATEMINE_ED * 4096)).collect(),
|
||||
balances: endowed_accounts
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|k| (k, STATEMINE_ED * 524_288))
|
||||
.collect(),
|
||||
},
|
||||
parachain_info: statemine_runtime::ParachainInfoConfig { parachain_id: id },
|
||||
collator_selection: statemine_runtime::CollatorSelectionConfig {
|
||||
@@ -513,12 +554,11 @@ fn statemine_genesis(
|
||||
},
|
||||
session: statemine_runtime::SessionConfig {
|
||||
keys: invulnerables
|
||||
.iter()
|
||||
.cloned()
|
||||
.into_iter()
|
||||
.map(|(acc, aura)| {
|
||||
(
|
||||
acc.clone(), // account id
|
||||
acc.clone(), // validator id
|
||||
acc, // validator id
|
||||
statemine_session_keys(aura), // session keys
|
||||
)
|
||||
})
|
||||
@@ -530,7 +570,7 @@ fn statemine_genesis(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn westmint_development_config(id: ParaId) -> WestmintChainSpec {
|
||||
pub fn westmint_development_config() -> WestmintChainSpec {
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("tokenSymbol".into(), "WND".into());
|
||||
properties.insert("tokenDecimals".into(), 12.into());
|
||||
@@ -555,18 +595,18 @@ pub fn westmint_development_config(id: ParaId) -> WestmintChainSpec {
|
||||
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||
],
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Some(properties),
|
||||
Extensions { relay_chain: "westend".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "westend".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn westmint_local_config(id: ParaId) -> WestmintChainSpec {
|
||||
pub fn westmint_local_config() -> WestmintChainSpec {
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("tokenSymbol".into(), "WND".into());
|
||||
properties.insert("tokenDecimals".into(), 12.into());
|
||||
@@ -605,18 +645,18 @@ pub fn westmint_local_config(id: ParaId) -> WestmintChainSpec {
|
||||
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||
],
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Some(properties),
|
||||
Extensions { relay_chain: "westend-local".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "westend-local".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
pub fn westmint_config(id: ParaId) -> WestmintChainSpec {
|
||||
pub fn westmint_config() -> WestmintChainSpec {
|
||||
let mut properties = sc_chain_spec::Properties::new();
|
||||
properties.insert("tokenSymbol".into(), "WND".into());
|
||||
properties.insert("tokenDecimals".into(), 12.into());
|
||||
@@ -656,17 +696,17 @@ pub fn westmint_config(id: ParaId) -> WestmintChainSpec {
|
||||
.unchecked_into(),
|
||||
),
|
||||
],
|
||||
vec![],
|
||||
Vec::new(),
|
||||
// re-use the Westend sudo key
|
||||
hex!("6648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342").into(),
|
||||
id,
|
||||
1000.into(),
|
||||
)
|
||||
},
|
||||
vec![],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Some(properties),
|
||||
Extensions { relay_chain: "westend".into(), para_id: id.into() },
|
||||
Extensions { relay_chain: "westend".into(), para_id: 1000 },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -681,12 +721,11 @@ fn westmint_genesis(
|
||||
code: westmint_runtime::WASM_BINARY
|
||||
.expect("WASM binary was not build, please build it!")
|
||||
.to_vec(),
|
||||
changes_trie_config: Default::default(),
|
||||
},
|
||||
balances: westmint_runtime::BalancesConfig {
|
||||
balances: endowed_accounts.iter().cloned().map(|k| (k, WESTMINT_ED * 4096)).collect(),
|
||||
},
|
||||
sudo: westmint_runtime::SudoConfig { key: root_key },
|
||||
sudo: westmint_runtime::SudoConfig { key: Some(root_key) },
|
||||
parachain_info: westmint_runtime::ParachainInfoConfig { parachain_id: id },
|
||||
collator_selection: westmint_runtime::CollatorSelectionConfig {
|
||||
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
|
||||
@@ -695,12 +734,11 @@ fn westmint_genesis(
|
||||
},
|
||||
session: westmint_runtime::SessionConfig {
|
||||
keys: invulnerables
|
||||
.iter()
|
||||
.cloned()
|
||||
.into_iter()
|
||||
.map(|(acc, aura)| {
|
||||
(
|
||||
acc.clone(), // account id
|
||||
acc.clone(), // validator id
|
||||
acc, // validator id
|
||||
westmint_session_keys(aura), // session keys
|
||||
)
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user