mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-09 18:47:59 +00:00
002d9260f9
**Update:** Pushed additional changes based on the review comments. **This pull request fixes various spelling mistakes in this repository.** Most of the changes are contained in the first **3** commits: - `Fix spelling mistakes in comments and docs` - `Fix spelling mistakes in test names` - `Fix spelling mistakes in error messages, panic messages, logs and tracing` Other source code spelling mistakes are separated into individual commits for easier reviewing: - `Fix the spelling of 'authority'` - `Fix the spelling of 'REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY'` - `Fix the spelling of 'prev_enqueud_messages'` - `Fix the spelling of 'endpoint'` - `Fix the spelling of 'children'` - `Fix the spelling of 'PenpalSiblingSovereignAccount'` - `Fix the spelling of 'PenpalSudoAccount'` - `Fix the spelling of 'insufficient'` - `Fix the spelling of 'PalletXcmExtrinsicsBenchmark'` - `Fix the spelling of 'subtracted'` - `Fix the spelling of 'CandidatePendingAvailability'` - `Fix the spelling of 'exclusive'` - `Fix the spelling of 'until'` - `Fix the spelling of 'discriminator'` - `Fix the spelling of 'nonexistent'` - `Fix the spelling of 'subsystem'` - `Fix the spelling of 'indices'` - `Fix the spelling of 'committed'` - `Fix the spelling of 'topology'` - `Fix the spelling of 'response'` - `Fix the spelling of 'beneficiary'` - `Fix the spelling of 'formatted'` - `Fix the spelling of 'UNKNOWN_PROOF_REQUEST'` - `Fix the spelling of 'succeeded'` - `Fix the spelling of 'reopened'` - `Fix the spelling of 'proposer'` - `Fix the spelling of 'InstantiationNonce'` - `Fix the spelling of 'depositor'` - `Fix the spelling of 'expiration'` - `Fix the spelling of 'phantom'` - `Fix the spelling of 'AggregatedKeyValue'` - `Fix the spelling of 'randomness'` - `Fix the spelling of 'defendant'` - `Fix the spelling of 'AquaticMammal'` - `Fix the spelling of 'transactions'` - `Fix the spelling of 'PassingTracingSubscriber'` - `Fix the spelling of 'TxSignaturePayload'` - `Fix the spelling of 'versioning'` - `Fix the spelling of 'descendant'` - `Fix the spelling of 'overridden'` - `Fix the spelling of 'network'` Let me know if this structure is adequate. **Note:** The usage of the words `Merkle`, `Merkelize`, `Merklization`, `Merkelization`, `Merkleization`, is somewhat inconsistent but I left it as it is. ~~**Note:** In some places the term `Receival` is used to refer to message reception, IMO `Reception` is the correct word here, but I left it as it is.~~ ~~**Note:** In some places the term `Overlayed` is used instead of the more acceptable version `Overlaid` but I also left it as it is.~~ ~~**Note:** In some places the term `Applyable` is used instead of the correct version `Applicable` but I also left it as it is.~~ **Note:** Some usage of British vs American english e.g. `judgement` vs `judgment`, `initialise` vs `initialize`, `optimise` vs `optimize` etc. are both present in different places, but I suppose that's understandable given the number of contributors. ~~**Note:** There is a spelling mistake in `.github/CODEOWNERS` but it triggers errors in CI when I make changes to it, so I left it as it is.~~
1227 lines
33 KiB
Rust
1227 lines
33 KiB
Rust
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// This file is part of Polkadot.
|
|
|
|
// Polkadot is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Polkadot is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use super::*;
|
|
use assert_matches::assert_matches;
|
|
use bitvec::bitvec;
|
|
use futures::executor;
|
|
use maplit::hashmap;
|
|
use polkadot_node_network_protocol::{
|
|
grid_topology::{SessionBoundGridTopologyStorage, SessionGridTopology, TopologyPeerInfo},
|
|
our_view,
|
|
peer_set::ValidationVersion,
|
|
view, ObservedRole,
|
|
};
|
|
use polkadot_node_subsystem::{
|
|
jaeger,
|
|
jaeger::{PerLeafSpan, Span},
|
|
messages::ReportPeerMessage,
|
|
};
|
|
use polkadot_node_subsystem_test_helpers::make_subsystem_context;
|
|
use polkadot_node_subsystem_util::TimeoutExt;
|
|
use polkadot_primitives::{AvailabilityBitfield, Signed, ValidatorIndex};
|
|
use rand_chacha::ChaCha12Rng;
|
|
use sp_application_crypto::AppCrypto;
|
|
use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair;
|
|
use sp_core::Pair as PairT;
|
|
use sp_keyring::Sr25519Keyring;
|
|
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr};
|
|
|
|
use std::{iter::FromIterator as _, sync::Arc, time::Duration};
|
|
|
|
const TIMEOUT: Duration = Duration::from_millis(50);
|
|
macro_rules! launch {
|
|
($fut:expr) => {
|
|
$fut.timeout(TIMEOUT).await.unwrap_or_else(|| {
|
|
panic!("{}ms is more than enough for sending messages.", TIMEOUT.as_millis())
|
|
});
|
|
};
|
|
}
|
|
|
|
/// Pre-seeded `crypto` random numbers generator for testing purposes
|
|
fn dummy_rng() -> ChaCha12Rng {
|
|
rand_chacha::ChaCha12Rng::seed_from_u64(12345)
|
|
}
|
|
|
|
fn peer_data_v1(view: View) -> PeerData {
|
|
PeerData { view, version: ValidationVersion::V1.into() }
|
|
}
|
|
|
|
/// A very limited state, only interested in the relay parent of the
|
|
/// given message, which must be signed by `validator` and a set of peers
|
|
/// which are also only interested in that relay parent.
|
|
fn prewarmed_state(
|
|
validator: ValidatorId,
|
|
signing_context: SigningContext,
|
|
known_message: BitfieldGossipMessage,
|
|
peers: Vec<PeerId>,
|
|
) -> ProtocolState {
|
|
let relay_parent = known_message.relay_parent;
|
|
let mut topologies = SessionBoundGridTopologyStorage::default();
|
|
topologies.update_topology(0_u32, SessionGridTopology::new(Vec::new(), Vec::new()), None);
|
|
topologies.get_current_topology_mut().local_grid_neighbors_mut().peers_x =
|
|
peers.iter().cloned().collect();
|
|
|
|
ProtocolState {
|
|
per_relay_parent: hashmap! {
|
|
relay_parent =>
|
|
PerRelayParentData {
|
|
signing_context,
|
|
validator_set: vec![validator.clone()],
|
|
one_per_validator: hashmap! {
|
|
validator.clone() => known_message.clone(),
|
|
},
|
|
message_received_from_peer: hashmap!{},
|
|
message_sent_to_peer: hashmap!{},
|
|
span: PerLeafSpan::new(Arc::new(jaeger::Span::Disabled), "test"),
|
|
},
|
|
},
|
|
peer_data: peers
|
|
.iter()
|
|
.cloned()
|
|
.map(|peer| (peer, peer_data_v1(view![relay_parent])))
|
|
.collect(),
|
|
topologies,
|
|
view: our_view!(relay_parent),
|
|
reputation: ReputationAggregator::new(|_| true),
|
|
}
|
|
}
|
|
|
|
fn state_with_view(
|
|
view: OurView,
|
|
relay_parent: Hash,
|
|
reputation: ReputationAggregator,
|
|
) -> (ProtocolState, SigningContext, KeystorePtr, ValidatorId) {
|
|
let mut state = ProtocolState { reputation, ..Default::default() };
|
|
|
|
let signing_context = SigningContext { session_index: 1, parent_hash: relay_parent };
|
|
|
|
let keystore: KeystorePtr = Arc::new(MemoryKeystore::new());
|
|
let validator = Keystore::sr25519_generate_new(&*keystore, ValidatorId::ID, None)
|
|
.expect("generating sr25519 key not to fail");
|
|
|
|
state.per_relay_parent = view
|
|
.iter()
|
|
.map(|relay_parent| {
|
|
(
|
|
*relay_parent,
|
|
PerRelayParentData {
|
|
signing_context: signing_context.clone(),
|
|
validator_set: vec![validator.into()],
|
|
one_per_validator: hashmap! {},
|
|
message_received_from_peer: hashmap! {},
|
|
message_sent_to_peer: hashmap! {},
|
|
span: PerLeafSpan::new(Arc::new(jaeger::Span::Disabled), "test"),
|
|
},
|
|
)
|
|
})
|
|
.collect();
|
|
|
|
state.view = view;
|
|
|
|
(state, signing_context, keystore, validator.into())
|
|
}
|
|
|
|
#[test]
|
|
fn receive_invalid_signature() {
|
|
let _ = env_logger::builder()
|
|
.filter(None, log::LevelFilter::Trace)
|
|
.is_test(true)
|
|
.try_init();
|
|
|
|
let hash_a: Hash = [0; 32].into();
|
|
|
|
let peer_a = PeerId::random();
|
|
let peer_b = PeerId::random();
|
|
assert_ne!(peer_a, peer_b);
|
|
|
|
let signing_context = SigningContext { session_index: 1, parent_hash: hash_a };
|
|
|
|
// another validator not part of the validator set
|
|
let keystore: KeystorePtr = Arc::new(MemoryKeystore::new());
|
|
let malicious = Keystore::sr25519_generate_new(&*keystore, ValidatorId::ID, None)
|
|
.expect("Malicious key created");
|
|
let validator_0 =
|
|
Keystore::sr25519_generate_new(&*keystore, ValidatorId::ID, None).expect("key created");
|
|
let validator_1 =
|
|
Keystore::sr25519_generate_new(&*keystore, ValidatorId::ID, None).expect("key created");
|
|
|
|
let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
|
|
let invalid_signed = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload.clone(),
|
|
&signing_context,
|
|
ValidatorIndex(0),
|
|
&malicious.into(),
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
let invalid_signed_2 = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload.clone(),
|
|
&signing_context,
|
|
ValidatorIndex(1),
|
|
&malicious.into(),
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
|
|
let valid_signed = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload,
|
|
&signing_context,
|
|
ValidatorIndex(0),
|
|
&validator_0.into(),
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
|
|
let invalid_msg =
|
|
BitfieldGossipMessage { relay_parent: hash_a, signed_availability: invalid_signed.clone() };
|
|
let invalid_msg_2 = BitfieldGossipMessage {
|
|
relay_parent: hash_a,
|
|
signed_availability: invalid_signed_2.clone(),
|
|
};
|
|
let valid_msg =
|
|
BitfieldGossipMessage { relay_parent: hash_a, signed_availability: valid_signed.clone() };
|
|
|
|
let pool = sp_core::testing::TaskExecutor::new();
|
|
let (mut ctx, mut handle) = make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
|
|
|
let mut state =
|
|
prewarmed_state(validator_0.into(), signing_context.clone(), valid_msg, vec![peer_b]);
|
|
state
|
|
.per_relay_parent
|
|
.get_mut(&hash_a)
|
|
.unwrap()
|
|
.validator_set
|
|
.push(validator_1.into());
|
|
let mut rng = dummy_rng();
|
|
|
|
executor::block_on(async move {
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_b,
|
|
invalid_msg.into_network_message(ValidationVersion::V1.into())
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
// reputation doesn't change due to one_job_per_validator check
|
|
assert!(handle.recv().timeout(TIMEOUT).await.is_none());
|
|
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_b,
|
|
invalid_msg_2.into_network_message(ValidationVersion::V1.into())
|
|
),
|
|
&mut rng,
|
|
));
|
|
// reputation change due to invalid signature
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_b);
|
|
assert_eq!(rep.value, COST_SIGNATURE_INVALID.cost_or_benefit())
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn receive_invalid_validator_index() {
|
|
let _ = env_logger::builder()
|
|
.filter(None, log::LevelFilter::Trace)
|
|
.is_test(true)
|
|
.try_init();
|
|
|
|
let hash_a: Hash = [0; 32].into();
|
|
let hash_b: Hash = [1; 32].into(); // other
|
|
|
|
let peer_a = PeerId::random();
|
|
let peer_b = PeerId::random();
|
|
assert_ne!(peer_a, peer_b);
|
|
|
|
// validator 0 key pair
|
|
let (mut state, signing_context, keystore, validator) =
|
|
state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| true));
|
|
|
|
state.peer_data.insert(peer_b, peer_data_v1(view![hash_a]));
|
|
|
|
let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
|
|
let signed = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload,
|
|
&signing_context,
|
|
ValidatorIndex(42),
|
|
&validator,
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
|
|
let msg = BitfieldGossipMessage { relay_parent: hash_a, signed_availability: signed.clone() };
|
|
|
|
let pool = sp_core::testing::TaskExecutor::new();
|
|
let (mut ctx, mut handle) = make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
|
let mut rng = dummy_rng();
|
|
|
|
executor::block_on(async move {
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_b,
|
|
msg.into_network_message(ValidationVersion::V1.into())
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
// reputation change due to invalid validator index
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_b);
|
|
assert_eq!(rep.value, COST_VALIDATOR_INDEX_INVALID.cost_or_benefit())
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn receive_duplicate_messages() {
|
|
let _ = env_logger::builder()
|
|
.filter(None, log::LevelFilter::Trace)
|
|
.is_test(true)
|
|
.try_init();
|
|
|
|
let hash_a: Hash = [0; 32].into();
|
|
let hash_b: Hash = [1; 32].into();
|
|
|
|
let peer_a = PeerId::random();
|
|
let peer_b = PeerId::random();
|
|
assert_ne!(peer_a, peer_b);
|
|
|
|
// validator 0 key pair
|
|
let (mut state, signing_context, keystore, validator) =
|
|
state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| true));
|
|
|
|
// create a signed message by validator 0
|
|
let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
|
|
let signed_bitfield = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload,
|
|
&signing_context,
|
|
ValidatorIndex(0),
|
|
&validator,
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
|
|
let msg = BitfieldGossipMessage {
|
|
relay_parent: hash_a,
|
|
signed_availability: signed_bitfield.clone(),
|
|
};
|
|
|
|
let pool = sp_core::testing::TaskExecutor::new();
|
|
let (mut ctx, mut handle) = make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
|
let mut rng = dummy_rng();
|
|
|
|
executor::block_on(async move {
|
|
// send a first message
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_b,
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
// none of our peers has any interest in any messages
|
|
// so we do not receive a network send type message here
|
|
// but only the one for the next subsystem
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::Provisioner(ProvisionerMessage::ProvisionableData(
|
|
_,
|
|
ProvisionableData::Bitfield(hash, signed)
|
|
)) => {
|
|
assert_eq!(hash, hash_a);
|
|
assert_eq!(signed, signed_bitfield)
|
|
}
|
|
);
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_b);
|
|
assert_eq!(rep.value, BENEFIT_VALID_MESSAGE_FIRST.cost_or_benefit())
|
|
}
|
|
);
|
|
|
|
// let peer A send the same message again
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_a,
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_a);
|
|
assert_eq!(rep.value, BENEFIT_VALID_MESSAGE.cost_or_benefit())
|
|
}
|
|
);
|
|
|
|
// let peer B send the initial message again
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_b,
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_b);
|
|
assert_eq!(rep.value, COST_PEER_DUPLICATE_MESSAGE.cost_or_benefit())
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn delay_reputation_change() {
|
|
use polkadot_node_subsystem_util::reputation::add_reputation;
|
|
|
|
let _ = env_logger::builder()
|
|
.filter(None, log::LevelFilter::Trace)
|
|
.is_test(true)
|
|
.try_init();
|
|
|
|
let hash_a: Hash = [0; 32].into();
|
|
let hash_b: Hash = [1; 32].into();
|
|
|
|
let peer = PeerId::random();
|
|
|
|
// validator 0 key pair
|
|
let (mut state, signing_context, keystore, validator) =
|
|
state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| false));
|
|
|
|
// create a signed message by validator 0
|
|
let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
|
|
let signed_bitfield = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload,
|
|
&signing_context,
|
|
ValidatorIndex(0),
|
|
&validator,
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
|
|
let msg = BitfieldGossipMessage {
|
|
relay_parent: hash_a,
|
|
signed_availability: signed_bitfield.clone(),
|
|
};
|
|
|
|
let pool = sp_core::testing::TaskExecutor::new();
|
|
let (ctx, mut handle) = make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
|
let mut rng = dummy_rng();
|
|
let reputation_interval = Duration::from_millis(100);
|
|
|
|
let bg = async move {
|
|
let subsystem = BitfieldDistribution::new(Default::default());
|
|
subsystem.run_inner(ctx, &mut state, reputation_interval, &mut rng).await;
|
|
};
|
|
|
|
let test_fut = async move {
|
|
// send a first message
|
|
handle
|
|
.send(FromOrchestra::Communication {
|
|
msg: BitfieldDistributionMessage::NetworkBridgeUpdate(
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer,
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
),
|
|
})
|
|
.await;
|
|
|
|
// none of our peers has any interest in any messages
|
|
// so we do not receive a network send type message here
|
|
// but only the one for the next subsystem
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::Provisioner(ProvisionerMessage::ProvisionableData(
|
|
_,
|
|
ProvisionableData::Bitfield(hash, signed)
|
|
)) => {
|
|
assert_eq!(hash, hash_a);
|
|
assert_eq!(signed, signed_bitfield)
|
|
}
|
|
);
|
|
|
|
// let peer send the initial message again
|
|
handle
|
|
.send(FromOrchestra::Communication {
|
|
msg: BitfieldDistributionMessage::NetworkBridgeUpdate(
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer,
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
),
|
|
})
|
|
.await;
|
|
|
|
// Wait enough to fire reputation delay
|
|
futures_timer::Delay::new(reputation_interval).await;
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Batch(v))
|
|
) => {
|
|
let mut expected_change = HashMap::new();
|
|
for rep in vec![BENEFIT_VALID_MESSAGE_FIRST, COST_PEER_DUPLICATE_MESSAGE] {
|
|
add_reputation(&mut expected_change, peer, rep)
|
|
}
|
|
assert_eq!(v, expected_change)
|
|
}
|
|
);
|
|
|
|
handle.send(FromOrchestra::Signal(OverseerSignal::Conclude)).await;
|
|
};
|
|
|
|
futures::pin_mut!(bg);
|
|
futures::pin_mut!(test_fut);
|
|
|
|
executor::block_on(futures::future::join(bg, test_fut));
|
|
}
|
|
|
|
#[test]
|
|
fn do_not_relay_message_twice() {
|
|
let _ = env_logger::builder()
|
|
.filter(None, log::LevelFilter::Trace)
|
|
.is_test(true)
|
|
.try_init();
|
|
|
|
let hash = Hash::random();
|
|
|
|
let peer_a = PeerId::random();
|
|
let peer_b = PeerId::random();
|
|
assert_ne!(peer_a, peer_b);
|
|
|
|
// validator 0 key pair
|
|
let (mut state, signing_context, keystore, validator) =
|
|
state_with_view(our_view![hash], hash, ReputationAggregator::new(|_| true));
|
|
|
|
// create a signed message by validator 0
|
|
let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
|
|
let signed_bitfield = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload,
|
|
&signing_context,
|
|
ValidatorIndex(0),
|
|
&validator,
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
|
|
state.peer_data.insert(peer_b, peer_data_v1(view![hash]));
|
|
state.peer_data.insert(peer_a, peer_data_v1(view![hash]));
|
|
|
|
let msg =
|
|
BitfieldGossipMessage { relay_parent: hash, signed_availability: signed_bitfield.clone() };
|
|
|
|
let pool = sp_core::testing::TaskExecutor::new();
|
|
let (mut ctx, mut handle) = make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
|
let mut rng = dummy_rng();
|
|
|
|
executor::block_on(async move {
|
|
let mut gossip_peers = GridNeighbors::empty();
|
|
gossip_peers.peers_x = HashSet::from_iter(vec![peer_a, peer_b].into_iter());
|
|
|
|
relay_message(
|
|
&mut ctx,
|
|
state.per_relay_parent.get_mut(&hash).unwrap(),
|
|
&gossip_peers,
|
|
&mut state.peer_data,
|
|
validator.clone(),
|
|
msg.clone(),
|
|
RequiredRouting::GridXY,
|
|
&mut rng,
|
|
)
|
|
.await;
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::Provisioner(ProvisionerMessage::ProvisionableData(
|
|
_,
|
|
ProvisionableData::Bitfield(h, signed)
|
|
)) => {
|
|
assert_eq!(h, hash);
|
|
assert_eq!(signed, signed_bitfield)
|
|
}
|
|
);
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::SendValidationMessage(peers, send_msg),
|
|
) => {
|
|
assert_eq!(2, peers.len());
|
|
assert!(peers.contains(&peer_a));
|
|
assert!(peers.contains(&peer_b));
|
|
assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V1.into()));
|
|
}
|
|
);
|
|
|
|
// Relaying the message a second time shouldn't work.
|
|
relay_message(
|
|
&mut ctx,
|
|
state.per_relay_parent.get_mut(&hash).unwrap(),
|
|
&gossip_peers,
|
|
&mut state.peer_data,
|
|
validator.clone(),
|
|
msg.clone(),
|
|
RequiredRouting::GridXY,
|
|
&mut rng,
|
|
)
|
|
.await;
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::Provisioner(ProvisionerMessage::ProvisionableData(
|
|
_,
|
|
ProvisionableData::Bitfield(h, signed)
|
|
)) => {
|
|
assert_eq!(h, hash);
|
|
assert_eq!(signed, signed_bitfield)
|
|
}
|
|
);
|
|
|
|
// There shouldn't be any other message
|
|
assert!(handle.recv().timeout(TIMEOUT).await.is_none());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn changing_view() {
|
|
let _ = env_logger::builder()
|
|
.filter(None, log::LevelFilter::Trace)
|
|
.is_test(true)
|
|
.try_init();
|
|
|
|
let hash_a: Hash = [0; 32].into();
|
|
let hash_b: Hash = [1; 32].into();
|
|
|
|
let peer_a = PeerId::random();
|
|
let peer_b = PeerId::random();
|
|
assert_ne!(peer_a, peer_b);
|
|
|
|
// validator 0 key pair
|
|
let (mut state, signing_context, keystore, validator) =
|
|
state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| true));
|
|
|
|
// create a signed message by validator 0
|
|
let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
|
|
let signed_bitfield = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload,
|
|
&signing_context,
|
|
ValidatorIndex(0),
|
|
&validator,
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
|
|
let msg = BitfieldGossipMessage {
|
|
relay_parent: hash_a,
|
|
signed_availability: signed_bitfield.clone(),
|
|
};
|
|
|
|
let pool = sp_core::testing::TaskExecutor::new();
|
|
let (mut ctx, mut handle) = make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
|
let mut rng = dummy_rng();
|
|
|
|
executor::block_on(async move {
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerConnected(
|
|
peer_b,
|
|
ObservedRole::Full,
|
|
ValidationVersion::V1.into(),
|
|
None
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
// make peer b interested
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerViewChange(peer_b, view![hash_a, hash_b]),
|
|
&mut rng,
|
|
));
|
|
|
|
assert!(state.peer_data.contains_key(&peer_b));
|
|
|
|
// recv a first message from the network
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_b,
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
// gossip to the overseer
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::Provisioner(ProvisionerMessage::ProvisionableData(
|
|
_,
|
|
ProvisionableData::Bitfield(hash, signed)
|
|
)) => {
|
|
assert_eq!(hash, hash_a);
|
|
assert_eq!(signed, signed_bitfield)
|
|
}
|
|
);
|
|
|
|
// reputation change for peer B
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_b);
|
|
assert_eq!(rep.value, BENEFIT_VALID_MESSAGE_FIRST.cost_or_benefit())
|
|
}
|
|
);
|
|
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerViewChange(peer_b, view![]),
|
|
&mut rng,
|
|
));
|
|
|
|
assert!(state.peer_data.contains_key(&peer_b));
|
|
assert_eq!(
|
|
&state.peer_data.get(&peer_b).expect("Must contain value for peer B").view,
|
|
&view![]
|
|
);
|
|
|
|
// on rx of the same message, since we are not interested,
|
|
// should give penalty
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_b,
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
// reputation change for peer B
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_b);
|
|
assert_eq!(rep.value, COST_PEER_DUPLICATE_MESSAGE.cost_or_benefit())
|
|
}
|
|
);
|
|
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerDisconnected(peer_b),
|
|
&mut rng,
|
|
));
|
|
|
|
// we are not interested in any peers at all anymore
|
|
state.view = our_view![];
|
|
|
|
// on rx of the same message, since we are not interested,
|
|
// should give penalty
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_a,
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
// reputation change for peer B
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_a);
|
|
assert_eq!(rep.value, COST_NOT_IN_VIEW.cost_or_benefit())
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn do_not_send_message_back_to_origin() {
|
|
let _ = env_logger::builder()
|
|
.filter(None, log::LevelFilter::Trace)
|
|
.is_test(true)
|
|
.try_init();
|
|
|
|
let hash: Hash = [0; 32].into();
|
|
|
|
let peer_a = PeerId::random();
|
|
let peer_b = PeerId::random();
|
|
assert_ne!(peer_a, peer_b);
|
|
|
|
// validator 0 key pair
|
|
let (mut state, signing_context, keystore, validator) =
|
|
state_with_view(our_view![hash], hash, ReputationAggregator::new(|_| true));
|
|
|
|
// create a signed message by validator 0
|
|
let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
|
|
let signed_bitfield = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload,
|
|
&signing_context,
|
|
ValidatorIndex(0),
|
|
&validator,
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
|
|
state.peer_data.insert(peer_b, peer_data_v1(view![hash]));
|
|
state.peer_data.insert(peer_a, peer_data_v1(view![hash]));
|
|
|
|
let msg =
|
|
BitfieldGossipMessage { relay_parent: hash, signed_availability: signed_bitfield.clone() };
|
|
|
|
let pool = sp_core::testing::TaskExecutor::new();
|
|
let (mut ctx, mut handle) = make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
|
let mut rng = dummy_rng();
|
|
|
|
executor::block_on(async move {
|
|
// send a first message
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_b,
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::Provisioner(ProvisionerMessage::ProvisionableData(
|
|
_,
|
|
ProvisionableData::Bitfield(hash, signed)
|
|
)) => {
|
|
assert_eq!(hash, hash);
|
|
assert_eq!(signed, signed_bitfield)
|
|
}
|
|
);
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::SendValidationMessage(peers, send_msg),
|
|
) => {
|
|
assert_eq!(1, peers.len());
|
|
assert!(peers.contains(&peer_a));
|
|
assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V1.into()));
|
|
}
|
|
);
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_b);
|
|
assert_eq!(rep.value, BENEFIT_VALID_MESSAGE_FIRST.cost_or_benefit())
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn topology_test() {
|
|
let _ = env_logger::builder()
|
|
.filter(None, log::LevelFilter::Trace)
|
|
.is_test(true)
|
|
.try_init();
|
|
|
|
let hash: Hash = [0; 32].into();
|
|
|
|
// validator 0 key pair
|
|
let (mut state, signing_context, keystore, validator) =
|
|
state_with_view(our_view![hash], hash, ReputationAggregator::new(|_| true));
|
|
|
|
// Create a simple grid without any shuffling. We occupy position 1.
|
|
let topology_peer_info: Vec<_> = (0..49)
|
|
.map(|i| TopologyPeerInfo {
|
|
peer_ids: vec![PeerId::random()],
|
|
validator_index: ValidatorIndex(i as _),
|
|
discovery_id: AuthorityDiscoveryPair::generate().0.public(),
|
|
})
|
|
.collect();
|
|
|
|
let topology = SessionGridTopology::new((0usize..49).collect(), topology_peer_info.clone());
|
|
state.topologies.update_topology(0_u32, topology, Some(ValidatorIndex(1)));
|
|
|
|
let peers_x: Vec<_> = [0, 2, 3, 4, 5, 6]
|
|
.iter()
|
|
.cloned()
|
|
.map(|i| topology_peer_info[i].peer_ids[0])
|
|
.collect();
|
|
|
|
let peers_y: Vec<_> = [8, 15, 22, 29, 36, 43]
|
|
.iter()
|
|
.cloned()
|
|
.map(|i| topology_peer_info[i].peer_ids[0])
|
|
.collect();
|
|
|
|
{
|
|
let t = state.topologies.get_current_topology().local_grid_neighbors();
|
|
for p_x in &peers_x {
|
|
assert!(t.peers_x.contains(p_x));
|
|
}
|
|
for p_y in &peers_y {
|
|
assert!(t.peers_y.contains(p_y));
|
|
}
|
|
}
|
|
|
|
// create a signed message by validator 0
|
|
let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
|
|
let signed_bitfield = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload,
|
|
&signing_context,
|
|
ValidatorIndex(0),
|
|
&validator,
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
|
|
peers_x.iter().chain(peers_y.iter()).for_each(|peer| {
|
|
state.peer_data.insert(*peer, peer_data_v1(view![hash]));
|
|
});
|
|
|
|
let msg =
|
|
BitfieldGossipMessage { relay_parent: hash, signed_availability: signed_bitfield.clone() };
|
|
|
|
let pool = sp_core::testing::TaskExecutor::new();
|
|
let (mut ctx, mut handle) = make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
|
let mut rng = dummy_rng();
|
|
|
|
executor::block_on(async move {
|
|
// send a first message
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peers_x[0],
|
|
msg.clone().into_network_message(ValidationVersion::V1.into()),
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::Provisioner(ProvisionerMessage::ProvisionableData(
|
|
_,
|
|
ProvisionableData::Bitfield(hash, signed)
|
|
)) => {
|
|
assert_eq!(hash, hash);
|
|
assert_eq!(signed, signed_bitfield)
|
|
}
|
|
);
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::SendValidationMessage(peers, send_msg),
|
|
) => {
|
|
let topology = state.topologies.get_current_topology().local_grid_neighbors();
|
|
// It should send message to all peers in y direction and to 4 random peers in x direction
|
|
assert_eq!(peers_y.len() + 4, peers.len());
|
|
assert!(topology.peers_y.iter().all(|peer| peers.contains(&peer)));
|
|
assert!(topology.peers_x.iter().filter(|peer| peers.contains(&peer)).count() == 4);
|
|
// Must never include originator
|
|
assert!(!peers.contains(&peers_x[0]));
|
|
assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V1.into()));
|
|
}
|
|
);
|
|
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peers_x[0]);
|
|
assert_eq!(rep.value, BENEFIT_VALID_MESSAGE_FIRST.cost_or_benefit())
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn need_message_works() {
|
|
let validators = vec![Sr25519Keyring::Alice.pair(), Sr25519Keyring::Bob.pair()];
|
|
|
|
let validator_set = Vec::from_iter(validators.iter().map(|k| ValidatorId::from(k.public())));
|
|
|
|
let signing_context = SigningContext { session_index: 1, parent_hash: Hash::repeat_byte(0x00) };
|
|
let mut state = PerRelayParentData::new(
|
|
signing_context,
|
|
validator_set.clone(),
|
|
PerLeafSpan::new(Arc::new(Span::Disabled), "foo"),
|
|
);
|
|
|
|
let peer_a = PeerId::random();
|
|
let peer_b = PeerId::random();
|
|
assert_ne!(peer_a, peer_b);
|
|
|
|
let pretend_send =
|
|
|state: &mut PerRelayParentData, dest_peer: PeerId, signed_by: &ValidatorId| -> bool {
|
|
if state.message_from_validator_needed_by_peer(&dest_peer, signed_by) {
|
|
state
|
|
.message_sent_to_peer
|
|
.entry(dest_peer)
|
|
.or_default()
|
|
.insert(signed_by.clone());
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
};
|
|
|
|
let pretend_receive =
|
|
|state: &mut PerRelayParentData, source_peer: PeerId, signed_by: &ValidatorId| {
|
|
state
|
|
.message_received_from_peer
|
|
.entry(source_peer)
|
|
.or_default()
|
|
.insert(signed_by.clone());
|
|
};
|
|
|
|
assert!(pretend_send(&mut state, peer_a, &validator_set[0]));
|
|
assert!(pretend_send(&mut state, peer_b, &validator_set[1]));
|
|
// sending the same thing must not be allowed
|
|
assert!(!pretend_send(&mut state, peer_a, &validator_set[0]));
|
|
|
|
// receive by Alice
|
|
pretend_receive(&mut state, peer_a, &validator_set[0]);
|
|
// must be marked as not needed by Alice, so attempt to send to Alice must be false
|
|
assert!(!pretend_send(&mut state, peer_a, &validator_set[0]));
|
|
// but ok for Bob
|
|
assert!(!pretend_send(&mut state, peer_b, &validator_set[1]));
|
|
|
|
// receive by Bob
|
|
pretend_receive(&mut state, peer_a, &validator_set[0]);
|
|
// not ok for Alice
|
|
assert!(!pretend_send(&mut state, peer_a, &validator_set[0]));
|
|
// also not ok for Bob
|
|
assert!(!pretend_send(&mut state, peer_b, &validator_set[1]));
|
|
}
|
|
|
|
#[test]
|
|
fn network_protocol_versioning() {
|
|
let hash_a: Hash = [0; 32].into();
|
|
let hash_b: Hash = [1; 32].into();
|
|
|
|
let peer_a = PeerId::random();
|
|
let peer_b = PeerId::random();
|
|
let peer_c = PeerId::random();
|
|
|
|
let peers = [
|
|
(peer_a, ValidationVersion::V2),
|
|
(peer_b, ValidationVersion::V1),
|
|
(peer_c, ValidationVersion::V2),
|
|
];
|
|
|
|
// validator 0 key pair
|
|
let (mut state, signing_context, keystore, validator) =
|
|
state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| true));
|
|
|
|
let pool = sp_core::testing::TaskExecutor::new();
|
|
let (mut ctx, mut handle) = make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
|
|
let mut rng = dummy_rng();
|
|
|
|
executor::block_on(async move {
|
|
// create a signed message by validator 0
|
|
let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
|
|
let signed_bitfield = Signed::<AvailabilityBitfield>::sign(
|
|
&keystore,
|
|
payload,
|
|
&signing_context,
|
|
ValidatorIndex(0),
|
|
&validator,
|
|
)
|
|
.ok()
|
|
.flatten()
|
|
.expect("should be signed");
|
|
let msg = BitfieldGossipMessage {
|
|
relay_parent: hash_a,
|
|
signed_availability: signed_bitfield.clone(),
|
|
};
|
|
|
|
for (peer, protocol_version) in peers {
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerConnected(
|
|
peer,
|
|
ObservedRole::Full,
|
|
protocol_version.into(),
|
|
None
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerViewChange(peer, view![hash_a, hash_b]),
|
|
&mut rng,
|
|
));
|
|
|
|
assert!(state.peer_data.contains_key(&peer));
|
|
}
|
|
|
|
launch!(handle_network_msg(
|
|
&mut ctx,
|
|
&mut state,
|
|
&Default::default(),
|
|
NetworkBridgeEvent::PeerMessage(
|
|
peer_a,
|
|
msg.clone().into_network_message(ValidationVersion::V2.into()),
|
|
),
|
|
&mut rng,
|
|
));
|
|
|
|
// gossip to the overseer
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::Provisioner(ProvisionerMessage::ProvisionableData(
|
|
_,
|
|
ProvisionableData::Bitfield(hash, signed)
|
|
)) => {
|
|
assert_eq!(hash, hash_a);
|
|
assert_eq!(signed, signed_bitfield)
|
|
}
|
|
);
|
|
|
|
// v1 gossip
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::SendValidationMessage(peers, send_msg),
|
|
) => {
|
|
assert_eq!(peers, vec![peer_b]);
|
|
assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V1.into()));
|
|
}
|
|
);
|
|
|
|
// v2 gossip
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::SendValidationMessage(peers, send_msg),
|
|
) => {
|
|
assert_eq!(peers, vec![peer_c]);
|
|
assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V2.into()));
|
|
}
|
|
);
|
|
|
|
// reputation change
|
|
assert_matches!(
|
|
handle.recv().await,
|
|
AllMessages::NetworkBridgeTx(
|
|
NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep))
|
|
) => {
|
|
assert_eq!(peer, peer_a);
|
|
assert_eq!(rep, BENEFIT_VALID_MESSAGE_FIRST.into())
|
|
}
|
|
);
|
|
});
|
|
}
|