Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Arkadi's fix for the 0.9.16 release (#10742)
Browse files Browse the repository at this point in the history
* Enable download of future forks

* Fixed external tests

* Fix warning.

* cargo fmt

* Fix benchmarking test

Co-authored-by: arkpar <arkady.paronyan@gmail.com>
Co-authored-by: Bastian Köcher <info@kchr.de>
  • Loading branch information
3 people authored Jan 27, 2022
1 parent ac8c2cd commit 1c2332d
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 95 deletions.
8 changes: 7 additions & 1 deletion client/network/src/protocol/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2418,7 +2418,11 @@ fn fork_sync_request<B: BlockT>(
if !r.peers.contains(id) {
continue
}
if r.number <= best_num {
// Download the fork only if it is behind or not too far ahead our tip of the chain
// Otherwise it should be downloaded in full sync mode.
if r.number <= best_num ||
(r.number - best_num).saturated_into::<u32>() < MAX_BLOCKS_TO_REQUEST as u32
{
let parent_status = r.parent_hash.as_ref().map_or(BlockStatus::Unknown, check_block);
let count = if parent_status == BlockStatus::Unknown {
(r.number - finalized).saturated_into::<u32>() // up to the last finalized block
Expand All @@ -2438,6 +2442,8 @@ fn fork_sync_request<B: BlockT>(
max: Some(count),
},
))
} else {
trace!(target: "sync", "Fork too far in the future: {:?} (#{})", hash, r.number);
}
}
None
Expand Down
58 changes: 37 additions & 21 deletions client/network/test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,23 +86,14 @@ type AuthorityId = sp_consensus_babe::AuthorityId;
#[derive(Clone)]
pub struct PassThroughVerifier {
finalized: bool,
fork_choice: ForkChoiceStrategy,
}

impl PassThroughVerifier {
/// Create a new instance.
///
/// Every verified block will use `finalized` for the `BlockImportParams`.
pub fn new(finalized: bool) -> Self {
Self { finalized, fork_choice: ForkChoiceStrategy::LongestChain }
}

/// Create a new instance.
///
/// Every verified block will use `finalized` for the `BlockImportParams` and
/// the given [`ForkChoiceStrategy`].
pub fn new_with_fork_choice(finalized: bool, fork_choice: ForkChoiceStrategy) -> Self {
Self { finalized, fork_choice }
Self { finalized }
}
}

Expand All @@ -121,8 +112,10 @@ impl<B: BlockT> Verifier<B> for PassThroughVerifier {
.or_else(|| l.try_as_raw(OpaqueDigestItemId::Consensus(b"babe")))
})
.map(|blob| vec![(well_known_cache_keys::AUTHORITIES, blob.to_vec())]);
if block.fork_choice.is_none() {
block.fork_choice = Some(ForkChoiceStrategy::LongestChain);
};
block.finalized = self.finalized;
block.fork_choice = Some(self.fork_choice.clone());
Ok((block, maybe_keys))
}
}
Expand Down Expand Up @@ -309,6 +302,33 @@ where
false,
true,
true,
ForkChoiceStrategy::LongestChain,
)
}

/// Add blocks to the peer -- edit the block before adding and use custom fork choice rule.
pub fn generate_blocks_with_fork_choice<F>(
&mut self,
count: usize,
origin: BlockOrigin,
edit_block: F,
fork_choice: ForkChoiceStrategy,
) -> H256
where
F: FnMut(
BlockBuilder<Block, PeersFullClient, substrate_test_runtime_client::Backend>,
) -> Block,
{
let best_hash = self.client.info().best_hash;
self.generate_blocks_at(
BlockId::Hash(best_hash),
count,
origin,
edit_block,
false,
true,
true,
fork_choice,
)
}

Expand All @@ -323,6 +343,7 @@ where
headers_only: bool,
inform_sync_about_new_best_block: bool,
announce_block: bool,
fork_choice: ForkChoiceStrategy,
) -> H256
where
F: FnMut(
Expand All @@ -346,6 +367,7 @@ where
let header = block.header.clone();
let mut import_block = BlockImportParams::new(origin, header.clone());
import_block.body = if headers_only { None } else { Some(block.extrinsics) };
import_block.fork_choice = Some(fork_choice);
let (import_block, cache) =
futures::executor::block_on(self.verifier.verify(import_block)).unwrap();
let cache = if let Some(cache) = cache {
Expand Down Expand Up @@ -442,6 +464,7 @@ where
headers_only,
inform_sync_about_new_best_block,
announce_block,
ForkChoiceStrategy::LongestChain,
)
} else {
self.generate_blocks_at(
Expand All @@ -452,6 +475,7 @@ where
headers_only,
inform_sync_about_new_best_block,
announce_block,
ForkChoiceStrategy::LongestChain,
)
}
}
Expand Down Expand Up @@ -993,14 +1017,6 @@ where

