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:
@@ -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
@@ -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",
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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).
|
||||
|
||||
+3
-3
@@ -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> {
|
||||
+3
-3
@@ -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> {
|
||||
+7
-7
@@ -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:
|
||||
+1
-1
@@ -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
@@ -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
|
||||
@@ -0,0 +1,48 @@
|
||||
# Bizinikiwi
|
||||
|
||||
[](#LICENSE)
|
||||
[](https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/pipelines)
|
||||
[](docs/contributor/CONTRIBUTING.md)
|
||||
[](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.
|
||||
@@ -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",
|
||||
]
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -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
|
||||
+2
-2
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -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
-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: 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(),
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
);
|
||||
});
|
||||
}
|
||||
+11
-11
@@ -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();
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
```
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
}
|
||||
@@ -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))
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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()
|
||||
);
|
||||
}
|
||||
+3
-3
@@ -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())
|
||||
+3
-3
@@ -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())
|
||||
+4
-4
@@ -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",
|
||||
+3
-3
@@ -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()
|
||||
}
|
||||
+2
-2
@@ -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()
|
||||
+3
-3
@@ -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")
|
||||
@@ -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())
|
||||
}
|
||||
+4
-4
@@ -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()
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
+3
-3
@@ -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());
|
||||
}
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
+24
-24
@@ -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();
|
||||
|
||||
+7
-7
@@ -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;
|
||||
}
|
||||
+3
-3
@@ -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())
|
||||
@@ -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
-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: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
@@ -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",
|
||||
]
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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])));
|
||||
}
|
||||
}
|
||||
@@ -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"]
|
||||
@@ -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>;
|
||||
@@ -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",
|
||||
]
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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"]
|
||||
@@ -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() {}
|
||||
+2
-2
@@ -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),
|
||||
)
|
||||
}
|
||||
@@ -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
-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
|
||||
@@ -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",
|
||||
]
|
||||
@@ -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, ×tamp)
|
||||
.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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
+19
-19
@@ -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,
|
||||
)
|
||||
@@ -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
Reference in New Issue
Block a user