Compare commits

...

220 Commits
main ... main

Author SHA1 Message Date
fae0fa4d7b
fixes in the readme guide
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-09-01 20:30:49 +03:00
71eb90a5fb
increase stable compiler version to match the ghost-eye dependencies
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-09-01 19:23:20 +03:00
25fcfed586
bump slow clap version
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-08-15 23:07:13 +03:00
f245879925
force parameters for RewardCurve to be a default balance type, which is u64
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-08-14 16:55:46 +03:00
101e7103f1
update specification version of CASPER runtime
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-08-14 16:20:38 +03:00
d9fa416d93
bump locked versions
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-08-10 22:09:14 +03:00
60b887f812
make MulDiv to be used with any 32 bit unsigned
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-08-10 22:07:53 +03:00
f7f25bd087
nullify bridged imbalance on each era reward payout
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-08-10 16:51:04 +03:00
e2c75ca558
implement muldiv without overflow and underflow
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-08-10 16:41:14 +03:00
9240f424e1
prepare starter script for the production
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-08-03 18:43:49 +03:00
72d6be6e29
change finality delay for sepolia in genesis specification
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-31 21:32:49 +03:00
da271a6f22
cargo clean only if the compiler version is downgraded
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 16:35:07 +03:00
b9b7d84466
update ghost-node and specification to the latest version
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 16:32:44 +03:00
8ff588cce9
remove spoiled rpc endpoint from the genesis file
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 16:18:47 +03:00
298a332681
make staking rewards dependant on bridged amount
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 16:17:10 +03:00
1c4c517728
avoiding back in time travel
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 15:30:28 +03:00
b969081cbf
make sure that disabled validator will not be checked with is_good_actor
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 14:21:55 +03:00
9bdb7b5d5c
add an early check for the disabled validator
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 14:02:14 +03:00
c4b16805f7
fix calculation of median, include special case when there're no claps
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 13:56:05 +03:00
f7b1b75d5a
dedup casper spec file
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-30 17:53:39 +03:00
6918e8057a
finalize starter script for the hard reset
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-29 19:41:14 +03:00
df85600159
generate chain spec for the latest ghost-node
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 16:03:34 +03:00
141f05ddab
finalize hard reset for starter script
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-29 16:00:58 +03:00
6ae3fd6291
rustfmt ghost cli and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 15:03:44 +03:00
767161ac9c
rustfmt ghost client cli and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 15:02:07 +03:00
a74e42369b
rustfmt ghost metrics and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 15:00:54 +03:00
7216f1d82b
rustfmt ghost slow clap and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:58:23 +03:00
792e70c988
rustfmt ghost sudo and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:57:58 +03:00
eb3b4f2651
rustfmt ghost rpc and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:54:56 +03:00
24a6f803c5
rustfmt common runtime and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:53:50 +03:00
8d69e5c87e
rustfmt casper runtime and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:51:15 +03:00
48ff511685
rustfmt service and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:49:16 +03:00
8f20b7ef5c
rustfmt tests and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:45:41 +03:00
ce26787a11
rustfmt staking-miner and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:38:49 +03:00
e21ac88235
rustfmt ghostkey and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:27:53 +03:00
c933ed3809
rustfmt generate-bags and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:27:08 +03:00
2ad43a56ba
rustfmt chain-spec-builder and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:26:12 +03:00
6d06fcf9a0
rustfmt bags-utils and fix typos
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:24:30 +03:00
c2f9958c1a
prepare chain spec for the genesis
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 14:09:32 +03:00
2bb66c4e19
update ghost-networks weights for the casper runtime
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 13:30:02 +03:00
63979e34a7
update weights for the ghost-networks based on the latest update
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-29 13:28:46 +03:00
28e8389bfc
fix struct field name in chain-spec
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-29 12:44:01 +03:00
1d826fbf7e
rotate endpoints on each offchain worker exection
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-29 12:42:36 +03:00
0375bd1434
preparation for the benchmarking of upgraded ghost-networks pallet
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-28 23:53:11 +03:00
b4ef445281
make ability to have multiple default endpoints for the network
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-28 23:34:42 +03:00
61056ed162
recomendations for rustc compilation and cargo usage for automation script
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-28 16:28:23 +03:00
b922bf6c20
update weights for casper runtime
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-28 16:20:06 +03:00
fe46566d7e
insert measured weights for ghost-sudo
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-07-28 16:18:24 +03:00
3380d16dc9
extend genesis config with ghost sudo
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-28 13:15:10 +03:00
384380ad55
ghost sudo added as a dependency to casper runtime
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-28 13:13:59 +03:00
4f23c39994
sudo pallet ported as local pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-28 13:12:08 +03:00
67fd48d500
hard reset flag added to starter script
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-28 13:10:07 +03:00
d575895841
make 1 second as a rate limit for default networks rpc endpoints
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-25 19:31:43 +03:00
47f7ae3847
separate evm structs, deserialisation functions and main logic
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-25 19:28:59 +03:00
591cce1fb1
rustfmt the ghost-slow-clap pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-25 18:20:10 +03:00
f7ba592d50
rustfmt the ghost-networks pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-25 18:17:55 +03:00
40a8152f69
rustfmt the ghost-claims pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-25 18:17:14 +03:00
116ca39dc4
rustfmt the ghost-traits pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-25 18:16:06 +03:00
8464da831f
rate limit for the rpc endpoint based on network_id, storage guard lock for the current network_id and other minor improvements
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-25 18:09:29 +03:00
0c3636fe79
bump all pallet versions
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-19 22:38:24 +03:00
d87184bbc2
update weights for the ghost networks pallet
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-19 22:37:03 +03:00
43f72ec842
update weights and add rate_limit_delay for slow claps
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-19 22:35:51 +03:00
ac6d70ae91
update chain specification based on new rate_limit_delay field of NetworkData
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-19 21:40:05 +03:00
49c5f3a9e9
update weights for the casper runtime, benchmarked with stopped ghost-node service
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-19 21:39:17 +03:00
060f61105c
additional network field, that represents default rate limit measured in blocks
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-19 21:32:40 +03:00
b53a58f431
update chain specification because of finality delay non-option type
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-19 15:02:07 +03:00
818f41d05e
update slow claps because of finality delay non-option type
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-19 15:00:30 +03:00
7bb18939bd
no need for finality delay to be an Option<u64>
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-19 14:37:06 +03:00
d8e934a98e
ability to avoid too big deviations between from_block and to_block
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-19 14:31:33 +03:00
d5643472ee
update chain specification based on NetworkData new fields
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-18 18:56:08 +03:00
a503295939
update weights for the ghost-networks on the casper runtime
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-18 18:54:44 +03:00
671196ebac
remove legacy release_delay and add block_distance for maximum block range for the eth_getLogs
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-18 18:53:19 +03:00
39a6192d28
avoid re-using of to_block during rotation of block_range
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-18 17:20:25 +03:00
6100e79ebf
make clap regardless of fail during applause
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-18 17:03:09 +03:00
99c43a0c24
runtime update, with history depth for the slow clap
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-18 14:17:02 +03:00
417de5a7b2
clear storage based on provided history depth
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-18 13:47:13 +03:00
b5845924dc
fixes for the default weights on slow-clap package
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-17 20:56:32 +03:00
7107283121
update casper runtime with pre-calculated weights
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-17 20:46:39 +03:00
f28e57cf8e
add files with weights for the slow-clap, benchmarked according to the casper reference machine
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-17 20:44:44 +03:00
3040dfb775
make benchmark work, issue with authorities fixed
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-17 20:34:42 +03:00
1196cc9faa
changes to runtime based on the new version of ghost-slow claps
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-17 13:54:32 +03:00
66fa8409fa
additional tests for the pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-17 13:50:38 +03:00
5beb22f116
avoid errors from minting sub-existential balance
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-13 16:42:14 +03:00
7be24ed139
use latest version of ghost-networks
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-13 16:22:21 +03:00
b5fc86aa9e
separate bridged imbalance and gatekeeper amount. requested by @st1nky for ghost-slow-clap
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-13 16:16:01 +03:00
e73f3855fd
authorities stored based on the session hash map
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-11 22:56:48 +03:00
a00eec9bb9
tests for clap and applause events added
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-04 16:33:03 +03:00
2c2df5a607
ability to do self applause if claps received
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-04 15:44:53 +03:00
186fb58367
merge new functionality which will be used for benchmarking purposes
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-04 15:40:13 +03:00
1e4abbfe69
function to trigger nullification period, tests for the new functionality and expansion of NetworkData trait
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-04 15:35:48 +03:00
573e57dfb4
new tests based on new ghost-network functinality
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-03 20:41:51 +03:00
46d4716f67
merge extended ghost-networks with ability to nullify accumulated commission
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-03 19:48:23 +03:00
9cb7f3c782
replacing the average claps in session with median to determine a harmful authority
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-03 19:38:07 +03:00
c55d9a05d9
auto nullification during finalization and appropriate tests
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-03 19:06:50 +03:00
5847097e94
extend network inspect handler trait with additional function
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-03 18:58:21 +03:00
04a63e234d
tests updated and small tweaks of the lib
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-02 19:20:14 +03:00
2b738c009b
merge latest ghost-network version
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-02 19:17:16 +03:00
f3d8ee3ab2
make bridge imbalance fields accesible aka public
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-02 19:11:11 +03:00
2da07d7b24
chmod 644 Cargo.toml for ghost-slow-claps
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-31 14:55:30 +03:00
9ba25d6b3d
friendly merge for ghost-claims weights
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-05-31 14:51:53 +03:00
3234341fed
use benchmarked weights as a default weights for ghost-claims pallet
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-31 14:48:08 +03:00
fa2cb811a8
update for slow-claps: remove companions, updgrade block range storage, new way of commission accumulation
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-05-31 14:30:15 +03:00
561d4430b4
another indention fix in main Cargo.toml
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-31 14:21:21 +03:00
b64700fb42
fix indentation in TOML files
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-31 13:12:48 +03:00
b3f85f426c
extend pallet ghost-networks and create BridgedInflationCurve
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-05-30 19:03:50 +03:00
ddec108ced
chmod 644 files in runtime
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-29 13:09:54 +03:00
cd8ad50ac3
chmod 644 utils
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-29 13:04:55 +03:00
e09ce03836
chmod 644 tests
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-29 13:01:30 +03:00
9f6f4953f7
chmod 644 service
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-29 12:59:25 +03:00
40aba0e3af
chmod 644 files in rpc
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-29 12:58:09 +03:00
596d9a6ca7
chmod 644 files in core-primitives
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-29 12:57:26 +03:00
39279697f2
chmod 644 files in cli
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-29 12:56:11 +03:00
d3a18e298a
chmod 644 files in project root
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-29 12:54:26 +03:00
aede9e6e2e
change access permissions of files in pallets folder
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-05-29 12:52:37 +03:00
9ce57763cb
extened the template.service for the node and add Requires= rule
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-04-29 22:02:33 +03:00
eab90d4173
adding first patch for the unit file
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-04-29 21:45:01 +03:00
bdc094663d
fix for the writing to permissioned file
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-03-11 15:57:11 +03:00
a22b6f92d2
pull from @doctor_whoami approved
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-02-25 18:57:20 +03:00
b51c0dffc4
Update README (update testnet version, link to the bootnode list and sha256sum of genesis, small text update)
Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2025-02-17 10:43:11 +03:00
eae752a7bf
issue with --validate flag fixed
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-02-06 20:55:55 +03:00
346d629f95
validator flag added to the starter.sh script
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-02-06 16:21:04 +03:00
8a0cbb94b4
update chain specs
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-30 22:24:30 +03:00
a2afa3fbbc
bump version
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-30 22:11:21 +03:00
885c519519
bridge slashing issue fix
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-30 22:09:32 +03:00
0d796420f2
fix incorrect definition of good actor
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-01-30 15:12:55 +03:00
2298454519
update sha256sum for the new genesis config file
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-21 15:21:27 +03:00
fcc2e170f8
node version update
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-21 15:16:04 +03:00
1fccc49139
v0.0.3 specification added
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-21 15:14:43 +03:00
560ca369cd
new genesis config. whales endowments, new genesis validators and extra params for staking
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-21 13:55:28 +03:00
2b53777b41
alignment for preparation script
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-21 13:47:18 +03:00
bfb023ad4c
additional bootstrap validators based on the Proposal #7
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-21 13:38:34 +03:00
905ad14b73
additional bootstrap validator
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-21 13:33:14 +03:00
11c435893d
downgrade spec version because of ghost-eye compatibility
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-21 13:29:41 +03:00
054bb23910
awakening1
Signed-off-by: ogenkidu <ogenkidu@ghostchain.io>
2025-01-20 12:23:58 -06:00
320ef53b50
Osiris3
Signed-off-by: Barry062 <barry062@ghostchain.io>
2025-01-20 19:15:24 +01:00
1b95024dca
Osiris3
Signed-off-by: Barry062 <barry062@ghostchain.io>
2025-01-20 18:19:21 +01:00
b54c2aee58
awakening1
Signed-off-by: ogenkidu <ogenkidu@ghostchain.io>
2025-01-20 10:57:24 -06:00
a04f19558c
update specification version
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-20 18:38:04 +03:00
4d7330fd4d
remove unneded braces
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-20 18:37:16 +03:00
53d4d9e142
update version for runtime
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-20 18:35:19 +03:00
f1eca789a4
make slashing instant and decrease bonding duration to one era, needed for TUI development only
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-20 18:03:03 +03:00
f4c8144c71
curve parameters changed, make everything 69 because its fun
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-01-20 18:00:55 +03:00
12e6f98dec
Osiris3
Signed-off-by: Barry062 <barry062@ghostchain.io>
2025-01-19 20:38:42 +01:00
4c49cf6ad2
Osiris3
Signed-off-by: Barry062 <barry062@ghostchain.io>
2025-01-19 20:34:04 +01:00
5738d30fbb
ssh and ARM-based instructions added
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-01-13 16:47:32 +03:00
a9e949d95f
Update README (add command for installing wasm on an ARM-based CPU, add SSH service startup command)
Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2025-01-11 22:19:09 +03:00
3fad815039
Merge branch 'PR_48'
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
Merging readme updates, many thanks to Doctor.K
2024-12-23 16:32:51 +03:00
a7cf93b730
Add bootnodes and Update images folder (ghostchain/ghost-node#47 (comment))
Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2024-12-23 16:02:46 +03:00
6aae4ed622
telemetry added as a default to --set-arguments
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2024-12-16 16:16:54 +03:00
e1287e7bab
Merge branch 'PR_46'
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-12-05 13:27:44 +03:00
941da651a8
Add README
Resolves #46

Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2024-12-04 17:19:10 +03:00
cd2d52df1c
temporary finalization test with limited group of validators
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-18 22:52:30 +03:00
8e88ab874f
fix for the read flag
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 23:11:02 +03:00
925b7d7beb
chain spec for testnet v0.0.2
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 21:19:51 +03:00
edc83e9d20
increment ghost version
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 21:18:35 +03:00
e792c8c113
not forcing new session - just let whatever happen
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 21:05:14 +03:00
71701ae427
make the stash balance 69 CSPR and total amount equal to 100 CSPR
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 20:48:38 +03:00
a359361c2c
keys from ghosties file added to the genesis file
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 20:47:19 +03:00
8d9682d71f
fixed ghosties template for the preparation script
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 20:41:22 +03:00
caada5574d
fix for tyron's mistype
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 20:35:18 +03:00
c0470b5c2b
Merge branch 'lastUpdate'
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 20:22:52 +03:00
31ca91ff67
Tyrone-Overit
Signed-off-by: tyronepinnoy <tyrone@pinnoy.net>
2024-11-10 14:28:42 +00:00
50214dfb11
Tyrone Updated Keys
Signed-off-by: tyronepinnoy <tyrone@pinnoy.net>
2024-11-10 14:22:50 +00:00
9d9fd22e1f
Tyrone Updated Keys
Signed-off-by: tyronepinnoy <tyrone@pinnoy.net>
2024-11-10 14:03:44 +00:00
57dad44667
Merge branch 'proxmio-fix-gran-key'
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-10 13:24:42 +03:00
c1ba311bbf
proxmio-fix-gran-key
Signed-off-by: proxmio <git.ghostchain.io.zd3lc@passmail.net>
2024-11-08 08:56:12 +01:00
b847ec7f78
grandpa keys fix for the doctor_k
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-05 17:16:31 +03:00
6f2e4088c1
additional cli argument, if proxy needed
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2024-11-05 16:54:37 +03:00
d12ecf15ec
make the systemd unit file creation as a last step
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2024-11-05 14:26:34 +03:00
7591be9d0b
change old script name
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2024-11-05 14:22:49 +03:00
3e697bf4db
fujisan's keys merged, final fix
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-05 14:20:41 +03:00
b88a1fe880
final changes from pietro0hz for the keys
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-05 14:15:36 +03:00
75399be704
Fujisan-1
Signed-off-by: fujisan <fujisan@ghostchain.io>
2024-11-04 21:58:04 +00:00
88483fb0f1
Fujisan-1
Signed-off-by: fujisan <fujisan@ghostchain.io>
2024-11-04 20:15:27 +00:00
3be0d87dbc
Fujisan-1
Signed-off-by: fujisan <fujisan@ghostchain.io>
2024-11-04 19:49:00 +00:00
eca2f7f26d
Fujisan-1
Signed-off-by: fujisan <fujisan@ghostchain.io>
2024-11-04 17:46:01 +00:00
83dc66520e
Doctor fix GRAN key
Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2024-11-04 19:33:55 +03:00
b7587a4d4f
Add SSH keys to ghosties file 2024-11-04 16:13:12 +01:00
7e37002377
added keys for youconnect
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 16:04:12 +03:00
4beccec324
keys merged for ogenkidu aka satsohi... -_-
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:58:50 +03:00
85a419a90a
tyron's keys are merged
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:56:12 +03:00
268757a80a
zoom's keys are merged
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:55:07 +03:00
d1c47db513
proxmio's keys merged
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:51:48 +03:00
ade1839d9c
second set of keys for kitsune merged
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:50:06 +03:00
ae96c4a78f
scientio branch merged
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:48:35 +03:00
b21b128ac7
keys for mridkwya merged
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:46:23 +03:00
eed94ef8b2
merged first kitsune's keys
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:45:13 +03:00
57b5687ed5
merge keys for sparta
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:41:53 +03:00
3051a399f2
IBN's keys merged
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:40:07 +03:00
b7b168758d
starman's keys merged
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:38:23 +03:00
d49f73ecf4
keys merged for neptune and doctor
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:37:13 +03:00
4dc51af2fd
Merge branch 'neptune-keys'
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2024-11-04 15:32:32 +03:00
7981d2fbab
Fujisan-1
Signed-off-by: fujisan <fujisan@ghostchain.io>
2024-11-01 00:05:44 +00:00
198671f68c
Youconnect keys changes to service/ghosties 2024-11-01 00:34:10 +01:00
701fcb2aad
Fujisan-1
Signed-off-by: fujisan <fujisan@ghostchain.io>
2024-10-31 22:55:55 +00:00
25e747caf7
ogenkidu
Signed-off-by: ogenkidu <ogenkidu@ghostchain.io>
2024-10-31 12:39:14 -05:00
eaa83536b8
tyronecommit
Signed-off-by: tyronepinnoy <tyrone@pinnoy.net>
2024-10-31 12:34:28 +00:00
4aa009f4db
tyroneghost
Signed-off-by: tyronepinnoy <tyrone@pinnoy.net>
2024-10-31 12:17:56 +00:00
3e455f23ef
My Submission for Genesis Code - GhostBranch
Signed-off-by: root tyrone@pinnoy.net
2024-10-31 12:11:16 +00:00
f28f905777
ssh-zoomnode
Signed-off-by: zoom_zam <zoom_zam@ghostchain.io>
2024-10-31 10:56:30 +00:00
4141fb834e
fujisan1
Signed-off-by: JMLFreedom <jmlfreedom@ghostchain.io>
2024-10-30 21:51:04 +00:00
27169e8eb6
proxmio
Signed-off-by: proxmio <git.ghostchain.io.zd3lc@passmail.net>
2024-10-30 22:22:57 +01:00
63b17a19a0
Kitsune1
Signed-off-by: Kitsune <KitsuneGhost@hotmail.com>
2024-10-30 21:46:06 +01:00
37bf0b56b4
Kitsune1
Signed-off-by: Kitsune <KitsuneGhost@hotmail.com>
2024-10-30 21:40:09 +01:00
3afca3794f
Kitsune
Signed-off-by: Kitsune <KitsuneGhost@hotmail.com>
2024-10-30 10:48:31 +00:00
8a431fa777
youaresparta
Signed-off-by: sparta <propitiouspartners@gmail.com>
2024-10-29 20:22:03 -05:00
88f47b61e5
mridkwya
Signed-off-by: mridkwya <mridkwya@ghostchain.io>
2024-10-29 18:39:53 -04:00
IBN
36ee6627f6
IBN1
Signed-off-by: IBN <ilya@ghostchain.io>
2024-10-29 11:12:36 +03:00
18c6094e3f
separate logic for user creation and folder preparation
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2024-10-28 14:00:22 +03:00
e182e86590
no need to have staging in runtime presets, removed
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2024-10-28 13:42:33 +03:00
98e65f891e
small typo fix of description
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2024-10-28 13:41:03 +03:00
b43a38e80f
youaresparta
Signed-off-by: sparta <propitiouspartners@gmail.com>
2024-10-27 20:24:22 -05:00
8ea9bc57ee
doctor_conf_n3
Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2024-10-28 02:26:58 +03:00
407bf934a1
doctor_conf_n2
Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2024-10-28 02:25:55 +03:00
738482fd80
starman
Signed-off-by: Paul <leaper23@ghostchain.io>
2024-10-27 13:39:01 -07:00
AJ
7f1cead55e
scientio
Signed-off-by: AJ <scientio.eth@gmail.com>
2024-10-27 12:01:46 -07:00
aeebed6fc8
doctor_conf_n
Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2024-10-27 15:46:16 +03:00
74ff7e9f5b
doctor_conf
Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2024-10-27 13:42:35 +03:00
f9243bc628
starman 2024-10-26 11:32:58 -07:00
f529f224dd
for arm cpu
Signed-off-by: neptune <neptune3526@proton.me>
2024-10-24 12:53:38 -04:00
174 changed files with 10924 additions and 5216 deletions

60
Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "Inflector"
@ -1186,7 +1186,7 @@ dependencies = [
[[package]]
name = "casper-runtime"
version = "3.5.18"
version = "3.5.31"
dependencies = [
"casper-runtime-constants",
"frame-benchmarking",
@ -1203,7 +1203,7 @@ dependencies = [
"ghost-networks",
"ghost-runtime-common",
"ghost-slow-clap",
"hex-literal",
"ghost-sudo",
"log",
"pallet-alliance",
"pallet-authority-discovery",
@ -3505,7 +3505,7 @@ dependencies = [
[[package]]
name = "ghost-claims"
version = "0.2.2"
version = "0.2.4"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -3529,7 +3529,7 @@ dependencies = [
[[package]]
name = "ghost-cli"
version = "0.7.179"
version = "0.8.2"
dependencies = [
"cfg-if",
"clap 4.5.4",
@ -3561,7 +3561,7 @@ dependencies = [
[[package]]
name = "ghost-client-cli"
version = "0.1.3"
version = "0.1.4"
dependencies = [
"array-bytes",
"clap 4.5.4",
@ -3585,7 +3585,7 @@ dependencies = [
[[package]]
name = "ghost-machine-primitives"
version = "0.7.179"
version = "0.8.2"
dependencies = [
"lazy_static",
"sc-sysinfo",
@ -3594,7 +3594,7 @@ dependencies = [
[[package]]
name = "ghost-metrics"
version = "0.7.179"
version = "0.8.2"
dependencies = [
"assert_cmd",
"bs58 0.5.1",
@ -3617,7 +3617,7 @@ dependencies = [
[[package]]
name = "ghost-miner"
version = "1.5.0"
version = "1.5.1"
dependencies = [
"anyhow",
"assert_cmd",
@ -3649,14 +3649,17 @@ dependencies = [
[[package]]
name = "ghost-networks"
version = "0.7.179"
version = "0.1.16"
dependencies = [
"frame-benchmarking",
"frame-support",
"frame-system",
"ghost-core-primitives",
"ghost-traits",
"num-traits",
"pallet-balances",
"pallet-staking",
"pallet-staking-reward-curve",
"parity-scale-codec",
"scale-info",
"sp-io 30.0.0",
@ -3666,7 +3669,7 @@ dependencies = [
[[package]]
name = "ghost-node"
version = "0.7.179"
version = "0.8.2"
dependencies = [
"assert_cmd",
"color-eyre",
@ -3682,7 +3685,7 @@ dependencies = [
[[package]]
name = "ghost-remote-ext-tests-bags-list"
version = "1.0.0"
version = "1.0.1"
dependencies = [
"casper-runtime",
"casper-runtime-constants",
@ -3697,7 +3700,7 @@ dependencies = [
[[package]]
name = "ghost-rpc"
version = "0.7.179"
version = "0.8.2"
dependencies = [
"ghost-core-primitives",
"jsonrpsee",
@ -3726,7 +3729,7 @@ dependencies = [
[[package]]
name = "ghost-runtime-common"
version = "0.4.2"
version = "0.4.3"
dependencies = [
"frame-support",
"frame-system",
@ -3749,7 +3752,7 @@ dependencies = [
[[package]]
name = "ghost-service"
version = "0.7.179"
version = "0.8.2"
dependencies = [
"assert_matches",
"async-trait",
@ -3833,7 +3836,7 @@ dependencies = [
[[package]]
name = "ghost-slow-clap"
version = "0.3.14"
version = "0.3.40"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -3842,6 +3845,8 @@ dependencies = [
"log",
"pallet-balances",
"pallet-session",
"pallet-staking",
"pallet-staking-reward-curve",
"parity-scale-codec",
"scale-info",
"serde",
@ -3856,7 +3861,7 @@ dependencies = [
[[package]]
name = "ghost-staging-chain-spec-builder"
version = "1.6.1"
version = "1.6.2"
dependencies = [
"clap 4.5.4",
"log",
@ -3865,9 +3870,24 @@ dependencies = [
"sp-tracing 16.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.12.0)",
]
[[package]]
name = "ghost-sudo"
version = "0.0.2"
dependencies = [
"docify",
"frame-benchmarking",
"frame-support",
"frame-system",
"parity-scale-codec",
"scale-info",
"sp-io 30.0.0",
"sp-runtime 31.0.1",
"sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.12.0)",
]
[[package]]
name = "ghost-traits"
version = "0.3.19"
version = "0.3.23"
dependencies = [
"frame-support",
"sp-runtime 31.0.1",
@ -3875,7 +3895,7 @@ dependencies = [
[[package]]
name = "ghost-voter-bags"
version = "0.3.6"
version = "0.3.7"
dependencies = [
"casper-runtime",
"clap 4.5.4",
@ -3885,7 +3905,7 @@ dependencies = [
[[package]]
name = "ghostkey"
version = "0.3.15"
version = "0.3.16"
dependencies = [
"clap 4.5.4",
"ghost-client-cli",

View File

@ -17,7 +17,7 @@ homepage.workspace = true
[workspace.package]
license = "GPL-3.0-only"
authors = ["571nky", "57r37ch", "f4750"]
version = "0.7.179"
version = "0.8.2"
edition = "2021"
homepage = "https://ghostchain.io"
repository = "https://git.ghostchain.io/ghostchain/ghost-node"
@ -69,6 +69,7 @@ bs58 = { version = "0.5.0" }
prometheus-parse = { version = "0.2.2" }
rustc-hex = { version = "2.1.0", default-features = false }
log = { version = "0.4", default-features = false }
num-traits = { version = "0.2.17", default-features = false }
libsecp256k1 = { version = "0.7", default-features = false }
bip39 = { package = "parity-bip39", version = "2.0.1" }
sha3 = { version = "0.10", default-features = false }
@ -229,6 +230,7 @@ ghost-traits = { path = "pallets/traits", default-features = false }
ghost-networks = { path = "pallets/networks", default-features = false }
ghost-claims = { path = "pallets/claims", default-features = false }
ghost-slow-clap = { path = "pallets/slow-clap", default-features = false }
ghost-sudo = { path = "pallets/sudo", default-features = false }
ghost-runtime-constants = { package = "ghost-runtime-constants", path = "runtime/ghost/constants", default-features = false }
casper-runtime = { path = "runtime/casper", default-features = false }
casper-runtime-constants = { package = "casper-runtime-constants", path = "runtime/casper/constants", default-features = false }
@ -258,24 +260,25 @@ substrate-build-script-utils = { workspace = true }
resolver = "2"
members = [
"core-primitives",
"core-primitives",
"cli",
"rpc",
"service",
"rpc",
"service",
"metrics",
"client/cli",
"primitives/machine",
"runtime/common",
"runtime/casper",
"runtime/casper/constants",
"pallets/networks",
"pallets/claims",
"pallets/slow-clap",
"utils/bags-list",
"utils/chain-spec-builder",
"utils/generate-bags",
"runtime/common",
"runtime/casper",
"runtime/casper/constants",
"pallets/networks",
"pallets/claims",
"pallets/slow-clap",
"pallets/sudo",
"utils/bags-list",
"utils/chain-spec-builder",
"utils/generate-bags",
"utils/ghostkey",
"utils/staking-miner",
"utils/staking-miner",
]
[badges]

0
LICENSE.md Executable file → Normal file
View File

462
README.md Executable file → Normal file
View File

@ -1 +1,461 @@
TODO
# Notes
Arrows will mark the places where your input is needed
# Update system
Update Your System: Before installing any new software,
it's a good practice to update your system's package list and
upgrade the existing packages to their latest versions.
```bash
sudo apt update
sudo apt upgrade
```
# Firewall
Install Ubuntu firewall
```bash
sudo apt install ufw
```
If you want to connect to your node-machine, allow connection to the SSH port
```bash
sudo ufw allow ssh
```
![images/img.png](images/img.png)
Enable firewall, confirm the operation
```bash
sudo ufw enable
```
![images/img_1.png](images/img_1.png)
Check firewall status. You should see `Status: active`
```bash
sudo ufw numbered
```
![images/img_2.png](images/img_2.png)
# SSH
## Install SSH
Once you have installed the proper Operating System on you machine
we recommend that you enable SSH. Most people have a Daily Driver machine.
GHOST requires a separate machine. Adding an extra machine to your life could be cumbersome.
Chances are you had to use an external monitor to install Ubuntu on GHOST Node,
the same screen regularly used by the Daily Driver machine.
SSH enables you to manage your GHOST Nodes remotely from the comfort of your Daily Driver.
Install OpenSSH Server: With your system updated, the next step is to install
the OpenSSH server package. This package contains the necessary software to run
an SSH server.
```bash
sudo apt install openssh-server
```
Start SSH Service using _systemctl_.
```bash
sudo systemctl start ssh
```
Enable SSH Service to Start on Boot: To ensure that the SSH service automatically
starts after a reboot, you need to enable it using _systemctl_.
```bash
sudo systemctl enable ssh
```
To check the status of the SSH service, run the following command:
```bash
sudo systemctl status ssh
```
You should be seeing something like this:
![images/img_3.png](images/img_3.png)
## Connect by SSH
With SSH enabled and the firewall configured, you can now connect
to your node machine from another computer using SSH.
You have to know your username and your local network ip
```bash
ssh [username]@[your_server_ip_OR_hostname]
```
# Install GHOST Application
## Allow Ports
Allow `port 30333` on GHOST Node:
```bash
sudo ufw allow 30333
```
![images/img_5.png](images/img_5.png)
To ensure that the ports are allowed, run the following command:
```bash
sudo ufw numbered
```
![images/img_6.png](images/img_6.png)
## Install Substrate Libraries
Click [here](https://docs.substrate.io/install/linux/) for a detailed Rust guide if you want to dive deep into the documentation. Otherwise let's proceed.
### Install Dependencies
Check the documentation for your operating system for information about
the packages that are installed and how to download and install
any additional packages you might need. For example,
if you use Debian/Ubuntu, you can use the Advanced Packaging Tool (apt)
to install packages:
```bash
sudo apt install -y build-essential clang curl git make libssl-dev protobuf-compiler llvm libudev-dev
```
### Rust Install
Download the rustup installation program and use it to install Rust by running the following command:
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Press Enter for using default options:
![images/img_7.png](images/img_7.png)
Update your current shell to include Cargo by running the following command:
```bash
source $HOME/.cargo/env
```
Verify your installation by running the following command:
```bash
rustc --version
```
You should see something like this:
![images/img_8.png](images/img_8.png)
Configure the Rust toolchain to default to the latest stable version by running the following commands:
```bash
rustup default stable
```
```bash
rustup update
```
```bash
rustup target add wasm32-unknown-unknown --toolchain stable
```
Verify the configuration of your development environment by running
the following command:
```bash
rustup show
```
You should see something like this:
![images/img_9.png](images/img_9.png)
![images/img_10.png](images/img_10.png)
Now run:
```bash
rustup component add rust-src --toolchain stable
```
## Install GHOST
Check if Git is already installed:
```bash
git --version
```
![images/img_11.png](images/img_11.png)
Make a GHOST Directory and go to it:
```bash
mkdir ~/ghost && cd ~/ghost
```
Clone GHOST Node Git:
```bash
git clone https://git.ghostchain.io/ghostchain/ghost-node.git
```
Go to ghost-node directory:
```bash
cd ghost-node
```
Compile the node template by running the following command:
```bash
./scripts/starter.sh --release
```
The build can take up to 20 minutes depending on the specifications of your machine.
![images/img_12.png](images/img_12.png)
# Boot Node Qualification
## Boot Node Qualification Test
Becoming a Boot Node on GHOST Chain is an absolute MUST if we want the network
to be sufficiently decentralized. However, due to certain ISP limitations
some countries make it being a Boot Node easier than others.
Hence, the GHOST Dev team came up with a Boot Node Qualification Test.
First we should install TRACEROUTE:
```bash
sudo apt install traceroute
```
Then we must determine the public IP for your GHOST Node Machine.
```bash
curl -4 icanhazip.com
```
![images/img_13.png](images/img_13.png)
Then type the following command replacing `<YOUR_IP_FROM_PREVIOUS_STEP>` with an actual IP address from previous step:
```bash
traceroute <YOUR_IP_FROM_PREVIOUS_STEP>
```
If your GHOST Node is **not behind a NAT** your terminal window should look something like this:
![images/img_14.png](images/img_14.png)
If your GHOST Node is **behind NAT** your terminal window should look something like this:
![images/img_15.png](images/img_15.png)
If your GHOST Node is NOT behind the NAT then your node can be a Boot Node.
If your GHOST Node is behind the NAT then your node CANNOT be a Boot Node
and you will have to use some kind of proxy to rectify the situation.
Afterwards, post the screenshot of your terminal window in the Whales group.
Feel free to blur out your IP.
## Setting Proper Firewall Rules
You must enable `port 30333` on your router
Based on prior instructions you may have configured your firewall in way that is
no longer needed. For the purpose of GHOST Chain you should only
open `port 30333` and close other ports.
### Checking Firewall
Check the ports that are opened on your firewall:
```bash
sudo ufw numbered
```
![images/img_16.png](images/img_16.png)
If `port 9945` is opened then close it:
```bash
sudo ufw deny 9945
```
### Configuring Router
Enable port forwarding for port 30333 on your router. Be mindful that different networks and routers have different ways of setting this up. It is best to search for portforwarding instruction for the specific router model.
![images/img_17.png](images/img_17.png)
### Checking Ports
Simulate a broadcasting node by running a dummy GHOST Node launch command:
```bash
./target/release/ghost --port=30333 --rpc-port=9945 --chain=dev --node-key=0000000000000000000000000000000000000000000000000000000000000001 --base-path=/tmp/alice --alice --validator --unsafe-rpc-external --no-telemetry --state-pruning=archive
```
To check ports go to [Port Checker Website](https://dnschecker.org/port-scanner.php) and check following ports:
```
30333, 9945
```
Only `port 30333` should be opened.
![images/img_18.png](images/img_18.png)
Press _CTRL+C_ to stop the node.
# Launching GHOST TestNet
Switch to main GIT branch:
```bash
git switch main
```
Make sure `ghost-node` is up to date:
```bash
git pull origin main
```
## Generating keys
Create ghost configuration directory:
```bash
sudo mkdir /etc/ghost
```
Give the user permission to the directory:
```bash
sudo chown $(whoami) /etc/ghost
```
To generate the node key use the following command:
```bash
./target/release/ghost key generate-node-key --bin --file=/etc/ghost/node-key
```
Feel free to backup the file on a separate storage device.
## Build and start the ghost-node
Recompile `ghost-node` using `starter.sh` and `--release` flag.
Make `ghost-node` service being able to be started by default user
using `--make-global`:
```bash
./scripts/starter.sh --release --make-global
```
We need to recompile so type y and press Enter to proceed:
![images/img_20.png](images/img_20.png)
Recompiling will take some time!
The script needs higher permissions to write the ghost-node startup file, so it may ask for your user's password
![images/img_21.png](images/img_21.png)
![images/img_28.png](images/img_28.png)
Check the hash of the build:
```bash
sha256sum /etc/ghost/casper.json
```
You should see:
```
9da6045ed6d4fd844e3939573b31c013d0e564e542029330faa6d978cb4a915a
```
Create running `ghost-node` service that starts on system boot using `--unit-file` flag.
And we must set up the `ghost-node` launch command by setting arguments using
`--set-arguments` flag:
```bash
./scripts/starter.sh --unit-file --set-arguments
```
Only change the defaults if you are advanced otherwise press _Enter_ for
the following prompts.
If this is your first node simply press _Enter_ to proceed with the default.
If this is your second node you should type a different port here,
for example `30334`, and then you should open this port on your firewall
and create a dedicated port forwarding rule on your router as specified
in the Testing Connectivity Part:
```
specify p2p protocol TCP port (default: 30333): 30334
```
To choose default options press Enter here:
![images/img_30.png](images/img_30.png)
If you want to validate from this node press Enter:
```
disable validator mode? [y/N]: y
```
![images/img_31.png](images/img_31.png)
Press _Enter_ for reject enabling Prometheus:
![images/img_32.png](images/img_32.png)
For the following prompt:
```
list of bootnodes if any:
```
Paste one of available **Boot Node** addresses.
Official **Boot Node** addresses:
```
/dns/bootnode69.chain.ghostchain.io/tcp/30334/p2p/12D3KooWF9SWxz9dmy6vfndQhoxqCa7PESaoFWEiF8Jkqh4xKDRf
```
```
/dns/bootnode70.chain.ghostchain.io/tcp/30333/p2p/12D3KooWP3h5dSdqcpvsCr7fp1jyfqDj291QDZ68a4gY6VQ8T1nW
```
A full list of available **Boot Nodes** can be found on [the guide page](https://blog.ghostchain.io/launching-ghost-testnet-3-1/#Boot_Node).
![images/img_33.png](images/img_33.png)
Press _Enter_:
![images/img_34.png](images/img_34.png)
Changing `unit-file` name is optional, otherwise press _Enter_:
![images/img_35.png](images/img_35.png)
Type `y` and press _Enter_ for create dedicated user for running `ghost-node`:
![images/img_36.png](images/img_36.png)
**DO NOT start and DO NOT enable** `ghost-node.service` (press _Enter_):
![images/img_37.png](images/img_37.png)
Full Node:
![images/img_38.png](images/img_38.png)
Validator Node:
![images/img_39.png](images/img_39.png)
Start `ghost-node`:
```bash
sudo systemctl start ghost-node
```
Wait ~60 seconds!
Check node is started:
```bash
sudo systemctl status ghost-node
```
![images/img_40.png](images/img_40.png)
For exit press _CTRL+C_
Restart `ghost-node`:
```bash
sudo systemctl restart ghost-node
```
Enable `ghost-node`:
```bash
sudo systemctl enable ghost-node
```
![images/img_41.png](images/img_41.png)
To see the logs produced by your `ghost-node`:
```bash
journalctl -f -u ghost-node
```
To exit press _CTRL+C_.
Congratulations! You have an operational GHOST Node.

16
cli/Cargo.toml Executable file → Normal file
View File

@ -1,6 +1,6 @@
[package]
name = "ghost-cli"
description = "Implementation of a Ghost Client Node in Rust"
description = "Implementation of the Ghost Client Node in Rust"
version.workspace = true
edition.workspace = true
authors.workspace = true
@ -52,14 +52,14 @@ substrate-build-script-utils = { workspace = true }
default = ["cli", "db", "full-node"]
db = ["service/db"]
cli = [
"clap",
"clap",
"frame-benchmarking-cli",
"sc-cli",
"sc-service",
"sc-tracing",
"service",
"ghost-client-cli",
"ghost-machine-primitives",
"sc-cli",
"sc-service",
"sc-tracing",
"service",
"ghost-client-cli",
"ghost-machine-primitives",
]
runtime-benchmarks = [
"frame-benchmarking-cli?/runtime-benchmarks",

2
cli/build.rs Executable file → Normal file
View File

@ -1,4 +1,4 @@
fn main () {
fn main() {
if let Ok(profile) = std::env::var("PROFILE") {
println!("cargo:rustc-cfg=build_type=\"{}\"", profile);
}

2
cli/src/cli.rs Executable file → Normal file
View File

@ -84,7 +84,7 @@ pub struct RunCmd {
#[arg(long)]
pub no_hardware_benchmarks: bool,
/// Enable the block authoring backoff that is triggered when finality is
/// Enable the block authoring backoff that is triggered when finality is
/// lagging.
#[arg(long)]
pub force_authoring_backoff: bool,

191
cli/src/command.rs Executable file → Normal file
View File

@ -1,14 +1,13 @@
use crate::cli::{Cli, Subcommand};
use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory};
use futures::future::TryFutureExt;
use keyring::Sr25519Keyring;
use sc_cli::SubstrateCli;
use service::{
self, IdentifyVariant,
benchmarking::{
benchmark_inherent_data, RemarkBuilder, TransferKeepAliveBuilder
},
self,
benchmarking::{benchmark_inherent_data, RemarkBuilder, TransferKeepAliveBuilder},
IdentifyVariant,
};
use keyring::Sr25519Keyring;
pub use crate::{error::Error, service::BlockId};
#[cfg(feature = "pyroscope")]
@ -68,28 +67,35 @@ impl SubstrateCli for Cli {
#[cfg(feature = "casper-native")]
"casper" => Box::new(service::chain_spec::casper_config()?),
#[cfg(feature = "casper-native")]
"casper-dev" | "dev" | "development" => Box::new(service::chain_spec::casper_development_config()?),
"casper-dev" | "dev" | "development" => {
Box::new(service::chain_spec::casper_development_config()?)
}
#[cfg(feature = "casper-native")]
"casper-local" | "local" => Box::new(service::chain_spec::casper_local_testnet_config()?),
"casper-local" | "local" => {
Box::new(service::chain_spec::casper_local_testnet_config()?)
}
#[cfg(feature = "casper-native")]
"casper-staging" | "staging" => Box::new(service::chain_spec::casper_staging_testnet_config()?),
"casper-staging" | "staging" => {
Box::new(service::chain_spec::casper_staging_testnet_config()?)
}
#[cfg(not(feature = "casper-native"))]
name if name.starts_with("casper-") && !name.ends_with(".json") =>
Err(format!("`{}` only supported with `casper-native` feature enabled.", name))?,
name if name.starts_with("casper-") && !name.ends_with(".json") => Err(format!(
"`{}` only supported with `casper-native` feature enabled.",
name
))?,
#[cfg(feature = "casper-native")]
path => {
let path = std::path::PathBuf::from(path);
let chain_spec = Box::new(
service::GenericChainSpec::from_json_file(path.clone())?
) as Box<dyn service::ChainSpec>;
let chain_spec = Box::new(service::GenericChainSpec::from_json_file(path.clone())?)
as Box<dyn service::ChainSpec>;
if chain_spec.is_casper() {
Box::new(service::CasperChainSpec::from_json_file(path)?)
Box::new(service::CasperChainSpec::from_json_file(path)?)
} else {
chain_spec
chain_spec
}
},
}
})
}
}
@ -109,10 +115,7 @@ fn set_ss58_version(spec: &Box<dyn service::ChainSpec>) {
sp_core::crypto::set_default_ss58_version(ss58_version);
}
fn run_node_inner<F>(
cli: Cli,
logger_hook: F,
) -> Result<()>
fn run_node_inner<F>(cli: Cli, logger_hook: F) -> Result<()>
where
F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration),
{
@ -128,7 +131,8 @@ where
.then_some(config.database.path().map(|database_path| {
let _ = std::fs::create_dir_all(&database_path);
sc_sysinfo::gather_hwbench(Some(database_path))
})).flatten();
}))
.flatten();
let database_source = config.database.clone();
let task_manager = service::build_full(
@ -138,7 +142,8 @@ where
telemetry_worker_handle: None,
hwbench,
},
).map(|full| full.task_manager)?;
)
.map(|full| full.task_manager)?;
if let Some(path) = database_source.path() {
sc_storage_monitor::StorageMonitorService::try_spawn(
@ -167,7 +172,9 @@ pub fn run() -> Result<()> {
let agent = pyro::Pyroscope::builder(
"http://".to_owned() + address.to_string().as_str(),
"ghost".to_owned(),
).backend(pprof_backend(PprofConfig::new().sample_rate(113))).build()?;
)
.backend(pprof_backend(PprofConfig::new().sample_rate(113)))
.build()?;
Some(agent.start()?)
} else {
@ -176,7 +183,7 @@ pub fn run() -> Result<()> {
#[cfg(not(feature = "pyroscope"))]
if cli.run.pyroscope_server.is_some() {
return Err(Error::PyroscopeNotCompiledIn)
return Err(Error::PyroscopeNotCompiledIn);
}
match &cli.subcommand {
@ -184,7 +191,7 @@ pub fn run() -> Result<()> {
Some(Subcommand::BuildSpec(cmd)) => {
let runner = cli.create_runner(cmd).map_err(Error::SubstrateCli)?;
Ok(runner.sync_run(|config| cmd.run(config.chain_spec, config.network))?)
},
}
Some(Subcommand::CheckBlock(cmd)) => {
let runner = cli.create_runner(cmd).map_err(Error::SubstrateCli)?;
let chain_spec = &runner.config().chain_spec;
@ -192,11 +199,13 @@ pub fn run() -> Result<()> {
set_ss58_version(chain_spec);
runner.async_run(|mut config| {
let (client, _, import_queue, task_manager) =
service::new_chain_ops(&mut config)?;
Ok((cmd.run(client, import_queue).map_err(Error::SubstrateCli), task_manager))
let (client, _, import_queue, task_manager) = service::new_chain_ops(&mut config)?;
Ok((
cmd.run(client, import_queue).map_err(Error::SubstrateCli),
task_manager,
))
})
},
}
Some(Subcommand::ExportBlocks(cmd)) => {
let runner = cli.create_runner(cmd).map_err(Error::SubstrateCli)?;
let chain_spec = &runner.config().chain_spec;
@ -204,11 +213,14 @@ pub fn run() -> Result<()> {
set_ss58_version(chain_spec);
Ok(runner.async_run(|mut config| {
let ( client, _, _, task_manager ) =
service::new_chain_ops(&mut config)?;
Ok((cmd.run(client, config.database).map_err(Error::SubstrateCli), task_manager))
let (client, _, _, task_manager) = service::new_chain_ops(&mut config)?;
Ok((
cmd.run(client, config.database)
.map_err(Error::SubstrateCli),
task_manager,
))
})?)
},
}
Some(Subcommand::ExportState(cmd)) => {
let runner = cli.create_runner(cmd).map_err(Error::SubstrateCli)?;
let chain_spec = &runner.config().chain_spec;
@ -216,11 +228,14 @@ pub fn run() -> Result<()> {
set_ss58_version(chain_spec);
Ok(runner.async_run(|mut config| {
let ( client, _, _, task_manager ) =
service::new_chain_ops(&mut config)?;
Ok((cmd.run(client, config.chain_spec).map_err(Error::SubstrateCli), task_manager))
let (client, _, _, task_manager) = service::new_chain_ops(&mut config)?;
Ok((
cmd.run(client, config.chain_spec)
.map_err(Error::SubstrateCli),
task_manager,
))
})?)
},
}
Some(Subcommand::ImportBlocks(cmd)) => {
let runner = cli.create_runner(cmd).map_err(Error::SubstrateCli)?;
let chain_spec = &runner.config().chain_spec;
@ -228,15 +243,17 @@ pub fn run() -> Result<()> {
set_ss58_version(chain_spec);
Ok(runner.async_run(|mut config| {
let ( client, _, import_queue, task_manager ) =
service::new_chain_ops(&mut config)?;
Ok((cmd.run(client, import_queue).map_err(Error::SubstrateCli), task_manager))
let (client, _, import_queue, task_manager) = service::new_chain_ops(&mut config)?;
Ok((
cmd.run(client, import_queue).map_err(Error::SubstrateCli),
task_manager,
))
})?)
},
}
Some(Subcommand::PurgeChain(cmd)) => {
let runner = cli.create_runner(cmd).map_err(Error::SubstrateCli)?;
Ok(runner.sync_run(|config| cmd.run(config.database))?)
},
}
Some(Subcommand::Revert(cmd)) => {
let runner = cli.create_runner(cmd).map_err(Error::SubstrateCli)?;
let chain_spec = &runner.config().chain_spec;
@ -244,62 +261,59 @@ pub fn run() -> Result<()> {
set_ss58_version(chain_spec);
Ok(runner.async_run(|mut config| {
let (client, backend, _, task_manager) =
service::new_chain_ops(&mut config)?;
let (client, backend, _, task_manager) = service::new_chain_ops(&mut config)?;
let aux_revert = Box::new(|client, backend, blocks| {
service::revert_backend(client, backend, blocks).map_err(|err| {
match err {
service::Error::Blockchain(err) => err.into(),
err => sc_cli::Error::Application(err.into()),
}
service::revert_backend(client, backend, blocks).map_err(|err| match err {
service::Error::Blockchain(err) => err.into(),
err => sc_cli::Error::Application(err.into()),
})
});
Ok((
cmd.run(client, backend, Some(aux_revert)).map_err(Error::SubstrateCli),
task_manager
cmd.run(client, backend, Some(aux_revert))
.map_err(Error::SubstrateCli),
task_manager,
))
})?)
},
}
Some(Subcommand::Benchmark(cmd)) => {
let runner = cli.create_runner(cmd).map_err(Error::SubstrateCli)?;
let chain_spec = &runner.config().chain_spec;
match cmd {
#[cfg(not(feature = "runtime-benchmarks"))]
BenchmarkCmd::Storage(_) =>
BenchmarkCmd::Storage(_) => {
return Err(sc_cli::Error::Input(
"Compile with `--feature=runtime-benchmarks \
to enable storage benchmarks.".into()
).into()),
to enable storage benchmarks."
.into(),
)
.into())
}
#[cfg(feature = "runtime-benchmarks")]
BenchmarkCmd::Storage(cmd) => runner.sync_run(|mut config| {
let (client, backend, _, _,) =
service::new_chain_ops(&mut config)?;
let (client, backend, _, _) = service::new_chain_ops(&mut config)?;
let db = backend.expose_db();
let storage = backend.expose_storage();
cmd.run(config, client.clone(), db, storage).map_err(Error::SubstrateCli)
cmd.run(config, client.clone(), db, storage)
.map_err(Error::SubstrateCli)
}),
BenchmarkCmd::Block(cmd) => runner.sync_run(|mut config| {
let (client, _, _, _,) =
service::new_chain_ops(&mut config)?;
let (client, _, _, _) = service::new_chain_ops(&mut config)?;
cmd.run(client.clone()).map_err(Error::SubstrateCli)
}),
// These commands are very similar and can be handled in nearly the same way
BenchmarkCmd::Extrinsic(_) | BenchmarkCmd::Overhead(_) =>
BenchmarkCmd::Extrinsic(_) | BenchmarkCmd::Overhead(_) => {
runner.sync_run(|mut config| {
let (client, _, _, _) =
service::new_chain_ops(&mut config)?;
let (client, _, _, _) = service::new_chain_ops(&mut config)?;
let inherent_data = benchmark_inherent_data()
.map_err(|e| format!("generating inherent data: {:?}", e))?;
let remark_builder = RemarkBuilder::new(
client.clone(),
config.chain_spec.identify_chain(),
);
let remark_builder =
RemarkBuilder::new(client.clone(), config.chain_spec.identify_chain());
match cmd {
BenchmarkCmd::Extrinsic(cmd) => {
@ -316,17 +330,20 @@ pub fn run() -> Result<()> {
cmd.run(client.clone(), inherent_data, Vec::new(), &ext_factory)
.map_err(Error::SubstrateCli)
},
BenchmarkCmd::Overhead(cmd) => cmd.run(
config,
client.clone(),
inherent_data,
Vec::new(),
&remark_builder,
).map_err(Error::SubstrateCli),
}
BenchmarkCmd::Overhead(cmd) => cmd
.run(
config,
client.clone(),
inherent_data,
Vec::new(),
&remark_builder,
)
.map_err(Error::SubstrateCli),
_ => unreachable!("Ensured by the outside match; qed"),
}
}),
})
}
BenchmarkCmd::Pallet(cmd) => {
set_ss58_version(chain_spec);
@ -334,30 +351,36 @@ pub fn run() -> Result<()> {
runner.sync_run(|config| {
cmd.run_with_spec::<sp_runtime::traits::HashingFor<service::Block>, ()>(
Some(config.chain_spec),
).map_err(|e| Error::SubstrateCli(e))
)
.map_err(|e| Error::SubstrateCli(e))
})
} else {
Err(sc_cli::Error::Input(
"Benchmarking wasn't enabled when building the node. \
You can enable it with `--features=runtime-benchmarks`.".into()
).into())
You can enable it with `--features=runtime-benchmarks`."
.into(),
)
.into())
}
},
}
BenchmarkCmd::Machine(cmd) => runner.sync_run(|config| {
cmd.run(&config, ghost_machine_primitives::GHOST_NODE_REFERENCE_HARDWARE.clone())
.map_err(Error::SubstrateCli)
cmd.run(
&config,
ghost_machine_primitives::GHOST_NODE_REFERENCE_HARDWARE.clone(),
)
.map_err(Error::SubstrateCli)
}),
// Note: this allows to implement additional new benchmark
// commands.
#[allow(unreachable_patterns)]
_ => Err(Error::CommandNotImplemented),
}
},
}
Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
Some(Subcommand::ChainInfo(cmd)) => {
let runner = cli.create_runner(cmd)?;
Ok(runner.sync_run(|config| cmd.run::<service::Block>(&config))?)
},
}
}?;
#[cfg(feature = "pyroscope")]

0
cli/src/error.rs Executable file → Normal file
View File

4
cli/src/lib.rs Executable file → Normal file
View File

@ -6,9 +6,7 @@ mod command;
mod error;
#[cfg(feature = "service")]
pub use service::{
self, Block, CoreApi, IdentifyVariant, ProvideRuntimeApi, TFullClient,
};
pub use service::{self, Block, CoreApi, IdentifyVariant, ProvideRuntimeApi, TFullClient};
#[cfg(feature = "cli")]
pub use cli::*;

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-client-cli"
version = "0.1.3"
version = "0.1.4"
description = "Ghost CLI interface"
license.workspace = true
authors.workspace = true

View File

@ -3,13 +3,10 @@
use bip39::Mnemonic;
use clap::Parser;
use itertools::Itertools;
use sc_cli::{
with_crypto_scheme, KeystoreParams, OutputTypeFlag,
CryptoSchemeFlag, Error,
};
use sc_cli::{with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, OutputTypeFlag};
use crate::params::NetworkSchemeFlag;
use crate::commands::utils::print_from_uri;
use crate::params::NetworkSchemeFlag;
/// The `generate` command
#[derive(Debug, Clone, Parser)]
@ -17,58 +14,58 @@ use crate::commands::utils::print_from_uri;
pub struct GenerateCmd {
/// The number of words in the phrase to generate. One of 12 (default),
/// 15, 18, 21 and 24.
#[arg(short = 'w', long, value_name = "WORDS")]
words: Option<usize>,
#[arg(short = 'w', long, value_name = "WORDS")]
words: Option<usize>,
#[allow(missing_docs)]
#[clap(flatten)]
pub keystore_params: KeystoreParams,
#[allow(missing_docs)]
#[clap(flatten)]
pub keystore_params: KeystoreParams,
#[allow(missing_docs)]
#[clap(flatten)]
pub network_scheme: NetworkSchemeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub network_scheme: NetworkSchemeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub output_scheme: OutputTypeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub output_scheme: OutputTypeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub crypto_scheme: CryptoSchemeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub crypto_scheme: CryptoSchemeFlag,
}
impl GenerateCmd {
/// Run the command
pub fn run(&self) -> Result<(), Error> {
let words = match self.words {
/// Run the command
pub fn run(&self) -> Result<(), Error> {
let words = match self.words {
Some(words_count) if [12, 15, 18, 21, 24].contains(&words_count) => Ok(words_count),
Some(_) => Err(Error::Input(
"Invalid number of words given for phrase: must be 12/15/18/21/24".into(),
)),
None => Ok(12),
}?;
let mnemonic = Mnemonic::generate(words)
}?;
let mnemonic = Mnemonic::generate(words)
.map_err(|e| Error::Input(format!("Mnemonic generation failed: {e}").into()))?;
let password = self.keystore_params.read_password()?;
let output = self.output_scheme.output_type;
let password = self.keystore_params.read_password()?;
let output = self.output_scheme.output_type;
let phrase = mnemonic.words().join(" ");
with_crypto_scheme!(
self.crypto_scheme.scheme,
print_from_uri(&phrase, password, self.network_scheme.network, output)
);
Ok(())
}
with_crypto_scheme!(
self.crypto_scheme.scheme,
print_from_uri(&phrase, password, self.network_scheme.network, output)
);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::*;
#[test]
fn generate() {
let generate = GenerateCmd::parse_from(&["generate", "--password", "12345"]);
assert!(generate.run().is_ok())
}
#[test]
fn generate() {
let generate = GenerateCmd::parse_from(&["generate", "--password", "12345"]);
assert!(generate.run().is_ok())
}
}

View File

@ -1,102 +1,101 @@
//! Implementation of the `inspect` subcommand
use crate::commands::utils::{print_from_public, print_from_uri};
use crate::params::NetworkSchemeFlag;
use clap::Parser;
use sc_cli::{
utils::read_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, OutputTypeFlag,
};
use sp_core::crypto::{ExposeSecret, SecretString, SecretUri, Ss58Codec};
use std::str::FromStr;
use sc_cli::{
with_crypto_scheme, KeystoreParams, OutputTypeFlag, CryptoSchemeFlag, Error,
utils::read_uri,
};
use crate::params::NetworkSchemeFlag;
use crate::commands::utils::{print_from_public, print_from_uri};
/// The `inspect` command
#[derive(Debug, Parser)]
#[command(
name = "inspect",
about = "Gets a public key and a SS58 address from the provided Secret URI"
name = "inspect",
about = "Gets a public key and a SS58 address from the provided Secret URI"
)]
pub struct InspectKeyCmd {
/// A Key URI to be inspected. May be a secret seed, secret URI
/// (with derivation paths and password), SS58, public URI or a hex encoded public key.
///
/// If it is a hex encoded public key, `--public` needs to be given as argument.
///
/// If the given value is a file, the file content will be used
/// as URI.
///
/// If omitted, you will be prompted for the URI.
uri: Option<String>,
/// A Key URI to be inspected. May be a secret seed, secret URI
/// (with derivation paths and password), SS58, public URI or a hex encoded public key.
///
/// If it is a hex encoded public key, `--public` needs to be given as argument.
///
/// If the given value is a file, the file content will be used
/// as URI.
///
/// If omitted, you will be prompted for the URI.
uri: Option<String>,
/// Is the given `uri` a hex encoded public key?
#[arg(long)]
public: bool,
/// Is the given `uri` a hex encoded public key?
#[arg(long)]
public: bool,
#[allow(missing_docs)]
#[clap(flatten)]
pub keystore_params: KeystoreParams,
#[allow(missing_docs)]
#[clap(flatten)]
pub keystore_params: KeystoreParams,
#[allow(missing_docs)]
#[clap(flatten)]
pub network_scheme: NetworkSchemeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub network_scheme: NetworkSchemeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub output_scheme: OutputTypeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub output_scheme: OutputTypeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub crypto_scheme: CryptoSchemeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
pub crypto_scheme: CryptoSchemeFlag,
/// Expect that `--uri` has the given public key/account-id.
///
/// If `--uri` has any derivations, the public key is checked against the base `uri`, i.e. the
/// `uri` without any derivation applied. However, if `uri` has a password or there is one
/// given by `--password`, it will be used to decrypt `uri` before comparing the public
/// key/account-id.
///
/// If there is no derivation in `--uri`, the public key will be checked against the public key
/// of `--uri` directly.
#[arg(long, conflicts_with = "public")]
pub expect_public: Option<String>,
/// Expect that `--uri` has the given public key/account-id.
///
/// If `--uri` has any derivations, the public key is checked against the base `uri`, i.e. the
/// `uri` without any derivation applied. However, if `uri` has a password or there is one
/// given by `--password`, it will be used to decrypt `uri` before comparing the public
/// key/account-id.
///
/// If there is no derivation in `--uri`, the public key will be checked against the public key
/// of `--uri` directly.
#[arg(long, conflicts_with = "public")]
pub expect_public: Option<String>,
}
impl InspectKeyCmd {
/// Run the command
pub fn run(&self) -> Result<(), Error> {
let uri = read_uri(self.uri.as_ref())?;
let password = self.keystore_params.read_password()?;
/// Run the command
pub fn run(&self) -> Result<(), Error> {
let uri = read_uri(self.uri.as_ref())?;
let password = self.keystore_params.read_password()?;
if self.public {
with_crypto_scheme!(
self.crypto_scheme.scheme,
print_from_public(
&uri,
self.network_scheme.network,
self.output_scheme.output_type,
)
)?;
} else {
if let Some(ref expect_public) = self.expect_public {
with_crypto_scheme!(
self.crypto_scheme.scheme,
expect_public_from_phrase(expect_public, &uri, password.as_ref())
)?;
}
if self.public {
with_crypto_scheme!(
self.crypto_scheme.scheme,
print_from_public(
&uri,
self.network_scheme.network,
self.output_scheme.output_type,
)
)?;
} else {
if let Some(ref expect_public) = self.expect_public {
with_crypto_scheme!(
self.crypto_scheme.scheme,
expect_public_from_phrase(expect_public, &uri, password.as_ref())
)?;
}
with_crypto_scheme!(
self.crypto_scheme.scheme,
print_from_uri(
&uri,
password,
self.network_scheme.network,
self.output_scheme.output_type,
)
);
}
with_crypto_scheme!(
self.crypto_scheme.scheme,
print_from_uri(
&uri,
password,
self.network_scheme.network,
self.output_scheme.output_type,
)
);
}
Ok(())
}
Ok(())
}
}
/// Checks that `expect_public` is the public key of `suri`.
@ -106,148 +105,156 @@ impl InspectKeyCmd {
///
/// Returns an error if the public key does not match.
fn expect_public_from_phrase<Pair: sp_core::Pair>(
expect_public: &str,
suri: &str,
password: Option<&SecretString>,
expect_public: &str,
suri: &str,
password: Option<&SecretString>,
) -> Result<(), Error> {
let secret_uri = SecretUri::from_str(suri).map_err(|e| format!("{:?}", e))?;
let expected_public = if let Some(public) = expect_public.strip_prefix("0x") {
let hex_public = array_bytes::hex2bytes(public)
.map_err(|_| format!("Invalid expected public key hex: `{}`", expect_public))?;
Pair::Public::try_from(&hex_public)
.map_err(|_| format!("Invalid expected public key: `{}`", expect_public))?
} else {
Pair::Public::from_string_with_version(expect_public)
.map_err(|_| format!("Invalid expected account id: `{}`", expect_public))?
.0
};
let secret_uri = SecretUri::from_str(suri).map_err(|e| format!("{:?}", e))?;
let expected_public = if let Some(public) = expect_public.strip_prefix("0x") {
let hex_public = array_bytes::hex2bytes(public)
.map_err(|_| format!("Invalid expected public key hex: `{}`", expect_public))?;
Pair::Public::try_from(&hex_public)
.map_err(|_| format!("Invalid expected public key: `{}`", expect_public))?
} else {
Pair::Public::from_string_with_version(expect_public)
.map_err(|_| format!("Invalid expected account id: `{}`", expect_public))?
.0
};
let pair = Pair::from_string_with_seed(
secret_uri.phrase.expose_secret().as_str(),
password
.or_else(|| secret_uri.password.as_ref())
.map(|p| p.expose_secret().as_str()),
)
.map_err(|_| format!("Invalid secret uri: {}", suri))?
.0;
let pair = Pair::from_string_with_seed(
secret_uri.phrase.expose_secret().as_str(),
password
.or_else(|| secret_uri.password.as_ref())
.map(|p| p.expose_secret().as_str()),
)
.map_err(|_| format!("Invalid secret uri: {}", suri))?
.0;
if pair.public() == expected_public {
Ok(())
} else {
Err(format!("Expected public ({}) key does not match.", expect_public).into())
}
if pair.public() == expected_public {
Ok(())
} else {
Err(format!("Expected public ({}) key does not match.", expect_public).into())
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_core::crypto::{ByteArray, Pair};
use sp_runtime::traits::IdentifyAccount;
use super::*;
use sp_core::crypto::{ByteArray, Pair};
use sp_runtime::traits::IdentifyAccount;
#[test]
fn inspect() {
let words =
"remember fiber forum demise paper uniform squirrel feel access exclude casual effort";
let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5";
#[test]
fn inspect() {
let words =
"remember fiber forum demise paper uniform squirrel feel access exclude casual effort";
let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5";
let inspect = InspectKeyCmd::parse_from(&["inspect-key", words, "--password", "12345"]);
assert!(inspect.run().is_ok());
let inspect = InspectKeyCmd::parse_from(&["inspect-key", words, "--password", "12345"]);
assert!(inspect.run().is_ok());
let inspect = InspectKeyCmd::parse_from(&["inspect-key", seed]);
assert!(inspect.run().is_ok());
}
let inspect = InspectKeyCmd::parse_from(&["inspect-key", seed]);
assert!(inspect.run().is_ok());
}
#[test]
fn inspect_public_key() {
let public = "0x12e76e0ae8ce41b6516cce52b3f23a08dcb4cfeed53c6ee8f5eb9f7367341069";
#[test]
fn inspect_public_key() {
let public = "0x12e76e0ae8ce41b6516cce52b3f23a08dcb4cfeed53c6ee8f5eb9f7367341069";
let inspect = InspectKeyCmd::parse_from(&["inspect-key", "--public", public]);
assert!(inspect.run().is_ok());
}
let inspect = InspectKeyCmd::parse_from(&["inspect-key", "--public", public]);
assert!(inspect.run().is_ok());
}
#[test]
fn inspect_with_expected_public_key() {
let check_cmd = |seed, expected_public, success| {
let inspect = InspectKeyCmd::parse_from(&[
"inspect-key",
"--expect-public",
expected_public,
seed,
]);
let res = inspect.run();
#[test]
fn inspect_with_expected_public_key() {
let check_cmd = |seed, expected_public, success| {
let inspect = InspectKeyCmd::parse_from(&[
"inspect-key",
"--expect-public",
expected_public,
seed,
]);
let res = inspect.run();
if success {
assert!(res.is_ok());
} else {
assert!(res.unwrap_err().to_string().contains(&format!(
"Expected public ({}) key does not match.",
expected_public
)));
}
};
if success {
assert!(res.is_ok());
} else {
assert!(res.unwrap_err().to_string().contains(&format!(
"Expected public ({}) key does not match.",
expected_public
)));
}
};
let seed =
"remember fiber forum demise paper uniform squirrel feel access exclude casual effort";
let invalid_public = "0x12e76e0ae8ce41b6516cce52b3f23a08dcb4cfeed53c6ee8f5eb9f7367341069";
let valid_public = sp_core::sr25519::Pair::from_string_with_seed(seed, None)
.expect("Valid")
.0
.public();
let valid_public_hex = array_bytes::bytes2hex("0x", valid_public.as_slice());
let valid_accountid = format!("{}", valid_public.into_account());
let seed =
"remember fiber forum demise paper uniform squirrel feel access exclude casual effort";
let invalid_public = "0x12e76e0ae8ce41b6516cce52b3f23a08dcb4cfeed53c6ee8f5eb9f7367341069";
let valid_public = sp_core::sr25519::Pair::from_string_with_seed(seed, None)
.expect("Valid")
.0
.public();
let valid_public_hex = array_bytes::bytes2hex("0x", valid_public.as_slice());
let valid_accountid = format!("{}", valid_public.into_account());
// It should fail with the invalid public key
check_cmd(seed, invalid_public, false);
// It should fail with the invalid public key
check_cmd(seed, invalid_public, false);
// It should work with the valid public key & account id
check_cmd(seed, &valid_public_hex, true);
check_cmd(seed, &valid_accountid, true);
// It should work with the valid public key & account id
check_cmd(seed, &valid_public_hex, true);
check_cmd(seed, &valid_accountid, true);
let password = "test12245";
let seed_with_password = format!("{}///{}", seed, password);
let valid_public_with_password =
sp_core::sr25519::Pair::from_string_with_seed(&seed_with_password, Some(password))
.expect("Valid")
.0
.public();
let valid_public_hex_with_password =
array_bytes::bytes2hex("0x", valid_public_with_password.as_slice());
let valid_accountid_with_password =
format!("{}", &valid_public_with_password.into_account());
let password = "test12245";
let seed_with_password = format!("{}///{}", seed, password);
let valid_public_with_password =
sp_core::sr25519::Pair::from_string_with_seed(&seed_with_password, Some(password))
.expect("Valid")
.0
.public();
let valid_public_hex_with_password =
array_bytes::bytes2hex("0x", valid_public_with_password.as_slice());
let valid_accountid_with_password =
format!("{}", &valid_public_with_password.into_account());
// Only the public key that corresponds to the seed with password should be accepted.
check_cmd(&seed_with_password, &valid_public_hex, false);
check_cmd(&seed_with_password, &valid_accountid, false);
// Only the public key that corresponds to the seed with password should be accepted.
check_cmd(&seed_with_password, &valid_public_hex, false);
check_cmd(&seed_with_password, &valid_accountid, false);
check_cmd(&seed_with_password, &valid_public_hex_with_password, true);
check_cmd(&seed_with_password, &valid_accountid_with_password, true);
check_cmd(&seed_with_password, &valid_public_hex_with_password, true);
check_cmd(&seed_with_password, &valid_accountid_with_password, true);
let seed_with_password_and_derivation = format!("{}//test//account///{}", seed, password);
let seed_with_password_and_derivation = format!("{}//test//account///{}", seed, password);
let valid_public_with_password_and_derivation =
sp_core::sr25519::Pair::from_string_with_seed(
&seed_with_password_and_derivation,
Some(password),
)
.expect("Valid")
.0
.public();
let valid_public_hex_with_password_and_derivation =
array_bytes::bytes2hex("0x", valid_public_with_password_and_derivation.as_slice());
let valid_public_with_password_and_derivation =
sp_core::sr25519::Pair::from_string_with_seed(
&seed_with_password_and_derivation,
Some(password),
)
.expect("Valid")
.0
.public();
let valid_public_hex_with_password_and_derivation =
array_bytes::bytes2hex("0x", valid_public_with_password_and_derivation.as_slice());
// They should still be valid, because we check the base secret key.
check_cmd(&seed_with_password_and_derivation, &valid_public_hex_with_password, true);
check_cmd(&seed_with_password_and_derivation, &valid_accountid_with_password, true);
// They should still be valid, because we check the base secret key.
check_cmd(
&seed_with_password_and_derivation,
&valid_public_hex_with_password,
true,
);
check_cmd(
&seed_with_password_and_derivation,
&valid_accountid_with_password,
true,
);
// And these should be invalid.
check_cmd(&seed_with_password_and_derivation, &valid_public_hex, false);
check_cmd(&seed_with_password_and_derivation, &valid_accountid, false);
// And these should be invalid.
check_cmd(&seed_with_password_and_derivation, &valid_public_hex, false);
check_cmd(&seed_with_password_and_derivation, &valid_accountid, false);
// The public of the derived account should fail.
check_cmd(
&seed_with_password_and_derivation,
&valid_public_hex_with_password_and_derivation,
false,
);
}
// The public of the derived account should fail.
check_cmd(
&seed_with_password_and_derivation,
&valid_public_hex_with_password_and_derivation,
false,
);
}
}

View File

@ -1,40 +1,37 @@
//! Key related CLI utilities
use super::{generate::GenerateCmd, inspect_key::InspectKeyCmd};
use sc_cli::{
GenerateKeyCmdCommon, InsertKeyCmd, InspectNodeKeyCmd, Error,
SubstrateCli,
};
use sc_cli::{Error, GenerateKeyCmdCommon, InsertKeyCmd, InspectNodeKeyCmd, SubstrateCli};
/// Key utilities for the cli.
#[derive(Debug, clap::Subcommand)]
pub enum KeySubcommand {
/// Generate a random node key, write it to a file or stdout and write the
/// corresponding peer-id to stderr
GenerateNodeKey(GenerateKeyCmdCommon),
/// Generate a random node key, write it to a file or stdout and write the
/// corresponding peer-id to stderr
GenerateNodeKey(GenerateKeyCmdCommon),
/// Generate a Substrate-based random account
Generate(GenerateCmd),
/// Generate a Substrate-based random account
Generate(GenerateCmd),
/// Gets a public key and a SS58 address from the provided Secret URI
Inspect(InspectKeyCmd),
/// Gets a public key and a SS58 address from the provided Secret URI
Inspect(InspectKeyCmd),
/// Load a node key from a file or stdin and print the corresponding peer-id
InspectNodeKey(InspectNodeKeyCmd),
/// Load a node key from a file or stdin and print the corresponding peer-id
InspectNodeKey(InspectNodeKeyCmd),
/// Insert a key to the keystore of a node.
Insert(InsertKeyCmd),
/// Insert a key to the keystore of a node.
Insert(InsertKeyCmd),
}
impl KeySubcommand {
/// run the key subcommands
pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), Error> {
match self {
KeySubcommand::GenerateNodeKey(cmd) => cmd.run(),
KeySubcommand::Generate(cmd) => cmd.run(),
KeySubcommand::Inspect(cmd) => cmd.run(),
KeySubcommand::Insert(cmd) => cmd.run(cli),
KeySubcommand::InspectNodeKey(cmd) => cmd.run(),
}
}
/// run the key subcommands
pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), Error> {
match self {
KeySubcommand::GenerateNodeKey(cmd) => cmd.run(),
KeySubcommand::Generate(cmd) => cmd.run(),
KeySubcommand::Inspect(cmd) => cmd.run(),
KeySubcommand::Insert(cmd) => cmd.run(cli),
KeySubcommand::InspectNodeKey(cmd) => cmd.run(),
}
}
}

View File

@ -1,11 +1,13 @@
mod key;
mod generate;
mod vanity;
mod inspect_key;
mod key;
mod utils;
mod vanity;
pub use self::{
key::KeySubcommand, vanity::VanityCmd, inspect_key::InspectKeyCmd,
generate::GenerateCmd,
utils::{unwrap_or_default_ss58_name, print_from_uri, print_from_public},
inspect_key::InspectKeyCmd,
key::KeySubcommand,
utils::{print_from_public, print_from_uri, unwrap_or_default_ss58_name},
vanity::VanityCmd,
};

View File

@ -1,194 +1,206 @@
use serde_json::json;
use sc_cli::{
OutputType,
utils::{PublicFor, SeedFor},
OutputType,
};
use sp_runtime::{traits::IdentifyAccount, MultiSigner};
use serde_json::json;
use sp_core::{
crypto::{
unwrap_or_default_ss58_version,
Ss58Codec, ExposeSecret, Ss58AddressFormat, SecretString,
unwrap_or_default_ss58_version, ExposeSecret, SecretString, Ss58AddressFormat, Ss58Codec,
},
hexdisplay::HexDisplay,
};
use sp_runtime::{traits::IdentifyAccount, MultiSigner};
pub fn print_from_uri<Pair>(
uri: &str,
password: Option<SecretString>,
network_override: Option<Ss58AddressFormat>,
output: OutputType,
uri: &str,
password: Option<SecretString>,
network_override: Option<Ss58AddressFormat>,
output: OutputType,
) where
Pair: sp_core::Pair,
Pair::Public: Into<MultiSigner>,
Pair: sp_core::Pair,
Pair::Public: Into<MultiSigner>,
{
let password = password.as_ref().map(|s| s.expose_secret().as_str());
let network_id = unwrap_or_default_ss58_name(network_override);
let password = password.as_ref().map(|s| s.expose_secret().as_str());
let network_id = unwrap_or_default_ss58_name(network_override);
if let Ok((pair, seed)) = Pair::from_phrase(uri, password) {
let public_key = pair.public();
let network_override = unwrap_or_default_ss58_version(network_override);
if let Ok((pair, seed)) = Pair::from_phrase(uri, password) {
let public_key = pair.public();
let network_override = unwrap_or_default_ss58_version(network_override);
match output {
OutputType::Json => {
let json = json!({
"secretPhrase": uri,
"networkId": network_id,
"secretSeed": format_seed::<Pair>(seed),
"publicKey": format_public_key::<Pair>(public_key.clone()),
"ss58PublicKey": public_key.to_ss58check_with_version(network_override),
"accountId": format_account_id::<Pair>(public_key),
"ss58Address": pair.public().into().into_account().to_ss58check_with_version(network_override),
});
println!(
"{}",
serde_json::to_string_pretty(&json).expect("Json pretty print failed")
);
},
OutputType::Text => {
println!(
"Secret phrase: {}\n \
match output {
OutputType::Json => {
let json = json!({
"secretPhrase": uri,
"networkId": network_id,
"secretSeed": format_seed::<Pair>(seed),
"publicKey": format_public_key::<Pair>(public_key.clone()),
"ss58PublicKey": public_key.to_ss58check_with_version(network_override),
"accountId": format_account_id::<Pair>(public_key),
"ss58Address": pair.public().into().into_account().to_ss58check_with_version(network_override),
});
println!(
"{}",
serde_json::to_string_pretty(&json).expect("Json pretty print failed")
);
}
OutputType::Text => {
println!(
"Secret phrase: {}\n \
Network ID: {}\n \
Secret seed: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
Public key (SS58): {}\n \
SS58 Address: {}",
uri,
network_id,
format_seed::<Pair>(seed),
format_public_key::<Pair>(public_key.clone()),
format_account_id::<Pair>(public_key.clone()),
public_key.to_ss58check_with_version(network_override),
pair.public().into().into_account().to_ss58check_with_version(network_override),
);
},
}
} else if let Ok((pair, seed)) = Pair::from_string_with_seed(uri, password) {
let public_key = pair.public();
let network_override = unwrap_or_default_ss58_version(network_override);
uri,
network_id,
format_seed::<Pair>(seed),
format_public_key::<Pair>(public_key.clone()),
format_account_id::<Pair>(public_key.clone()),
public_key.to_ss58check_with_version(network_override),
pair.public()
.into()
.into_account()
.to_ss58check_with_version(network_override),
);
}
}
} else if let Ok((pair, seed)) = Pair::from_string_with_seed(uri, password) {
let public_key = pair.public();
let network_override = unwrap_or_default_ss58_version(network_override);
match output {
OutputType::Json => {
let json = json!({
"secretKeyUri": uri,
"networkId": network_id,
"secretSeed": if let Some(seed) = seed { format_seed::<Pair>(seed) } else { "n/a".into() },
"publicKey": format_public_key::<Pair>(public_key.clone()),
"ss58PublicKey": public_key.to_ss58check_with_version(network_override),
"accountId": format_account_id::<Pair>(public_key),
"ss58Address": pair.public().into().into_account().to_ss58check_with_version(network_override),
});
println!(
"{}",
serde_json::to_string_pretty(&json).expect("Json pretty print failed")
);
},
OutputType::Text => {
println!(
"Secret Key URI `{}` is account:\n \
match output {
OutputType::Json => {
let json = json!({
"secretKeyUri": uri,
"networkId": network_id,
"secretSeed": if let Some(seed) = seed { format_seed::<Pair>(seed) } else { "n/a".into() },
"publicKey": format_public_key::<Pair>(public_key.clone()),
"ss58PublicKey": public_key.to_ss58check_with_version(network_override),
"accountId": format_account_id::<Pair>(public_key),
"ss58Address": pair.public().into().into_account().to_ss58check_with_version(network_override),
});
println!(
"{}",
serde_json::to_string_pretty(&json).expect("Json pretty print failed")
);
}
OutputType::Text => {
println!(
"Secret Key URI `{}` is account:\n \
Network ID: {}\n \
Secret seed: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
Public key (SS58): {}\n \
SS58 Address: {}",
uri,
network_id,
if let Some(seed) = seed { format_seed::<Pair>(seed) } else { "n/a".into() },
format_public_key::<Pair>(public_key.clone()),
format_account_id::<Pair>(public_key.clone()),
public_key.to_ss58check_with_version(network_override),
pair.public().into().into_account().to_ss58check_with_version(network_override),
);
},
}
} else if let Ok((public_key, network)) = Pair::Public::from_string_with_version(uri) {
let network_override = network_override.unwrap_or(network);
uri,
network_id,
if let Some(seed) = seed {
format_seed::<Pair>(seed)
} else {
"n/a".into()
},
format_public_key::<Pair>(public_key.clone()),
format_account_id::<Pair>(public_key.clone()),
public_key.to_ss58check_with_version(network_override),
pair.public()
.into()
.into_account()
.to_ss58check_with_version(network_override),
);
}
}
} else if let Ok((public_key, network)) = Pair::Public::from_string_with_version(uri) {
let network_override = network_override.unwrap_or(network);
match output {
OutputType::Json => {
let json = json!({
"publicKeyUri": uri,
"networkId": String::from(network_override),
"publicKey": format_public_key::<Pair>(public_key.clone()),
"accountId": format_account_id::<Pair>(public_key.clone()),
"ss58PublicKey": public_key.to_ss58check_with_version(network_override),
"ss58Address": public_key.to_ss58check_with_version(network_override),
});
match output {
OutputType::Json => {
let json = json!({
"publicKeyUri": uri,
"networkId": String::from(network_override),
"publicKey": format_public_key::<Pair>(public_key.clone()),
"accountId": format_account_id::<Pair>(public_key.clone()),
"ss58PublicKey": public_key.to_ss58check_with_version(network_override),
"ss58Address": public_key.to_ss58check_with_version(network_override),
});
println!(
"{}",
serde_json::to_string_pretty(&json).expect("Json pretty print failed")
);
},
OutputType::Text => {
println!(
"Public Key URI `{}` is account:\n \
println!(
"{}",
serde_json::to_string_pretty(&json).expect("Json pretty print failed")
);
}
OutputType::Text => {
println!(
"Public Key URI `{}` is account:\n \
Network ID/Version: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
Public key (SS58): {}\n \
SS58 Address: {}",
uri,
String::from(network_override),
format_public_key::<Pair>(public_key.clone()),
format_account_id::<Pair>(public_key.clone()),
public_key.to_ss58check_with_version(network_override),
public_key.to_ss58check_with_version(network_override),
);
},
}
} else {
println!("Invalid phrase/URI given");
}
uri,
String::from(network_override),
format_public_key::<Pair>(public_key.clone()),
format_account_id::<Pair>(public_key.clone()),
public_key.to_ss58check_with_version(network_override),
public_key.to_ss58check_with_version(network_override),
);
}
}
} else {
println!("Invalid phrase/URI given");
}
}
/// Try to parse given `public` as hex encoded public key and print relevant information.
pub fn print_from_public<Pair>(
public_str: &str,
network_override: Option<Ss58AddressFormat>,
output: OutputType,
public_str: &str,
network_override: Option<Ss58AddressFormat>,
output: OutputType,
) -> Result<(), sc_cli::Error>
where
Pair: sp_core::Pair,
Pair::Public: Into<MultiSigner>,
Pair: sp_core::Pair,
Pair::Public: Into<MultiSigner>,
{
let public = array_bytes::hex2bytes(public_str)?;
let public = array_bytes::hex2bytes(public_str)?;
let public_key = Pair::Public::try_from(&public)
.map_err(|_| "Failed to construct public key from given hex")?;
let public_key = Pair::Public::try_from(&public)
.map_err(|_| "Failed to construct public key from given hex")?;
let network_override = unwrap_or_default_ss58_version(network_override);
let network_override = unwrap_or_default_ss58_version(network_override);
match output {
OutputType::Json => {
let json = json!({
"networkId": String::from(network_override),
"publicKey": format_public_key::<Pair>(public_key.clone()),
"accountId": format_account_id::<Pair>(public_key.clone()),
"ss58PublicKey": public_key.to_ss58check_with_version(network_override),
"ss58Address": public_key.to_ss58check_with_version(network_override),
});
match output {
OutputType::Json => {
let json = json!({
"networkId": String::from(network_override),
"publicKey": format_public_key::<Pair>(public_key.clone()),
"accountId": format_account_id::<Pair>(public_key.clone()),
"ss58PublicKey": public_key.to_ss58check_with_version(network_override),
"ss58Address": public_key.to_ss58check_with_version(network_override),
});
println!("{}", serde_json::to_string_pretty(&json).expect("Json pretty print failed"));
},
OutputType::Text => {
println!(
"Network ID/Version: {}\n \
println!(
"{}",
serde_json::to_string_pretty(&json).expect("Json pretty print failed")
);
}
OutputType::Text => {
println!(
"Network ID/Version: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
Public key (SS58): {}\n \
SS58 Address: {}",
String::from(network_override),
format_public_key::<Pair>(public_key.clone()),
format_account_id::<Pair>(public_key.clone()),
public_key.to_ss58check_with_version(network_override),
public_key.to_ss58check_with_version(network_override),
);
},
}
String::from(network_override),
format_public_key::<Pair>(public_key.clone()),
format_account_id::<Pair>(public_key.clone()),
public_key.to_ss58check_with_version(network_override),
public_key.to_ss58check_with_version(network_override),
);
}
}
Ok(())
Ok(())
}
pub fn unwrap_or_default_ss58_name(x: Option<Ss58AddressFormat>) -> String {
@ -216,5 +228,8 @@ fn format_account_id<P: sp_core::Pair>(public_key: PublicFor<P>) -> String
where
PublicFor<P>: Into<MultiSigner>,
{
format!("0x{}", HexDisplay::from(&public_key.into().into_account().as_ref()))
format!(
"0x{}",
HexDisplay::from(&public_key.into().into_account().as_ref())
)
}

View File

@ -2,213 +2,218 @@
use clap::Parser;
use rand::{rngs::OsRng, RngCore};
use sp_core::crypto::{
unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec,
};
use sc_cli::{utils::format_seed, with_crypto_scheme, CryptoSchemeFlag, Error, OutputTypeFlag};
use sp_core::crypto::{unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec};
use sp_runtime::traits::IdentifyAccount;
use sc_cli::{
with_crypto_scheme, Error, OutputTypeFlag, CryptoSchemeFlag,
utils::format_seed,
};
use crate::commands::utils::print_from_uri;
use crate::params::NetworkSchemeFlag;
/// The `vanity` command
#[derive(Debug, Clone, Parser)]
#[command(name = "vanity", about = "Generate a seed that provides a vanity address")]
#[command(
name = "vanity",
about = "Generate a seed that provides a vanity address"
)]
pub struct VanityCmd {
/// Desired pattern
#[arg(long, value_parser = assert_non_empty_string)]
pattern: String,
/// Desired pattern
#[arg(long, value_parser = assert_non_empty_string)]
pattern: String,
#[allow(missing_docs)]
#[clap(flatten)]
network_scheme: NetworkSchemeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
network_scheme: NetworkSchemeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
output_scheme: OutputTypeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
output_scheme: OutputTypeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
crypto_scheme: CryptoSchemeFlag,
#[allow(missing_docs)]
#[clap(flatten)]
crypto_scheme: CryptoSchemeFlag,
}
impl VanityCmd {
/// Run the command
pub fn run(&self) -> Result<(), Error> {
let formated_seed = with_crypto_scheme!(
self.crypto_scheme.scheme,
generate_key(
&self.pattern,
unwrap_or_default_ss58_version(self.network_scheme.network)
),
)?;
/// Run the command
pub fn run(&self) -> Result<(), Error> {
let formated_seed = with_crypto_scheme!(
self.crypto_scheme.scheme,
generate_key(
&self.pattern,
unwrap_or_default_ss58_version(self.network_scheme.network)
),
)?;
with_crypto_scheme!(
self.crypto_scheme.scheme,
print_from_uri(
&formated_seed,
None,
self.network_scheme.network,
self.output_scheme.output_type,
),
);
Ok(())
}
with_crypto_scheme!(
self.crypto_scheme.scheme,
print_from_uri(
&formated_seed,
None,
self.network_scheme.network,
self.output_scheme.output_type,
),
);
Ok(())
}
}
/// genertae a key based on given pattern
fn generate_key<Pair>(
desired: &str,
network_override: Ss58AddressFormat,
desired: &str,
network_override: Ss58AddressFormat,
) -> Result<String, &'static str>
where
Pair: sp_core::Pair,
Pair::Public: IdentifyAccount,
<Pair::Public as IdentifyAccount>::AccountId: Ss58Codec,
Pair: sp_core::Pair,
Pair::Public: IdentifyAccount,
<Pair::Public as IdentifyAccount>::AccountId: Ss58Codec,
{
println!("Generating key containing pattern '{}'", desired);
println!("Generating key containing pattern '{}'", desired);
let top = 45 + (desired.len() * 48);
let mut best = 0;
let mut seed = Pair::Seed::default();
let mut done = 0;
let top = 45 + (desired.len() * 48);
let mut best = 0;
let mut seed = Pair::Seed::default();
let mut done = 0;
loop {
if done % 100000 == 0 {
OsRng.fill_bytes(seed.as_mut());
} else {
next_seed(seed.as_mut());
}
loop {
if done % 100000 == 0 {
OsRng.fill_bytes(seed.as_mut());
} else {
next_seed(seed.as_mut());
}
let p = Pair::from_seed(&seed);
let ss58 = p.public().into_account().to_ss58check_with_version(network_override);
let p = Pair::from_seed(&seed);
let ss58 = p
.public()
.into_account()
.to_ss58check_with_version(network_override);
println!("{:?}", ss58);
let score = calculate_score(desired, &ss58);
if score > best || desired.len() < 2 {
best = score;
if best >= top {
println!("best: {} == top: {}", best, top);
return Ok(format_seed::<Pair>(seed.clone()))
}
}
done += 1;
let score = calculate_score(desired, &ss58);
if score > best || desired.len() < 2 {
best = score;
if best >= top {
println!("best: {} == top: {}", best, top);
return Ok(format_seed::<Pair>(seed.clone()));
}
}
done += 1;
if done % good_waypoint(done) == 0 {
println!("{} keys searched; best is {}/{} complete", done, best, top);
}
}
if done % good_waypoint(done) == 0 {
println!("{} keys searched; best is {}/{} complete", done, best, top);
}
}
}
fn good_waypoint(done: u64) -> u64 {
match done {
0..=1_000_000 => 100_000,
1_000_001..=10_000_000 => 1_000_000,
10_000_001..=100_000_000 => 10_000_000,
100_000_001.. => 100_000_000,
}
match done {
0..=1_000_000 => 100_000,
1_000_001..=10_000_000 => 1_000_000,
10_000_001..=100_000_000 => 10_000_000,
100_000_001.. => 100_000_000,
}
}
fn next_seed(seed: &mut [u8]) {
for s in seed {
match s {
255 => {
*s = 0;
},
_ => {
*s += 1;
break
},
}
}
for s in seed {
match s {
255 => {
*s = 0;
}
_ => {
*s += 1;
break;
}
}
}
}
/// Calculate the score of a key based on the desired
/// input.
fn calculate_score(_desired: &str, key: &str) -> usize {
for truncate in 0.._desired.len() {
let snip_size = _desired.len() - truncate;
let truncated = &_desired[0..snip_size];
if let Some(pos) = key.find(truncated) {
return (47 - pos) + (snip_size * 48)
}
}
0
for truncate in 0.._desired.len() {
let snip_size = _desired.len() - truncate;
let truncated = &_desired[0..snip_size];
if let Some(pos) = key.find(truncated) {
return (47 - pos) + (snip_size * 48);
}
}
0
}
/// checks that `pattern` is non-empty
fn assert_non_empty_string(pattern: &str) -> Result<String, &'static str> {
if pattern.is_empty() {
Err("Pattern must not be empty")
} else {
Ok(pattern.to_string())
}
if pattern.is_empty() {
Err("Pattern must not be empty")
} else {
Ok(pattern.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_core::{
crypto::{default_ss58_version, Ss58AddressFormatRegistry, Ss58Codec},
sr25519, Pair,
};
use super::*;
use sp_core::{
crypto::{default_ss58_version, Ss58AddressFormatRegistry, Ss58Codec},
sr25519, Pair,
};
#[test]
fn vanity() {
let vanity = VanityCmd::parse_from(&["vanity", "--pattern", "j"]);
assert!(vanity.run().is_ok());
}
#[test]
fn vanity() {
let vanity = VanityCmd::parse_from(&["vanity", "--pattern", "j"]);
assert!(vanity.run().is_ok());
}
#[test]
fn test_generation_with_single_char() {
let seed = generate_key::<sr25519::Pair>("ab", default_ss58_version()).unwrap();
assert!(sr25519::Pair::from_seed_slice(&array_bytes::hex2bytes_unchecked(&seed))
.unwrap()
.public()
.to_ss58check()
.contains("ab"));
}
#[test]
fn test_generation_with_single_char() {
let seed = generate_key::<sr25519::Pair>("ab", default_ss58_version()).unwrap();
assert!(
sr25519::Pair::from_seed_slice(&array_bytes::hex2bytes_unchecked(&seed))
.unwrap()
.public()
.to_ss58check()
.contains("ab")
);
}
#[test]
fn generate_key_respects_network_override() {
let seed =
generate_key::<sr25519::Pair>("ab", Ss58AddressFormatRegistry::PolkadotAccount.into())
.unwrap();
assert!(sr25519::Pair::from_seed_slice(&array_bytes::hex2bytes_unchecked(&seed))
.unwrap()
.public()
.to_ss58check_with_version(Ss58AddressFormatRegistry::PolkadotAccount.into())
.contains("ab"));
}
#[test]
fn generate_key_respects_network_override() {
let seed =
generate_key::<sr25519::Pair>("ab", Ss58AddressFormatRegistry::PolkadotAccount.into())
.unwrap();
assert!(
sr25519::Pair::from_seed_slice(&array_bytes::hex2bytes_unchecked(&seed))
.unwrap()
.public()
.to_ss58check_with_version(Ss58AddressFormatRegistry::PolkadotAccount.into())
.contains("ab")
);
}
#[test]
fn test_score_1_char_100() {
let score = calculate_score("j", "sYrjWiZkEP1PQe2kKEZiC1Bi9L8yFSsB5RPEkzEPd5NThsB5H");
assert_eq!(score, 96);
}
#[test]
fn test_score_1_char_100() {
let score = calculate_score("j", "sYrjWiZkEP1PQe2kKEZiC1Bi9L8yFSsB5RPEkzEPd5NThsB5H");
assert_eq!(score, 96);
}
#[test]
fn test_score_100() {
let score = calculate_score("ghst", "sYsghstuhYd9p6unUC3kPxjD2gv2zRCztYQaEDCMJpYrPTqTG");
assert_eq!(score, 246);
}
#[test]
fn test_score_100() {
let score = calculate_score("ghst", "sYsghstuhYd9p6unUC3kPxjD2gv2zRCztYQaEDCMJpYrPTqTG");
assert_eq!(score, 246);
}
#[test]
fn test_score_50_2() {
// 50% for the position + 50% for the size
assert_eq!(
calculate_score("ghst", "sYsghXXuhYd9p6unUC3kPxjD2gv2zRCztYQaEDCMJpYrPTqTG"),
146
);
}
#[test]
fn test_score_50_2() {
// 50% for the position + 50% for the size
assert_eq!(
calculate_score("ghst", "sYsghXXuhYd9p6unUC3kPxjD2gv2zRCztYQaEDCMJpYrPTqTG"),
146
);
}
#[test]
fn test_score_0() {
assert_eq!(
calculate_score("ghst", "sYrjWiZkEP1PQe2kKEZiC1Bi9L8yFSsB5RPEkzEPd5NThsB5H"),
0
);
}
#[test]
fn test_score_0() {
assert_eq!(
calculate_score("ghst", "sYrjWiZkEP1PQe2kKEZiC1Bi9L8yFSsB5RPEkzEPd5NThsB5H"),
0
);
}
}

View File

@ -1,5 +1,5 @@
pub mod params;
pub mod commands;
pub mod params;
pub use commands::KeySubcommand;
pub use commands::VanityCmd;

View File

@ -21,19 +21,25 @@ pub struct InnerSs58AddressFormat(Ss58AddressFormat);
impl InnerSs58AddressFormat {
#[inline]
pub fn custom(prefix: u16) -> Self {
Self { 0: Ss58AddressFormat::custom(prefix) }
Self {
0: Ss58AddressFormat::custom(prefix),
}
}
}
impl std::fmt::Display for InnerSs58AddressFormat {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} network", ALL_POSSIBLE_IDS
.binary_search(&u16::from(self.0))
.expect("always be found"))
write!(
f,
"{} network",
ALL_POSSIBLE_IDS
.binary_search(&u16::from(self.0))
.expect("always be found")
)
}
}
impl<'a>TryFrom<&'a str> for InnerSs58AddressFormat {
impl<'a> TryFrom<&'a str> for InnerSs58AddressFormat {
type Error = ParseError;
fn try_from(x: &'a str) -> Result<Self, Self::Error> {
@ -44,13 +50,13 @@ impl<'a>TryFrom<&'a str> for InnerSs58AddressFormat {
}
}
pub fn parse_s58_prefix_address_format(x: &str,) -> Result<Ss58AddressFormat, String> {
pub fn parse_s58_prefix_address_format(x: &str) -> Result<Ss58AddressFormat, String> {
match InnerSs58AddressFormat::try_from(x) {
Ok(format_registry) => Ok(format_registry.0.into()),
Err(_) => Err(format!(
"Unable to parse variant. Known variants: {:?}",
&ALL_POSSIBLE_NAMES
))
)),
}
}

6
core-primitives/Cargo.toml Executable file → Normal file
View File

@ -15,7 +15,7 @@ sp-runtime = { workspace = true }
[features]
default = ["std"]
std = [
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
]

0
core-primitives/src/lib.rs Executable file → Normal file
View File

0
file_header.txt Executable file → Normal file
View File

BIN
images/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
images/img_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
images/img_10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
images/img_11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
images/img_12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/img_13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
images/img_14.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
images/img_15.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
images/img_16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
images/img_17.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
images/img_18.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
images/img_19.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
images/img_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
images/img_20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
images/img_21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
images/img_22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
images/img_23.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
images/img_24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
images/img_25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
images/img_26.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
images/img_27.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
images/img_28.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
images/img_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
images/img_30.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
images/img_31.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
images/img_32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
images/img_33.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
images/img_34.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
images/img_35.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
images/img_36.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
images/img_37.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
images/img_38.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
images/img_39.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
images/img_40.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
images/img_41.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
images/img_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
images/img_6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
images/img_7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/img_8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
images/img_9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -14,7 +14,7 @@ pub fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Con
|_logger_builder, _config| {}
}
/// This module exports Prometheus types an:d defines
/// This module exports Prometheus types an:d defines
/// the [`Metrics`](metrics::Metrics) trait.
pub mod metrics {
pub use prometheus_endpoint as prometheus;

View File

@ -22,7 +22,11 @@ impl Metronome {
/// Create a new metronome source with a defined cycle duration.
pub fn new(cycle: Duration) -> Self {
let period = cycle.into();
Self { period, delay: Delay::new(period), state: MetronomeState::Snooze }
Self {
period,
delay: Delay::new(period),
state: MetronomeState::Snooze,
}
}
}
@ -36,14 +40,14 @@ impl futures::Stream for Metronome {
let val = self.period;
self.delay.reset(val);
self.state = MetronomeState::Snooze;
},
}
MetronomeState::Snooze => {
if !Pin::new(&mut self.delay).poll(cx).is_ready() {
break
break;
}
self.state = MetronomeState::SetAlarm;
return Poll::Ready(Some(()))
},
return Poll::Ready(Some(()));
}
}
}
Poll::Pending

View File

@ -2,19 +2,16 @@
use codec::Decode;
use core_primitives::{
metrics_definitions::{
CounterDefinition, CounterVecDefinition, HistogramDefinition,
},
metrics_definitions::{CounterDefinition, CounterVecDefinition, HistogramDefinition},
RuntimeMetricLabelValues, RuntimeMetricOp, RuntimeMetricUpdate,
};
use prometheus_endpoint::{
register, Counter, CounterVec, Histogram, HistogramOpts, Opts, Registry,
PrometheusError, U64,
register, Counter, CounterVec, Histogram, HistogramOpts, Opts, PrometheusError, Registry, U64,
};
use std::{
collections::hash_map::HashMap,
sync::{Arc, Mutex, MutexGuard},
}
};
#[derive(Clone, Debug)]
pub struct Metrics {
@ -32,13 +29,15 @@ impl RuntimeMetricsProvider {
pub fn register_countervec(&self, countervec: CounterVecDefinition) {
self.with_counter_vecs_lock_held(|mut hashmap| {
hashmap.entry(countervec.name.to_owned()).or_insert(register(
CounterVec::new(
Opts::new(countervec.name, countervec.description),
countervec.labels,
)?,
&self.0,
)?);
hashmap
.entry(countervec.name.to_owned())
.or_insert(register(
CounterVec::new(
Opts::new(countervec.name, countervec.description),
countervec.labels,
)?,
&self.0,
)?);
Ok(())
})
}
@ -46,10 +45,7 @@ impl RuntimeMetricsProvider {
pub fn register_counter(&self, counter: CounterDefinition) {
self.with_counters_lock_held(|mut hashmap| {
hashmap.entry(counter.name.to_owned()).or_insert(register(
Counter::new(
counter.name,
counter.description,
)?,
Counter::new(counter.name, counter.description)?,
&self.0,
)?);
Ok(())
@ -60,8 +56,7 @@ impl RuntimeMetricsProvider {
self.with_histograms_lock_held(|mut hashmap| {
hashmap.entry(hist.name.to_owned()).or_insert(register(
Histogram::with_opts(
HistogramOpts::new(hist.name, hist.description)
.buckets(hist.buckets.to_vec()),
HistogramOpts::new(hist.name, hist.description).buckets(hist.buckets.to_vec()),
)?,
&self.0,
)?);
@ -69,23 +64,21 @@ impl RuntimeMetricsProvider {
})
}
pub fn inc_counter_vec_by(
&self,
name: &str,
value: u64,
labels: &RuntimeMetricsProvider,
) {
pub fn inc_counter_vec_by(&self, name: &str, value: u64, labels: &RuntimeMetricsProvider) {
self.with_counter_vecs_lock_held(|mut hashmap| {
hashmap.entry(name.to_owned()).and_modify(|counter_vec| {
counter_vec.with_label_values(&labels.as_str_vec()).inc_by(value)
counter_vec
.with_label_values(&labels.as_str_vec())
.inc_by(value)
});
Ok(())
})
}
pub fn inc_counter_by(&self, name: &str, value: u64) {
self.with_counters_lock_held(|mut hashmap| {
hashmap.entry(name.to_owned())
hashmap
.entry(name.to_owned())
.and_modify(|counter_vec| counter_vec.inc_by(value));
Ok(())
})
@ -93,8 +86,9 @@ impl RuntimeMetricsProvider {
pub fn observe_histogram(&self, name: &str, value: u128) {
self.with_histograms_lock_held(|mut hashmap| {
hashmap.entry(name.to_owned())
and_modify(|histogram| histogram.observe(value as f64 / 1_000_000_000.0));
hashmap
.entry(name.to_owned())
.and_modify(|histogram| histogram.observe(value as f64 / 1_000_000_000.0));
Ok(())
})
}
@ -103,21 +97,36 @@ impl RuntimeMetricsProvider {
where
F: FnOnce(MutexGuard<'_, HashMap<String, Counter<U64>>>) -> Result<(), PrometheusError>,
{
let _ = self.1.counters.lock().map(do_something).or_else(|error| Err(error));
let _ = self
.1
.counters
.lock()
.map(do_something)
.or_else(|error| Err(error));
}
fn with_counter_vecs_lock_held<F>(&self, do_something: F)
where
F: FnOnce(MutexGuard<'_, HashMap<String, CounterVec<U64>>>) -> Result<(), PrometheusError>,
{
let _ = self.1.counter_vecs.lock().map(do_something).or_else(|error| Err(error));
let _ = self
.1
.counter_vecs
.lock()
.map(do_something)
.or_else(|error| Err(error));
}
fn with_histograms_lock_held<F>(&self, do_something: F)
where
F: FnOnce(MutexGuard<'_, HashMap<String, Histogram>>) -> Result<(), PrometheusError>,
{
let _ = self.1.histograms.lock().map(do_something).or_else(|error| Err(error));
let _ = self
.1
.histograms
.lock()
.map(do_something)
.or_else(|error| Err(error));
}
}
@ -131,7 +140,7 @@ impl sc_tracing::TraceHandler for RuntimeMetricsProvider {
.unwrap_or(&String::default())
.ne("metrics")
{
return
return;
}
if let Some(update_op_bs58) = event.values.string_values.get("params") {
@ -141,7 +150,7 @@ impl sc_tracing::TraceHandler for RuntimeMetricsProvider {
.as_slice(),
) {
Ok(update_op) => self.parse_metric_update(update_op),
Err(_) => {},
Err(_) => {}
}
}
}
@ -150,12 +159,15 @@ impl sc_tracing::TraceHandler for RuntimeMetricsProvider {
impl RuntimeMetricsProvider {
fn parse_metric_update(&self, update: RuntimeMetricUpdate) {
match update.op {
RuntimeMetricOp::IncrementCounterVec(value, ref labels) =>
self.inc_counter_vec_by(update.metric_name(), value, labels),
RuntimeMetricOp::IncrementCounter(value) =>
self.inc_counter_by(update.metric_name(), value),
RuntimeMetricOp::ObserveHistogram(value) =>
self.observe_histogram(update.metric_name(), value),
RuntimeMetricOp::IncrementCounterVec(value, ref labels) => {
self.inc_counter_vec_by(update.metric_name(), value, labels)
}
RuntimeMetricOp::IncrementCounter(value) => {
self.inc_counter_by(update.metric_name(), value)
}
RuntimeMetricOp::ObserveHistogram(value) => {
self.observe_histogram(update.metric_name(), value)
}
}
}
@ -178,7 +190,7 @@ impl RuntimeMetricsProvider {
pub fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration) -> () {
|logger_builder, config| {
if config.prometheus_registry().is_none() {
return
return;
}
let registry = config.prometheus_registry().cloned().unwrap();

View File

@ -1,5 +1,5 @@
use hyper::{Client, Uri};
use ghost_test_service::{node_config, run_validator_node, test_prometheus_config};
use hyper::{Client, Uri};
use keyring::AccountKeyring::*;
use std::collections::HashMap;
@ -7,8 +7,13 @@ const DEFAULT_PROMETHEUS_PORT: u16 = 9616;
#[tokio::test(flavor = "multi_thread")]
async fn runtime_can_publish_metrics() {
let mut alice_config =
node_config(|| {}, tokio::runtime::Handle::current(), Alice, Vec::new(), true);
let mut alice_config = node_config(
|| {},
tokio::runtime::Handle::current(),
Alice,
Vec::new(),
true,
);
// Enable prometheus metrics for Alice.
alice_config.prometheus_config = Some(test_prometheus_config(DEFAULT_PROMETHEUS_PORT));
@ -26,8 +31,13 @@ async fn runtime_can_publish_metrics() {
// Start validator Alice
let alice = run_validator_node(alice_config, None);
let bob_config =
node_config(|| {}, tokio::runtime::Handle::current(), Bob, vec![alice.addr.clone()], true);
let bob_config = node_config(
|| {},
tokio::runtime::Handle::current(),
Bob,
vec![alice.addr.clone()],
true,
);
// Start validator Bob
let _bob = run_validator_node(bob_config, None);
@ -48,19 +58,25 @@ async fn scrape_prometheus_metrics(metrics_uri: &str) -> HashMap<String, u64> {
.expect("GET request failed");
let body = String::from_utf8(
hyper::body::to_bytes(res).await.expect("can't get body as bytes").to_vec(),
).expect("body is not an UTF8 string");
hyper::body::to_bytes(res)
.await
.expect("can't get body as bytes")
.to_vec(),
)
.expect("body is not an UTF8 string");
let lines: Vec<_> = body.lines().map(|s| Ok(s.to_owned())).collect();
prometheus_parse::Scrape::parse(lines.into_iter())
.expect("Scraper failed to parse Prometheus metrics")
.samples
.into_iter()
.filter_map(|prometheus_parse::Sample { metric, value, .. }| match value {
prometheus_parse::Value::Counter(value) => Some((metric, value as u64)),
prometheus_parse::Value::Gauge(value) => Some((metric, value as u64)),
prometheus_parse::Value::Untyped(value) => Some((metric, value as u64)),
_ => None,
})
.filter_map(
|prometheus_parse::Sample { metric, value, .. }| match value {
prometheus_parse::Value::Counter(value) => Some((metric, value as u64)),
prometheus_parse::Value::Gauge(value) => Some((metric, value as u64)),
prometheus_parse::Value::Untyped(value) => Some((metric, value as u64)),
_ => None,
},
)
.collect()
}

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-claims"
version = "0.2.2"
version = "0.2.4"
description = "Ghost balance and rank claims based on EVM actions"
license.workspace = true
authors.workspace = true
@ -37,17 +37,17 @@ serde_json = { workspace = true, default-features = true }
[features]
default = ["std"]
std = [
"frame-benchmarking?/std",
"frame-benchmarking?/std",
"serde/std",
"codec/std",
"codec/std",
"scale-info/std",
"libsecp256k1/std",
"frame-support/std",
"frame-system/std",
"sp-core/std",
"sp-runtime/std",
"sp-io/std",
"sp-std/std",
"libsecp256k1/std",
"frame-support/std",
"frame-system/std",
"sp-core/std",
"sp-runtime/std",
"sp-io/std",
"sp-std/std",
"pallet-ranked-collective/std",
"pallet-vesting/std",
"pallet-balances/std",
@ -56,19 +56,19 @@ std = [
runtime-benchmarks = [
"libsecp256k1/hmac",
"libsecp256k1/static-context",
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-ranked-collective/runtime-benchmarks",
"pallet-vesting/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-ranked-collective/runtime-benchmarks",
"pallet-vesting/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-ranked-collective/try-runtime",
"pallet-vesting/try-runtime",
"pallet-balances/try-runtime",
"sp-runtime/try-runtime",
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-ranked-collective/try-runtime",
"pallet-vesting/try-runtime",
"pallet-balances/try-runtime",
"sp-runtime/try-runtime",
]

View File

@ -6,14 +6,14 @@ use frame_benchmarking::v2::*;
#[instance_benchmarks]
mod benchmarks {
use super::*;
use pallet_ranked_collective::Pallet as Club;
use frame_support::dispatch::RawOrigin;
use pallet_ranked_collective::Pallet as Club;
#[benchmark]
fn claim() {
let i = 1337u32;
let ethereum_secret_key = libsecp256k1::SecretKey::parse(
&keccak_256(&i.to_le_bytes())).unwrap();
let ethereum_secret_key =
libsecp256k1::SecretKey::parse(&keccak_256(&i.to_le_bytes())).unwrap();
let eth_address = crate::secp_utils::eth(&ethereum_secret_key);
let balance = CurrencyOf::<T, I>::minimum_balance();
@ -22,23 +22,30 @@ mod benchmarks {
Total::<T, I>::put(balance);
let pseudo_rank = 5u16;
let _ = Club::<T, I>::do_add_member_to_rank(
pseudo_account.clone(),
pseudo_rank,
false,
);
let _ = Club::<T, I>::do_add_member_to_rank(pseudo_account.clone(), pseudo_rank, false);
let user_account: T::AccountId = account("user", i, 0);
let signature = crate::secp_utils::sig::<T, I>(&ethereum_secret_key, &user_account.encode());
let signature =
crate::secp_utils::sig::<T, I>(&ethereum_secret_key, &user_account.encode());
let prev_balance = CurrencyOf::<T, I>::free_balance(&user_account);
let prev_rank = Club::<T, I>::rank_of(&user_account);
#[extrinsic_call]
claim(RawOrigin::Signed(user_account.clone()), eth_address, signature);
claim(
RawOrigin::Signed(user_account.clone()),
eth_address,
signature,
);
assert_eq!(CurrencyOf::<T, I>::free_balance(&user_account), prev_balance + balance);
assert_eq!(CurrencyOf::<T, I>::free_balance(&pseudo_account), balance - balance);
assert_eq!(
CurrencyOf::<T, I>::free_balance(&user_account),
prev_balance + balance
);
assert_eq!(
CurrencyOf::<T, I>::free_balance(&pseudo_account),
balance - balance
);
let rank = match prev_rank {
Some(current_rank) if pseudo_rank <= current_rank => Some(current_rank),
@ -48,9 +55,5 @@ mod benchmarks {
assert_eq!(Club::<T, I>::rank_of(&pseudo_account), None);
}
impl_benchmark_test_suite!(
Pallet,
crate::mock::new_test_ext(),
crate::mock::Test,
);
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test,);
}

View File

@ -1,31 +1,33 @@
#![cfg_attr(not(feature = "std"), no_std)]
use frame_support::{
ensure, pallet_prelude::*,
ensure,
pallet_prelude::*,
traits::{
Currency, ExistenceRequirement, Get, RankedMembers,
RankedMembersSwapHandler, VestingSchedule,
Currency, ExistenceRequirement, Get, RankedMembers, RankedMembersSwapHandler,
VestingSchedule,
},
DefaultNoBound,
};
use frame_system::pallet_prelude::*;
use serde::{self, Deserialize, Deserializer, Serialize, Serializer};
pub use pallet::*;
use serde::{self, Deserialize, Deserializer, Serialize, Serializer};
use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256};
use sp_runtime::traits::{CheckedSub, CheckedDiv, BlockNumberProvider};
use sp_runtime::traits::{BlockNumberProvider, CheckedDiv, CheckedSub};
use sp_std::prelude::*;
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::{format, string::String};
pub mod weights;
mod weights;
pub use crate::weights::WeightInfo;
mod tests;
mod mock;
mod benchmarking;
mod mock;
mod secp_utils;
mod tests;
/// An ethereum address (i.e. 20 bytes, used to represent an Ethereum account).
///
@ -55,7 +57,7 @@ impl<'de> Deserialize<'de> for EthereumAddress {
Err(serde::de::Error::custom(
"Bad length of Ethereum address (should be 42 including `0x`)",
))?;
}
}
let raw: Vec<u8> = rustc_hex::FromHex::from_hex(s)
.map_err(|e| serde::de::Error::custom(format!("{:?}", e)))?;
let mut r = Self::default();
@ -80,15 +82,14 @@ impl sp_std::fmt::Debug for EcdsaSignature {
}
type CurrencyOf<T, I> = <<T as Config<I>>::VestingSchedule as VestingSchedule<
<T as frame_system::Config>::AccountId
<T as frame_system::Config>::AccountId,
>>::Currency;
type BalanceOf<T, I> = <CurrencyOf<T, I> as Currency<
<T as frame_system::Config>::AccountId>
>::Balance;
type BalanceOf<T, I> =
<CurrencyOf<T, I> as Currency<<T as frame_system::Config>::AccountId>>::Balance;
type RankOf<T, I> = <pallet_ranked_collective::Pallet::<T, I> as RankedMembers>::Rank;
type AccountIdOf<T, I> = <pallet_ranked_collective::Pallet::<T, I> as RankedMembers>::AccountId;
type RankOf<T, I> = <pallet_ranked_collective::Pallet<T, I> as RankedMembers>::Rank;
type AccountIdOf<T, I> = <pallet_ranked_collective::Pallet<T, I> as RankedMembers>::AccountId;
#[frame_support::pallet]
pub mod pallet {
@ -99,8 +100,11 @@ pub mod pallet {
pub struct Pallet<T, I = ()>(_);
#[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config + pallet_ranked_collective::Config<I> {
type RuntimeEvent: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
pub trait Config<I: 'static = ()>:
frame_system::Config + pallet_ranked_collective::Config<I>
{
type RuntimeEvent: From<Event<Self, I>>
+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
type VestingSchedule: VestingSchedule<Self::AccountId, Moment = BlockNumberFor<Self>>;
type BlockNumberProvider: BlockNumberProvider<BlockNumber = BlockNumberFor<Self>>;
@ -117,13 +121,13 @@ pub mod pallet {
type WeightInfo: WeightInfo;
}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
Claimed {
receiver: T::AccountId,
donor: T::AccountId,
receiver: T::AccountId,
donor: T::AccountId,
amount: BalanceOf<T, I>,
rank: Option<RankOf<T, I>>,
},
@ -158,12 +162,16 @@ pub mod pallet {
.map(|(account_id, rank)| {
assert!(
pallet_ranked_collective::Pallet::<T, I>::do_add_member_to_rank(
account_id.clone(), *rank, false).is_ok(),
"error during adding and promotion"
account_id.clone(),
*rank,
false
)
.is_ok(),
"error during adding and promotion"
);
account_id
})
.collect();
.collect();
assert!(
self.members_and_ranks.len() == cult_accounts.len(),
@ -185,13 +193,13 @@ pub mod pallet {
) -> DispatchResult {
let who = ensure_signed(origin)?;
let data = who.using_encoded(to_ascii_hex);
let recovered_address = Self::recover_ethereum_address(
&ethereum_signature,
&data,
).ok_or(Error::<T, I>::InvalidEthereumSignature)?;
let recovered_address = Self::recover_ethereum_address(&ethereum_signature, &data)
.ok_or(Error::<T, I>::InvalidEthereumSignature)?;
ensure!(recovered_address == ethereum_address,
Error::<T, I>::InvalidEthereumAddress);
ensure!(
recovered_address == ethereum_address,
Error::<T, I>::InvalidEthereumAddress
);
Self::do_claim(who, ethereum_address)
}
@ -199,37 +207,37 @@ pub mod pallet {
}
fn to_ascii_hex(data: &[u8]) -> Vec<u8> {
let mut r = Vec::with_capacity(data.len() * 2);
let mut push_nibble = |n| r.push(if n < 10 { b'0' + n } else { b'a' - 10 + n });
for &b in data.iter() {
push_nibble(b / 16);
push_nibble(b % 16);
}
r
let mut r = Vec::with_capacity(data.len() * 2);
let mut push_nibble = |n| r.push(if n < 10 { b'0' + n } else { b'a' - 10 + n });
for &b in data.iter() {
push_nibble(b / 16);
push_nibble(b % 16);
}
r
}
impl<T: Config<I>, I: 'static> Pallet<T, I> {
fn ethereum_signable_message(what: &[u8]) -> Vec<u8> {
let prefix = T::Prefix::get();
let mut l = prefix.len() + what.len();
let mut rev = Vec::new();
while l > 0 {
rev.push(b'0' + (l % 10) as u8);
l /= 10;
}
let mut v = b"\x19Ethereum Signed Message:\n".to_vec();
v.extend(rev.into_iter().rev());
v.extend_from_slice(prefix);
v.extend_from_slice(what);
v
let mut l = prefix.len() + what.len();
let mut rev = Vec::new();
while l > 0 {
rev.push(b'0' + (l % 10) as u8);
l /= 10;
}
let mut v = b"\x19Ethereum Signed Message:\n".to_vec();
v.extend(rev.into_iter().rev());
v.extend_from_slice(prefix);
v.extend_from_slice(what);
v
}
fn recover_ethereum_address(s: &EcdsaSignature, what: &[u8]) -> Option<EthereumAddress> {
let msg = keccak_256(&Self::ethereum_signable_message(what));
let mut res = EthereumAddress::default();
res.0
.copy_from_slice(&keccak_256(&secp256k1_ecdsa_recover(&s.0, &msg).ok()?[..])[12..]);
Some(res)
let mut res = EthereumAddress::default();
res.0
.copy_from_slice(&keccak_256(&secp256k1_ecdsa_recover(&s.0, &msg).ok()?[..])[12..]);
Some(res)
}
fn into_account_id(address: EthereumAddress) -> Result<T::AccountId, codec::Error> {
@ -242,21 +250,24 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
}
fn do_claim(receiver: T::AccountId, ethereum_address: EthereumAddress) -> DispatchResult {
let donor = Self::into_account_id(ethereum_address).ok()
let donor = Self::into_account_id(ethereum_address)
.ok()
.ok_or(Error::<T, I>::AddressDecodingFailed)?;
let balance_due = CurrencyOf::<T, I>::free_balance(&donor);
ensure!(balance_due >= CurrencyOf::<T, I>::minimum_balance(),
Error::<T, I>::NoBalanceToClaim);
ensure!(
balance_due >= CurrencyOf::<T, I>::minimum_balance(),
Error::<T, I>::NoBalanceToClaim
);
let new_total = Total::<T, I>::get()
.checked_sub(&balance_due)
.ok_or(Error::<T, I>::PotUnderflow)?;
CurrencyOf::<T, I>::transfer(
&donor,
&receiver,
balance_due,
&donor,
&receiver,
balance_due,
ExistenceRequirement::AllowDeath,
)?;
@ -272,28 +283,40 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
.ok_or(Error::<T, I>::ArithmeticError)?;
T::VestingSchedule::add_vesting_schedule(
&receiver,
&receiver,
vesting_balance,
per_block_balance,
T::BlockNumberProvider::current_block_number(),
)?;
}
let rank = if let Some(rank) = <pallet_ranked_collective::Pallet::<T, I> as RankedMembers>::rank_of(&donor) {
let rank = if let Some(rank) =
<pallet_ranked_collective::Pallet<T, I> as RankedMembers>::rank_of(&donor)
{
pallet_ranked_collective::Pallet::<T, I>::do_remove_member_from_rank(&donor, rank)?;
let new_rank = match <pallet_ranked_collective::Pallet::<T, I> as RankedMembers>::rank_of(&receiver) {
Some(current_rank) if current_rank >= rank => current_rank,
Some(current_rank) if current_rank < rank => {
for _ in 0..rank - current_rank {
pallet_ranked_collective::Pallet::<T, I>::do_promote_member(receiver.clone(), None, false)?;
let new_rank =
match <pallet_ranked_collective::Pallet<T, I> as RankedMembers>::rank_of(&receiver)
{
Some(current_rank) if current_rank >= rank => current_rank,
Some(current_rank) if current_rank < rank => {
for _ in 0..rank - current_rank {
pallet_ranked_collective::Pallet::<T, I>::do_promote_member(
receiver.clone(),
None,
false,
)?;
}
rank
}
rank
},
_ => {
pallet_ranked_collective::Pallet::<T, I>::do_add_member_to_rank(receiver.clone(), rank, false)?;
rank
},
};
_ => {
pallet_ranked_collective::Pallet::<T, I>::do_add_member_to_rank(
receiver.clone(),
rank,
false,
)?;
rank
}
};
<T as pallet::Config<I>>::MemberSwappedHandler::swapped(&donor, &receiver, new_rank);
Some(new_rank)
} else {
@ -302,7 +325,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
Total::<T, I>::put(new_total);
Self::deposit_event(Event::<T, I>::Claimed {
receiver,
receiver,
donor,
amount: balance_due,
rank,

View File

@ -4,51 +4,113 @@ use super::*;
pub use crate as ghost_claims;
use frame_support::{
parameter_types, derive_impl,
traits::{PollStatus, Polling, WithdrawReasons, ConstU16, ConstU64},
derive_impl, parameter_types,
traits::{ConstU16, ConstU64, PollStatus, Polling, WithdrawReasons},
};
use frame_system::EnsureRootWithSuccess;
use sp_runtime::{BuildStorage, traits::Convert};
pub use pallet_ranked_collective::{TallyOf, Rank};
pub use pallet_ranked_collective::{Rank, TallyOf};
use sp_runtime::{traits::Convert, BuildStorage};
pub mod eth_keys {
use crate::{
mock::Test,
EcdsaSignature, EthereumAddress,
};
use hex_literal::hex;
use crate::{mock::Test, EcdsaSignature, EthereumAddress};
use codec::Encode;
use hex_literal::hex;
pub fn total_claims() -> u64 { 10 + 100 + 1000 }
pub fn alice_account_id() -> <Test as frame_system::Config>::AccountId { 69 }
pub fn bob_account_id() -> <Test as frame_system::Config>::AccountId { 1337 }
pub fn total_claims() -> u64 {
10 + 100 + 1000
}
pub fn alice_account_id() -> <Test as frame_system::Config>::AccountId {
69
}
pub fn bob_account_id() -> <Test as frame_system::Config>::AccountId {
1337
}
pub fn first_eth_public_known() -> EthereumAddress { EthereumAddress(hex!("1A69d2D5568D1878023EeB121a73d33B9116A760")) }
pub fn second_eth_public_known() -> EthereumAddress { EthereumAddress(hex!("2f86cfBED3fbc1eCf2989B9aE5fc019a837A9C12")) }
pub fn third_eth_public_known() -> EthereumAddress { EthereumAddress(hex!("e83f67361Ac74D42A48E2DAfb6706eb047D8218D")) }
pub fn fourth_eth_public_known() -> EthereumAddress { EthereumAddress(hex!("827ee4ad9b259b6fa1390ed60921508c78befd63")) }
pub fn first_eth_public_known() -> EthereumAddress {
EthereumAddress(hex!("1A69d2D5568D1878023EeB121a73d33B9116A760"))
}
pub fn second_eth_public_known() -> EthereumAddress {
EthereumAddress(hex!("2f86cfBED3fbc1eCf2989B9aE5fc019a837A9C12"))
}
pub fn third_eth_public_known() -> EthereumAddress {
EthereumAddress(hex!("e83f67361Ac74D42A48E2DAfb6706eb047D8218D"))
}
pub fn fourth_eth_public_known() -> EthereumAddress {
EthereumAddress(hex!("827ee4ad9b259b6fa1390ed60921508c78befd63"))
}
fn first_eth_private_key() -> libsecp256k1::SecretKey { libsecp256k1::SecretKey::parse(&hex!("01c928771aea942a1e7ac06adf2b73dfbc9a25d9eaa516e3673116af7f345198")).unwrap() }
fn second_eth_private_key() -> libsecp256k1::SecretKey { libsecp256k1::SecretKey::parse(&hex!("b19a435901872f817185f7234a1484eae837613f9d10cf21927a23c2d8cb9139")).unwrap() }
fn third_eth_private_key() -> libsecp256k1::SecretKey { libsecp256k1::SecretKey::parse(&hex!("d3baf57b74d65719b2dc33f5a464176022d0cc5edbca002234229f3e733875fc")).unwrap() }
fn fourth_eth_private_key() -> libsecp256k1::SecretKey { libsecp256k1::SecretKey::parse(&hex!("c4683d566436af6b58b4a59c8f501319226e85b21869bf93d5eeb4596d4791d4")).unwrap() }
fn wrong_eth_private_key() -> libsecp256k1::SecretKey { libsecp256k1::SecretKey::parse(&hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")).unwrap() }
fn first_eth_private_key() -> libsecp256k1::SecretKey {
libsecp256k1::SecretKey::parse(&hex!(
"01c928771aea942a1e7ac06adf2b73dfbc9a25d9eaa516e3673116af7f345198"
))
.unwrap()
}
fn second_eth_private_key() -> libsecp256k1::SecretKey {
libsecp256k1::SecretKey::parse(&hex!(
"b19a435901872f817185f7234a1484eae837613f9d10cf21927a23c2d8cb9139"
))
.unwrap()
}
fn third_eth_private_key() -> libsecp256k1::SecretKey {
libsecp256k1::SecretKey::parse(&hex!(
"d3baf57b74d65719b2dc33f5a464176022d0cc5edbca002234229f3e733875fc"
))
.unwrap()
}
fn fourth_eth_private_key() -> libsecp256k1::SecretKey {
libsecp256k1::SecretKey::parse(&hex!(
"c4683d566436af6b58b4a59c8f501319226e85b21869bf93d5eeb4596d4791d4"
))
.unwrap()
}
fn wrong_eth_private_key() -> libsecp256k1::SecretKey {
libsecp256k1::SecretKey::parse(&hex!(
"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
))
.unwrap()
}
pub fn first_eth_public_key() -> EthereumAddress { crate::secp_utils::eth(&first_eth_private_key()) }
pub fn second_eth_public_key() -> EthereumAddress { crate::secp_utils::eth(&second_eth_private_key()) }
pub fn third_eth_public_key() -> EthereumAddress { crate::secp_utils::eth(&third_eth_private_key()) }
pub fn fourth_eth_public_key() -> EthereumAddress { crate::secp_utils::eth(&fourth_eth_private_key()) }
pub fn first_eth_public_key() -> EthereumAddress {
crate::secp_utils::eth(&first_eth_private_key())
}
pub fn second_eth_public_key() -> EthereumAddress {
crate::secp_utils::eth(&second_eth_private_key())
}
pub fn third_eth_public_key() -> EthereumAddress {
crate::secp_utils::eth(&third_eth_private_key())
}
pub fn fourth_eth_public_key() -> EthereumAddress {
crate::secp_utils::eth(&fourth_eth_private_key())
}
pub fn first_account_id() -> <Test as frame_system::Config>::AccountId { crate::secp_utils::into_account_id::<Test, ()>(first_eth_public_key()) }
pub fn second_account_id() -> <Test as frame_system::Config>::AccountId { crate::secp_utils::into_account_id::<Test, ()>(second_eth_public_key()) }
pub fn third_account_id() -> <Test as frame_system::Config>::AccountId { crate::secp_utils::into_account_id::<Test, ()>(third_eth_public_key()) }
pub fn fourth_account_id() -> <Test as frame_system::Config>::AccountId { crate::secp_utils::into_account_id::<Test, ()>(fourth_eth_public_key()) }
pub fn first_account_id() -> <Test as frame_system::Config>::AccountId {
crate::secp_utils::into_account_id::<Test, ()>(first_eth_public_key())
}
pub fn second_account_id() -> <Test as frame_system::Config>::AccountId {
crate::secp_utils::into_account_id::<Test, ()>(second_eth_public_key())
}
pub fn third_account_id() -> <Test as frame_system::Config>::AccountId {
crate::secp_utils::into_account_id::<Test, ()>(third_eth_public_key())
}
pub fn fourth_account_id() -> <Test as frame_system::Config>::AccountId {
crate::secp_utils::into_account_id::<Test, ()>(fourth_eth_public_key())
}
pub fn first_signature() -> EcdsaSignature { crate::secp_utils::sig::<Test, ()>(&first_eth_private_key(), &alice_account_id().encode()) }
pub fn second_signature() -> EcdsaSignature { crate::secp_utils::sig::<Test, ()>(&second_eth_private_key(), &alice_account_id().encode()) }
pub fn third_signature() -> EcdsaSignature { crate::secp_utils::sig::<Test, ()>(&third_eth_private_key(), &alice_account_id().encode()) }
pub fn fourth_signature() -> EcdsaSignature { crate::secp_utils::sig::<Test, ()>(&fourth_eth_private_key(), &bob_account_id().encode()) }
pub fn wrong_signature() -> EcdsaSignature { crate::secp_utils::sig::<Test, ()>(&wrong_eth_private_key(), &alice_account_id().encode()) }
pub fn first_signature() -> EcdsaSignature {
crate::secp_utils::sig::<Test, ()>(&first_eth_private_key(), &alice_account_id().encode())
}
pub fn second_signature() -> EcdsaSignature {
crate::secp_utils::sig::<Test, ()>(&second_eth_private_key(), &alice_account_id().encode())
}
pub fn third_signature() -> EcdsaSignature {
crate::secp_utils::sig::<Test, ()>(&third_eth_private_key(), &alice_account_id().encode())
}
pub fn fourth_signature() -> EcdsaSignature {
crate::secp_utils::sig::<Test, ()>(&fourth_eth_private_key(), &bob_account_id().encode())
}
pub fn wrong_signature() -> EcdsaSignature {
crate::secp_utils::sig::<Test, ()>(&wrong_eth_private_key(), &alice_account_id().encode())
}
}
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
@ -66,10 +128,9 @@ impl pallet_balances::Config for Test {
type AccountStore = System;
}
parameter_types! {
pub const MinVestedTransfer: u64 = 1;
pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons =
pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons =
WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE);
}
@ -79,9 +140,8 @@ impl pallet_vesting::Config for Test {
type BlockNumberToBalance = sp_runtime::traits::ConvertInto;
type MinVestedTransfer = MinVestedTransfer;
type WeightInfo = ();
type UnvestedFundsAllowedWithdrawReasons =
UnvestedFundsAllowedWithdrawReasons;
type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons;
type BlockNumberProvider = System;
const MAX_VESTING_SCHEDULES: u32 = 28;
}
@ -148,7 +208,7 @@ impl pallet_ranked_collective::Config for Test {
type PromoteOrigin = EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>;
type DemoteOrigin = EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>;
type ExchangeOrigin = EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>;
type Polls = TestPolls;
type MemberSwappedHandler = ();
type MinRankOfClass = MinRankOfClass<MinRankOfClassDelta>;
@ -200,8 +260,8 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
(crate::mock::eth_keys::third_account_id(), 1000),
],
}
.assimilate_storage(&mut t)
.unwrap();
.assimilate_storage(&mut t)
.unwrap();
ghost_claims::GenesisConfig::<Test> {
total: crate::mock::eth_keys::total_claims(),
@ -210,8 +270,8 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
(crate::mock::eth_keys::third_account_id(), 3),
],
}
.assimilate_storage(&mut t)
.unwrap();
.assimilate_storage(&mut t)
.unwrap();
let mut ext = sp_io::TestExternalities::new(t);
ext.execute_with(|| {

View File

@ -8,7 +8,8 @@ pub fn public(secret: &libsecp256k1::SecretKey) -> libsecp256k1::PublicKey {
pub fn eth(secret: &libsecp256k1::SecretKey) -> EthereumAddress {
let mut res = EthereumAddress::default();
res.0.copy_from_slice(&keccak_256(&public(secret).serialize()[1..65])[12..]);
res.0
.copy_from_slice(&keccak_256(&public(secret).serialize()[1..65])[12..]);
res
}
@ -18,17 +19,14 @@ pub fn into_account_id<T: Config<I>, I: 'static>(address: EthereumAddress) -> T:
}
pub fn sig<T: Config<I>, I: 'static>(
secret: &libsecp256k1::SecretKey,
secret: &libsecp256k1::SecretKey,
what: &[u8],
) -> EcdsaSignature {
let msg = keccak_256(&super::Pallet::<T, I>::ethereum_signable_message(
&crate::to_ascii_hex(what)[..],
&crate::to_ascii_hex(what)[..],
));
let (sig, recovery_id) = libsecp256k1::sign(
&libsecp256k1::Message::parse(&msg),
secret,
);
let (sig, recovery_id) = libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), secret);
let mut r = [0u8; 65];
r[0..64].copy_from_slice(&sig.serialize()[..]);

View File

@ -1,21 +1,19 @@
#![cfg(test)]
use mock::{
new_test_ext, ghost_claims,
Test, System, Balances, Club, Vesting, Claims, RuntimeOrigin, RuntimeEvent,
eth_keys::{
alice_account_id, total_claims, first_eth_public_known,
first_eth_public_key, first_account_id, first_signature,
second_eth_public_known, second_eth_public_key, second_account_id,
second_signature, third_eth_public_known, third_eth_public_key,
third_account_id, third_signature, fourth_eth_public_known,
fourth_eth_public_key, fourth_account_id, fourth_signature,
wrong_signature, bob_account_id,
}
};
use hex_literal::hex;
use frame_support::{assert_err, assert_ok};
use super::*;
use frame_support::{assert_err, assert_ok};
use hex_literal::hex;
use mock::{
eth_keys::{
alice_account_id, bob_account_id, first_account_id, first_eth_public_key,
first_eth_public_known, first_signature, fourth_account_id, fourth_eth_public_key,
fourth_eth_public_known, fourth_signature, second_account_id, second_eth_public_key,
second_eth_public_known, second_signature, third_account_id, third_eth_public_key,
third_eth_public_known, third_signature, total_claims, wrong_signature,
},
ghost_claims, new_test_ext, Balances, Claims, Club, RuntimeEvent, RuntimeOrigin, System, Test,
Vesting,
};
#[test]
fn serde_works() {
@ -41,12 +39,12 @@ fn basic_setup_works() {
assert_eq!(Balances::usable_balance(&first_account_id()), 10);
assert_eq!(Balances::usable_balance(&second_account_id()), 100);
assert_eq!(Balances::usable_balance(&third_account_id()), 1000);
assert_eq!(Club::rank_of(&alice_account_id()), None);
assert_eq!(Club::rank_of(&first_account_id()), None);
assert_eq!(Club::rank_of(&second_account_id()), Some(1));
assert_eq!(Club::rank_of(&third_account_id()), Some(3));
assert_eq!(Vesting::vesting_balance(&alice_account_id()), None);
assert_eq!(ghost_claims::Total::<Test, ()>::get(), total_claims());
});
@ -56,9 +54,10 @@ fn basic_setup_works() {
fn small_claiming_works() {
new_test_ext().execute_with(|| {
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
first_eth_public_key(),
first_signature()));
RuntimeOrigin::signed(alice_account_id()),
first_eth_public_key(),
first_signature()
));
assert_eq!(Balances::usable_balance(&alice_account_id()), 10);
assert_eq!(Balances::usable_balance(&first_account_id()), 0);
@ -77,9 +76,9 @@ fn small_claiming_works() {
fn medium_claiming_works() {
new_test_ext().execute_with(|| {
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
second_eth_public_key(),
second_signature(),
RuntimeOrigin::signed(alice_account_id()),
second_eth_public_key(),
second_signature(),
));
assert_eq!(Balances::usable_balance(&alice_account_id()), 100);
@ -99,9 +98,9 @@ fn medium_claiming_works() {
fn big_claiming_works() {
new_test_ext().execute_with(|| {
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
third_eth_public_key(),
third_signature(),
RuntimeOrigin::signed(alice_account_id()),
third_eth_public_key(),
third_signature(),
));
assert_eq!(Balances::usable_balance(&alice_account_id()), 200);
@ -113,11 +112,15 @@ fn big_claiming_works() {
assert_eq!(Club::rank_of(&third_account_id()), None);
assert_eq!(Vesting::vesting_balance(&alice_account_id()), Some(800));
assert_eq!(ghost_claims::Total::<Test, ()>::get(), total_claims() - 1000);
assert_eq!(
ghost_claims::Total::<Test, ()>::get(),
total_claims() - 1000
);
assert_ok!(Balances::transfer_allow_death(
RuntimeOrigin::signed(alice_account_id()),
bob_account_id(),
200));
RuntimeOrigin::signed(alice_account_id()),
bob_account_id(),
200
));
})
}
@ -125,19 +128,19 @@ fn big_claiming_works() {
fn multiple_accounts_claiming_works() {
new_test_ext().execute_with(|| {
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
first_eth_public_key(),
first_signature(),
RuntimeOrigin::signed(alice_account_id()),
first_eth_public_key(),
first_signature(),
));
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
second_eth_public_key(),
second_signature(),
RuntimeOrigin::signed(alice_account_id()),
second_eth_public_key(),
second_signature(),
));
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
third_eth_public_key(),
third_signature(),
RuntimeOrigin::signed(alice_account_id()),
third_eth_public_key(),
third_signature(),
));
assert_eq!(Balances::usable_balance(&alice_account_id()), 310);
@ -157,19 +160,19 @@ fn multiple_accounts_claiming_works() {
fn multiple_accounts_reverese_claiming_works() {
new_test_ext().execute_with(|| {
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
third_eth_public_key(),
third_signature(),
RuntimeOrigin::signed(alice_account_id()),
third_eth_public_key(),
third_signature(),
));
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
second_eth_public_key(),
second_signature(),
RuntimeOrigin::signed(alice_account_id()),
second_eth_public_key(),
second_signature(),
));
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
first_eth_public_key(),
first_signature(),
RuntimeOrigin::signed(alice_account_id()),
first_eth_public_key(),
first_signature(),
));
assert_eq!(Balances::usable_balance(&alice_account_id()), 310);
@ -188,11 +191,14 @@ fn multiple_accounts_reverese_claiming_works() {
#[test]
fn cannot_claim_with_bad_signature() {
new_test_ext().execute_with(|| {
assert_err!(Claims::claim(
assert_err!(
Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
first_eth_public_key(),
wrong_signature()),
crate::Error::<Test>::InvalidEthereumAddress);
wrong_signature()
),
crate::Error::<Test>::InvalidEthereumAddress
);
assert_eq!(Balances::usable_balance(&alice_account_id()), 0);
assert_eq!(Balances::usable_balance(&first_account_id()), 10);
@ -212,11 +218,14 @@ fn cannot_claim_with_bad_signature() {
#[test]
fn cannot_claim_with_wrong_address() {
new_test_ext().execute_with(|| {
assert_err!(Claims::claim(
assert_err!(
Claims::claim(
RuntimeOrigin::signed(bob_account_id()),
first_eth_public_key(),
first_signature()),
crate::Error::<Test>::InvalidEthereumAddress);
first_signature()
),
crate::Error::<Test>::InvalidEthereumAddress
);
assert_eq!(Balances::usable_balance(&bob_account_id()), 0);
assert_eq!(Balances::usable_balance(&alice_account_id()), 0);
@ -237,11 +246,14 @@ fn cannot_claim_with_wrong_address() {
#[test]
fn cannot_claim_nothing() {
new_test_ext().execute_with(|| {
assert_err!(Claims::claim(
assert_err!(
Claims::claim(
RuntimeOrigin::signed(bob_account_id()),
fourth_eth_public_key(),
fourth_signature()),
crate::Error::<Test>::NoBalanceToClaim);
fourth_signature()
),
crate::Error::<Test>::NoBalanceToClaim
);
assert_eq!(Balances::usable_balance(&bob_account_id()), 0);
assert_eq!(Balances::usable_balance(&fourth_account_id()), 0);
assert_eq!(Vesting::vesting_balance(&bob_account_id()), None);
@ -259,16 +271,15 @@ fn event_emitted_during_claim() {
System::reset_events();
assert_eq!(System::event_count(), 0);
assert_ok!(Claims::claim(
RuntimeOrigin::signed(alice_account_id()),
third_eth_public_key(),
third_signature(),
RuntimeOrigin::signed(alice_account_id()),
third_eth_public_key(),
third_signature(),
));
System::assert_has_event(RuntimeEvent::Claims(
crate::Event::Claimed {
receiver: alice_account_id(),
donor: account,
amount,
rank,
}));
System::assert_has_event(RuntimeEvent::Claims(crate::Event::Claimed {
receiver: alice_account_id(),
donor: account,
amount,
rank,
}));
})
}

View File

@ -1,9 +1,104 @@
use frame_support::weights::Weight;
// This file is part of Ghost Network.
// Ghost Network 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.
// Ghost Network 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 Ghost Network. If not, see <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `ghost_claims`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2024-08-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
// Executed Command:
// ./target/release/ghost
// benchmark
// pallet
// --chain=casper-dev
// --steps=50
// --repeat=20
// --pallet=ghost_claims
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --header=./file_header.txt
// --output=./runtime/casper/src/weights/ghost_claims.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
use frame_support::{
traits::Get,
weights::{Weight, constants::RocksDbWeight},
};
use core::marker::PhantomData;
/// Weight functions needed for `ghost_claims`.
pub trait WeightInfo {
fn claim() -> Weight;
fn claim() -> Weight;
}
/// Weight for ghost_claims using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: `System::Account` (r:2 w:2)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `GhostClaims::Total` (r:1 w:1)
/// Proof: `GhostClaims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `CultCollective::Members` (r:2 w:2)
/// Proof: `CultCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::MemberCount` (r:6 w:6)
/// Proof: `CultCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::IdToIndex` (r:6 w:12)
/// Proof: `CultCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::IndexToId` (r:0 w:6)
/// Proof: `CultCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
fn claim() -> Weight {
// Proof Size summary in bytes:
// Measured: `896`
// Estimated: `16164`
// Minimum execution time: 754_086_000 picoseconds.
Weight::from_parts(756_147_000, 0)
.saturating_add(Weight::from_parts(0, 16164))
.saturating_add(T::DbWeight::get().reads(17))
.saturating_add(T::DbWeight::get().writes(29))
}
}
impl WeightInfo for () {
fn claim() -> Weight { Weight::zero() }
/// Storage: `System::Account` (r:2 w:2)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `GhostClaims::Total` (r:1 w:1)
/// Proof: `GhostClaims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `CultCollective::Members` (r:2 w:2)
/// Proof: `CultCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::MemberCount` (r:6 w:6)
/// Proof: `CultCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::IdToIndex` (r:6 w:12)
/// Proof: `CultCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::IndexToId` (r:0 w:6)
/// Proof: `CultCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
fn claim() -> Weight {
// Proof Size summary in bytes:
// Measured: `896`
// Estimated: `16164`
// Minimum execution time: 754_086_000 picoseconds.
Weight::from_parts(756_147_000, 0)
.saturating_add(Weight::from_parts(0, 16164))
.saturating_add(RocksDbWeight::get().reads(17))
.saturating_add(RocksDbWeight::get().writes(29))
}
}

44
pallets/networks/Cargo.toml Executable file → Normal file
View File

@ -1,8 +1,8 @@
[package]
name = "ghost-networks"
version = "0.1.16"
license.workspace = true
authors.workspace = true
version.workspace = true
edition.workspace = true
homepage.workspace = true
repository.workspace = true
@ -10,40 +10,48 @@ repository.workspace = true
[dependencies]
scale-info = { workspace = true, features = ["derive"] }
codec = { workspace = true, features = ["max-encoded-len"] }
num-traits = { workspace = true }
frame-benchmarking = { workspace = true, optional = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-staking = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
ghost-traits = { workspace = true }
[dev-dependencies]
primitives = { workspace = true }
pallet-balances = { workspace = true }
sp-io = { workspace = true }
pallet-balances = { workspace = true }
pallet-staking-reward-curve = { workspace = true }
[features]
default = ["std"]
std = [
"scale-info/std",
"codec/std",
"frame-support/std",
"frame-system/std",
"frame-benchmarking?/std",
"sp-runtime/std",
"sp-std/std",
"sp-io/std",
"ghost-traits/std",
"pallet-balances/std",
"scale-info/std",
"codec/std",
"num-traits/std",
"frame-support/std",
"frame-system/std",
"frame-benchmarking?/std",
"sp-runtime/std",
"sp-std/std",
"sp-io/std",
"ghost-traits/std",
"pallet-staking/std",
"pallet-balances/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"pallet-staking/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-staking/try-runtime",
"pallet-balances/try-runtime",
]

88
pallets/networks/src/benchmarking.rs Executable file → Normal file
View File

@ -8,31 +8,44 @@ use sp_runtime::Saturating;
const MAX_NAME_LEN: u32 = 20;
const MAX_ENDPOINT_LEN: u32 = 150;
const MAX_ENDPOINT_NUMBER: u32 = 20;
fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
frame_system::Pallet::<T>::assert_last_event(generic_event.into());
}
fn prepare_network<T: Config>(
n: u32, m: u32,
n: u32,
m: u32,
k: u32,
) -> (<T as module::Config>::NetworkId, NetworkData) {
let chain_id: <T as module::Config>::NetworkId = Default::default();
let chain_id = chain_id.saturating_add((n + m).into());
let mut gatekeeper = b"0x".to_vec();
for i in 0..40 { gatekeeper.push(i); }
for i in 0..40 {
gatekeeper.push(i);
}
let mut topic_name = b"0x".to_vec();
for i in 0..64 { topic_name.push(i); }
for i in 0..64 {
topic_name.push(i);
}
let mut default_endpoints = sp_std::vec![];
for _ in 0..(k as usize) {
default_endpoints.push(sp_std::vec![0x69; m as usize]);
}
let network = NetworkData {
chain_name: sp_std::vec![0x69; n as usize],
default_endpoint: sp_std::vec![0x69; m as usize],
default_endpoints,
gatekeeper,
topic_name,
finality_delay: Some(69),
release_delay: Some(69),
network_type: NetworkType::Evm,
finality_delay: 69,
rate_limit_delay: 69,
block_distance: 69,
incoming_fee: 0,
outgoing_fee: 0,
};
@ -50,8 +63,11 @@ fn create_network<T: Config>(
let authority = T::RegisterOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
GhostNetworks::<T>::register_network(
authority.clone(), chain_id.clone(), network.clone()
).map_err(|_| BenchmarkError::Weightless)?;
authority.clone(),
chain_id.clone(),
network.clone(),
)
.map_err(|_| BenchmarkError::Weightless)?;
network
}
};
@ -63,8 +79,9 @@ benchmarks! {
register_network {
let i in 1 .. MAX_NAME_LEN;
let j in 1 .. MAX_ENDPOINT_LEN;
let k in 1 .. MAX_ENDPOINT_NUMBER;
let (chain_id, network) = prepare_network::<T>(i, j);
let (chain_id, network) = prepare_network::<T>(i, j, k);
let authority = T::RegisterOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = GhostNetworks::<T>::networks(chain_id.clone());
@ -79,7 +96,7 @@ benchmarks! {
update_network_name {
let n in 1 .. MAX_NAME_LEN;
let name = sp_std::vec![0x42; n as usize];
let (chain_id, network) = prepare_network::<T>(1, 1);
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
@ -93,22 +110,25 @@ benchmarks! {
update_network_endpoint {
let n in 1 .. MAX_ENDPOINT_LEN;
let index_to_update = 0u32;
let endpoint = sp_std::vec![0x42; n as usize];
let (chain_id, network) = prepare_network::<T>(1, 1);
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
}: _<T::RuntimeOrigin>(authority, chain_id.clone(), endpoint.clone())
}: _<T::RuntimeOrigin>(authority, chain_id.clone(), Some(index_to_update), Some(endpoint.clone()))
verify {
assert_last_event::<T>(Event::NetworkEndpointUpdated {
chain_id: chain_id.clone(), default_endpoint: endpoint,
chain_id: chain_id.clone(),
index: index_to_update,
endpoint,
}.into());
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
}
update_network_finality_delay {
let delay = Some(1337);
let (chain_id, network) = prepare_network::<T>(1, 1);
let delay = 1337;
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
@ -120,23 +140,37 @@ benchmarks! {
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
}
update_network_release_delay {
let delay = Some(1337);
let (chain_id, network) = prepare_network::<T>(1, 1);
update_network_rate_limit_delay {
let rate_limit = 1337;
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
}: _<T::RuntimeOrigin>(authority, chain_id.clone(), delay)
}: _<T::RuntimeOrigin>(authority, chain_id.clone(), rate_limit)
verify {
assert_last_event::<T>(Event::NetworkReleaseDelayUpdated {
chain_id: chain_id.clone(), release_delay: delay,
assert_last_event::<T>(Event::NetworkRateLimitDelayUpdated {
chain_id: chain_id.clone(), rate_limit_delay: rate_limit,
}.into());
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
}
update_network_block_distance {
let block_distance = 1337;
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
}: _<T::RuntimeOrigin>(authority, chain_id.clone(), block_distance)
verify {
assert_last_event::<T>(Event::NetworkBlockDistanceUpdated {
chain_id: chain_id.clone(), block_distance,
}.into());
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
}
update_network_type {
let network_type = NetworkType::Utxo;
let (chain_id, network) = prepare_network::<T>(1, 1);
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
@ -151,7 +185,7 @@ benchmarks! {
update_network_gatekeeper {
let mut gatekeeper = b"0x".to_vec();
for i in 0..40 { gatekeeper.push(i + 1); }
let (chain_id, network) = prepare_network::<T>(1, 1);
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
@ -165,7 +199,7 @@ benchmarks! {
update_network_topic_name {
let topic_name = b"0x9876543219876543219876543219876543219876543219876543219876543219".to_vec();
let (chain_id, network) = prepare_network::<T>(1, 1);
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
@ -179,7 +213,7 @@ benchmarks! {
update_incoming_network_fee {
let incoming_fee = 1337;
let (chain_id, network) = prepare_network::<T>(1, 1);
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
@ -193,7 +227,7 @@ benchmarks! {
update_outgoing_network_fee {
let outgoing_fee = 1337;
let (chain_id, network) = prepare_network::<T>(1, 1);
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
@ -206,7 +240,7 @@ benchmarks! {
}
remove_network {
let (chain_id, network) = prepare_network::<T>(1, 1);
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::RemoveOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;

488
pallets/networks/src/lib.rs Executable file → Normal file
View File

@ -4,25 +4,29 @@
use frame_support::{
pallet_prelude::*,
storage::PrefixIterator, traits::EnsureOrigin,
storage::PrefixIterator,
traits::{tokens::fungible::Inspect, EnsureOrigin},
};
use frame_system::pallet_prelude::*;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{AtLeast32BitUnsigned, Member},
curve::PiecewiseLinear,
traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Member},
DispatchResult,
};
use sp_std::prelude::*;
use sp_std::{convert::TryInto, prelude::*};
pub use ghost_traits::networks::{
NetworkDataBasicHandler, NetworkDataInspectHandler,
NetworkDataMutateHandler,
NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler,
};
mod math;
mod weights;
pub use module::*;
pub use crate::weights::WeightInfo;
use math::MulDiv;
pub use module::*;
#[cfg(any(feature = "runtime-benchmarks", test))]
mod benchmarking;
@ -31,6 +35,9 @@ mod mock;
#[cfg(all(feature = "std", test))]
mod tests;
pub type BalanceOf<T> =
<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub enum NetworkType {
Evm = 0,
@ -39,22 +46,78 @@ pub enum NetworkType {
}
impl Default for NetworkType {
fn default() -> Self { NetworkType::Evm }
fn default() -> Self {
NetworkType::Evm
}
}
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct NetworkData {
pub chain_name: Vec<u8>,
pub default_endpoint: Vec<u8>,
pub default_endpoints: Vec<Vec<u8>>,
pub gatekeeper: Vec<u8>,
pub topic_name: Vec<u8>,
pub finality_delay: Option<u64>,
pub release_delay: Option<u64>,
pub network_type: NetworkType,
pub finality_delay: u64,
pub rate_limit_delay: u64,
pub block_distance: u64,
pub incoming_fee: u32,
pub outgoing_fee: u32,
}
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct BridgeAdjustment<Balance> {
pub bridged_out: Balance,
pub bridged_in: Balance,
}
pub struct BridgedInflationCurve<RewardCurve, T>(core::marker::PhantomData<(RewardCurve, T)>);
impl<Balance, RewardCurve, T> pallet_staking::EraPayout<Balance>
for BridgedInflationCurve<RewardCurve, T>
where
Balance: Default
+ Copy
+ From<BalanceOf<T>>
+ AtLeast32BitUnsigned
+ num_traits::ops::wrapping::WrappingAdd
+ num_traits::ops::overflowing::OverflowingAdd
+ sp_std::ops::AddAssign
+ sp_std::ops::Not<Output = Balance>
+ sp_std::ops::Shl<Output = Balance>
+ sp_std::ops::Shr<Output = Balance>
+ sp_std::ops::BitAnd<Balance, Output = Balance>,
RewardCurve: Get<&'static PiecewiseLinear<'static>>,
T: Config,
{
fn era_payout(
total_staked: Balance,
total_issuance: Balance,
_era_duration_in_millis: u64,
) -> (Balance, Balance) {
let reward_curve = RewardCurve::get();
let bridged_imbalance = BridgedImbalance::<T>::get();
let accumulated_commission = AccumulatedCommission::<T>::get();
let accumulated_commission: Balance = accumulated_commission.into();
let adjusted_issuance: Balance = total_issuance
.saturating_add(bridged_imbalance.bridged_out.into())
.saturating_sub(bridged_imbalance.bridged_in.into());
NullifyNeeded::<T>::set(true);
let estimated_reward =
reward_curve.calculate_for_fraction_times_denominator(total_staked, adjusted_issuance);
let payout = MulDiv::<Balance>::calculate(
estimated_reward,
accumulated_commission,
adjusted_issuance,
);
let rest_payout = accumulated_commission.saturating_sub(payout);
(payout, rest_payout)
}
}
#[frame_support::pallet]
pub mod module {
use super::*;
@ -63,6 +126,9 @@ pub mod module {
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// The type used for the internal balance storage.
type Currency: Inspect<Self::AccountId>;
/// The type used as a unique network id.
type NetworkId: Parameter
+ Member
@ -74,7 +140,7 @@ pub mod module {
+ TypeInfo
+ MaybeSerializeDeserialize
+ MaxEncodedLen;
/// The origin required to register new network.
type RegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;
/// The origin required to update network information.
@ -101,24 +167,87 @@ pub mod module {
#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config> {
NetworkRegistered { chain_id: T::NetworkId, network: NetworkData },
NetworkNameUpdated { chain_id: T::NetworkId, chain_name: Vec<u8> },
NetworkEndpointUpdated { chain_id: T::NetworkId, default_endpoint: Vec<u8> },
NetworkFinalityDelayUpdated { chain_id: T::NetworkId, finality_delay: Option<u64> },
NetworkReleaseDelayUpdated { chain_id: T::NetworkId, release_delay: Option<u64> },
NetworkTypeUpdated { chain_id: T::NetworkId, network_type: NetworkType },
NetworkGatekeeperUpdated { chain_id: T::NetworkId, gatekeeper: Vec<u8> },
NetworkTopicNameUpdated { chain_id: T::NetworkId, topic_name: Vec<u8> },
NetworkIncomingFeeUpdated { chain_id: T::NetworkId, incoming_fee: u32 },
NetworkOutgoingFeeUpdated { chain_id: T::NetworkId, outgoing_fee: u32 },
NetworkRemoved { chain_id: T::NetworkId },
NetworkRegistered {
chain_id: T::NetworkId,
network: NetworkData,
},
NetworkNameUpdated {
chain_id: T::NetworkId,
chain_name: Vec<u8>,
},
NetworkEndpointUpdated {
chain_id: T::NetworkId,
index: u32,
endpoint: Vec<u8>,
},
NetworkEndpointRemoved {
chain_id: T::NetworkId,
index: u32,
},
NetworkEndpointAdded {
chain_id: T::NetworkId,
endpoint: Vec<u8>,
},
NetworkFinalityDelayUpdated {
chain_id: T::NetworkId,
finality_delay: u64,
},
NetworkRateLimitDelayUpdated {
chain_id: T::NetworkId,
rate_limit_delay: u64,
},
NetworkBlockDistanceUpdated {
chain_id: T::NetworkId,
block_distance: u64,
},
NetworkTypeUpdated {
chain_id: T::NetworkId,
network_type: NetworkType,
},
NetworkGatekeeperUpdated {
chain_id: T::NetworkId,
gatekeeper: Vec<u8>,
},
NetworkTopicNameUpdated {
chain_id: T::NetworkId,
topic_name: Vec<u8>,
},
NetworkIncomingFeeUpdated {
chain_id: T::NetworkId,
incoming_fee: u32,
},
NetworkOutgoingFeeUpdated {
chain_id: T::NetworkId,
outgoing_fee: u32,
},
NetworkRemoved {
chain_id: T::NetworkId,
},
}
#[pallet::storage]
#[pallet::getter(fn nullify_needed)]
pub type NullifyNeeded<T: Config> = StorageValue<_, bool, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn bridged_imbalance)]
pub type BridgedImbalance<T: Config> =
StorageValue<_, BridgeAdjustment<BalanceOf<T>>, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn accumulated_commission)]
pub type AccumulatedCommission<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn networks)]
pub type Networks<T: Config> =
StorageMap<_, Twox64Concat, T::NetworkId, NetworkData, OptionQuery>;
#[pallet::storage]
#[pallet::getter(fn gatekeeper_amount)]
pub type GatekeeperAmount<T: Config> =
StorageMap<_, Twox64Concat, T::NetworkId, BalanceOf<T>, ValueQuery>;
#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
pub networks: Vec<(T::NetworkId, Vec<u8>)>,
@ -126,7 +255,7 @@ pub mod module {
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self { networks: vec![] }
Self { networks: vec![] }
}
}
@ -134,12 +263,13 @@ pub mod module {
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
if !self.networks.is_empty() {
self.networks.iter().for_each(|(chain_id, network_metadata)| {
let network =
NetworkData::decode(&mut &network_metadata[..])
.expect("Error decoding NetworkData");
Pallet::<T>::do_register_network(chain_id.clone(), network)
.expect("Error registering network");
self.networks
.iter()
.for_each(|(chain_id, network_metadata)| {
let network = NetworkData::decode(&mut &network_metadata[..])
.expect("Error decoding NetworkData");
Pallet::<T>::do_register_network(chain_id.clone(), network)
.expect("Error registering network");
});
}
}
@ -150,14 +280,30 @@ pub mod module {
pub struct Pallet<T>(PhantomData<T>);
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_initialize(_: BlockNumberFor<T>) -> Weight {
T::DbWeight::get().reads_writes(1, 1)
}
fn on_finalize(_: BlockNumberFor<T>) {
if Self::nullify_needed() {
Self::nullify_commission();
NullifyNeeded::<T>::put(false);
}
}
}
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::register_network(
network.chain_name.len() as u32,
network.default_endpoint.len() as u32,
network.default_endpoints
.iter()
.map(|endpoint| endpoint.len())
.max()
.unwrap_or_default() as u32,
network.default_endpoints.len() as u32,
))]
pub fn register_network(
origin: OriginFor<T>,
@ -178,26 +324,24 @@ pub mod module {
chain_name: Vec<u8>,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_network_name(
chain_id,
chain_name,
)
Self::do_update_network_name(chain_id, chain_name)
}
#[pallet::call_index(2)]
#[pallet::weight(T::WeightInfo::update_network_endpoint(
default_endpoint.len() as u32
maybe_endpoint
.as_ref()
.map(|endpoint| endpoint.len())
.unwrap_or_default() as u32
))]
pub fn update_network_endpoint(
origin: OriginFor<T>,
chain_id: T::NetworkId,
default_endpoint: Vec<u8>,
maybe_index: Option<u32>,
maybe_endpoint: Option<Vec<u8>>,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_network_endpoint(
chain_id,
default_endpoint,
)
Self::do_update_network_endpoint(chain_id, maybe_index, maybe_endpoint)
}
#[pallet::call_index(3)]
@ -205,30 +349,35 @@ pub mod module {
pub fn update_network_finality_delay(
origin: OriginFor<T>,
chain_id: T::NetworkId,
finality_delay: Option<u64>,
finality_delay: u64,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_network_finality_delay(
chain_id,
finality_delay,
)
Self::do_update_network_finality_delay(chain_id, finality_delay)
}
#[pallet::call_index(4)]
#[pallet::weight(T::WeightInfo::update_network_release_delay())]
pub fn update_network_release_delay(
#[pallet::weight(T::WeightInfo::update_network_rate_limit_delay())]
pub fn update_network_rate_limit_delay(
origin: OriginFor<T>,
chain_id: T::NetworkId,
release_delay: Option<u64>,
rate_limit_delay: u64,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_network_release_delay(
chain_id,
release_delay,
)
Self::do_update_network_rate_limit_delay(chain_id, rate_limit_delay)
}
#[pallet::call_index(5)]
#[pallet::weight(T::WeightInfo::update_network_block_distance())]
pub fn update_network_block_distance(
origin: OriginFor<T>,
chain_id: T::NetworkId,
block_distance: u64,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_network_block_distance(chain_id, block_distance)
}
#[pallet::call_index(6)]
#[pallet::weight(T::WeightInfo::update_network_type())]
pub fn update_network_type(
origin: OriginFor<T>,
@ -236,13 +385,10 @@ pub mod module {
network_type: NetworkType,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_network_type(
chain_id,
network_type,
)
Self::do_update_network_type(chain_id, network_type)
}
#[pallet::call_index(6)]
#[pallet::call_index(7)]
#[pallet::weight(T::WeightInfo::update_network_gatekeeper())]
pub fn update_network_gatekeeper(
origin: OriginFor<T>,
@ -250,13 +396,10 @@ pub mod module {
gatekeeper: Vec<u8>,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_network_gatekeeper(
chain_id,
gatekeeper,
)
Self::do_update_network_gatekeeper(chain_id, gatekeeper)
}
#[pallet::call_index(7)]
#[pallet::call_index(8)]
#[pallet::weight(T::WeightInfo::update_network_topic_name())]
pub fn update_network_topic_name(
origin: OriginFor<T>,
@ -264,13 +407,10 @@ pub mod module {
topic_name: Vec<u8>,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_network_topic_name(
chain_id,
topic_name,
)
Self::do_update_network_topic_name(chain_id, topic_name)
}
#[pallet::call_index(8)]
#[pallet::call_index(9)]
#[pallet::weight(T::WeightInfo::update_incoming_network_fee())]
pub fn update_incoming_network_fee(
origin: OriginFor<T>,
@ -278,13 +418,10 @@ pub mod module {
incoming_fee: u32,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_incoming_network_fee(
chain_id,
incoming_fee,
)
Self::do_update_incoming_network_fee(chain_id, incoming_fee)
}
#[pallet::call_index(9)]
#[pallet::call_index(10)]
#[pallet::weight(T::WeightInfo::update_outgoing_network_fee())]
pub fn update_outgoing_network_fee(
origin: OriginFor<T>,
@ -292,18 +429,12 @@ pub mod module {
outgoing_fee: u32,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_outgoing_network_fee(
chain_id,
outgoing_fee,
)
Self::do_update_outgoing_network_fee(chain_id, outgoing_fee)
}
#[pallet::call_index(10)]
#[pallet::call_index(11)]
#[pallet::weight(T::WeightInfo::remove_network())]
pub fn remove_network(
origin: OriginFor<T>,
chain_id: T::NetworkId,
) -> DispatchResult {
pub fn remove_network(origin: OriginFor<T>, chain_id: T::NetworkId) -> DispatchResult {
T::RemoveOrigin::ensure_origin_or_root(origin)?;
Self::do_remove_network(chain_id)
}
@ -312,12 +443,12 @@ pub mod module {
impl<T: Config> Pallet<T> {
/// Register a new network.
pub fn do_register_network(
chain_id: T::NetworkId,
network: NetworkData,
) -> DispatchResult {
pub fn do_register_network(chain_id: T::NetworkId, network: NetworkData) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_none(), Error::<T>::NetworkAlreadyRegistered);
ensure!(
maybe_network.is_none(),
Error::<T>::NetworkAlreadyRegistered
);
*maybe_network = Some(network.clone());
Ok(())
})?;
@ -339,10 +470,7 @@ impl<T: Config> Pallet<T> {
}
/// Update existent network name.
pub fn do_update_network_name(
chain_id: T::NetworkId,
chain_name: Vec<u8>,
) -> DispatchResult {
pub fn do_update_network_name(chain_id: T::NetworkId, chain_name: Vec<u8>) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap();
@ -361,26 +489,45 @@ impl<T: Config> Pallet<T> {
/// Update existent network default endpoint.
pub fn do_update_network_endpoint(
chain_id: T::NetworkId,
default_endpoint: Vec<u8>,
maybe_index: Option<u32>,
maybe_endpoint: Option<Vec<u8>>,
) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap();
net.default_endpoint = default_endpoint.clone();
*maybe_network = Some(net.clone());
let updated_network = maybe_network.as_mut().unwrap();
match (maybe_index, maybe_endpoint) {
(Some(index), Some(endpoint)) => {
if let Some(previous_endpoint) =
updated_network.default_endpoints.get_mut(index as usize)
{
*previous_endpoint = endpoint.clone();
Self::deposit_event(Event::<T>::NetworkEndpointUpdated {
chain_id,
index,
endpoint,
});
}
}
(None, Some(endpoint)) => {
updated_network.default_endpoints.push(endpoint.clone());
Self::deposit_event(Event::<T>::NetworkEndpointAdded { chain_id, endpoint });
}
(Some(index), None) => {
updated_network.default_endpoints.remove(index as usize);
Self::deposit_event(Event::<T>::NetworkEndpointRemoved { chain_id, index });
}
(None, None) => {}
}
*maybe_network = Some(updated_network.clone());
Ok(())
})?;
Self::deposit_event(Event::<T>::NetworkEndpointUpdated {
chain_id,
default_endpoint,
});
Ok(())
}
/// Update existent network default endpoint.
/// Update existent network default finality delay.
pub fn do_update_network_finality_delay(
chain_id: T::NetworkId,
finality_delay: Option<u64>,
finality_delay: u64,
) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
@ -396,21 +543,40 @@ impl<T: Config> Pallet<T> {
Ok(())
}
/// Update existent network default endpoint.
pub fn do_update_network_release_delay(
/// Update existent network default rate limit delay.
pub fn do_update_network_rate_limit_delay(
chain_id: T::NetworkId,
release_delay: Option<u64>,
rate_limit_delay: u64,
) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap();
net.release_delay = release_delay;
net.rate_limit_delay = rate_limit_delay;
*maybe_network = Some(net.clone());
Ok(())
})?;
Self::deposit_event(Event::<T>::NetworkReleaseDelayUpdated {
Self::deposit_event(Event::<T>::NetworkRateLimitDelayUpdated {
chain_id,
release_delay,
rate_limit_delay,
});
Ok(())
}
/// Update existent network default max distance between blocks.
pub fn do_update_network_block_distance(
chain_id: T::NetworkId,
block_distance: u64,
) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap();
net.block_distance = block_distance;
*maybe_network = Some(net.clone());
Ok(())
})?;
Self::deposit_event(Event::<T>::NetworkBlockDistanceUpdated {
chain_id,
block_distance,
});
Ok(())
}
@ -439,8 +605,10 @@ impl<T: Config> Pallet<T> {
chain_id: T::NetworkId,
gatekeeper: Vec<u8>,
) -> DispatchResult {
ensure!(gatekeeper.len() == 42 && gatekeeper[0] == 48 && gatekeeper[1] == 120,
Error::<T>::WrongGatekeeperAddress);
ensure!(
gatekeeper.len() == 42 && gatekeeper[0] == 48 && gatekeeper[1] == 120,
Error::<T>::WrongGatekeeperAddress
);
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap();
@ -460,8 +628,10 @@ impl<T: Config> Pallet<T> {
chain_id: T::NetworkId,
topic_name: Vec<u8>,
) -> DispatchResult {
ensure!(topic_name.len() == 66 && topic_name[0] == 48 && topic_name[1] == 120,
Error::<T>::WrongTopicName);
ensure!(
topic_name.len() == 66 && topic_name[0] == 48 && topic_name[1] == 120,
Error::<T>::WrongTopicName
);
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap();
@ -525,9 +695,13 @@ impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
fn iter() -> PrefixIterator<(Self::NetworkId, NetworkData)> {
Networks::<T>::iter()
}
fn is_nullification_period() -> bool {
NullifyNeeded::<T>::get()
}
}
impl<T: Config> NetworkDataMutateHandler<NetworkData> for Pallet<T> {
impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T> {
fn register(chain_id: Self::NetworkId, network: NetworkData) -> DispatchResult {
Self::do_register_network(chain_id, network)
}
@ -535,4 +709,94 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData> for Pallet<T> {
fn remove(chain_id: Self::NetworkId) -> DispatchResult {
Self::do_remove_network(chain_id)
}
fn increase_gatekeeper_amount(
network_id: &T::NetworkId,
amount: &BalanceOf<T>,
) -> Result<BalanceOf<T>, ()> {
let new_gatekeeper_amount =
GatekeeperAmount::<T>::mutate(network_id, |gatekeeper_amount| match gatekeeper_amount
.checked_add(amount)
{
Some(value) => {
*gatekeeper_amount = value;
Ok(value)
}
None => Err(()),
})?;
Ok(new_gatekeeper_amount)
}
fn decrease_gatekeeper_amount(
network_id: &T::NetworkId,
amount: &BalanceOf<T>,
) -> Result<BalanceOf<T>, ()> {
let new_gatekeeper_amount =
GatekeeperAmount::<T>::mutate(network_id, |gatekeeper_amount| match gatekeeper_amount
.checked_sub(amount)
{
Some(value) => {
*gatekeeper_amount = value;
Ok(value)
}
None => Err(()),
})?;
Ok(new_gatekeeper_amount)
}
fn accumulate_outgoing_imbalance(amount: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> {
let new_bridged_out_amount = BridgedImbalance::<T>::mutate(|bridged_imbalance| {
match bridged_imbalance.bridged_out.checked_add(amount) {
Some(value) => {
(*bridged_imbalance).bridged_out = value;
Ok(value)
}
None => Err(()),
}
})?;
Ok(new_bridged_out_amount)
}
fn accumulate_incoming_imbalance(amount: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> {
let new_bridged_in_amount = BridgedImbalance::<T>::mutate(|bridged_imbalance| {
match bridged_imbalance.bridged_in.checked_add(amount) {
Some(value) => {
(*bridged_imbalance).bridged_in = value;
Ok(value)
}
None => Err(()),
}
})?;
Ok(new_bridged_in_amount)
}
fn accumulate_commission(commission: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> {
AccumulatedCommission::<T>::mutate(|accumulated| {
match accumulated.checked_add(commission) {
Some(value) => {
*accumulated = value;
Ok(value)
}
None => Err(()),
}
})
}
fn nullify_commission() {
AccumulatedCommission::<T>::set(Default::default());
BridgedImbalance::<T>::set(Default::default());
}
fn trigger_nullification() {
if NullifyNeeded::<T>::get() {
Self::nullify_commission();
NullifyNeeded::<T>::put(false);
} else {
NullifyNeeded::<T>::put(true);
}
}
}

View File

@ -0,0 +1,135 @@
use crate::AtLeast32BitUnsigned;
pub struct MulDiv<Balance>(core::marker::PhantomData<Balance>);
impl<Balance> MulDiv<Balance>
where
Balance: Copy
+ AtLeast32BitUnsigned
+ num_traits::ops::wrapping::WrappingAdd
+ num_traits::ops::overflowing::OverflowingAdd
+ sp_std::ops::AddAssign
+ sp_std::ops::Not<Output = Balance>
+ sp_std::ops::Shl<Output = Balance>
+ sp_std::ops::Shr<Output = Balance>
+ sp_std::ops::BitAnd<Balance, Output = Balance>,
{
fn zero(&self) -> Balance {
0u32.into()
}
fn one(&self) -> Balance {
1u32.into()
}
fn bit_shift(&self) -> Balance {
let u32_shift: u32 = core::mem::size_of::<Balance>()
.saturating_mul(4)
.try_into()
.unwrap_or_default();
u32_shift.into()
}
fn least_significant_bits(&self, a: Balance) -> Balance {
a & ((self.one() << self.bit_shift()) - self.one())
}
fn most_significant_bits(&self, a: Balance) -> Balance {
a >> self.bit_shift()
}
fn two_complement(&self, a: Balance) -> Balance {
(!a).wrapping_add(&self.one())
}
fn adjusted_ratio(&self, a: Balance) -> Balance {
(self.two_complement(a) / a).wrapping_add(&self.one())
}
fn modulo(&self, a: Balance) -> Balance {
self.two_complement(a) % a
}
fn overflow_resistant_addition(
&self,
a0: Balance,
a1: Balance,
b0: Balance,
b1: Balance,
) -> (Balance, Balance) {
let (r0, overflow) = a0.overflowing_add(&b0);
let overflow: Balance = overflow.then(|| 1u32).unwrap_or_default().into();
let r1 = a1.wrapping_add(&b1).wrapping_add(&overflow);
(r0, r1)
}
fn overflow_resistant_multiplication(&self, a: Balance, b: Balance) -> (Balance, Balance) {
let (a0, a1) = (
self.least_significant_bits(a),
self.most_significant_bits(a),
);
let (b0, b1) = (
self.least_significant_bits(b),
self.most_significant_bits(b),
);
let (x, y) = (a1 * b0, b1 * a0);
let (r0, r1) = (a0 * b0, a1 * b1);
let (r0, r1) = self.overflow_resistant_addition(
r0,
r1,
self.least_significant_bits(x) << self.bit_shift(),
self.most_significant_bits(x),
);
let (r0, r1) = self.overflow_resistant_addition(
r0,
r1,
self.least_significant_bits(y) << self.bit_shift(),
self.most_significant_bits(y),
);
(r0, r1)
}
fn overflow_resistant_division(
&self,
mut a0: Balance,
mut a1: Balance,
b: Balance,
) -> (Balance, Balance) {
if b == self.one() {
return (a0, a1);
}
let zero: Balance = 0u32.into();
let (q, r) = (self.adjusted_ratio(b), self.modulo(b));
let (mut x0, mut x1) = (zero, zero);
while a1 != zero {
let (t0, t1) = self.overflow_resistant_multiplication(a1, q);
let (new_x0, new_x1) = self.overflow_resistant_addition(x0, x1, t0, t1);
x0 = new_x0;
x1 = new_x1;
let (t0, t1) = self.overflow_resistant_multiplication(a1, r);
let (new_a0, new_a1) = self.overflow_resistant_addition(t0, t1, a0, zero);
a0 = new_a0;
a1 = new_a1;
}
self.overflow_resistant_addition(x0, x1, a0 / b, zero)
}
fn mul_div(&self, a: Balance, b: Balance, c: Balance) -> Balance {
let (t0, t1) = self.overflow_resistant_multiplication(a, b);
self.overflow_resistant_division(t0, t1, c).0
}
pub fn calculate(a: Balance, b: Balance, c: Balance) -> Balance {
let inner = MulDiv(core::marker::PhantomData);
if c == inner.zero() {
return c;
}
inner.mul_div(a, b, c)
}
}

41
pallets/networks/src/mock.rs Executable file → Normal file
View File

@ -1,19 +1,24 @@
use crate as ghost_networks;
use frame_system::EnsureSignedBy;
use crate::{self as ghost_networks};
use frame_support::{
construct_runtime, ord_parameter_types, parameter_types, traits::{ConstU128, ConstU32, Everything}
construct_runtime, ord_parameter_types, parameter_types,
traits::{ConstU128, ConstU32, Everything},
};
use frame_system::EnsureSignedBy;
pub use primitives::{
AccountId, Balance, Nonce, BlockNumber, Hash,
ReserveIdentifier, FreezeIdentifier,
AccountId, Balance, BlockNumber, FreezeIdentifier, Hash, Nonce, ReserveIdentifier,
};
use sp_runtime::{
traits::{BlakeTwo256, AccountIdLookup},
curve::PiecewiseLinear,
traits::{AccountIdLookup, BlakeTwo256},
BuildStorage,
};
parameter_types! {
pub const BlockHashCount: BlockNumber = 250;
pub static SlashDeferDuration: u32 = 0;
pub static Period: BlockNumber = 5;
pub static Offset: BlockNumber = 0;
pub static MaxControllersInDeprecationBatch: u32 = 5_000;
}
impl frame_system::Config for Test {
@ -64,6 +69,21 @@ impl pallet_balances::Config for Test {
type MaxFreezes = ConstU32<50>;
}
pallet_staking_reward_curve::build! {
const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
min_inflation: 0_006_900,
max_inflation: 1_000_000,
ideal_stake: 0_690_000,
falloff: 0_050_000,
max_piece_count: 100,
test_precision: 0_005_000,
);
}
parameter_types! {
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
}
ord_parameter_types! {
pub const RegistererAccount: AccountId = AccountId::from([1u8; 32]);
pub const UpdaterAccount: AccountId = AccountId::from([2u8; 32]);
@ -73,14 +93,15 @@ ord_parameter_types! {
impl ghost_networks::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type NetworkId = u32;
type RegisterOrigin = EnsureSignedBy::<RegistererAccount, AccountId>;
type UpdateOrigin = EnsureSignedBy::<UpdaterAccount, AccountId>;
type RemoveOrigin = EnsureSignedBy::<RemoverAccount, AccountId>;
type RegisterOrigin = EnsureSignedBy<RegistererAccount, AccountId>;
type UpdateOrigin = EnsureSignedBy<UpdaterAccount, AccountId>;
type RemoveOrigin = EnsureSignedBy<RemoverAccount, AccountId>;
type WeightInfo = crate::weights::SubstrateWeight<Test>;
}
type Block = frame_system::mocking::MockBlockU32<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
construct_runtime!(
pub enum Test {

2264
pallets/networks/src/tests.rs Executable file → Normal file

File diff suppressed because it is too large Load Diff

383
pallets/networks/src/weights.rs Executable file → Normal file
View File

@ -7,7 +7,7 @@
// Ghost Network 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
// 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
@ -15,14 +15,14 @@
//! Autogenerated weights for `ghost_networks`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2025-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `ghost`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("casper-dev"), DB CACHE: 1024
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
// Executed Command:
// ./target/production/ghost
// ./target/release/ghost
// benchmark
// pallet
// --chain=casper-dev
@ -30,8 +30,8 @@
// --repeat=20
// --pallet=ghost_networks
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --heap-pages=4096
// --header=./file_header.txt
// --output=./runtime/casper/src/weights/ghost_networks.rs
@ -49,11 +49,12 @@ use sp_std::marker::PhantomData;
/// Weight functions needed for ghost_networks
pub trait WeightInfo {
fn register_network(n: u32, m: u32, ) -> Weight;
fn register_network(i: u32, j: u32, k: u32, ) -> Weight;
fn update_network_name(n: u32, ) -> Weight;
fn update_network_endpoint(n: u32, ) -> Weight;
fn update_network_finality_delay() -> Weight;
fn update_network_release_delay() -> Weight;
fn update_network_rate_limit_delay() -> Weight;
fn update_network_block_distance() -> Weight;
fn update_network_type() -> Weight;
fn update_network_gatekeeper() -> Weight;
fn update_network_topic_name() -> Weight;
@ -65,260 +66,316 @@ pub trait WeightInfo {
/// Weight for ghost_networks using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// The range of component `n` is `[1, 20]`.
/// The range of component `m` is `[1, 150]`.
fn register_network(_n: u32, _m: u32, ) -> Weight {
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `i` is `[1, 20]`.
/// The range of component `j` is `[1, 150]`.
/// The range of component `k` is `[1, 20]`.
fn register_network(_i: u32, _j: u32, k: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `76`
// Estimated: `2551`
// Minimum execution time: 32_086 nanoseconds.
Weight::from_parts(33_092_855, 2551)
// Measured: `109`
// Estimated: `3574`
// Minimum execution time: 46_023_000 picoseconds.
Weight::from_parts(97_871_287, 0)
.saturating_add(Weight::from_parts(0, 3574))
// Standard Error: 94_524
.saturating_add(Weight::from_parts(940_486, 0).saturating_mul(k.into()))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `n` is `[1, 20]`.
fn update_network_name(_n: u32, ) -> Weight {
fn update_network_name(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_496 nanoseconds.
Weight::from_parts(35_728_230, 2616)
// Standard Error: 2_591
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_906_000 picoseconds.
Weight::from_parts(55_537_587, 0)
.saturating_add(Weight::from_parts(0, 3767))
// Standard Error: 87_704
.saturating_add(Weight::from_parts(92_366, 0).saturating_mul(n.into()))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `n` is `[1, 150]`.
fn update_network_endpoint(_n: u32, ) -> Weight {
fn update_network_endpoint(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_666 nanoseconds.
Weight::from_parts(35_959_961, 2616)
// Standard Error: 381
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 50_556_000 picoseconds.
Weight::from_parts(57_726_674, 0)
.saturating_add(Weight::from_parts(0, 3767))
// Standard Error: 12_261
.saturating_add(Weight::from_parts(274, 0).saturating_mul(n.into()))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_finality_delay() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 33_860 nanoseconds.
Weight::from_parts(34_995_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_406_000 picoseconds.
Weight::from_parts(51_256_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
fn update_network_release_delay() -> Weight {
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_rate_limit_delay() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 33_860 nanoseconds.
Weight::from_parts(34_995_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_572_000 picoseconds.
Weight::from_parts(52_584_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_block_distance() -> Weight {
// Proof Size summary in bytes:
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 48_880_000 picoseconds.
Weight::from_parts(50_596_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_type() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_976 nanoseconds.
Weight::from_parts(36_182_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 48_282_000 picoseconds.
Weight::from_parts(49_137_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_gatekeeper() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_768 nanoseconds.
Weight::from_parts(35_580_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 50_853_000 picoseconds.
Weight::from_parts(51_982_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_topic_name() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_768 nanoseconds.
Weight::from_parts(35_580_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 50_343_000 picoseconds.
Weight::from_parts(52_380_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_incoming_network_fee() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_768 nanoseconds.
Weight::from_parts(35_580_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_393_000 picoseconds.
Weight::from_parts(80_966_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_outgoing_network_fee() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_768 nanoseconds.
Weight::from_parts(35_580_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_579_000 picoseconds.
Weight::from_parts(51_126_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn remove_network() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 33_336 nanoseconds.
Weight::from_parts(34_609_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 44_634_000 picoseconds.
Weight::from_parts(45_815_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
}
impl WeightInfo for () {
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// The range of component `n` is `[1, 20]`.
/// The range of component `m` is `[1, 150]`.
fn register_network(_n: u32, _m: u32, ) -> Weight {
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `i` is `[1, 20]`.
/// The range of component `j` is `[1, 150]`.
/// The range of component `k` is `[1, 20]`.
fn register_network(_i: u32, _j: u32, k: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `76`
// Estimated: `2551`
// Minimum execution time: 32_086 nanoseconds.
Weight::from_parts(33_092_855, 2551)
// Measured: `109`
// Estimated: `3574`
// Minimum execution time: 46_023_000 picoseconds.
Weight::from_parts(97_871_287, 0)
.saturating_add(Weight::from_parts(0, 3574))
// Standard Error: 94_524
.saturating_add(Weight::from_parts(940_486, 0).saturating_mul(k.into()))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `n` is `[1, 20]`.
fn update_network_name(_n: u32, ) -> Weight {
fn update_network_name(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_496 nanoseconds.
Weight::from_parts(35_728_230, 2616)
// Standard Error: 2_591
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_906_000 picoseconds.
Weight::from_parts(55_537_587, 0)
.saturating_add(Weight::from_parts(0, 3767))
// Standard Error: 87_704
.saturating_add(Weight::from_parts(92_366, 0).saturating_mul(n.into()))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `n` is `[1, 150]`.
fn update_network_endpoint(_n: u32, ) -> Weight {
fn update_network_endpoint(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_666 nanoseconds.
Weight::from_parts(35_959_961, 2616)
// Standard Error: 381
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 50_556_000 picoseconds.
Weight::from_parts(57_726_674, 0)
.saturating_add(Weight::from_parts(0, 3767))
// Standard Error: 12_261
.saturating_add(Weight::from_parts(274, 0).saturating_mul(n.into()))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_finality_delay() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 33_860 nanoseconds.
Weight::from_parts(34_995_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_406_000 picoseconds.
Weight::from_parts(51_256_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
fn update_network_release_delay() -> Weight {
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_rate_limit_delay() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 33_860 nanoseconds.
Weight::from_parts(34_995_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_572_000 picoseconds.
Weight::from_parts(52_584_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_block_distance() -> Weight {
// Proof Size summary in bytes:
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 48_880_000 picoseconds.
Weight::from_parts(50_596_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_type() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_976 nanoseconds.
Weight::from_parts(36_182_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 48_282_000 picoseconds.
Weight::from_parts(49_137_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_gatekeeper() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_768 nanoseconds.
Weight::from_parts(35_580_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 50_853_000 picoseconds.
Weight::from_parts(51_982_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_topic_name() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_768 nanoseconds.
Weight::from_parts(35_580_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 50_343_000 picoseconds.
Weight::from_parts(52_380_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_incoming_network_fee() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_768 nanoseconds.
Weight::from_parts(35_580_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_393_000 picoseconds.
Weight::from_parts(80_966_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_outgoing_network_fee() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 34_768 nanoseconds.
Weight::from_parts(35_580_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_579_000 picoseconds.
Weight::from_parts(51_126_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: GhostNetworks Networks (r:1 w:1)
/// Proof Skipped: GhostNetworks Networks (max_values: None, max_size: None, mode: Measured)
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn remove_network() -> Weight {
// Proof Size summary in bytes:
// Measured: `141`
// Estimated: `2616`
// Minimum execution time: 33_336 nanoseconds.
Weight::from_parts(34_609_000, 2616)
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 44_634_000 picoseconds.
Weight::from_parts(45_815_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}

9
pallets/slow-clap/Cargo.toml Executable file → Normal file
View File

@ -1,6 +1,6 @@
[package]
name = "ghost-slow-clap"
version = "0.3.14"
version = "0.3.40"
description = "Applause protocol for the EVM bridge"
license.workspace = true
authors.workspace = true
@ -27,11 +27,13 @@ sp-staking = { workspace = true }
sp-io = { workspace = true }
sp-std = { workspace = true }
pallet-balances = { workspace = true }
ghost-networks = { workspace = true }
[dev-dependencies]
pallet-session = { workspace = true, default-features = true }
pallet-balances = { workspace = true }
pallet-session = { workspace = true }
pallet-staking = { workspace = true }
pallet-staking-reward-curve = { workspace = true }
[features]
default = ["std"]
@ -49,6 +51,7 @@ std = [
"sp-io/std",
"sp-std/std",
"pallet-session/std",
"pallet-staking/std",
"pallet-balances/std",
"ghost-networks/std",
]

View File

@ -3,13 +3,8 @@
use super::*;
use frame_benchmarking::v1::*;
use frame_support::traits::fungible::Inspect;
use frame_system::RawOrigin;
use frame_support::traits::fungible::{Inspect, Mutate};
use crate::Pallet as SlowClap;
const MAX_CLAPS: u32 = 100;
const MAX_COMPANIONS: u32 = 20;
pub fn create_account<T: Config>() -> T::AccountId {
let account_bytes = Vec::from([1u8; 32]);
@ -17,184 +12,89 @@ pub fn create_account<T: Config>() -> T::AccountId {
.expect("32 bytes always construct an AccountId32")
}
pub fn create_companions<T: Config>(
total: usize,
network_id: NetworkIdOf<T>,
user_account: T::AccountId,
fee: H256,
receiver: H160,
) -> Result<CompanionId, &'static str> {
T::NetworkDataHandler::register(network_id.into(), NetworkData {
chain_name: "Ethereum".into(),
default_endpoint:
"https://base-mainnet.core.chainstack.com/2fc1de7f08c0465f6a28e3c355e0cb14/".into(),
finality_delay: Some(0),
release_delay: Some(0),
network_type: Default::default(),
gatekeeper: b"0x1234567891234567891234567891234567891234".to_vec(),
topic_name: b"0x12345678912345678912345678912345678912345678912345678912345678".to_vec(),
incoming_fee: 0,
outgoing_fee: 0,
}).map_err(|_| BenchmarkError::Weightless)?;
let mut last_companion_id = 0;
for _ in 0..total {
let minimum_balance = <<T as pallet::Config>::Currency>::minimum_balance();
let balance = minimum_balance + minimum_balance;
let companion = Companion::<NetworkIdOf::<T>, BalanceOf::<T>> {
network_id: network_id.into(), receiver,
fee, amount: balance,
};
let _ = <<T as pallet::Config>::Currency>::mint_into(&user_account, balance);
let companion_id = SlowClap::<T>::current_companion_id();
let _ = SlowClap::<T>::propose_companion(
RawOrigin::Signed(user_account.clone()).into(),
network_id,
companion,
)?;
last_companion_id = companion_id;
}
Ok(last_companion_id)
}
pub fn create_claps<T: Config>(i: u32, j: u32) -> Result<
(
Vec<crate::Clap<T::AccountId, NetworkIdOf<T>, BalanceOf<T>>>,
<T::AuthorityId as RuntimeAppPublic>::Signature,
),
&'static str,
> {
let minimum_balance = <<T as pallet::Config>::Currency>::minimum_balance();
let amount = minimum_balance + minimum_balance;
let total_amount = amount.saturating_mul(j.into());
let network_id = NetworkIdOf::<T>::default();
let mut claps = Vec::new();
let mut companions = BTreeMap::new();
let authorities = vec![T::AuthorityId::generate_pair(None)];
let bounded_authorities =
WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.clone())
.map_err(|()| "more than the maximum number of keys provided")?;
Authorities::<T>::put(bounded_authorities);
for index in 0..j {
companions.insert(
index.into(),
amount,
);
}
for _ in 0..i {
claps.push(Clap {
session_index: 1,
authority_index: 0,
network_id,
transaction_hash: H256::repeat_byte(1u8),
block_number: 69,
removed: true,
receiver: create_account::<T>(),
amount: total_amount,
companions: companions.clone(),
});
}
let authority_id = authorities
.get(0usize)
.expect("first authority should exist");
let encoded_claps = claps.encode();
let signature = authority_id.sign(&encoded_claps)
.ok_or("couldn't make signature")?;
Ok((claps, signature))
}
benchmarks! {
slow_clap {
let k in 1 .. MAX_CLAPS;
let j in 1 .. MAX_COMPANIONS;
let receiver = H160::repeat_byte(69u8);
let fee = H256::repeat_byte(0u8);
let user_account: T::AccountId = whitelisted_caller();
let network_id = <<T as pallet::Config>::NetworkDataHandler as NetworkDataBasicHandler>::NetworkId::default();
let (claps, signature) = create_claps::<T>(k, j)?;
let _ = create_companions::<T>(j as usize, network_id, user_account, fee, receiver)?;
}: _(RawOrigin::None, claps, signature)
verify {
let minimum_balance = <<T as pallet::Config>::Currency>::minimum_balance();
let total_amount = (minimum_balance + minimum_balance).saturating_mul(j.into());
}
let receiver = create_account::<T>();
let amount = minimum_balance + minimum_balance;
let network_id = NetworkIdOf::<T>::default();
let session_index = T::ValidatorSet::session_index();
propose_companion {
let receiver = H160::repeat_byte(69u8);
let fee = H256::repeat_byte(0u8);
let user_account: T::AccountId = whitelisted_caller();
let network_id = <<T as pallet::Config>::NetworkDataHandler as NetworkDataBasicHandler>::NetworkId::default();
// T::NetworkDataHandler::register(network_id.into(), NetworkData {
// chain_name: "Ethereum".into(),
// // https://nd-422-757-666.p2pify.com/0a9d79d93fb2f4a4b1e04695da2b77a7/
// default_endpoint:
// "https://base-mainnet.core.chainstack.com/2fc1de7f08c0465f6a28e3c355e0cb14/".into(),
// finality_delay: Some(50),
// release_delay: Some(100),
// network_type: Default::default(),
// gatekeeper: b"0x1234567891234567891234567891234567891234".to_vec(),
// topic_name: b"0x12345678912345678912345678912345678912345678912345678912345678".to_vec(),
// incoming_fee: 0,
// outgoing_fee: 0,
// }).map_err(|_| BenchmarkError::Weightless)?;
let companion_id = create_companions::<T>(1, network_id, user_account.clone(), fee, receiver)?;
let companion_id = SlowClap::<T>::current_companion_id();
let minimum_balance = <<T as pallet::Config>::Currency>::minimum_balance();
let balance = minimum_balance + minimum_balance;
let companion = Companion::<NetworkIdOf::<T>, BalanceOf::<T>> {
network_id: network_id.into(), receiver,
fee, amount: balance,
let authorities = vec![T::AuthorityId::generate_pair(None)];
let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.clone())
.map_err(|()| "more than the maximum number of keys provided")?;
Authorities::<T>::set(&session_index, bounded_authorities);
let clap = Clap {
session_index: 0,
authority_index: 0,
transaction_hash: H256::repeat_byte(1u8),
block_number: 69,
removed: false,
network_id,
receiver: receiver.clone(),
amount,
};
let _ = <<T as pallet::Config>::Currency>::mint_into(&user_account, balance);
assert_eq!(SlowClap::<T>::current_companion_id(), companion_id);
}: _(RawOrigin::Signed(user_account), network_id.into(), companion)
let authority_id = authorities
.get(0usize)
.expect("first authority should exist");
let encoded_clap = clap.encode();
let signature = authority_id.sign(&encoded_clap)
.ok_or("couldn't make signature")?;
}: _(RawOrigin::None, clap, signature)
verify {
assert_eq!(SlowClap::<T>::current_companion_id(), companion_id + 1);
assert_eq!(<<T as pallet::Config>::Currency>::total_balance(&receiver), amount);
}
release_companion {
let receiver = H160::repeat_byte(69u8);
let fee = H256::repeat_byte(0u8);
let user_account: T::AccountId = whitelisted_caller();
let network_id = <<T as pallet::Config>::NetworkDataHandler as NetworkDataBasicHandler>::NetworkId::default();
let companion_id = create_companions::<T>(1, network_id, user_account.clone(), fee, receiver)?;
assert_eq!(SlowClap::<T>::release_blocks(companion_id), BlockNumberFor::<T>::default());
}: _(RawOrigin::Signed(user_account), network_id.into(), companion_id)
verify {
assert_ne!(SlowClap::<T>::release_blocks(companion_id), BlockNumberFor::<T>::default());
}
self_applause {
let session_index = T::ValidatorSet::session_index();
let authorities = vec![T::AuthorityId::generate_pair(None)];
let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.clone())
.map_err(|()| "more than the maximum number of keys provided")?;
Authorities::<T>::set(&session_index, bounded_authorities);
kill_companion {
let receiver = H160::repeat_byte(69u8);
let fee = H256::repeat_byte(0u8);
let user_account: T::AccountId = whitelisted_caller();
let network_id = <<T as pallet::Config>::NetworkDataHandler as NetworkDataBasicHandler>::NetworkId::default();
let companion_id = create_companions::<T>(1, network_id, user_account.clone(), fee, receiver)?;
SlowClap::<T>::release_companion(
RawOrigin::Signed(user_account.clone()).into(),
network_id,
companion_id,
)?;
let block_shift =
<<T as pallet::Config>::NetworkDataHandler as NetworkDataInspectHandler<NetworkData>>::get(&network_id)
.unwrap()
.release_delay
.unwrap();
frame_system::Pallet::<T>::set_block_number((block_shift + 1).saturated_into());
}: _(RawOrigin::Signed(user_account), network_id.into(), companion_id)
let minimum_balance = <<T as pallet::Config>::Currency>::minimum_balance();
let receiver = create_account::<T>();
let receiver_clone = receiver.clone();
let amount = minimum_balance + minimum_balance;
let network_id = NetworkIdOf::<T>::default();
let transaction_hash = H256::repeat_byte(1u8);
let unique_transaction_hash = <Pallet<T>>::generate_unique_hash(
&receiver,
&amount,
&network_id,
);
let storage_key = (session_index, &transaction_hash, &unique_transaction_hash);
<Pallet::<T>>::trigger_nullification_for_benchmark();
let clap = Clap {
session_index,
authority_index: 0,
transaction_hash,
block_number: 69,
removed: false,
network_id,
receiver: receiver.clone(),
amount,
};
let authority_id = authorities
.get(0usize)
.expect("first authority should exist");
let encoded_clap = clap.encode();
let signature = authority_id.sign(&encoded_clap).unwrap();
<Pallet<T>>::slow_clap(RawOrigin::None.into(), clap, signature)?;
<Pallet::<T>>::trigger_nullification_for_benchmark();
assert_eq!(<<T as pallet::Config>::Currency>::total_balance(&receiver), Default::default());
assert_eq!(ApplausesForTransaction::<T>::get(&storage_key), false);
}: _(RawOrigin::Signed(receiver_clone), network_id, session_index, transaction_hash, receiver_clone.clone(), amount)
verify {
assert_eq!(SlowClap::<T>::companions(network_id, companion_id), None);
assert_eq!(SlowClap::<T>::companion_details(companion_id), None);
assert_eq!(SlowClap::<T>::current_companion_id(), companion_id + 1);
assert_eq!(<<T as pallet::Config>::Currency>::total_balance(&receiver), amount);
assert_eq!(ApplausesForTransaction::<T>::get(&storage_key), true);
}
impl_benchmark_test_suite!(

View File

@ -0,0 +1,57 @@
use crate::{Deserialize, Deserializer, Vec, H256};
pub fn de_string_to_bytes<'de, D>(de: D) -> Result<Option<Vec<u8>>, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(de)?;
Ok(Some(s.as_bytes().to_vec()))
}
pub fn de_string_to_u64<'de, D>(de: D) -> Result<Option<u64>, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(de)?;
let s = if s.starts_with("0x") { &s[2..] } else { &s };
Ok(u64::from_str_radix(s, 16).ok())
}
pub fn de_string_to_u64_pure<'de, D>(de: D) -> Result<u64, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(de)?;
let s = if s.starts_with("0x") { &s[2..] } else { &s };
Ok(u64::from_str_radix(s, 16).unwrap_or_default())
}
pub fn de_string_to_h256<'de, D>(de: D) -> Result<Option<H256>, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(de)?;
let start_index = if s.starts_with("0x") { 2 } else { 0 };
let h256: Vec<_> = (start_index..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid u8 symbol; qed"))
.collect();
Ok(Some(H256::from_slice(&h256)))
}
pub fn de_string_to_vec_of_bytes<'de, D>(de: D) -> Result<Vec<Vec<u8>>, D::Error>
where
D: Deserializer<'de>,
{
let strings: Vec<&str> = Deserialize::deserialize(de)?;
Ok(strings
.iter()
.map(|s| {
let start_index = if s.starts_with("0x") { 2 } else { 0 };
(start_index..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid u8 symbol; qed"))
.collect::<Vec<u8>>()
})
.collect::<Vec<Vec<u8>>>())
}

View File

@ -0,0 +1,49 @@
use crate::{
deserialisations::{
de_string_to_bytes, de_string_to_h256, de_string_to_u64, de_string_to_u64_pure,
de_string_to_vec_of_bytes,
},
Decode, Deserialize, Encode, RuntimeDebug, Vec, H256,
};
const NUMBER_OF_TOPICS: usize = 3;
#[derive(RuntimeDebug, Clone, PartialEq, Deserialize, Encode, Decode)]
pub struct EvmResponse {
#[serde(default)]
id: Option<u32>,
#[serde(default, deserialize_with = "de_string_to_bytes")]
jsonrpc: Option<Vec<u8>>,
#[serde(default, deserialize_with = "de_string_to_bytes")]
pub error: Option<Vec<u8>>,
#[serde(default)]
pub result: Option<EvmResponseType>,
}
#[derive(RuntimeDebug, Clone, PartialEq, Deserialize, Encode, Decode)]
#[serde(untagged)]
pub enum EvmResponseType {
#[serde(deserialize_with = "de_string_to_u64_pure")]
BlockNumber(u64),
TransactionLogs(Vec<Log>),
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize, Encode, Decode)]
#[serde(rename_all = "camelCase")]
pub struct Log {
#[serde(default, deserialize_with = "de_string_to_h256")]
pub transaction_hash: Option<H256>,
#[serde(default, deserialize_with = "de_string_to_u64")]
pub block_number: Option<u64>,
#[serde(default, deserialize_with = "de_string_to_vec_of_bytes")]
pub topics: Vec<Vec<u8>>,
pub removed: bool,
}
impl Log {
pub fn is_sufficient(&self) -> bool {
self.transaction_hash.is_some()
&& self.block_number.is_some()
&& self.topics.len() == NUMBER_OF_TOPICS
}
}

1577
pallets/slow-clap/src/lib.rs Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,20 +4,22 @@ use frame_support::{
derive_impl, parameter_types,
traits::{ConstU32, ConstU64},
weights::Weight,
PalletId,
};
use frame_system::EnsureRoot;
use pallet_session::historical as pallet_session_historical;
use sp_runtime::{
curve::PiecewiseLinear,
testing::{TestXt, UintAuthorityId},
traits::ConvertInto,
BuildStorage, Permill,
Permill,
};
use sp_staking::{
offence::{OffenceError, ReportOffence},
SessionIndex,
};
use sp_runtime::BuildStorage;
use crate as slow_clap;
use crate::Config;
@ -36,8 +38,8 @@ frame_support::construct_runtime!(
parameter_types! {
pub static Validators: Option<Vec<u64>> = Some(vec![
1,
2,
1,
2,
3,
]);
}
@ -53,13 +55,10 @@ impl pallet_session::SessionManager<u64> for TestSessionManager {
impl pallet_session::historical::SessionManager<u64, u64> for TestSessionManager {
fn new_session(_new_index: SessionIndex) -> Option<Vec<(u64, u64)>> {
Validators::mutate(|l| l
.take()
.map(|validators| validators
.iter()
.map(|v| (*v, *v))
.collect())
)
Validators::mutate(|l| {
l.take()
.map(|validators| validators.iter().map(|v| (*v, *v)).collect())
})
}
fn end_session(_: SessionIndex) {}
fn start_session(_: SessionIndex) {}
@ -84,24 +83,21 @@ impl ReportOffence<u64, IdentificationTuple, Offence> for OffenceHandler {
}
}
pub fn alice_account_id() -> <Runtime as frame_system::Config>::AccountId { 69 }
pub fn eve_account_id() -> <Runtime as frame_system::Config>::AccountId { 1337 }
pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::<Runtime>::default()
let t = frame_system::GenesisConfig::<Runtime>::default()
.build_storage()
.unwrap();
pallet_balances::GenesisConfig::<Runtime> {
balances: vec![ (alice_account_id(), 100) ],
}
.assimilate_storage(&mut t)
.unwrap();
let mut result = sp_io::TestExternalities::new(t);
result.execute_with(|| {
System::set_block_number(1);
for i in 1..=3 {
System::inc_providers(&i);
assert_eq!(
Session::set_keys(RuntimeOrigin::signed(i), i.into(), vec![],),
Ok(())
);
}
});
result
@ -152,7 +148,7 @@ impl frame_support::traits::EstimateNextSessionRotation<u64> for TestNextSession
}
fn estimate_current_session_progress(now: u64) -> (Option<Permill>, Weight) {
let (estimate, weight) =
let (estimate, weight) =
pallet_session::PeriodicSessions::<Period, Offset>::estimate_current_session_progress(
now,
);
@ -167,6 +163,7 @@ impl frame_support::traits::EstimateNextSessionRotation<u64> for TestNextSession
impl ghost_networks::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type NetworkId = u32;
type RegisterOrigin = EnsureRoot<Self::AccountId>;
type UpdateOrigin = EnsureRoot<Self::AccountId>;
@ -174,9 +171,21 @@ impl ghost_networks::Config for Runtime {
type WeightInfo = ();
}
pallet_staking_reward_curve::build! {
const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
min_inflation: 0_006_000,
max_inflation: 1_000_000,
ideal_stake: 0_690_000,
falloff: 0_050_000,
max_piece_count: 100,
test_precision: 0_005_000,
);
}
parameter_types! {
pub static ExistentialDeposit: u64 = 2;
pub const TreasuryPalletId: PalletId = PalletId(*b"mck/test");
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
pub const HistoryDepth: u32 = 10;
}
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
@ -199,23 +208,16 @@ impl Config for Runtime {
type ReportUnresponsiveness = OffenceHandler;
type MaxAuthorities = ConstU32<5>;
type MaxNumberOfClaps = ConstU32<100>;
type ApplauseThreshold = ConstU32<0>;
type MaxAuthorityInfoInSession = ConstU32<5_000>;
type OffenceThreshold = ConstU32<40>;
type ApplauseThreshold = ConstU32<50>;
type OffenceThreshold = ConstU32<75>;
type UnsignedPriority = ConstU64<{ 1 << 20 }>;
type TreasuryPalletId = TreasuryPalletId;
type HistoryDepth = HistoryDepth;
type WeightInfo = ();
}
pub type Extrinsic = TestXt<RuntimeCall, ()>;
// impl frame_system::offchain::SigningTypes for Runtime {
// type Public = <Signature as Verify>::Signer;
// type Signature = Signature;
// }
impl<LocalCall> frame_system::offchain::SendTransactionTypes<LocalCall> for Runtime
where
RuntimeCall: From<LocalCall>,
@ -224,30 +226,36 @@ where
type Extrinsic = Extrinsic;
}
// impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
// where
// RuntimeCall: From<LocalCall>,
// {
// fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
// call: Self::OverarchingCall,
// _public: Self::Public,
// _account: Self::AccountId,
// nonce: Self::Nonce,
// ) -> Option<(RuntimeCall, <Extrinsic as ExtrinsicT>::SignaturePayload)> {
// Some((call, (nonce.into(), ())))
// }
// }
pub fn advance_session() {
let now = System::block_number().max(1);
System::set_block_number(now + 1);
Session::rotate_session();
let session_index = Session::current_index();
// pub fn advance_session() {
// let now = System::block_number().max(1);
// System::set_block_number(now + 1);
// Session::rotate_session();
//
// let authorities = Session::validators()
// .into_iter()
// .map(UintAuthorityId)
// .collect();
//
// SlowClap::set_authorities(authorities);
// assert_eq!(Session::current_index(), (now / Period::get()) as u32);
// }
let authorities = Session::validators()
.into_iter()
.map(UintAuthorityId)
.collect();
SlowClap::set_test_authorities(session_index, authorities);
assert_eq!(session_index, (now / Period::get()) as u32);
}
pub fn advance_session_with_authority(authority: u64) {
let now = System::block_number().max(1);
System::set_block_number(now + 1);
Session::rotate_session();
let session_index = Session::current_index();
SlowClap::set_test_authorities(
session_index,
vec![
UintAuthorityId::from(authority),
UintAuthorityId::from(69),
UintAuthorityId::from(420),
UintAuthorityId::from(1337),
],
);
assert_eq!(session_index, (now / Period::get()) as u32);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,176 @@
use frame_support::weights::Weight;
// This file is part of Ghost Network.
// Ghost Network 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.
// Ghost Network 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 Ghost Network. If not, see <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `ghost_slow_clap`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2025-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
// Executed Command:
// ./target/release/ghost
// benchmark
// pallet
// --chain=casper-dev
// --steps=50
// --repeat=20
// --pallet=ghost_slow_clap
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --header=./file_header.txt
// --output=./runtime/casper/src/weights/ghost_slow_clap.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
use frame_support::{
traits::Get,
weights::{Weight, constants::RocksDbWeight}
};
use core::marker::PhantomData;
pub trait WeightInfo {
fn slow_clap(claps_len: u32, companions_len: u32) -> Weight;
fn propose_companion() -> Weight;
fn release_companion() -> Weight;
fn kill_companion() -> Weight;
fn slow_clap() -> Weight;
fn self_applause()-> Weight;
}
/// Weight functions for `ghost_slow_clap`.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: `GhostSlowClaps::Authorities` (r:1 w:0)
/// Proof: `GhostSlowClaps::Authorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ReceivedClaps` (r:1 w:1)
/// Proof: `GhostSlowClaps::ReceivedClaps` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ClapsInSession` (r:1 w:1)
/// Proof: `GhostSlowClaps::ClapsInSession` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ApplausesForTransaction` (r:1 w:1)
/// Proof: `GhostSlowClaps::ApplausesForTransaction` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NullifyNeeded` (r:1 w:0)
/// Proof: `GhostNetworks::NullifyNeeded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::GatekeeperAmount` (r:1 w:1)
/// Proof: `GhostNetworks::GatekeeperAmount` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::BridgedImbalance` (r:1 w:1)
/// Proof: `GhostNetworks::BridgedImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::AccumulatedCommission` (r:1 w:1)
/// Proof: `GhostNetworks::AccumulatedCommission` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
fn slow_clap() -> Weight {
// Proof Size summary in bytes:
// Measured: `355`
// Estimated: `3820`
// Minimum execution time: 213_817_000 picoseconds.
Weight::from_parts(216_977_000, 0)
.saturating_add(Weight::from_parts(0, 3820))
.saturating_add(T::DbWeight::get().reads(10))
.saturating_add(T::DbWeight::get().writes(7))
}
/// Storage: `GhostSlowClaps::ReceivedClaps` (r:1 w:0)
/// Proof: `GhostSlowClaps::ReceivedClaps` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::Authorities` (r:1 w:0)
/// Proof: `GhostSlowClaps::Authorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ApplausesForTransaction` (r:1 w:1)
/// Proof: `GhostSlowClaps::ApplausesForTransaction` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NullifyNeeded` (r:1 w:0)
/// Proof: `GhostNetworks::NullifyNeeded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::GatekeeperAmount` (r:1 w:1)
/// Proof: `GhostNetworks::GatekeeperAmount` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::BridgedImbalance` (r:1 w:1)
/// Proof: `GhostNetworks::BridgedImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::AccumulatedCommission` (r:1 w:1)
/// Proof: `GhostNetworks::AccumulatedCommission` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
fn self_applause() -> Weight {
// Proof Size summary in bytes:
// Measured: `655`
// Estimated: `4120`
// Minimum execution time: 210_676_000 picoseconds.
Weight::from_parts(212_905_000, 0)
.saturating_add(Weight::from_parts(0, 4120))
.saturating_add(T::DbWeight::get().reads(9))
.saturating_add(T::DbWeight::get().writes(5))
}
}
impl WeightInfo for () {
fn slow_clap(
_claps_len: u32,
_companions_len: u32,
) -> Weight { Weight::zero() }
fn propose_companion() -> Weight { Weight::zero() }
fn release_companion() -> Weight { Weight::zero() }
fn kill_companion() -> Weight { Weight::zero() }
/// Storage: `GhostSlowClaps::Authorities` (r:1 w:0)
/// Proof: `GhostSlowClaps::Authorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ReceivedClaps` (r:1 w:1)
/// Proof: `GhostSlowClaps::ReceivedClaps` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ClapsInSession` (r:1 w:1)
/// Proof: `GhostSlowClaps::ClapsInSession` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ApplausesForTransaction` (r:1 w:1)
/// Proof: `GhostSlowClaps::ApplausesForTransaction` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NullifyNeeded` (r:1 w:0)
/// Proof: `GhostNetworks::NullifyNeeded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::GatekeeperAmount` (r:1 w:1)
/// Proof: `GhostNetworks::GatekeeperAmount` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::BridgedImbalance` (r:1 w:1)
/// Proof: `GhostNetworks::BridgedImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::AccumulatedCommission` (r:1 w:1)
/// Proof: `GhostNetworks::AccumulatedCommission` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
fn slow_clap() -> Weight {
// Proof Size summary in bytes:
// Measured: `355`
// Estimated: `3820`
// Minimum execution time: 213_817_000 picoseconds.
Weight::from_parts(216_977_000, 0)
.saturating_add(Weight::from_parts(0, 3820))
.saturating_add(RocksDbWeight::get().reads(10))
.saturating_add(RocksDbWeight::get().writes(7))
}
/// Storage: `GhostSlowClaps::ReceivedClaps` (r:1 w:0)
/// Proof: `GhostSlowClaps::ReceivedClaps` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::Authorities` (r:1 w:0)
/// Proof: `GhostSlowClaps::Authorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ApplausesForTransaction` (r:1 w:1)
/// Proof: `GhostSlowClaps::ApplausesForTransaction` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NullifyNeeded` (r:1 w:0)
/// Proof: `GhostNetworks::NullifyNeeded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::GatekeeperAmount` (r:1 w:1)
/// Proof: `GhostNetworks::GatekeeperAmount` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::BridgedImbalance` (r:1 w:1)
/// Proof: `GhostNetworks::BridgedImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::AccumulatedCommission` (r:1 w:1)
/// Proof: `GhostNetworks::AccumulatedCommission` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
fn self_applause() -> Weight {
// Proof Size summary in bytes:
// Measured: `655`
// Estimated: `4120`
// Minimum execution time: 210_676_000 picoseconds.
Weight::from_parts(212_905_000, 0)
.saturating_add(Weight::from_parts(0, 4120))
.saturating_add(RocksDbWeight::get().reads(9))
.saturating_add(RocksDbWeight::get().writes(5))
}
}

45
pallets/sudo/Cargo.toml Normal file
View File

@ -0,0 +1,45 @@
[package]
name = "ghost-sudo"
version = "0.0.2"
description = "Port of the sudo pallet because of dependencies issue"
license.workspace = true
authors.workspace = true
edition.workspace = true
homepage.workspace = true
repository.workspace = true
[dependencies]
docify = "0.2.8"
codec = { workspace = true, features = ["derive"] }
frame-benchmarking = { workspace = true, optional = true }
scale-info = { workspace = true, features = ["derive"] }
frame-support = { workspace = true }
frame-system = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
[features]
default = ["std"]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"sp-runtime/try-runtime",
]

View File

@ -0,0 +1,77 @@
use super::*;
use crate::Pallet;
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;
fn assert_last_event<T: Config>(generic_event: crate::Event<T>) {
let re: <T as Config>::RuntimeEvent = generic_event.into();
frame_system::Pallet::<T>::assert_last_event(re.into());
}
#[benchmarks(where <T as Config>::RuntimeCall: From<frame_system::Call<T>>)]
mod benchmarks {
use super::*;
#[benchmark]
fn set_key() {
let caller: T::AccountId = whitelisted_caller();
Key::<T>::put(&caller);
let new_sudoer: T::AccountId = account("sudoer", 0, 0);
let new_sudoer_lookup = T::Lookup::unlookup(new_sudoer.clone());
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), new_sudoer_lookup);
assert_last_event::<T>(Event::KeyChanged {
old: Some(caller),
new: new_sudoer,
});
}
#[benchmark]
fn sudo() {
let caller: T::AccountId = whitelisted_caller();
Key::<T>::put(&caller);
let call = frame_system::Call::remark { remark: vec![] }.into();
#[extrinsic_call]
_(RawOrigin::Signed(caller), Box::new(call));
assert_last_event::<T>(Event::Sudid {
sudo_result: Ok(()),
})
}
#[benchmark]
fn sudo_as() {
let caller: T::AccountId = whitelisted_caller();
Key::<T>::put(caller.clone());
let call = frame_system::Call::remark { remark: vec![] }.into();
let who: T::AccountId = account("as", 0, 0);
let who_lookup = T::Lookup::unlookup(who);
#[extrinsic_call]
_(RawOrigin::Signed(caller), who_lookup, Box::new(call));
assert_last_event::<T>(Event::SudoAsDone {
sudo_result: Ok(()),
})
}
#[benchmark]
fn remove_key() {
let caller: T::AccountId = whitelisted_caller();
Key::<T>::put(&caller);
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()));
assert_last_event::<T>(Event::KeyRemoved {});
}
impl_benchmark_test_suite!(Pallet, crate::mock::new_bench_ext(), crate::mock::Test);
}

View File

@ -0,0 +1,82 @@
use crate::{Config, Key};
use codec::{Decode, Encode};
use frame_support::{dispatch::DispatchInfo, ensure};
use scale_info::TypeInfo;
use sp_runtime::{
traits::{DispatchInfoOf, Dispatchable, SignedExtension},
transaction_validity::{
InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,
UnknownTransaction, ValidTransaction,
},
};
use sp_std::{fmt, marker::PhantomData};
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct CheckOnlySudoAccount<T: Config + Send + Sync>(PhantomData<T>);
impl<T: Config + Send + Sync> Default for CheckOnlySudoAccount<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<T: Config + Send + Sync> fmt::Debug for CheckOnlySudoAccount<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "CheckOnlySudoAccount")
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
impl<T: Config + Send + Sync> CheckOnlySudoAccount<T> {
/// Creates new `SignedExtension` to check sudo key.
pub fn new() -> Self {
Self::default()
}
}
impl<T: Config + Send + Sync> SignedExtension for CheckOnlySudoAccount<T>
where
<T as Config>::RuntimeCall: Dispatchable<Info = DispatchInfo>,
{
const IDENTIFIER: &'static str = "CheckOnlySudoAccount";
type AccountId = T::AccountId;
type Call = <T as Config>::RuntimeCall;
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(())
}
fn validate(
&self,
who: &Self::AccountId,
_call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
let sudo_key: T::AccountId = Key::<T>::get().ok_or(UnknownTransaction::CannotLookup)?;
ensure!(*who == sudo_key, InvalidTransaction::BadSigner);
Ok(ValidTransaction {
priority: info.weight.ref_time() as TransactionPriority,
..Default::default()
})
}
fn pre_dispatch(
self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
self.validate(who, call, info, len).map(|_| ())
}
}

212
pallets/sudo/src/lib.rs Normal file
View File

@ -0,0 +1,212 @@
#![cfg_attr(not(feature = "std"), no_std)]
use sp_runtime::{traits::StaticLookup, DispatchResult};
use sp_std::prelude::*;
use frame_support::{dispatch::GetDispatchInfo, traits::UnfilteredDispatchable};
mod extension;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;
pub use weights::WeightInfo;
pub use extension::CheckOnlySudoAccount;
pub use pallet::*;
type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
#[frame_support::pallet]
pub mod pallet {
use super::{DispatchResult, *};
use frame_support::pallet_prelude::*;
use frame_system::{pallet_prelude::*, RawOrigin};
pub mod config_preludes {
use super::*;
use frame_support::derive_impl;
pub struct TestDefaultConfig;
#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
impl frame_system::DefaultConfig for TestDefaultConfig {}
#[frame_support::register_default_impl(TestDefaultConfig)]
impl DefaultConfig for TestDefaultConfig {
type WeightInfo = ();
#[inject_runtime_type]
type RuntimeEvent = ();
#[inject_runtime_type]
type RuntimeCall = ();
}
}
#[pallet::config(with_default)]
pub trait Config: frame_system::Config {
#[pallet::no_default_bounds]
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
#[pallet::no_default_bounds]
type RuntimeCall: Parameter
+ UnfilteredDispatchable<RuntimeOrigin = Self::RuntimeOrigin>
+ GetDispatchInfo;
type WeightInfo: WeightInfo;
}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight({
let dispatch_info = call.get_dispatch_info();
(
T::WeightInfo::sudo().saturating_add(dispatch_info.weight),
dispatch_info.class
)
})]
pub fn sudo(
origin: OriginFor<T>,
call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
let res = call.dispatch_bypass_filter(RawOrigin::Root.into());
Self::deposit_event(Event::Sudid {
sudo_result: res.map(|_| ()).map_err(|e| e.error),
});
Ok(Pays::No.into())
}
#[pallet::call_index(1)]
#[pallet::weight((*weight, call.get_dispatch_info().class))]
pub fn sudo_unchecked_weight(
origin: OriginFor<T>,
call: Box<<T as Config>::RuntimeCall>,
weight: Weight,
) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
let _ = weight;
let res = call.dispatch_bypass_filter(RawOrigin::Root.into());
Self::deposit_event(Event::Sudid {
sudo_result: res.map(|_| ()).map_err(|e| e.error),
});
Ok(Pays::No.into())
}
#[pallet::call_index(2)]
#[pallet::weight(T::WeightInfo::set_key())]
pub fn set_key(
origin: OriginFor<T>,
new: AccountIdLookupOf<T>,
) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
let new = T::Lookup::lookup(new)?;
Self::deposit_event(Event::KeyChanged {
old: Key::<T>::get(),
new: new.clone(),
});
Key::<T>::put(new);
Ok(Pays::No.into())
}
#[pallet::call_index(3)]
#[pallet::weight({
let dispatch_info = call.get_dispatch_info();
(
T::WeightInfo::sudo_as().saturating_add(dispatch_info.weight),
dispatch_info.class,
)
})]
pub fn sudo_as(
origin: OriginFor<T>,
who: AccountIdLookupOf<T>,
call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
let who = T::Lookup::lookup(who)?;
let res = call.dispatch_bypass_filter(RawOrigin::Signed(who).into());
Self::deposit_event(Event::SudoAsDone {
sudo_result: res.map(|_| ()).map_err(|e| e.error),
});
Ok(Pays::No.into())
}
#[pallet::call_index(4)]
#[pallet::weight(T::WeightInfo::remove_key())]
pub fn remove_key(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
Self::deposit_event(Event::KeyRemoved {});
Key::<T>::kill();
Ok(Pays::No.into())
}
}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
Sudid {
sudo_result: DispatchResult,
},
KeyChanged {
old: Option<T::AccountId>,
new: T::AccountId,
},
KeyRemoved,
SudoAsDone {
sudo_result: DispatchResult,
},
}
#[pallet::error]
pub enum Error<T> {
RequireSudo,
}
#[pallet::storage]
pub(super) type Key<T: Config> = StorageValue<_, T::AccountId, OptionQuery>;
#[pallet::genesis_config]
#[derive(frame_support::DefaultNoBound)]
pub struct GenesisConfig<T: Config> {
pub key: Option<T::AccountId>,
}
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
Key::<T>::set(self.key.clone());
}
}
impl<T: Config> Pallet<T> {
pub(crate) fn ensure_sudo(origin: OriginFor<T>) -> DispatchResult {
let sender = ensure_signed_or_root(origin)?;
if let Some(sender) = sender {
if Key::<T>::get().map_or(false, |k| k == sender) {
Ok(())
} else {
Err(Error::<T>::RequireSudo.into())
}
} else {
Ok(())
}
}
}
}

127
pallets/sudo/src/mock.rs Normal file
View File

@ -0,0 +1,127 @@
use super::*;
use crate as sudo;
use frame_support::derive_impl;
use sp_io;
use sp_runtime::BuildStorage;
#[frame_support::pallet]
pub mod logger {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(*weight)]
pub fn privileged_i32_log(
origin: OriginFor<T>,
i: i32,
weight: Weight,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
<I32Log<T>>::try_append(i).map_err(|_| "could not append")?;
Self::deposit_event(Event::AppendI32 { value: i, weight });
Ok(().into())
}
#[pallet::call_index(1)]
#[pallet::weight(*weight)]
pub fn non_privileged_log(
origin: OriginFor<T>,
i: i32,
weight: Weight,
) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;
<I32Log<T>>::try_append(i).map_err(|_| "could not append")?;
<AccountLog<T>>::try_append(sender.clone()).map_err(|_| "could not append")?;
Self::deposit_event(Event::AppendI32AndAccount {
sender,
value: i,
weight,
});
Ok(().into())
}
}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
AppendI32 {
value: i32,
weight: Weight,
},
AppendI32AndAccount {
sender: T::AccountId,
value: i32,
weight: Weight,
},
}
#[pallet::storage]
#[pallet::getter(fn account_log)]
pub(super) type AccountLog<T: Config> =
StorageValue<_, BoundedVec<T::AccountId, ConstU32<1_000>>, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn i32_log)]
pub(super) type I32Log<T> = StorageValue<_, BoundedVec<i32, ConstU32<1_000>>, ValueQuery>;
}
type Block = frame_system::mocking::MockBlock<Test>;
frame_support::construct_runtime!(
pub enum Test
{
System: frame_system,
Sudo: sudo,
Logger: logger,
}
);
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
type Block = Block;
}
impl logger::Config for Test {
type RuntimeEvent = RuntimeEvent;
}
impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type WeightInfo = ();
}
pub type SudoCall = sudo::Call<Test>;
pub type LoggerCall = logger::Call<Test>;
pub fn new_test_ext(root_key: u64) -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::<Test>::default()
.build_storage()
.unwrap();
sudo::GenesisConfig::<Test> {
key: Some(root_key),
}
.assimilate_storage(&mut t)
.unwrap();
let mut ext: sp_io::TestExternalities = t.into();
ext.execute_with(|| System::set_block_number(1));
ext
}
#[cfg(feature = "runtime-benchmarks")]
pub fn new_bench_ext() -> sp_io::TestExternalities {
frame_system::GenesisConfig::<Test>::default()
.build_storage()
.unwrap()
.into()
}

217
pallets/sudo/src/tests.rs Normal file
View File

@ -0,0 +1,217 @@
use super::*;
use frame_support::{assert_noop, assert_ok, weights::Weight};
use mock::{
new_test_ext, Logger, LoggerCall, RuntimeCall, RuntimeEvent as TestEvent, RuntimeOrigin, Sudo,
SudoCall, System, Test,
};
#[test]
fn test_setup_works() {
new_test_ext(1).execute_with(|| {
assert_eq!(Key::<Test>::get(), Some(1u64));
assert!(Logger::i32_log().is_empty());
assert!(Logger::account_log().is_empty());
});
}
#[docify::export]
#[test]
fn sudo_basics() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call));
assert_eq!(Logger::i32_log(), vec![42i32]);
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_noop!(
Sudo::sudo(RuntimeOrigin::signed(2), call),
Error::<Test>::RequireSudo
);
});
}
#[test]
fn sudo_emits_events_correctly() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call));
System::assert_has_event(TestEvent::Sudo(Event::Sudid {
sudo_result: Ok(()),
}));
})
}
#[test]
fn sudo_unchecked_weight_basics() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_ok!(Sudo::sudo_unchecked_weight(
RuntimeOrigin::signed(1),
call,
Weight::from_parts(1_000, 0)
));
assert_eq!(Logger::i32_log(), vec![42i32]);
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_noop!(
Sudo::sudo_unchecked_weight(
RuntimeOrigin::signed(2),
call,
Weight::from_parts(1_000, 0)
),
Error::<Test>::RequireSudo,
);
assert_eq!(Logger::i32_log(), vec![42i32]);
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
let sudo_unchecked_weight_call = SudoCall::sudo_unchecked_weight {
call,
weight: Weight::from_parts(1_000, 0),
};
let info = sudo_unchecked_weight_call.get_dispatch_info();
assert_eq!(info.weight, Weight::from_parts(1_000, 0));
});
}
#[test]
fn sudo_unchecked_weight_emits_events_correctly() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_ok!(Sudo::sudo_unchecked_weight(
RuntimeOrigin::signed(1),
call,
Weight::from_parts(1_000, 0)
));
System::assert_has_event(TestEvent::Sudo(Event::Sudid {
sudo_result: Ok(()),
}));
})
}
#[docify::export]
#[test]
fn set_key_basics() {
new_test_ext(1).execute_with(|| {
assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2));
assert_eq!(Key::<Test>::get(), Some(2u64));
});
new_test_ext(1).execute_with(|| {
assert_noop!(
Sudo::set_key(RuntimeOrigin::signed(2), 3),
Error::<Test>::RequireSudo
);
});
}
#[test]
fn set_key_emits_events_correctly() {
new_test_ext(1).execute_with(|| {
assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2));
System::assert_has_event(TestEvent::Sudo(Event::KeyChanged {
old: Some(1),
new: 2,
}));
assert_ok!(Sudo::set_key(RuntimeOrigin::signed(2), 4));
System::assert_has_event(TestEvent::Sudo(Event::KeyChanged {
old: Some(2),
new: 4,
}));
});
}
#[test]
fn remove_key_works() {
new_test_ext(1).execute_with(|| {
assert_ok!(Sudo::remove_key(RuntimeOrigin::signed(1)));
assert!(Key::<Test>::get().is_none());
System::assert_has_event(TestEvent::Sudo(Event::KeyRemoved {}));
assert_noop!(
Sudo::remove_key(RuntimeOrigin::signed(1)),
Error::<Test>::RequireSudo
);
assert_noop!(
Sudo::set_key(RuntimeOrigin::signed(1), 1),
Error::<Test>::RequireSudo
);
});
}
#[test]
fn using_root_origin_works() {
new_test_ext(1).execute_with(|| {
assert_ok!(Sudo::remove_key(RuntimeOrigin::root()));
assert!(Key::<Test>::get().is_none());
System::assert_has_event(TestEvent::Sudo(Event::KeyRemoved {}));
assert_ok!(Sudo::set_key(RuntimeOrigin::root(), 1));
assert_eq!(Some(1), Key::<Test>::get());
});
}
#[test]
fn sudo_as_basics() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
i: 42,
weight: Weight::from_parts(1_000, 0),
}));
assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call));
assert!(Logger::i32_log().is_empty());
assert!(Logger::account_log().is_empty());
let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_noop!(
Sudo::sudo_as(RuntimeOrigin::signed(3), 2, call),
Error::<Test>::RequireSudo
);
let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call));
assert_eq!(Logger::i32_log(), vec![42i32]);
assert_eq!(Logger::account_log(), vec![2]);
});
}
#[docify::export]
#[test]
fn sudo_as_emits_events_correctly() {
new_test_ext(1).execute_with(|| {
let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log {
i: 42,
weight: Weight::from_parts(1, 0),
}));
assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call));
System::assert_has_event(TestEvent::Sudo(Event::SudoAsDone {
sudo_result: Ok(()),
}));
});
}

156
pallets/sudo/src/weights.rs Normal file
View File

@ -0,0 +1,156 @@
// This file is part of Ghost Network.
// Ghost Network 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.
// Ghost Network 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 Ghost Network. If not, see <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `ghost_sudo`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2025-07-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
// Executed Command:
// ./target/release/ghost
// benchmark
// pallet
// --chain=casper-dev
// --steps=50
// --repeat=20
// --pallet=ghost-sudo
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --header=./file_header.txt
// --output=./runtime/casper/src/weights/ghost_sudo.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
use frame_support::{
traits::Get,
weights::{Weight, constants::RocksDbWeight},
};
use core::marker::PhantomData;
/// Weight functions needed for `pallet_sudo`.
pub trait WeightInfo {
fn set_key() -> Weight;
fn sudo() -> Weight;
fn sudo_as() -> Weight;
fn remove_key() -> Weight;
}
/// Weight functions for `ghost_sudo`.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: `GhostSudo::Key` (r:1 w:1)
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn set_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 40_014_000 picoseconds.
Weight::from_parts(40_856_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: `GhostSudo::Key` (r:1 w:0)
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 44_086_000 picoseconds.
Weight::from_parts(45_920_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
}
/// Storage: `GhostSudo::Key` (r:1 w:0)
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 44_106_000 picoseconds.
Weight::from_parts(44_650_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
}
/// Storage: `GhostSudo::Key` (r:1 w:1)
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn remove_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 36_416_000 picoseconds.
Weight::from_parts(37_373_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
}
// For backwards compatibility and tests.
impl WeightInfo for () {
/// Storage: `GhostSudo::Key` (r:1 w:1)
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn set_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 40_014_000 picoseconds.
Weight::from_parts(40_856_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: `GhostSudo::Key` (r:1 w:0)
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 44_086_000 picoseconds.
Weight::from_parts(45_920_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(RocksDbWeight::get().reads(1))
}
/// Storage: `GhostSudo::Key` (r:1 w:0)
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 44_106_000 picoseconds.
Weight::from_parts(44_650_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(RocksDbWeight::get().reads(1))
}
/// Storage: `GhostSudo::Key` (r:1 w:1)
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn remove_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Estimated: `1517`
// Minimum execution time: 36_416_000 picoseconds.
Weight::from_parts(37_373_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
}

6
pallets/traits/Cargo.toml Executable file → Normal file
View File

@ -1,6 +1,6 @@
[package]
name = "ghost-traits"
version = "0.3.19"
version = "0.3.23"
license.workspace = true
authors.workspace = true
edition.workspace = true
@ -14,6 +14,6 @@ sp-runtime = { workspace = true }
[features]
default = ["std"]
std = [
"frame-support/std",
"sp-runtime/std",
"frame-support/std",
"sp-runtime/std",
]

0
pallets/traits/src/lib.rs Executable file → Normal file
View File

26
pallets/traits/src/networks.rs Executable file → Normal file
View File

@ -1,10 +1,7 @@
use frame_support::{
pallet_prelude::*,
storage::PrefixIterator,
};
use frame_support::{pallet_prelude::*, storage::PrefixIterator};
use sp_runtime::{
DispatchResult,
traits::{AtLeast32BitUnsigned, Member},
DispatchResult,
};
pub trait NetworkDataBasicHandler {
@ -21,9 +18,26 @@ pub trait NetworkDataBasicHandler {
pub trait NetworkDataInspectHandler<Network>: NetworkDataBasicHandler {
fn get(n: &Self::NetworkId) -> Option<Network>;
fn iter() -> PrefixIterator<(Self::NetworkId, Network)>;
fn is_nullification_period() -> bool;
}
pub trait NetworkDataMutateHandler<Network>: NetworkDataInspectHandler<Network> {
pub trait NetworkDataMutateHandler<Network, Balance>: NetworkDataInspectHandler<Network> {
fn register(chain_id: Self::NetworkId, network: Network) -> DispatchResult;
fn remove(chain_id: Self::NetworkId) -> DispatchResult;
fn increase_gatekeeper_amount(
chain_id: &Self::NetworkId,
amount: &Balance,
) -> Result<Balance, ()>;
fn decrease_gatekeeper_amount(
chain_id: &Self::NetworkId,
amount: &Balance,
) -> Result<Balance, ()>;
fn accumulate_outgoing_imbalance(amount: &Balance) -> Result<Balance, ()>;
fn accumulate_incoming_imbalance(amount: &Balance) -> Result<Balance, ()>;
fn accumulate_commission(commission: &Balance) -> Result<Balance, ()>;
fn nullify_commission();
fn trigger_nullification();
}

0
rpc/Cargo.toml Executable file → Normal file
View File

58
rpc/src/lib.rs Executable file → Normal file
View File

@ -1,17 +1,15 @@
use std::sync::Arc;
use jsonrpsee::RpcModule;
use primitives::{
AccountId, Balance, Block, BlockNumber, Hash, Nonce,
};
use sc_client_api::AuxStore;
use babe_primitives::BabeApi;
use block_builder_api::BlockBuilder;
use consensus_common::SelectChain;
use grandpa::FinalityProofProvider;
use jsonrpsee::RpcModule;
use primitives::{AccountId, Balance, Block, BlockNumber, Hash, Nonce};
use sc_client_api::AuxStore;
pub use sc_rpc::{DenyUnsafe, SubscriptionTaskExecutor};
use sp_api::ProvideRuntimeApi;
use block_builder_api::BlockBuilder;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
use consensus_common::SelectChain;
use babe_primitives::BabeApi;
use sp_keystore::KeystorePtr;
use tx_pool_api::TransactionPool;
@ -61,7 +59,16 @@ pub struct FullDeps<C, P, SC, B> {
}
pub fn create_full_rpc<C, P, SC, B>(
FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa, backend } : FullDeps<C, P, SC, B>,
FullDeps {
client,
pool,
select_chain,
chain_spec,
deny_unsafe,
babe,
grandpa,
backend,
}: FullDeps<C, P, SC, B>,
) -> Result<RpcExtension, Box<dyn std::error::Error + Send + Sync>>
where
C: ProvideRuntimeApi<Block>
@ -80,20 +87,19 @@ where
B: sc_client_api::Backend<Block> + Send + Sync + 'static,
B::State: sc_client_api::StateBackend<sp_runtime::traits::HashingFor<Block>>,
{
use frame_rpc_system::{System, SystemApiServer};
use pallet_transaction_payment_rpc::{
TransactionPayment, TransactionPaymentApiServer,
};
use babe_rpc::{Babe, BabeApiServer};
use frame_rpc_system::{System, SystemApiServer};
use grandpa_rpc::{Grandpa, GrandpaApiServer};
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
use sc_rpc_spec_v2::chain_spec::{ChainSpec, ChainSpecApiServer};
use sc_sync_state_rpc::{SyncState, SyncStateApiServer};
use substrate_state_trie_migration_rpc::{
StateMigration, StateMigrationApiServer,
};
use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer};
let mut io = RpcModule::new(());
let BabeDeps { babe_worker_handle, keystore } = babe;
let BabeDeps {
babe_worker_handle,
keystore,
} = babe;
let GrandpaDeps {
shared_voter_state,
shared_authority_set,
@ -103,10 +109,13 @@ where
} = grandpa;
let chain_name = chain_spec.name().to_string();
let genesis_hash = client.hash(0).ok().flatten().expect("Genesis block exists; qed;");
let genesis_hash = client
.hash(0)
.ok()
.flatten()
.expect("Genesis block exists; qed;");
let properties = chain_spec.properties();
io.merge(ChainSpec::new(chain_name, genesis_hash, properties).into_rpc())?;
io.merge(StateMigration::new(client.clone(), backend.clone(), deny_unsafe).into_rpc())?;
io.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?;
@ -119,7 +128,8 @@ where
keystore,
select_chain,
deny_unsafe,
).into_rpc()
)
.into_rpc(),
)?;
io.merge(
@ -129,7 +139,8 @@ where
shared_voter_state,
justification_stream,
finality_provider,
).into_rpc(),
)
.into_rpc(),
)?;
io.merge(
@ -137,8 +148,9 @@ where
chain_spec,
client.clone(),
shared_authority_set,
babe_worker_handle
)?.into_rpc(),
babe_worker_handle,
)?
.into_rpc(),
)?;
Ok(io)

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