pub struct TestNet {
peers: Vec<Peer<(), PeersClient>>,
fork_choice: ForkChoiceStrategy,
}

impl TestNet {
/// Create a `TestNet` that used the given fork choice rule.
pub fn with_fork_choice(fork_choice: ForkChoiceStrategy) -> Self {
Self { peers: Vec::new(), fork_choice }
}
}

impl TestNetFactory for TestNet {
Expand All @@ -1010,7 +1026,7 @@ impl TestNetFactory for TestNet {

/// Create new test network with peers and given config.
fn from_config(_config: &ProtocolConfig) -> Self {
TestNet { peers: Vec::new(), fork_choice: ForkChoiceStrategy::LongestChain }
TestNet { peers: Vec::new() }
}

fn make_verifier(
Expand All @@ -1019,7 +1035,7 @@ impl TestNetFactory for TestNet {
_config: &ProtocolConfig,
_peer_data: &(),
) -> Self::Verifier {
PassThroughVerifier::new_with_fork_choice(false, self.fork_choice.clone())
PassThroughVerifier::new(false)
}

fn make_block_import(
Expand Down
63 changes: 53 additions & 10 deletions client/network/test/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,38 @@ fn can_sync_small_non_best_forks() {
}));
}

#[test]
fn can_sync_forks_ahead_of_the_best_chain() {
sp_tracing::try_init_simple();
let mut net = TestNet::new(2);
net.peer(0).push_blocks(1, false);
net.peer(1).push_blocks(1, false);

net.block_until_connected();
// Peer 0 is on 2-block fork which is announced with is_best=false
let fork_hash = net.peer(0).generate_blocks_with_fork_choice(
2,
BlockOrigin::Own,
|builder| builder.build().unwrap().block,
ForkChoiceStrategy::Custom(false),
);
// Peer 1 is on 1-block fork
net.peer(1).push_blocks(1, false);
assert!(net.peer(0).client().header(&BlockId::Hash(fork_hash)).unwrap().is_some());
assert_eq!(net.peer(0).client().info().best_number, 1);
assert_eq!(net.peer(1).client().info().best_number, 2);

// after announcing, peer 1 downloads the block.
block_on(futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);

if net.peer(1).client().header(&BlockId::Hash(fork_hash)).unwrap().is_none() {
return Poll::Pending
}
Poll::Ready(())
}));
}

