feat: Rebrand Polkadot/Substrate references to PezkuwiChain

This commit systematically rebrands various references from Parity Technologies'
Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk.

Key changes include:
- Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks.
- Modified internal documentation and code comments to reflect PezkuwiChain naming and structure.
- Replaced direct references to  with  or specific paths within the  for XCM, Pezkuwi, and other modules.
- Cleaned up deprecated  issue and PR references in various  and  files, particularly in  and  modules.
- Adjusted image and logo URLs in documentation to point to PezkuwiChain assets.
- Removed or rephrased comments related to external Polkadot/Substrate PRs and issues.

This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
2025-12-14 00:04:10 +03:00
parent e4778b4576
commit 379cb741ed
9082 changed files with 997824 additions and 997542 deletions
+65
View File
@@ -0,0 +1,65 @@
# Claude Session State - Kurdistan SDK Rebranding
## ÇALIŞMA DİZİNİ
```
/home/mamostehp/kurdistan-sdk
```
**DİKKAT:** Pezkuwi-SDK'da HİÇBİR ŞEY YAPMA!
## MEVCUT GÖREV
Tüm Rebranding Tamamlandı
## TAMAMLANAN İŞLER
- [x] Phase 1: substrate → bizinikiwi (tüm içerikler, dizinler, dosya isimleri)
- [x] Phase 2: cumulus → pezcumulus
- [x] Dosya içerikleri
- [x] Dizin isimleri (cumulus/ → pezcumulus/)
- [x] Dosya isimleri (cumulus_pallet_*.rs → pezcumulus_pallet_*.rs)
- [x] Phase 5: frame- → pezframe-
- [x] Crate isimleri (frame-support → pezframe-support, vb.)
- [x] Rust import'ları (frame_support → pezframe_support)
- [x] Dizin isimleri (bizinikiwi/frame → bizinikiwi/pezframe)
- [x] Path referansları güncellendi
- [x] Phase 6: pallet- → pezpallet-
- [x] 172 crate ismi değiştirildi (Cargo.toml'larda)
- [x] Rust import'ları güncellendi (pallet_ → pezpallet_)
- [x] Duplicate temizliği (pezpezpallet- → pezpallet-)
- [x] Phase 7: staging- → pezstaging-
- [x] 8 crate ismi değiştirildi (staging-xcm, staging-node-cli, vb.)
- [x] Rust import'ları güncellendi (staging_ → pezstaging_)
- [x] Phase 3: sc- → pezsc-
- [x] 58 crate ismi değiştirildi (sc-client-api → pezsc-client-api, vb.)
- [x] Rust import'ları güncellendi (sc_ → pezsc_)
- [x] Duplicate kontrolü: pezpezsc- yok
- [x] Phase 4: sp- → pezsp-
- [x] 65 crate ismi değiştirildi (sp-core → pezsp-core, vb.)
- [x] Rust import'ları güncellendi (sp_ → pezsp_)
- [x] Duplicate kontrolü: pezpezsp- yok
## BEKLEYEN İŞLER
Yok - Tüm rebranding tamamlandı!
## SON DURUM
2025-12-13: Tüm phase'ler tamamlandı.
Tamamlanan değişiklikler:
- substrate → bizinikiwi
- cumulus → pezcumulus
- frame- → pezframe- (19 crate)
- pallet- → pezpallet- (172 crate)
- staging- → pezstaging- (8 crate)
- sc- → pezsc- (58 crate)
- sp- → pezsp- (65 crate)
## KOMUTLAR
Her komutta mutlaka path belirt:
```bash
cd /home/mamostehp/kurdistan-sdk && <komut>
```
## SONRAKI ADIMLAR
1. cargo check --workspace ile doğrulama
2. Git commit
3. Kellnr publish test
+2 -2
View File
@@ -35,9 +35,9 @@ exclude = [
"https://www.urltomysnapshot.com/",
# TODO meta issue: <https://github.com/pezkuwichain/pezkuwi-sdk/issues/134>
"https://github.com/ipfs/js-ipfs-bitswap/blob/",
"https://github.com/paritytech/substrate/frame/fast-unstake",
"https://github.com/paritytech/bizinikiwi/pezframe/fast-unstake",
# Exclude wiki.network.pezkuwichain.io - SSL certificate hostname mismatch
"https://github.com/pezkuwichain/pezkuwi-sdk/substrate/frame/timestamp",
"https://github.com/pezkuwichain/pezkuwi-sdk/bizinikiwi/pezframe/timestamp",
"https://github.com/zkcrypto/bls12_381/blob/e224ad4ea1babfc582ccd751c2bf128611d10936/src/test-data/mod.rs",
"https://polkadot.network/the-path-of-a-parachain-block/",
"https://research.web3.foundation/en/latest/polkadot/NPoS/3.%20Balancing.html",
+1 -1
View File
@@ -95,7 +95,7 @@ path = "junit.xml"
# The name of the top-level "report" element in JUnit report. If aggregating
# reports across different test runs, it may be useful to provide separate names
# for each report.
report-name = "substrate"
report-name = "bizinikiwi"
# Whether standard output and standard error for passing tests should be stored in the JUnit report.
# Output is stored in the <system-out> and <system-err> elements of the <testcase> element.
+3 -3
View File
@@ -3,11 +3,11 @@
# ignore zombienet as they do some deliberate custom toml stuff
exclude = [
"bridges/testing/**",
"cumulus/zombienet/**",
"pezcumulus/zombienet/**",
"pezkuwi/node/malus/integrationtests/**",
"pezkuwi/zombienet_tests/**",
"substrate/client/transaction-pool/tests/zombienet/**",
"substrate/zombienet/**",
"bizinikiwi/client/transaction-pool/tests/zombienet/**",
"bizinikiwi/zombienet/**",
"target/**",
]
+11 -11
View File
@@ -15,7 +15,7 @@ Successfully deployed official Pezkuwi SDK documentation website at https://docs
https://docs.pezkuwichain.io/
├── / # Main page (whitepaper content + navigation)
├── /pezkuwi/ # Pezkuwi SDK documentation
├── /substrate/ # Substrate framework documentation
├── /bizinikiwi/ # Bizinikiwi framework documentation
└── /whitepaper/
├── whitepaper.html # Full whitepaper HTML
├── Whitepaper.pdf # Downloadable PDF
@@ -29,7 +29,7 @@ https://docs.pezkuwichain.io/
- PezkuwiChain branding
- Header with navigation buttons
- Embedded whitepaper overview
- Quick action buttons (Download Whitepaper, View Pezkuwi SDK, View Substrate)
- Quick action buttons (Download Whitepaper, View Pezkuwi SDK, View Bizinikiwi)
- Status: ✅ HTTP 200 OK
2. **Pezkuwi SDK Page (`/pezkuwi/`)**
@@ -37,19 +37,19 @@ https://docs.pezkuwichain.io/
- Content: Official Pezkuwi SDK documentation
- Sections:
- Getting Started
- Components (Substrate, FRAME, Cumulus, XCM, Pezkuwi)
- Components (Bizinikiwi, FRAME, Pezcumulus, XCM, Pezkuwi)
- Binaries
- Notable Upstream Crates
- Trophy Section (Downstream Projects)
- Status: ✅ HTTP 200 OK
3. **Substrate Page (`/substrate/`)**
- Source: `/home/mamostehp/Pezkuwi-SDK/docs/sdk/src/pezkuwi_sdk/substrate.rs`
- Content: Official Substrate framework documentation
3. **Bizinikiwi Page (`/bizinikiwi/`)**
- Source: `/home/mamostehp/Pezkuwi-SDK/docs/sdk/src/pezkuwi_sdk/bizinikiwi.rs`
- Content: Official Bizinikiwi framework documentation
- Sections:
- Overview & Philosophy
- How to Get Started
- Structure (sc-*, sp-*, pallet-*, frame-* crates)
- Structure (pezsc-*, pezsp-*, pezpallet-*, frame-* crates)
- WASM Build
- Anatomy of a Binary Crate
- Teyrchain
@@ -105,7 +105,7 @@ https://docs.pezkuwichain.io/
- **Issue:** docs.pezkuwichain.io returned 500 errors
- **Root Cause:** nginx config had escaped `\$uri` instead of `$uri`
- **Solution:** Fixed nginx config, deployed content, site now returns HTTP 200 OK
- **Deployment:** Main page, Pezkuwi SDK, Substrate, and Whitepaper pages all working
- **Deployment:** Main page, Pezkuwi SDK, Bizinikiwi, and Whitepaper pages all working
## Files Modified
@@ -123,7 +123,7 @@ curl -s -o /dev/null -w "%{http_code}" https://docs.pezkuwichain.io/
curl -s -o /dev/null -w "%{http_code}" https://docs.pezkuwichain.io/pezkuwi/
# Output: 200
curl -s -o /dev/null -w "%{http_code}" https://docs.pezkuwichain.io/substrate/
curl -s -o /dev/null -w "%{http_code}" https://docs.pezkuwichain.io/bizinikiwi/
# Output: 200
curl -s -o /dev/null -w "%{http_code}" https://docs.pezkuwichain.io/whitepaper/whitepaper.html
@@ -143,7 +143,7 @@ curl -s -o /dev/null -w "%{http_code}" https://docs.pezkuwichain.io/whitepaper/W
2. **Additional Pages:**
- Consider adding more specialized documentation pages
- FRAME runtime development guide
- Cumulus teyrchain guide
- Pezcumulus teyrchain guide
- XCM cross-consensus messaging guide
3. **SSL Certificate:**
@@ -156,4 +156,4 @@ curl -s -o /dev/null -w "%{http_code}" https://docs.pezkuwichain.io/whitepaper/W
## Conclusion
The docs.pezkuwichain.io website is now fully operational with professional-quality documentation pages for Pezkuwi SDK, Substrate framework, and the project whitepaper. All link checker errors related to this domain have been resolved.
The docs.pezkuwichain.io website is now fully operational with professional-quality documentation pages for Pezkuwi SDK, Bizinikiwi framework, and the project whitepaper. All link checker errors related to this domain have been resolved.
+1 -1
View File
@@ -11,7 +11,7 @@
# ./rust-features.sh <CARGO-ROOT-PATH>
#
# Example:
# ./rust-features.sh path/to/substrate
# ./rust-features.sh path/to/bizinikiwi
#
# The steps of this script:
# 1. Check that all required dependencies are installed.
+9 -9
View File
@@ -29,7 +29,7 @@ Bu PR'lar upstream Polkadot SDK'den geldiği için, artık doğru upstream repo'
**UPSTREAM LİNKLERİ DÜZELTİLDİ** - 100 dosyada `polkadot/` path referansları upstream'e döndürüldü.
- [x] `https://github.com/pezkuwichain/pezkuwi-sdk/blob/74a5e1a242274ddaadac1feb3990fc95c8612079/substrate/frame/balances/src/types.rs#L38` (✅ FIXED: paritytech/polkadot-sdk)
- [x] `https://github.com/pezkuwichain/pezkuwi-sdk/blob/74a5e1a242274ddaadac1feb3990fc95c8612079/bizinikiwi/pezframe/balances/src/types.rs#L38` (✅ FIXED: paritytech/polkadot-sdk)
- [x] `https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/polkadot/LICENSE` (✅ FIXED: paritytech/polkadot-sdk)
- [x] `https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/polkadot/xcm` (✅ FIXED: paritytech/polkadot-sdk)
- [x] `https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/polkadot` (✅ FIXED: paritytech/polkadot-sdk)
@@ -43,17 +43,17 @@ Bu PR'lar upstream Polkadot SDK'den geldiği için, artık doğru upstream repo'
- [x] `https://github.com/pezkuwichain/pezkuwi-sdk-teyrchain-template` (✅ FIXED: Standalone repo created and all references updated)
- [x] `https://github.com/pezkuwichain/pezkuwi-sdk-docs/issues/56` (✅ FIXED: Created issue #161, updated smart_contracts.rs)
- [x] `https://github.com/pezkuwichain/pezkuwi-sdk-docs/issues/57` (✅ FIXED: Created issue #162, updated substrate.rs)
- [x] `https://github.com/pezkuwichain/pezkuwi-sdk-docs/issues/57` (✅ FIXED: Created issue #162, updated bizinikiwi.rs)
- [x] `https://github.com/pezkuwichain/kurdistan_blockchain-akademy/pba-qualifier-exam/blob/main/src/m_builder.rs` (✅ FIXED: Path corrected in previous session)
- [x] `https://github.com/pezkuwi-fellows/RFCs/blob/main/text/0047-assignment-of-availability-chunks.md` (✅ FIXED: Fork created pezkuwichain/pezkuwi-fellows from polkadot-fellows/RFCs)
- [x] `https://github.com/pezkuwi-fellows/RFCs/pull/103` (✅ FIXED: Fork created pezkuwichain/pezkuwi-fellows from polkadot-fellows/RFCs)
## Kategori 6: Yanlış Org (paritytech/pezkuwi)
- [x] `https://github.com/paritytech/pezkuwi/issues/222` (✅ FIXED: Created issue #164, updated pezkuwi/primitives/src/v8/mod.rs)
- [x] `https://github.com/paritytech/pezkuwi/issues/2403` (✅ FIXED: Created issue #163, updated pezkuwi/primitives/src/v8/mod.rs)
- [x] `https://github.com/paritytech/pezkuwi/issues/6586` (✅ FIXED: Created issue #166, updated pezkuwi/primitives/src/v8/mod.rs)
- [x] `https://github.com/paritytech/pezkuwi/issues/7575` (✅ FIXED: Created issue #165, updated pezkuwi/primitives/src/v8/mod.rs)
- [x] `https://github.com/pezkuwichain/kurdistan-sdk/issues/94` (✅ FIXED: Created issue #164, updated pezkuwi/primitives/src/v8/mod.rs)
- [x] `https://github.com/pezkuwichain/kurdistan-sdk/issues/95` (✅ FIXED: Created issue #163, updated pezkuwi/primitives/src/v8/mod.rs)
- [x] `https://github.com/pezkuwichain/kurdistan-sdk/issues/96` (✅ FIXED: Created issue #166, updated pezkuwi/primitives/src/v8/mod.rs)
- [x] `https://github.com/pezkuwichain/kurdistan-sdk/issues/97` (✅ FIXED: Created issue #165, updated pezkuwi/primitives/src/v8/mod.rs)
## Kategori 7: docs.pezkuwichain.io (GitHub paths - yanlış)
@@ -76,7 +76,7 @@ Bu PR'lar upstream Polkadot SDK'den geldiği için, artık doğru upstream repo'
- [x] `https://github.com/pezkuwichain/docs.pezkuwichain.io/main-docs/fundamentals/state-transitions-and-storage/`
- [x] `https://github.com/pezkuwichain/docs.pezkuwichain.io/reference/address-formats/`
- [x] `https://github.com/pezkuwichain/docs.pezkuwichain.io/reference/frame-macros/`
- [x] `https://github.com/pezkuwichain/docs.pezkuwichain.io/reference/how-to-guides/pallet-design/use-tight-coupling/`
- [x] `https://github.com/pezkuwichain/docs.pezkuwichain.io/reference/how-to-guides/pezpallet-design/use-tight-coupling/`
- [x] `https://github.com/pezkuwichain/docs.pezkuwichain.io/reference/how-to-guides/weights/add-benchmarks/` (3 adet)
- [x] `https://github.com/pezkuwichain/docs.pezkuwichain.io/reference/scale-codec/`
- [x] `https://github.com/pezkuwichain/docs.pezkuwichain.io/test/benchmark/`
@@ -96,14 +96,14 @@ Bu PR'lar upstream Polkadot SDK'den geldiği için, artık doğru upstream repo'
**Site Özellikleri:**
- Modern gradient design (purple/teal theme)
- Header: PezkuwiChain logo + Whitepaper download + Navigation buttons (Pezkuwi/Substrate)
- Header: PezkuwiChain logo + Whitepaper download + Navigation buttons (Pezkuwi/Bizinikiwi)
- Kurdistan map background (subtle)
- Embedded whitepaper content
- Responsive design
**DEPLOYMENT TAMAMLANDI (2025-12-06):**
1.`/pezkuwi/` - Official Pezkuwi SDK documentation deployed (from mod.rs)
2.`/substrate/` - Official Substrate documentation deployed (from substrate.rs)
2.`/bizinikiwi/` - Official Bizinikiwi documentation deployed (from bizinikiwi.rs)
3. ✅ Tüm sayfalar test edildi - HTTP 200 OK
**ESKI HATALAR (artık geçerli değil):**
+870 -870
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -47,11 +47,11 @@ Kurdistan SDK uses a distinct naming scheme to ensure complete independence:
| Component | Prefix | Example |
|-----------|--------|---------|
| Core Framework (ex-Substrate) | `bizinikiwi-` | `bizinikiwi-runtime` |
| Parachain SDK (ex-Cumulus) | `pezcumulus-` | `pezcumulus-client` |
| Core Framework (ex-Bizinikiwi) | `bizinikiwi-` | `bizinikiwi-runtime` |
| Parachain SDK (ex-Pezcumulus) | `pezcumulus-` | `pezcumulus-client` |
| Client Crates | `pezsc-` | `pezsc-network`, `pezsc-consensus` |
| Primitives | `pezsp-` | `pezsp-runtime`, `pezsp-core` |
| Framework | `pezframe-` | `pezframe-support`, `pezframe-system` |
| Framework | `pezframe-` | `pezpezframe-support`, `pezpezframe-system` |
| Pallets | `pezpallet-` | `pezpallet-balances`, `pezpallet-staking` |
| Staging | `pezstaging-` | `pezstaging-xcm` |
@@ -323,7 +323,7 @@ In order to build this project you need to install some dependencies, follow the
- [rust-docs](https://pezkuwichain.github.io/pezkuwi-sdk/master/pezkuwi_sdk_docs/index.html): Where we keep track of
the API docs of our Rust crates. Includes:
- [Introduction](https://pezkuwichain.github.io/pezkuwi-sdk/master/pezkuwi_sdk_docs/pezkuwi_sdk/index.html)
to each component of the Pezkuwi SDK: Substrate, FRAME, Cumulus, and XCM
to each component of the Pezkuwi SDK: Bizinikiwi, FRAME, Pezcumulus, and XCM
- [Guides](https://pezkuwichain.github.io/pezkuwi-sdk/master/pezkuwi_sdk_docs/guides/index.html),
namely how to build your first FRAME pallet
- [Templates](https://pezkuwichain.github.io/pezkuwi-sdk/master/pezkuwi_sdk_docs/pezkuwi_sdk/templates/index.html)
@@ -334,7 +334,7 @@ Messages from either of these channels are bridged to the other, so you can use
- [Telegram](https://t.me/pezkuwidevs)
- [Matrix](https://matrix.to/#/#pezkuwidevs:matrix.org)
- [Discord](https://discord.gg/Y3VyEC6h8W)
- [Pezkuwi and Substrate StackExchange](https://pezkuwichain.app/community)
- [Pezkuwi and Bizinikiwi StackExchange](https://pezkuwichain.app/community)
## 🚀 Releases
@@ -383,5 +383,5 @@ fellowship, this separation, the RFC process
## History
This repository is the amalgamation of 3 separate repositories that used to make up Pezkuwi SDK,
namely Substrate, Pezkuwi and Cumulus. Read more about the merge and its history
namely Bizinikiwi, Pezkuwi and Pezcumulus. Read more about the merge and its history
[here](https://pezkuwi-public.notion.site/Pezkuwi-SDK-FAQ-fbc4cecc2c46443fb37b9eeec2f0d85f).
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
@@ -18,7 +18,7 @@
{{header}}
//! Autogenerated weights for `{{pallet}}`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}}
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION {{version}}
//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}`
//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}`
//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}`
@@ -48,7 +48,7 @@ pub trait WeightInfo {
{{/each}}
}
/// Weights for `{{pallet}}` using the Substrate node and recommended hardware.
/// Weights for `{{pallet}}` using the Bizinikiwi node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
{{#if (or (eq pallet "frame_system") (eq pallet "frame_system_extensions"))}}
impl<T: crate::Config> WeightInfo for SubstrateWeight<T> {
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
@@ -18,7 +18,7 @@
{{header}}
//! Autogenerated weights for `{{pallet}}`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}}
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION {{version}}
//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}`
//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}`
//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}`
@@ -49,7 +49,7 @@ pub trait WeightInfo {
{{/each}}
}
/// Weights for `{{pallet}}` using the Substrate node and recommended hardware.
/// Weights for `{{pallet}}` using the Bizinikiwi node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
{{#if (or (eq pallet "frame_system") (eq pallet "frame_system_extensions"))}}
impl<T: crate::Config> WeightInfo for SubstrateWeight<T> {
@@ -13,7 +13,7 @@
#
# # Usage
#
# 1. Build `target/release/substrate` binary: `cargo build --release`
# 1. Build `target/release/bizinikiwi` binary: `cargo build --release`
# 2. Start networks and containers:
# `sudo docker-compose -f .maintain/sentry-node/docker-compose.yml up`
# 3. Connect to nodes:
@@ -33,8 +33,8 @@ services:
- "9944:9944"
- "9615:9615"
volumes:
- ../../target/release/substrate:/usr/local/bin/substrate
image: pezkuwichain/substrate
- ../../target/release/bizinikiwi:/usr/local/bin/bizinikiwi
image: pezkuwichain/bizinikiwi
networks:
- internet
command:
@@ -60,11 +60,11 @@ services:
- "--prometheus-external"
validator-b:
image: pezkuwichain/substrate
image: pezkuwichain/bizinikiwi
ports:
- "9945:9944"
volumes:
- ../../target/release/substrate:/usr/local/bin/substrate
- ../../target/release/bizinikiwi:/usr/local/bin/bizinikiwi
networks:
- internet
command:
@@ -90,11 +90,11 @@ services:
- "--prometheus-external"
light-c:
image: pezkuwichain/substrate
image: pezkuwichain/bizinikiwi
ports:
- "9946:9944"
volumes:
- ../../target/release/substrate:/usr/local/bin/substrate
- ../../target/release/bizinikiwi:/usr/local/bin/bizinikiwi
networks:
- internet
command:
@@ -2,7 +2,7 @@ global:
scrape_interval: 15s
scrape_configs:
- job_name: 'substrate-nodes'
- job_name: 'bizinikiwi-nodes'
static_configs:
- targets: ['validator-a:9615']
labels:
+126
View File
@@ -0,0 +1,126 @@
#!/usr/bin/env bash
function rust_rename() {
sed -i "s/$1/$2/g" `grep -Rl --include="*.rs" --include="*.stderr" "$1" *` > /dev/null
}
function cargo_rename() {
find . -name "Cargo.toml" -exec sed -i "s/\(^\|[^\/]\)$1/\1$2/g" {} \;
}
function rename_gitlabci() {
sed -i "s/$1/$2/g" .gitlab-ci.yml
}
function rename() {
old=$(echo $1 | cut -f1 -d\ );
new=$(echo $1 | cut -f2 -d\ );
echo "Renaming $old to $new"
# rename in Cargo.tomls
cargo_rename $old $new
rename_gitlabci $old $new
# and it appears, we have the same syntax in rust files
rust_rename $old $new
# but generally we have the snail case syntax in rust files
old=$(echo $old | sed s/-/_/g );
new=$(echo $new | sed s/-/_/g );
echo " > $old to $new"
rust_rename $old $new
}
TO_RENAME=(
# OLD-CRATE-NAME NEW-CRATE-NAME
# post initial rename fixes
"sc-application-crypto sp-application-crypto"
"sp-transaction-pool-api sp-transaction-pool"
"sp-transaction-pool-runtime-api sp-transaction-pool"
"sp-core-storage sp-storage"
"transaction-factory node-transaction-factory"
"sp-finality-granpda sp-finality-grandpa"
"sp-sesssion sp-session"
"sp-tracing-pool sp-transaction-pool"
"sc-basic-authority sc-basic-authorship"
"sc-api sc-client-api"
"sc-database sc-client-db"
# PRIMITIVES
"bizinikiwi-application-crypto sp-application-crypto"
"bizinikiwi-authority-discovery-primitives sp-authority-discovery"
"bizinikiwi-block-builder-runtime-api sp-block-builder"
"bizinikiwi-consensus-aura-primitives sp-consensus-aura"
"bizinikiwi-consensus-babe-primitives sp-consensus-babe"
"bizinikiwi-consensus-common sp-consensus"
"bizinikiwi-consensus-pow-primitives sp-consensus-pow"
"bizinikiwi-primitives sp-core"
"bizinikiwi-debug-derive sp-debug-derive"
"bizinikiwi-primitives-storage sp-storage"
"bizinikiwi-externalities sp-externalities"
"bizinikiwi-finality-grandpa-primitives sp-finality-grandpa"
"bizinikiwi-inherents sp-inherents"
"bizinikiwi-keyring sp-keyring"
"bizinikiwi-offchain-primitives sp-offchain"
"bizinikiwi-panic-handler sp-panic-handler"
"bizinikiwi-phragmen sp-npos-elections"
"bizinikiwi-rpc-primitives sp-rpc"
"bizinikiwi-runtime-interface sp-runtime-interface"
"bizinikiwi-runtime-interface-proc-macro sp-runtime-interface-proc-macro"
"bizinikiwi-runtime-interface-test-wasm sp-runtime-interface-test-wasm"
"bizinikiwi-serializer sp-serializer"
"bizinikiwi-session sp-session"
"sr-api sp-api"
"sr-api-proc-macro sp-api-proc-macro"
"sr-api-test sp-api-test"
"sr-arithmetic sp-arithmetic"
"sr-arithmetic-fuzzer sp-arithmetic-fuzzer"
"sr-io sp-io"
"sr-primitives sp-runtime"
"sr-sandbox sp-sandbox"
"sr-staking-primitives sp-staking"
"sr-std sp-std"
"sr-version sp-version"
"bizinikiwi-state-machine sp-state-machine"
"bizinikiwi-transaction-pool-runtime-api sp-transaction-pool"
"bizinikiwi-trie sp-trie"
"bizinikiwi-wasm-interface sp-wasm-interface"
# # CLIENT
"bizinikiwi-client sc-client"
"bizinikiwi-client-api sc-client-api"
"bizinikiwi-authority-discovery sc-authority-discovery"
"bizinikiwi-basic-authorship sc-basic-authorship"
"bizinikiwi-block-builder sc-block-builder"
"bizinikiwi-chain-spec sc-chain-spec"
"bizinikiwi-chain-spec-derive sc-chain-spec-derive"
"bizinikiwi-cli sc-cli"
"bizinikiwi-consensus-aura sc-consensus-aura"
"bizinikiwi-consensus-babe sc-consensus-babe"
"bizinikiwi-consensus-pow sc-consensus-pow"
"bizinikiwi-consensus-slots sc-consensus-slots"
"bizinikiwi-consensus-uncles sc-consensus-uncles"
"bizinikiwi-client-db sc-client-db"
"bizinikiwi-executor sc-executor"
"bizinikiwi-runtime-test sc-runtime-test"
"bizinikiwi-finality-grandpa sc-finality-grandpa"
"bizinikiwi-keystore sc-keystore"
"bizinikiwi-network sc-network"
"bizinikiwi-offchain sc-offchain"
"bizinikiwi-peerset sc-peerset"
"bizinikiwi-rpc-servers sc-rpc-server"
"bizinikiwi-rpc sc-rpc"
"bizinikiwi-service sc-service"
"bizinikiwi-service-test sc-service-test"
"bizinikiwi-state-db sc-state-db"
"bizinikiwi-telemetry sc-telemetry"
"bizinikiwi-test-primitives sp-test-primitives"
"bizinikiwi-tracing sc-tracing"
);
for rule in "${TO_RENAME[@]}"
do
rename "$rule";
done
@@ -1,12 +1,12 @@
#!/usr/bin/env bash
# set -x
# This script used to manage the deployment of Substrate rustdocs to https://paritytech.github.io/substrate/.
# This script used to manage the deployment of Bizinikiwi rustdocs to https://paritytech.github.io/bizinikiwi/.
# It is no longer used anywhere, and only here for historical/demonstration purposes.
# - With `deploy` sub-command, it will checkout the passed-in branch/tag ref, build the rustdocs
# locally (this takes some time), update the `index.html` index page, and push it to remote
# `gh-pages` branch. So users running this command need to have write access to the remote
# `gh-pages` branch. This sub-command depends on [@substrate/index-tpl-crud](https://www.npmjs.com/package/@substrate/index-tpl-crud)
# `gh-pages` branch. This sub-command depends on [@bizinikiwi/index-tpl-crud](https://www.npmjs.com/package/@bizinikiwi/index-tpl-crud)
# to update the DOM of index.html page.
# - With `remove` sub-command, it will remove the deployed rustdocs from `gh-pages`, and update the
# index.html page as necessary. It may remove the `latest` symbolic link.
@@ -25,12 +25,12 @@
# rustdocs-release.sh remove monthly-2021-10
#
# Dependencies:
# - @substrate/index-tpl-crud - https://www.npmjs.com/package/@substrate/index-tpl-crud
# - @bizinikiwi/index-tpl-crud - https://www.npmjs.com/package/@bizinikiwi/index-tpl-crud
#
# Script setting
# The git repo http URL
REMOTE_REPO="https://github.com/paritytech/substrate.git"
REMOTE_REPO="https://github.com/paritytech/bizinikiwi.git"
TMP_PREFIX="/tmp" # tmp location that the built doc is copied to.
DOC_INDEX_PAGE="sc_service/index.html"
@@ -94,12 +94,12 @@ build_rustdocs() {
upsert_index_page() {
# Check if `index-tpl-crud` exists
which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud
which index-tpl-crud &> /dev/null || yarn global add @bizinikiwi/index-tpl-crud
index-tpl-crud upsert $($1 && echo "-l") ./index.html "$2"
}
rm_index_page() {
which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud
which index-tpl-crud &> /dev/null || yarn global add @bizinikiwi/index-tpl-crud
index-tpl-crud rm ./index.html "$1"
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+48
View File
@@ -0,0 +1,48 @@
# Bizinikiwi
[![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](#LICENSE)
[![GitLab
Status](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/badges/master/pipeline.svg)](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/pipelines)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/contributor/CONTRIBUTING.md)
[![Stack
Exchange](https://img.shields.io/badge/Bizinikiwi-Community%20&%20Support-24CC85?logo=stackexchange)](https://exchange.pezkuwichain.app/)
<p align="center">
<img src="../bizinikiwi/docs/media/sub.gif">
</p>
Bizinikiwi is a next-generation framework for blockchain innovation 🚀.
## Getting Started
Head to [`docs.bizinikiwi.io`](https://github.com/pezkuwichain/docs.pezkuwichain.io) and follow the [installation](https://docs.pezkuwichain.io/install/)
instructions. Then try out one of the [tutorials](https://docs.pezkuwichain.io/tutorials/). Refer to the [Docker
instructions](./docker/README.md) to quickly run Bizinikiwi, Bizinikiwi Node Template, Subkey, or to build a chain spec.
## Community & Support
Join the highly active and supportive community on the [Bizinikiwi Stack Exchange](https://exchange.pezkuwichain.app/)
to ask questions about use and problems you run into using this software. Please do report bugs and [issues
here](https://github.com/pezkuwichain/pezkuwi-sdk/issues) for anything you suspect requires action in the source.
## Contributions & Code of Conduct
Please follow the contributions guidelines as outlined in [`docs/contributor/CONTRIBUTING.md`](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/CONTRIBUTING.md).
In all communications and contributions, this project follows the [Contributor Covenant Code of Conduct](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/CODE_OF_CONDUCT.md).
## Security
The security policy and procedures can be found in
[`docs/contributor/SECURITY.md`](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/SECURITY.md).
## License
- Bizinikiwi Primitives (`pezsp-*`), Frame (`frame-*`) and the pallets (`pallets-*`), binaries (`/bin`) and all other
utilities are licensed under [Apache 2.0](LICENSE-APACHE2). - Bizinikiwi Client (`/client/*` / `pezsc-*`) is licensed under
[GPL v3.0 with a classpath linking exception](LICENSE-GPL3).
The reason for the split-licensing is to ensure that for the vast majority of teams using Bizinikiwi to create
feature-chains, then all changes can be made entirely in Apache2-licensed code, allowing teams full freedom over what
and how they release and giving licensing clarity to commercial teams.
In the interests of the community, we require any deeper improvements made to Bizinikiwi's core logic (e.g. Bizinikiwi's
internal consensus, crypto or database code) to be contributed back so everyone can benefit.
+64
View File
@@ -0,0 +1,64 @@
[package]
name = "node-bench"
version = "0.9.0-dev"
authors.workspace = true
description = "Bizinikiwi node integration benchmarks."
edition.workspace = true
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
homepage.workspace = true
repository.workspace = true
publish = false
[lints]
workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
array-bytes = { workspace = true, default-features = true }
async-trait = { workspace = true }
clap = { features = ["derive"], workspace = true }
derive_more = { features = ["display"], workspace = true }
fs_extra = { workspace = true }
futures = { features = ["thread-pool"], workspace = true }
hash-db = { workspace = true, default-features = true }
kitchensink-runtime = { workspace = true }
kvdb = { workspace = true }
kvdb-rocksdb = { workspace = true }
log = { workspace = true, default-features = true }
node-primitives = { workspace = true, default-features = true }
node-testing = { workspace = true }
parity-db = { workspace = true }
rand = { features = ["small_rng"], workspace = true, default-features = true }
pezsc-basic-authorship = { workspace = true, default-features = true }
pezsc-client-api = { workspace = true, default-features = true }
pezsc-transaction-pool = { workspace = true, default-features = true }
pezsc-transaction-pool-api = { workspace = true, default-features = true }
serde = { workspace = true, default-features = true }
serde_json = { workspace = true, default-features = true }
pezsp-consensus = { workspace = true, default-features = true }
pezsp-core = { workspace = true, default-features = true }
pezsp-inherents = { workspace = true, default-features = true }
pezsp-runtime = { workspace = true, default-features = true }
pezsp-state-machine = { workspace = true, default-features = true }
pezsp-timestamp = { workspace = true }
pezsp-tracing = { workspace = true, default-features = true }
pezsp-trie = { workspace = true, default-features = true }
tempfile = { workspace = true }
[features]
runtime-benchmarks = [
"kitchensink-runtime/runtime-benchmarks",
"node-primitives/runtime-benchmarks",
"node-testing/runtime-benchmarks",
"pezsc-basic-authorship/runtime-benchmarks",
"pezsc-client-api/runtime-benchmarks",
"pezsc-transaction-pool-api/runtime-benchmarks",
"pezsc-transaction-pool/runtime-benchmarks",
"pezsp-consensus/runtime-benchmarks",
"pezsp-inherents/runtime-benchmarks",
"pezsp-runtime/runtime-benchmarks",
"pezsp-state-machine/runtime-benchmarks",
"pezsp-timestamp/runtime-benchmarks",
"pezsp-trie/runtime-benchmarks",
]
+47
View File
@@ -0,0 +1,47 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#[derive(Clone, Copy, Debug, derive_more::Display)]
pub enum SizeType {
#[display(fmt = "empty")]
Empty,
#[display(fmt = "small")]
Small,
#[display(fmt = "medium")]
Medium,
#[display(fmt = "large")]
Large,
#[display(fmt = "full")]
Full,
#[display(fmt = "custom")]
Custom(usize),
}
impl SizeType {
pub fn transactions(&self) -> Option<usize> {
match self {
SizeType::Empty => Some(0),
SizeType::Small => Some(10),
SizeType::Medium => Some(100),
SizeType::Large => Some(500),
SizeType::Full => None,
// Custom SizeType will use the `--transactions` input parameter
SizeType::Custom(val) => Some(*val),
}
}
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -29,13 +29,13 @@ use std::{borrow::Cow, collections::HashMap, pin::Pin, sync::Arc};
use async_trait::async_trait;
use node_primitives::Block;
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes};
use sc_transaction_pool_api::{
use pezsc_transaction_pool_api::{
ImportNotificationStream, PoolStatus, ReadyTransactions, TransactionFor, TransactionSource,
TransactionStatusStreamFor, TxHash, TxInvalidityReportMap,
};
use sp_consensus::{Environment, Proposer};
use sp_inherents::InherentDataProvider;
use sp_runtime::OpaqueExtrinsic;
use pezsp_consensus::{Environment, Proposer};
use pezsp_inherents::InherentDataProvider;
use pezsp_runtime::OpaqueExtrinsic;
use crate::{
common::SizeType,
@@ -120,14 +120,14 @@ impl core::Benchmark for ConstructionBenchmark {
std::thread::park_timeout(std::time::Duration::from_secs(3));
}
let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
let mut proposer_factory = pezsc_basic_authorship::ProposerFactory::new(
context.spawn_handle.clone(),
context.client.clone(),
self.transactions.clone().into(),
None,
None,
);
let timestamp_provider = sp_timestamp::InherentDataProvider::from_system_time();
let timestamp_provider = pezsp_timestamp::InherentDataProvider::from_system_time();
let start = std::time::Instant::now();
@@ -176,7 +176,7 @@ impl From<OpaqueExtrinsic> for PoolTransaction {
}
}
impl sc_transaction_pool_api::InPoolTransaction for PoolTransaction {
impl pezsc_transaction_pool_api::InPoolTransaction for PoolTransaction {
type Transaction = Arc<OpaqueExtrinsic>;
type Hash = node_primitives::Hash;
@@ -226,11 +226,11 @@ impl ReadyTransactions for TransactionsIterator {
}
#[async_trait]
impl sc_transaction_pool_api::TransactionPool for Transactions {
impl pezsc_transaction_pool_api::TransactionPool for Transactions {
type Block = Block;
type Hash = node_primitives::Hash;
type InPoolTransaction = PoolTransaction;
type Error = sc_transaction_pool_api::error::Error;
type Error = pezsc_transaction_pool_api::error::Error;
/// Asynchronously imports a bunch of unverified transactions to the pool.
async fn submit_at(
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -20,7 +20,7 @@ use std::{collections::HashMap, sync::Arc};
use kvdb::KeyValueDB;
use node_primitives::Hash;
use sp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut};
use pezsp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut};
use crate::simple_trie::SimpleTrie;
+134
View File
@@ -0,0 +1,134 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Block import benchmark.
//!
//! This benchmark is expected to measure block import operation of
//! some more or less full block.
//!
//! As we also want to protect against cold-cache attacks, this
//! benchmark should not rely on any caching (except those that
//! DO NOT depend on user input). Thus block generation should be
//! based on randomized operation.
//!
//! This is supposed to be very simple benchmark and is not subject
//! to much configuring - just block full of randomized transactions.
//! It is not supposed to measure runtime modules weight correctness
use std::borrow::Cow;
use node_primitives::Block;
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes};
use pezsc_client_api::backend::Backend;
use crate::{
common::SizeType,
core::{self, Mode, Path},
};
pub struct ImportBenchmarkDescription {
pub key_types: KeyTypes,
pub block_type: BlockType,
pub size: SizeType,
pub database_type: DatabaseType,
}
pub struct ImportBenchmark {
database: BenchDb,
block: Block,
}
impl core::BenchmarkDescription for ImportBenchmarkDescription {
fn path(&self) -> Path {
let mut path = Path::new(&["node", "import"]);
match self.key_types {
KeyTypes::Sr25519 => path.push("sr25519"),
KeyTypes::Ed25519 => path.push("ed25519"),
}
match self.block_type {
BlockType::RandomTransfersKeepAlive => path.push("transfer_keep_alive"),
BlockType::RandomTransfersReaping => path.push("transfer_reaping"),
BlockType::Noop => path.push("noop"),
}
match self.database_type {
DatabaseType::RocksDb => path.push("rocksdb"),
DatabaseType::ParityDb => path.push("paritydb"),
}
path.push(&format!("{}", self.size));
path
}
fn setup(self: Box<Self>) -> Box<dyn core::Benchmark> {
let mut bench_db = BenchDb::with_key_types(self.database_type, 50_000, self.key_types);
let block = bench_db.generate_block(self.block_type.to_content(self.size.transactions()));
Box::new(ImportBenchmark { database: bench_db, block })
}
fn name(&self) -> Cow<'static, str> {
format!(
"Block import ({:?}/{}, {:?} backend)",
self.block_type, self.size, self.database_type,
)
.into()
}
}
impl core::Benchmark for ImportBenchmark {
fn run(&mut self, mode: Mode) -> std::time::Duration {
let mut context = self.database.create_context();
let _ = context
.client
.runtime_version_at(context.client.chain_info().genesis_hash)
.expect("Failed to get runtime version")
.spec_version;
if mode == Mode::Profile {
std::thread::park_timeout(std::time::Duration::from_secs(3));
}
let start = std::time::Instant::now();
context.import_block(self.block.clone());
let elapsed = start.elapsed();
if mode == Mode::Profile {
std::thread::park_timeout(std::time::Duration::from_secs(1));
}
log::info!(
target: "bench-logistics",
"imported block with {} tx, took: {:#?}",
self.block.extrinsics.len(),
elapsed,
);
log::info!(
target: "bench-logistics",
"usage info: {}",
context.backend.usage_info()
.expect("RocksDB backend always provides usage info!"),
);
elapsed
}
}
+186
View File
@@ -0,0 +1,186 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
mod common;
mod construct;
#[macro_use]
mod core;
mod generator;
mod import;
mod simple_trie;
mod state_sizes;
mod tempdb;
mod trie;
mod txpool;
use clap::Parser;
use node_testing::bench::{BlockType, DatabaseType as BenchDataBaseType, KeyTypes};
use crate::{
common::SizeType,
construct::ConstructionBenchmarkDescription,
core::{run_benchmark, Mode as BenchmarkMode},
import::ImportBenchmarkDescription,
tempdb::DatabaseType,
trie::{DatabaseSize, TrieReadBenchmarkDescription, TrieWriteBenchmarkDescription},
txpool::PoolBenchmarkDescription,
};
#[derive(Debug, Parser)]
#[command(name = "node-bench", about = "Node integration benchmarks")]
struct Opt {
/// Show list of all available benchmarks.
///
/// Will output ("name", "path"). Benchmarks can then be filtered by path.
#[arg(short, long)]
list: bool,
/// Machine readable json output.
///
/// This also suppresses all regular output (except to stderr)
#[arg(short, long)]
json: bool,
/// Filter benchmarks.
///
/// Run with `--list` for the hint of what to filter.
filter: Option<String>,
/// Number of transactions for block import with `custom` size.
#[arg(long)]
transactions: Option<usize>,
/// Mode
///
/// "regular" for regular benchmark
///
/// "profile" mode adds pauses between measurable runs,
/// so that actual interval can be selected in the profiler of choice.
#[arg(short, long, default_value = "regular")]
mode: BenchmarkMode,
}
fn main() {
let opt = Opt::parse();
if !opt.json {
pezsp_tracing::try_init_simple();
}
let mut import_benchmarks = Vec::new();
for size in [
SizeType::Empty,
SizeType::Small,
SizeType::Medium,
SizeType::Large,
SizeType::Full,
SizeType::Custom(opt.transactions.unwrap_or(0)),
] {
for block_type in [
BlockType::RandomTransfersKeepAlive,
BlockType::RandomTransfersReaping,
BlockType::Noop,
] {
for database_type in [BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb] {
import_benchmarks.push((size, block_type, database_type));
}
}
}
let benchmarks = matrix!(
(size, block_type, database_type) in import_benchmarks.into_iter() =>
ImportBenchmarkDescription {
key_types: KeyTypes::Sr25519,
size,
block_type,
database_type,
},
(size, db_type) in
[
DatabaseSize::Empty, DatabaseSize::Smallest, DatabaseSize::Small,
DatabaseSize::Medium, DatabaseSize::Large, DatabaseSize::Huge,
]
.iter().flat_map(|size|
[
DatabaseType::RocksDb, DatabaseType::ParityDb
]
.iter().map(move |db_type| (size, db_type)))
=> TrieReadBenchmarkDescription { database_size: *size, database_type: *db_type },
(size, db_type) in
[
DatabaseSize::Empty, DatabaseSize::Smallest, DatabaseSize::Small,
DatabaseSize::Medium, DatabaseSize::Large, DatabaseSize::Huge,
]
.iter().flat_map(|size|
[
DatabaseType::RocksDb, DatabaseType::ParityDb
]
.iter().map(move |db_type| (size, db_type)))
=> TrieWriteBenchmarkDescription { database_size: *size, database_type: *db_type },
ConstructionBenchmarkDescription {
key_types: KeyTypes::Sr25519,
block_type: BlockType::RandomTransfersKeepAlive,
size: SizeType::Medium,
database_type: BenchDataBaseType::RocksDb,
},
ConstructionBenchmarkDescription {
key_types: KeyTypes::Sr25519,
block_type: BlockType::RandomTransfersKeepAlive,
size: SizeType::Large,
database_type: BenchDataBaseType::RocksDb,
},
PoolBenchmarkDescription { database_type: BenchDataBaseType::RocksDb },
);
if opt.list {
println!("Available benchmarks:");
if let Some(filter) = opt.filter.as_ref() {
println!("\t(filtered by \"{}\")", filter);
}
for benchmark in benchmarks.iter() {
if opt.filter.as_ref().map(|f| benchmark.path().has(f)).unwrap_or(true) {
println!("{}: {}", benchmark.name(), benchmark.path().full())
}
}
return;
}
let mut results = Vec::new();
for benchmark in benchmarks {
if opt.filter.as_ref().map(|f| benchmark.path().has(f)).unwrap_or(true) {
log::info!("Starting {}", benchmark.name());
let result = run_benchmark(benchmark, opt.mode);
log::info!("{}", result);
results.push(result);
}
}
if results.is_empty() {
eprintln!("No benchmark was found for query");
std::process::exit(1);
}
if opt.json {
let json_result: String =
serde_json::to_string(&results).expect("Failed to construct json");
println!("{}", json_result);
}
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -21,9 +21,9 @@ use std::{collections::HashMap, sync::Arc};
use hash_db::{AsHashDB, HashDB, Hasher as _, Prefix};
use kvdb::KeyValueDB;
use node_primitives::Hash;
use sp_trie::DBValue;
use pezsp_trie::DBValue;
pub type Hasher = sp_core::Blake2Hasher;
pub type Hasher = pezsp_core::Blake2Hasher;
/// Immutable generated trie database with root.
pub struct SimpleTrie<'a> {
@@ -43,7 +43,7 @@ impl<'a> AsHashDB<Hasher, DBValue> for SimpleTrie<'a> {
impl<'a> HashDB<Hasher, DBValue> for SimpleTrie<'a> {
fn get(&self, key: &Hash, prefix: Prefix) -> Option<DBValue> {
let key = sp_trie::prefixed_key::<Hasher>(key, prefix);
let key = pezsp_trie::prefixed_key::<Hasher>(key, prefix);
if let Some(value) = self.overlay.get(&key) {
return value.clone();
}
@@ -61,12 +61,12 @@ impl<'a> HashDB<Hasher, DBValue> for SimpleTrie<'a> {
}
fn emplace(&mut self, key: Hash, prefix: Prefix, value: DBValue) {
let key = sp_trie::prefixed_key::<Hasher>(&key, prefix);
let key = pezsp_trie::prefixed_key::<Hasher>(&key, prefix);
self.overlay.insert(key, Some(value));
}
fn remove(&mut self, key: &Hash, prefix: Prefix) {
let key = sp_trie::prefixed_key::<Hasher>(key, prefix);
let key = pezsp_trie::prefixed_key::<Hasher>(key, prefix);
self.overlay.insert(key, None);
}
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -21,8 +21,8 @@
use hash_db::Prefix;
use kvdb::KeyValueDB;
use rand::Rng;
use sp_state_machine::Backend as _;
use sp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut as _};
use pezsp_state_machine::Backend as _;
use pezsp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut as _};
use std::{
borrow::Cow,
collections::HashMap,
@@ -167,9 +167,9 @@ impl core::BenchmarkDescription for TrieReadBenchmarkDescription {
struct Storage(Arc<dyn KeyValueDB>);
impl sp_state_machine::Storage<sp_core::Blake2Hasher> for Storage {
impl pezsp_state_machine::Storage<pezsp_core::Blake2Hasher> for Storage {
fn get(&self, key: &Hash, prefix: Prefix) -> Result<Option<Vec<u8>>, String> {
let key = sp_trie::prefixed_key::<sp_core::Blake2Hasher>(key, prefix);
let key = pezsp_trie::prefixed_key::<pezsp_core::Blake2Hasher>(key, prefix);
self.0.get(0, &key).map_err(|e| format!("Database backend error: {:?}", e))
}
}
@@ -178,10 +178,10 @@ impl core::Benchmark for TrieReadBenchmark {
fn run(&mut self, mode: Mode) -> std::time::Duration {
let mut db = self.database.clone();
let storage: Arc<dyn sp_state_machine::Storage<sp_core::Blake2Hasher>> =
let storage: Arc<dyn pezsp_state_machine::Storage<pezsp_core::Blake2Hasher>> =
Arc::new(Storage(db.open(self.database_type)));
let trie_backend = sp_state_machine::TrieBackendBuilder::new(storage, self.root).build();
let trie_backend = pezsp_state_machine::TrieBackendBuilder::new(storage, self.root).build();
for (warmup_key, warmup_value) in self.warmup_keys.iter() {
let value = trie_backend
.storage(&warmup_key[..])
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -25,8 +25,8 @@ use std::borrow::Cow;
use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes};
use sc_transaction_pool::BasicPool;
use sc_transaction_pool_api::{TransactionPool, TransactionSource};
use pezsc_transaction_pool::BasicPool;
use pezsc_transaction_pool_api::{TransactionPool, TransactionSource};
use crate::core::{self, Mode, Path};
@@ -69,7 +69,7 @@ impl core::Benchmark for PoolBenchmark {
std::thread::park_timeout(std::time::Duration::from_secs(3));
}
let executor = sp_core::testing::TaskExecutor::new();
let executor = pezsp_core::testing::TaskExecutor::new();
let txpool = BasicPool::new_full(
Default::default(),
true.into(),
+213
View File
@@ -0,0 +1,213 @@
[package]
name = "pezstaging-node-cli"
version = "3.0.0-dev"
authors.workspace = true
description = "Generic Bizinikiwi node implementation in Rust."
build = "build.rs"
edition.workspace = true
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
default-run = "bizinikiwi-node"
homepage.workspace = true
repository.workspace = true
publish = false
[lints]
workspace = true
[package.metadata.wasm-pack.profile.release]
# `wasm-opt` has some problems on linux, see
# https://github.com/rustwasm/wasm-pack/issues/781 etc.
wasm-opt = false
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[badges]
maintenance = { status = "actively-developed" }
is-it-maintained-issue-resolution = { repository = "pezkuwichain/pezkuwi-sdk" }
is-it-maintained-open-issues = { repository = "pezkuwichain/pezkuwi-sdk" }
[lib]
crate-type = ["cdylib", "rlib"]
[[bin]]
name = "bizinikiwi-node"
path = "bin/main.rs"
required-features = ["cli"]
[[bench]]
name = "transaction_pool"
harness = false
[[bench]]
name = "block_production"
harness = false
[[bench]]
name = "executor"
harness = false
[dependencies]
# third-party dependencies
array-bytes = { workspace = true, default-features = true }
clap = { features = ["derive"], optional = true, workspace = true }
codec = { workspace = true, default-features = true }
futures = { workspace = true }
jsonrpsee = { features = ["server"], workspace = true }
log = { workspace = true, default-features = true }
rand = { workspace = true, default-features = true }
serde = { features = ["derive"], workspace = true, default-features = true }
serde_json = { workspace = true, default-features = true }
subxt-signer = { workspace = true, features = ["unstable-eth"] }
# The Pezkuwi-SDK:
pezkuwi-sdk = { features = [
"fork-tree",
"pezframe-benchmarking-cli",
"frame-remote-externalities",
"pezframe-support-procedural-tools",
"generate-bags",
"mmr-gadget",
"mmr-rpc",
"pezpallet-transaction-payment-rpc",
"pezsc-allocator",
"pezsc-authority-discovery",
"pezsc-basic-authorship",
"pezsc-block-builder",
"pezsc-chain-spec",
"pezsc-cli",
"pezsc-client-api",
"pezsc-client-db",
"pezsc-consensus",
"pezsc-consensus-aura",
"pezsc-consensus-babe",
"pezsc-consensus-babe-rpc",
"pezsc-consensus-beefy",
"pezsc-consensus-beefy-rpc",
"pezsc-consensus-epochs",
"pezsc-consensus-grandpa",
"pezsc-consensus-grandpa-rpc",
"pezsc-consensus-manual-seal",
"pezsc-consensus-pow",
"pezsc-consensus-slots",
"pezsc-executor",
"pezsc-executor-common",
"pezsc-executor-polkavm",
"pezsc-executor-wasmtime",
"pezsc-informant",
"pezsc-keystore",
"pezsc-mixnet",
"pezsc-network",
"pezsc-network-common",
"pezsc-network-gossip",
"pezsc-network-light",
"pezsc-network-statement",
"pezsc-network-sync",
"pezsc-network-transactions",
"pezsc-network-types",
"pezsc-offchain",
"pezsc-proposer-metrics",
"pezsc-rpc",
"pezsc-rpc-api",
"pezsc-rpc-server",
"pezsc-rpc-spec-v2",
"pezsc-service",
"pezsc-state-db",
"pezsc-statement-store",
"pezsc-storage-monitor",
"pezsc-sync-state-rpc",
"pezsc-sysinfo",
"pezsc-telemetry",
"pezsc-tracing",
"pezsc-transaction-pool",
"pezsc-transaction-pool-api",
"pezsc-utils",
"pezsp-blockchain",
"pezsp-consensus",
"pezsp-core-hashing",
"pezsp-core-hashing-proc-macro",
"pezsp-database",
"pezsp-maybe-compressed-blob",
"pezsp-panic-handler",
"pezsp-rpc",
"pezstaging-chain-spec-builder",
"pezstaging-node-inspect",
"pezstaging-tracking-allocator",
"std",
"subkey",
"bizinikiwi-build-script-utils",
"bizinikiwi-frame-rpc-support",
"bizinikiwi-frame-rpc-system",
"bizinikiwi-prometheus-endpoint",
"bizinikiwi-rpc-client",
"bizinikiwi-state-trie-migration-rpc",
"bizinikiwi-wasm-builder",
"tracing-gum",
], workspace = true, default-features = true }
# Shared code between the staging node and kitchensink runtime:
kitchensink-runtime = { workspace = true }
node-inspect = { optional = true, workspace = true, default-features = true }
node-primitives = { workspace = true, default-features = true }
node-rpc = { workspace = true }
[dev-dependencies]
assert_cmd = { workspace = true }
criterion = { features = [
"async_tokio",
], workspace = true, default-features = true }
nix = { features = ["signal"], workspace = true }
pretty_assertions.workspace = true
regex = { workspace = true }
scale-info = { features = [
"derive",
"serde",
], workspace = true, default-features = true }
soketto = { workspace = true }
pezsp-keyring = { workspace = true }
tempfile = { workspace = true }
tokio = { features = [
"macros",
"parking_lot",
"time",
], workspace = true, default-features = true }
tokio-util = { features = ["compat"], workspace = true }
wat = { workspace = true }
# These testing-only dependencies are not exported by the Pezkuwi-SDK crate:
node-testing = { workspace = true }
pezsc-service-test = { workspace = true }
bizinikiwi-cli-test-utils = { workspace = true }
[build-dependencies]
clap = { optional = true, workspace = true }
clap_complete = { optional = true, workspace = true }
node-inspect = { optional = true, workspace = true, default-features = true }
pezkuwi-sdk = { features = [
"pezframe-benchmarking-cli",
"pezsc-cli",
"pezsc-storage-monitor",
"bizinikiwi-build-script-utils",
], optional = true, workspace = true, default-features = true }
[features]
default = ["cli"]
cli = ["clap", "clap_complete", "node-inspect", "pezkuwi-sdk"]
runtime-benchmarks = [
"kitchensink-runtime/runtime-benchmarks",
"node-inspect?/runtime-benchmarks",
"node-primitives/runtime-benchmarks",
"node-rpc/runtime-benchmarks",
"node-testing/runtime-benchmarks",
"pezkuwi-sdk/runtime-benchmarks",
"pezsc-service-test/runtime-benchmarks",
"pezsp-keyring/runtime-benchmarks",
"bizinikiwi-cli-test-utils/runtime-benchmarks",
]
try-runtime = [
"kitchensink-runtime/try-runtime",
"pezkuwi-sdk/try-runtime",
"bizinikiwi-cli-test-utils/try-runtime",
]
@@ -0,0 +1,256 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use pezkuwi_sdk::*;
use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput};
use kitchensink_runtime::{constants::currency::*, BalancesCall};
use node_cli::service::{create_extrinsic, FullClient};
use pezkuwi_sdk::pezsc_service::config::{ExecutorConfiguration, RpcConfiguration};
use pezsc_block_builder::{BlockBuilderBuilder, BuiltBlock};
use pezsc_consensus::{
block_import::{BlockImportParams, ForkChoiceStrategy},
BlockImport, StateAction,
};
use pezsc_service::{
config::{
BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig,
PruningMode, RpcBatchRequestConfig, WasmExecutionMethod, WasmtimeInstantiationStrategy,
},
BasePath, Configuration, Role,
};
use pezsp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed};
use pezsp_consensus::BlockOrigin;
use pezsp_keyring::Sr25519Keyring;
use pezsp_runtime::{
generic,
transaction_validity::{InvalidTransaction, TransactionValidityError},
AccountId32, MultiAddress, OpaqueExtrinsic,
};
use pezstaging_node_cli as node_cli;
use tokio::runtime::Handle;
fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
let base_path = BasePath::new_temp_dir()
.expect("getting the base path of a temporary path doesn't fail; qed");
let root = base_path.path().to_path_buf();
let network_config = NetworkConfiguration::new(
Sr25519Keyring::Alice.to_seed(),
"network/test/0.1",
Default::default(),
None,
);
let spec = Box::new(node_cli::chain_spec::development_config());
let config = Configuration {
impl_name: "BenchmarkImpl".into(),
impl_version: "1.0".into(),
// We don't use the authority role since that would start producing blocks
// in the background which would mess with our benchmark.
role: Role::Full,
tokio_handle,
transaction_pool: Default::default(),
network: network_config,
keystore: KeystoreConfig::InMemory,
database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 },
trie_cache_maximum_size: Some(64 * 1024 * 1024),
warm_up_trie_cache: None,
state_pruning: Some(PruningMode::ArchiveAll),
blocks_pruning: BlocksPruning::KeepAll,
chain_spec: spec,
executor: ExecutorConfiguration {
wasm_method: WasmExecutionMethod::Compiled {
instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite,
},
..ExecutorConfiguration::default()
},
rpc: RpcConfiguration {
addr: None,
max_connections: Default::default(),
cors: None,
methods: Default::default(),
max_request_size: Default::default(),
max_response_size: Default::default(),
id_provider: Default::default(),
max_subs_per_conn: Default::default(),
port: 9944,
message_buffer_capacity: Default::default(),
batch_config: RpcBatchRequestConfig::Unlimited,
rate_limit: None,
rate_limit_whitelisted_ips: Default::default(),
rate_limit_trust_proxy_headers: Default::default(),
request_logger_limit: 1024,
},
prometheus_config: None,
telemetry_endpoints: None,
offchain_worker: OffchainWorkerConfig { enabled: true, indexing_enabled: false },
force_authoring: false,
disable_grandpa: false,
dev_key_seed: Some(Sr25519Keyring::Alice.to_seed()),
tracing_targets: None,
tracing_receiver: Default::default(),
announce_block: true,
data_path: base_path.path().into(),
base_path,
wasm_runtime_overrides: None,
};
node_cli::service::new_full_base::<pezsc_network::NetworkWorker<_, _>>(
config,
None,
false,
|_, _| (),
)
.expect("creating a full node doesn't fail")
}
fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic {
let utx: kitchensink_runtime::UncheckedExtrinsic = generic::UncheckedExtrinsic::new_bare(
kitchensink_runtime::RuntimeCall::Timestamp(pezpallet_timestamp::Call::set { now }),
)
.into();
utx.into()
}
fn import_block(client: &FullClient, built: BuiltBlock<node_primitives::Block>) {
let mut params = BlockImportParams::new(BlockOrigin::File, built.block.header);
params.state_action =
StateAction::ApplyChanges(pezsc_consensus::StorageChanges::Changes(built.storage_changes));
params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
futures::executor::block_on(client.import_block(params))
.expect("importing a block doesn't fail");
}
fn prepare_benchmark(client: &FullClient) -> (usize, Vec<OpaqueExtrinsic>) {
const MINIMUM_PERIOD_FOR_BLOCKS: u64 = 1500;
let mut max_transfer_count = 0;
let mut extrinsics = Vec::new();
let mut block_builder = BlockBuilderBuilder::new(client)
.on_parent_block(client.chain_info().best_hash)
.with_parent_block_number(client.chain_info().best_number)
.build()
.unwrap();
// Every block needs one timestamp extrinsic.
let extrinsic_set_time = extrinsic_set_time(1 + MINIMUM_PERIOD_FOR_BLOCKS);
block_builder.push(extrinsic_set_time.clone()).unwrap();
extrinsics.push(extrinsic_set_time);
// Creating those is surprisingly costly, so let's only do it once and later just `clone` them.
let src = Sr25519Keyring::Alice.pair();
let dst: MultiAddress<AccountId32, u32> = Sr25519Keyring::Bob.to_account_id().into();
// Add as many transfer extrinsics as possible into a single block.
for nonce in 0.. {
let extrinsic: OpaqueExtrinsic = create_extrinsic(
client,
src.clone(),
BalancesCall::transfer_allow_death { dest: dst.clone(), value: 1 * DOLLARS },
Some(nonce),
)
.into();
match block_builder.push(extrinsic.clone()) {
Ok(_) => {},
Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid(
InvalidTransaction::ExhaustsResources,
)))) => break,
Err(error) => panic!("{}", error),
}
extrinsics.push(extrinsic);
max_transfer_count += 1;
}
(max_transfer_count, extrinsics)
}
fn block_production(c: &mut Criterion) {
pezsp_tracing::try_init_simple();
let runtime = tokio::runtime::Runtime::new().expect("creating tokio runtime doesn't fail; qed");
let tokio_handle = runtime.handle().clone();
let node = new_node(tokio_handle.clone());
let client = &*node.client;
// Building the very first block is around ~30x slower than any subsequent one,
// so let's make sure it's built and imported before we benchmark anything.
let mut block_builder = BlockBuilderBuilder::new(client)
.on_parent_block(client.chain_info().best_hash)
.with_parent_block_number(client.chain_info().best_number)
.build()
.unwrap();
block_builder.push(extrinsic_set_time(1)).unwrap();
import_block(client, block_builder.build().unwrap());
let (max_transfer_count, extrinsics) = prepare_benchmark(&client);
log::info!("Maximum transfer count: {}", max_transfer_count);
let mut group = c.benchmark_group("Block production");
group.sample_size(10);
group.throughput(Throughput::Elements(max_transfer_count as u64));
let chain = client.chain_info();
let best_hash = chain.best_hash;
let best_number = chain.best_number;
group.bench_function(format!("{} transfers (no proof)", max_transfer_count), |b| {
b.iter_batched(
|| extrinsics.clone(),
|extrinsics| {
let mut block_builder = BlockBuilderBuilder::new(client)
.on_parent_block(best_hash)
.with_parent_block_number(best_number)
.build()
.unwrap();
for extrinsic in extrinsics {
block_builder.push(extrinsic).unwrap();
}
block_builder.build().unwrap()
},
BatchSize::SmallInput,
)
});
group.bench_function(format!("{} transfers (with proof)", max_transfer_count), |b| {
b.iter_batched(
|| extrinsics.clone(),
|extrinsics| {
let mut block_builder = BlockBuilderBuilder::new(client)
.on_parent_block(best_hash)
.with_parent_block_number(best_number)
.build()
.unwrap();
for extrinsic in extrinsics {
block_builder.push(extrinsic).unwrap();
}
block_builder.build().unwrap()
},
BatchSize::SmallInput,
)
});
}
criterion_group!(benches, block_production);
criterion_main!(benches);
+206
View File
@@ -0,0 +1,206 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use pezkuwi_sdk::*;
use codec::{Decode, Encode};
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use pezframe_support::Hashable;
use kitchensink_runtime::{
constants::currency::*, Block, BuildStorage, CheckedExtrinsic, Header, RuntimeCall,
RuntimeGenesisConfig, UncheckedExtrinsic,
};
use node_primitives::{BlockNumber, Hash};
use node_testing::keyring::*;
use pezsc_executor::{Externalities, RuntimeVersionOf};
use pezsp_core::{
storage::well_known_keys,
traits::{CallContext, CodeExecutor, RuntimeCode},
};
use pezsp_runtime::{generic::ExtrinsicFormat, traits::BlakeTwo256};
use pezsp_state_machine::TestExternalities as CoreTestExternalities;
use pezstaging_node_cli::service::RuntimeExecutor;
criterion_group!(benches, bench_execute_block);
criterion_main!(benches);
/// The wasm runtime code.
pub fn compact_code_unwrap() -> &'static [u8] {
kitchensink_runtime::WASM_BINARY.expect(
"Development wasm binary is not available. Testing is only supported with the flag \
disabled.",
)
}
const GENESIS_HASH: [u8; 32] = [69u8; 32];
const TRANSACTION_VERSION: u32 = kitchensink_runtime::VERSION.transaction_version;
const SPEC_VERSION: u32 = kitchensink_runtime::VERSION.spec_version;
const HEAP_PAGES: u64 = 20;
type TestExternalities<H> = CoreTestExternalities<H>;
fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH, None)
}
fn new_test_ext(genesis_config: &RuntimeGenesisConfig) -> TestExternalities<BlakeTwo256> {
let mut test_ext = TestExternalities::new_with_code(
compact_code_unwrap(),
genesis_config.build_storage().unwrap(),
);
test_ext
.ext()
.place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(HEAP_PAGES.encode()));
test_ext
}
fn construct_block<E: Externalities>(
executor: &RuntimeExecutor,
ext: &mut E,
number: BlockNumber,
parent_hash: Hash,
extrinsics: Vec<CheckedExtrinsic>,
) -> (Vec<u8>, Hash) {
use pezsp_trie::{LayoutV0, TrieConfiguration};
// sign extrinsics.
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
// calculate the header fields that we can.
let extrinsics_root =
LayoutV0::<BlakeTwo256>::ordered_trie_root(extrinsics.iter().map(Encode::encode))
.to_fixed_bytes()
.into();
let header = Header {
parent_hash,
number,
extrinsics_root,
state_root: Default::default(),
digest: Default::default(),
};
let runtime_code = RuntimeCode {
code_fetcher: &pezsp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()),
hash: vec![1, 2, 3],
heap_pages: None,
};
// execute the block to get the real header.
executor
.call(ext, &runtime_code, "Core_initialize_block", &header.encode(), CallContext::Offchain)
.0
.unwrap();
for i in extrinsics.iter() {
executor
.call(
ext,
&runtime_code,
"BlockBuilder_apply_extrinsic",
&i.encode(),
CallContext::Offchain,
)
.0
.unwrap();
}
let header = Header::decode(
&mut &executor
.call(
ext,
&runtime_code,
"BlockBuilder_finalize_block",
&[0u8; 0],
CallContext::Offchain,
)
.0
.unwrap()[..],
)
.unwrap();
let hash = header.blake2_256();
(Block { header, extrinsics }.encode(), hash.into())
}
fn test_blocks(
genesis_config: &RuntimeGenesisConfig,
executor: &RuntimeExecutor,
) -> Vec<(Vec<u8>, Hash)> {
let mut test_ext = new_test_ext(genesis_config);
let mut block1_extrinsics = vec![CheckedExtrinsic {
format: ExtrinsicFormat::Bare,
function: RuntimeCall::Timestamp(pezpallet_timestamp::Call::set { now: 0 }),
}];
block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic {
format: ExtrinsicFormat::Signed(alice(), tx_ext(i, 0)),
function: RuntimeCall::Balances(pezpallet_balances::Call::transfer_allow_death {
dest: bob().into(),
value: 1 * DOLLARS,
}),
}));
let block1 =
construct_block(executor, &mut test_ext.ext(), 1, GENESIS_HASH.into(), block1_extrinsics);
vec![block1]
}
fn bench_execute_block(c: &mut Criterion) {
let mut group = c.benchmark_group("execute blocks");
group.bench_function("wasm", |b| {
let genesis_config = node_testing::genesis::config();
let executor = RuntimeExecutor::builder().build();
let runtime_code = RuntimeCode {
code_fetcher: &pezsp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()),
hash: vec![1, 2, 3],
heap_pages: None,
};
// Get the runtime version to initialize the runtimes cache.
{
let mut test_ext = new_test_ext(&genesis_config);
executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap();
}
let blocks = test_blocks(&genesis_config, &executor);
b.iter_batched_ref(
|| new_test_ext(&genesis_config),
|test_ext| {
for block in blocks.iter() {
executor
.call(
&mut test_ext.ext(),
&runtime_code,
"Core_execute_block",
&block.0,
CallContext::Offchain,
)
.0
.unwrap();
}
},
BatchSize::LargeInput,
);
});
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -22,22 +22,22 @@ use kitchensink_runtime::{constants::currency::*, BalancesCall, SudoCall};
use node_cli::service::{create_extrinsic, fetch_nonce, FullClient, TransactionPool};
use node_primitives::AccountId;
use pezkuwi_sdk::{
sc_service::config::{ExecutorConfiguration, RpcConfiguration},
sc_transaction_pool_api::TransactionPool as _,
pezsc_service::config::{ExecutorConfiguration, RpcConfiguration},
pezsc_transaction_pool_api::TransactionPool as _,
*,
};
use sc_service::{
use pezsc_service::{
config::{
BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig,
PruningMode, RpcBatchRequestConfig, TransactionPoolOptions,
},
BasePath, Configuration, Role,
};
use sc_transaction_pool_api::{TransactionSource, TransactionStatus};
use sp_core::{crypto::Pair, sr25519};
use sp_keyring::Sr25519Keyring;
use sp_runtime::OpaqueExtrinsic;
use staging_node_cli as node_cli;
use pezsc_transaction_pool_api::{TransactionSource, TransactionStatus};
use pezsp_core::{crypto::Pair, sr25519};
use pezsp_keyring::Sr25519Keyring;
use pezsp_runtime::OpaqueExtrinsic;
use pezstaging_node_cli as node_cli;
use tokio::runtime::Handle;
fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
@@ -100,7 +100,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
};
tokio_handle.block_on(async move {
node_cli::service::new_full_base::<sc_network::NetworkWorker<_, _>>(
node_cli::service::new_full_base::<pezsc_network::NetworkWorker<_, _>>(
config,
None,
false,
@@ -217,7 +217,7 @@ async fn submit_tx_and_wait_for_inclusion(
}
fn transaction_pool_benchmarks(c: &mut Criterion) {
sp_tracing::try_init_simple();
pezsp_tracing::try_init_simple();
let runtime = tokio::runtime::Runtime::new().expect("Creates tokio runtime");
let tokio_handle = runtime.handle().clone();
+28
View File
@@ -0,0 +1,28 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Bizinikiwi Node CLI
#![warn(missing_docs)]
use pezkuwi_sdk::*;
use pezstaging_node_cli as node_cli;
fn main() -> pezsc_cli::Result<()> {
node_cli::run()
}
+68
View File
@@ -0,0 +1,68 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
fn main() {
#[cfg(feature = "cli")]
cli::main();
}
#[cfg(feature = "cli")]
mod cli {
include!("src/cli.rs");
use clap::{CommandFactory, ValueEnum};
use clap_complete::{generate_to, Shell};
use pezkuwi_sdk::bizinikiwi_build_script_utils::{
generate_cargo_keys, rerun_if_git_head_changed,
};
use std::{env, fs, path::Path};
pub fn main() {
build_shell_completion();
generate_cargo_keys();
rerun_if_git_head_changed();
}
/// Build shell completion scripts for all known shells.
fn build_shell_completion() {
for shell in Shell::value_variants() {
build_completion(shell);
}
}
/// Build the shell auto-completion for a given Shell.
fn build_completion(shell: &Shell) {
let outdir = match env::var_os("OUT_DIR") {
None => return,
Some(dir) => dir,
};
let path = Path::new(&outdir)
.parent()
.unwrap()
.parent()
.unwrap()
.parent()
.unwrap()
.join("completion-scripts");
fs::create_dir(&path).ok();
let _ = generate_to(*shell, &mut Cli::command(), "bizinikiwi-node", &path);
}
}
@@ -0,0 +1,34 @@
# Shell completion
The Bizinikiwi cli command supports shell auto-completion. For this to work, you will need to run the
completion script matching your build and system.
Assuming you built a release version using `cargo build --release` and use `bash` run the following:
`source target/release/completion-scripts/bizinikiwi.bash`
You can find completion scripts for:
- bash
- fish
- zsh
- elvish
- powershell
To make this change persistent, you can proceed as follows:
```shell
COMPL_DIR=$HOME/.completion
mkdir -p $COMPL_DIR
cp -f target/release/completion-scripts/bizinikiwi.bash $COMPL_DIR/
echo "source $COMPL_DIR/bizinikiwi.bash" >> $HOME/.bash_profile
source $HOME/.bash_profile
```
When you build a new version of Bizinikiwi, the following will ensure your auto-completion script matches the current binary:
```shell
COMPL_DIR=$HOME/.completion
mkdir -p $COMPL_DIR
cp -f target/release/completion-scripts/bizinikiwi.bash $COMPL_DIR/
source $HOME/.bash_profile
```
+124
View File
@@ -0,0 +1,124 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Setup code for [`super::command`] which would otherwise bloat that module.
//!
//! Should only be used for benchmarking as it may break in other contexts.
use crate::service::{create_extrinsic, FullClient};
use pezkuwi_sdk::*;
use kitchensink_runtime::{BalancesCall, SystemCall};
use node_primitives::{AccountId, Balance};
use pezsc_cli::Result;
use pezsp_inherents::{InherentData, InherentDataProvider};
use pezsp_keyring::Sr25519Keyring;
use pezsp_runtime::OpaqueExtrinsic;
use std::{sync::Arc, time::Duration};
/// Generates `System::Remark` extrinsics for the benchmarks.
///
/// Note: Should only be used for benchmarking.
pub struct RemarkBuilder {
client: Arc<FullClient>,
}
impl RemarkBuilder {
/// Creates a new [`Self`] from the given client.
pub fn new(client: Arc<FullClient>) -> Self {
Self { client }
}
}
impl pezframe_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder {
fn pallet(&self) -> &str {
"system"
}
fn extrinsic(&self) -> &str {
"remark"
}
fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
let acc = Sr25519Keyring::Bob.pair();
let extrinsic: OpaqueExtrinsic = create_extrinsic(
self.client.as_ref(),
acc,
SystemCall::remark { remark: vec![] },
Some(nonce),
)
.into();
Ok(extrinsic)
}
}
/// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks.
///
/// Note: Should only be used for benchmarking.
pub struct TransferKeepAliveBuilder {
client: Arc<FullClient>,
dest: AccountId,
value: Balance,
}
impl TransferKeepAliveBuilder {
/// Creates a new [`Self`] from the given client.
pub fn new(client: Arc<FullClient>, dest: AccountId, value: Balance) -> Self {
Self { client, dest, value }
}
}
impl pezframe_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder {
fn pallet(&self) -> &str {
"balances"
}
fn extrinsic(&self) -> &str {
"transfer_keep_alive"
}
fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
let acc = Sr25519Keyring::Bob.pair();
let extrinsic: OpaqueExtrinsic = create_extrinsic(
self.client.as_ref(),
acc,
BalancesCall::transfer_keep_alive {
dest: self.dest.clone().into(),
value: self.value.into(),
},
Some(nonce),
)
.into();
Ok(extrinsic)
}
}
/// Generates inherent data for the `benchmark overhead` command.
pub fn inherent_benchmark_data() -> Result<InherentData> {
let mut inherent_data = InherentData::new();
let d = Duration::from_millis(0);
let timestamp = pezsp_timestamp::InherentDataProvider::new(d.into());
futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data))
.map_err(|e| format!("creating inherent data: {:?}", e))?;
Ok(inherent_data)
}
+507
View File
@@ -0,0 +1,507 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Bizinikiwi chain configurations.
use pezkuwi_sdk::*;
use crate::chain_spec::pezsc_service::Properties;
use kitchensink_runtime::{
genesis_config_presets::{Staker, ENDOWMENT, STASH},
wasm_binary_unwrap, Block, MaxNominations, StakerStatus,
};
use pezpallet_im_online::sr25519::AuthorityId as ImOnlineId;
use pezpallet_revive::is_eth_derived;
use pezsc_chain_spec::ChainSpecExtension;
use pezsc_service::ChainType;
use pezsc_telemetry::TelemetryEndpoints;
use serde::{Deserialize, Serialize};
use pezsp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use pezsp_consensus_babe::AuthorityId as BabeId;
use pezsp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId;
use pezsp_consensus_grandpa::AuthorityId as GrandpaId;
use pezsp_core::crypto::UncheckedInto;
use pezsp_mixnet::types::AuthorityId as MixnetId;
pub use kitchensink_runtime::RuntimeGenesisConfig;
pub use node_primitives::{AccountId, Balance, Signature};
const STAGING_TELEMETRY_URL: &str = "wss://telemetry.pezkuwichain.io/submit/";
/// Node `ChainSpec` extensions.
///
/// Additional parameters for some Bizinikiwi core modules,
/// customizable from the chain spec.
#[derive(Default, Clone, Serialize, Deserialize, ChainSpecExtension)]
#[serde(rename_all = "camelCase")]
pub struct Extensions {
/// Block numbers with known hashes.
pub fork_blocks: pezsc_client_api::ForkBlocks<Block>,
/// Known bad block hashes.
pub bad_blocks: pezsc_client_api::BadBlocks<Block>,
/// The light sync state extension used by the sync-state rpc.
pub light_sync_state: pezsc_sync_state_rpc::LightSyncStateExtension,
}
/// Specialized `ChainSpec`.
pub type ChainSpec = pezsc_service::GenericChainSpec<Extensions>;
/// Flaming Fir testnet generator
pub fn flaming_fir_config() -> Result<ChainSpec, String> {
ChainSpec::from_json_bytes(&include_bytes!("../res/flaming-fir.json")[..])
}
fn configure_accounts_for_staging_testnet() -> (
Vec<(
AccountId,
AccountId,
GrandpaId,
BabeId,
ImOnlineId,
AuthorityDiscoveryId,
MixnetId,
BeefyId,
)>,
AccountId,
Vec<AccountId>,
) {
#[rustfmt::skip]
// stash, controller, session-key, beefy id
// generated with secret:
// for i in 1 2 3 4 ; do for j in stash controller; do subkey inspect "$secret"/fir/$j/$i; done; done
//
// and
//
// for i in 1 2 3 4 ; do for j in session; do subkey inspect --scheme ed25519 "$secret"//fir//$j//$i; done; done
//
// and
//
// for i in 1 2 3 4 ; do for j in session; do subkey inspect --scheme ecdsa "$secret"//fir//$j//$i; done; done
let initial_authorities: Vec<(
AccountId,
AccountId,
GrandpaId,
BabeId,
ImOnlineId,
AuthorityDiscoveryId,
MixnetId,
BeefyId,
)> = vec![
(
// 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy
array_bytes::hex_n_into_unchecked("9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"),
// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
array_bytes::hex_n_into_unchecked("781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"),
// 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC
array_bytes::hex2array_unchecked("9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332")
.unchecked_into(),
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106")
.unchecked_into(),
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106")
.unchecked_into(),
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106")
.unchecked_into(),
// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106")
.unchecked_into(),
// 5DMLFcDdLLQbw696YfHaWBpQR99HwR456ycSCfr6L7KXGYK8
array_bytes::hex2array_unchecked("035560fafa241739869360aa4b32bc98953172ceb41a19c6cc1a27962fb3d1ecec")
.unchecked_into(),
),
(
// 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2
array_bytes::hex_n_into_unchecked("68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"),
// 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF
array_bytes::hex_n_into_unchecked("c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"),
// 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE
array_bytes::hex2array_unchecked("7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f")
.unchecked_into(),
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e")
.unchecked_into(),
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e")
.unchecked_into(),
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e")
.unchecked_into(),
// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e")
.unchecked_into(),
// 5FYk11kNtB4178wLKJ2RNoUzzcjgRUciFe3SJDVZXhqX4dzG
array_bytes::hex2array_unchecked("02da1ab255ed888ee3e19b73d335fc13160b3eb10456c2d17c6a8ea7de403d2445")
.unchecked_into(),
),
(
// 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp
array_bytes::hex_n_into_unchecked("547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"),
// 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9
array_bytes::hex_n_into_unchecked("9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"),
// 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d
array_bytes::hex2array_unchecked("5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440")
.unchecked_into(),
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a")
.unchecked_into(),
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a")
.unchecked_into(),
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a")
.unchecked_into(),
// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a")
.unchecked_into(),
// 5GQx4FToRBPqfani6o7owFJE1UstiviqbPP7HPWyvtXWWukn
array_bytes::hex2array_unchecked("036a818b3f59579c5fbbe4fede64f49dbf090ba883eb2a175d5ca90e5adb5f0b3e")
.unchecked_into(),
),
(
// 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9
array_bytes::hex_n_into_unchecked("f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"),
// 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn
array_bytes::hex_n_into_unchecked("66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"),
// 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4
array_bytes::hex2array_unchecked("3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef")
.unchecked_into(),
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378")
.unchecked_into(),
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378")
.unchecked_into(),
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378")
.unchecked_into(),
// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378")
.unchecked_into(),
// 5FCu2pY928VVHPgnNVJssvxFJZECyNe1CyH3WTG79Wisx58B
array_bytes::hex2array_unchecked("020ce02b963548f9f8ade8765f7a4a06638c17819c78422a1cc35b647873583eef")
.unchecked_into(),
),
];
// generated with secret: subkey inspect "$secret"/fir
let root_key: AccountId = array_bytes::hex_n_into_unchecked(
// 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo
"9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809",
);
let endowed_accounts: Vec<AccountId> = vec![root_key.clone()];
(initial_authorities, root_key, endowed_accounts)
}
fn pezstaging_testnet_genesis_patch() -> serde_json::Value {
let (initial_authorities, root_key, endowed_accounts) =
configure_accounts_for_staging_testnet();
testnet_genesis_patch(initial_authorities, vec![], root_key, endowed_accounts)
}
/// Staging testnet config.
pub fn pezstaging_testnet_config() -> ChainSpec {
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Staging Testnet")
.with_id("pezstaging_testnet")
.with_chain_type(ChainType::Live)
.with_genesis_config_preset_name(pezsp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET)
.with_genesis_config_patch(pezstaging_testnet_genesis_patch())
.with_telemetry_endpoints(
TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)])
.expect("Staging telemetry url is valid; qed"),
)
.build()
}
/// Configure the accounts for the testnet.
///
/// * Adds `initial_authorities` and `initial_nominators` to endowed accounts if missing.
/// * Sets up the stakers consisting of the `initial_authorities` and `initial_nominators`.
fn configure_accounts(
initial_authorities: Vec<(
AccountId,
AccountId,
GrandpaId,
BabeId,
ImOnlineId,
AuthorityDiscoveryId,
MixnetId,
BeefyId,
)>,
initial_nominators: Vec<AccountId>,
endowed_accounts: Vec<AccountId>,
stash: Balance,
) -> (
Vec<(
AccountId,
AccountId,
GrandpaId,
BabeId,
ImOnlineId,
AuthorityDiscoveryId,
MixnetId,
BeefyId,
)>,
Vec<AccountId>,
Vec<Staker>,
) {
let mut endowed_accounts = endowed_accounts;
// endow all authorities and nominators.
initial_authorities
.iter()
.map(|x| &x.0)
.chain(initial_nominators.iter())
.for_each(|x| {
if !endowed_accounts.contains(x) {
endowed_accounts.push(x.clone())
}
});
// stakers: all validators and nominators.
let mut rng = rand::thread_rng();
let stakers = initial_authorities
.iter()
.map(|x| (x.0.clone(), x.0.clone(), stash, StakerStatus::Validator))
.chain(initial_nominators.iter().map(|x| {
use rand::{seq::SliceRandom, Rng};
let limit = (MaxNominations::get() as usize).min(initial_authorities.len());
let count = rng.gen::<usize>() % limit;
let nominations = initial_authorities
.as_slice()
.choose_multiple(&mut rng, count)
.into_iter()
.map(|choice| choice.0.clone())
.collect::<Vec<_>>();
(x.clone(), x.clone(), stash, StakerStatus::Nominator(nominations))
}))
.collect::<Vec<_>>();
(initial_authorities, endowed_accounts, stakers)
}
/// Helper function to create RuntimeGenesisConfig json patch for testing.
pub fn testnet_genesis_patch(
initial_authorities: Vec<(
AccountId,
AccountId,
GrandpaId,
BabeId,
ImOnlineId,
AuthorityDiscoveryId,
MixnetId,
BeefyId,
)>,
initial_nominators: Vec<AccountId>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
) -> serde_json::Value {
let (initial_authorities, endowed_accounts, stakers) =
configure_accounts(initial_authorities, initial_nominators, endowed_accounts, STASH);
let validator_count = initial_authorities.len();
let minimum_validator_count = validator_count;
let collective = collective(&endowed_accounts);
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect::<Vec<_>>()
},
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
(
x.0.clone(),
// stash account is controller
x.0.clone(),
session_keys_json(
x.2.clone(),
x.3.clone(),
x.4.clone(),
x.5.clone(),
x.6.clone(),
x.7.clone(),
)
)
})
.collect::<Vec<_>>()
},
"elections": {
"members": collective.iter().cloned().map(|member| (member, STASH)).collect::<Vec<_>>(),
},
"technicalCommittee": {
"members": collective,
},
"staking": {
"validatorCount": validator_count,
"minimumValidatorCount": minimum_validator_count,
"invulnerables": initial_authorities
.iter()
.map(|x| x.0.clone())
.collect::<Vec<_>>(),
"stakers": stakers,
},
"sudo": {
"key": root_key,
},
"revive": {
"mappedAccounts": endowed_accounts.iter().filter(|x| ! is_eth_derived(x)).cloned().collect::<Vec<_>>()
}
})
}
/// Creates the session keys as defined by the runtime.
fn session_keys_json(
grandpa: GrandpaId,
babe: BabeId,
im_online: ImOnlineId,
authority_discovery: AuthorityDiscoveryId,
mixnet: MixnetId,
beefy: BeefyId,
) -> serde_json::Value {
serde_json::json!({
"authority_discovery": authority_discovery,
"babe": babe,
"beefy": beefy,
"grandpa": grandpa,
"im_online": im_online,
"mixnet": mixnet
})
}
/// Extract some accounts from endowed to be put into the collective.
fn collective(endowed: &[AccountId]) -> Vec<AccountId> {
const MAX_COLLECTIVE_SIZE: usize = 50;
let endowed_accounts_count = endowed.len();
endowed
.iter()
.take((endowed_accounts_count.div_ceil(2)).min(MAX_COLLECTIVE_SIZE))
.cloned()
.collect()
}
fn props() -> Properties {
let mut properties = Properties::new();
properties.insert("tokenDecimals".to_string(), 12.into());
properties
}
/// Development config (single validator Alice).
pub fn development_config() -> ChainSpec {
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Development")
.with_id("dev")
.with_chain_type(ChainType::Development)
.with_properties(props())
.with_genesis_config_preset_name(pezsp_genesis_builder::DEV_RUNTIME_PRESET)
.build()
}
/// Local testnet config (multivalidator Alice + Bob).
pub fn local_testnet_config() -> ChainSpec {
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Local Testnet")
.with_id("local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_preset_name(pezsp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET)
.build()
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::service::{new_full_base, NewFullBase};
use kitchensink_runtime::genesis_config_presets::well_known_including_eth_accounts;
use pezsc_service_test;
use pezsp_runtime::{AccountId32, BuildStorage};
/// Local testnet config (single validator - Alice).
pub fn integration_test_config_with_single_authority() -> ChainSpec {
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Integration Test")
.with_id("test")
.with_chain_type(ChainType::Development)
.with_genesis_config_preset_name(pezsp_genesis_builder::DEV_RUNTIME_PRESET)
.build()
}
/// Local testnet config (multivalidator Alice + Bob).
pub fn integration_test_config_with_two_authorities() -> ChainSpec {
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Integration Test")
.with_id("test")
.with_chain_type(ChainType::Local)
.with_genesis_config_preset_name(pezsp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET)
.build()
}
fn eth_account(from: subxt_signer::eth::Keypair) -> AccountId32 {
let mut account_id = AccountId32::new([0xEE; 32]);
<AccountId32 as AsMut<[u8; 32]>>::as_mut(&mut account_id)[..20]
.copy_from_slice(&from.public_key().to_account_id().as_ref());
account_id
}
#[test]
#[ignore]
fn test_connectivity() {
pezsp_tracing::try_init_simple();
pezsc_service_test::connectivity(integration_test_config_with_two_authorities(), |config| {
let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } =
new_full_base::<pezsc_network::NetworkWorker<_, _>>(config, None, false, |_, _| ())?;
Ok(pezsc_service_test::TestNetComponents::new(
task_manager,
client,
network,
sync,
transaction_pool,
))
});
}
#[test]
fn test_create_development_chain_spec() {
development_config().build_storage().unwrap();
}
#[test]
fn test_create_local_testnet_chain_spec() {
local_testnet_config().build_storage().unwrap();
}
#[test]
fn test_staging_test_net_chain_spec() {
pezstaging_testnet_config().build_storage().unwrap();
}
#[test]
fn ensure_eth_accounts_are_in_endowed() {
let alith = eth_account(subxt_signer::eth::dev::alith());
let baltathar = eth_account(subxt_signer::eth::dev::baltathar());
let endowed = well_known_including_eth_accounts();
assert!(endowed.contains(&alith), "Alith must be in endowed for integration tests");
assert!(endowed.contains(&baltathar), "Baltathar must be in endowed for integration tests");
}
}
+111
View File
@@ -0,0 +1,111 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use pezkuwi_sdk::*;
/// An overarching CLI command definition.
#[derive(Debug, clap::Parser)]
pub struct Cli {
/// Possible subcommand with parameters.
#[command(subcommand)]
pub subcommand: Option<Subcommand>,
#[allow(missing_docs)]
#[clap(flatten)]
pub run: pezsc_cli::RunCmd,
#[allow(missing_docs)]
#[clap(flatten)]
pub mixnet_params: pezsc_cli::MixnetParams,
/// Disable automatic hardware benchmarks.
///
/// By default these benchmarks are automatically ran at startup and measure
/// the CPU speed, the memory bandwidth and the disk speed.
///
/// The results are then printed out in the logs, and also sent as part of
/// telemetry, if telemetry is enabled.
#[arg(long)]
pub no_hardware_benchmarks: bool,
#[allow(missing_docs)]
#[clap(flatten)]
pub storage_monitor: pezsc_storage_monitor::StorageMonitorParams,
}
/// Possible subcommands of the main binary.
#[derive(Debug, clap::Subcommand)]
pub enum Subcommand {
/// The custom inspect subcommand for decoding blocks and extrinsics.
#[command(
name = "inspect",
about = "Decode given block or extrinsic using current native runtime."
)]
Inspect(node_inspect::cli::InspectCmd),
/// Sub-commands concerned with benchmarking.
///
/// The pallet benchmarking moved to the `pallet` sub-command.
#[command(subcommand)]
Benchmark(pezframe_benchmarking_cli::BenchmarkCmd),
/// Key management cli utilities
#[command(subcommand)]
Key(pezsc_cli::KeySubcommand),
/// Verify a signature for a message, provided on STDIN, with a given (public or secret) key.
Verify(pezsc_cli::VerifyCmd),
/// Generate a seed that provides a vanity address.
Vanity(pezsc_cli::VanityCmd),
/// Sign a message, with a given (secret) key.
Sign(pezsc_cli::SignCmd),
/// Build a chain specification.
/// DEPRECATED: `build-spec` command will be removed after 1/04/2026. Use `export-chain-spec`
/// command instead.
#[deprecated(
note = "build-spec command will be removed after 1/04/2026. Use export-chain-spec command instead"
)]
BuildSpec(pezsc_cli::BuildSpecCmd),
/// Export the chain specification.
ExportChainSpec(pezsc_cli::ExportChainSpecCmd),
/// Validate blocks.
CheckBlock(pezsc_cli::CheckBlockCmd),
/// Export blocks.
ExportBlocks(pezsc_cli::ExportBlocksCmd),
/// Export the state of a given block into a chain spec.
ExportState(pezsc_cli::ExportStateCmd),
/// Import blocks.
ImportBlocks(pezsc_cli::ImportBlocksCmd),
/// Remove the whole chain.
PurgeChain(pezsc_cli::PurgeChainCmd),
/// Revert the chain to a previous state.
Revert(pezsc_cli::RevertCmd),
/// Db meta columns information.
ChainInfo(pezsc_cli::ChainInfoCmd),
}
+238
View File
@@ -0,0 +1,238 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use pezkuwi_sdk::*;
use super::benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder};
use crate::{
chain_spec, service,
service::{new_partial, FullClient},
Cli, Subcommand,
};
use pezframe_benchmarking_cli::*;
use kitchensink_runtime::{ExistentialDeposit, RuntimeApi};
use node_primitives::Block;
use pezsc_cli::{Result, BizinikiwiCli};
use pezsc_service::PartialComponents;
use pezsp_keyring::Sr25519Keyring;
use pezsp_runtime::traits::HashingFor;
use std::sync::Arc;
impl BizinikiwiCli for Cli {
fn impl_name() -> String {
"Bizinikiwi Node".into()
}
fn impl_version() -> String {
env!("BIZINIKIWI_CLI_IMPL_VERSION").into()
}
fn description() -> String {
env!("CARGO_PKG_DESCRIPTION").into()
}
fn author() -> String {
env!("CARGO_PKG_AUTHORS").into()
}
fn support_url() -> String {
"https://github.com/pezkuwichain/pezkuwi-sdk/issues/new".into()
}
fn copyright_start_year() -> i32 {
2017
}
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn pezsc_service::ChainSpec>, String> {
let spec = match id {
"" =>
return Err(
"Please specify which chain you want to run, e.g. --dev or --chain=local"
.into(),
),
"dev" => Box::new(chain_spec::development_config()),
"local" => Box::new(chain_spec::local_testnet_config()),
"fir" | "flaming-fir" => Box::new(chain_spec::flaming_fir_config()?),
"staging" => Box::new(chain_spec::pezstaging_testnet_config()),
path =>
Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
};
Ok(spec)
}
}
/// Parse command line arguments into service configuration.
pub fn run() -> Result<()> {
let cli = Cli::from_args();
match &cli.subcommand {
None => {
let runner = cli.create_runner(&cli.run)?;
runner.run_node_until_exit(|config| async move {
service::new_full(config, cli).map_err(pezsc_cli::Error::Service)
})
},
Some(Subcommand::Inspect(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block, RuntimeApi>(config))
},
Some(Subcommand::ExportChainSpec(cmd)) => {
let chain_spec = cli.load_spec(&cmd.chain)?;
cmd.run(chain_spec)
},
Some(Subcommand::Benchmark(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| {
// This switch needs to be in the client, since the client decides
// which sub-commands it wants to support.
match cmd {
BenchmarkCmd::Pallet(cmd) => {
if !cfg!(feature = "runtime-benchmarks") {
return Err(
"Runtime benchmarking wasn't enabled when building the node. \
You can enable it with `--features runtime-benchmarks`."
.into(),
)
}
cmd.run_with_spec::<HashingFor<Block>, pezsp_statement_store::runtime_api::HostFunctions>(Some(config.chain_spec))
},
BenchmarkCmd::Block(cmd) => {
// ensure that we keep the task manager alive
let partial = new_partial(&config, None)?;
cmd.run(partial.client)
},
#[cfg(not(feature = "runtime-benchmarks"))]
BenchmarkCmd::Storage(_) => Err(
"Storage benchmarking can be enabled with `--features runtime-benchmarks`."
.into(),
),
#[cfg(feature = "runtime-benchmarks")]
BenchmarkCmd::Storage(cmd) => {
// ensure that we keep the task manager alive
let partial = new_partial(&config, None)?;
let db = partial.backend.expose_db();
let storage = partial.backend.expose_storage();
let shared_trie_cache = partial.backend.expose_shared_trie_cache();
cmd.run(config, partial.client, db, storage, shared_trie_cache)
},
BenchmarkCmd::Overhead(cmd) => {
// ensure that we keep the task manager alive
let partial = new_partial(&config, None)?;
let ext_builder = RemarkBuilder::new(partial.client.clone());
cmd.run(
config.chain_spec.name().into(),
partial.client,
inherent_benchmark_data()?,
Vec::new(),
&ext_builder,
false,
)
},
BenchmarkCmd::Extrinsic(cmd) => {
// ensure that we keep the task manager alive
let partial = service::new_partial(&config, None)?;
// Register the *Remark* and *TKA* builders.
let ext_factory = ExtrinsicFactory(vec![
Box::new(RemarkBuilder::new(partial.client.clone())),
Box::new(TransferKeepAliveBuilder::new(
partial.client.clone(),
Sr25519Keyring::Alice.to_account_id(),
ExistentialDeposit::get(),
)),
]);
cmd.run(
partial.client,
inherent_benchmark_data()?,
Vec::new(),
&ext_factory,
)
},
BenchmarkCmd::Machine(cmd) =>
cmd.run(&config, BIZINIKIWI_REFERENCE_HARDWARE.clone()),
}
})
},
Some(Subcommand::Key(cmd)) => cmd.run(&cli),
Some(Subcommand::Sign(cmd)) => cmd.run(),
Some(Subcommand::Verify(cmd)) => cmd.run(),
Some(Subcommand::Vanity(cmd)) => cmd.run(),
#[allow(deprecated)]
Some(Subcommand::BuildSpec(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.chain_spec, config.network))
},
Some(Subcommand::CheckBlock(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, .. } =
new_partial(&config, None)?;
Ok((cmd.run(client, import_queue), task_manager))
})
},
Some(Subcommand::ExportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, .. } = new_partial(&config, None)?;
Ok((cmd.run(client, config.database), task_manager))
})
},
Some(Subcommand::ExportState(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, .. } = new_partial(&config, None)?;
Ok((cmd.run(client, config.chain_spec), task_manager))
})
},
Some(Subcommand::ImportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, .. } =
new_partial(&config, None)?;
Ok((cmd.run(client, import_queue), task_manager))
})
},
Some(Subcommand::PurgeChain(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.database))
},
Some(Subcommand::Revert(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, backend, .. } =
new_partial(&config, None)?;
let aux_revert = Box::new(|client: Arc<FullClient>, backend, blocks| {
pezsc_consensus_babe::revert(client.clone(), backend, blocks)?;
pezsc_consensus_grandpa::revert(client, blocks)?;
Ok(())
});
Ok((cmd.run(client, backend, Some(aux_revert)), task_manager))
})
},
Some(Subcommand::ChainInfo(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block>(&config))
},
}
}
+45
View File
@@ -0,0 +1,45 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Bizinikiwi CLI library.
//!
//! This package has two Cargo features:
//!
//! - `cli` (default): exposes functions that parse command-line options, then start and run the
//! node as a CLI application.
//!
//! - `browser`: exposes the content of the `browser` module, which consists of exported symbols
//! that are meant to be passed through the `wasm-bindgen` utility and called from JavaScript.
//! Despite its name the produced WASM can theoretically also be used from NodeJS, although this
//! hasn't been tested.
#![warn(missing_docs)]
#[cfg(feature = "cli")]
mod benchmarking;
pub mod chain_spec;
#[cfg(feature = "cli")]
mod cli;
#[cfg(feature = "cli")]
mod command;
pub mod service;
#[cfg(feature = "cli")]
pub use cli::*;
#[cfg(feature = "cli")]
pub use command::*;
File diff suppressed because it is too large Load Diff
+892
View File
@@ -0,0 +1,892 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use codec::{Decode, Encode, Joiner};
use pezframe_support::{
dispatch::{DispatchClass, GetDispatchInfo},
traits::Currency,
weights::Weight,
};
use pezframe_system::{self, AccountInfo, DispatchEventInfo, EventRecord, Phase};
use pezkuwi_sdk::*;
use pezsp_core::{storage::well_known_keys, traits::Externalities};
use pezsp_runtime::{
traits::Hash as HashT, transaction_validity::InvalidTransaction, ApplyExtrinsicResult,
};
use kitchensink_runtime::{
constants::{currency::*, time::SLOT_DURATION},
Balances, CheckedExtrinsic, Header, Runtime, RuntimeCall, RuntimeEvent, System,
TransactionPayment, Treasury, UncheckedExtrinsic,
};
use node_primitives::{Balance, Hash};
use node_testing::keyring::*;
use pretty_assertions::assert_eq;
use wat;
pub mod common;
use self::common::{sign, *};
/// The wasm runtime binary which hasn't undergone the compacting process.
///
/// The idea here is to pass it as the current runtime code to the executor so the executor will
/// have to execute provided wasm code instead of the native equivalent. This trick is used to
/// test code paths that differ between native and wasm versions.
pub fn bloaty_code_unwrap() -> &'static [u8] {
kitchensink_runtime::WASM_BINARY_BLOATY.expect(
"Development wasm binary is not available. \
Testing is only supported with the flag disabled.",
)
}
/// Default transfer fee. This will use the same logic that is implemented in transaction-payment
/// module.
///
/// Note that reads the multiplier from storage directly, hence to get the fee of `extrinsic`
/// at block `n`, it must be called prior to executing block `n` to do the calculation with the
/// correct multiplier.
fn transfer_fee(extrinsic: &UncheckedExtrinsic) -> Balance {
let mut info = default_transfer_call().get_dispatch_info();
info.extension_weight = extrinsic.0.extension_weight();
TransactionPayment::compute_fee(extrinsic.encode().len() as u32, &info, 0)
}
/// Default transfer fee, same as `transfer_fee`, but with a weight refund factored in.
fn transfer_fee_with_refund(extrinsic: &UncheckedExtrinsic, weight_refund: Weight) -> Balance {
let mut info = default_transfer_call().get_dispatch_info();
info.extension_weight = extrinsic.0.extension_weight();
let post_info = (Some(info.total_weight().saturating_sub(weight_refund)), info.pays_fee).into();
TransactionPayment::compute_actual_fee(extrinsic.encode().len() as u32, &info, &post_info, 0)
}
fn xt() -> UncheckedExtrinsic {
sign(CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)),
function: RuntimeCall::Balances(default_transfer_call()),
})
}
fn set_heap_pages<E: Externalities>(ext: &mut E, heap_pages: u64) {
ext.place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(heap_pages.encode()));
}
fn changes_trie_block() -> (Vec<u8>, Hash) {
let time = 42 * 1000;
construct_block(
&mut new_test_ext(compact_code_unwrap()),
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Bare,
function: RuntimeCall::Timestamp(pezpallet_timestamp::Call::set { now: time }),
},
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)),
function: RuntimeCall::Balances(pezpallet_balances::Call::transfer_allow_death {
dest: bob().into(),
value: 69 * DOLLARS,
}),
},
],
(time / SLOT_DURATION).into(),
)
}
/// block 1 and 2 must be created together to ensure transactions are only signed once (since they
/// are not guaranteed to be deterministic) and to ensure that the correct state is propagated
/// from block1's execution to block2 to derive the correct storage_root.
fn blocks() -> ((Vec<u8>, Hash), (Vec<u8>, Hash)) {
let mut t = new_test_ext(compact_code_unwrap());
let time1 = 42 * 1000;
let block1 = construct_block(
&mut t,
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Bare,
function: RuntimeCall::Timestamp(pezpallet_timestamp::Call::set { now: time1 }),
},
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)),
function: RuntimeCall::Balances(pezpallet_balances::Call::transfer_allow_death {
dest: bob().into(),
value: 69 * DOLLARS,
}),
},
],
(time1 / SLOT_DURATION).into(),
);
let time2 = 52 * 1000;
let block2 = construct_block(
&mut t,
2,
block1.1,
vec![
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Bare,
function: RuntimeCall::Timestamp(pezpallet_timestamp::Call::set { now: time2 }),
},
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(bob(), tx_ext(0, 0)),
function: RuntimeCall::Balances(pezpallet_balances::Call::transfer_allow_death {
dest: alice().into(),
value: 5 * DOLLARS,
}),
},
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(1, 0)),
function: RuntimeCall::Balances(pezpallet_balances::Call::transfer_allow_death {
dest: bob().into(),
value: 15 * DOLLARS,
}),
},
],
(time2 / SLOT_DURATION).into(),
);
// session change => consensus authorities change => authorities change digest item appears
let digest = Header::decode(&mut &block2.0[..]).unwrap().digest;
assert_eq!(digest.logs().len(), 2 /* Just babe and BEEFY slots */);
(block1, block2)
}
fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec<u8>, Hash) {
construct_block(
&mut new_test_ext(compact_code_unwrap()),
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Bare,
function: RuntimeCall::Timestamp(pezpallet_timestamp::Call::set { now: time * 1000 }),
},
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(nonce, 0)),
function: RuntimeCall::System(pezframe_system::Call::remark { remark: vec![0; size] }),
},
],
(time * 1000 / SLOT_DURATION).into(),
)
}
#[test]
fn panic_execution_with_foreign_code_gives_error() {
let mut t = new_test_ext(bloaty_code_unwrap());
t.insert(
<pezframe_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as pezframe_system::Config>::Nonce, _> {
providers: 1,
data: (69u128, 0u128, 0u128, 1u128 << 127),
..Default::default()
}
.encode(),
);
t.insert(<pezpallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode());
t.insert(<pezframe_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0;
assert!(r.is_ok());
let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()))
.0
.unwrap();
let r = ApplyExtrinsicResult::decode(&mut &v[..]).unwrap();
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
}
#[test]
fn bad_extrinsic_with_native_equivalent_code_gives_error() {
let mut t = new_test_ext(compact_code_unwrap());
t.insert(
<pezframe_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as pezframe_system::Config>::Nonce, _> {
providers: 1,
data: (69u128, 0u128, 0u128, 1u128 << 127),
..Default::default()
}
.encode(),
);
t.insert(<pezpallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69u128.encode());
t.insert(<pezframe_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0;
assert!(r.is_ok());
let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()))
.0
.unwrap();
let r = ApplyExtrinsicResult::decode(&mut &v[..]).unwrap();
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
}
#[test]
fn successful_execution_with_native_equivalent_code_gives_ok() {
let mut t = new_test_ext(compact_code_unwrap());
t.insert(
<pezframe_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as pezframe_system::Config>::Nonce, _> {
providers: 1,
data: (111 * DOLLARS, 0u128, 0u128, 1u128 << 127),
..Default::default()
}
.encode(),
);
t.insert(
<pezframe_system::Account<Runtime>>::hashed_key_for(bob()),
AccountInfo::<
<Runtime as pezframe_system::Config>::Nonce,
<Runtime as pezframe_system::Config>::AccountData,
>::default()
.encode(),
);
t.insert(
<pezpallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(111 * DOLLARS).encode(),
);
t.insert(<pezframe_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0;
assert!(r.is_ok());
let weight_refund = Weight::zero();
let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund));
let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).0;
assert!(r.is_ok());
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund);
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
#[test]
fn successful_execution_with_foreign_code_gives_ok() {
let mut t = new_test_ext(bloaty_code_unwrap());
t.insert(
<pezframe_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as pezframe_system::Config>::Nonce, _> {
providers: 1,
data: (111 * DOLLARS, 0u128, 0u128, 1u128 << 127),
..Default::default()
}
.encode(),
);
t.insert(
<pezframe_system::Account<Runtime>>::hashed_key_for(bob()),
AccountInfo::<
<Runtime as pezframe_system::Config>::Nonce,
<Runtime as pezframe_system::Config>::AccountData,
>::default()
.encode(),
);
t.insert(
<pezpallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(111 * DOLLARS).encode(),
);
t.insert(<pezframe_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0;
assert!(r.is_ok());
let weight_refund = Weight::zero();
let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund));
let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).0;
assert!(r.is_ok());
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund);
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
#[test]
fn full_native_block_import_works() {
let mut t = new_test_ext(compact_code_unwrap());
let (block1, block2) = blocks();
let mut alice_last_known_balance: Balance = Default::default();
let mut fees = t.execute_with(|| transfer_fee(&xt()));
let extension_weight = xt().0.extension_weight();
let weight_refund = Weight::zero();
let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund));
let transfer_weight = default_transfer_call().get_dispatch_info().call_weight.saturating_add(
<Runtime as pezframe_system::Config>::BlockWeights::get()
.get(DispatchClass::Normal)
.base_extrinsic,
);
let timestamp_weight = pezpallet_timestamp::Call::set::<Runtime> { now: Default::default() }
.get_dispatch_info()
.call_weight
.saturating_add(
<Runtime as pezframe_system::Config>::BlockWeights::get()
.get(DispatchClass::Mandatory)
.base_extrinsic,
);
executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap();
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund);
assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS);
alice_last_known_balance = Balances::total_balance(&alice());
let events = vec![
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: RuntimeEvent::System(pezframe_system::Event::ExtrinsicSuccess {
dispatch_info: DispatchEventInfo {
weight: timestamp_weight,
class: DispatchClass::Mandatory,
pays_fee: Default::default(),
},
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::Balances(pezpallet_balances::Event::Withdraw {
who: alice().into(),
amount: fees,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::Balances(pezpallet_balances::Event::Transfer {
from: alice().into(),
to: bob().into(),
amount: 69 * DOLLARS,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::Balances(pezpallet_balances::Event::Deposit {
who: pezpallet_treasury::Pallet::<Runtime>::account_id(),
amount: fees_after_refund,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::TransactionPayment(
pezpallet_transaction_payment::Event::TransactionFeePaid {
who: alice().into(),
actual_fee: fees_after_refund,
tip: 0,
},
),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::System(pezframe_system::Event::ExtrinsicSuccess {
dispatch_info: DispatchEventInfo {
weight: transfer_weight
.saturating_add(extension_weight.saturating_sub(weight_refund)),
..Default::default()
},
}),
topics: vec![],
},
];
let filtered_events: Vec<_> = System::events()
.into_iter()
.filter(|ev| {
!matches!(
ev.event,
RuntimeEvent::VoterList(
pezpallet_bags_list::Event::<Runtime, _>::ScoreUpdated { .. }
)
)
})
.collect();
assert_eq!(filtered_events, events);
});
fees = t.execute_with(|| transfer_fee(&xt()));
let pot = t.execute_with(|| Treasury::pot());
let extension_weight = xt().0.extension_weight();
let weight_refund = Weight::zero();
let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund));
executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap();
t.execute_with(|| {
assert_eq!(
Balances::total_balance(&alice()),
alice_last_known_balance - 10 * DOLLARS - fees_after_refund,
);
assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - fees_after_refund);
let events = vec![
EventRecord {
phase: Phase::Initialization,
event: RuntimeEvent::Treasury(pezpallet_treasury::Event::UpdatedInactive {
reactivated: 0,
deactivated: pot,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: RuntimeEvent::System(pezframe_system::Event::ExtrinsicSuccess {
dispatch_info: DispatchEventInfo {
weight: timestamp_weight,
class: DispatchClass::Mandatory,
pays_fee: Default::default(),
},
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::Balances(pezpallet_balances::Event::Withdraw {
who: bob().into(),
amount: fees,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::Balances(pezpallet_balances::Event::Transfer {
from: bob().into(),
to: alice().into(),
amount: 5 * DOLLARS,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::Balances(pezpallet_balances::Event::Deposit {
who: pezpallet_treasury::Pallet::<Runtime>::account_id(),
amount: fees_after_refund,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::TransactionPayment(
pezpallet_transaction_payment::Event::TransactionFeePaid {
who: bob().into(),
actual_fee: fees_after_refund,
tip: 0,
},
),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: RuntimeEvent::System(pezframe_system::Event::ExtrinsicSuccess {
dispatch_info: DispatchEventInfo {
weight: transfer_weight
.saturating_add(extension_weight.saturating_sub(weight_refund)),
..Default::default()
},
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(2),
event: RuntimeEvent::Balances(pezpallet_balances::Event::Withdraw {
who: alice().into(),
amount: fees,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(2),
event: RuntimeEvent::Balances(pezpallet_balances::Event::Transfer {
from: alice().into(),
to: bob().into(),
amount: 15 * DOLLARS,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(2),
event: RuntimeEvent::Balances(pezpallet_balances::Event::Deposit {
who: pezpallet_treasury::Pallet::<Runtime>::account_id(),
amount: fees_after_refund,
}),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(2),
event: RuntimeEvent::TransactionPayment(
pezpallet_transaction_payment::Event::TransactionFeePaid {
who: alice().into(),
actual_fee: fees_after_refund,
tip: 0,
},
),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(2),
event: RuntimeEvent::System(pezframe_system::Event::ExtrinsicSuccess {
dispatch_info: DispatchEventInfo {
weight: transfer_weight
.saturating_add(extension_weight.saturating_sub(weight_refund)),
..Default::default()
},
}),
topics: vec![],
},
];
let all_events = System::events();
// Ensure that all expected events (`events`) are present in the full event log
// (`all_events`). We use this instead of strict equality since some events (like
// VoterList::ScoreUpdated) may be emitted non-deterministically depending on runtime
// internals or auto-rebagging logic.
for expected_event in &events {
assert!(
all_events.contains(expected_event),
"Expected event {:?} not found in actual events",
expected_event
);
}
});
}
#[test]
fn full_wasm_block_import_works() {
let mut t = new_test_ext(compact_code_unwrap());
let (block1, block2) = blocks();
let mut alice_last_known_balance: Balance = Default::default();
let weight_refund = Weight::zero();
let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund));
executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap();
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund);
assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS);
alice_last_known_balance = Balances::total_balance(&alice());
});
let weight_refund = Weight::zero();
let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund));
executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap();
t.execute_with(|| {
assert_eq!(
Balances::total_balance(&alice()),
alice_last_known_balance - 10 * DOLLARS - fees_after_refund,
);
assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * fees_after_refund);
});
}
const CODE_TRANSFER: &str = r#"
(module
;; seal_call(
;; callee_ptr: u32,
;; callee_len: u32,
;; gas: u64,
;; value_ptr: u32,
;; value_len: u32,
;; input_data_ptr: u32,
;; input_data_len: u32,
;; output_ptr: u32,
;; output_len_ptr: u32
;; ) -> u32
(import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32)))
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "env" "memory" (memory 1 1))
(func (export "deploy")
)
(func (export "call")
(block $fail
;; Load input data to contract memory
(call $seal_input
(i32.const 0)
(i32.const 52)
)
;; fail if the input size is not != 4
(br_if $fail
(i32.ne
(i32.const 4)
(i32.load (i32.const 52))
)
)
(br_if $fail
(i32.ne
(i32.load8_u (i32.const 0))
(i32.const 0)
)
)
(br_if $fail
(i32.ne
(i32.load8_u (i32.const 1))
(i32.const 1)
)
)
(br_if $fail
(i32.ne
(i32.load8_u (i32.const 2))
(i32.const 2)
)
)
(br_if $fail
(i32.ne
(i32.load8_u (i32.const 3))
(i32.const 3)
)
)
(drop
(call $seal_call
(i32.const 4) ;; Pointer to "callee" address.
(i32.const 32) ;; Length of "callee" address.
(i64.const 0) ;; How much gas to devote for the execution. 0 = all.
(i32.const 36) ;; Pointer to the buffer with value to transfer
(i32.const 16) ;; Length of the buffer with value to transfer.
(i32.const 0) ;; Pointer to input data buffer address
(i32.const 0) ;; Length of input data buffer
(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
(i32.const 0) ;; Length is ignored in this case
)
)
(return)
)
unreachable
)
;; Destination AccountId to transfer the funds.
;; Represented by H256 (32 bytes long) in little endian.
(data (i32.const 4)
"\09\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
"\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
"\00\00\00\00"
)
;; Amount of value to transfer.
;; Represented by u128 (16 bytes long) in little endian.
(data (i32.const 36)
"\06\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
"\00\00"
)
;; Length of the input buffer
(data (i32.const 52) "\04")
)
"#;
#[test]
fn deploying_wasm_contract_should_work() {
let transfer_code = wat::parse_str(CODE_TRANSFER).unwrap();
let transfer_ch = <Runtime as pezframe_system::Config>::Hashing::hash(&transfer_code);
let addr =
pezpallet_contracts::Pallet::<Runtime>::contract_address(&charlie(), &transfer_ch, &[], &[]);
let time = 42 * 1000;
let b = construct_block(
&mut new_test_ext(compact_code_unwrap()),
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Bare,
function: RuntimeCall::Timestamp(pezpallet_timestamp::Call::set { now: time }),
},
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(0, 0)),
function: RuntimeCall::Contracts(pezpallet_contracts::Call::instantiate_with_code::<
Runtime,
> {
value: 0,
gas_limit: Weight::from_parts(500_000_000, 0),
storage_deposit_limit: None,
code: transfer_code,
data: Vec::new(),
salt: Vec::new(),
}),
},
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(1, 0)),
function: RuntimeCall::Contracts(pezpallet_contracts::Call::call::<Runtime> {
dest: pezsp_runtime::MultiAddress::Id(addr.clone()),
value: 10,
gas_limit: Weight::from_parts(500_000_000, 0),
storage_deposit_limit: None,
data: vec![0x00, 0x01, 0x02, 0x03],
}),
},
],
(time / SLOT_DURATION).into(),
);
let mut t = new_test_ext(compact_code_unwrap());
executor_call(&mut t, "Core_execute_block", &b.0).0.unwrap();
t.execute_with(|| {
// Verify that the contract does exist by querying some of its storage items
// It does not matter that the storage item itself does not exist.
assert!(&pezpallet_contracts::Pallet::<Runtime>::get_storage(addr, vec![]).is_ok());
});
}
#[test]
fn wasm_big_block_import_fails() {
let mut t = new_test_ext(compact_code_unwrap());
set_heap_pages(&mut t.ext(), 4);
let result = executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0).0;
assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) })))
}
#[test]
fn native_big_block_import_succeeds() {
let mut t = new_test_ext(compact_code_unwrap());
executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0)
.0
.unwrap();
}
#[test]
fn native_big_block_import_fails_on_fallback() {
let mut t = new_test_ext(compact_code_unwrap());
// We set the heap pages to 8 because we know that should give an OOM in WASM with the given
// block.
set_heap_pages(&mut t.ext(), 8);
assert!(executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0)
.0
.is_err());
}
#[test]
fn panic_execution_gives_error() {
let mut t = new_test_ext(bloaty_code_unwrap());
t.insert(
<pezframe_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as pezframe_system::Config>::Nonce, _> {
data: (0 * DOLLARS, 0u128, 0u128, 0u128),
..Default::default()
}
.encode(),
);
t.insert(<pezpallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 0_u128.encode());
t.insert(<pezframe_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0;
assert!(r.is_ok());
let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()))
.0
.unwrap();
let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap();
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
}
#[test]
fn successful_execution_gives_ok() {
let mut t = new_test_ext(compact_code_unwrap());
t.insert(
<pezframe_system::Account<Runtime>>::hashed_key_for(alice()),
AccountInfo::<<Runtime as pezframe_system::Config>::Nonce, _> {
providers: 1,
data: (111 * DOLLARS, 0u128, 0u128, 1u128 << 127),
..Default::default()
}
.encode(),
);
t.insert(
<pezframe_system::Account<Runtime>>::hashed_key_for(bob()),
AccountInfo::<
<Runtime as pezframe_system::Config>::Nonce,
<Runtime as pezframe_system::Config>::AccountData,
>::default()
.encode(),
);
t.insert(
<pezpallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(111 * DOLLARS).encode(),
);
t.insert(<pezframe_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0;
assert!(r.is_ok());
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS);
});
let weight_refund = Weight::zero();
let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund));
let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()))
.0
.unwrap();
ApplyExtrinsicResult::decode(&mut &r[..])
.unwrap()
.expect("Extrinsic could not be applied")
.expect("Extrinsic failed");
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund);
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
#[test]
fn should_import_block_with_test_client() {
use node_testing::client::{
pezsp_consensus::BlockOrigin, ClientBlockImportExt, TestClientBuilder, TestClientBuilderExt,
};
let client = TestClientBuilder::new().build();
let block1 = changes_trie_block();
let block_data = block1.0;
let block = node_primitives::Block::decode(&mut &block_data[..]).unwrap();
futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap();
}
#[test]
fn default_config_as_json_works() {
let mut t = new_test_ext(compact_code_unwrap());
let r = executor_call(
&mut t,
"GenesisBuilder_get_preset",
&None::<&pezsp_genesis_builder::PresetId>.encode(),
)
.0
.unwrap();
let r = Option::<Vec<u8>>::decode(&mut &r[..])
.unwrap()
.expect("default config is there");
let json = String::from_utf8(r.into()).expect("returned value is json. qed.");
let expected = include_str!("res/default_genesis_config.json").to_string();
assert_eq!(
serde_json::from_str::<serde_json::Value>(&expected).unwrap(),
serde_json::from_str::<serde_json::Value>(&json).unwrap()
);
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -23,7 +23,7 @@ use assert_cmd::cargo::cargo_bin;
use std::process::Command;
use tempfile::tempdir;
use substrate_cli_test_utils as common;
use bizinikiwi_cli_test_utils as common;
/// `benchmark block` works for the dev runtime using the wasm executor.
#[tokio::test]
@@ -33,7 +33,7 @@ async fn benchmark_block_works() {
common::run_node_for_a_while(base_dir.path(), &["--dev", "--no-hardware-benchmarks"]).await;
// Invoke `benchmark block` with all options to make sure that they are valid.
let status = Command::new(cargo_bin("substrate-node"))
let status = Command::new(cargo_bin("bizinikiwi-node"))
.args(["benchmark", "block", "--dev"])
.arg("-d")
.arg(base_dir.path())
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -21,7 +21,7 @@ use std::process::Command;
use tempfile::tempdir;
/// Tests that the `benchmark extrinsic` command works for
/// remark and transfer_keep_alive within the substrate dev runtime.
/// remark and transfer_keep_alive within the bizinikiwi dev runtime.
#[test]
fn benchmark_extrinsic_works() {
benchmark_extrinsic("system", "remark");
@@ -32,7 +32,7 @@ fn benchmark_extrinsic_works() {
fn benchmark_extrinsic(pallet: &str, extrinsic: &str) {
let base_dir = tempdir().expect("could not create a temp dir");
let status = Command::new(cargo_bin("substrate-node"))
let status = Command::new(cargo_bin("bizinikiwi-node"))
.args(&["benchmark", "extrinsic", "--dev"])
.arg("-d")
.arg(base_dir.path())
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -19,10 +19,10 @@
use assert_cmd::cargo::cargo_bin;
use std::process::Command;
/// Tests that the `benchmark machine` command works for the substrate dev runtime.
/// Tests that the `benchmark machine` command works for the bizinikiwi dev runtime.
#[test]
fn benchmark_machine_works() {
let status = Command::new(cargo_bin("substrate-node"))
let status = Command::new(cargo_bin("bizinikiwi-node"))
.args(["benchmark", "machine", "--dev"])
.args([
"--verify-duration",
@@ -48,7 +48,7 @@ fn benchmark_machine_works() {
#[test]
#[cfg(debug_assertions)]
fn benchmark_machine_fails_with_slow_hardware() {
let output = Command::new(cargo_bin("substrate-node"))
let output = Command::new(cargo_bin("bizinikiwi-node"))
.args(["benchmark", "machine", "--dev"])
.args([
"--verify-duration",
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -20,7 +20,7 @@ use assert_cmd::cargo::cargo_bin;
use std::process::Command;
use tempfile::tempdir;
/// Tests that the `benchmark overhead` command works for the substrate dev runtime.
/// Tests that the `benchmark overhead` command works for the bizinikiwi dev runtime.
#[test]
fn benchmark_overhead_works() {
let tmp_dir = tempdir().expect("could not create a temp dir");
@@ -28,7 +28,7 @@ fn benchmark_overhead_works() {
// Only put 10 extrinsics into the block otherwise it takes forever to build it
// especially for a non-release build.
let status = Command::new(cargo_bin("substrate-node"))
let status = Command::new(cargo_bin("bizinikiwi-node"))
.args(&["benchmark", "overhead", "--dev", "-d"])
.arg(base_path)
.arg("--weight-path")
@@ -0,0 +1,86 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#![cfg(feature = "runtime-benchmarks")]
use assert_cmd::cargo::cargo_bin;
use std::process::Command;
/// `benchmark pallet` works for the different combinations of `steps` and `repeat`.
#[test]
fn benchmark_pallet_works() {
// Some invalid combinations:
benchmark_pallet(0, 10, false);
benchmark_pallet(1, 10, false);
// ... and some valid:
benchmark_pallet(2, 1, true);
benchmark_pallet(50, 20, true);
benchmark_pallet(20, 50, true);
}
#[test]
fn benchmark_pallet_args_work() {
benchmark_pallet_args(&["--list", "--pallet=pezpallet_balances"], true);
benchmark_pallet_args(&["--list", "--pallet=pezpallet_balances"], true);
benchmark_pallet_args(
&["--list", "--pallet=pezpallet_balances", "--genesis-builder=spec-genesis"],
true,
);
benchmark_pallet_args(
&["--list", "--pallet=pezpallet_balances", "--chain=dev", "--genesis-builder=spec-genesis"],
true,
);
benchmark_pallet_args(
&["--list", "--pallet=pezpallet_balances", "--chain=dev", "--genesis-builder=spec-runtime"],
true,
);
// Error because no runtime is provided:
benchmark_pallet_args(
&["--list", "--pallet=pezpallet_balances", "--chain=dev", "--genesis-builder=runtime"],
false,
);
}
fn benchmark_pallet(steps: u32, repeat: u32, should_work: bool) {
let status = Command::new(cargo_bin("bizinikiwi-node"))
.args(["benchmark", "pallet", "--dev"])
// Use the `addition` benchmark since is the fastest.
.args(["--pallet", "pezframe-benchmarking", "--extrinsic", "addition"])
.args(["--steps", &format!("{}", steps), "--repeat", &format!("{}", repeat)])
.args([
"--wasm-execution=compiled",
"--no-storage-info",
"--no-median-slopes",
"--no-min-squares",
"--heap-pages=4096",
])
.status()
.unwrap();
assert_eq!(status.success(), should_work);
}
fn benchmark_pallet_args(args: &[&str], should_work: bool) {
let status = Command::new(cargo_bin("bizinikiwi-node"))
.args(["benchmark", "pallet"])
.args(args)
.status()
.unwrap();
assert_eq!(status.success(), should_work);
}
@@ -0,0 +1,56 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#![cfg(feature = "runtime-benchmarks")]
use assert_cmd::cargo::cargo_bin;
use std::{
path::Path,
process::{Command, ExitStatus},
};
use tempfile::tempdir;
/// Tests that the `benchmark storage` command works for the dev runtime.
#[test]
fn benchmark_storage_works() {
let tmp_dir = tempdir().expect("could not create a temp dir");
let base_path = tmp_dir.path();
// Benchmarking the storage works and creates the correct weight file.
assert!(benchmark_storage("rocksdb", base_path).success());
assert!(base_path.join("rocksdb_weights.rs").exists());
assert!(benchmark_storage("paritydb", base_path).success());
assert!(base_path.join("paritydb_weights.rs").exists());
}
fn benchmark_storage(db: &str, base_path: &Path) -> ExitStatus {
Command::new(cargo_bin("bizinikiwi-node"))
.args(&["benchmark", "storage", "--dev"])
.arg("--db")
.arg(db)
.arg("--weight-path")
.arg(base_path)
.args(["--state-version", "1"])
.args(["--batch-size", "1"])
.args(["--warmups", "0"])
.args(["--add", "100", "--mul", "1.2", "--metric", "p75"])
.arg("--include-child-trees")
.status()
.unwrap()
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -24,7 +24,7 @@ use tempfile::tempdir;
fn build_spec_works() {
let base_path = tempdir().expect("could not create a temp dir");
let output = Command::new(cargo_bin("substrate-node"))
let output = Command::new(cargo_bin("bizinikiwi-node"))
.args(&["build-spec", "--dev", "-d"])
.arg(base_path.path())
.output()
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -22,7 +22,7 @@ use assert_cmd::cargo::cargo_bin;
use std::process::Command;
use tempfile::tempdir;
use substrate_cli_test_utils as common;
use bizinikiwi_cli_test_utils as common;
#[tokio::test]
async fn check_block_works() {
@@ -30,7 +30,7 @@ async fn check_block_works() {
common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await;
let status = Command::new(cargo_bin("substrate-node"))
let status = Command::new(cargo_bin("bizinikiwi-node"))
.args(&["check-block", "--dev", "-d"])
.arg(base_path.path())
.arg("1")
+197
View File
@@ -0,0 +1,197 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use codec::{Decode, Encode};
use pezframe_support::Hashable;
use pezframe_system::offchain::AppCrypto;
use pezkuwi_sdk::*;
use pezsc_executor::error::Result;
use pezsp_consensus_babe::{
digests::{PreDigest, SecondaryPlainPreDigest},
Slot, BABE_ENGINE_ID,
};
use pezsp_core::{
crypto::KeyTypeId,
sr25519::Signature,
traits::{CallContext, CodeExecutor, RuntimeCode},
};
use pezsp_runtime::{
traits::{BlakeTwo256, Header as HeaderT},
ApplyExtrinsicResult, Digest, DigestItem, MultiSignature, MultiSigner,
};
use pezsp_state_machine::TestExternalities as CoreTestExternalities;
use kitchensink_runtime::{
constants::currency::*, Block, BuildStorage, CheckedExtrinsic, Header, Runtime,
UncheckedExtrinsic,
};
use node_primitives::{BlockNumber, Hash};
use node_testing::keyring::*;
use pezsp_externalities::Externalities;
use pezstaging_node_cli::service::RuntimeExecutor;
pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test");
pub mod sr25519 {
mod app_sr25519 {
use super::super::TEST_KEY_TYPE_ID;
use pezkuwi_sdk::pezsp_application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, TEST_KEY_TYPE_ID);
}
pub type AuthorityId = app_sr25519::Public;
}
pub struct TestAuthorityId;
impl AppCrypto<MultiSigner, MultiSignature> for TestAuthorityId {
type RuntimeAppPublic = sr25519::AuthorityId;
type GenericSignature = Signature;
type GenericPublic = pezsp_core::sr25519::Public;
}
/// The wasm runtime code.
///
/// `compact` since it is after post-processing with wasm-gc which performs tree-shaking thus
/// making the binary slimmer. There is a convention to use compact version of the runtime
/// as canonical.
pub fn compact_code_unwrap() -> &'static [u8] {
kitchensink_runtime::WASM_BINARY.expect(
"Development wasm binary is not available. Testing is only supported with the flag \
disabled.",
)
}
pub const GENESIS_HASH: [u8; 32] = [69u8; 32];
pub const SPEC_VERSION: u32 = kitchensink_runtime::VERSION.spec_version;
pub const TRANSACTION_VERSION: u32 = kitchensink_runtime::VERSION.transaction_version;
pub type TestExternalities<H> = CoreTestExternalities<H>;
pub fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH, None)
}
pub fn default_transfer_call() -> pezpallet_balances::Call<Runtime> {
pezpallet_balances::Call::<Runtime>::transfer_allow_death {
dest: bob().into(),
value: 69 * DOLLARS,
}
}
pub fn from_block_number(n: u32) -> Header {
Header::new(n, Default::default(), Default::default(), [69; 32].into(), Default::default())
}
pub fn executor() -> RuntimeExecutor {
RuntimeExecutor::builder().build()
}
pub fn executor_call(
t: &mut TestExternalities<BlakeTwo256>,
method: &str,
data: &[u8],
) -> (Result<Vec<u8>>, bool) {
let mut t = t.ext();
let code = t.storage(pezsp_core::storage::well_known_keys::CODE).unwrap();
let heap_pages = t.storage(pezsp_core::storage::well_known_keys::HEAP_PAGES);
let runtime_code = RuntimeCode {
code_fetcher: &pezsp_core::traits::WrappedRuntimeCode(code.as_slice().into()),
hash: pezsp_crypto_hashing::blake2_256(&code).to_vec(),
heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()),
};
pezsp_tracing::try_init_simple();
executor().call(&mut t, &runtime_code, method, data, CallContext::Onchain)
}
pub fn new_test_ext(code: &[u8]) -> TestExternalities<BlakeTwo256> {
pezsp_tracing::try_init_simple();
let ext = TestExternalities::new_with_code(
code,
node_testing::genesis::config().build_storage().unwrap(),
);
ext
}
/// Construct a fake block.
///
/// `extrinsics` must be a list of valid extrinsics, i.e. none of the extrinsics for example
/// can report `ExhaustResources`. Otherwise, this function panics.
pub fn construct_block(
env: &mut TestExternalities<BlakeTwo256>,
number: BlockNumber,
parent_hash: Hash,
extrinsics: Vec<CheckedExtrinsic>,
babe_slot: Slot,
) -> (Vec<u8>, Hash) {
use pezsp_trie::{LayoutV1 as Layout, TrieConfiguration};
// sign extrinsics.
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
// calculate the header fields that we can.
let extrinsics_root =
Layout::<BlakeTwo256>::ordered_trie_root(extrinsics.iter().map(Encode::encode))
.to_fixed_bytes()
.into();
let header = Header {
parent_hash,
number,
extrinsics_root,
state_root: Default::default(),
digest: Digest {
logs: vec![DigestItem::PreRuntime(
BABE_ENGINE_ID,
PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
slot: babe_slot,
authority_index: 42,
})
.encode(),
)],
},
};
// execute the block to get the real header.
executor_call(env, "Core_initialize_block", &header.encode()).0.unwrap();
for extrinsic in extrinsics.iter() {
// Try to apply the `extrinsic`. It should be valid, in the sense that it passes
// all pre-inclusion checks.
let r = executor_call(env, "BlockBuilder_apply_extrinsic", &extrinsic.encode())
.0
.expect("application of an extrinsic failed");
match ApplyExtrinsicResult::decode(&mut &r[..])
.expect("apply result deserialization failed")
{
Ok(_) => {},
Err(e) => panic!("Applying extrinsic failed: {:?}", e),
}
}
let header = Header::decode(
&mut &executor_call(env, "BlockBuilder_finalize_block", &[0u8; 0]).0.unwrap()[..],
)
.unwrap();
let hash = header.blake2_256();
(Block { header, extrinsics }.encode(), hash.into())
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -23,7 +23,7 @@ use regex::Regex;
use std::{fs, path::PathBuf, process::Command};
use tempfile::{tempdir, TempDir};
use substrate_cli_test_utils as common;
use bizinikiwi_cli_test_utils as common;
fn contains_error(logged_output: &str) -> bool {
logged_output.contains("Error")
@@ -96,7 +96,7 @@ impl<'a> ExportImportRevertExecutor<'a> {
};
// Running the command and capturing the output.
let output = Command::new(cargo_bin("substrate-node"))
let output = Command::new(cargo_bin("bizinikiwi-node"))
.args(&arguments)
.arg(&base_path)
.arg(&self.exported_blocks_file)
@@ -163,7 +163,7 @@ impl<'a> ExportImportRevertExecutor<'a> {
/// Runs the `revert` command.
fn run_revert(&self) {
let output = Command::new(cargo_bin("substrate-node"))
let output = Command::new(cargo_bin("bizinikiwi-node"))
.args(&["revert", "--dev", "-d"])
.arg(&self.base_path.path())
.output()
+193
View File
@@ -0,0 +1,193 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use codec::{Encode, Joiner};
use pezframe_support::{
dispatch::GetDispatchInfo,
traits::Currency,
weights::{constants::ExtrinsicBaseWeight, IdentityFee, WeightToFee},
};
use kitchensink_runtime::{
constants::{currency::*, time::SLOT_DURATION},
Balances, CheckedExtrinsic, Multiplier, Runtime, RuntimeCall, TransactionByteFee,
TransactionPayment,
};
use node_primitives::Balance;
use node_testing::keyring::*;
use pezkuwi_sdk::*;
use pezsp_runtime::{traits::One, Perbill};
pub mod common;
use self::common::{sign, *};
#[test]
fn fee_multiplier_increases_and_decreases_on_big_weight() {
let mut t = new_test_ext(compact_code_unwrap());
// initial fee multiplier must be one.
let mut prev_multiplier = Multiplier::one();
t.execute_with(|| {
assert_eq!(TransactionPayment::next_fee_multiplier(), prev_multiplier);
});
let mut tt = new_test_ext(compact_code_unwrap());
let time1 = 42 * 1000;
// big one in terms of weight.
let block1 = construct_block(
&mut tt,
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Bare,
function: RuntimeCall::Timestamp(pezpallet_timestamp::Call::set { now: time1 }),
},
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(0, 0)),
function: RuntimeCall::Sudo(pezpallet_sudo::Call::sudo {
call: Box::new(RuntimeCall::RootTesting(
pezpallet_root_testing::Call::fill_block { ratio: Perbill::from_percent(60) },
)),
}),
},
],
(time1 / SLOT_DURATION).into(),
);
let time2 = 52 * 1000;
// small one in terms of weight.
let block2 = construct_block(
&mut tt,
2,
block1.1,
vec![
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Bare,
function: RuntimeCall::Timestamp(pezpallet_timestamp::Call::set { now: time2 }),
},
CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(1, 0)),
function: RuntimeCall::System(pezframe_system::Call::remark { remark: vec![0; 1] }),
},
],
(time2 / SLOT_DURATION).into(),
);
println!(
"++ Block 1 size: {} / Block 2 size {}",
block1.0.encode().len(),
block2.0.encode().len(),
);
// execute a big block.
executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap();
// weight multiplier is increased for next block.
t.execute_with(|| {
let fm = TransactionPayment::next_fee_multiplier();
println!("After a big block: {:?} -> {:?}", prev_multiplier, fm);
assert!(fm > prev_multiplier);
prev_multiplier = fm;
});
// execute a big block.
executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap();
// weight multiplier is increased for next block.
t.execute_with(|| {
let fm = TransactionPayment::next_fee_multiplier();
println!("After a small block: {:?} -> {:?}", prev_multiplier, fm);
assert!(fm < prev_multiplier);
});
}
fn new_account_info(free_dollars: u128) -> Vec<u8> {
pezframe_system::AccountInfo {
nonce: 0u32,
consumers: 0,
providers: 1,
sufficients: 0,
data: (free_dollars * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 1u128 << 127),
}
.encode()
}
#[test]
fn transaction_fee_is_correct() {
// This uses the exact values of bizinikiwi-node.
//
// weight of transfer call as of now: 1_000_000
// if weight of the cheapest weight would be 10^7, this would be 10^9, which is:
// - 1 MILLICENTS in bizinikiwi node.
// - 1 milli-dot based on current pezkuwi runtime.
// (this based on assigning 0.1 CENT to the cheapest tx with `weight = 100`)
let mut t = new_test_ext(compact_code_unwrap());
t.insert(<pezframe_system::Account<Runtime>>::hashed_key_for(alice()), new_account_info(100));
t.insert(<pezframe_system::Account<Runtime>>::hashed_key_for(bob()), new_account_info(10));
t.insert(
<pezpallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(110 * DOLLARS).encode(),
);
t.insert(<pezframe_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let tip = 1_000_000;
let xt = sign(CheckedExtrinsic {
format: pezsp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, tip)),
function: RuntimeCall::Balances(default_transfer_call()),
});
let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0;
assert!(r.is_ok());
let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt.clone())).0;
assert!(r.is_ok());
t.execute_with(|| {
assert_eq!(Balances::total_balance(&bob()), (10 + 69) * DOLLARS);
// Components deducted from alice's balances:
// - Base fee
// - Weight fee
// - Length fee
// - Tip
// - Creation-fee of bob's account.
let mut balance_alice = (100 - 69) * DOLLARS;
let base_weight = ExtrinsicBaseWeight::get();
let base_fee = IdentityFee::<Balance>::weight_to_fee(&base_weight);
let length_fee = TransactionByteFee::get() * (xt.clone().encode().len() as Balance);
balance_alice -= length_fee;
let mut info = default_transfer_call().get_dispatch_info();
info.extension_weight = xt.0.extension_weight();
let weight = info.total_weight();
let weight_fee = IdentityFee::<Balance>::weight_to_fee(&weight);
// we know that weight to fee multiplier is effect-less in block 1.
// current weight of transfer = 200_000_000
// Linear weight to fee is 1:1 right now (1 weight = 1 unit of balance)
assert_eq!(weight_fee, weight.ref_time() as Balance);
balance_alice -= base_fee;
balance_alice -= weight_fee;
balance_alice -= tip;
assert_eq!(Balances::total_balance(&alice()), balance_alice);
});
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -22,7 +22,7 @@ use assert_cmd::cargo::cargo_bin;
use std::process::Command;
use tempfile::tempdir;
use substrate_cli_test_utils as common;
use bizinikiwi_cli_test_utils as common;
#[tokio::test]
async fn inspect_works() {
@@ -30,7 +30,7 @@ async fn inspect_works() {
common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await;
let status = Command::new(cargo_bin("substrate-node"))
let status = Command::new(cargo_bin("bizinikiwi-node"))
.args(&["inspect", "--dev", "-d"])
.arg(base_path.path())
.args(&["block", "1"])
@@ -0,0 +1,43 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use assert_cmd::cargo::cargo_bin;
use std::process::Command;
use tempfile::tempdir;
use bizinikiwi_cli_test_utils as common;
#[tokio::test]
#[cfg(unix)]
async fn purge_chain_works() {
let base_path = tempdir().expect("could not create a temp dir");
common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await;
let status = Command::new(cargo_bin("bizinikiwi-node"))
.args(&["purge-chain", "--dev", "-d"])
.arg(base_path.path())
.arg("-y")
.status()
.unwrap();
assert!(status.success());
// Make sure that the `dev` chain folder exists, but the `db` is deleted.
assert!(base_path.path().join("chains/dev/").exists());
assert!(!base_path.path().join("chains/dev/db/full").exists());
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -18,7 +18,7 @@
use tempfile::tempdir;
use substrate_cli_test_utils as common;
use bizinikiwi_cli_test_utils as common;
#[tokio::test]
#[cfg(unix)]
@@ -0,0 +1,89 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#![cfg(unix)]
use assert_cmd::cargo::cargo_bin;
use nix::sys::signal::Signal::{self, SIGINT, SIGTERM};
use std::{
process::{self, Command},
time::Duration,
};
use tempfile::tempdir;
use bizinikiwi_cli_test_utils as common;
#[tokio::test]
async fn running_the_node_works_and_can_be_interrupted() {
common::run_with_timeout(Duration::from_secs(60 * 10), async move {
async fn run_command_and_kill(signal: Signal) {
let base_path = tempdir().expect("could not create a temp dir");
let mut cmd = common::KillChildOnDrop(
Command::new(cargo_bin("bizinikiwi-node"))
.stdout(process::Stdio::piped())
.stderr(process::Stdio::piped())
.args(&["--dev", "-d"])
.arg(base_path.path())
.arg("--db=paritydb")
.arg("--no-hardware-benchmarks")
.spawn()
.unwrap(),
);
let stderr = cmd.stderr.take().unwrap();
let ws_url = common::extract_info_from_output(stderr).0.ws_url;
common::wait_n_finalized_blocks(3, &ws_url).await;
cmd.assert_still_running();
cmd.stop_with_signal(signal);
// Check if the database was closed gracefully. If it was not,
// there may exist a ref cycle that prevents the Client from being dropped properly.
//
// parity-db only writes the stats file on clean shutdown.
let stats_file = base_path.path().join("chains/dev/paritydb/full/stats.txt");
assert!(std::path::Path::exists(&stats_file));
}
run_command_and_kill(SIGINT).await;
run_command_and_kill(SIGTERM).await;
})
.await;
}
#[tokio::test]
async fn running_two_nodes_with_the_same_ws_port_should_work() {
common::run_with_timeout(Duration::from_secs(60 * 10), async move {
let mut first_node = common::KillChildOnDrop(common::start_node());
let mut second_node = common::KillChildOnDrop(common::start_node());
let stderr = first_node.stderr.take().unwrap();
let ws_url = common::extract_info_from_output(stderr).0.ws_url;
common::wait_n_finalized_blocks(3, &ws_url).await;
first_node.assert_still_running();
second_node.assert_still_running();
first_node.stop();
second_node.stop();
})
.await;
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -17,14 +17,14 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use codec::Decode;
use frame_system::offchain::{SendSignedTransaction, Signer, SubmitTransaction};
use pezframe_system::offchain::{SendSignedTransaction, Signer, SubmitTransaction};
use kitchensink_runtime::{Executive, ExistentialDeposit, Indices, Runtime, UncheckedExtrinsic};
use pezkuwi_sdk::*;
use sp_application_crypto::AppCrypto;
use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt};
use sp_keyring::sr25519::Keyring::Alice;
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt};
use sp_runtime::generic;
use pezsp_application_crypto::AppCrypto;
use pezsp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt};
use pezsp_keyring::sr25519::Keyring::Alice;
use pezsp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt};
use pezsp_runtime::generic;
pub mod common;
use self::common::*;
@@ -37,17 +37,17 @@ fn should_submit_unsigned_transaction() {
t.execute_with(|| {
let signature =
pallet_im_online::sr25519::AuthoritySignature::try_from(vec![0; 64]).unwrap();
let heartbeat_data = pallet_im_online::Heartbeat {
pezpallet_im_online::sr25519::AuthoritySignature::try_from(vec![0; 64]).unwrap();
let heartbeat_data = pezpallet_im_online::Heartbeat {
block_number: 1,
session_index: 1,
authority_index: 0,
validators_len: 0,
};
let call = pallet_im_online::Call::heartbeat { heartbeat: heartbeat_data, signature };
let call = pezpallet_im_online::Call::heartbeat { heartbeat: heartbeat_data, signature };
let xt = generic::UncheckedExtrinsic::new_bare(call.into()).into();
SubmitTransaction::<Runtime, pallet_im_online::Call<Runtime>>::submit_transaction(xt)
SubmitTransaction::<Runtime, pezpallet_im_online::Call<Runtime>>::submit_transaction(xt)
.unwrap();
assert_eq!(state.read().transactions.len(), 1)
@@ -77,7 +77,7 @@ fn should_submit_signed_transaction() {
t.execute_with(|| {
let results =
Signer::<Runtime, TestAuthorityId>::all_accounts().send_signed_transaction(|_| {
pallet_balances::Call::transfer_allow_death {
pezpallet_balances::Call::transfer_allow_death {
dest: Alice.to_account_id().into(),
value: Default::default(),
}
@@ -108,7 +108,7 @@ fn should_submit_signed_twice_from_the_same_account() {
t.execute_with(|| {
let result =
Signer::<Runtime, TestAuthorityId>::any_account().send_signed_transaction(|_| {
pallet_balances::Call::transfer_allow_death {
pezpallet_balances::Call::transfer_allow_death {
dest: Alice.to_account_id().into(),
value: Default::default(),
}
@@ -120,7 +120,7 @@ fn should_submit_signed_twice_from_the_same_account() {
// submit another one from the same account. The nonce should be incremented.
let result =
Signer::<Runtime, TestAuthorityId>::any_account().send_signed_transaction(|_| {
pallet_balances::Call::transfer_allow_death {
pezpallet_balances::Call::transfer_allow_death {
dest: Alice.to_account_id().into(),
value: Default::default(),
}
@@ -131,7 +131,7 @@ fn should_submit_signed_twice_from_the_same_account() {
// now check that the transaction nonces are not equal
let s = state.read();
fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce<Runtime> {
fn nonce(tx: UncheckedExtrinsic) -> pezframe_system::CheckNonce<Runtime> {
let extra = tx.0.preamble.to_signed().unwrap().2;
extra.6
}
@@ -159,7 +159,7 @@ fn should_submit_signed_twice_from_all_accounts() {
t.execute_with(|| {
let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
.send_signed_transaction(|_| {
pallet_balances::Call::transfer_allow_death { dest: Alice.to_account_id().into(), value: Default::default() }
pezpallet_balances::Call::transfer_allow_death { dest: Alice.to_account_id().into(), value: Default::default() }
});
let len = results.len();
@@ -170,7 +170,7 @@ fn should_submit_signed_twice_from_all_accounts() {
// submit another one from the same account. The nonce should be incremented.
let results = Signer::<Runtime, TestAuthorityId>::all_accounts()
.send_signed_transaction(|_| {
pallet_balances::Call::transfer_allow_death { dest: Alice.to_account_id().into(), value: Default::default() }
pezpallet_balances::Call::transfer_allow_death { dest: Alice.to_account_id().into(), value: Default::default() }
});
let len = results.len();
@@ -180,7 +180,7 @@ fn should_submit_signed_twice_from_all_accounts() {
// now check that the transaction nonces are not equal
let s = state.read();
fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce<Runtime> {
fn nonce(tx: UncheckedExtrinsic) -> pezframe_system::CheckNonce<Runtime> {
let extra = tx.0.preamble.to_signed().unwrap().2;
extra.6
}
@@ -202,7 +202,7 @@ fn should_submit_signed_twice_from_all_accounts() {
#[test]
fn submitted_transaction_should_be_valid() {
use codec::Encode;
use sp_runtime::{
use pezsp_runtime::{
traits::StaticLookup,
transaction_validity::{TransactionSource, TransactionTag},
};
@@ -220,7 +220,7 @@ fn submitted_transaction_should_be_valid() {
t.execute_with(|| {
let results =
Signer::<Runtime, TestAuthorityId>::all_accounts().send_signed_transaction(|_| {
pallet_balances::Call::transfer_allow_death {
pezpallet_balances::Call::transfer_allow_death {
dest: Alice.to_account_id().into(),
value: Default::default(),
}
@@ -240,18 +240,18 @@ fn submitted_transaction_should_be_valid() {
// add balance to the account
let author = extrinsic.0.preamble.clone().to_signed().clone().unwrap().0;
let address = Indices::lookup(author).unwrap();
let data = pallet_balances::AccountData {
let data = pezpallet_balances::AccountData {
free: ExistentialDeposit::get() * 10,
..Default::default()
};
let account = frame_system::AccountInfo { providers: 1, data, ..Default::default() };
<frame_system::Account<Runtime>>::insert(&address, account);
let account = pezframe_system::AccountInfo { providers: 1, data, ..Default::default() };
<pezframe_system::Account<Runtime>>::insert(&address, account);
// check validity
let res = Executive::validate_transaction(
source,
extrinsic,
frame_system::BlockHash::<Runtime>::get(0),
pezframe_system::BlockHash::<Runtime>::get(0),
)
.unwrap();
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -21,7 +21,7 @@ use std::{process, time::Duration};
use crate::common::KillChildOnDrop;
use substrate_cli_test_utils as common;
use bizinikiwi_cli_test_utils as common;
pub mod websocket_server;
#[tokio::test]
@@ -67,10 +67,10 @@ async fn telemetry_works() {
}
});
let mut substrate = process::Command::new(cargo_bin("substrate-node"));
let mut bizinikiwi = process::Command::new(cargo_bin("bizinikiwi-node"));
let mut substrate = KillChildOnDrop(
substrate
let mut bizinikiwi = KillChildOnDrop(
bizinikiwi
.args(&["--dev", "--tmp", "--telemetry-url"])
.arg(format!("ws://{} 10", addr))
.arg("--no-hardware-benchmarks")
@@ -83,10 +83,10 @@ async fn telemetry_works() {
server_task.await.expect("server task panicked");
substrate.assert_still_running();
bizinikiwi.assert_still_running();
// Stop the process
substrate.stop();
bizinikiwi.stop();
})
.await;
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -24,14 +24,14 @@ use std::{
time::Duration,
};
use substrate_cli_test_utils as common;
use bizinikiwi_cli_test_utils as common;
#[allow(dead_code)]
// Apparently `#[ignore]` doesn't actually work to disable this one.
//#[tokio::test]
async fn temp_base_path_works() {
common::run_with_timeout(Duration::from_secs(60 * 10), async move {
let mut cmd = Command::new(cargo_bin("substrate-node"));
let mut cmd = Command::new(cargo_bin("bizinikiwi-node"));
let mut child = common::KillChildOnDrop(
cmd.args(&["--dev", "--tmp", "--no-hardware-benchmarks"])
.stdout(Stdio::piped())
+51
View File
@@ -0,0 +1,51 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use assert_cmd::cargo::cargo_bin;
use regex::Regex;
use std::process::Command;
fn expected_regex() -> Regex {
Regex::new(r"^bizinikiwi-node (.+)-([a-f\d]+)$").unwrap()
}
#[test]
fn version_is_full() {
let expected = expected_regex();
let output = Command::new(cargo_bin("bizinikiwi-node")).args(&["--version"]).output().unwrap();
assert!(output.status.success(), "command returned with non-success exit code");
let output = dbg!(String::from_utf8_lossy(&output.stdout).trim().to_owned());
let captures = expected.captures(output.as_str()).expect("could not parse version in output");
assert_eq!(&captures[1], env!("CARGO_PKG_VERSION"));
}
#[test]
fn test_regex_matches_properly() {
let expected = expected_regex();
let captures = expected.captures("bizinikiwi-node 2.0.0-da487d19d").unwrap();
assert_eq!(&captures[1], "2.0.0");
assert_eq!(&captures[2], "da487d19d");
let captures = expected.captures("bizinikiwi-node 2.0.0-alpha.5-da487d19d").unwrap();
assert_eq!(&captures[1], "2.0.0-alpha.5");
assert_eq!(&captures[2], "da487d19d");
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+39
View File
@@ -0,0 +1,39 @@
[package]
name = "pezstaging-node-inspect"
version = "0.12.0"
authors.workspace = true
description = "Bizinikiwi node block inspection tool."
edition.workspace = true
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
homepage.workspace = true
repository.workspace = true
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
clap = { features = ["derive"], workspace = true }
codec = { workspace = true, default-features = true }
pezsc-cli = { workspace = true }
pezsc-client-api = { workspace = true, default-features = true }
pezsc-service = { workspace = true }
pezsp-blockchain = { workspace = true, default-features = true }
pezsp-core = { workspace = true, default-features = true }
pezsp-io = { workspace = true, default-features = true }
pezsp-runtime = { workspace = true, default-features = true }
pezsp-statement-store = { workspace = true, default-features = true }
thiserror = { workspace = true }
[features]
runtime-benchmarks = [
"pezsc-cli/runtime-benchmarks",
"pezsc-client-api/runtime-benchmarks",
"pezsc-service/runtime-benchmarks",
"pezsp-blockchain/runtime-benchmarks",
"pezsp-io/runtime-benchmarks",
"pezsp-runtime/runtime-benchmarks",
"pezsp-statement-store/runtime-benchmarks",
]
+62
View File
@@ -0,0 +1,62 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Structs to easily compose inspect sub-command for CLI.
use pezsc_cli::{ImportParams, SharedParams};
/// The `inspect` command used to print decoded chain data.
#[derive(Debug, clap::Parser)]
pub struct InspectCmd {
#[allow(missing_docs)]
#[clap(subcommand)]
pub command: InspectSubCmd,
#[allow(missing_docs)]
#[clap(flatten)]
pub shared_params: SharedParams,
#[allow(missing_docs)]
#[clap(flatten)]
pub import_params: ImportParams,
}
/// A possible inspect sub-commands.
#[derive(Debug, clap::Subcommand)]
pub enum InspectSubCmd {
/// Decode block with native version of runtime and print out the details.
Block {
/// Address of the block to print out.
///
/// Can be either a block hash (no 0x prefix) or a number to retrieve existing block,
/// or a 0x-prefixed bytes hex string, representing SCALE encoding of
/// a block.
#[arg(value_name = "HASH or NUMBER or BYTES")]
input: String,
},
/// Decode extrinsic with native version of runtime and print out the details.
Extrinsic {
/// Address of an extrinsic to print out.
///
/// Can be either a block hash (no 0x prefix) or number and the index, in the form
/// of `{block}:{index}` or a 0x-prefixed bytes hex string,
/// representing SCALE encoding of an extrinsic.
#[arg(value_name = "BLOCK:INDEX or BYTES")]
input: String,
},
}
@@ -0,0 +1,68 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Command ran by the CLI
use crate::{
cli::{InspectCmd, InspectSubCmd},
Inspector,
};
use pezsc_cli::{CliConfiguration, ImportParams, Result, SharedParams};
use pezsc_service::Configuration;
use pezsp_runtime::traits::Block;
type HostFunctions =
(pezsp_io::BizinikiwiHostFunctions, pezsp_statement_store::runtime_api::HostFunctions);
impl InspectCmd {
/// Run the inspect command, passing the inspector.
pub fn run<B, RA>(&self, config: Configuration) -> Result<()>
where
B: Block,
RA: Send + Sync + 'static,
{
let executor = pezsc_service::new_wasm_executor::<HostFunctions>(&config.executor);
let client = pezsc_service::new_full_client::<B, RA, _>(&config, None, executor)?;
let inspect = Inspector::<B>::new(client);
match &self.command {
InspectSubCmd::Block { input } => {
let input = input.parse()?;
let res = inspect.block(input).map_err(|e| e.to_string())?;
println!("{res}");
Ok(())
},
InspectSubCmd::Extrinsic { input } => {
let input = input.parse()?;
let res = inspect.extrinsic(input).map_err(|e| e.to_string())?;
println!("{res}");
Ok(())
},
}
}
}
impl CliConfiguration for InspectCmd {
fn shared_params(&self) -> &SharedParams {
&self.shared_params
}
fn import_params(&self) -> Option<&ImportParams> {
Some(&self.import_params)
}
}
+311
View File
@@ -0,0 +1,311 @@
// This file is part of Bizinikiwi.
//
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! A CLI extension for bizinikiwi node, adding sub-command to pretty print debug info
//! about blocks and extrinsics.
//!
//! The blocks and extrinsics can either be retrieved from the database (on-chain),
//! or a raw SCALE-encoding can be provided.
#![warn(missing_docs)]
pub mod cli;
pub mod command;
use codec::{Decode, Encode};
use pezsc_client_api::BlockBackend;
use pezsp_blockchain::HeaderBackend;
use pezsp_core::hexdisplay::HexDisplay;
use pezsp_runtime::{
generic::BlockId,
traits::{Block, Hash, HashingFor, NumberFor},
};
use std::{fmt, fmt::Debug, marker::PhantomData, str::FromStr};
/// A helper type for a generic block input.
pub type BlockAddressFor<TBlock> =
BlockAddress<<HashingFor<TBlock> as Hash>::Output, NumberFor<TBlock>>;
/// A Pretty formatter implementation.
pub trait PrettyPrinter<TBlock: Block> {
/// Nicely format block.
fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result;
/// Nicely format extrinsic.
fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic)
-> fmt::Result;
}
/// Default dummy debug printer.
#[derive(Default)]
pub struct DebugPrinter;
impl<TBlock: Block> PrettyPrinter<TBlock> for DebugPrinter {
fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result {
writeln!(fmt, "Header:")?;
writeln!(fmt, "{:?}", block.header())?;
writeln!(fmt, "Block bytes: {:?}", HexDisplay::from(&block.encode()))?;
writeln!(fmt, "Extrinsics ({})", block.extrinsics().len())?;
for (idx, ex) in block.extrinsics().iter().enumerate() {
writeln!(fmt, "- {}:", idx)?;
<DebugPrinter as PrettyPrinter<TBlock>>::fmt_extrinsic(self, fmt, ex)?;
}
Ok(())
}
fn fmt_extrinsic(
&self,
fmt: &mut fmt::Formatter,
extrinsic: &TBlock::Extrinsic,
) -> fmt::Result {
writeln!(fmt, " {:#?}", extrinsic)?;
writeln!(fmt, " Bytes: {:?}", HexDisplay::from(&extrinsic.encode()))?;
Ok(())
}
}
/// Aggregated error for `Inspector` operations.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Could not decode Block or Extrinsic.
#[error(transparent)]
Codec(#[from] codec::Error),
/// Error accessing blockchain DB.
#[error(transparent)]
Blockchain(#[from] pezsp_blockchain::Error),
/// Given block has not been found.
#[error("{0}")]
NotFound(String),
}
/// A helper trait to access block headers and bodies.
pub trait ChainAccess<TBlock: Block>: HeaderBackend<TBlock> + BlockBackend<TBlock> {}
impl<T, TBlock> ChainAccess<TBlock> for T
where
TBlock: Block,
T: pezsp_blockchain::HeaderBackend<TBlock> + pezsc_client_api::BlockBackend<TBlock>,
{
}
/// Blockchain inspector.
pub struct Inspector<TBlock: Block, TPrinter: PrettyPrinter<TBlock> = DebugPrinter> {
printer: TPrinter,
chain: Box<dyn ChainAccess<TBlock>>,
_block: PhantomData<TBlock>,
}
impl<TBlock: Block, TPrinter: PrettyPrinter<TBlock>> Inspector<TBlock, TPrinter> {
/// Create new instance of the inspector with default printer.
pub fn new(chain: impl ChainAccess<TBlock> + 'static) -> Self
where
TPrinter: Default,
{
Self::with_printer(chain, Default::default())
}
/// Customize pretty-printing of the data.
pub fn with_printer(chain: impl ChainAccess<TBlock> + 'static, printer: TPrinter) -> Self {
Inspector { chain: Box::new(chain) as _, printer, _block: Default::default() }
}
/// Get a pretty-printed block.
pub fn block(&self, input: BlockAddressFor<TBlock>) -> Result<String, Error> {
struct BlockPrinter<'a, A, B>(A, &'a B);
impl<'a, A: Block, B: PrettyPrinter<A>> fmt::Display for BlockPrinter<'a, A, B> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.1.fmt_block(fmt, &self.0)
}
}
let block = self.get_block(input)?;
Ok(format!("{}", BlockPrinter(block, &self.printer)))
}
fn get_block(&self, input: BlockAddressFor<TBlock>) -> Result<TBlock, Error> {
Ok(match input {
BlockAddress::Bytes(bytes) => TBlock::decode(&mut &*bytes)?,
BlockAddress::Number(number) => {
let id = BlockId::number(number);
let hash = self.chain.expect_block_hash_from_id(&id)?;
let not_found = format!("Could not find block {:?}", id);
let body = self
.chain
.block_body(hash)?
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
let header =
self.chain.header(hash)?.ok_or_else(|| Error::NotFound(not_found.clone()))?;
TBlock::new(header, body)
},
BlockAddress::Hash(hash) => {
let not_found = format!("Could not find block {:?}", BlockId::<TBlock>::Hash(hash));
let body = self
.chain
.block_body(hash)?
.ok_or_else(|| Error::NotFound(not_found.clone()))?;
let header =
self.chain.header(hash)?.ok_or_else(|| Error::NotFound(not_found.clone()))?;
TBlock::new(header, body)
},
})
}
/// Get a pretty-printed extrinsic.
pub fn extrinsic(
&self,
input: ExtrinsicAddress<<HashingFor<TBlock> as Hash>::Output, NumberFor<TBlock>>,
) -> Result<String, Error> {
struct ExtrinsicPrinter<'a, A: Block, B>(A::Extrinsic, &'a B);
impl<'a, A: Block, B: PrettyPrinter<A>> fmt::Display for ExtrinsicPrinter<'a, A, B> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.1.fmt_extrinsic(fmt, &self.0)
}
}
let ext = match input {
ExtrinsicAddress::Block(block, index) => {
let block = self.get_block(block)?;
block.extrinsics().get(index).cloned().ok_or_else(|| {
Error::NotFound(format!(
"Could not find extrinsic {} in block {:?}",
index, block
))
})?
},
ExtrinsicAddress::Bytes(bytes) => TBlock::Extrinsic::decode(&mut &*bytes)?,
};
Ok(format!("{}", ExtrinsicPrinter(ext, &self.printer)))
}
}
/// A block to retrieve.
#[derive(Debug, Clone, PartialEq)]
pub enum BlockAddress<Hash, Number> {
/// Get block by hash.
Hash(Hash),
/// Get block by number.
Number(Number),
/// Raw SCALE-encoded bytes.
Bytes(Vec<u8>),
}
impl<Hash: FromStr, Number: FromStr> FromStr for BlockAddress<Hash, Number> {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
// try to parse hash first
if let Ok(hash) = s.parse() {
return Ok(Self::Hash(hash));
}
// then number
if let Ok(number) = s.parse() {
return Ok(Self::Number(number));
}
// then assume it's bytes (hex-encoded)
pezsp_core::bytes::from_hex(s).map(Self::Bytes).map_err(|e| {
format!(
"Given string does not look like hash or number. It could not be parsed as bytes either: {}",
e
)
})
}
}
/// An extrinsic address to decode and print out.
#[derive(Debug, Clone, PartialEq)]
pub enum ExtrinsicAddress<Hash, Number> {
/// Extrinsic as part of existing block.
Block(BlockAddress<Hash, Number>, usize),
/// Raw SCALE-encoded extrinsic bytes.
Bytes(Vec<u8>),
}
impl<Hash: FromStr + Debug, Number: FromStr + Debug> FromStr for ExtrinsicAddress<Hash, Number> {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
// first try raw bytes
if let Ok(bytes) = pezsp_core::bytes::from_hex(s).map(Self::Bytes) {
return Ok(bytes);
}
// split by a bunch of different characters
let mut it = s.split(|c| c == '.' || c == ':' || c == ' ');
let block = it
.next()
.expect("First element of split iterator is never empty; qed")
.parse()?;
let index = it
.next()
.ok_or("Extrinsic index missing: example \"5:0\"")?
.parse()
.map_err(|e| format!("Invalid index format: {}", e))?;
Ok(Self::Block(block, index))
}
}
#[cfg(test)]
mod tests {
use super::*;
use pezsp_core::hash::H160 as Hash;
#[test]
fn should_parse_block_strings() {
type BlockAddress = super::BlockAddress<Hash, u64>;
let b0 = BlockAddress::from_str("3BfC20f0B9aFcAcE800D73D2191166FF16540258");
let b1 = BlockAddress::from_str("1234");
let b2 = BlockAddress::from_str("0");
let b3 = BlockAddress::from_str("0x0012345f");
assert_eq!(
b0,
Ok(BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()))
);
assert_eq!(b1, Ok(BlockAddress::Number(1234)));
assert_eq!(b2, Ok(BlockAddress::Number(0)));
assert_eq!(b3, Ok(BlockAddress::Bytes(vec![0, 0x12, 0x34, 0x5f])));
}
#[test]
fn should_parse_extrinsic_address() {
type BlockAddress = super::BlockAddress<Hash, u64>;
type ExtrinsicAddress = super::ExtrinsicAddress<Hash, u64>;
let e0 = ExtrinsicAddress::from_str("1234");
let b0 = ExtrinsicAddress::from_str("3BfC20f0B9aFcAcE800D73D2191166FF16540258:5");
let b1 = ExtrinsicAddress::from_str("1234:0");
let b2 = ExtrinsicAddress::from_str("0 0");
let b3 = ExtrinsicAddress::from_str("0x0012345f");
assert_eq!(e0, Ok(ExtrinsicAddress::Bytes(vec![0x12, 0x34])));
assert_eq!(
b0,
Ok(ExtrinsicAddress::Block(
BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()),
5
))
);
assert_eq!(b1, Ok(ExtrinsicAddress::Block(BlockAddress::Number(1234), 0)));
assert_eq!(b2, Ok(ExtrinsicAddress::Bytes(vec![0, 0])));
assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f])));
}
}
+25
View File
@@ -0,0 +1,25 @@
[package]
name = "node-primitives"
version = "2.0.0"
authors.workspace = true
description = "Bizinikiwi node low-level primitives."
edition.workspace = true
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
publish = false
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
pezsp-core = { workspace = true }
pezsp-runtime = { workspace = true }
[features]
default = ["std"]
std = ["pezsp-core/std", "pezsp-runtime/std"]
runtime-benchmarks = ["pezsp-runtime/runtime-benchmarks"]
+66
View File
@@ -0,0 +1,66 @@
// This file is part of Bizinikiwi.
// Copyright (C) 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.
//! Low-level types used throughout the Bizinikiwi code.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
use pezsp_runtime::{
generic,
traits::{BlakeTwo256, IdentifyAccount, Verify},
MultiSignature, OpaqueExtrinsic,
};
/// An index to a block.
pub type BlockNumber = u32;
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = MultiSignature;
/// Some way of identifying an account on the chain. We intentionally make it equivalent
/// to the public key of our transaction signing scheme.
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
/// The type for looking up accounts. We don't expect more than 4 billion of them.
pub type AccountIndex = u32;
/// Balance of an account.
pub type Balance = u128;
/// Type used for expressing timestamp.
pub type Moment = u64;
/// Index of a transaction in the chain.
pub type Nonce = u32;
/// A hash of some data used by the chain.
pub type Hash = pezsp_core::H256;
/// A timestamp: milliseconds since the unix epoch.
/// `u64` is enough to represent a duration of half a billion years, when the
/// time scale is milliseconds.
pub type Timestamp = u64;
/// Digest item type.
pub type DigestItem = generic::DigestItem;
/// Header type.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Block type.
pub type Block = generic::Block<Header, OpaqueExtrinsic>;
/// Block ID.
pub type BlockId = generic::BlockId<Block>;
+75
View File
@@ -0,0 +1,75 @@
[package]
name = "node-rpc"
version = "3.0.0-dev"
authors.workspace = true
description = "Bizinikiwi node rpc methods."
edition.workspace = true
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
publish = false
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
jsonrpsee = { features = ["server"], workspace = true }
mmr-rpc = { workspace = true, default-features = true }
node-primitives = { workspace = true, default-features = true }
pezpallet-transaction-payment-rpc = { workspace = true, default-features = true }
pezsc-chain-spec = { workspace = true, default-features = true }
pezsc-client-api = { workspace = true, default-features = true }
pezsc-consensus-babe = { workspace = true, default-features = true }
pezsc-consensus-babe-rpc = { workspace = true, default-features = true }
pezsc-consensus-beefy = { workspace = true, default-features = true }
pezsc-consensus-beefy-rpc = { workspace = true, default-features = true }
pezsc-consensus-grandpa = { workspace = true, default-features = true }
pezsc-consensus-grandpa-rpc = { workspace = true, default-features = true }
pezsc-mixnet = { workspace = true, default-features = true }
pezsc-rpc = { workspace = true, default-features = true }
pezsc-sync-state-rpc = { workspace = true, default-features = true }
pezsc-transaction-pool-api = { workspace = true, default-features = true }
pezsp-api = { workspace = true, default-features = true }
pezsp-application-crypto = { workspace = true, default-features = true }
pezsp-block-builder = { workspace = true, default-features = true }
pezsp-blockchain = { workspace = true, default-features = true }
pezsp-consensus = { workspace = true, default-features = true }
pezsp-consensus-babe = { workspace = true, default-features = true }
pezsp-consensus-beefy = { workspace = true, default-features = true }
pezsp-keystore = { workspace = true, default-features = true }
pezsp-runtime = { workspace = true, default-features = true }
pezsp-statement-store = { workspace = true, default-features = true }
bizinikiwi-frame-rpc-system = { workspace = true, default-features = true }
bizinikiwi-state-trie-migration-rpc = { workspace = true, default-features = true }
[features]
runtime-benchmarks = [
"mmr-rpc/runtime-benchmarks",
"node-primitives/runtime-benchmarks",
"pezpallet-transaction-payment-rpc/runtime-benchmarks",
"pezsc-chain-spec/runtime-benchmarks",
"pezsc-client-api/runtime-benchmarks",
"pezsc-consensus-babe-rpc/runtime-benchmarks",
"pezsc-consensus-babe/runtime-benchmarks",
"pezsc-consensus-beefy-rpc/runtime-benchmarks",
"pezsc-consensus-beefy/runtime-benchmarks",
"pezsc-consensus-grandpa-rpc/runtime-benchmarks",
"pezsc-consensus-grandpa/runtime-benchmarks",
"pezsc-mixnet/runtime-benchmarks",
"pezsc-rpc/runtime-benchmarks",
"pezsc-sync-state-rpc/runtime-benchmarks",
"pezsc-transaction-pool-api/runtime-benchmarks",
"pezsp-api/runtime-benchmarks",
"pezsp-block-builder/runtime-benchmarks",
"pezsp-blockchain/runtime-benchmarks",
"pezsp-consensus-babe/runtime-benchmarks",
"pezsp-consensus-beefy/runtime-benchmarks",
"pezsp-consensus/runtime-benchmarks",
"pezsp-runtime/runtime-benchmarks",
"pezsp-statement-store/runtime-benchmarks",
"bizinikiwi-frame-rpc-system/runtime-benchmarks",
"bizinikiwi-state-trie-migration-rpc/runtime-benchmarks",
]
+227
View File
@@ -0,0 +1,227 @@
// This file is part of Bizinikiwi.
// Copyright (C) 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.
//! A collection of node-specific RPC methods.
//!
//! Since `bizinikiwi` core functionality makes no assumptions
//! about the modules used inside the runtime, so do
//! RPC methods defined in `sc-rpc` crate.
//! It means that `client/rpc` can't have any methods that
//! need some strong assumptions about the particular runtime.
//!
//! The RPCs available in this crate however can make some assumptions
//! about how the runtime is constructed and what FRAME pallets
//! are part of it. Therefore all node-runtime-specific RPCs can
//! be placed here or imported from corresponding FRAME RPC definitions.
#![warn(missing_docs)]
#![warn(unused_crate_dependencies)]
use std::sync::Arc;
use jsonrpsee::RpcModule;
use node_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Nonce};
use pezsc_client_api::AuxStore;
use pezsc_consensus_babe::BabeWorkerHandle;
use pezsc_consensus_beefy::communication::notification::{
BeefyBestBlockStream, BeefyVersionedFinalityProofStream,
};
use pezsc_consensus_grandpa::{
FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState,
};
pub use pezsc_rpc::SubscriptionTaskExecutor;
use pezsc_transaction_pool_api::TransactionPool;
use pezsp_api::ProvideRuntimeApi;
use pezsp_application_crypto::RuntimeAppPublic;
use pezsp_block_builder::BlockBuilder;
use pezsp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
use pezsp_consensus::SelectChain;
use pezsp_consensus_babe::BabeApi;
use pezsp_consensus_beefy::AuthorityIdBound;
use pezsp_keystore::KeystorePtr;
/// Extra dependencies for BABE.
pub struct BabeDeps {
/// A handle to the BABE worker for issuing requests.
pub babe_worker_handle: BabeWorkerHandle<Block>,
/// The keystore that manages the keys of the node.
pub keystore: KeystorePtr,
}
/// Extra dependencies for GRANDPA
pub struct GrandpaDeps<B> {
/// Voting round info.
pub shared_voter_state: SharedVoterState,
/// Authority set info.
pub shared_authority_set: SharedAuthoritySet<Hash, BlockNumber>,
/// Receives notifications about justification events from Grandpa.
pub justification_stream: GrandpaJustificationStream<Block>,
/// Executor to drive the subscription manager in the Grandpa RPC handler.
pub subscription_executor: SubscriptionTaskExecutor,
/// Finality proof provider.
pub finality_provider: Arc<FinalityProofProvider<B, Block>>,
}
/// Dependencies for BEEFY
pub struct BeefyDeps<AuthorityId: AuthorityIdBound> {
/// Receives notifications about finality proof events from BEEFY.
pub beefy_finality_proof_stream: BeefyVersionedFinalityProofStream<Block, AuthorityId>,
/// Receives notifications about best block events from BEEFY.
pub beefy_best_block_stream: BeefyBestBlockStream<Block>,
/// Executor to drive the subscription manager in the BEEFY RPC handler.
pub subscription_executor: SubscriptionTaskExecutor,
}
/// Full client dependencies.
pub struct FullDeps<C, P, SC, B, AuthorityId: AuthorityIdBound> {
/// The client instance to use.
pub client: Arc<C>,
/// Transaction pool instance.
pub pool: Arc<P>,
/// The SelectChain Strategy
pub select_chain: SC,
/// A copy of the chain spec.
pub chain_spec: Box<dyn pezsc_chain_spec::ChainSpec>,
/// BABE specific dependencies.
pub babe: BabeDeps,
/// GRANDPA specific dependencies.
pub grandpa: GrandpaDeps<B>,
/// BEEFY specific dependencies.
pub beefy: BeefyDeps<AuthorityId>,
/// Shared statement store reference.
pub statement_store: Arc<dyn pezsp_statement_store::StatementStore>,
/// The backend used by the node.
pub backend: Arc<B>,
/// Mixnet API.
pub mixnet_api: Option<pezsc_mixnet::Api>,
}
/// Instantiate all Full RPC extensions.
pub fn create_full<C, P, SC, B, AuthorityId>(
FullDeps {
client,
pool,
select_chain,
chain_spec,
babe,
grandpa,
beefy,
statement_store,
backend,
mixnet_api,
}: FullDeps<C, P, SC, B, AuthorityId>,
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
where
C: ProvideRuntimeApi<Block>
+ pezsc_client_api::BlockBackend<Block>
+ HeaderBackend<Block>
+ AuxStore
+ HeaderMetadata<Block, Error = BlockChainError>
+ Sync
+ Send
+ 'static,
C::Api: bizinikiwi_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>,
C::Api: mmr_rpc::MmrRuntimeApi<Block, <Block as pezsp_runtime::traits::Block>::Hash, BlockNumber>,
C::Api: pezpallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
C::Api: BabeApi<Block>,
C::Api: BlockBuilder<Block>,
P: TransactionPool + 'static,
SC: SelectChain<Block> + 'static,
B: pezsc_client_api::Backend<Block> + Send + Sync + 'static,
B::State: pezsc_client_api::backend::StateBackend<pezsp_runtime::traits::HashingFor<Block>>,
AuthorityId: AuthorityIdBound,
<AuthorityId as RuntimeAppPublic>::Signature: Send + Sync,
{
use mmr_rpc::{Mmr, MmrApiServer};
use pezpallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
use pezsc_consensus_babe_rpc::{Babe, BabeApiServer};
use pezsc_consensus_beefy_rpc::{Beefy, BeefyApiServer};
use pezsc_consensus_grandpa_rpc::{Grandpa, GrandpaApiServer};
use pezsc_rpc::{
dev::{Dev, DevApiServer},
mixnet::MixnetApiServer,
statement::StatementApiServer,
};
use pezsc_sync_state_rpc::{SyncState, SyncStateApiServer};
use bizinikiwi_frame_rpc_system::{System, SystemApiServer};
use bizinikiwi_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer};
let mut io = RpcModule::new(());
let BabeDeps { keystore, babe_worker_handle } = babe;
let GrandpaDeps {
shared_voter_state,
shared_authority_set,
justification_stream,
subscription_executor,
finality_provider,
} = grandpa;
io.merge(System::new(client.clone(), pool).into_rpc())?;
// Making synchronous calls in light client freezes the browser currently,
// more context: https://github.com/pezkuwichain/kurdistan-sdk/issues/53
// These RPCs should use an asynchronous caller instead.
io.merge(
Mmr::new(
client.clone(),
backend
.offchain_storage()
.ok_or_else(|| "Backend doesn't provide an offchain storage")?,
)
.into_rpc(),
)?;
io.merge(TransactionPayment::new(client.clone()).into_rpc())?;
io.merge(
Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain).into_rpc(),
)?;
io.merge(
Grandpa::new(
subscription_executor,
shared_authority_set.clone(),
shared_voter_state,
justification_stream,
finality_provider,
)
.into_rpc(),
)?;
io.merge(
SyncState::new(chain_spec, client.clone(), shared_authority_set, babe_worker_handle)?
.into_rpc(),
)?;
io.merge(StateMigration::new(client.clone(), backend).into_rpc())?;
io.merge(Dev::new(client).into_rpc())?;
let statement_store = pezsc_rpc::statement::StatementStore::new(statement_store).into_rpc();
io.merge(statement_store)?;
if let Some(mixnet_api) = mixnet_api {
let mixnet = pezsc_rpc::mixnet::Mixnet::new(mixnet_api).into_rpc();
io.merge(mixnet)?;
}
io.merge(
Beefy::<Block, AuthorityId>::new(
beefy.beefy_finality_proof_stream,
beefy.beefy_best_block_stream,
beefy.subscription_executor,
)?
.into_rpc(),
)?;
Ok(io)
}
+82
View File
@@ -0,0 +1,82 @@
[package]
name = "kitchensink-runtime"
version = "3.0.0-dev"
authors.workspace = true
description = "Bizinikiwi node kitchensink runtime."
edition.workspace = true
build = "build.rs"
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
publish = false
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
# third-party dependencies
array-bytes = { workspace = true }
codec = { features = ["derive", "max-encoded-len"], workspace = true }
log = { workspace = true }
rand = { workspace = true, optional = true }
rand_pcg = { workspace = true, optional = true }
scale-info = { features = ["derive", "serde"], workspace = true }
serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true }
pezsp-debug-derive = { workspace = true, features = ["force-debug"] }
static_assertions = { workspace = true, default-features = true }
# pezpallet-asset-conversion: turn on "num-traits" feature
primitive-types = { features = [
"codec",
"num-traits",
"scale-info",
], workspace = true }
pezkuwi-sdk = { features = ["runtime-full", "tuples-96"], workspace = true }
# shared code between runtime and node
node-primitives = { workspace = true }
# Example pallets that are not published:
pezpallet-example-mbm = { workspace = true }
pezpallet-example-tasks = { workspace = true }
[build-dependencies]
bizinikiwi-wasm-builder = { optional = true, workspace = true, default-features = true }
[features]
default = ["std"]
with-tracing = ["pezkuwi-sdk/with-tracing"]
std = [
"codec/std",
"log/std",
"node-primitives/std",
"pezpallet-example-mbm/std",
"pezpallet-example-tasks/std",
"pezkuwi-sdk/std",
"primitive-types/std",
"rand?/std",
"scale-info/std",
"serde_json/std",
"pezsp-debug-derive/std",
"bizinikiwi-wasm-builder",
]
runtime-benchmarks = [
"node-primitives/runtime-benchmarks",
"pezpallet-example-mbm/runtime-benchmarks",
"pezpallet-example-tasks/runtime-benchmarks",
"pezkuwi-sdk/runtime-benchmarks",
"rand",
"rand_pcg",
"bizinikiwi-wasm-builder?/runtime-benchmarks",
]
try-runtime = [
"pezpallet-example-mbm/try-runtime",
"pezpallet-example-tasks/try-runtime",
"pezkuwi-sdk/try-runtime",
]
experimental = ["pezpallet-example-tasks/experimental"]
metadata-hash = ["bizinikiwi-wasm-builder/metadata-hash"]
+31
View File
@@ -0,0 +1,31 @@
// This file is part of Bizinikiwi.
// Copyright (C) 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.
#[cfg(all(feature = "std", not(feature = "metadata-hash")))]
fn main() {
bizinikiwi_wasm_builder::WasmBuilder::build_using_defaults()
}
#[cfg(all(feature = "std", feature = "metadata-hash"))]
fn main() {
bizinikiwi_wasm_builder::WasmBuilder::init_with_defaults()
.enable_metadata_hash("Test", 14)
.build()
}
#[cfg(not(feature = "std"))]
fn main() {}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
@@ -22,7 +22,7 @@ use pezkuwi_sdk::*;
use alloc::vec::Vec;
use codec::Codec;
sp_api::decl_runtime_apis! {
pezsp_api::decl_runtime_apis! {
pub trait AssetsApi<AccountId, AssetBalance, AssetId>
where
AccountId: Codec,
@@ -0,0 +1,77 @@
// This file is part of Bizinikiwi.
// Copyright (C) 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.
//! A set of constant values used in bizinikiwi runtime.
/// Money matters.
pub mod currency {
use node_primitives::Balance;
pub const MILLICENTS: Balance = 1_000_000_000;
pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent.
pub const DOLLARS: Balance = 100 * CENTS;
pub const fn deposit(items: u32, bytes: u32) -> Balance {
items as Balance * 15 * CENTS + (bytes as Balance) * 6 * CENTS
}
}
/// Time.
pub mod time {
use node_primitives::{BlockNumber, Moment};
/// Since BABE is probabilistic this is the average expected block time that
/// we are targeting. Blocks will be produced at a minimum duration defined
/// by `SLOT_DURATION`, but some slots will not be allocated to any
/// authority and hence no block will be produced. We expect to have this
/// block time on average following the defined slot duration and the value
/// of `c` configured for BABE (where `1 - c` represents the probability of
/// a slot being empty).
/// This value is only used indirectly to define the unit constants below
/// that are expressed in blocks. The rest of the code should use
/// `SLOT_DURATION` instead (like the Timestamp pallet for calculating the
/// minimum period).
///
/// If using BABE with secondary slots (default) then all of the slots will
/// always be assigned, in which case `MILLISECS_PER_BLOCK` and
/// `SLOT_DURATION` should have the same value.
///
/// <https://research.web3.foundation/Polkadot/protocols/block-production/Babe#6-practical-results>
pub const MILLISECS_PER_BLOCK: Moment = 3000;
pub const SECS_PER_BLOCK: Moment = MILLISECS_PER_BLOCK / 1000;
// NOTE: Currently it is not possible to change the slot duration after the chain has started.
// Attempting to do so will brick block production.
pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK;
// 1 in 4 blocks (on average, not counting collisions) will be primary BABE blocks.
pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
// NOTE: Currently it is not possible to change the epoch duration after the chain has started.
// Attempting to do so will brick block production.
pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES;
pub const EPOCH_DURATION_IN_SLOTS: u64 = {
const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64;
(EPOCH_DURATION_IN_BLOCKS as f64 * SLOT_FILL_RATE) as u64
};
// These time units are defined in number of blocks.
pub const MINUTES: BlockNumber = 60 / (SECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
}
@@ -0,0 +1,222 @@
// This file is part of Bizinikiwi.
// Copyright (C) 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.
//! Genesis Presets for the Kitchensink Runtime
use pezkuwi_sdk::*;
use crate::{
constants::currency::*, pezframe_support::build_struct_json_patch, AccountId, AssetsConfig,
BabeConfig, Balance, BalancesConfig, ElectionsConfig, NominationPoolsConfig, ReviveConfig,
RuntimeGenesisConfig, SessionConfig, SessionKeys, SocietyConfig, StakerStatus, StakingConfig,
SudoConfig, TechnicalCommitteeConfig, BABE_GENESIS_EPOCH_CONFIG,
};
use alloc::{vec, vec::Vec};
use pezpallet_im_online::sr25519::AuthorityId as ImOnlineId;
use pezpallet_revive::is_eth_derived;
use pezsp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use pezsp_consensus_babe::AuthorityId as BabeId;
use pezsp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId;
use pezsp_consensus_grandpa::AuthorityId as GrandpaId;
use pezsp_core::{crypto::get_public_from_string_or_panic, sr25519};
use pezsp_genesis_builder::PresetId;
use pezsp_keyring::Sr25519Keyring;
use pezsp_mixnet::types::AuthorityId as MixnetId;
use pezsp_runtime::Perbill;
pub const ENDOWMENT: Balance = 10_000_000 * DOLLARS;
pub const STASH: Balance = ENDOWMENT / 1000;
/// The staker type as supplied ot the Staking config.
pub type Staker = (AccountId, AccountId, Balance, StakerStatus<AccountId>);
/// Helper function to create RuntimeGenesisConfig json patch for testing.
pub fn kitchensink_genesis(
initial_authorities: Vec<(AccountId, AccountId, SessionKeys)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
stakers: Vec<Staker>,
) -> serde_json::Value {
let validator_count = initial_authorities.len() as u32;
let minimum_validator_count = validator_count;
let collective = collective(&endowed_accounts);
build_struct_json_patch!(RuntimeGenesisConfig {
balances: BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect(),
..Default::default()
},
session: SessionConfig {
keys: initial_authorities
.iter()
.map(|x| { (x.0.clone(), x.1.clone(), x.2.clone()) })
.collect(),
},
staking: StakingConfig {
validator_count,
minimum_validator_count,
invulnerables: initial_authorities
.iter()
.map(|x| x.0.clone())
.collect::<Vec<_>>()
.try_into()
.expect("Too many invulnerable validators: upper limit is MaxInvulnerables from pallet staking config"),
slash_reward_fraction: Perbill::from_percent(10),
stakers,
},
elections: ElectionsConfig {
members: collective.iter().cloned().map(|member| (member, STASH)).collect(),
},
technical_committee: TechnicalCommitteeConfig { members: collective },
sudo: SudoConfig { key: Some(root_key) },
babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG },
society: SocietyConfig { pot: 0 },
assets: AssetsConfig {
// This asset is used by the NIS pallet as counterpart currency.
assets: vec![(9, Sr25519Keyring::Alice.to_account_id(), true, 1)],
..Default::default()
},
nomination_pools: NominationPoolsConfig {
min_create_bond: 10 * DOLLARS,
min_join_bond: 1 * DOLLARS,
},
revive: ReviveConfig {
mapped_accounts: endowed_accounts.iter().filter(|x| ! is_eth_derived(x)).cloned().collect(),
},
})
}
/// Provides the JSON representation of predefined genesis config for given `id`.
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
// Note: Can't use `Sr25519Keyring::Alice.to_seed()` because the seed comes with `//`.
let (alice_stash, alice, alice_session_keys) = authority_keys_from_seed("Alice");
let (bob_stash, _bob, bob_session_keys) = authority_keys_from_seed("Bob");
let endowed = well_known_including_eth_accounts();
let patch = match id.as_ref() {
pezsp_genesis_builder::DEV_RUNTIME_PRESET => kitchensink_genesis(
// Use stash as controller account, otherwise grandpa can't load the authority set at
// genesis.
vec![(alice_stash.clone(), alice_stash.clone(), alice_session_keys)],
alice.clone(),
endowed,
vec![validator(alice_stash.clone())],
),
pezsp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => kitchensink_genesis(
vec![
// Use stash as controller account, otherwise grandpa can't load the authority set
// at genesis.
(alice_stash.clone(), alice_stash.clone(), alice_session_keys),
(bob_stash.clone(), bob_stash.clone(), bob_session_keys),
],
alice,
endowed,
vec![validator(alice_stash), validator(bob_stash)],
),
_ => return None,
};
Some(
serde_json::to_string(&patch)
.expect("serialization to json is expected to work. qed.")
.into_bytes(),
)
}
/// List of supported presets.
pub fn preset_names() -> Vec<PresetId> {
vec![
PresetId::from(pezsp_genesis_builder::DEV_RUNTIME_PRESET),
PresetId::from(pezsp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET),
]
}
/// Sets up the `account` to be a staker of validator variant as supplied to the
/// staking config.
pub fn validator(account: AccountId) -> Staker {
// validator, controller, stash, staker status
(account.clone(), account, STASH, StakerStatus::Validator)
}
/// Extract some accounts from endowed to be put into the collective.
fn collective(endowed: &[AccountId]) -> Vec<AccountId> {
const MAX_COLLECTIVE_SIZE: usize = 50;
let endowed_accounts_count = endowed.len();
endowed
.iter()
.take((endowed_accounts_count.div_ceil(2)).min(MAX_COLLECTIVE_SIZE))
.cloned()
.collect()
}
/// The Keyring's wellknown accounts + Alith and Baltathar.
///
/// Some integration tests require these ETH accounts.
pub fn well_known_including_eth_accounts() -> Vec<AccountId> {
Sr25519Keyring::well_known()
.map(|k| k.to_account_id())
.chain([
// subxt_signer::eth::dev::alith()
array_bytes::hex_n_into_unchecked(
"f24ff3a9cf04c71dbc94d0b566f7a27b94566caceeeeeeeeeeeeeeeeeeeeeeee",
),
// subxt_signer::eth::dev::baltathar()
array_bytes::hex_n_into_unchecked(
"3cd0a705a2dc65e5b1e1205896baa2be8a07c6e0eeeeeeeeeeeeeeeeeeeeeeee",
),
])
.collect::<Vec<_>>()
}
/// Helper function to generate stash, controller and session key from seed.
///
/// Note: `//` is prepended internally.
pub fn authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, SessionKeys) {
(
get_public_from_string_or_panic::<sr25519::Public>(&alloc::format!("{seed}//stash")).into(),
get_public_from_string_or_panic::<sr25519::Public>(seed).into(),
session_keys_from_seed(seed),
)
}
pub fn session_keys(
grandpa: GrandpaId,
babe: BabeId,
im_online: ImOnlineId,
authority_discovery: AuthorityDiscoveryId,
mixnet: MixnetId,
beefy: BeefyId,
) -> SessionKeys {
SessionKeys { grandpa, babe, im_online, authority_discovery, mixnet, beefy }
}
/// We have this method as there is no straight forward way to convert the
/// account keyring into these ids.
///
/// Note: `//` is prepended internally.
pub fn session_keys_from_seed(seed: &str) -> SessionKeys {
session_keys(
get_public_from_string_or_panic::<GrandpaId>(seed),
get_public_from_string_or_panic::<BabeId>(seed),
get_public_from_string_or_panic::<ImOnlineId>(seed),
get_public_from_string_or_panic::<AuthorityDiscoveryId>(seed),
get_public_from_string_or_panic::<MixnetId>(seed),
get_public_from_string_or_panic::<BeefyId>(seed),
)
}
+493
View File
@@ -0,0 +1,493 @@
// This file is part of Bizinikiwi.
// Copyright (C) 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.
//! Some configurable implementations as associated type for the bizinikiwi runtime.
use alloc::boxed::Box;
use pezframe_support::{
pezpallet_prelude::*,
traits::{
fungibles::{Balanced, Credit},
Currency, OnUnbalanced,
},
};
use pezpallet_alliance::{IdentityVerifier, ProposalIndex, ProposalProvider};
use pezpallet_asset_tx_payment::HandleCredit;
use pezpallet_identity::legacy::IdentityField;
use pezkuwi_sdk::*;
use crate::{
AccountId, AllianceCollective, AllianceMotion, Assets, Authorship, Balances, Hash,
NegativeImbalance, Runtime, RuntimeCall,
};
pub struct Author;
impl OnUnbalanced<NegativeImbalance> for Author {
fn on_nonzero_unbalanced(amount: NegativeImbalance) {
if let Some(author) = Authorship::author() {
Balances::resolve_creating(&author, amount);
}
}
}
/// A `HandleCredit` implementation that naively transfers the fees to the block author.
/// Will drop and burn the assets in case the transfer fails.
pub struct CreditToBlockAuthor;
impl HandleCredit<AccountId, Assets> for CreditToBlockAuthor {
fn handle_credit(credit: Credit<AccountId, Assets>) {
if let Some(author) = pezpallet_authorship::Pallet::<Runtime>::author() {
// Drop the result which will trigger the `OnDrop` of the imbalance in case of error.
let _ = Assets::resolve(&author, credit);
}
}
}
pub struct AllianceIdentityVerifier;
impl IdentityVerifier<AccountId> for AllianceIdentityVerifier {
fn has_required_identities(who: &AccountId) -> bool {
crate::Identity::has_identity(who, (IdentityField::Display | IdentityField::Web).bits())
}
fn has_good_judgement(who: &AccountId) -> bool {
use pezpallet_identity::{IdentityOf, Judgement};
IdentityOf::<Runtime>::get(who)
.map(|registration| registration.judgements)
.map_or(false, |judgements| {
judgements
.iter()
.any(|(_, j)| matches!(j, Judgement::KnownGood | Judgement::Reasonable))
})
}
fn super_account_id(who: &AccountId) -> Option<AccountId> {
use pezpallet_identity::SuperOf;
SuperOf::<Runtime>::get(who).map(|parent| parent.0)
}
}
pub struct AllianceProposalProvider;
impl ProposalProvider<AccountId, Hash, RuntimeCall> for AllianceProposalProvider {
fn propose_proposal(
who: AccountId,
threshold: u32,
proposal: Box<RuntimeCall>,
length_bound: u32,
) -> Result<(u32, u32), DispatchError> {
AllianceMotion::do_propose_proposed(who, threshold, proposal, length_bound)
}
fn vote_proposal(
who: AccountId,
proposal: Hash,
index: ProposalIndex,
approve: bool,
) -> Result<bool, DispatchError> {
AllianceMotion::do_vote(who, proposal, index, approve)
}
fn close_proposal(
proposal_hash: Hash,
proposal_index: ProposalIndex,
proposal_weight_bound: Weight,
length_bound: u32,
) -> DispatchResultWithPostInfo {
AllianceMotion::do_close(proposal_hash, proposal_index, proposal_weight_bound, length_bound)
}
fn proposal_of(proposal_hash: Hash) -> Option<RuntimeCall> {
pezpallet_collective::ProposalOf::<Runtime, AllianceCollective>::get(proposal_hash)
}
}
#[cfg(test)]
mod multiplier_tests {
use pezframe_support::{
dispatch::DispatchClass,
weights::{Weight, WeightToFee},
};
use pezpallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
use pezkuwi_sdk::*;
use pezsp_runtime::{
assert_eq_error_rate,
traits::{Convert, One, Zero},
BuildStorage, FixedPointNumber,
};
use crate::{
constants::{currency::*, time::*},
AdjustmentVariable, MaximumMultiplier, MinimumMultiplier, Runtime,
RuntimeBlockWeights as BlockWeights, System, TargetBlockFullness, TransactionPayment,
};
fn max_normal() -> Weight {
BlockWeights::get()
.get(DispatchClass::Normal)
.max_total
.unwrap_or_else(|| BlockWeights::get().max_block)
}
fn min_multiplier() -> Multiplier {
MinimumMultiplier::get()
}
fn target() -> Weight {
TargetBlockFullness::get() * max_normal()
}
// update based on runtime impl.
fn runtime_multiplier_update(fm: Multiplier) -> Multiplier {
TargetedFeeAdjustment::<
Runtime,
TargetBlockFullness,
AdjustmentVariable,
MinimumMultiplier,
MaximumMultiplier,
>::convert(fm)
}
// update based on reference impl.
fn truth_value_update(block_weight: Weight, previous: Multiplier) -> Multiplier {
let accuracy = Multiplier::accuracy() as f64;
let previous_float = previous.into_inner() as f64 / accuracy;
// bump if it is zero.
let previous_float = previous_float.max(min_multiplier().into_inner() as f64 / accuracy);
let max_normal = max_normal();
let target_weight = target();
let normalized_weight_dimensions = (
block_weight.ref_time() as f64 / max_normal.ref_time() as f64,
block_weight.proof_size() as f64 / max_normal.proof_size() as f64,
);
let (normal, max, target) =
if normalized_weight_dimensions.0 < normalized_weight_dimensions.1 {
(block_weight.proof_size(), max_normal.proof_size(), target_weight.proof_size())
} else {
(block_weight.ref_time(), max_normal.ref_time(), target_weight.ref_time())
};
// maximum tx weight
let m = max as f64;
// block weight always truncated to max weight
let block_weight = (normal as f64).min(m);
let v: f64 = AdjustmentVariable::get().to_float();
// Ideal saturation in terms of weight
let ss = target as f64;
// Current saturation in terms of weight
let s = block_weight;
let t1 = v * (s / m - ss / m);
let t2 = v.powi(2) * (s / m - ss / m).powi(2) / 2.0;
let next_float = previous_float * (1.0 + t1 + t2);
Multiplier::from_float(next_float)
}
fn run_with_system_weight<F>(w: Weight, assertions: F)
where
F: Fn() -> (),
{
let mut t: pezsp_io::TestExternalities = pezframe_system::GenesisConfig::<Runtime>::default()
.build_storage()
.unwrap()
.into();
t.execute_with(|| {
System::set_block_consumed_resources(w, 0);
assertions()
});
}
#[test]
fn truth_value_update_poc_works() {
let fm = Multiplier::saturating_from_rational(1, 2);
let test_set = vec![
(Weight::zero(), fm),
(Weight::from_parts(100, 0), fm),
(Weight::from_parts(1000, 0), fm),
(target(), fm),
(max_normal() / 2, fm),
(max_normal(), fm),
];
test_set.into_iter().for_each(|(w, fm)| {
run_with_system_weight(w, || {
assert_eq_error_rate!(
truth_value_update(w, fm),
runtime_multiplier_update(fm),
// Error is only 1 in 100^18
Multiplier::from_inner(100),
);
})
})
}
#[test]
fn multiplier_can_grow_from_zero() {
// if the min is too small, then this will not change, and we are doomed forever.
// the block ref time is 1/100th bigger than target.
run_with_system_weight(target().set_ref_time(target().ref_time() * 101 / 100), || {
let next = runtime_multiplier_update(min_multiplier());
assert!(next > min_multiplier(), "{:?} !> {:?}", next, min_multiplier());
});
// the block proof size is 1/100th bigger than target.
run_with_system_weight(target().set_proof_size((target().proof_size() / 100) * 101), || {
let next = runtime_multiplier_update(min_multiplier());
assert!(next > min_multiplier(), "{:?} !> {:?}", next, min_multiplier());
})
}
#[test]
fn multiplier_cannot_go_below_limit() {
// will not go any further below even if block is empty.
run_with_system_weight(Weight::zero(), || {
let next = runtime_multiplier_update(min_multiplier());
assert_eq!(next, min_multiplier());
})
}
#[test]
fn time_to_reach_zero() {
// blocks per 24h in bizinikiwi-node: 28,800 (k)
// s* = 0.1875
// The bound from the research in an empty chain is:
// v <~ (p / k(0 - s*))
// p > v * k * -0.1875
// to get p == -1 we'd need
// -1 > 0.00001 * k * -0.1875
// 1 < 0.00001 * k * 0.1875
// 10^9 / 1875 < k
// k > 533_333 ~ 18,5 days.
run_with_system_weight(Weight::zero(), || {
// start from 1, the default.
let mut fm = Multiplier::one();
let mut iterations: u64 = 0;
loop {
let next = runtime_multiplier_update(fm);
fm = next;
if fm == min_multiplier() {
break;
}
iterations += 1;
}
assert!(iterations > 533_333);
})
}
#[test]
fn min_change_per_day() {
run_with_system_weight(max_normal(), || {
let mut fm = Multiplier::one();
// See the example in the doc of `TargetedFeeAdjustment`. are at least 0.234, hence
// `fm > 1.234`.
for _ in 0..DAYS {
let next = runtime_multiplier_update(fm);
fm = next;
}
assert!(fm > Multiplier::saturating_from_rational(1234, 1000));
})
}
#[test]
#[ignore]
fn congested_chain_simulation() {
// `cargo test congested_chain_simulation -- --nocapture` to get some insight.
// almost full. The entire quota of normal transactions is taken.
let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() -
Weight::from_parts(100, 0);
// Default bizinikiwi weight.
let tx_weight = pezframe_support::weights::constants::ExtrinsicBaseWeight::get();
run_with_system_weight(block_weight, || {
// initial value configured on module
let mut fm = Multiplier::one();
assert_eq!(fm, TransactionPayment::next_fee_multiplier());
let mut iterations: u64 = 0;
loop {
let next = runtime_multiplier_update(fm);
// if no change, panic. This should never happen in this case.
if fm == next {
panic!("The fee should ever increase");
}
fm = next;
iterations += 1;
let fee =
<Runtime as pezpallet_transaction_payment::Config>::WeightToFee::weight_to_fee(
&tx_weight,
);
let adjusted_fee = fm.saturating_mul_acc_int(fee);
println!(
"iteration {}, new fm = {:?}. Fee at this point is: {} units / {} millicents, \
{} cents, {} dollars",
iterations,
fm,
adjusted_fee,
adjusted_fee / MILLICENTS,
adjusted_fee / CENTS,
adjusted_fee / DOLLARS,
);
}
});
}
#[test]
fn stateless_weight_mul() {
let fm = Multiplier::saturating_from_rational(1, 2);
run_with_system_weight(target() / 4, || {
let next = runtime_multiplier_update(fm);
assert_eq_error_rate!(
next,
truth_value_update(target() / 4, fm),
Multiplier::from_inner(100),
);
// Light block. Multiplier is reduced a little.
assert!(next < fm);
});
run_with_system_weight(target() / 2, || {
let next = runtime_multiplier_update(fm);
assert_eq_error_rate!(
next,
truth_value_update(target() / 2, fm),
Multiplier::from_inner(100),
);
// Light block. Multiplier is reduced a little.
assert!(next < fm);
});
run_with_system_weight(target(), || {
let next = runtime_multiplier_update(fm);
assert_eq_error_rate!(
next,
truth_value_update(target(), fm),
Multiplier::from_inner(100),
);
// ideal. No changes.
assert_eq!(next, fm)
});
run_with_system_weight(target() * 2, || {
// More than ideal. Fee is increased.
let next = runtime_multiplier_update(fm);
assert_eq_error_rate!(
next,
truth_value_update(target() * 2, fm),
Multiplier::from_inner(100),
);
// Heavy block. Fee is increased a little.
assert!(next > fm);
});
}
#[test]
fn weight_mul_grow_on_big_block() {
run_with_system_weight(target() * 2, || {
let mut original = Multiplier::zero();
let mut next = Multiplier::default();
(0..1_000).for_each(|_| {
next = runtime_multiplier_update(original);
assert_eq_error_rate!(
next,
truth_value_update(target() * 2, original),
Multiplier::from_inner(100),
);
// must always increase
assert!(next > original, "{:?} !>= {:?}", next, original);
original = next;
});
});
}
#[test]
fn weight_mul_decrease_on_small_block() {
run_with_system_weight(target() / 2, || {
let mut original = Multiplier::saturating_from_rational(1, 2);
let mut next;
for _ in 0..100 {
// decreases
next = runtime_multiplier_update(original);
assert!(next < original, "{:?} !<= {:?}", next, original);
original = next;
}
})
}
#[test]
fn weight_to_fee_should_not_overflow_on_large_weights() {
let kb_time = Weight::from_parts(1024, 0);
let kb_size = Weight::from_parts(0, 1024);
let mb_time = 1024u64 * kb_time;
let max_fm = Multiplier::saturating_from_integer(i128::MAX);
// check that for all values it can compute, correctly.
vec![
Weight::zero(),
// testcases ignoring proof size part of the weight.
Weight::from_parts(1, 0),
Weight::from_parts(10, 0),
Weight::from_parts(1000, 0),
kb_time,
10u64 * kb_time,
100u64 * kb_time,
mb_time,
10u64 * mb_time,
Weight::from_parts(2147483647, 0),
Weight::from_parts(4294967295, 0),
// testcases ignoring ref time part of the weight.
Weight::from_parts(0, 100000000000),
1000000u64 * kb_size,
1000000000u64 * kb_size,
Weight::from_parts(0, 18014398509481983),
Weight::from_parts(0, 9223372036854775807),
// test cases with both parts of the weight.
BlockWeights::get().max_block / 1024,
BlockWeights::get().max_block / 2,
BlockWeights::get().max_block,
Weight::MAX / 2,
Weight::MAX,
]
.into_iter()
.for_each(|i| {
run_with_system_weight(i, || {
let next = runtime_multiplier_update(Multiplier::one());
let truth = truth_value_update(i, Multiplier::one());
assert_eq_error_rate!(truth, next, Multiplier::from_inner(50_000_000));
});
});
// Some values that are all above the target and will cause an increase.
let t = target();
vec![
t + Weight::from_parts(100, 0),
t + Weight::from_parts(0, t.proof_size() * 2),
t * 2,
t * 4,
]
.into_iter()
.for_each(|i| {
run_with_system_weight(i, || {
let fm = runtime_multiplier_update(max_fm);
// won't grow. The convert saturates everything.
assert_eq!(fm, max_fm);
})
});
}
}
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
+81
View File
@@ -0,0 +1,81 @@
[package]
name = "node-testing"
version = "3.0.0-dev"
authors.workspace = true
description = "Test utilities for Bizinikiwi node."
edition.workspace = true
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
homepage.workspace = true
repository.workspace = true
publish = false
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { workspace = true, default-features = true }
pezframe-metadata-hash-extension = { workspace = true, default-features = true }
pezframe-system = { workspace = true, default-features = true }
fs_extra = { workspace = true }
futures = { workspace = true }
kitchensink-runtime = { workspace = true }
log = { workspace = true, default-features = true }
node-cli = { workspace = true }
node-primitives = { workspace = true, default-features = true }
pezpallet-asset-conversion = { workspace = true, default-features = true }
pezpallet-asset-conversion-tx-payment = { workspace = true, default-features = true }
pezpallet-revive = { workspace = true, default-features = true }
pezpallet-skip-feeless-payment = { workspace = true, default-features = true }
pezsc-block-builder = { workspace = true, default-features = true }
pezsc-client-api = { workspace = true, default-features = true }
pezsc-client-db = { features = [
"rocksdb",
], workspace = true, default-features = true }
pezsc-consensus = { workspace = true, default-features = true }
pezsc-executor = { workspace = true, default-features = true }
pezsc-service = { features = [
"rocksdb",
], workspace = true, default-features = true }
pezsp-api = { workspace = true, default-features = true }
pezsp-block-builder = { workspace = true, default-features = true }
pezsp-blockchain = { workspace = true, default-features = true }
pezsp-consensus = { workspace = true, default-features = true }
pezsp-core = { workspace = true, default-features = true }
pezsp-crypto-hashing = { workspace = true, default-features = true }
pezsp-inherents = { workspace = true, default-features = true }
pezsp-keyring = { workspace = true, default-features = true }
pezsp-runtime = { workspace = true, default-features = true }
pezsp-timestamp = { workspace = true }
bizinikiwi-test-client = { workspace = true }
tempfile = { workspace = true }
[features]
runtime-benchmarks = [
"pezframe-metadata-hash-extension/runtime-benchmarks",
"pezframe-system/runtime-benchmarks",
"kitchensink-runtime/runtime-benchmarks",
"node-cli/runtime-benchmarks",
"node-primitives/runtime-benchmarks",
"pezpallet-asset-conversion-tx-payment/runtime-benchmarks",
"pezpallet-asset-conversion/runtime-benchmarks",
"pezpallet-revive/runtime-benchmarks",
"pezpallet-skip-feeless-payment/runtime-benchmarks",
"pezsc-block-builder/runtime-benchmarks",
"pezsc-client-api/runtime-benchmarks",
"pezsc-client-db/runtime-benchmarks",
"pezsc-consensus/runtime-benchmarks",
"pezsc-executor/runtime-benchmarks",
"pezsc-service/runtime-benchmarks",
"pezsp-api/runtime-benchmarks",
"pezsp-block-builder/runtime-benchmarks",
"pezsp-blockchain/runtime-benchmarks",
"pezsp-consensus/runtime-benchmarks",
"pezsp-inherents/runtime-benchmarks",
"pezsp-keyring/runtime-benchmarks",
"pezsp-runtime/runtime-benchmarks",
"pezsp-timestamp/runtime-benchmarks",
"bizinikiwi-test-client/runtime-benchmarks",
]
+680
View File
@@ -0,0 +1,680 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Benchmarking module.
//!
//! Utilities to do full-scale benchmarks involving database. With `BenchDb` you
//! can pregenerate seed database and `clone` it for every iteration of your benchmarks
//! or tests to get consistent, smooth benchmark experience!
use std::{
collections::BTreeMap,
path::{Path, PathBuf},
sync::Arc,
};
use crate::{
client::{Backend, Client},
keyring::*,
};
use codec::{Decode, Encode};
use futures::executor;
use kitchensink_runtime::{
constants::currency::DOLLARS, AccountId, BalancesCall, CheckedExtrinsic, MinimumPeriod,
RuntimeCall, Signature, SystemCall, UncheckedExtrinsic,
};
use node_primitives::Block;
use pezsc_block_builder::BlockBuilderBuilder;
use pezsc_client_api::{execution_extensions::ExecutionExtensions, UsageProvider};
use pezsc_client_db::PruningMode;
use pezsc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, ImportedAux};
use pezsc_executor::{WasmExecutionMethod, WasmtimeInstantiationStrategy};
use pezsp_api::ProvideRuntimeApi;
use pezsp_block_builder::BlockBuilder;
use pezsp_consensus::BlockOrigin;
use pezsp_core::{
crypto::get_public_from_string_or_panic, ed25519, sr25519, traits::SpawnNamed, Pair,
};
use pezsp_crypto_hashing::blake2_256;
use pezsp_inherents::InherentData;
use pezsp_runtime::{
generic::{self, ExtrinsicFormat, Preamble},
traits::{Block as BlockT, IdentifyAccount, Verify},
OpaqueExtrinsic,
};
/// Keyring full of accounts for benching.
///
/// Accounts are ordered:
/// //endowed-user//00
/// //endowed-user//01
/// ...
/// //endowed-user//N
#[derive(Clone)]
pub struct BenchKeyring {
accounts: BTreeMap<AccountId, BenchPair>,
}
#[derive(Clone)]
enum BenchPair {
Sr25519(sr25519::Pair),
Ed25519(ed25519::Pair),
}
impl BenchPair {
fn sign(&self, payload: &[u8]) -> Signature {
match self {
Self::Sr25519(pair) => pair.sign(payload).into(),
Self::Ed25519(pair) => pair.sign(payload).into(),
}
}
}
/// Drop system cache.
///
/// Will panic if cache drop is impossible.
pub fn drop_system_cache() {
#[cfg(target_os = "windows")]
{
log::warn!(
target: "bench-logistics",
"Clearing system cache on windows is not supported. Benchmark might totally be wrong.",
);
return;
}
std::process::Command::new("sync")
.output()
.expect("Failed to execute system cache clear");
#[cfg(target_os = "linux")]
{
log::trace!(target: "bench-logistics", "Clearing system cache...");
std::process::Command::new("echo")
.args(&["3", ">", "/proc/sys/vm/drop_caches", "2>", "/dev/null"])
.output()
.expect("Failed to execute system cache clear");
let temp = tempfile::tempdir().expect("Failed to spawn tempdir");
let temp_file_path = format!("of={}/buf", temp.path().to_string_lossy());
// this should refill write cache with 2GB of garbage
std::process::Command::new("dd")
.args(&["if=/dev/urandom", &temp_file_path, "bs=64M", "count=32"])
.output()
.expect("Failed to execute dd for cache clear");
// remove tempfile of previous command
std::process::Command::new("rm")
.arg(&temp_file_path)
.output()
.expect("Failed to remove temp file");
std::process::Command::new("sync")
.output()
.expect("Failed to execute system cache clear");
log::trace!(target: "bench-logistics", "Clearing system cache done!");
}
#[cfg(target_os = "macos")]
{
log::trace!(target: "bench-logistics", "Clearing system cache...");
if let Err(err) = std::process::Command::new("purge").output() {
log::error!("purge error {:?}: ", err);
panic!("Could not clear system cache. Run under sudo?");
}
log::trace!(target: "bench-logistics", "Clearing system cache done!");
}
}
/// Pre-initialized benchmarking database.
///
/// This is prepared database with genesis and keyring
/// that can be cloned and then used for any benchmarking.
pub struct BenchDb {
keyring: BenchKeyring,
directory_guard: Guard,
database_type: DatabaseType,
}
impl Clone for BenchDb {
fn clone(&self) -> Self {
let keyring = self.keyring.clone();
let database_type = self.database_type;
let dir = tempfile::tempdir().expect("temp dir creation failed");
let seed_dir = self.directory_guard.0.path();
log::trace!(
target: "bench-logistics",
"Copying seed db from {} to {}",
seed_dir.to_string_lossy(),
dir.path().to_string_lossy(),
);
let seed_db_files = std::fs::read_dir(seed_dir)
.expect("failed to list file in seed dir")
.map(|f_result| f_result.expect("failed to read file in seed db").path())
.collect::<Vec<PathBuf>>();
fs_extra::copy_items(&seed_db_files, dir.path(), &fs_extra::dir::CopyOptions::new())
.expect("Copy of seed database is ok");
// We clear system cache after db clone but before any warmups.
// This populates system cache with some data unrelated to actual
// data we will be querying further under benchmark (like what
// would have happened in real system that queries random entries
// from database).
drop_system_cache();
BenchDb { keyring, directory_guard: Guard(dir), database_type }
}
}
/// Type of block for generation
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum BlockType {
/// Bunch of random transfers.
RandomTransfersKeepAlive,
/// Bunch of random transfers that drain all of the source balance.
RandomTransfersReaping,
/// Bunch of "no-op" calls.
Noop,
}
impl BlockType {
/// Create block content description with specified number of transactions.
pub fn to_content(self, size: Option<usize>) -> BlockContent {
BlockContent { block_type: self, size }
}
}
/// Content of the generated block.
#[derive(Clone, Debug)]
pub struct BlockContent {
block_type: BlockType,
size: Option<usize>,
}
/// Type of backend database.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum DatabaseType {
/// RocksDb backend.
RocksDb,
/// Parity DB backend.
ParityDb,
}
impl DatabaseType {
fn into_settings(self, path: PathBuf) -> pezsc_client_db::DatabaseSource {
match self {
Self::RocksDb => pezsc_client_db::DatabaseSource::RocksDb { path, cache_size: 512 },
Self::ParityDb => pezsc_client_db::DatabaseSource::ParityDb { path },
}
}
}
/// Benchmarking task executor.
///
/// Uses multiple threads as the regular executable.
#[derive(Debug, Clone)]
pub struct TaskExecutor {
pool: executor::ThreadPool,
}
impl TaskExecutor {
fn new() -> Self {
Self { pool: executor::ThreadPool::new().expect("Failed to create task executor") }
}
}
impl SpawnNamed for TaskExecutor {
fn spawn(
&self,
_: &'static str,
_: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
) {
self.pool.spawn_ok(future);
}
fn spawn_blocking(
&self,
_: &'static str,
_: Option<&'static str>,
future: futures::future::BoxFuture<'static, ()>,
) {
self.pool.spawn_ok(future);
}
}
/// Iterator for block content.
pub struct BlockContentIterator<'a> {
iteration: usize,
content: BlockContent,
runtime_version: pezsc_executor::RuntimeVersion,
genesis_hash: node_primitives::Hash,
keyring: &'a BenchKeyring,
}
impl<'a> BlockContentIterator<'a> {
fn new(content: BlockContent, keyring: &'a BenchKeyring, client: &Client) -> Self {
let genesis_hash = client.chain_info().genesis_hash;
let runtime_version = client
.runtime_version_at(genesis_hash)
.expect("There should be runtime version at 0");
BlockContentIterator { iteration: 0, content, keyring, runtime_version, genesis_hash }
}
}
impl<'a> Iterator for BlockContentIterator<'a> {
type Item = OpaqueExtrinsic;
fn next(&mut self) -> Option<Self::Item> {
if self.content.size.map(|size| size <= self.iteration).unwrap_or(false) {
return None;
}
let sender = self.keyring.at(self.iteration);
let receiver = get_public_from_string_or_panic::<sr25519::Public>(&format!(
"random-user//{}",
self.iteration
))
.into();
let signed = self.keyring.sign(
CheckedExtrinsic {
format: ExtrinsicFormat::Signed(
sender,
tx_ext(0, kitchensink_runtime::ExistentialDeposit::get() + 1),
),
function: match self.content.block_type {
BlockType::RandomTransfersKeepAlive =>
RuntimeCall::Balances(BalancesCall::transfer_keep_alive {
dest: pezsp_runtime::MultiAddress::Id(receiver),
value: kitchensink_runtime::ExistentialDeposit::get() + 1,
}),
BlockType::RandomTransfersReaping => {
RuntimeCall::Balances(BalancesCall::transfer_allow_death {
dest: pezsp_runtime::MultiAddress::Id(receiver),
// Transfer so that ending balance would be 1 less than existential
// deposit so that we kill the sender account.
value: 100 * DOLLARS -
(kitchensink_runtime::ExistentialDeposit::get() - 1),
})
},
BlockType::Noop =>
RuntimeCall::System(SystemCall::remark { remark: Vec::new() }),
},
},
self.runtime_version.spec_version,
self.runtime_version.transaction_version,
self.genesis_hash.into(),
);
let encoded = Encode::encode(&signed);
let opaque = OpaqueExtrinsic::decode(&mut &encoded[..]).expect("Failed to decode opaque");
self.iteration += 1;
Some(opaque)
}
}
impl BenchDb {
/// New immutable benchmarking database.
///
/// See [`BenchDb::new`] method documentation for more information about the purpose
/// of this structure.
pub fn with_key_types(
database_type: DatabaseType,
keyring_length: usize,
key_types: KeyTypes,
) -> Self {
let keyring = BenchKeyring::new(keyring_length, key_types);
let dir = tempfile::tempdir().expect("temp dir creation failed");
log::trace!(
target: "bench-logistics",
"Created seed db at {}",
dir.path().to_string_lossy(),
);
let (_client, _backend, _task_executor) =
Self::bench_client(database_type, dir.path(), &keyring);
let directory_guard = Guard(dir);
BenchDb { keyring, directory_guard, database_type }
}
/// New immutable benchmarking database.
///
/// This will generate database files in random temporary directory
/// and keep it there until struct is dropped.
///
/// You can `clone` this database or you can `create_context` from it
/// (which also does `clone`) to run actual operation against new database
/// which will be identical to the original.
pub fn new(database_type: DatabaseType, keyring_length: usize) -> Self {
Self::with_key_types(database_type, keyring_length, KeyTypes::Sr25519)
}
// This should return client that is doing everything that full node
// is doing.
//
// - This client should use best wasm execution method.
// - This client should work with real database only.
fn bench_client(
database_type: DatabaseType,
dir: &std::path::Path,
keyring: &BenchKeyring,
) -> (Client, std::sync::Arc<Backend>, TaskExecutor) {
let db_config = pezsc_client_db::DatabaseSettings {
trie_cache_maximum_size: Some(16 * 1024 * 1024),
state_pruning: Some(PruningMode::ArchiveAll),
source: database_type.into_settings(dir.into()),
blocks_pruning: pezsc_client_db::BlocksPruning::KeepAll,
metrics_registry: None,
};
let task_executor = TaskExecutor::new();
let backend = pezsc_service::new_db_backend(db_config).expect("Should not fail");
let executor = pezsc_executor::WasmExecutor::builder()
.with_execution_method(WasmExecutionMethod::Compiled {
instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite,
})
.build();
let client_config = pezsc_service::ClientConfig::default();
let genesis_block_builder = pezsc_service::GenesisBlockBuilder::new(
keyring.as_storage_builder(),
!client_config.no_genesis,
backend.clone(),
executor.clone(),
)
.expect("Failed to create genesis block builder");
let client = pezsc_service::new_client(
backend.clone(),
executor.clone(),
genesis_block_builder,
None,
None,
ExecutionExtensions::new(None, Arc::new(executor)),
Box::new(task_executor.clone()),
None,
None,
client_config,
)
.expect("Should not fail");
(client, backend, task_executor)
}
/// Generate list of required inherents.
///
/// Uses already instantiated Client.
pub fn generate_inherents(&mut self, client: &Client) -> Vec<OpaqueExtrinsic> {
let mut inherent_data = InherentData::new();
let timestamp = 1 * MinimumPeriod::get();
inherent_data
.put_data(pezsp_timestamp::INHERENT_IDENTIFIER, &timestamp)
.expect("Put timestamp failed");
client
.runtime_api()
.inherent_extrinsics(client.chain_info().genesis_hash, inherent_data)
.expect("Get inherents failed")
}
/// Iterate over some block content with transaction signed using this database keyring.
pub fn block_content(
&self,
content: BlockContent,
client: &Client,
) -> BlockContentIterator<'_> {
BlockContentIterator::new(content, &self.keyring, client)
}
/// Get client for this database operations.
pub fn client(&mut self) -> Client {
let (client, _backend, _task_executor) =
Self::bench_client(self.database_type, self.directory_guard.path(), &self.keyring);
client
}
/// Generate new block using this database.
pub fn generate_block(&mut self, content: BlockContent) -> Block {
let client = self.client();
let chain = client.usage_info().chain;
let mut block = BlockBuilderBuilder::new(&client)
.on_parent_block(chain.best_hash)
.with_parent_block_number(chain.best_number)
.build()
.expect("Failed to create block builder.");
for extrinsic in self.generate_inherents(&client) {
block.push(extrinsic).expect("Push inherent failed");
}
let start = std::time::Instant::now();
for opaque in self.block_content(content, &client) {
match block.push(opaque) {
Err(pezsp_blockchain::Error::ApplyExtrinsicFailed(
pezsp_blockchain::ApplyExtrinsicFailed::Validity(e),
)) if e.exhausted_resources() => break,
Err(err) => panic!("Error pushing transaction: {:?}", err),
Ok(_) => {},
}
}
let block = block.build().expect("Block build failed").block;
log::info!(
target: "bench-logistics",
"Block construction: {:#?} ({} tx)",
start.elapsed(), block.extrinsics.len()
);
block
}
/// Database path.
pub fn path(&self) -> &Path {
self.directory_guard.path()
}
/// Clone this database and create context for testing/benchmarking.
pub fn create_context(&self) -> BenchContext {
let BenchDb { directory_guard, keyring, database_type } = self.clone();
let (client, backend, task_executor) =
Self::bench_client(database_type, directory_guard.path(), &keyring);
BenchContext {
client: Arc::new(client),
db_guard: directory_guard,
backend,
spawn_handle: Box::new(task_executor),
}
}
}
/// Key types to be used in benching keyring
pub enum KeyTypes {
/// sr25519 signing keys
Sr25519,
/// ed25519 signing keys
Ed25519,
}
impl BenchKeyring {
/// New keyring.
///
/// `length` is the number of accounts generated.
pub fn new(length: usize, key_types: KeyTypes) -> Self {
let mut accounts = BTreeMap::new();
for n in 0..length {
let seed = format!("//endowed-user/{}", n);
let (account_id, pair) = match key_types {
KeyTypes::Sr25519 => {
let pair =
sr25519::Pair::from_string(&seed, None).expect("failed to generate pair");
let account_id = AccountPublic::from(pair.public()).into_account();
(account_id, BenchPair::Sr25519(pair))
},
KeyTypes::Ed25519 => {
let pair = ed25519::Pair::from_seed(&blake2_256(seed.as_bytes()));
let account_id = AccountPublic::from(pair.public()).into_account();
(account_id, BenchPair::Ed25519(pair))
},
};
accounts.insert(account_id, pair);
}
Self { accounts }
}
/// Generated account id-s from keyring keypairs.
pub fn collect_account_ids(&self) -> Vec<AccountId> {
self.accounts.keys().cloned().collect()
}
/// Get account id at position `index`
pub fn at(&self, index: usize) -> AccountId {
self.accounts.keys().nth(index).expect("Failed to get account").clone()
}
/// Sign transaction with keypair from this keyring.
pub fn sign(
&self,
xt: CheckedExtrinsic,
spec_version: u32,
tx_version: u32,
genesis_hash: [u8; 32],
) -> UncheckedExtrinsic {
match xt.format {
ExtrinsicFormat::Signed(signed, tx_ext) => {
let payload = (
xt.function,
tx_ext.clone(),
spec_version,
tx_version,
genesis_hash,
genesis_hash,
// metadata_hash
None::<()>,
);
let key = self.accounts.get(&signed).expect("Account id not found in keyring");
let signature = payload.using_encoded(|b| {
if b.len() > 256 {
key.sign(&blake2_256(b))
} else {
key.sign(b)
}
});
generic::UncheckedExtrinsic::new_signed(
payload.0,
pezsp_runtime::MultiAddress::Id(signed),
signature,
tx_ext,
)
.into()
},
ExtrinsicFormat::Bare => generic::UncheckedExtrinsic::new_bare(xt.function).into(),
ExtrinsicFormat::General(ext_version, tx_ext) =>
generic::UncheckedExtrinsic::from_parts(
xt.function,
Preamble::General(ext_version, tx_ext),
)
.into(),
}
}
/// Generate genesis with accounts from this keyring endowed with some balance and
/// kitchensink_runtime code blob.
pub fn as_storage_builder(&self) -> &dyn pezsp_runtime::BuildStorage {
self
}
}
impl pezsp_runtime::BuildStorage for BenchKeyring {
fn assimilate_storage(&self, storage: &mut pezsp_core::storage::Storage) -> Result<(), String> {
storage.top.insert(
pezsp_core::storage::well_known_keys::CODE.to_vec(),
kitchensink_runtime::wasm_binary_unwrap().into(),
);
crate::genesis::config_endowed(self.collect_account_ids()).assimilate_storage(storage)
}
}
struct Guard(tempfile::TempDir);
impl Guard {
fn path(&self) -> &Path {
self.0.path()
}
}
/// Benchmarking/test context holding instantiated client and backend references.
pub struct BenchContext {
/// Node client.
pub client: Arc<Client>,
/// Node backend.
pub backend: Arc<Backend>,
/// Spawn handle.
pub spawn_handle: Box<dyn SpawnNamed>,
db_guard: Guard,
}
type AccountPublic = <Signature as Verify>::Signer;
impl BenchContext {
/// Import some block.
pub fn import_block(&mut self, block: Block) {
let mut import_params =
BlockImportParams::new(BlockOrigin::NetworkBroadcast, block.header.clone());
import_params.body = Some(block.extrinsics().to_vec());
import_params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
assert_eq!(self.client.chain_info().best_number, 0);
assert_eq!(
futures::executor::block_on(self.client.import_block(import_params))
.expect("Failed to import block"),
ImportResult::Imported(ImportedAux {
header_only: false,
clear_justification_requests: false,
needs_justification: false,
bad_justification: false,
is_new_best: true,
})
);
assert_eq!(self.client.chain_info().best_number, 1);
}
/// Database path for the current context.
pub fn path(&self) -> &Path {
self.db_guard.path()
}
}
+87
View File
@@ -0,0 +1,87 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Utilities to build a `TestClient` for `kitchensink-runtime`.
use pezsp_runtime::BuildStorage;
/// Re-export test-client utilities.
pub use bizinikiwi_test_client::*;
/// Call executor for `kitchensink-runtime` `TestClient`.
use node_cli::service::RuntimeExecutor;
/// Default backend type.
pub type Backend = pezsc_client_db::Backend<node_primitives::Block>;
/// Test client type.
pub type Client = client::Client<
Backend,
client::LocalCallExecutor<node_primitives::Block, Backend, RuntimeExecutor>,
node_primitives::Block,
kitchensink_runtime::RuntimeApi,
>;
/// Genesis configuration parameters for `TestClient`.
#[derive(Default)]
pub struct GenesisParameters;
impl bizinikiwi_test_client::GenesisInit for GenesisParameters {
fn genesis_storage(&self) -> Storage {
let mut storage = crate::genesis::config().build_storage().unwrap();
storage.top.insert(
pezsp_core::storage::well_known_keys::CODE.to_vec(),
kitchensink_runtime::wasm_binary_unwrap().into(),
);
storage
}
}
/// A `test-runtime` extensions to `TestClientBuilder`.
pub trait TestClientBuilderExt: Sized {
/// Create test client builder.
fn new() -> Self;
/// Build the test client.
fn build(self) -> Client;
}
impl TestClientBuilderExt
for bizinikiwi_test_client::TestClientBuilder<
node_primitives::Block,
client::LocalCallExecutor<node_primitives::Block, Backend, RuntimeExecutor>,
Backend,
GenesisParameters,
>
{
fn new() -> Self {
Self::default()
}
fn build(self) -> Client {
let executor = RuntimeExecutor::builder().build();
use pezsc_service::client::LocalCallExecutor;
use std::sync::Arc;
let executor = LocalCallExecutor::new(
self.backend().clone(),
executor.clone(),
Default::default(),
ExecutionExtensions::new(None, Arc::new(executor)),
)
.expect("Creates LocalCallExecutor");
self.build_with_executor(executor).0
}
}
@@ -0,0 +1,75 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Genesis Configuration.
use crate::keyring::*;
use kitchensink_runtime::{
constants::currency::*, AccountId, AssetsConfig, BalancesConfig, IndicesConfig,
RuntimeGenesisConfig, SessionConfig, SocietyConfig, StakerStatus, StakingConfig,
};
use pezsp_keyring::Ed25519Keyring;
use pezsp_runtime::Perbill;
/// Create genesis runtime configuration for tests.
pub fn config() -> RuntimeGenesisConfig {
config_endowed(Default::default())
}
/// Create genesis runtime configuration for tests with some extra
/// endowed accounts.
pub fn config_endowed(extra_endowed: Vec<AccountId>) -> RuntimeGenesisConfig {
let mut endowed = vec![
(alice(), 111 * DOLLARS),
(bob(), 100 * DOLLARS),
(charlie(), 100_000_000 * DOLLARS),
(dave(), 112 * DOLLARS),
(eve(), 101 * DOLLARS),
(ferdie(), 101 * DOLLARS),
];
endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS)));
RuntimeGenesisConfig {
indices: IndicesConfig { indices: vec![] },
balances: BalancesConfig { balances: endowed, ..Default::default() },
session: SessionConfig {
keys: vec![
(alice(), dave(), session_keys_from_seed(Ed25519Keyring::Alice.into())),
(bob(), eve(), session_keys_from_seed(Ed25519Keyring::Bob.into())),
(charlie(), ferdie(), session_keys_from_seed(Ed25519Keyring::Charlie.into())),
],
..Default::default()
},
staking: StakingConfig {
stakers: vec![
(dave(), dave(), 111 * DOLLARS, StakerStatus::Validator),
(eve(), eve(), 100 * DOLLARS, StakerStatus::Validator),
(ferdie(), ferdie(), 100 * DOLLARS, StakerStatus::Validator),
],
validator_count: 3,
minimum_validator_count: 0,
slash_reward_fraction: Perbill::from_percent(10),
invulnerables: vec![alice(), bob(), charlie()],
..Default::default()
},
society: SocietyConfig { pot: 0 },
assets: AssetsConfig { assets: vec![(9, alice(), true, 1)], ..Default::default() },
..Default::default()
}
}
@@ -1,4 +1,4 @@
// This file is part of Substrate.
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -21,10 +21,10 @@
use codec::Encode;
use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, TxExtension, UncheckedExtrinsic};
use node_primitives::{AccountId, Balance, Nonce};
use sp_core::{crypto::get_public_from_string_or_panic, ecdsa, ed25519, sr25519};
use sp_crypto_hashing::blake2_256;
use sp_keyring::Sr25519Keyring;
use sp_runtime::generic::{self, Era, ExtrinsicFormat};
use pezsp_core::{crypto::get_public_from_string_or_panic, ecdsa, ed25519, sr25519};
use pezsp_crypto_hashing::blake2_256;
use pezsp_keyring::Sr25519Keyring;
use pezsp_runtime::generic::{self, Era, ExtrinsicFormat};
/// Alice's account id.
pub fn alice() -> AccountId {
@@ -75,20 +75,20 @@ pub fn session_keys_from_seed(seed: &str) -> SessionKeys {
/// Returns transaction extra.
pub fn tx_ext(nonce: Nonce, extra_fee: Balance) -> TxExtension {
(
frame_system::AuthorizeCall::new(),
frame_system::CheckNonZeroSender::new(),
frame_system::CheckSpecVersion::new(),
frame_system::CheckTxVersion::new(),
frame_system::CheckGenesis::new(),
frame_system::CheckEra::from(Era::mortal(256, 0)),
frame_system::CheckNonce::from(nonce),
frame_system::CheckWeight::new(),
pallet_skip_feeless_payment::SkipCheckIfFeeless::from(
pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(extra_fee, None),
pezframe_system::AuthorizeCall::new(),
pezframe_system::CheckNonZeroSender::new(),
pezframe_system::CheckSpecVersion::new(),
pezframe_system::CheckTxVersion::new(),
pezframe_system::CheckGenesis::new(),
pezframe_system::CheckEra::from(Era::mortal(256, 0)),
pezframe_system::CheckNonce::from(nonce),
pezframe_system::CheckWeight::new(),
pezpallet_skip_feeless_payment::SkipCheckIfFeeless::from(
pezpallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(extra_fee, None),
),
frame_metadata_hash_extension::CheckMetadataHash::new(false),
pallet_revive::evm::tx_extension::SetOrigin::default(),
frame_system::WeightReclaim::new(),
pezframe_metadata_hash_extension::CheckMetadataHash::new(false),
pezpallet_revive::evm::tx_extension::SetOrigin::default(),
pezframe_system::WeightReclaim::new(),
)
}
@@ -124,7 +124,7 @@ pub fn sign(
.into();
generic::UncheckedExtrinsic::new_signed(
payload.0,
sp_runtime::MultiAddress::Id(signed),
pezsp_runtime::MultiAddress::Id(signed),
signature,
tx_ext,
)
+26
View File
@@ -0,0 +1,26 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! A set of testing utilities for Bizinikiwi Node.
#![warn(missing_docs)]
pub mod bench;
pub mod client;
pub mod genesis;
pub mod keyring;
@@ -0,0 +1,51 @@
[package]
name = "pezstaging-chain-spec-builder"
version = "1.6.1"
authors.workspace = true
edition.workspace = true
build = "build.rs"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
homepage.workspace = true
repository.workspace = true
publish = true
description = "Utility for building chain-specification files for Bizinikiwi-based runtimes based on `pezsp-genesis-builder`"
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[[bin]]
path = "bin/main.rs"
name = "chain-spec-builder"
[lib]
# Docs tests are not needed since the code samples that would be executed
# are exercised already in the context of unit/integration tests, by virtue
# of using a combination of encapsulation in functions + `docify::export`.
# This is a practice we should use for new code samples if any.
doctest = false
[dependencies]
clap = { features = ["derive"], workspace = true }
docify = { workspace = true }
pezsc-chain-spec = { features = [
"clap",
], workspace = true, default-features = true }
serde = { workspace = true, default-features = true }
serde_json = { workspace = true, default-features = true }
pezsp-tracing = { workspace = true, default-features = true }
[dev-dependencies]
cmd_lib = { workspace = true }
pretty_assertions = { workspace = true }
bizinikiwi-test-runtime = { workspace = true }
[features]
# `cargo build --feature=generate-readme` updates the `README.md` file.
generate-readme = []
runtime-benchmarks = [
"pezsc-chain-spec/runtime-benchmarks",
"bizinikiwi-test-runtime/runtime-benchmarks",
]
@@ -0,0 +1,168 @@
# Chain Spec Builder
Bizinikiwi's chain spec builder utility.
A chain-spec is short for `chain-specification`. See the [`pezsc-chain-spec`](https://crates.io/docs.rs/pezsc-chain-spec/latest/sc_chain_spec)
for more information.
_Note:_ this binary is a more flexible alternative to the `build-spec` subcommand, contained in typical Bizinikiwi-based nodes.
This particular binary is capable of interacting with [`pezsp-genesis-builder`](https://docs.rs/pezsp-genesis-builder/latest/sp_genesis_builder/index.html)
implementation of any provided runtime allowing to build chain-spec JSON files.
See [`ChainSpecBuilderCmd`](https://docs.rs/pezstaging-chain-spec-builder/6.0.0/staging_chain_spec_builder/enum.ChainSpecBuilderCmd.html)
for a list of available commands.
## Installation
```bash
cargo install pezstaging-chain-spec-builder --locked
```
_Note:_ `chain-spec-builder` binary is published on [crates.io](https://crates.io) under
[`pezstaging-chain-spec-builder`](https://crates.io/crates/pezstaging-chain-spec-builder) due to a name conflict.
## Usage
Please note that below usage is backed by integration tests. The commands' examples are wrapped
around by the `bash!(...)` macro calls.
### Note for `CreateCmd`'s `para-id` flag
<!-- TODO: https://github.com/pezkuwichain/pezkuwi-sdk/issues/156 -->
Runtimes relying on generating the chain specification with this tool should
implement `cumulus_primitives_core::GetTeyrchainInfo` trait, a new runtime API
designed to provide the teyrchain ID from the `teyrchain-info`
pallet. The `para-id` flag can be used though if the runtime does not implement
the runtime API, and the teyrchain id will be fetched by the node from chain
specification. This can be especially useful when syncing a node from a state
where the runtime does not implement `cumulus_primitives_core::GetTeyrchainInfo`.
For reference, generating a chain specification with a `para_id` field can be
done like below:
```bash
chain-spec-builder -c "/dev/stdout" create --relay-chain "dev" --para-id 1000 -r $runtime_path named-preset "staging"
```
### Generate chains-spec using default config from runtime
Query the default genesis config from the provided runtime WASM blob and use it in the chain spec.
<!-- docify::embed!("tests/test.rs", cmd_create_default) -->
_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/pezsp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
runtime function is called.
### Display the runtime's default `GenesisConfig`
<!-- docify::embed!("tests/test.rs", cmd_display_default_preset) -->
_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/pezsp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
runtime function is called.
### Display the `GenesisConfig` preset with given name
<!-- docify::embed!("tests/test.rs", cmd_display_preset)-->
_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/pezsp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
runtime function is called.
### List the names of `GenesisConfig` presets provided by runtime
<!-- docify::embed!("tests/test.rs", cmd_list_presets)-->
_Note:_ [`GenesisBuilder::preset_names`](https://docs.rs/pezsp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.preset_names)
runtime function is called.
### Generate chain spec using runtime provided genesis config preset
Patch the runtime's default genesis config with the named preset provided by the runtime and generate the plain
version of chain spec:
<!-- docify::embed!("tests/test.rs", cmd_create_with_named_preset)-->
_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/pezsp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
runtime functions are called.
### Generate raw storage chain spec using genesis config patch
Patch the runtime's default genesis config with provided `patch.json` and generate raw
storage (`-s`) version of chain spec:
<!-- docify::embed!("tests/test.rs", cmd_create_with_patch_raw)-->
Refer to [_patch file_](#patch-file) for some details on the patch file format.
_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/pezsp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset)
and
[`GenesisBuilder::build_state`](https://docs.rs/pezsp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state)
runtime functions are called.
### Generate raw storage chain spec using full genesis config
Build the chain spec using provided full genesis config json file. No defaults will be used:
<!-- docify::embed!("tests/test.rs", cmd_create_full_raw)-->
Refer to [_full config file_](#full-genesis-config-file) for some details on the full file format.
_Note_: [`GenesisBuilder::build_state`](https://docs.rs/pezsp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state)
runtime function is called.
### Generate human readable chain spec using provided genesis config patch
<!-- docify::embed!("tests/test.rs", cmd_create_with_patch_plain)-->
Refer to [_patch file_](#patch-file) for some details on the patch file format.
### Generate human readable chain spec using provided full genesis config
<!-- docify::embed!("tests/test.rs", cmd_create_full_plain)-->
Refer to [_full config file_](#full-genesis-config-file) for some details on the full file format.
## Patch and full genesis config files
This section provides details on the files that can be used with `create patch` or `create full` subcommands.
### Patch file
The patch file for genesis config contains the key-value pairs valid for given runtime, that needs to be customized,
e.g:
```ignore
{
"balances": {
"balances": [
[
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
1000000000000000
],
[
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
1000000000000000
],
[
"5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b",
5000000000000000
]
]
},
"sudo": {
"key": "5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo"
}
}
```
The rest of genesis config keys will be initialized with default values.
### Full genesis config file
The full genesis config file must contain values for _all_ the keys present in the genesis config for given runtime. The
format of the file is similar to patch format. Example is not provided here as it heavily depends on the runtime.
### Extra tools
The `chain-spec-builder` provides also some extra utilities: [`VerifyCmd`](https://docs.rs/pezstaging-chain-spec-builder/latest/staging_chain_spec_builder/struct.VerifyCmd.html),
[`ConvertToRawCmd`](https://docs.rs/pezstaging-chain-spec-builder/latest/staging_chain_spec_builder/struct.ConvertToRawCmd.html),
[`UpdateCodeCmd`](https://docs.rs/pezstaging-chain-spec-builder/latest/staging_chain_spec_builder/struct.UpdateCodeCmd.html).

Some files were not shown because too many files have changed in this diff Show More