mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 08:11:03 +00:00
Update for new peerset API (#644)
* Reputation changes require reason * Fixes * Bump version
This commit is contained in:
committed by
Gavin Wood
parent
72bfa8c615
commit
7cb57e7ab6
Generated
+154
-154
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -4,7 +4,7 @@ path = "src/main.rs"
|
||||
|
||||
[package]
|
||||
name = "polkadot"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
edition = "2018"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "polkadot-availability-store"
|
||||
description = "Persistent database for parachain data"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-cli"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Polkadot node implementation in Rust."
|
||||
edition = "2018"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-collator"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Collator node implementation"
|
||||
edition = "2018"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-erasure-coding"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-executor"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Polkadot node implementation in Rust."
|
||||
edition = "2018"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-network"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Polkadot-specific networking protocol"
|
||||
edition = "2018"
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
use sp_runtime::{generic::BlockId, traits::ProvideRuntimeApi};
|
||||
use sp_blockchain::Error as ClientError;
|
||||
use sc_network::{config::Roles, PeerId};
|
||||
use sc_network::{config::Roles, PeerId, ReputationChange};
|
||||
use sc_network::consensus_gossip::{
|
||||
self as network_gossip, ValidationResult as GossipValidationResult,
|
||||
ValidatorContext, MessageIntent, ConsensusMessage,
|
||||
@@ -87,35 +87,39 @@ pub(crate) const MAX_CHAIN_HEADS: usize = 5;
|
||||
pub type LeavesVec = ArrayVec<[Hash; MAX_CHAIN_HEADS]>;
|
||||
|
||||
mod benefit {
|
||||
use sc_network::ReputationChange as Rep;
|
||||
/// When a peer sends us a previously-unknown candidate statement.
|
||||
pub const NEW_CANDIDATE: i32 = 100;
|
||||
pub const NEW_CANDIDATE: Rep = Rep::new(100, "Polkadot: New candidate");
|
||||
/// When a peer sends us a previously-unknown attestation.
|
||||
pub const NEW_ATTESTATION: i32 = 50;
|
||||
pub const NEW_ATTESTATION: Rep = Rep::new(50, "Polkadot: New attestation");
|
||||
/// When a peer sends us a previously-unknown message packet.
|
||||
pub const NEW_ICMP_MESSAGES: i32 = 50;
|
||||
pub const NEW_ICMP_MESSAGES: Rep = Rep::new(50, "Polkadot: New ICMP messages");
|
||||
}
|
||||
|
||||
mod cost {
|
||||
use sc_network::ReputationChange as Rep;
|
||||
/// No cost. This will not be reported.
|
||||
pub const NONE: Rep = Rep::new(0, "");
|
||||
/// A peer sent us an attestation and we don't know the candidate.
|
||||
pub const ATTESTATION_NO_CANDIDATE: i32 = -100;
|
||||
pub const ATTESTATION_NO_CANDIDATE: Rep = Rep::new(-100, "Polkadot: No candidate");
|
||||
/// A peer sent us a statement we consider in the future.
|
||||
pub const FUTURE_MESSAGE: i32 = -100;
|
||||
pub const FUTURE_MESSAGE: Rep = Rep::new(-100, "Polkadot: Future message");
|
||||
/// A peer sent us a statement from the past.
|
||||
pub const PAST_MESSAGE: i32 = -30;
|
||||
pub const PAST_MESSAGE: Rep = Rep::new(-30, "Polkadot: Past message");
|
||||
/// A peer sent us a malformed message.
|
||||
pub const MALFORMED_MESSAGE: i32 = -500;
|
||||
pub const MALFORMED_MESSAGE: Rep = Rep::new(-500, "Polkadot: Malformed message");
|
||||
/// A peer sent us a wrongly signed message.
|
||||
pub const BAD_SIGNATURE: i32 = -500;
|
||||
pub const BAD_SIGNATURE: Rep = Rep::new(-500, "Polkadot: Bad signature");
|
||||
/// A peer sent us a bad neighbor packet.
|
||||
pub const BAD_NEIGHBOR_PACKET: i32 = -300;
|
||||
pub const BAD_NEIGHBOR_PACKET: Rep = Rep::new(-300, "Polkadot: Bad neighbor");
|
||||
/// A peer sent us an ICMP queue we haven't advertised a need for.
|
||||
pub const UNNEEDED_ICMP_MESSAGES: i32 = -100;
|
||||
pub const UNNEEDED_ICMP_MESSAGES: Rep = Rep::new(-100, "Polkadot: Unexpected ICMP message");
|
||||
|
||||
/// A peer sent us an ICMP queue with a bad root.
|
||||
pub fn icmp_messages_root_mismatch(n_messages: usize) -> i32 {
|
||||
pub fn icmp_messages_root_mismatch(n_messages: usize) -> Rep {
|
||||
const PER_MESSAGE: i32 = -150;
|
||||
|
||||
(0..n_messages).map(|_| PER_MESSAGE).sum()
|
||||
Rep::new((0..n_messages).map(|_| PER_MESSAGE).sum(), "Polkadot: ICMP root mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,8 +292,10 @@ pub fn register_validator<C: ChainContext + 'static>(
|
||||
) -> RegisteredMessageValidator
|
||||
{
|
||||
let s = service.clone();
|
||||
let report_handle = Box::new(move |peer: &PeerId, cost_benefit| {
|
||||
s.report_peer(peer.clone(), cost_benefit);
|
||||
let report_handle = Box::new(move |peer: &PeerId, cost_benefit: ReputationChange| {
|
||||
if cost_benefit.value != 0 {
|
||||
s.report_peer(peer.clone(), cost_benefit);
|
||||
}
|
||||
});
|
||||
let validator = Arc::new(MessageValidator {
|
||||
report_handle,
|
||||
@@ -355,7 +361,7 @@ impl RegisteredMessageValidator {
|
||||
#[cfg(test)]
|
||||
pub(crate) fn new_test<C: ChainContext + 'static>(
|
||||
chain: C,
|
||||
report_handle: Box<dyn Fn(&PeerId, i32) + Send + Sync>,
|
||||
report_handle: Box<dyn Fn(&PeerId, ReputationChange) + Send + Sync>,
|
||||
) -> Self {
|
||||
let validator = Arc::new(MessageValidator::new_test(chain, report_handle));
|
||||
|
||||
@@ -474,7 +480,7 @@ struct Inner<C: ?Sized> {
|
||||
|
||||
impl<C: ?Sized + ChainContext> Inner<C> {
|
||||
fn validate_neighbor_packet(&mut self, sender: &PeerId, packet: NeighborPacket)
|
||||
-> (GossipValidationResult<Hash>, i32, Vec<Hash>)
|
||||
-> (GossipValidationResult<Hash>, ReputationChange, Vec<Hash>)
|
||||
{
|
||||
let chain_heads = packet.chain_heads;
|
||||
if chain_heads.len() > MAX_CHAIN_HEADS {
|
||||
@@ -494,7 +500,7 @@ impl<C: ?Sized + ChainContext> Inner<C> {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
(GossipValidationResult::Discard, 0, new_topics)
|
||||
(GossipValidationResult::Discard, cost::NONE, new_topics)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,7 +520,7 @@ impl<C: ?Sized + ChainContext> Inner<C> {
|
||||
|
||||
/// An unregistered message validator. Register this with `register_validator`.
|
||||
pub struct MessageValidator<C: ?Sized> {
|
||||
report_handle: Box<dyn Fn(&PeerId, i32) + Send + Sync>,
|
||||
report_handle: Box<dyn Fn(&PeerId, ReputationChange) + Send + Sync>,
|
||||
inner: RwLock<Inner<C>>,
|
||||
}
|
||||
|
||||
@@ -522,7 +528,7 @@ impl<C: ChainContext + ?Sized> MessageValidator<C> {
|
||||
#[cfg(test)]
|
||||
fn new_test(
|
||||
chain: C,
|
||||
report_handle: Box<dyn Fn(&PeerId, i32) + Send + Sync>,
|
||||
report_handle: Box<dyn Fn(&PeerId, ReputationChange) + Send + Sync>,
|
||||
) -> Self where C: Sized {
|
||||
MessageValidator {
|
||||
report_handle,
|
||||
@@ -535,7 +541,7 @@ impl<C: ChainContext + ?Sized> MessageValidator<C> {
|
||||
}
|
||||
}
|
||||
|
||||
fn report(&self, who: &PeerId, cost_benefit: i32) {
|
||||
fn report(&self, who: &PeerId, cost_benefit: ReputationChange) {
|
||||
(self.report_handle)(who, cost_benefit)
|
||||
}
|
||||
}
|
||||
@@ -720,7 +726,7 @@ mod tests {
|
||||
fn message_allowed() {
|
||||
let (tx, _rx) = mpsc::channel();
|
||||
let tx = Mutex::new(tx);
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: i32| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: ReputationChange| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
let validator = MessageValidator::new_test(
|
||||
TestChainContext::default(),
|
||||
report_handle,
|
||||
@@ -803,7 +809,7 @@ mod tests {
|
||||
fn too_many_chain_heads_is_report() {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let tx = Mutex::new(tx);
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: i32| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: ReputationChange| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
let validator = MessageValidator::new_test(
|
||||
TestChainContext::default(),
|
||||
report_handle,
|
||||
@@ -845,7 +851,7 @@ mod tests {
|
||||
fn statement_only_sent_when_candidate_known() {
|
||||
let (tx, _rx) = mpsc::channel();
|
||||
let tx = Mutex::new(tx);
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: i32| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: ReputationChange| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
let validator = MessageValidator::new_test(
|
||||
TestChainContext::default(),
|
||||
report_handle,
|
||||
@@ -922,7 +928,7 @@ mod tests {
|
||||
fn multicasts_icmp_queues_when_building_on_new_leaf() {
|
||||
let (tx, _rx) = mpsc::channel();
|
||||
let tx = Mutex::new(tx);
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: i32| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: ReputationChange| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
|
||||
let hash_a = [1u8; 32].into();
|
||||
let root_a = [11u8; 32].into();
|
||||
@@ -1017,7 +1023,7 @@ mod tests {
|
||||
fn multicasts_icmp_queues_on_neighbor_update() {
|
||||
let (tx, _rx) = mpsc::channel();
|
||||
let tx = Mutex::new(tx);
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: i32| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: ReputationChange| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
|
||||
let hash_a = [1u8; 32].into();
|
||||
let root_a = [11u8; 32].into();
|
||||
@@ -1128,7 +1134,7 @@ mod tests {
|
||||
fn accepts_needed_unknown_icmp_message_queue() {
|
||||
let (tx, _rx) = mpsc::channel();
|
||||
let tx = Mutex::new(tx);
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: i32| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
let report_handle = Box::new(move |peer: &PeerId, cb: ReputationChange| tx.lock().send((peer.clone(), cb)).unwrap());
|
||||
|
||||
let hash_a = [1u8; 32].into();
|
||||
let root_a_messages = vec![
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
//! consider an infinite amount of attestations produced by a misbehaving validator.
|
||||
|
||||
use sc_network::consensus_gossip::{ValidationResult as GossipValidationResult};
|
||||
use sc_network::ReputationChange;
|
||||
use polkadot_validation::GenericStatement;
|
||||
use polkadot_primitives::Hash;
|
||||
|
||||
@@ -39,7 +40,9 @@ use std::collections::{HashMap, HashSet};
|
||||
use log::warn;
|
||||
use crate::router::attestation_topic;
|
||||
|
||||
use super::{cost, benefit, MAX_CHAIN_HEADS, LeavesVec, ChainContext, Known, MessageValidationData, GossipStatement};
|
||||
use super::{cost, benefit, MAX_CHAIN_HEADS, LeavesVec,
|
||||
ChainContext, Known, MessageValidationData, GossipStatement
|
||||
};
|
||||
|
||||
// knowledge about attestations on a single parent-hash.
|
||||
#[derive(Default)]
|
||||
@@ -170,7 +173,7 @@ impl View {
|
||||
message: GossipStatement,
|
||||
chain: &C,
|
||||
)
|
||||
-> (GossipValidationResult<Hash>, i32)
|
||||
-> (GossipValidationResult<Hash>, ReputationChange)
|
||||
{
|
||||
// message must reference one of our chain heads and
|
||||
// if message is not a `Candidate` we should have the candidate available
|
||||
@@ -184,8 +187,7 @@ impl View {
|
||||
"Leaf block {} not considered live for attestation",
|
||||
message.relay_chain_leaf,
|
||||
);
|
||||
|
||||
0
|
||||
cost::NONE
|
||||
}
|
||||
Some(Known::Old) => cost::PAST_MESSAGE,
|
||||
_ => cost::FUTURE_MESSAGE,
|
||||
|
||||
@@ -133,7 +133,7 @@ impl View {
|
||||
/// Validate an incoming message queue against this view. If it is accepted
|
||||
/// by our view of un-routed message queues, we will keep and re-propagate.
|
||||
pub fn validate_queue_and_note_known(&mut self, messages: &super::GossipParachainMessages)
|
||||
-> (GossipValidationResult<Hash>, i32)
|
||||
-> (GossipValidationResult<Hash>, sc_network::ReputationChange)
|
||||
{
|
||||
let ostensible_topic = queue_topic(messages.queue_root);
|
||||
match self.expected_queues.get_mut(&ostensible_topic) {
|
||||
|
||||
+16
-13
@@ -54,23 +54,26 @@ use crate::gossip::{POLKADOT_ENGINE_ID, GossipMessage};
|
||||
mod tests;
|
||||
|
||||
mod cost {
|
||||
pub(super) const UNEXPECTED_MESSAGE: i32 = -200;
|
||||
pub(super) const INVALID_FORMAT: i32 = -200;
|
||||
use sc_network::ReputationChange as Rep;
|
||||
pub(super) const UNEXPECTED_MESSAGE: Rep = Rep::new(-200, "Polkadot: Unexpected message");
|
||||
pub(super) const UNEXPECTED_ROLE: Rep = Rep::new(-200, "Polkadot: Unexpected role");
|
||||
pub(super) const INVALID_FORMAT: Rep = Rep::new(-200, "Polkadot: Bad message");
|
||||
|
||||
pub(super) const UNKNOWN_PEER: i32 = -50;
|
||||
pub(super) const COLLATOR_ALREADY_KNOWN: i32 = -100;
|
||||
pub(super) const BAD_COLLATION: i32 = -1000;
|
||||
pub(super) const BAD_POV_BLOCK: i32 = -1000;
|
||||
pub(super) const UNKNOWN_PEER: Rep = Rep::new(-50, "Polkadot: Unknown peer");
|
||||
pub(super) const COLLATOR_ALREADY_KNOWN: Rep = Rep::new( -100, "Polkadot: Known collator");
|
||||
pub(super) const BAD_COLLATION: Rep = Rep::new(-1000, "Polkadot: Bad collation");
|
||||
pub(super) const BAD_POV_BLOCK: Rep = Rep::new(-1000, "Polkadot: Bad POV block");
|
||||
}
|
||||
|
||||
mod benefit {
|
||||
pub(super) const EXPECTED_MESSAGE: i32 = 20;
|
||||
pub(super) const VALID_FORMAT: i32 = 20;
|
||||
use sc_network::ReputationChange as Rep;
|
||||
pub(super) const EXPECTED_MESSAGE: Rep = Rep::new(20, "Polkadot: Expected message");
|
||||
pub(super) const VALID_FORMAT: Rep = Rep::new(20, "Polkadot: Valid message format");
|
||||
|
||||
pub(super) const KNOWN_PEER: i32 = 5;
|
||||
pub(super) const NEW_COLLATOR: i32 = 10;
|
||||
pub(super) const GOOD_COLLATION: i32 = 100;
|
||||
pub(super) const GOOD_POV_BLOCK: i32 = 100;
|
||||
pub(super) const KNOWN_PEER: Rep = Rep::new(5, "Polkadot: Known peer");
|
||||
pub(super) const NEW_COLLATOR: Rep = Rep::new(10, "Polkadot: New collator");
|
||||
pub(super) const GOOD_COLLATION: Rep = Rep::new(100, "Polkadot: Good collation");
|
||||
pub(super) const GOOD_POV_BLOCK: Rep = Rep::new(100, "Polkadot: Good POV block");
|
||||
}
|
||||
|
||||
type FullStatus = GenericFullStatus<Block>;
|
||||
@@ -553,7 +556,7 @@ impl PolkadotProtocol {
|
||||
debug!(target: "p_net", "New collator role {:?} from {}", role, who);
|
||||
|
||||
if info.validator_keys.as_slice().is_empty() {
|
||||
ctx.report_peer(who, cost::UNEXPECTED_MESSAGE);
|
||||
ctx.report_peer(who, cost::UNEXPECTED_ROLE)
|
||||
} else {
|
||||
// update role for all saved session keys for this validator.
|
||||
let local_collations = &mut self.local_collations;
|
||||
|
||||
@@ -29,7 +29,7 @@ use polkadot_primitives::parachain::{
|
||||
use sp_core::crypto::UncheckedInto;
|
||||
use codec::Encode;
|
||||
use sc_network::{
|
||||
PeerId, Context, config::Roles, message::generic::ConsensusMessage,
|
||||
PeerId, Context, ReputationChange, config::Roles, message::generic::ConsensusMessage,
|
||||
specialization::NetworkSpecialization,
|
||||
};
|
||||
|
||||
@@ -46,8 +46,8 @@ struct TestContext {
|
||||
}
|
||||
|
||||
impl Context<Block> for TestContext {
|
||||
fn report_peer(&mut self, peer: PeerId, reputation: i32) {
|
||||
let reputation = self.reputations.get(&peer).map_or(reputation, |v| v + reputation);
|
||||
fn report_peer(&mut self, peer: PeerId, reputation: ReputationChange) {
|
||||
let reputation = self.reputations.get(&peer).map_or(reputation.value, |v| v + reputation.value);
|
||||
self.reputations.insert(peer.clone(), reputation);
|
||||
|
||||
match reputation {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-parachain"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Types and utilities for creating and working with parachains"
|
||||
edition = "2018"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-primitives"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-rpc"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-runtime"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
||||
@@ -97,7 +97,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: create_runtime_str!("kusama"),
|
||||
impl_name: create_runtime_str!("parity-kusama"),
|
||||
authoring_version: 2,
|
||||
spec_version: 1024,
|
||||
spec_version: 1025,
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-service"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-statement-table"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "adder"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Test parachain which adds to a number as its state transition"
|
||||
edition = "2018"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "halt"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Test parachain which executes forever"
|
||||
edition = "2018"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "polkadot-validation"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user