#[test]
fn can_sync_explicit_forks() {
sp_tracing::try_init_simple();
Expand Down Expand Up @@ -678,7 +710,7 @@ impl BlockAnnounceValidator<Block> for FailingBlockAnnounceValidator {
#[test]
fn sync_blocks_when_block_announce_validator_says_it_is_new_best() {
sp_tracing::try_init_simple();
let mut net = TestNet::with_fork_choice(ForkChoiceStrategy::Custom(false));
let mut net = TestNet::new(0);
net.add_full_peer_with_config(Default::default());
net.add_full_peer_with_config(Default::default());
net.add_full_peer_with_config(FullPeerConfig {
Expand All @@ -688,16 +720,17 @@ fn sync_blocks_when_block_announce_validator_says_it_is_new_best() {

net.block_until_connected();

let block_hash = net.peer(0).push_blocks(1, false);
// Add blocks but don't set them as best
let block_hash = net.peer(0).generate_blocks_with_fork_choice(
1,
BlockOrigin::Own,
|builder| builder.build().unwrap().block,
ForkChoiceStrategy::Custom(false),
);

while !net.peer(2).has_block(&block_hash) {
net.block_until_idle();
}

// Peer1 should not have the block, because peer 0 did not reported the block
// as new best. However, peer2 has a special block announcement validator
// that flags all blocks as `is_new_best` and thus, it should have synced the blocks.
assert!(!net.peer(1).has_block(&block_hash));
}

/// Waits for some time until the validation is successfull.
Expand All @@ -721,7 +754,7 @@ impl BlockAnnounceValidator<Block> for DeferredBlockAnnounceValidator {
#[test]
fn wait_until_deferred_block_announce_validation_is_ready() {
sp_tracing::try_init_simple();
let mut net = TestNet::with_fork_choice(ForkChoiceStrategy::Custom(false));
let mut net = TestNet::new(0);
net.add_full_peer_with_config(Default::default());
net.add_full_peer_with_config(FullPeerConfig {
block_announce_validator: Some(Box::new(NewBestBlockAnnounceValidator)),
Expand All @@ -730,7 +763,13 @@ fn wait_until_deferred_block_announce_validation_is_ready() {

net.block_until_connected();

let block_hash = net.peer(0).push_blocks(1, true);
// Add blocks but don't set them as best
let block_hash = net.peer(0).generate_blocks_with_fork_choice(
1,
BlockOrigin::Own,
|builder| builder.build().unwrap().block,
ForkChoiceStrategy::Custom(false),
);

while !net.peer(1).has_block(&block_hash) {
net.block_until_idle();
Expand Down Expand Up @@ -847,7 +886,10 @@ fn block_announce_data_is_propagated() {
// Wait until peer 1 is connected to both nodes.
block_on(futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
if net.peer(1).num_peers() == 2 {
if net.peer(1).num_peers() == 2 &&
net.peer(0).num_peers() == 1 &&
net.peer(2).num_peers() == 1
{
Poll::Ready(())
} else {
Poll::Pending
Expand Down Expand Up @@ -1109,6 +1151,7 @@ fn syncs_indexed_blocks() {
false,
true,
true,
ForkChoiceStrategy::LongestChain,
);
let indexed_key = sp_runtime::traits::BlakeTwo256::hash(&42u64.to_le_bytes());
assert!(net
Expand Down
3 changes: 1 addition & 2 deletions frame/support/src/storage/child.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@ pub fn put_raw(child_info: &ChildInfo, key: &[u8], value: &[u8]) {
/// Calculate current child root value.
pub fn root(child_info: &ChildInfo, _: StateVersion) -> Vec<u8> {
match child_info.child_type() {
ChildType::ParentKeyId =>
sp_io::default_child_storage::root(child_info.storage_key()),
ChildType::ParentKeyId => sp_io::default_child_storage::root(child_info.storage_key()),
}
}

Expand Down
104 changes: 46 additions & 58 deletions frame/transaction-storage/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,64 +42,52 @@ use crate::Pallet as TransactionStorage;
// while hardforcing target chunk key in `build_proof` to [22, 21, 1, 0].
const PROOF: &[u8] = &hex_literal::hex!(
"
0104000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000014cd0780ffff8030
2eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba0080302eb0a6d2
f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15
f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1
004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e304
8cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697
eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a
30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302e
b0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b
834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e7
29d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c10046
57e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf2
06d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb1
53f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba
bd058077778010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de
808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f
19117affa96e077905fe48a99723a065969c638593b7d9ab57b538438010fd81bc1359802f0b
871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bc
cee5e71d5cf6b1faff338ad7120b0256c283008010fd81bc1359802f0b871aeb95e4410a8ec9
2b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff
338ad7120b0256c28380221ce17f19117affa96e077905fe48a99723a065969c638593b7d9ab
57b538438010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de80
8da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f19
117affa96e077905fe48a99723a065969c638593b7d9ab57b53843cd0780ffff804509f59593
fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c00804509f59593fd47b1a9
7189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba6
5a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0
346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f983
6e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf89
1a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c8045
09f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd
47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189
127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a56
49cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb03466
37f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e15
5eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a93
9c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939ccd0780ff
ff8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e
776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea
05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f
015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d
06feafa3610fc44a5b2ef543cb81008078916e776c64ccea05e958559f015c082d9d06feafa3
610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b
2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb81
8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e77
6c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05
e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f01
5c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06
feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610f
c44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef5
43cb811044010000
"
0104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000014cd0780ffff80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe8
7d12a3662c4c0080e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb
13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2
f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f
1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f
3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a47
8e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cf
f93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e31
6a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f
53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c8
0e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4cbd05807777809a5d7a720ce5f9d9a012
fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a3dc2f6b9e957d129e610c06d411e11743062dc1cf
3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce186c4ddc53f118e0ddd4decd8cc809a5d7a720ce5f9d9
a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a3dc2f6b9e957d129e610c06d411e11743062d
c1cf3ac289390ae4c00809a5d7a720ce5f9d9a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a
3dc2f6b9e957d129e610c06d411e11743062dc1cf3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce186c
4ddc53f118e0ddd4decd8cc809a5d7a720ce5f9d9a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bc
bf8a3dc2f6b9e957d129e610c06d411e11743062dc1cf3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce
186c4ddc53f118e0ddd4decd8cccd0780ffff8081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb0
3bdb31008081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253
515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa139
8e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5
f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3a
a1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2b
a8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f32
2d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa
9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f0
2f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b82
5bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb31cd0780ffff80b4f23ac50c8e67d9b280f2b31a
5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd1885
44c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2
b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd
188544c5f9b0080b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9
b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84
d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e
67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977aca
ac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac5
0c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b89297
7acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b104401
0000
"
);

type BalanceOf<T> =
Expand Down
Loading

0 comments on commit 1c2332d

Please sign in to comment.