From ed5079c70dd71318229faa73574240852b9f99b4 Mon Sep 17 00:00:00 2001 From: Jacek Malec <145967538+jacek-casper@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:52:33 +0000 Subject: [PATCH 1/7] Implementation for 'Part 2 : Update Gossipers' Signed-off-by: Jacek Malec <145967538+jacek-casper@users.noreply.github.com> --- node/src/components/block_accumulator.rs | 11 +- .../block_accumulator/block_acceptor.rs | 12 +- .../src/components/block_accumulator/tests.rs | 342 +++++++++---- .../block_synchronizer/block_builder/tests.rs | 48 +- .../signature_acquisition.rs | 89 +++- .../components/block_synchronizer/tests.rs | 126 ++++- .../event_stream_server/sse_server.rs | 6 +- node/src/components/network/limiter.rs | 3 +- node/src/components/storage.rs | 75 +-- node/src/components/storage/tests.rs | 91 +++- .../components/storage/versioned_databases.rs | 8 +- node/src/effect/requests.rs | 2 +- node/src/reactor/main_reactor.rs | 1 + node/src/types/sync_leap.rs | 162 +++++-- node/src/types/validator_matrix.rs | 31 +- node/src/utils/block_signatures.rs | 54 ++- node/src/utils/specimen.rs | 38 +- types/src/block.rs | 8 +- types/src/block/block_signatures.rs | 448 +++++++++++++----- .../block_signatures/block_signatures_v1.rs | 165 +++++++ .../block_signatures/block_signatures_v2.rs | 200 ++++++++ types/src/block/chain_name_digest.rs | 98 ++++ types/src/block/finality_signature.rs | 281 +++-------- .../finality_signature_v1.rs | 265 +++++++++++ .../finality_signature_v2.rs | 351 ++++++++++++++ .../json_block_with_signatures.rs | 26 +- types/src/block/signed_block_header.rs | 11 +- types/src/chainspec.rs | 7 +- types/src/lib.rs | 7 +- 29 files changed, 2337 insertions(+), 629 deletions(-) create mode 100644 types/src/block/block_signatures/block_signatures_v1.rs create mode 100644 types/src/block/block_signatures/block_signatures_v2.rs create mode 100644 types/src/block/chain_name_digest.rs create mode 100644 types/src/block/finality_signature/finality_signature_v1.rs create mode 100644 types/src/block/finality_signature/finality_signature_v2.rs diff --git a/node/src/components/block_accumulator.rs b/node/src/components/block_accumulator.rs index b4668733e7..408fad90cf 100644 --- a/node/src/components/block_accumulator.rs +++ b/node/src/components/block_accumulator.rs @@ -23,8 +23,8 @@ use prometheus::Registry; use tracing::{debug, error, info, warn}; use casper_types::{ - ActivationPoint, Block, BlockHash, BlockSignatures, EraId, FinalitySignature, TimeDiff, - Timestamp, + ActivationPoint, Block, BlockHash, BlockSignatures, BlockSignaturesV1, EraId, + FinalitySignature, TimeDiff, Timestamp, }; use crate::{ @@ -737,13 +737,14 @@ impl BlockAccumulator { ShouldStore::SingleSignature(signature) => { debug!(%signature, "storing finality signature"); let mut block_signatures = - BlockSignatures::new(*signature.block_hash(), signature.era_id()); - block_signatures.insert_signature(signature.clone()); + BlockSignaturesV1::new(*signature.block_hash(), signature.era_id()); + block_signatures + .insert_signature(signature.public_key().clone(), *signature.signature()); effect_builder .put_finality_signature_to_storage(signature) .event(move |_| Event::Stored { maybe_meta_block: None, - maybe_block_signatures: Some(block_signatures), + maybe_block_signatures: Some(block_signatures.into()), }) } ShouldStore::Nothing => { diff --git a/node/src/components/block_accumulator/block_acceptor.rs b/node/src/components/block_accumulator/block_acceptor.rs index a454ab4e18..440f65ddfc 100644 --- a/node/src/components/block_accumulator/block_acceptor.rs +++ b/node/src/components/block_accumulator/block_acceptor.rs @@ -5,7 +5,8 @@ use itertools::Itertools; use tracing::{debug, error, warn}; use casper_types::{ - ActivationPoint, BlockHash, BlockSignatures, EraId, FinalitySignature, PublicKey, Timestamp, + ActivationPoint, BlockHash, BlockSignatures, BlockSignaturesV1, EraId, FinalitySignature, + PublicKey, Timestamp, }; use crate::{ @@ -241,9 +242,10 @@ impl BlockAcceptor { self.touch(); if let Some(meta_block) = self.meta_block.as_mut() { let mut block_signatures = - BlockSignatures::new(*meta_block.block.hash(), meta_block.block.era_id()); + BlockSignaturesV1::new(*meta_block.block.hash(), meta_block.block.era_id()); self.signatures.values().for_each(|(signature, _)| { - block_signatures.insert_signature(signature.clone()); + block_signatures + .insert_signature(signature.public_key().clone(), *signature.signature()); }); if meta_block .state @@ -275,7 +277,7 @@ impl BlockAcceptor { return ( ShouldStore::CompletedBlock { meta_block: meta_block.clone(), - block_signatures, + block_signatures: block_signatures.into(), }, faulty_senders, ); @@ -295,7 +297,7 @@ impl BlockAcceptor { return ( ShouldStore::SufficientlySignedBlock { meta_block: meta_block.clone(), - block_signatures, + block_signatures: block_signatures.into(), }, faulty_senders, ); diff --git a/node/src/components/block_accumulator/tests.rs b/node/src/components/block_accumulator/tests.rs index 10c31857e6..8da2cb6f76 100644 --- a/node/src/components/block_accumulator/tests.rs +++ b/node/src/components/block_accumulator/tests.rs @@ -15,8 +15,9 @@ use thiserror::Error as ThisError; use tokio::time; use casper_types::{ - generate_ed25519_keypair, testing::TestRng, ActivationPoint, BlockV2, Chainspec, - ChainspecRawBytes, ProtocolVersion, PublicKey, SecretKey, Signature, TestBlockBuilder, U512, + generate_ed25519_keypair, testing::TestRng, ActivationPoint, BlockSignaturesV2, BlockV2, + ChainNameDigest, Chainspec, ChainspecRawBytes, FinalitySignatureV2, ProtocolVersion, PublicKey, + SecretKey, Signature, TestBlockBuilder, U512, }; use reactor::ReactorEvent; @@ -52,12 +53,21 @@ fn meta_block_with_default_state(block: Arc) -> ForwardMetaBlock { .unwrap() } -fn signatures_for_block(block: &BlockV2, signatures: &Vec) -> BlockSignatures { - let mut block_signatures = BlockSignatures::new(*block.hash(), block.era_id()); +fn signatures_for_block( + block: &BlockV2, + signatures: &[FinalitySignatureV2], + chain_name_hash: ChainNameDigest, +) -> BlockSignatures { + let mut block_signatures = BlockSignaturesV2::new( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + ); for signature in signatures { - block_signatures.insert_signature(signature.clone()); + block_signatures.insert_signature(signature.public_key().clone(), *signature.signature()); } - block_signatures + BlockSignatures::V2(block_signatures) } /// Top-level event for the reactor. @@ -394,9 +404,10 @@ fn acceptor_get_peers() { #[test] fn acceptor_register_finality_signature() { - let mut rng = TestRng::new(); + let rng = &mut TestRng::new(); // Create a block and an acceptor for it. - let block = Arc::new(TestBlockBuilder::new().build(&mut rng)); + let block = Arc::new(TestBlockBuilder::new().build(rng)); + let chain_name_hash = ChainNameDigest::random(rng); let mut meta_block: ForwardMetaBlock = MetaBlock::new_forward(block.clone(), vec![], MetaBlockState::new()) .try_into() @@ -404,8 +415,13 @@ fn acceptor_register_finality_signature() { let mut acceptor = BlockAcceptor::new(*block.hash(), vec![]); // Create a finality signature with the wrong block hash. - let wrong_fin_sig = - FinalitySignature::random_for_block(BlockHash::random(&mut rng), EraId::new(0), &mut rng); + let wrong_fin_sig = FinalitySignature::random_for_block( + BlockHash::random(rng), + rng.gen(), + EraId::new(0), + ChainNameDigest::random(rng), + rng, + ); assert!(matches!( acceptor .register_finality_signature(wrong_fin_sig, None, VALIDATOR_SLOTS) @@ -417,36 +433,44 @@ fn acceptor_register_finality_signature() { )); // Create an invalid finality signature. - let invalid_fin_sig = FinalitySignature::new( + let invalid_fin_sig = FinalitySignatureV2::new( *block.hash(), - EraId::random(&mut rng), + block.height(), + EraId::random(rng), + chain_name_hash, Signature::System, - PublicKey::random(&mut rng), + PublicKey::random(rng), ); // We shouldn't be able to create invalid signatures ourselves, so we've // reached an invalid state. assert!(matches!( acceptor - .register_finality_signature(invalid_fin_sig.clone(), None, VALIDATOR_SLOTS) + .register_finality_signature(invalid_fin_sig.clone().into(), None, VALIDATOR_SLOTS) .unwrap_err(), Error::InvalidConfiguration )); // Peers shouldn't send us invalid signatures. - let first_peer = NodeId::random(&mut rng); + let first_peer = NodeId::random(rng); assert!(matches!( acceptor - .register_finality_signature(invalid_fin_sig, Some(first_peer), VALIDATOR_SLOTS) + .register_finality_signature(invalid_fin_sig.into(), Some(first_peer), VALIDATOR_SLOTS) .unwrap_err(), Error::InvalidGossip(_) )); // Create a valid finality signature and register it. - let fin_sig = FinalitySignature::random_for_block(*block.hash(), block.era_id(), &mut rng); + let fin_sig = FinalitySignature::random_for_block( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + rng, + ); assert!(acceptor .register_finality_signature(fin_sig.clone(), Some(first_peer), VALIDATOR_SLOTS) .unwrap() .is_none()); // Register it from the second peer as well. - let second_peer = NodeId::random(&mut rng); + let second_peer = NodeId::random(rng); assert!(acceptor .register_finality_signature(fin_sig.clone(), Some(second_peer), VALIDATOR_SLOTS) .unwrap() @@ -456,8 +480,13 @@ fn acceptor_register_finality_signature() { assert_eq!(*sig, fin_sig); assert_eq!(*senders, BTreeSet::from([first_peer, second_peer])); // Create a second finality signature and register it. - let second_fin_sig = - FinalitySignature::random_for_block(*block.hash(), block.era_id(), &mut rng); + let second_fin_sig = FinalitySignature::random_for_block( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + rng, + ); assert!(acceptor .register_finality_signature(second_fin_sig.clone(), Some(first_peer), VALIDATOR_SLOTS) .unwrap() @@ -484,7 +513,13 @@ fn acceptor_register_finality_signature() { .unwrap(); // Registering invalid signatures should still yield an error. let wrong_era = EraId::from(u64::MAX ^ u64::from(block.era_id())); - let invalid_fin_sig = FinalitySignature::random_for_block(*block.hash(), wrong_era, &mut rng); + let invalid_fin_sig = FinalitySignature::random_for_block( + *block.hash(), + block.height(), + wrong_era, + chain_name_hash, + rng, + ); assert!(matches!( acceptor .register_finality_signature(invalid_fin_sig.clone(), Some(first_peer), VALIDATOR_SLOTS) @@ -517,8 +552,13 @@ fn acceptor_register_finality_signature() { .1 .contains(&second_peer)); // Register a new valid signature which should be yielded by the function. - let third_fin_sig = - FinalitySignature::random_for_block(*block.hash(), block.era_id(), &mut rng); + let third_fin_sig = FinalitySignature::random_for_block( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + rng, + ); assert_eq!( acceptor .register_finality_signature(third_fin_sig.clone(), Some(first_peer), VALIDATOR_SLOTS) @@ -622,6 +662,7 @@ fn acceptor_should_store_block() { let mut rng = TestRng::new(); // Create a block and an acceptor for it. let block = Arc::new(TestBlockBuilder::new().build(&mut rng)); + let chain_name_hash = ChainNameDigest::random(&mut rng); let mut meta_block = meta_block_with_default_state(block.clone()); let mut acceptor = BlockAcceptor::new(*block.hash(), vec![]); @@ -665,11 +706,17 @@ fn acceptor_should_store_block() { let mut signatures = vec![]; // Create the first validator's signature. - let fin_sig = FinalitySignature::create(*block.hash(), block.era_id(), &keys[0].0); + let fin_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &keys[0].0, + ); signatures.push(fin_sig.clone()); // First signature with 40% weight brings the block to weak finality. acceptor - .register_finality_signature(fin_sig, None, VALIDATOR_SLOTS) + .register_finality_signature(fin_sig.into(), None, VALIDATOR_SLOTS) .unwrap(); let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); assert_eq!(should_store, ShouldStore::Nothing); @@ -680,12 +727,18 @@ fn acceptor_should_store_block() { assert_eq!(should_store, ShouldStore::Nothing); // Create the third validator's signature. - let fin_sig = FinalitySignature::create(*block.hash(), block.era_id(), &keys[2].0); + let fin_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &keys[2].0, + ); // The third signature with weight 10% doesn't make the block go to // strict finality. signatures.push(fin_sig.clone()); acceptor - .register_finality_signature(fin_sig, None, VALIDATOR_SLOTS) + .register_finality_signature(fin_sig.into(), None, VALIDATOR_SLOTS) .unwrap(); let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); assert_eq!(should_store, ShouldStore::Nothing); @@ -693,9 +746,15 @@ fn acceptor_should_store_block() { // Create a bogus signature from a non-validator for this era. let non_validator_keys = generate_ed25519_keypair(); let faulty_peer = NodeId::random(&mut rng); - let bogus_sig = FinalitySignature::create(*block.hash(), block.era_id(), &non_validator_keys.0); + let bogus_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &non_validator_keys.0, + ); acceptor - .register_finality_signature(bogus_sig, Some(faulty_peer), VALIDATOR_SLOTS) + .register_finality_signature(bogus_sig.into(), Some(faulty_peer), VALIDATOR_SLOTS) .unwrap(); let (should_store, offenders) = acceptor.should_store_block(&era_validator_weights); assert_eq!(should_store, ShouldStore::Nothing); @@ -704,14 +763,20 @@ fn acceptor_should_store_block() { assert_eq!(offenders[0].0, faulty_peer); // Create the second validator's signature. - let fin_sig = FinalitySignature::create(*block.hash(), block.era_id(), &keys[1].0); + let fin_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &keys[1].0, + ); signatures.push(fin_sig.clone()); // Second signature with 40% weight brings the block to strict finality. acceptor - .register_finality_signature(fin_sig, None, VALIDATOR_SLOTS) + .register_finality_signature(fin_sig.into(), None, VALIDATOR_SLOTS) .unwrap(); let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); - let block_signatures = signatures_for_block(&block, &signatures); + let block_signatures = signatures_for_block(&block, &signatures, chain_name_hash); let mut meta_block_with_expected_state = meta_block.clone(); meta_block_with_expected_state.state.register_as_stored(); meta_block_with_expected_state @@ -726,11 +791,17 @@ fn acceptor_should_store_block() { ); // Create the fourth validator's signature. - let fin_sig = FinalitySignature::create(*block.hash(), block.era_id(), &keys[3].0); + let fin_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &keys[3].0, + ); // Already have sufficient finality signatures, so we're not supposed to // store anything else. acceptor - .register_finality_signature(fin_sig, None, VALIDATOR_SLOTS) + .register_finality_signature(fin_sig.into(), None, VALIDATOR_SLOTS) .unwrap(); let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); assert_eq!(should_store, ShouldStore::Nothing); @@ -756,20 +827,33 @@ fn acceptor_should_correctly_bound_the_signatures() { // Create a block and an acceptor for it. let block = Arc::new(TestBlockBuilder::new().build(&mut rng)); + let chain_name_hash = ChainNameDigest::random(&mut rng); let mut acceptor = BlockAcceptor::new(*block.hash(), vec![]); let first_peer = NodeId::random(&mut rng); // Fill the signatures map: - for fin_sig in (0..validator_slots * 2) - .map(|_| FinalitySignature::random_for_block(*block.hash(), block.era_id(), &mut rng)) - { + for fin_sig in (0..validator_slots * 2).map(|_| { + FinalitySignature::random_for_block( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &mut rng, + ) + }) { assert!(acceptor .register_finality_signature(fin_sig, Some(first_peer), validator_slots) .unwrap() .is_none()); } - let fin_sig = FinalitySignature::random_for_block(*block.hash(), block.era_id(), &mut rng); + let fin_sig = FinalitySignature::random_for_block( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &mut rng, + ); assert!(matches!( acceptor.register_finality_signature(fin_sig, Some(first_peer), validator_slots), Err(Error::TooManySignatures { .. }), @@ -783,14 +867,21 @@ fn acceptor_signatures_bound_should_not_be_triggered_if_peers_are_different() { // Create a block and an acceptor for it. let block = Arc::new(TestBlockBuilder::new().build(&mut rng)); + let chain_name_hash = ChainNameDigest::random(&mut rng); let mut acceptor = BlockAcceptor::new(*block.hash(), vec![]); let first_peer = NodeId::random(&mut rng); let second_peer = NodeId::random(&mut rng); // Fill the signatures map: - for fin_sig in (0..validator_slots) - .map(|_| FinalitySignature::random_for_block(*block.hash(), block.era_id(), &mut rng)) - { + for fin_sig in (0..validator_slots).map(|_| { + FinalitySignature::random_for_block( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &mut rng, + ) + }) { assert!(acceptor .register_finality_signature(fin_sig, Some(first_peer), validator_slots) .unwrap() @@ -798,7 +889,13 @@ fn acceptor_signatures_bound_should_not_be_triggered_if_peers_are_different() { } // This should pass, because it is another peer: - let fin_sig = FinalitySignature::random_for_block(*block.hash(), block.era_id(), &mut rng); + let fin_sig = FinalitySignature::random_for_block( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &mut rng, + ); assert!(acceptor .register_finality_signature(fin_sig, Some(second_peer), validator_slots) .unwrap() @@ -824,6 +921,7 @@ fn accumulator_should_leap() { .unwrap(); let era_id = EraId::from(0); + let chain_name_hash = ChainNameDigest::random(&mut rng); // Register the era in the validator matrix so the block is valid. register_evw_for_era(&mut validator_matrix, era_id); @@ -865,7 +963,7 @@ fn accumulator_should_leap() { block_accumulator .block_acceptors - .insert(*block.hash(), block_acceptor(block)); + .insert(*block.hash(), block_acceptor(block, chain_name_hash)); } expected_leap_instruction( @@ -884,7 +982,7 @@ fn accumulator_should_leap() { block_accumulator .block_acceptors - .insert(*block.hash(), block_acceptor(block)); + .insert(*block.hash(), block_acceptor(block, chain_name_hash)); } expected_leap_instruction( @@ -905,7 +1003,7 @@ fn accumulator_should_leap() { block_accumulator .block_acceptors - .insert(*block.hash(), block_acceptor(block)); + .insert(*block.hash(), block_acceptor(block, chain_name_hash)); } expected_leap_instruction( @@ -977,12 +1075,19 @@ fn expected_leap_instruction(expected: LeapInstruction, actual: LeapInstruction) ); } -fn block_acceptor(block: BlockV2) -> BlockAcceptor { +fn block_acceptor(block: BlockV2, chain_name_hash: ChainNameDigest) -> BlockAcceptor { let mut acceptor = BlockAcceptor::new(*block.hash(), vec![]); // One finality signature from our only validator for block 1. acceptor .register_finality_signature( - FinalitySignature::create(*block.hash(), block.era_id(), &ALICE_SECRET_KEY), + FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ) + .into(), None, VALIDATOR_SLOTS, ) @@ -1029,12 +1134,32 @@ fn accumulator_purge() { let peer_1 = NodeId::random(&mut rng); let peer_2 = NodeId::random(&mut rng); + let chain_name_hash = ChainNameDigest::random(&mut rng); + // One finality signature from our only validator for block 1. - let fin_sig_1 = FinalitySignature::create(*block_1.hash(), block_1.era_id(), &ALICE_SECRET_KEY); + let fin_sig_1 = FinalitySignatureV2::create( + *block_1.hash(), + block_1.height(), + block_1.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // One finality signature from our only validator for block 2. - let fin_sig_2 = FinalitySignature::create(*block_2.hash(), block_2.era_id(), &ALICE_SECRET_KEY); + let fin_sig_2 = FinalitySignatureV2::create( + *block_2.hash(), + block_2.height(), + block_2.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // One finality signature from our only validator for block 3. - let fin_sig_3 = FinalitySignature::create(*block_3.hash(), block_3.era_id(), &ALICE_SECRET_KEY); + let fin_sig_3 = FinalitySignatureV2::create( + *block_3.hash(), + block_3.height(), + block_3.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // Register the eras in the validator matrix so the blocks are valid. { @@ -1058,7 +1183,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(fin_sig_1, Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature(fin_sig_1.into(), Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, None).unwrap(); } @@ -1077,7 +1202,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(fin_sig_2, Some(peer_2), VALIDATOR_SLOTS) + .register_finality_signature(fin_sig_2.into(), Some(peer_2), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, None).unwrap(); } @@ -1096,7 +1221,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(fin_sig_3, Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature(fin_sig_3.into(), Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1193,9 +1318,11 @@ fn accumulator_purge() { .build(&mut rng), ); - let in_range_block_sig = FinalitySignature::create( + let in_range_block_sig = FinalitySignatureV2::create( *in_range_block.hash(), + in_range_block.height(), in_range_block.era_id(), + chain_name_hash, &ALICE_SECRET_KEY, ); @@ -1216,7 +1343,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(in_range_block_sig, Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature(in_range_block_sig.into(), Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1230,9 +1357,11 @@ fn accumulator_purge() { .switch_block(false) .build(&mut rng), ); - let out_of_range_block_sig = FinalitySignature::create( + let out_of_range_block_sig = FinalitySignatureV2::create( *out_of_range_block.hash(), + out_of_range_block.height(), out_of_range_block.era_id(), + chain_name_hash, &ALICE_SECRET_KEY, ); @@ -1253,7 +1382,11 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(out_of_range_block_sig, Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature( + out_of_range_block_sig.into(), + Some(peer_1), + VALIDATOR_SLOTS, + ) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1313,9 +1446,11 @@ fn accumulator_purge() { .switch_block(false) .build(&mut rng), ); - let future_block_sig = FinalitySignature::create( + let future_block_sig = FinalitySignatureV2::create( *future_block.hash(), + future_block.height(), future_block.era_id(), + chain_name_hash, &ALICE_SECRET_KEY, ); @@ -1336,7 +1471,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(future_block_sig, Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature(future_block_sig.into(), Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1351,9 +1486,11 @@ fn accumulator_purge() { .switch_block(false) .build(&mut rng), ); - let future_unsigned_block_sig = FinalitySignature::create( + let future_unsigned_block_sig = FinalitySignatureV2::create( *future_unsigned_block.hash(), + future_unsigned_block.height(), future_unsigned_block.era_id(), + chain_name_hash, &ALICE_SECRET_KEY, ); @@ -1373,7 +1510,11 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(future_unsigned_block_sig, Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature( + future_unsigned_block_sig.into(), + Some(peer_1), + VALIDATOR_SLOTS, + ) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1492,10 +1633,24 @@ async fn block_accumulator_reactor_flow() { let peer_1 = NodeId::random(&mut rng); let peer_2 = NodeId::random(&mut rng); + let chain_name_hash = ChainNameDigest::random(&mut rng); + // One finality signature from our only validator for block 1. - let fin_sig_1 = FinalitySignature::create(*block_1.hash(), block_1.era_id(), &ALICE_SECRET_KEY); + let fin_sig_1 = FinalitySignatureV2::create( + *block_1.hash(), + block_1.height(), + block_1.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // One finality signature from our only validator for block 2. - let fin_sig_2 = FinalitySignature::create(*block_2.hash(), block_2.era_id(), &ALICE_SECRET_KEY); + let fin_sig_2 = FinalitySignatureV2::create( + *block_2.hash(), + block_2.height(), + block_2.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // Register the eras in the validator matrix so the blocks are valid. { @@ -1513,7 +1668,7 @@ async fn block_accumulator_reactor_flow() { block_accumulator.register_local_tip(0, 0.into()); let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(fin_sig_1.clone()), + finality_signature: Box::new(fin_sig_1.clone().into()), sender: peer_1, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); @@ -1554,7 +1709,7 @@ async fn block_accumulator_reactor_flow() { expected_block_signatures .and_then(|sigs| sigs.finality_signature(fin_sig_1.public_key())) .unwrap(), - fin_sig_1 + FinalitySignature::from(fin_sig_1) ); } @@ -1577,7 +1732,7 @@ async fn block_accumulator_reactor_flow() { runner .process_injected_effects(|effect_builder| { let event = super::Event::CreatedFinalitySignature { - finality_signature: Box::new(fin_sig_2.clone()), + finality_signature: Box::new(fin_sig_2.clone().into()), }; effect_builder .into_inner() @@ -1606,7 +1761,7 @@ async fn block_accumulator_reactor_flow() { expected_block_signatures .and_then(|sigs| sigs.finality_signature(fin_sig_2.public_key())) .unwrap(), - fin_sig_2 + FinalitySignature::from(fin_sig_2) ); } @@ -1778,8 +1933,13 @@ async fn block_accumulator_reactor_flow() { .contains_key(older_block.hash())); } - let older_block_signature = - FinalitySignature::create(*older_block.hash(), older_block.era_id(), &ALICE_SECRET_KEY); + let older_block_signature = FinalitySignatureV2::create( + *older_block.hash(), + older_block.height(), + older_block.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // Register a signature for an older block. { let effect_builder = runner.effect_builder(); @@ -1787,7 +1947,7 @@ async fn block_accumulator_reactor_flow() { let block_accumulator = &mut reactor.block_accumulator; let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(older_block_signature), + finality_signature: Box::new(older_block_signature.into()), sender: peer_2, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); @@ -1807,9 +1967,11 @@ async fn block_accumulator_reactor_flow() { .switch_block(false) .build(&mut rng); - let old_era_signature = FinalitySignature::create( + let old_era_signature = FinalitySignatureV2::create( *old_era_block.hash(), + old_era_block.height(), old_era_block.era_id(), + chain_name_hash, &ALICE_SECRET_KEY, ); // Register a signature for a block in an old era. @@ -1819,7 +1981,7 @@ async fn block_accumulator_reactor_flow() { let block_accumulator = &mut reactor.block_accumulator; let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(old_era_signature), + finality_signature: Box::new(old_era_signature.into()), sender: peer_2, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); @@ -1853,13 +2015,31 @@ async fn block_accumulator_doesnt_purge_with_delayed_block_execution() { let peer_1 = NodeId::random(&mut rng); let peer_2 = NodeId::random(&mut rng); - let fin_sig_bob = FinalitySignature::create(*block_1.hash(), block_1.era_id(), &BOB_SECRET_KEY); + let chain_name_hash = ChainNameDigest::random(&mut rng); + + let fin_sig_bob = FinalitySignatureV2::create( + *block_1.hash(), + block_1.height(), + block_1.era_id(), + chain_name_hash, + &BOB_SECRET_KEY, + ); - let fin_sig_carol = - FinalitySignature::create(*block_1.hash(), block_1.era_id(), &CAROL_SECRET_KEY); + let fin_sig_carol = FinalitySignatureV2::create( + *block_1.hash(), + block_1.height(), + block_1.era_id(), + chain_name_hash, + &CAROL_SECRET_KEY, + ); - let fin_sig_alice = - FinalitySignature::create(*block_1.hash(), block_1.era_id(), &ALICE_SECRET_KEY); + let fin_sig_alice = FinalitySignatureV2::create( + *block_1.hash(), + block_1.height(), + block_1.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // Register the era in the validator matrix so the block is valid. { @@ -1886,14 +2066,14 @@ async fn block_accumulator_doesnt_purge_with_delayed_block_execution() { block_accumulator.register_local_tip(0, 0.into()); let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(fin_sig_bob.clone()), + finality_signature: Box::new(fin_sig_bob.clone().into()), sender: peer_1, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); assert!(effects.is_empty()); let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(fin_sig_carol.clone()), + finality_signature: Box::new(fin_sig_carol.clone().into()), sender: peer_1, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); @@ -1902,7 +2082,7 @@ async fn block_accumulator_doesnt_purge_with_delayed_block_execution() { // Register the finality signature created by Alice (this validator) after executing the // block. let event = super::Event::CreatedFinalitySignature { - finality_signature: Box::new(fin_sig_alice.clone()), + finality_signature: Box::new(fin_sig_alice.clone().into()), }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); assert!(effects.is_empty()); @@ -1942,7 +2122,7 @@ async fn block_accumulator_doesnt_purge_with_delayed_block_execution() { expected_block_signatures .and_then(|sigs| sigs.finality_signature(fin_sig_alice.public_key())) .unwrap(), - fin_sig_alice + FinalitySignature::from(fin_sig_alice) ); } diff --git a/node/src/components/block_synchronizer/block_builder/tests.rs b/node/src/components/block_synchronizer/block_builder/tests.rs index 2dbcff53b4..be87b417b6 100644 --- a/node/src/components/block_synchronizer/block_builder/tests.rs +++ b/node/src/components/block_synchronizer/block_builder/tests.rs @@ -2,7 +2,9 @@ use std::{collections::BTreeMap, thread, time::Duration}; use num_rational::Ratio; -use casper_types::{testing::TestRng, TestBlockBuilder, Transaction}; +use casper_types::{ + testing::TestRng, ChainNameDigest, FinalitySignatureV2, TestBlockBuilder, Transaction, +}; use crate::components::consensus::tests::utils::{ALICE_PUBLIC_KEY, ALICE_SECRET_KEY}; @@ -211,6 +213,7 @@ fn register_era_validator_weights() { #[test] fn register_executable_block() { let mut rng = TestRng::new(); + let chain_name_hash = ChainNameDigest::random(&mut rng); // Create a random block. let block = TestBlockBuilder::new().build(&mut rng); // Create a builder for the block. @@ -234,9 +237,15 @@ fn register_executable_block() { vec![ALICE_PUBLIC_KEY.clone()], LegacyRequiredFinality::Strict, ); - let sig = FinalitySignature::create(*block.hash(), block.era_id(), &ALICE_SECRET_KEY); + let sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); assert_eq!( - signature_acquisition.apply_signature(sig, &weights), + signature_acquisition.apply_signature(sig.into(), &weights), Acceptance::NeededIt ); // Set the builder's state to `HaveStrictFinalitySignatures`. @@ -280,6 +289,7 @@ fn register_executable_block() { #[test] fn register_block_execution() { let mut rng = TestRng::new(); + let chain_name_hash = ChainNameDigest::random(&mut rng); // Create a random block. let block = TestBlockBuilder::new().build(&mut rng); // Create a builder for the block. @@ -303,9 +313,15 @@ fn register_block_execution() { vec![ALICE_PUBLIC_KEY.clone()], LegacyRequiredFinality::Strict, ); - let sig = FinalitySignature::create(*block.hash(), block.era_id(), &ALICE_SECRET_KEY); + let sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); assert_eq!( - signature_acquisition.apply_signature(sig, &weights), + signature_acquisition.apply_signature(sig.into(), &weights), Acceptance::NeededIt ); @@ -356,6 +372,7 @@ fn register_block_execution() { #[test] fn register_block_executed() { let mut rng = TestRng::new(); + let chain_name_hash = ChainNameDigest::random(&mut rng); // Create a random block. let block = TestBlockBuilder::new().build(&mut rng); // Create a builder for the block. @@ -379,9 +396,15 @@ fn register_block_executed() { vec![ALICE_PUBLIC_KEY.clone()], LegacyRequiredFinality::Strict, ); - let sig = FinalitySignature::create(*block.hash(), block.era_id(), &ALICE_SECRET_KEY); + let sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); assert_eq!( - signature_acquisition.apply_signature(sig, &weights), + signature_acquisition.apply_signature(sig.into(), &weights), Acceptance::NeededIt ); // Set the builder state to `HaveStrictFinalitySignatures`. @@ -421,6 +444,7 @@ fn register_block_executed() { #[test] fn register_block_marked_complete() { let mut rng = TestRng::new(); + let chain_name_hash = ChainNameDigest::random(&mut rng); // Create a random block. let block = TestBlockBuilder::new().build(&mut rng); // Create a builder for the block. @@ -446,9 +470,15 @@ fn register_block_marked_complete() { vec![ALICE_PUBLIC_KEY.clone()], LegacyRequiredFinality::Strict, ); - let sig = FinalitySignature::create(*block.hash(), block.era_id(), &ALICE_SECRET_KEY); + let sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); assert_eq!( - signature_acquisition.apply_signature(sig, &weights), + signature_acquisition.apply_signature(sig.into(), &weights), Acceptance::NeededIt ); diff --git a/node/src/components/block_synchronizer/signature_acquisition.rs b/node/src/components/block_synchronizer/signature_acquisition.rs index be47b75b2a..371c7aa1f1 100644 --- a/node/src/components/block_synchronizer/signature_acquisition.rs +++ b/node/src/components/block_synchronizer/signature_acquisition.rs @@ -148,7 +148,9 @@ mod tests { use num_rational::Ratio; use rand::Rng; - use casper_types::{testing::TestRng, BlockHash, EraId, SecretKey, U512}; + use casper_types::{ + testing::TestRng, BlockHash, ChainNameDigest, EraId, FinalitySignatureV2, SecretKey, U512, + }; use super::*; @@ -184,7 +186,9 @@ mod tests { let rng = &mut TestRng::new(); let validators = iter::repeat_with(|| keypair(rng)).take(4).collect_vec(); let block_hash = BlockHash::random(rng); + let block_height = rng.gen(); let era_id = EraId::new(rng.gen()); + let chain_name_hash = ChainNameDigest::random(rng); let weights = EraValidatorWeights::new( era_id, validators @@ -202,9 +206,15 @@ mod tests { // Signature for the validator #0 weighting 1: let (public_0, secret_0) = validators.get(0).unwrap(); - let finality_signature = FinalitySignature::create(block_hash, era_id, secret_0); + let finality_signature = FinalitySignatureV2::create( + block_hash, + block_height, + era_id, + chain_name_hash, + secret_0, + ); assert_matches!( - signature_acquisition.apply_signature(finality_signature, &weights), + signature_acquisition.apply_signature(finality_signature.into(), &weights), Acceptance::NeededIt ); assert_iter_equal!(signature_acquisition.have_signatures(), [public_0]); @@ -219,9 +229,15 @@ mod tests { // Signature for the validator #2 weighting 3: let (public_2, secret_2) = validators.get(2).unwrap(); - let finality_signature = FinalitySignature::create(block_hash, era_id, secret_2); + let finality_signature = FinalitySignatureV2::create( + block_hash, + block_height, + era_id, + chain_name_hash, + secret_2, + ); assert_matches!( - signature_acquisition.apply_signature(finality_signature, &weights), + signature_acquisition.apply_signature(finality_signature.into(), &weights), Acceptance::NeededIt ); assert_iter_equal!( @@ -242,9 +258,15 @@ mod tests { // Signature for the validator #3 weighting 4: let (public_3, secret_3) = validators.get(3).unwrap(); - let finality_signature = FinalitySignature::create(block_hash, era_id, secret_3); + let finality_signature = FinalitySignatureV2::create( + block_hash, + block_height, + era_id, + chain_name_hash, + secret_3, + ); assert_matches!( - signature_acquisition.apply_signature(finality_signature, &weights), + signature_acquisition.apply_signature(finality_signature.into(), &weights), Acceptance::NeededIt ); assert_iter_equal!( @@ -287,6 +309,8 @@ mod tests { let rng = &mut TestRng::new(); let validators = iter::repeat_with(|| keypair(rng)).take(4).collect_vec(); let block_hash = BlockHash::random(rng); + let block_height = rng.gen(); + let chain_name_hash = ChainNameDigest::random(rng); let era_id = EraId::new(rng.gen()); let weights = EraValidatorWeights::new( era_id, @@ -305,17 +329,24 @@ mod tests { // Signature for an already stored validator: let (_public_0, secret_0) = validators.first().unwrap(); - let finality_signature = FinalitySignature::create(block_hash, era_id, secret_0); + let finality_signature = FinalitySignatureV2::create( + block_hash, + block_height, + era_id, + chain_name_hash, + secret_0, + ); assert_matches!( - signature_acquisition.apply_signature(finality_signature, &weights), + signature_acquisition.apply_signature(finality_signature.into(), &weights), Acceptance::NeededIt ); // Signature for an unknown validator: let (_public, secret) = keypair(rng); - let finality_signature = FinalitySignature::create(block_hash, era_id, &secret); + let finality_signature = + FinalitySignatureV2::create(block_hash, block_height, era_id, chain_name_hash, &secret); assert_matches!( - signature_acquisition.apply_signature(finality_signature, &weights), + signature_acquisition.apply_signature(finality_signature.into(), &weights), Acceptance::NeededIt ); } @@ -325,6 +356,8 @@ mod tests { let rng = &mut TestRng::new(); let validators = iter::repeat_with(|| keypair(rng)).take(4).collect_vec(); let block_hash = BlockHash::random(rng); + let block_height = rng.gen(); + let chain_name_hash = ChainNameDigest::random(rng); let era_id = EraId::new(rng.gen()); let weights = EraValidatorWeights::new( era_id, @@ -344,16 +377,28 @@ mod tests { let (_public_0, secret_0) = validators.first().unwrap(); // Signature for an already stored validator: - let finality_signature = FinalitySignature::create(block_hash, era_id, secret_0); + let finality_signature = FinalitySignatureV2::create( + block_hash, + block_height, + era_id, + chain_name_hash, + secret_0, + ); assert_matches!( - signature_acquisition.apply_signature(finality_signature, &weights), + signature_acquisition.apply_signature(finality_signature.into(), &weights), Acceptance::NeededIt ); // Signing again returns `HadIt`: - let finality_signature = FinalitySignature::create(block_hash, era_id, secret_0); + let finality_signature = FinalitySignatureV2::create( + block_hash, + block_height, + era_id, + chain_name_hash, + secret_0, + ); assert_matches!( - signature_acquisition.apply_signature(finality_signature, &weights), + signature_acquisition.apply_signature(finality_signature.into(), &weights), Acceptance::HadIt ); } @@ -362,8 +407,10 @@ mod tests { fn register_pending_has_the_expected_behavior() { let rng = &mut TestRng::new(); let validators = iter::repeat_with(|| keypair(rng)).take(4).collect_vec(); - let era_id = EraId::new(rng.gen()); let block_hash = BlockHash::random(rng); + let block_height = rng.gen(); + let era_id = EraId::new(rng.gen()); + let chain_name_hash = ChainNameDigest::random(rng); let weights = EraValidatorWeights::new( era_id, validators @@ -395,9 +442,15 @@ mod tests { ); // Sign it: - let finality_signature = FinalitySignature::create(block_hash, era_id, secret_0); + let finality_signature = FinalitySignatureV2::create( + block_hash, + block_height, + era_id, + chain_name_hash, + secret_0, + ); assert_matches!( - signature_acquisition.apply_signature(finality_signature, &weights), + signature_acquisition.apply_signature(finality_signature.into(), &weights), Acceptance::NeededIt ); assert_iter_equal!(signature_acquisition.have_signatures(), [public_0]); diff --git a/node/src/components/block_synchronizer/tests.rs b/node/src/components/block_synchronizer/tests.rs index a1c578dd1b..a3aa1e9cc2 100644 --- a/node/src/components/block_synchronizer/tests.rs +++ b/node/src/components/block_synchronizer/tests.rs @@ -15,9 +15,9 @@ use rand::{seq::IteratorRandom, Rng}; use casper_storage::global_state::trie::merkle_proof::TrieMerkleProof; use casper_types::{ - testing::TestRng, AccessRights, BlockV2, CLValue, Chainspec, Deploy, EraId, Key, - LegacyRequiredFinality, ProtocolVersion, PublicKey, SecretKey, StoredValue, TestBlockBuilder, - TestBlockV1Builder, TimeDiff, URef, U512, + testing::TestRng, AccessRights, BlockV2, CLValue, ChainNameDigest, Chainspec, Deploy, EraId, + FinalitySignatureV2, Key, LegacyRequiredFinality, ProtocolVersion, PublicKey, SecretKey, + StoredValue, TestBlockBuilder, TestBlockV1Builder, TimeDiff, URef, U512, }; use super::*; @@ -144,6 +144,7 @@ impl TestEnv { // Set up a validator matrix for the era in which our test block was created let mut validator_matrix = ValidatorMatrix::new( Ratio::new(1, 3), + ChainNameDigest::new(Digest::hash(b"casper-example")), None, EraId::from(0), self.validator_keys[0].clone(), @@ -207,13 +208,21 @@ fn register_multiple_signatures<'a, I: IntoIterator>>( builder: &mut BlockBuilder, block: &Block, validator_keys_iter: I, + chain_name_hash: ChainNameDigest, ) { for secret_key in validator_keys_iter { // Register a finality signature - let signature = - FinalitySignature::create(*block.hash(), block.era_id(), secret_key.as_ref()); + let signature = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + secret_key.as_ref(), + ); assert!(signature.is_verified().is_ok()); - assert!(builder.register_finality_signature(signature, None).is_ok()); + assert!(builder + .register_finality_signature(signature.into(), None) + .is_ok()); } } @@ -346,6 +355,7 @@ async fn global_state_sync_wont_stall_with_bad_peers() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let cfg = Config { latch_reset_interval: TimeDiff::from_millis(TEST_LATCH_RESET_INTERVAL_MILLIS), @@ -377,6 +387,7 @@ async fn global_state_sync_wont_stall_with_bad_peers() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!( historical_builder @@ -391,6 +402,7 @@ async fn global_state_sync_wont_stall_with_bad_peers() { validators_secret_keys .iter() .skip(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); // At this point, the next step the synchronizer takes should be to get global state @@ -1074,6 +1086,7 @@ async fn fwd_more_signatures_are_requested_if_weak_finality_is_not_reached() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1099,9 +1112,11 @@ async fn fwd_more_signatures_are_requested_if_weak_finality_is_not_reached() { ); // Simulate a successful fetch of a single signature - let signature = FinalitySignature::create( + let signature = FinalitySignatureV2::create( *block.hash(), + block.height(), block.era_id(), + chain_name_hash, validators_secret_keys[0].as_ref(), ); assert!(signature.is_verified().is_ok()); @@ -1109,7 +1124,7 @@ async fn fwd_more_signatures_are_requested_if_weak_finality_is_not_reached() { mock_reactor.effect_builder(), &mut rng, Event::FinalitySignatureFetched(Ok(FetchedData::FromPeer { - item: Box::new(signature), + item: Box::new(signature.into()), peer: peers[0], })), ); @@ -1148,14 +1163,19 @@ async fn fwd_more_signatures_are_requested_if_weak_finality_is_not_reached() { .take(weak_finality_threshold(validators_secret_keys.len())) { // Register a finality signature - let signature = - FinalitySignature::create(*block.hash(), block.era_id(), secret_key.as_ref()); + let signature = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + secret_key.as_ref(), + ); assert!(signature.is_verified().is_ok()); let effects = block_synchronizer.handle_event( mock_reactor.effect_builder(), &mut rng, Event::FinalitySignatureFetched(Ok(FetchedData::FromPeer { - item: Box::new(signature), + item: Box::new(signature.into()), peer: peers[2], })), ); @@ -1329,6 +1349,7 @@ async fn next_action_for_have_weak_finality_is_fetching_block_body() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1354,6 +1375,7 @@ async fn next_action_for_have_weak_finality_is_fetching_block_body() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); // Check the block acquisition state @@ -1395,6 +1417,7 @@ async fn registering_block_body_transitions_builder_to_have_block_state() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1420,6 +1443,7 @@ async fn registering_block_body_transitions_builder_to_have_block_state() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); // Check the block acquisition state @@ -1475,6 +1499,7 @@ async fn fwd_having_block_body_for_block_without_deploys_requires_only_signature let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1500,6 +1525,7 @@ async fn fwd_having_block_body_for_block_without_deploys_requires_only_signature validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(fwd_builder.register_block(block.clone(), None).is_ok()); @@ -1539,6 +1565,7 @@ async fn fwd_having_block_body_for_block_with_deploys_requires_approvals_hashes( let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1564,6 +1591,7 @@ async fn fwd_having_block_body_for_block_with_deploys_requires_approvals_hashes( validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(fwd_builder.register_block(block.clone(), None).is_ok()); @@ -1623,6 +1651,7 @@ async fn fwd_registering_approvals_hashes_triggers_fetch_for_deploys() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1648,6 +1677,7 @@ async fn fwd_registering_approvals_hashes_triggers_fetch_for_deploys() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(fwd_builder.register_block(block.clone(), None).is_ok()); @@ -1700,6 +1730,7 @@ async fn fwd_have_block_body_without_deploys_and_strict_finality_transitions_sta let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1719,7 +1750,12 @@ async fn fwd_have_block_body_without_deploys_and_strict_finality_transitions_sta fwd_builder.register_era_validator_weights(&block_synchronizer.validator_matrix); // Register finality signatures to reach strict finality - register_multiple_signatures(fwd_builder, block, validators_secret_keys.iter()); + register_multiple_signatures( + fwd_builder, + block, + validators_secret_keys.iter(), + chain_name_hash, + ); assert!(fwd_builder.register_block(block.clone(), None).is_ok()); @@ -1761,6 +1797,7 @@ async fn fwd_have_block_with_strict_finality_requires_creation_of_finalized_bloc let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1786,6 +1823,7 @@ async fn fwd_have_block_with_strict_finality_requires_creation_of_finalized_bloc validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(fwd_builder.register_block(block.clone(), None).is_ok()); @@ -1802,6 +1840,7 @@ async fn fwd_have_block_with_strict_finality_requires_creation_of_finalized_bloc validators_secret_keys .iter() .skip(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); // Check the block acquisition state @@ -1832,6 +1871,7 @@ async fn fwd_have_strict_finality_requests_enqueue_when_finalized_block_is_creat let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1857,6 +1897,7 @@ async fn fwd_have_strict_finality_requests_enqueue_when_finalized_block_is_creat validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(fwd_builder.register_block(block.clone(), None).is_ok()); // Register the remaining signatures to reach strict finality @@ -1866,6 +1907,7 @@ async fn fwd_have_strict_finality_requests_enqueue_when_finalized_block_is_creat validators_secret_keys .iter() .skip(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); // Check the block acquisition state @@ -1926,6 +1968,7 @@ async fn fwd_builder_status_is_executing_when_block_is_enqueued_for_execution() let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -1951,6 +1994,7 @@ async fn fwd_builder_status_is_executing_when_block_is_enqueued_for_execution() validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(fwd_builder.register_block(block.clone(), None).is_ok()); // Register the remaining signatures to reach strict finality @@ -1960,6 +2004,7 @@ async fn fwd_builder_status_is_executing_when_block_is_enqueued_for_execution() validators_secret_keys .iter() .skip(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); // Check the block acquisition state @@ -2001,6 +2046,7 @@ async fn fwd_sync_is_finished_when_block_is_marked_as_executed() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -2026,6 +2072,7 @@ async fn fwd_sync_is_finished_when_block_is_marked_as_executed() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(fwd_builder.register_block(block.clone(), None).is_ok()); // Register the remaining signatures to reach strict finality @@ -2035,6 +2082,7 @@ async fn fwd_sync_is_finished_when_block_is_marked_as_executed() { validators_secret_keys .iter() .skip(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); // Register finalized block @@ -2072,6 +2120,7 @@ async fn historical_sync_announces_meta_block() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -2097,6 +2146,7 @@ async fn historical_sync_announces_meta_block() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(historical_builder .register_block(block.clone(), None) @@ -2108,6 +2158,7 @@ async fn historical_sync_announces_meta_block() { validators_secret_keys .iter() .skip(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); // Set the builder state to `HaveStrictFinalitySignatures` @@ -2217,6 +2268,7 @@ async fn synchronizer_halts_if_block_cannot_be_made_executable() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -2241,6 +2293,7 @@ async fn synchronizer_halts_if_block_cannot_be_made_executable() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(fwd_builder.register_block(block.clone(), None).is_ok()); // Register the remaining signatures to reach strict finality @@ -2250,6 +2303,7 @@ async fn synchronizer_halts_if_block_cannot_be_made_executable() { validators_secret_keys .iter() .skip(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); // Block should have strict finality and will require to be executed @@ -2314,6 +2368,7 @@ async fn historical_sync_skips_exec_results_and_deploys_if_block_empty() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(rng, validator_matrix, Default::default()) @@ -2340,6 +2395,7 @@ async fn historical_sync_skips_exec_results_and_deploys_if_block_empty() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(historical_builder .register_block(block.clone(), None) @@ -2421,6 +2477,7 @@ async fn historical_sync_no_legacy_block() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(rng, validator_matrix, Default::default()) @@ -2445,6 +2502,7 @@ async fn historical_sync_no_legacy_block() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(historical_builder .register_block(block.clone(), None) @@ -2645,6 +2703,7 @@ async fn historical_sync_legacy_block_strict_finality() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(rng, validator_matrix, Default::default()) @@ -2669,6 +2728,7 @@ async fn historical_sync_legacy_block_strict_finality() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(historical_builder .register_block(block.clone(), None) @@ -2845,6 +2905,7 @@ async fn historical_sync_legacy_block_weak_finality() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(rng, validator_matrix, Default::default()) @@ -2869,6 +2930,7 @@ async fn historical_sync_legacy_block_weak_finality() { validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(historical_builder .register_block(block.clone(), None) @@ -3058,6 +3120,7 @@ async fn historical_sync_legacy_block_any_finality() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(rng, validator_matrix, Default::default()) @@ -3080,6 +3143,7 @@ async fn historical_sync_legacy_block_any_finality() { historical_builder, block, validators_secret_keys.iter().take(1), + chain_name_hash, ); assert!(historical_builder .register_block(block.clone(), None) @@ -3269,6 +3333,7 @@ async fn fwd_sync_latch_should_not_decrement_for_old_responses() { let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(&mut rng, validator_matrix, Config::default()); @@ -3407,14 +3472,19 @@ async fn fwd_sync_latch_should_not_decrement_for_old_responses() { .take(weak_finality_threshold(validators_secret_keys.len())) { // Register a finality signature - let signature = - FinalitySignature::create(*block.hash(), block.era_id(), secret_key.as_ref()); + let signature = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + secret_key.as_ref(), + ); assert!(signature.is_verified().is_ok()); let effects = block_synchronizer.handle_event( mock_reactor.effect_builder(), &mut rng, Event::FinalitySignatureFetched(Ok(FetchedData::FromPeer { - item: Box::new(signature), + item: Box::new(signature.into()), peer: peers[2], })), ); @@ -3462,14 +3532,19 @@ async fn fwd_sync_latch_should_not_decrement_for_old_responses() { .take(2) { // Register a finality signature - let signature = - FinalitySignature::create(*block.hash(), block.era_id(), secret_key.as_ref()); + let signature = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + secret_key.as_ref(), + ); assert!(signature.is_verified().is_ok()); let effects = block_synchronizer.handle_event( mock_reactor.effect_builder(), &mut rng, Event::FinalitySignatureFetched(Ok(FetchedData::FromPeer { - item: Box::new(signature), + item: Box::new(signature.into()), peer: peers[2], })), ); @@ -3675,14 +3750,19 @@ async fn fwd_sync_latch_should_not_decrement_for_old_responses() { - weak_finality_threshold(validators_secret_keys.len()), ) { // Register a finality signature - let signature = - FinalitySignature::create(*block.hash(), block.era_id(), secret_key.as_ref()); + let signature = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + secret_key.as_ref(), + ); assert!(signature.is_verified().is_ok()); let effects = block_synchronizer.handle_event( mock_reactor.effect_builder(), &mut rng, Event::FinalitySignatureFetched(Ok(FetchedData::FromPeer { - item: Box::new(signature), + item: Box::new(signature.into()), peer: peers[2], })), ); @@ -3746,6 +3826,7 @@ async fn historical_sync_latch_should_not_decrement_for_old_deploy_fetch_respons let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(rng, validator_matrix, Default::default()) @@ -3769,6 +3850,7 @@ async fn historical_sync_latch_should_not_decrement_for_old_deploy_fetch_respons validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(historical_builder .register_block(block.clone(), None) @@ -4013,6 +4095,7 @@ async fn historical_sync_latch_should_not_decrement_for_old_execution_results() let peers = test_env.peers(); let block = test_env.block(); let validator_matrix = test_env.gen_validator_matrix(); + let chain_name_hash = validator_matrix.chain_name_hash(); let validators_secret_keys = test_env.validator_keys(); let mut block_synchronizer = BlockSynchronizer::new_initialized(rng, validator_matrix, Default::default()) @@ -4036,6 +4119,7 @@ async fn historical_sync_latch_should_not_decrement_for_old_execution_results() validators_secret_keys .iter() .take(weak_finality_threshold(validators_secret_keys.len())), + chain_name_hash, ); assert!(historical_builder .register_block(block.clone(), None) diff --git a/node/src/components/event_stream_server/sse_server.rs b/node/src/components/event_stream_server/sse_server.rs index cbd9dc7def..614f099f21 100644 --- a/node/src/components/event_stream_server/sse_server.rs +++ b/node/src/components/event_stream_server/sse_server.rs @@ -172,11 +172,7 @@ impl SseData { /// Returns a random `SseData::FinalitySignature`. pub(super) fn random_finality_signature(rng: &mut TestRng) -> Self { - SseData::FinalitySignature(Box::new(FinalitySignature::random_for_block( - BlockHash::random(rng), - EraId::random(rng), - rng, - ))) + SseData::FinalitySignature(Box::new(FinalitySignature::random(rng))) } /// Returns a random `SseData::Step`. diff --git a/node/src/components/network/limiter.rs b/node/src/components/network/limiter.rs index fcba95d2af..4bc0c4256a 100644 --- a/node/src/components/network/limiter.rs +++ b/node/src/components/network/limiter.rs @@ -293,7 +293,7 @@ struct ConsumerId { mod tests { use std::{sync::Arc, time::Duration}; - use casper_types::{EraId, SecretKey}; + use casper_types::{ChainNameDigest, Digest, EraId, SecretKey}; use num_rational::Ratio; use prometheus::Counter; use tokio::time::Instant; @@ -460,6 +460,7 @@ mod tests { wait_metric.clone(), ValidatorMatrix::new( Ratio::new(1, 3), + ChainNameDigest::new(Digest::hash(b"casper-example")), None, EraId::from(0), Arc::new(secret_key), diff --git a/node/src/components/storage.rs b/node/src/components/storage.rs index 56176f0972..4b8b99977c 100644 --- a/node/src/components/storage.rs +++ b/node/src/components/storage.rs @@ -75,10 +75,10 @@ use casper_types::{ execution::{ execution_result_v1, ExecutionResult, ExecutionResultV1, ExecutionResultV2, TransformKind, }, - Block, BlockBody, BlockHash, BlockHeader, BlockSignatures, BlockV2, DeployApprovalsHash, - DeployHash, Digest, EraId, FinalitySignature, ProtocolVersion, PublicKey, SignedBlockHeader, - StoredValue, Timestamp, Transaction, TransactionApprovalsHash, TransactionHash, - TransactionHeader, TransactionId, TransactionV1ApprovalsHash, Transfer, + Block, BlockBody, BlockHash, BlockHeader, BlockSignatures, BlockSignaturesV1, BlockV2, + DeployApprovalsHash, DeployHash, Digest, EraId, FinalitySignature, ProtocolVersion, PublicKey, + SignedBlockHeader, StoredValue, Timestamp, Transaction, TransactionApprovalsHash, + TransactionHash, TransactionHeader, TransactionId, TransactionV1ApprovalsHash, Transfer, }; use crate::{ @@ -164,8 +164,7 @@ pub struct Storage { /// The approvals hashes databases. approvals_hashes_dbs: VersionedDatabases, /// The block metadata db. - #[data_size(skip)] - block_metadata_db: Database, + block_metadata_dbs: VersionedDatabases, /// The transaction databases. transaction_dbs: VersionedDatabases, /// Databases of `ExecutionResult`s indexed by transaction hash for current DB or by deploy @@ -332,7 +331,8 @@ impl Storage { let env = new_environment(total_size, root.as_path())?; let block_header_dbs = VersionedDatabases::new(&env, "block_header", "block_header_v2")?; - let block_metadata_db = env.create_db(Some("block_metadata"), DatabaseFlags::empty())?; + let block_metadata_dbs = + VersionedDatabases::new(&env, "block_metadata", "block_metadata_v2")?; let transaction_dbs = VersionedDatabases::new(&env, "deploys", "transactions")?; let execution_result_dbs = VersionedDatabases::new(&env, "deploy_metadata", "execution_results")?; @@ -446,7 +446,7 @@ impl Storage { .filter_map(|(body_hash, retain)| (!retain).then_some(body_hash)) .collect(); initialize_block_body_dbs(&env, block_body_dbs, deleted_block_body_hashes)?; - initialize_block_metadata_db(&env, block_metadata_db, deleted_block_hashes)?; + initialize_block_metadata_dbs(&env, block_metadata_dbs, deleted_block_hashes)?; initialize_execution_result_dbs(&env, execution_result_dbs, deleted_transaction_hashes)?; let metrics = registry.map(Metrics::new).transpose()?; @@ -456,7 +456,7 @@ impl Storage { env: Rc::new(env), block_header_dbs, block_body_dbs, - block_metadata_db, + block_metadata_dbs, approvals_hashes_dbs, transaction_dbs, execution_result_dbs, @@ -950,7 +950,7 @@ impl Storage { } let block_signatures = match self.get_block_signatures(&mut txn, &block_hash)? { Some(signatures) => signatures, - None => BlockSignatures::new(block_hash, block.era_id()), + None => BlockSignaturesV1::new(block_hash, block.era_id()).into(), }; if block_signatures.is_verified().is_err() { error!(?block, "invalid block signatures for block"); @@ -1002,7 +1002,7 @@ impl Storage { let hash = block.hash(); let block_signatures = match self.get_block_signatures(&mut txn, hash)? { Some(signatures) => signatures, - None => BlockSignatures::new(*hash, block.era_id()), + None => BlockSignaturesV1::new(*hash, block.era_id()).into(), }; responder .respond(Some(BlockWithMetadata { @@ -1033,7 +1033,7 @@ impl Storage { let hash = block.hash(); let block_signatures = match self.get_block_signatures(&mut txn, hash)? { Some(signatures) => signatures, - None => BlockSignatures::new(*hash, block.era_id()), + None => BlockSignaturesV1::new(*hash, block.era_id()).into(), }; responder .respond(Some(SignedBlock { @@ -1063,7 +1063,7 @@ impl Storage { let hash = highest_block.hash(); let block_signatures = match self.get_block_signatures(&mut txn, hash)? { Some(signatures) => signatures, - None => BlockSignatures::new(*hash, highest_block.era_id()), + None => BlockSignaturesV1::new(*hash, highest_block.era_id()).into(), }; responder .respond(Some(SignedBlock { @@ -1084,8 +1084,9 @@ impl Storage { return Ok(responder.respond(false).ignore()); } let mut txn = self.env.begin_rw_txn()?; - let old_data: Option = - txn.get_value(self.block_metadata_db, signatures.block_hash())?; + let old_data: Option = self + .block_metadata_dbs + .get(&mut txn, signatures.block_hash())?; let new_data = match old_data { None => signatures, Some(mut data) => { @@ -1096,8 +1097,8 @@ impl Storage { data } }; - let outcome = txn.put_value( - self.block_metadata_db, + let outcome = self.block_metadata_dbs.put( + &mut txn, new_data.block_hash(), &new_data, true, @@ -1279,12 +1280,15 @@ impl Storage { signature: Box, ) -> Result { let mut txn = self.env.begin_rw_txn()?; - let mut block_signatures = txn - .get_value(self.block_metadata_db, signature.block_hash())? - .unwrap_or_else(|| BlockSignatures::new(*signature.block_hash(), signature.era_id())); - block_signatures.insert_signature(*signature); - let outcome = txn.put_value( - self.block_metadata_db, + let mut block_signatures = self + .block_metadata_dbs + .get(&mut txn, signature.block_hash())? + .unwrap_or_else(|| { + BlockSignaturesV1::new(*signature.block_hash(), signature.era_id()).into() + }); + block_signatures.insert_signature(signature.public_key().clone(), *signature.signature()); + let outcome = self.block_metadata_dbs.put( + &mut txn, block_signatures.block_hash(), &block_signatures, true, @@ -1562,8 +1566,9 @@ impl Storage { ) -> Result<(), FatalStorageError> { let mut txn = self.env.begin_rw_txn()?; let block_hash = signatures.block_hash(); - if txn - .put_value(self.block_metadata_db, block_hash, signatures, true) + if self + .block_metadata_dbs + .put(&mut txn, block_hash, signatures, true) .is_err() { panic!("write_finality_signatures() failed"); @@ -2046,7 +2051,7 @@ impl Storage { let block_signatures = match self.get_block_signatures(txn, &block_header_hash)? { Some(signatures) => signatures, - None => BlockSignatures::new(block_header_hash, block_header.era_id()), + None => BlockSignaturesV1::new(block_header_hash, block_header.era_id()).into(), }; Ok(Some(SignedBlockHeader::new(block_header, block_signatures))) @@ -2223,7 +2228,7 @@ impl Storage { txn: &mut Tx, block_hash: &BlockHash, ) -> Result, FatalStorageError> { - Ok(txn.get_value(self.block_metadata_db, block_hash)?) + Ok(self.block_metadata_dbs.get(txn, block_hash)?) } /// Retrieves a finality signature for a block with a given block hash. @@ -2234,7 +2239,7 @@ impl Storage { public_key: &PublicKey, ) -> Result, FatalStorageError> { let maybe_signatures: Option = - txn.get_value(self.block_metadata_db, block_hash)?; + self.block_metadata_dbs.get(txn, block_hash)?; Ok(maybe_signatures.and_then(|signatures| signatures.finality_signature(public_key))) } @@ -2822,8 +2827,9 @@ impl Storage { .env .begin_ro_txn() .expect("could not create RO transaction"); - let res = txn - .get_value(self.block_metadata_db, &block_hash) + let res = self + .block_metadata_dbs + .get(&mut txn, &block_hash) .expect("could not retrieve value from storage"); txn.commit().expect("Could not commit transaction"); res @@ -2865,9 +2871,9 @@ fn initialize_block_body_dbs( } /// Purges stale entries from the block metadata database. -fn initialize_block_metadata_db( +fn initialize_block_metadata_dbs( env: &Environment, - block_metadata_db: Database, + block_metadata_dbs: VersionedDatabases, deleted_block_hashes: HashSet, ) -> Result<(), FatalStorageError> { let block_count_to_be_deleted = deleted_block_hashes.len(); @@ -2877,9 +2883,8 @@ fn initialize_block_metadata_db( ); let mut txn = env.begin_rw_txn()?; for block_hash in deleted_block_hashes { - match txn.del(block_metadata_db, &block_hash, None) { - Ok(()) | Err(lmdb::Error::NotFound) => {} - Err(error) => return Err(error.into()), + if let Err(error) = block_metadata_dbs.delete(&mut txn, &block_hash) { + return Err(error.into()); } } txn.commit()?; diff --git a/node/src/components/storage/tests.rs b/node/src/components/storage/tests.rs index 6854a1b2cd..ec8bb40361 100644 --- a/node/src/components/storage/tests.rs +++ b/node/src/components/storage/tests.rs @@ -24,16 +24,16 @@ use casper_types::{ generate_ed25519_keypair, system::auction::UnbondingPurse, testing::TestRng, - AccessRights, Block, BlockHash, BlockHeader, BlockSignatures, BlockV2, Chainspec, - ChainspecRawBytes, Deploy, DeployApprovalsHash, DeployHash, Digest, EraId, FinalitySignature, - Key, ProtocolVersion, PublicKey, SecretKey, SignedBlockHeader, TestBlockBuilder, - TestBlockV1Builder, TimeDiff, Transaction, TransactionApprovalsHash, TransactionHash, - TransactionV1Hash, Transfer, URef, U512, + AccessRights, Block, BlockHash, BlockHeader, BlockSignatures, BlockSignaturesV2, BlockV2, + ChainNameDigest, Chainspec, ChainspecRawBytes, Deploy, DeployApprovalsHash, DeployHash, Digest, + EraId, FinalitySignature, FinalitySignatureV2, Key, ProtocolVersion, PublicKey, SecretKey, + SignedBlockHeader, TestBlockBuilder, TestBlockV1Builder, TimeDiff, Transaction, + TransactionApprovalsHash, TransactionHash, TransactionV1Hash, Transfer, URef, U512, }; use tempfile::tempdir; use super::{ - initialize_block_metadata_db, + initialize_block_metadata_dbs, lmdb_ext::{deserialize_internal, serialize_internal, TransactionExt, WriteTransactionExt}, move_storage_files_to_network_subdir, should_move_storage_files_to_network_subdir, BlockHashHeightAndEra, Config, Storage, FORCE_RESYNC_FILE_NAME, @@ -144,15 +144,26 @@ fn create_sync_leap_test_chain( blocks.iter().for_each(|block| { storage.put_block(block).unwrap(); - let fs = FinalitySignature::create(*block.hash(), block.era_id(), &validator_secret_key); + let fs = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chainspec.name_hash(), + &validator_secret_key, + ); assert!(fs.is_verified().is_ok()); - let mut block_signatures = BlockSignatures::new(*block.hash(), block.era_id()); - block_signatures.insert_signature(fs); + let mut block_signatures = BlockSignaturesV2::new( + *block.hash(), + block.height(), + block.era_id(), + chainspec.name_hash(), + ); + block_signatures.insert_signature(fs.public_key().clone(), *fs.signature()); if !non_signed_blocks.contains(&block.height()) { storage - .write_finality_signatures(&block_signatures) + .write_finality_signatures(&BlockSignatures::from(block_signatures)) .unwrap(); storage.completed_blocks.insert(block.height()); } @@ -257,14 +268,27 @@ fn storage_fixture_with_hard_reset( } /// Creates 3 random signatures for the given block. -fn random_signatures(rng: &mut TestRng, block_hash: BlockHash, era_id: EraId) -> BlockSignatures { - let mut block_signatures = BlockSignatures::new(block_hash, era_id); +fn random_signatures( + rng: &mut TestRng, + block_hash: BlockHash, + block_height: u64, + era_id: EraId, + chain_name_hash: ChainNameDigest, +) -> BlockSignatures { + let mut block_signatures = + BlockSignaturesV2::new(block_hash, block_height, era_id, chain_name_hash); for _ in 0..3 { let secret_key = SecretKey::random(rng); - let signature = FinalitySignature::create(block_hash, era_id, &secret_key); - block_signatures.insert_signature(signature); + let signature = FinalitySignatureV2::create( + block_hash, + block_height, + era_id, + chain_name_hash, + &secret_key, + ); + block_signatures.insert_signature(signature.public_key().clone(), *signature.signature()); } - block_signatures + block_signatures.into() } /// Requests block header at a specific height from a storage component. @@ -1597,6 +1621,7 @@ fn should_hard_reset() { let blocks_per_era = 3; let mut harness = ComponentHarness::default(); let mut storage = storage_fixture(&harness); + let chain_name_hash = ChainNameDigest::random(&mut harness.rng); let random_txns: Vec<_> = iter::repeat_with(|| Transaction::random(&mut harness.rng)) .take(blocks_count) @@ -1627,7 +1652,13 @@ fn should_hard_reset() { // Create and store signatures for these blocks. for block in &blocks { - let block_signatures = random_signatures(&mut harness.rng, *block.hash(), block.era_id()); + let block_signatures = random_signatures( + &mut harness.rng, + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + ); assert!(put_block_signatures( &mut harness, &mut storage, @@ -2318,40 +2349,53 @@ fn assert_signatures(storage: &Storage, block_hash: BlockHash, expected: Vec(); -const_assert!(_STORAGE_REQUEST_SIZE < 97); +const_assert!(_STORAGE_REQUEST_SIZE < 129); /// A metrics request. #[derive(Debug)] diff --git a/node/src/reactor/main_reactor.rs b/node/src/reactor/main_reactor.rs index f8350c4c8f..4abadcdfca 100644 --- a/node/src/reactor/main_reactor.rs +++ b/node/src/reactor/main_reactor.rs @@ -1035,6 +1035,7 @@ impl reactor::Reactor for MainReactor { let (our_secret_key, our_public_key) = config.consensus.load_keys(&root_dir)?; let validator_matrix = ValidatorMatrix::new( chainspec.core_config.finality_threshold_fraction, + chainspec.name_hash(), chainspec .protocol_config .global_state_update diff --git a/node/src/types/sync_leap.rs b/node/src/types/sync_leap.rs index 8d6ffa8c51..e4295a82e6 100644 --- a/node/src/types/sync_leap.rs +++ b/node/src/types/sync_leap.rs @@ -450,10 +450,10 @@ mod tests { use rand::Rng; use casper_types::{ - crypto, testing::TestRng, ActivationPoint, Block, BlockHash, BlockHeader, BlockSignatures, - BlockV2, EraEndV2, EraId, FinalitySignature, GlobalStateUpdate, ProtocolConfig, - ProtocolVersion, PublicKey, SecretKey, SignedBlockHeader, TestBlockBuilder, Timestamp, - TransactionHash, TransactionV1Hash, U512, + crypto, testing::TestRng, ActivationPoint, Block, BlockHash, BlockHeader, + BlockSignaturesV2, BlockV2, ChainNameDigest, EraEndV2, EraId, FinalitySignatureV2, + GlobalStateUpdate, ProtocolConfig, ProtocolVersion, PublicKey, SecretKey, + SignedBlockHeader, TestBlockBuilder, Timestamp, TransactionHash, TransactionV1Hash, U512, }; use super::SyncLeap; @@ -471,34 +471,39 @@ mod tests { height: usize, test_chain: &[BlockV2], validators: &[ValidatorSpec], + chain_name_hash: ChainNameDigest, add_proofs: bool, ) -> SignedBlockHeader { let header = Block::from(test_chain.get(height).unwrap()).clone_header(); - make_signed_block_header_from_header(&header, validators, add_proofs) + make_signed_block_header_from_header(&header, validators, chain_name_hash, add_proofs) } fn make_signed_block_header_from_header( block_header: &BlockHeader, validators: &[ValidatorSpec], + chain_name_hash: ChainNameDigest, add_proofs: bool, ) -> SignedBlockHeader { let hash = block_header.block_hash(); + let height = block_header.height(); let era_id = block_header.era_id(); - let mut block_signatures = BlockSignatures::new(hash, era_id); + let mut block_signatures = BlockSignaturesV2::new(hash, height, era_id, chain_name_hash); validators.iter().for_each( |ValidatorSpec { secret_key, public_key: _, weight: _, }| { - let finality_signature = FinalitySignature::create(hash, era_id, secret_key); + let fin_sig = + FinalitySignatureV2::create(hash, height, era_id, chain_name_hash, secret_key); if add_proofs { - block_signatures.insert_signature(finality_signature); + block_signatures + .insert_signature(fin_sig.public_key().clone(), *fin_sig.signature()); } }, ); - SignedBlockHeader::new(block_header.clone(), block_signatures) + SignedBlockHeader::new(block_header.clone(), block_signatures.into()) } fn make_test_sync_leap_with_chain( @@ -507,6 +512,7 @@ mod tests { query: usize, trusted_ancestor_headers: &[usize], signed_block_headers: &[usize], + chain_name_hash: ChainNameDigest, add_proofs: bool, ) -> SyncLeap { let trusted_block_header = Block::from(test_chain.get(query).unwrap()).clone_header(); @@ -519,7 +525,13 @@ mod tests { let signed_block_headers: Vec<_> = signed_block_headers .iter() .map(|height| { - make_signed_block_header_from_height(*height, test_chain, validators, add_proofs) + make_signed_block_header_from_height( + *height, + test_chain, + validators, + chain_name_hash, + add_proofs, + ) }) .collect(); @@ -544,6 +556,7 @@ mod tests { let mut test_chain_spec = TestChainSpec::new(rng, Some(switch_blocks.to_vec()), None, validators); let test_chain: Vec<_> = test_chain_spec.iter().take(12).collect(); + let chain_name_hash = ChainNameDigest::random(rng); make_test_sync_leap_with_chain( validators, @@ -551,6 +564,7 @@ mod tests { query, trusted_ancestor_headers, signed_block_headers, + chain_name_hash, add_proofs, ) } @@ -692,6 +706,7 @@ mod tests { let generated_block_count = max_allowed_size; let block = TestBlockBuilder::new().height(0).build_versioned(&mut rng); + let chain_name_hash = ChainNameDigest::random(&mut rng); let sync_leap = SyncLeap { trusted_ancestor_only: false, trusted_block_header: block.clone_header(), @@ -699,7 +714,11 @@ mod tests { signed_block_headers: iter::repeat_with(|| { let block = TestBlockBuilder::new().build_versioned(&mut rng); let hash = block.hash(); - SignedBlockHeader::new(block.clone_header(), BlockSignatures::new(*hash, 0.into())) + let height = block.height(); + SignedBlockHeader::new( + block.clone_header(), + BlockSignaturesV2::new(*hash, height, 0.into(), chain_name_hash).into(), + ) }) .take(generated_block_count as usize) .collect(), @@ -721,7 +740,11 @@ mod tests { signed_block_headers: iter::repeat_with(|| { let block = TestBlockBuilder::new().build_versioned(&mut rng); let hash = block.hash(); - SignedBlockHeader::new(block.clone_header(), BlockSignatures::new(*hash, 0.into())) + let height = block.height(); + SignedBlockHeader::new( + block.clone_header(), + BlockSignaturesV2::new(*hash, height, 0.into(), chain_name_hash).into(), + ) }) .take(generated_block_count as usize) .collect(), @@ -1127,6 +1150,7 @@ mod tests { #[test] fn should_return_headers() { let mut rng = TestRng::new(); + let chain_name_hash = ChainNameDigest::random(&mut rng); let trusted_block = TestBlockBuilder::new() .switch_block(false) @@ -1151,12 +1175,24 @@ mod tests { let signed_block_3 = TestBlockBuilder::new() .switch_block(false) .build_versioned(&mut rng); - let signed_block_header_1 = - make_signed_block_header_from_header(&signed_block_1.clone_header(), &[], false); - let signed_block_header_2 = - make_signed_block_header_from_header(&signed_block_2.clone_header(), &[], false); - let signed_block_header_3 = - make_signed_block_header_from_header(&signed_block_3.clone_header(), &[], false); + let signed_block_header_1 = make_signed_block_header_from_header( + &signed_block_1.clone_header(), + &[], + chain_name_hash, + false, + ); + let signed_block_header_2 = make_signed_block_header_from_header( + &signed_block_2.clone_header(), + &[], + chain_name_hash, + false, + ); + let signed_block_header_3 = make_signed_block_header_from_header( + &signed_block_3.clone_header(), + &[], + chain_name_hash, + false, + ); let sync_leap = SyncLeap { trusted_ancestor_only: false, @@ -1196,6 +1232,8 @@ mod tests { fn should_return_switch_block_headers() { let mut rng = TestRng::new(); + let chain_name_hash = ChainNameDigest::random(&mut rng); + let trusted_block = TestBlockBuilder::new() .switch_block(false) .build_versioned(&mut rng); @@ -1219,12 +1257,24 @@ mod tests { let signed_block_3 = TestBlockBuilder::new() .switch_block(false) .build_versioned(&mut rng); - let signed_block_header_1 = - make_signed_block_header_from_header(&signed_block_1.clone_header(), &[], false); - let signed_block_header_2 = - make_signed_block_header_from_header(&signed_block_2.clone_header(), &[], false); - let signed_block_header_3 = - make_signed_block_header_from_header(&signed_block_3.clone_header(), &[], false); + let signed_block_header_1 = make_signed_block_header_from_header( + &signed_block_1.clone_header(), + &[], + chain_name_hash, + false, + ); + let signed_block_header_2 = make_signed_block_header_from_header( + &signed_block_2.clone_header(), + &[], + chain_name_hash, + false, + ); + let signed_block_header_3 = make_signed_block_header_from_header( + &signed_block_3.clone_header(), + &[], + chain_name_hash, + false, + ); let sync_leap = SyncLeap { trusted_ancestor_only: false, @@ -1564,6 +1614,7 @@ mod tests { // Test block iterator will pull 2 validators for each created block. Indices 0 and 1 are // used for validators for the trusted ancestor headers. const FIRST_SIGNED_BLOCK_HEADER_VALIDATOR_OFFSET: usize = 2; + let validators: Vec<_> = (1..100) .map(|weight| { let (secret_key, public_key) = crypto::generate_ed25519_keypair(); @@ -1685,6 +1736,8 @@ mod tests { const DEFAULT_VALIDATOR_WEIGHT: u32 = 100; + let chain_name_hash = ChainNameDigest::random(&mut rng); + let validators: Vec<_> = iter::repeat_with(crypto::generate_ed25519_keypair) .take(2) .map(|(secret_key, public_key)| ValidatorSpec { @@ -1697,8 +1750,15 @@ mod tests { let mut test_chain_spec = TestChainSpec::new(&mut rng, Some(vec![4, 8]), None, &validators); let chain: Vec<_> = test_chain_spec.iter().take(12).collect(); - let sync_leap = - make_test_sync_leap_with_chain(&validators, &chain, 11, &[10, 9, 8], &[], false); + let sync_leap = make_test_sync_leap_with_chain( + &validators, + &chain, + 11, + &[10, 9, 8], + &[], + chain_name_hash, + false, + ); let global_states_metadata = sync_leap.global_states_for_sync_across_upgrade(); assert!(global_states_metadata.is_none()); @@ -1710,6 +1770,8 @@ mod tests { const DEFAULT_VALIDATOR_WEIGHT: u32 = 100; + let chain_name_hash = ChainNameDigest::random(&mut rng); + let validators: Vec<_> = iter::repeat_with(crypto::generate_ed25519_keypair) .take(2) .map(|(secret_key, public_key)| ValidatorSpec { @@ -1723,8 +1785,15 @@ mod tests { TestChainSpec::new(&mut rng, Some(vec![4, 8]), Some(vec![8]), &validators); let chain: Vec<_> = test_chain_spec.iter().take(12).collect(); - let sync_leap = - make_test_sync_leap_with_chain(&validators, &chain, 11, &[10, 9, 8], &[], false); + let sync_leap = make_test_sync_leap_with_chain( + &validators, + &chain, + 11, + &[10, 9, 8], + &[], + chain_name_hash, + false, + ); let global_states_metadata = sync_leap .global_states_for_sync_across_upgrade() @@ -1763,6 +1832,8 @@ mod tests { const DEFAULT_VALIDATOR_WEIGHT: u32 = 100; + let chain_name_hash = ChainNameDigest::random(&mut rng); + let validators: Vec<_> = iter::repeat_with(crypto::generate_ed25519_keypair) .take(2) .map(|(secret_key, public_key)| ValidatorSpec { @@ -1776,7 +1847,15 @@ mod tests { TestChainSpec::new(&mut rng, Some(vec![4, 8, 9]), Some(vec![8]), &validators); let chain: Vec<_> = test_chain_spec.iter().take(12).collect(); - let sync_leap = make_test_sync_leap_with_chain(&validators, &chain, 9, &[8], &[], false); + let sync_leap = make_test_sync_leap_with_chain( + &validators, + &chain, + 9, + &[8], + &[], + chain_name_hash, + false, + ); let global_states_metadata = sync_leap .global_states_for_sync_across_upgrade() @@ -1999,6 +2078,7 @@ mod tests { (era_2, height_2, version_2): (u64, u64, ProtocolVersion), (era_3, height_3, version_3): (u64, u64, ProtocolVersion), ) -> (SignedBlockHeader, SignedBlockHeader, SignedBlockHeader) { + let chain_name_hash = ChainNameDigest::random(rng); let signed_block_1 = TestBlockBuilder::new() .height(height_1) .era(era_1) @@ -2018,12 +2098,24 @@ mod tests { .switch_block(true) .build_versioned(rng); - let signed_block_header_1 = - make_signed_block_header_from_header(&signed_block_1.clone_header(), &[], false); - let signed_block_header_2 = - make_signed_block_header_from_header(&signed_block_2.clone_header(), &[], false); - let signed_block_header_3 = - make_signed_block_header_from_header(&signed_block_3.clone_header(), &[], false); + let signed_block_header_1 = make_signed_block_header_from_header( + &signed_block_1.clone_header(), + &[], + chain_name_hash, + false, + ); + let signed_block_header_2 = make_signed_block_header_from_header( + &signed_block_2.clone_header(), + &[], + chain_name_hash, + false, + ); + let signed_block_header_3 = make_signed_block_header_from_header( + &signed_block_3.clone_header(), + &[], + chain_name_hash, + false, + ); ( signed_block_header_1, signed_block_header_2, diff --git a/node/src/types/validator_matrix.rs b/node/src/types/validator_matrix.rs index 4dbb04cfb2..644fb579d4 100644 --- a/node/src/types/validator_matrix.rs +++ b/node/src/types/validator_matrix.rs @@ -13,7 +13,10 @@ use serde::Serialize; use static_assertions::const_assert; use tracing::info; -use casper_types::{BlockHeaderV2, EraId, FinalitySignature, PublicKey, SecretKey, U512}; +use casper_types::{ + BlockHeaderV2, ChainNameDigest, EraId, FinalitySignature, FinalitySignatureV2, PublicKey, + SecretKey, U512, +}; const MAX_VALIDATOR_MATRIX_ENTRIES: usize = 6; const_assert!(MAX_VALIDATOR_MATRIX_ENTRIES % 2 == 0); @@ -41,6 +44,7 @@ impl SignatureWeight { #[derive(Clone, DataSize)] pub(crate) struct ValidatorMatrix { inner: Arc>>, + chainspec_name_hash: ChainNameDigest, chainspec_validators: Option>>, chainspec_activation_era: EraId, #[data_size(skip)] @@ -54,6 +58,7 @@ pub(crate) struct ValidatorMatrix { impl ValidatorMatrix { pub(crate) fn new( finality_threshold_fraction: Ratio, + chainspec_name_hash: ChainNameDigest, chainspec_validators: Option>, chainspec_activation_era: EraId, secret_signing_key: Arc, @@ -64,6 +69,7 @@ impl ValidatorMatrix { ValidatorMatrix { inner, finality_threshold_fraction, + chainspec_name_hash, chainspec_validators: chainspec_validators.map(Arc::new), chainspec_activation_era, secret_signing_key, @@ -76,6 +82,8 @@ impl ValidatorMatrix { /// Creates a new validator matrix with just a single validator. #[cfg(test)] pub(crate) fn new_with_validator(secret_signing_key: Arc) -> Self { + use casper_types::Digest; + let public_signing_key = PublicKey::from(&*secret_signing_key); let finality_threshold_fraction = Ratio::new(1, 3); let era_id = EraId::new(0); @@ -86,6 +94,7 @@ impl ValidatorMatrix { ); ValidatorMatrix { inner: Arc::new(RwLock::new(iter::once((era_id, weights)).collect())), + chainspec_name_hash: ChainNameDigest::new(Digest::hash(b"casper-example")), chainspec_validators: None, chainspec_activation_era: EraId::from(0), finality_threshold_fraction, @@ -272,11 +281,16 @@ impl ValidatorMatrix { .is_self_validator_in_era(block_header.era_id()) .unwrap_or(false) { - return Some(FinalitySignature::create( - block_header.block_hash(), - block_header.era_id(), - &self.secret_signing_key, - )); + return Some( + FinalitySignatureV2::create( + block_header.block_hash(), + block_header.height(), + block_header.era_id(), + self.chainspec_name_hash, + &self.secret_signing_key, + ) + .into(), + ); } None } @@ -289,6 +303,11 @@ impl ValidatorMatrix { self.read_inner().keys().copied().collect_vec() } + #[cfg(test)] + pub fn chain_name_hash(&self) -> ChainNameDigest { + self.chainspec_name_hash + } + #[cfg(test)] pub(crate) fn purge_era_validators(&mut self, era_id: &EraId) { self.inner.write().unwrap().remove(era_id); diff --git a/node/src/utils/block_signatures.rs b/node/src/utils/block_signatures.rs index f92c5a4ee2..0087bff1f2 100644 --- a/node/src/utils/block_signatures.rs +++ b/node/src/utils/block_signatures.rs @@ -144,7 +144,10 @@ pub(crate) enum BlockSignatureError { mod tests { use rand::Rng; - use casper_types::{crypto, testing::TestRng, BlockHash, EraId, FinalitySignature, SecretKey}; + use casper_types::{ + crypto, testing::TestRng, BlockHash, BlockSignaturesV2, ChainNameDigest, EraId, + FinalitySignature, SecretKey, + }; use super::*; @@ -169,17 +172,18 @@ mod tests { rng: &mut TestRng, validators: &BTreeMap, n_sigs: usize, - ) -> BlockSignatures { + ) -> BlockSignaturesV2 { let era_id = EraId::new(rng.gen_range(10..100)); let block_hash = BlockHash::random(rng); + let block_height = rng.gen(); + let chain_name_hash = ChainNameDigest::random(rng); - let mut sigs = BlockSignatures::new(block_hash, era_id); + let mut sigs = BlockSignaturesV2::new(block_hash, block_height, era_id, chain_name_hash); for (pub_key, secret_key) in validators.iter().take(n_sigs) { let sig = crypto::sign(block_hash, secret_key, pub_key); - let finality_sig = FinalitySignature::new(block_hash, era_id, sig, pub_key.clone()); - sigs.insert_signature(finality_sig); + sigs.insert_signature(pub_key.clone(), sig); } sigs @@ -214,7 +218,7 @@ mod tests { let result = check_sufficient_block_signatures( &validator_weights, fault_tolerance_fraction, - Some(&insufficient), + Some(&BlockSignatures::from(insufficient)), ); assert!(matches!( result, @@ -230,7 +234,7 @@ mod tests { let result = check_sufficient_block_signatures( &validator_weights, fault_tolerance_fraction, - Some(&just_enough_weight), + Some(&BlockSignatures::from(just_enough_weight)), ); assert!(result.is_ok()); } @@ -268,7 +272,7 @@ mod tests { let result = check_sufficient_block_signatures_with_quorum_formula( &validator_weights, fault_tolerance_fraction, - Some(&insufficient), + Some(&BlockSignatures::from(insufficient)), custom_quorum_formula, ); assert!(matches!( @@ -285,7 +289,7 @@ mod tests { let result = check_sufficient_block_signatures_with_quorum_formula( &validator_weights, fault_tolerance_fraction, - Some(&just_enough_weight), + Some(&BlockSignatures::from(just_enough_weight)), custom_quorum_formula, ); assert!(result.is_ok()); @@ -332,21 +336,41 @@ mod tests { let result = check_sufficient_block_signatures( &validator_weights, fault_tolerance_fraction, - Some(&signatures), + Some(&BlockSignatures::from(signatures.clone())), ); assert!(result.is_ok()); // Smuggle bogus proofs in. let block_hash = *signatures.block_hash(); + let block_height = signatures.block_height(); let era_id = signatures.era_id(); - let finality_sig_1 = FinalitySignature::random_for_block(block_hash, era_id, &mut rng); - signatures.insert_signature(finality_sig_1.clone()); - let finality_sig_2 = FinalitySignature::random_for_block(block_hash, era_id, &mut rng); - signatures.insert_signature(finality_sig_2.clone()); + let chain_name_hash = signatures.chain_name_hash(); + let finality_sig_1 = FinalitySignature::random_for_block( + block_hash, + block_height, + era_id, + chain_name_hash, + &mut rng, + ); + signatures.insert_signature( + finality_sig_1.public_key().clone(), + *finality_sig_1.signature(), + ); + let finality_sig_2 = FinalitySignature::random_for_block( + block_hash, + block_height, + era_id, + chain_name_hash, + &mut rng, + ); + signatures.insert_signature( + finality_sig_2.public_key().clone(), + *finality_sig_2.signature(), + ); let result = check_sufficient_block_signatures( &validator_weights, fault_tolerance_fraction, - Some(&signatures), + Some(&BlockSignatures::from(signatures)), ); let error = result.unwrap_err(); if let BlockSignatureError::BogusValidators { diff --git a/node/src/utils/specimen.rs b/node/src/utils/specimen.rs index aa084c934a..828feba897 100644 --- a/node/src/utils/specimen.rs +++ b/node/src/utils/specimen.rs @@ -22,13 +22,14 @@ use casper_types::{ bytesrepr::Bytes, crypto::{sign, PublicKey, Signature}, AccessRights, AsymmetricType, Block, BlockHash, BlockHeader, BlockHeaderV1, BlockHeaderV2, - BlockSignatures, BlockV2, ChunkWithProof, Deploy, DeployApproval, DeployApprovalsHash, - DeployHash, DeployId, Digest, EraEndV1, EraEndV2, EraId, EraReport, ExecutableDeployItem, - FinalitySignature, FinalitySignatureId, PackageHash, ProtocolVersion, RewardedSignatures, - RuntimeArgs, SecretKey, SemVer, SignedBlockHeader, SingleBlockRewardedSignatures, TimeDiff, - Timestamp, Transaction, TransactionApprovalsHash, TransactionHash, TransactionId, - TransactionV1, TransactionV1Approval, TransactionV1ApprovalsHash, TransactionV1Builder, - TransactionV1Hash, URef, KEY_HASH_LENGTH, U512, + BlockSignatures, BlockSignaturesV2, BlockV2, ChainNameDigest, ChunkWithProof, Deploy, + DeployApproval, DeployApprovalsHash, DeployHash, DeployId, Digest, EraEndV1, EraEndV2, EraId, + EraReport, ExecutableDeployItem, FinalitySignature, FinalitySignatureId, FinalitySignatureV2, + PackageHash, ProtocolVersion, RewardedSignatures, RuntimeArgs, SecretKey, SemVer, + SignedBlockHeader, SingleBlockRewardedSignatures, TimeDiff, Timestamp, Transaction, + TransactionApprovalsHash, TransactionHash, TransactionId, TransactionV1, TransactionV1Approval, + TransactionV1ApprovalsHash, TransactionV1Builder, TransactionV1Hash, URef, KEY_HASH_LENGTH, + U512, }; use crate::{ @@ -658,18 +659,17 @@ impl LargestSpecimen for SignedBlockHeader { impl LargestSpecimen for BlockSignatures { fn largest_specimen(estimator: &E, cache: &mut Cache) -> Self { - let mut block_signatures = BlockSignatures::new( + let mut block_signatures = BlockSignaturesV2::new( + LargestSpecimen::largest_specimen(estimator, cache), + LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), ); - let block_hash = *block_signatures.block_hash(); - let era_id = block_signatures.era_id(); let sigs = btree_map_distinct_from_prop(estimator, "validator_count", cache); sigs.into_iter().for_each(|(public_key, sig)| { - block_signatures - .insert_signature(FinalitySignature::new(block_hash, era_id, sig, public_key)); + block_signatures.insert_signature(public_key, sig); }); - block_signatures + BlockSignatures::V2(block_signatures) } } @@ -735,12 +735,14 @@ impl LargestSpecimen for FinalizedBlock { impl LargestSpecimen for FinalitySignature { fn largest_specimen(estimator: &E, cache: &mut Cache) -> Self { - FinalitySignature::new( + FinalitySignature::V2(FinalitySignatureV2::new( LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), - ) + LargestSpecimen::largest_specimen(estimator, cache), + LargestSpecimen::largest_specimen(estimator, cache), + )) } } @@ -770,6 +772,12 @@ impl LargestSpecimen for BlockHash { } } +impl LargestSpecimen for ChainNameDigest { + fn largest_specimen(estimator: &E, cache: &mut Cache) -> Self { + ChainNameDigest::new(LargestSpecimen::largest_specimen(estimator, cache)) + } +} + // impls for `casper_hashing`, which is technically a foreign crate -- so we put them here. impl LargestSpecimen for Digest { fn largest_specimen(_estimator: &E, _cache: &mut Cache) -> Self { diff --git a/types/src/block.rs b/types/src/block.rs index 687a393e51..719770c744 100644 --- a/types/src/block.rs +++ b/types/src/block.rs @@ -4,6 +4,7 @@ mod block_header; mod block_signatures; mod block_v1; mod block_v2; +mod chain_name_digest; mod era_end; mod finality_signature; mod finality_signature_id; @@ -39,11 +40,14 @@ use crate::{ pub use block_body::{BlockBody, BlockBodyV1, BlockBodyV2}; pub use block_hash::BlockHash; pub use block_header::{BlockHeader, BlockHeaderV1, BlockHeaderV2}; -pub use block_signatures::{BlockSignatures, BlockSignaturesMergeError}; +pub use block_signatures::{ + BlockSignatures, BlockSignaturesMergeError, BlockSignaturesV1, BlockSignaturesV2, +}; pub use block_v1::BlockV1; pub use block_v2::BlockV2; +pub use chain_name_digest::ChainNameDigest; pub use era_end::{EraEnd, EraEndV1, EraEndV2, EraReport}; -pub use finality_signature::FinalitySignature; +pub use finality_signature::{FinalitySignature, FinalitySignatureV1, FinalitySignatureV2}; pub use finality_signature_id::FinalitySignatureId; #[cfg(all(feature = "std", feature = "json-schema"))] pub use json_compatibility::JsonBlockWithSignatures; diff --git a/types/src/block/block_signatures.rs b/types/src/block/block_signatures.rs index 5bba42d745..6881c29acd 100644 --- a/types/src/block/block_signatures.rs +++ b/types/src/block/block_signatures.rs @@ -1,207 +1,393 @@ -use alloc::collections::BTreeMap; -use core::fmt::{self, Display, Formatter}; +mod block_signatures_v1; +mod block_signatures_v2; + +pub use block_signatures_v1::BlockSignaturesV1; +pub use block_signatures_v2::BlockSignaturesV2; + +use alloc::{collections::BTreeMap, vec::Vec}; +use core::{ + fmt::{self, Display, Formatter}, + hash::Hash, +}; +use itertools::Either; #[cfg(feature = "std")] use std::error::Error as StdError; #[cfg(feature = "datasize")] use datasize::DataSize; -#[cfg(any(feature = "once_cell", test))] -use once_cell::sync::OnceCell; #[cfg(any(feature = "std", test))] use serde::{Deserialize, Serialize}; -use super::{BlockHash, FinalitySignature}; -use crate::{crypto, EraId, PublicKey, Signature}; +use crate::{ + bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH}, + crypto, BlockHash, ChainNameDigest, EraId, FinalitySignature, PublicKey, Signature, +}; -/// An error returned during an attempt to merge two incompatible [`BlockSignatures`]. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -#[non_exhaustive] -pub enum BlockSignaturesMergeError { - /// A mismatch between block hashes. - BlockHashMismatch { - /// The `self` hash. - self_hash: BlockHash, - /// The `other` hash. - other_hash: BlockHash, - }, - /// A mismatch between era IDs. - EraIdMismatch { - /// The `self` era ID. - self_era_id: EraId, - /// The `other` era ID. - other_era_id: EraId, - }, -} - -impl Display for BlockSignaturesMergeError { - fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - match self { - BlockSignaturesMergeError::BlockHashMismatch { - self_hash, - other_hash, - } => { - write!( - formatter, - "mismatch between block hashes while merging block signatures - self: {}, \ - other: {}", - self_hash, other_hash - ) - } - BlockSignaturesMergeError::EraIdMismatch { - self_era_id, - other_era_id, - } => { - write!( - formatter, - "mismatch between era ids while merging block signatures - self: {}, other: \ - {}", - self_era_id, other_era_id - ) - } - } - } -} +const TAG_LENGTH: usize = U8_SERIALIZED_LENGTH; -#[cfg(feature = "std")] -impl StdError for BlockSignaturesMergeError {} +/// Tag for block signatures v1. +pub const BLOCK_SIGNATURES_V1_TAG: u8 = 0; +/// Tag for block signatures v2. +pub const BLOCK_SIGNATURES_V2_TAG: u8 = 1; /// A collection of signatures for a single block, along with the associated block's hash and era /// ID. #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] #[cfg_attr(any(feature = "std", test), derive(Serialize, Deserialize))] #[cfg_attr(feature = "datasize", derive(DataSize))] -pub struct BlockSignatures { - /// The block hash. - pub(super) block_hash: BlockHash, - /// The era ID in which this block was created. - pub(super) era_id: EraId, - /// The proofs of the block, i.e. a collection of validators' signatures of the block hash. - pub(super) proofs: BTreeMap, +pub enum BlockSignatures { + /// Version 1 of the block signatures. + V1(BlockSignaturesV1), + /// Version 2 of the block signatures. + V2(BlockSignaturesV2), } impl BlockSignatures { - /// Constructs a new `BlockSignatures`. - pub fn new(block_hash: BlockHash, era_id: EraId) -> Self { - BlockSignatures { - block_hash, - era_id, - proofs: BTreeMap::new(), - } - } - /// Returns the block hash of the associated block. pub fn block_hash(&self) -> &BlockHash { - &self.block_hash + match self { + BlockSignatures::V1(block_signatures) => block_signatures.block_hash(), + BlockSignatures::V2(block_signatures) => block_signatures.block_hash(), + } } /// Returns the era id of the associated block. pub fn era_id(&self) -> EraId { - self.era_id + match self { + BlockSignatures::V1(block_signatures) => block_signatures.era_id(), + BlockSignatures::V2(block_signatures) => block_signatures.era_id(), + } } /// Returns the finality signature associated with the given public key, if available. pub fn finality_signature(&self, public_key: &PublicKey) -> Option { - self.proofs - .get(public_key) - .map(|signature| FinalitySignature { - block_hash: self.block_hash, - era_id: self.era_id, - signature: *signature, - public_key: public_key.clone(), - #[cfg(any(feature = "once_cell", test))] - is_verified: OnceCell::new(), - }) + match self { + BlockSignatures::V1(block_signatures) => block_signatures + .finality_signature(public_key) + .map(FinalitySignature::V1), + BlockSignatures::V2(block_signatures) => block_signatures + .finality_signature(public_key) + .map(FinalitySignature::V2), + } } /// Returns `true` if there is a signature associated with the given public key. pub fn has_finality_signature(&self, public_key: &PublicKey) -> bool { - self.proofs.contains_key(public_key) + match self { + BlockSignatures::V1(block_signatures) => { + block_signatures.has_finality_signature(public_key) + } + BlockSignatures::V2(block_signatures) => { + block_signatures.has_finality_signature(public_key) + } + } } /// Returns an iterator over all the signatures. pub fn finality_signatures(&self) -> impl Iterator + '_ { - self.proofs - .iter() - .map(move |(public_key, signature)| FinalitySignature { - block_hash: self.block_hash, - era_id: self.era_id, - signature: *signature, - public_key: public_key.clone(), - #[cfg(any(feature = "once_cell", test))] - is_verified: OnceCell::new(), - }) + match self { + BlockSignatures::V1(block_signatures) => Either::Left( + block_signatures + .finality_signatures() + .map(FinalitySignature::V1), + ), + BlockSignatures::V2(block_signatures) => Either::Right( + block_signatures + .finality_signatures() + .map(FinalitySignature::V2), + ), + } + } + + /// Returns an `BTreeMap` of public keys to signatures. + pub fn proofs(&self) -> &BTreeMap { + match self { + BlockSignatures::V1(block_signatures) => &block_signatures.proofs, + BlockSignatures::V2(block_signatures) => &block_signatures.proofs, + } } /// Returns an iterator over all the validator public keys. pub fn signers(&self) -> impl Iterator + '_ { - self.proofs.keys() + match self { + BlockSignatures::V1(block_signatures) => Either::Left(block_signatures.signers()), + BlockSignatures::V2(block_signatures) => Either::Right(block_signatures.signers()), + } } /// Returns the number of signatures in the collection. pub fn len(&self) -> usize { - self.proofs.len() + match self { + BlockSignatures::V1(block_signatures) => block_signatures.len(), + BlockSignatures::V2(block_signatures) => block_signatures.len(), + } } /// Returns `true` if there are no signatures in the collection. pub fn is_empty(&self) -> bool { - self.proofs.is_empty() - } - - /// Inserts a new signature. - pub fn insert_signature(&mut self, finality_signature: FinalitySignature) { - let _ = self - .proofs - .insert(finality_signature.public_key, finality_signature.signature); + match self { + BlockSignatures::V1(block_signatures) => block_signatures.is_empty(), + BlockSignatures::V2(block_signatures) => block_signatures.is_empty(), + } } /// Merges the collection of signatures in `other` into `self`. /// - /// Returns an error if the block hashes or era IDs do not match. + /// Returns an error if the block hashes, block heights, era IDs, or chain name hashes do not + /// match. pub fn merge(&mut self, mut other: Self) -> Result<(), BlockSignaturesMergeError> { - if self.block_hash != other.block_hash { + if self.block_hash() != other.block_hash() { return Err(BlockSignaturesMergeError::BlockHashMismatch { - self_hash: self.block_hash, - other_hash: other.block_hash, + self_hash: *self.block_hash(), + other_hash: *other.block_hash(), }); } - if self.era_id != other.era_id { + if self.era_id() != other.era_id() { return Err(BlockSignaturesMergeError::EraIdMismatch { - self_era_id: self.era_id, - other_era_id: other.era_id, + self_era_id: self.era_id(), + other_era_id: other.era_id(), }); } - self.proofs.append(&mut other.proofs); + if let (BlockSignatures::V2(self_), BlockSignatures::V2(other)) = (&self, &other) { + if self_.block_height != other.block_height { + return Err(BlockSignaturesMergeError::BlockHeightMismatch { + self_height: self_.block_height, + other_height: other.block_height, + }); + } + if self_.chain_name_hash != other.chain_name_hash { + return Err(BlockSignaturesMergeError::ChainNameHashMismatch { + self_chain_name_hash: self_.chain_name_hash, + other_chain_name_hash: other.chain_name_hash, + }); + } + } + + match (self, &mut other) { + (BlockSignatures::V1(self_), BlockSignatures::V1(other)) => { + self_.proofs.append(&mut other.proofs); + } + (BlockSignatures::V2(self_), BlockSignatures::V2(other)) => { + self_.proofs.append(&mut other.proofs); + } + (BlockSignatures::V1(self_), BlockSignatures::V2(other)) => { + self_.proofs.append(&mut other.proofs); + } + (BlockSignatures::V2(self_), BlockSignatures::V1(other)) => { + self_.proofs.append(&mut other.proofs); + } + } Ok(()) } /// Returns `Ok` if and only if all the signatures are cryptographically valid. pub fn is_verified(&self) -> Result<(), crypto::Error> { - for (public_key, signature) in self.proofs.iter() { - let signature = FinalitySignature { - block_hash: self.block_hash, - era_id: self.era_id, - signature: *signature, - public_key: public_key.clone(), - #[cfg(any(feature = "once_cell", test))] - is_verified: OnceCell::new(), - }; - signature.is_verified()?; + match self { + BlockSignatures::V1(block_signatures) => block_signatures.is_verified(), + BlockSignatures::V2(block_signatures) => block_signatures.is_verified(), + } + } + + /// Converts self into a `BTreeMap` of public keys to signatures. + pub fn into_proofs(self) -> BTreeMap { + match self { + BlockSignatures::V1(block_signatures) => block_signatures.proofs, + BlockSignatures::V2(block_signatures) => block_signatures.proofs, } - Ok(()) + } + + /// Inserts a new signature. + pub fn insert_signature(&mut self, public_key: PublicKey, signature: Signature) { + match self { + BlockSignatures::V1(block_signatures) => { + block_signatures.insert_signature(public_key, signature) + } + BlockSignatures::V2(block_signatures) => { + block_signatures.insert_signature(public_key, signature) + } + } + } + + /// Sets the era ID to its max value, rendering it and hence `self` invalid (assuming the + /// relevant era ID for this `SignedBlockHeader` wasn't already the max value). + #[cfg(any(feature = "testing", test))] + pub fn invalidate_era(&mut self) { + match self { + BlockSignatures::V1(block_signatures) => block_signatures.era_id = EraId::new(u64::MAX), + BlockSignatures::V2(block_signatures) => block_signatures.era_id = EraId::new(u64::MAX), + } + } + + /// Replaces the signature field of the last `proofs` entry with the `System` variant + /// of [`Signature`], rendering that entry invalid. + #[cfg(any(feature = "testing", test))] + pub fn invalidate_last_signature(&mut self) { + let proofs = match self { + BlockSignatures::V1(block_signatures) => &mut block_signatures.proofs, + BlockSignatures::V2(block_signatures) => &mut block_signatures.proofs, + }; + let last_proof = proofs + .last_entry() + .expect("should have at least one signature"); + *last_proof.into_mut() = Signature::System; } } impl Display for BlockSignatures { fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - write!( - formatter, - "block signatures for {} in {} with {} proofs", - self.block_hash, - self.era_id, - self.proofs.len() - ) + match self { + BlockSignatures::V1(block_signatures) => write!(formatter, "{}", block_signatures), + BlockSignatures::V2(block_signatures) => write!(formatter, "{}", block_signatures), + } + } +} + +impl From for BlockSignatures { + fn from(block_signatures: BlockSignaturesV1) -> Self { + BlockSignatures::V1(block_signatures) + } +} + +impl From for BlockSignatures { + fn from(block_signatures: BlockSignaturesV2) -> Self { + BlockSignatures::V2(block_signatures) + } +} + +impl ToBytes for BlockSignatures { + fn to_bytes(&self) -> Result, bytesrepr::Error> { + let mut buf = bytesrepr::allocate_buffer(self)?; + self.write_bytes(&mut buf)?; + Ok(buf) + } + + fn write_bytes(&self, writer: &mut Vec) -> Result<(), bytesrepr::Error> { + match self { + BlockSignatures::V1(block_signatures) => { + writer.push(BLOCK_SIGNATURES_V1_TAG); + block_signatures.write_bytes(writer)?; + } + BlockSignatures::V2(block_signatures) => { + writer.push(BLOCK_SIGNATURES_V2_TAG); + block_signatures.write_bytes(writer)?; + } + } + Ok(()) + } + + fn serialized_length(&self) -> usize { + TAG_LENGTH + + match self { + BlockSignatures::V1(block_signatures) => block_signatures.serialized_length(), + BlockSignatures::V2(block_signatures) => block_signatures.serialized_length(), + } } } + +impl FromBytes for BlockSignatures { + fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> { + let (tag, remainder) = u8::from_bytes(bytes)?; + match tag { + BLOCK_SIGNATURES_V1_TAG => { + let (block_signatures, remainder) = BlockSignaturesV1::from_bytes(remainder)?; + Ok((BlockSignatures::V1(block_signatures), remainder)) + } + BLOCK_SIGNATURES_V2_TAG => { + let (block_signatures, remainder) = BlockSignaturesV2::from_bytes(remainder)?; + Ok((BlockSignatures::V2(block_signatures), remainder)) + } + _ => Err(bytesrepr::Error::Formatting), + } + } +} + +/// An error returned during an attempt to merge two incompatible [`BlockSignaturesV1`]. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[non_exhaustive] +pub enum BlockSignaturesMergeError { + /// A mismatch between block hashes. + BlockHashMismatch { + /// The `self` hash. + self_hash: BlockHash, + /// The `other` hash. + other_hash: BlockHash, + }, + /// A mismatch between block heights. + BlockHeightMismatch { + /// The `self` height. + self_height: u64, + /// The `other` height. + other_height: u64, + }, + /// A mismatch between era IDs. + EraIdMismatch { + /// The `self` era ID. + self_era_id: EraId, + /// The `other` era ID. + other_era_id: EraId, + }, + /// A mismatch between chain name hashes. + ChainNameHashMismatch { + /// The `self` chain name hash. + self_chain_name_hash: ChainNameDigest, + /// The `other` chain name hash. + other_chain_name_hash: ChainNameDigest, + }, +} + +impl Display for BlockSignaturesMergeError { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + match self { + BlockSignaturesMergeError::BlockHashMismatch { + self_hash, + other_hash, + } => { + write!( + formatter, + "mismatch between block hashes while merging block signatures - self: {}, \ + other: {}", + self_hash, other_hash + ) + } + BlockSignaturesMergeError::BlockHeightMismatch { + self_height, + other_height, + } => { + write!( + formatter, + "mismatch between block heights while merging block signatures - self: {}, \ + other: {}", + self_height, other_height + ) + } + BlockSignaturesMergeError::EraIdMismatch { + self_era_id, + other_era_id, + } => { + write!( + formatter, + "mismatch between era ids while merging block signatures - self: {}, other: \ + {}", + self_era_id, other_era_id + ) + } + BlockSignaturesMergeError::ChainNameHashMismatch { + self_chain_name_hash, + other_chain_name_hash, + } => { + write!( + formatter, + "mismatch between chain name hashes while merging block signatures - self: {}, \ + other: {}", + self_chain_name_hash, other_chain_name_hash + ) + } + } + } +} + +#[cfg(feature = "std")] +impl StdError for BlockSignaturesMergeError {} diff --git a/types/src/block/block_signatures/block_signatures_v1.rs b/types/src/block/block_signatures/block_signatures_v1.rs new file mode 100644 index 0000000000..2bdcfa0efc --- /dev/null +++ b/types/src/block/block_signatures/block_signatures_v1.rs @@ -0,0 +1,165 @@ +use alloc::{collections::BTreeMap, vec::Vec}; +use core::fmt::{self, Display, Formatter}; + +#[cfg(feature = "datasize")] +use datasize::DataSize; +#[cfg(any(feature = "std", test))] +use serde::{Deserialize, Serialize}; + +use super::BlockHash; +use crate::{ + bytesrepr::{self, FromBytes, ToBytes}, + crypto, EraId, FinalitySignatureV1, PublicKey, Signature, +}; + +/// A collection of signatures for a single block, along with the associated block's hash and era +/// ID. +#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] +#[cfg_attr(any(feature = "std", test), derive(Serialize, Deserialize))] +#[cfg_attr(feature = "datasize", derive(DataSize))] +pub struct BlockSignaturesV1 { + /// The block hash. + pub(super) block_hash: BlockHash, + /// The era ID in which this block was created. + pub(super) era_id: EraId, + /// The proofs of the block, i.e. a collection of validators' signatures of the block hash. + pub(super) proofs: BTreeMap, +} + +impl BlockSignaturesV1 { + /// Constructs a new `BlockSignaturesV1`. + pub fn new(block_hash: BlockHash, era_id: EraId) -> Self { + BlockSignaturesV1 { + block_hash, + era_id, + proofs: BTreeMap::new(), + } + } + + /// Returns the block hash of the associated block. + pub fn block_hash(&self) -> &BlockHash { + &self.block_hash + } + + /// Returns the era id of the associated block. + pub fn era_id(&self) -> EraId { + self.era_id + } + + /// Returns the finality signature associated with the given public key, if available. + pub fn finality_signature(&self, public_key: &PublicKey) -> Option { + self.proofs + .get(public_key) + .map(|signature| FinalitySignatureV1 { + block_hash: self.block_hash, + era_id: self.era_id, + signature: *signature, + public_key: public_key.clone(), + #[cfg(any(feature = "once_cell", test))] + is_verified: Default::default(), + }) + } + + /// Returns `true` if there is a signature associated with the given public key. + pub fn has_finality_signature(&self, public_key: &PublicKey) -> bool { + self.proofs.contains_key(public_key) + } + + /// Returns an iterator over all the signatures. + pub fn finality_signatures(&self) -> impl Iterator + '_ { + self.proofs + .iter() + .map(move |(public_key, signature)| FinalitySignatureV1 { + block_hash: self.block_hash, + era_id: self.era_id, + signature: *signature, + public_key: public_key.clone(), + #[cfg(any(feature = "once_cell", test))] + is_verified: Default::default(), + }) + } + + /// Returns an iterator over all the validator public keys. + pub fn signers(&self) -> impl Iterator + '_ { + self.proofs.keys() + } + + /// Returns the number of signatures in the collection. + pub fn len(&self) -> usize { + self.proofs.len() + } + + /// Returns `true` if there are no signatures in the collection. + pub fn is_empty(&self) -> bool { + self.proofs.is_empty() + } + + /// Inserts a new signature. + pub fn insert_signature(&mut self, public_key: PublicKey, signature: Signature) { + let _ = self.proofs.insert(public_key, signature); + } + + /// Returns `Ok` if and only if all the signatures are cryptographically valid. + pub fn is_verified(&self) -> Result<(), crypto::Error> { + for (public_key, signature) in self.proofs.iter() { + let signature = FinalitySignatureV1 { + block_hash: self.block_hash, + era_id: self.era_id, + signature: *signature, + public_key: public_key.clone(), + #[cfg(any(feature = "once_cell", test))] + is_verified: Default::default(), + }; + signature.is_verified()?; + } + Ok(()) + } +} + +impl Display for BlockSignaturesV1 { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + write!( + formatter, + "block signatures for {} in {} with {} proofs", + self.block_hash, + self.era_id, + self.proofs.len() + ) + } +} + +impl ToBytes for BlockSignaturesV1 { + fn to_bytes(&self) -> Result, bytesrepr::Error> { + let mut buf = bytesrepr::allocate_buffer(self)?; + self.write_bytes(&mut buf)?; + Ok(buf) + } + + fn write_bytes(&self, writer: &mut Vec) -> Result<(), bytesrepr::Error> { + self.block_hash.write_bytes(writer)?; + self.era_id.write_bytes(writer)?; + self.proofs.write_bytes(writer) + } + + fn serialized_length(&self) -> usize { + self.block_hash.serialized_length() + + self.era_id.serialized_length() + + self.proofs.serialized_length() + } +} + +impl FromBytes for BlockSignaturesV1 { + fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> { + let (block_hash, remainder) = BlockHash::from_bytes(bytes)?; + let (era_id, remainder) = EraId::from_bytes(remainder)?; + let (proofs, remainder) = BTreeMap::::from_bytes(remainder)?; + Ok(( + Self { + block_hash, + era_id, + proofs, + }, + remainder, + )) + } +} diff --git a/types/src/block/block_signatures/block_signatures_v2.rs b/types/src/block/block_signatures/block_signatures_v2.rs new file mode 100644 index 0000000000..1bdc1861f7 --- /dev/null +++ b/types/src/block/block_signatures/block_signatures_v2.rs @@ -0,0 +1,200 @@ +use alloc::{collections::BTreeMap, vec::Vec}; +use core::fmt::{self, Display, Formatter}; + +#[cfg(feature = "datasize")] +use datasize::DataSize; +#[cfg(any(feature = "std", test))] +use serde::{Deserialize, Serialize}; + +use crate::{ + bytesrepr::{self, FromBytes, ToBytes}, + crypto, BlockHash, ChainNameDigest, EraId, FinalitySignatureV2, PublicKey, Signature, +}; + +/// A collection of signatures for a single block, along with the associated block's hash and era +/// ID. +#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] +#[cfg_attr(any(feature = "std", test), derive(Serialize, Deserialize))] +#[cfg_attr(feature = "datasize", derive(DataSize))] +pub struct BlockSignaturesV2 { + /// The block hash. + pub(super) block_hash: BlockHash, + /// The block height. + pub(super) block_height: u64, + /// The era ID in which this block was created. + pub(super) era_id: EraId, + /// The hash of the chain name of the associated block. + pub(super) chain_name_hash: ChainNameDigest, + /// The proofs of the block, i.e. a collection of validators' signatures of the block hash. + pub(super) proofs: BTreeMap, +} + +impl BlockSignaturesV2 { + /// Constructs a new `BlockSignaturesV2`. + pub fn new( + block_hash: BlockHash, + block_height: u64, + era_id: EraId, + chain_name_hash: ChainNameDigest, + ) -> Self { + BlockSignaturesV2 { + block_hash, + block_height, + era_id, + chain_name_hash, + proofs: BTreeMap::new(), + } + } + + /// Returns the block hash of the associated block. + pub fn block_hash(&self) -> &BlockHash { + &self.block_hash + } + + /// Returns the block height of the associated block. + pub fn block_height(&self) -> u64 { + self.block_height + } + + /// Returns the era id of the associated block. + pub fn era_id(&self) -> EraId { + self.era_id + } + + /// Returns the chain name hash of the associated block. + pub fn chain_name_hash(&self) -> ChainNameDigest { + self.chain_name_hash + } + + /// Returns the finality signature associated with the given public key, if available. + pub fn finality_signature(&self, public_key: &PublicKey) -> Option { + self.proofs + .get(public_key) + .map(|signature| FinalitySignatureV2 { + block_hash: self.block_hash, + block_height: self.block_height, + era_id: self.era_id, + chain_name_hash: self.chain_name_hash, + signature: *signature, + public_key: public_key.clone(), + #[cfg(any(feature = "once_cell", test))] + is_verified: Default::default(), + }) + } + + /// Returns `true` if there is a signature associated with the given public key. + pub fn has_finality_signature(&self, public_key: &PublicKey) -> bool { + self.proofs.contains_key(public_key) + } + + /// Returns an iterator over all the signatures. + pub fn finality_signatures(&self) -> impl Iterator + '_ { + self.proofs + .iter() + .map(move |(public_key, signature)| FinalitySignatureV2 { + block_hash: self.block_hash, + block_height: self.block_height, + era_id: self.era_id, + chain_name_hash: self.chain_name_hash, + signature: *signature, + public_key: public_key.clone(), + #[cfg(any(feature = "once_cell", test))] + is_verified: Default::default(), + }) + } + + /// Returns an iterator over all the validator public keys. + pub fn signers(&self) -> impl Iterator + '_ { + self.proofs.keys() + } + + /// Returns the number of signatures in the collection. + pub fn len(&self) -> usize { + self.proofs.len() + } + + /// Returns `true` if there are no signatures in the collection. + pub fn is_empty(&self) -> bool { + self.proofs.is_empty() + } + + /// Inserts a new signature. + pub fn insert_signature(&mut self, public_key: PublicKey, signature: Signature) { + let _ = self.proofs.insert(public_key, signature); + } + + /// Returns `Ok` if and only if all the signatures are cryptographically valid. + pub fn is_verified(&self) -> Result<(), crypto::Error> { + for (public_key, signature) in self.proofs.iter() { + let signature = FinalitySignatureV2 { + block_hash: self.block_hash, + block_height: self.block_height, + era_id: self.era_id, + chain_name_hash: self.chain_name_hash, + signature: *signature, + public_key: public_key.clone(), + #[cfg(any(feature = "once_cell", test))] + is_verified: Default::default(), + }; + signature.is_verified()?; + } + Ok(()) + } +} + +impl Display for BlockSignaturesV2 { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + write!( + formatter, + "block signatures for {} in {} with {} proofs", + self.block_hash, + self.era_id, + self.proofs.len() + ) + } +} + +impl ToBytes for BlockSignaturesV2 { + fn to_bytes(&self) -> Result, bytesrepr::Error> { + let mut buf = bytesrepr::allocate_buffer(self)?; + self.write_bytes(&mut buf)?; + Ok(buf) + } + + fn write_bytes(&self, writer: &mut Vec) -> Result<(), bytesrepr::Error> { + self.block_hash.write_bytes(writer)?; + self.block_height.write_bytes(writer)?; + self.era_id.write_bytes(writer)?; + self.chain_name_hash.write_bytes(writer)?; + self.proofs.write_bytes(writer)?; + Ok(()) + } + + fn serialized_length(&self) -> usize { + self.block_hash.serialized_length() + + self.block_height.serialized_length() + + self.era_id.serialized_length() + + self.chain_name_hash.serialized_length() + + self.proofs.serialized_length() + } +} + +impl FromBytes for BlockSignaturesV2 { + fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> { + let (block_hash, remainder) = BlockHash::from_bytes(bytes)?; + let (block_height, remainder) = u64::from_bytes(remainder)?; + let (era_id, remainder) = EraId::from_bytes(remainder)?; + let (chain_name_hash, remainder) = ChainNameDigest::from_bytes(remainder)?; + let (proofs, remainder) = BTreeMap::::from_bytes(remainder)?; + Ok(( + Self { + block_hash, + block_height, + era_id, + chain_name_hash, + proofs, + }, + remainder, + )) + } +} diff --git a/types/src/block/chain_name_digest.rs b/types/src/block/chain_name_digest.rs new file mode 100644 index 0000000000..7f2d92234e --- /dev/null +++ b/types/src/block/chain_name_digest.rs @@ -0,0 +1,98 @@ +use core::fmt::{self, Display, Formatter}; + +use alloc::vec::Vec; + +#[cfg(feature = "datasize")] +use datasize::DataSize; +#[cfg(any(feature = "testing", test))] +use rand::Rng; +#[cfg(feature = "json-schema")] +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[cfg(any(feature = "testing", test))] +use crate::testing::TestRng; +use crate::{ + bytesrepr::{self, FromBytes, ToBytes}, + Digest, +}; + +/// A cryptographic hash of a chain name. +#[derive( + Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize, Debug, Default, +)] +#[cfg_attr(feature = "datasize", derive(DataSize))] +#[cfg_attr( + feature = "json-schema", + derive(JsonSchema), + schemars(description = "Hex-encoded cryptographic hash of a chain name.") +)] +#[serde(deny_unknown_fields)] +pub struct ChainNameDigest(Digest); + +impl ChainNameDigest { + /// The number of bytes in a `ChainNameDigest` digest. + pub const LENGTH: usize = Digest::LENGTH; + + /// Constructs a new `ChainNameDigest`. + pub const fn new(hash: Digest) -> Self { + ChainNameDigest(hash) + } + + /// Returns the wrapped inner digest. + pub fn inner(&self) -> &Digest { + &self.0 + } + + /// Returns a new `ChainNameDigest` directly initialized with the provided bytes; no hashing is + /// done. + #[cfg(any(feature = "testing", test))] + pub const fn from_raw(raw_digest: [u8; Self::LENGTH]) -> Self { + ChainNameDigest(Digest::from_raw(raw_digest)) + } + + /// Returns a random `ChainNameDigest`. + #[cfg(any(feature = "testing", test))] + pub fn random(rng: &mut TestRng) -> Self { + let hash = rng.gen::<[u8; Digest::LENGTH]>().into(); + ChainNameDigest(hash) + } +} + +impl Display for ChainNameDigest { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "chain-name-hash({})", self.0) + } +} + +impl ToBytes for ChainNameDigest { + fn write_bytes(&self, writer: &mut Vec) -> Result<(), bytesrepr::Error> { + self.0.write_bytes(writer) + } + + fn to_bytes(&self) -> Result, bytesrepr::Error> { + self.0.to_bytes() + } + + fn serialized_length(&self) -> usize { + self.0.serialized_length() + } +} + +impl FromBytes for ChainNameDigest { + fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> { + Digest::from_bytes(bytes).map(|(inner, remainder)| (Self(inner), remainder)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bytesrepr_roundtrip() { + let rng = &mut TestRng::new(); + let hash = ChainNameDigest::random(rng); + bytesrepr::test_serialization_roundtrip(&hash); + } +} diff --git a/types/src/block/finality_signature.rs b/types/src/block/finality_signature.rs index 57b1c2a6d8..4b908db3f7 100644 --- a/types/src/block/finality_signature.rs +++ b/types/src/block/finality_signature.rs @@ -1,266 +1,137 @@ -use alloc::vec::Vec; +mod finality_signature_v1; +mod finality_signature_v2; + +pub use finality_signature_v1::FinalitySignatureV1; +pub use finality_signature_v2::FinalitySignatureV2; + use core::{ - cmp::Ordering, fmt::{self, Display, Formatter}, - hash::{Hash, Hasher}, + hash::Hash, }; #[cfg(feature = "datasize")] use datasize::DataSize; -#[cfg(any(feature = "once_cell", test))] -use once_cell::sync::OnceCell; +#[cfg(any(feature = "testing", test))] +use rand::Rng; #[cfg(feature = "json-schema")] use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use super::BlockHash; +use crate::{crypto, BlockHash, EraId, PublicKey, Signature}; #[cfg(any(feature = "testing", test))] -use crate::testing::TestRng; -use crate::{crypto, EraId, PublicKey, SecretKey, Signature}; +use crate::{testing::TestRng, ChainNameDigest}; /// A validator's signature of a block, confirming it is finalized. /// /// Clients and joining nodes should wait until the signers' combined weight exceeds the fault /// tolerance threshold before accepting the block as finalized. -#[derive(Clone, Eq, Serialize, Deserialize, Debug)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)] #[cfg_attr( feature = "json-schema", derive(JsonSchema), schemars(description = "A validator's signature of a block, confirming it is finalized.") )] #[cfg_attr(feature = "datasize", derive(DataSize))] -pub struct FinalitySignature { - /// The block hash of the associated block. - pub(super) block_hash: BlockHash, - /// The era in which the associated block was created. - pub(super) era_id: EraId, - /// The signature over the block hash of the associated block. - pub(super) signature: Signature, - /// The public key of the signing validator. - pub(super) public_key: PublicKey, - #[serde(skip)] - #[cfg_attr( - all(any(feature = "once_cell", test), feature = "datasize"), - data_size(skip) - )] - #[cfg(any(feature = "once_cell", test))] - pub(super) is_verified: OnceCell>, +pub enum FinalitySignature { + /// Version 1 of the finality signature. + V1(FinalitySignatureV1), + /// Version 2 of the finality signature. + V2(FinalitySignatureV2), } impl FinalitySignature { - /// Constructs a new `FinalitySignature`. - pub fn create(block_hash: BlockHash, era_id: EraId, secret_key: &SecretKey) -> Self { - let bytes = Self::bytes_to_sign(&block_hash, era_id); - let public_key = PublicKey::from(secret_key); - let signature = crypto::sign(bytes, secret_key, &public_key); - FinalitySignature { - block_hash, - era_id, - signature, - public_key, - #[cfg(any(feature = "once_cell", test))] - is_verified: OnceCell::with_value(Ok(())), - } - } - /// Returns the block hash of the associated block. pub fn block_hash(&self) -> &BlockHash { - &self.block_hash + match self { + FinalitySignature::V1(fs) => fs.block_hash(), + FinalitySignature::V2(fs) => fs.block_hash(), + } } /// Returns the era in which the associated block was created. pub fn era_id(&self) -> EraId { - self.era_id - } - - /// Returns the signature over the block hash of the associated block. - pub fn signature(&self) -> &Signature { - &self.signature + match self { + FinalitySignature::V1(fs) => fs.era_id(), + FinalitySignature::V2(fs) => fs.era_id(), + } } /// Returns the public key of the signing validator. pub fn public_key(&self) -> &PublicKey { - &self.public_key + match self { + FinalitySignature::V1(fs) => fs.public_key(), + FinalitySignature::V2(fs) => fs.public_key(), + } } - /// Returns `Ok` if the signature is cryptographically valid. - pub fn is_verified(&self) -> Result<(), crypto::Error> { - #[cfg(any(feature = "once_cell", test))] - return self.is_verified.get_or_init(|| self.verify()).clone(); - - #[cfg(not(any(feature = "once_cell", test)))] - self.verify() + /// Returns the signature over the block hash of the associated block. + pub fn signature(&self) -> &Signature { + match self { + FinalitySignature::V1(fs) => fs.signature(), + FinalitySignature::V2(fs) => fs.signature(), + } } - /// Constructs a new `FinalitySignature`. - #[cfg(any(feature = "testing", test))] - pub fn new( - block_hash: BlockHash, - era_id: EraId, - signature: Signature, - public_key: PublicKey, - ) -> Self { - FinalitySignature { - block_hash, - era_id, - signature, - public_key, - #[cfg(any(feature = "once_cell", test))] - is_verified: OnceCell::new(), + /// Returns `Ok` if the signature is cryptographically valid. + pub fn is_verified(&self) -> Result<(), crypto::Error> { + match self { + FinalitySignature::V1(fs) => fs.is_verified(), + FinalitySignature::V2(fs) => fs.is_verified(), } } /// Returns a random `FinalitySignature`. #[cfg(any(feature = "testing", test))] pub fn random(rng: &mut TestRng) -> Self { - FinalitySignature::random_for_block(BlockHash::random(rng), EraId::random(rng), rng) + let block_hash = BlockHash::random(rng); + let block_height = rng.gen(); + let era_id = EraId::random(rng); + let chain_name_hash = ChainNameDigest::random(rng); + Self::random_for_block(block_hash, block_height, era_id, chain_name_hash, rng) } /// Returns a random `FinalitySignature` for the provided `block_hash` and `era_id`. #[cfg(any(feature = "testing", test))] - pub fn random_for_block(block_hash: BlockHash, era_id: EraId, rng: &mut TestRng) -> Self { - let secret_key = SecretKey::random(rng); - FinalitySignature::create(block_hash, era_id, &secret_key) - } - - fn bytes_to_sign(block_hash: &BlockHash, era_id: EraId) -> Vec { - let mut bytes = block_hash.inner().into_vec(); - bytes.extend_from_slice(&era_id.to_le_bytes()); - bytes - } - - fn verify(&self) -> Result<(), crypto::Error> { - let bytes = Self::bytes_to_sign(&self.block_hash, self.era_id); - crypto::verify(bytes, &self.signature, &self.public_key) - } -} - -impl Hash for FinalitySignature { - fn hash(&self, state: &mut H) { - // Ensure we initialize self.is_verified field. - let is_verified = self.is_verified().is_ok(); - // Destructure to make sure we don't accidentally omit fields. - #[cfg(any(feature = "once_cell", test))] - let FinalitySignature { - block_hash, - era_id, - signature, - public_key, - is_verified: _, - } = self; - #[cfg(not(any(feature = "once_cell", test)))] - let FinalitySignature { - block_hash, - era_id, - signature, - public_key, - } = self; - block_hash.hash(state); - era_id.hash(state); - signature.hash(state); - public_key.hash(state); - is_verified.hash(state); - } -} - -impl PartialEq for FinalitySignature { - fn eq(&self, other: &FinalitySignature) -> bool { - // Ensure we initialize self.is_verified field. - let is_verified = self.is_verified().is_ok(); - // Destructure to make sure we don't accidentally omit fields. - #[cfg(any(feature = "once_cell", test))] - let FinalitySignature { - block_hash, - era_id, - signature, - public_key, - is_verified: _, - } = self; - #[cfg(not(any(feature = "once_cell", test)))] - let FinalitySignature { - block_hash, - era_id, - signature, - public_key, - } = self; - *block_hash == other.block_hash - && *era_id == other.era_id - && *signature == other.signature - && *public_key == other.public_key - && is_verified == other.is_verified().is_ok() + pub fn random_for_block( + block_hash: BlockHash, + block_height: u64, + era_id: EraId, + chain_name_hash: ChainNameDigest, + rng: &mut TestRng, + ) -> Self { + if rng.gen_bool(0.5) { + FinalitySignature::V1(FinalitySignatureV1::random_for_block( + block_hash, era_id, rng, + )) + } else { + FinalitySignature::V2(FinalitySignatureV2::random_for_block( + block_hash, + block_height, + era_id, + chain_name_hash, + rng, + )) + } } } -impl Ord for FinalitySignature { - fn cmp(&self, other: &FinalitySignature) -> Ordering { - // Ensure we initialize self.is_verified field. - let is_verified = self.is_verified().is_ok(); - // Destructure to make sure we don't accidentally omit fields. - #[cfg(any(feature = "once_cell", test))] - let FinalitySignature { - block_hash, - era_id, - signature, - public_key, - is_verified: _, - } = self; - #[cfg(not(any(feature = "once_cell", test)))] - let FinalitySignature { - block_hash, - era_id, - signature, - public_key, - } = self; - block_hash - .cmp(&other.block_hash) - .then_with(|| era_id.cmp(&other.era_id)) - .then_with(|| signature.cmp(&other.signature)) - .then_with(|| public_key.cmp(&other.public_key)) - .then_with(|| is_verified.cmp(&other.is_verified().is_ok())) +impl From for FinalitySignature { + fn from(fs: FinalitySignatureV1) -> Self { + FinalitySignature::V1(fs) } } -impl PartialOrd for FinalitySignature { - fn partial_cmp(&self, other: &FinalitySignature) -> Option { - Some(self.cmp(other)) +impl From for FinalitySignature { + fn from(fs: FinalitySignatureV2) -> Self { + FinalitySignature::V2(fs) } } impl Display for FinalitySignature { - fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { - write!( - formatter, - "finality signature for {}, from {}", - self.block_hash, self.public_key - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::TestBlockBuilder; - - #[test] - fn finality_signature() { - let rng = &mut TestRng::new(); - let block = TestBlockBuilder::new().build(rng); - // Signature should be over both block hash and era id. - let secret_key = SecretKey::random(rng); - let public_key = PublicKey::from(&secret_key); - let era_id = EraId::from(1); - let finality_signature = FinalitySignature::create(*block.hash(), era_id, &secret_key); - finality_signature.is_verified().unwrap(); - let signature = finality_signature.signature; - // Verify that signature includes era id. - let invalid_finality_signature = FinalitySignature { - block_hash: *block.hash(), - era_id: EraId::from(2), - signature, - public_key, - is_verified: OnceCell::new(), - }; - // Test should fail b/c `signature` is over `era_id=1` and here we're using `era_id=2`. - assert!(invalid_finality_signature.is_verified().is_err()); + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + FinalitySignature::V1(fs) => write!(f, "{}", fs), + FinalitySignature::V2(fs) => write!(f, "{}", fs), + } } } diff --git a/types/src/block/finality_signature/finality_signature_v1.rs b/types/src/block/finality_signature/finality_signature_v1.rs new file mode 100644 index 0000000000..5fe272eb58 --- /dev/null +++ b/types/src/block/finality_signature/finality_signature_v1.rs @@ -0,0 +1,265 @@ +use alloc::vec::Vec; +use core::{ + cmp::Ordering, + fmt::{self, Display, Formatter}, + hash::{Hash, Hasher}, +}; + +#[cfg(feature = "datasize")] +use datasize::DataSize; +#[cfg(any(feature = "once_cell", test))] +use once_cell::sync::OnceCell; +#[cfg(feature = "json-schema")] +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[cfg(any(feature = "testing", test))] +use crate::testing::TestRng; +use crate::{crypto, BlockHash, EraId, PublicKey, SecretKey, Signature}; + +/// A validator's signature of a block, confirming it is finalized. +/// +/// Clients and joining nodes should wait until the signers' combined weight exceeds the fault +/// tolerance threshold before accepting the block as finalized. +#[derive(Clone, Eq, Serialize, Deserialize, Debug)] +#[cfg_attr( + feature = "json-schema", + derive(JsonSchema), + schemars(description = "A validator's signature of a block, confirming it is finalized.") +)] +#[cfg_attr(feature = "datasize", derive(DataSize))] +pub struct FinalitySignatureV1 { + /// The block hash of the associated block. + pub(crate) block_hash: BlockHash, + /// The era in which the associated block was created. + pub(crate) era_id: EraId, + /// The signature over the block hash of the associated block. + pub(crate) signature: Signature, + /// The public key of the signing validator. + pub(crate) public_key: PublicKey, + #[serde(skip)] + #[cfg_attr( + all(any(feature = "once_cell", test), feature = "datasize"), + data_size(skip) + )] + #[cfg(any(feature = "once_cell", test))] + pub(crate) is_verified: OnceCell>, +} + +impl FinalitySignatureV1 { + /// Constructs a new `FinalitySignatureV1`. + pub fn create(block_hash: BlockHash, era_id: EraId, secret_key: &SecretKey) -> Self { + let bytes = Self::bytes_to_sign(&block_hash, era_id); + let public_key = PublicKey::from(secret_key); + let signature = crypto::sign(bytes, secret_key, &public_key); + FinalitySignatureV1 { + block_hash, + era_id, + signature, + public_key, + #[cfg(any(feature = "once_cell", test))] + is_verified: OnceCell::with_value(Ok(())), + } + } + + /// Returns the block hash of the associated block. + pub fn block_hash(&self) -> &BlockHash { + &self.block_hash + } + + /// Returns the era in which the associated block was created. + pub fn era_id(&self) -> EraId { + self.era_id + } + + /// Returns the signature over the block hash of the associated block. + pub fn signature(&self) -> &Signature { + &self.signature + } + + /// Returns the public key of the signing validator. + pub fn public_key(&self) -> &PublicKey { + &self.public_key + } + + /// Returns `Ok` if the signature is cryptographically valid. + pub fn is_verified(&self) -> Result<(), crypto::Error> { + #[cfg(any(feature = "once_cell", test))] + return self.is_verified.get_or_init(|| self.verify()).clone(); + + #[cfg(not(any(feature = "once_cell", test)))] + self.verify() + } + + /// Constructs a new `FinalitySignatureV1`. + #[cfg(any(feature = "testing", test))] + pub fn new( + block_hash: BlockHash, + era_id: EraId, + signature: Signature, + public_key: PublicKey, + ) -> Self { + FinalitySignatureV1 { + block_hash, + era_id, + signature, + public_key, + #[cfg(any(feature = "once_cell", test))] + is_verified: OnceCell::new(), + } + } + + /// Returns a random `FinalitySignatureV1`. + #[cfg(any(feature = "testing", test))] + pub fn random(rng: &mut TestRng) -> Self { + FinalitySignatureV1::random_for_block(BlockHash::random(rng), EraId::random(rng), rng) + } + + /// Returns a random `FinalitySignatureV1` for the provided `block_hash` and `era_id`. + #[cfg(any(feature = "testing", test))] + pub fn random_for_block(block_hash: BlockHash, era_id: EraId, rng: &mut TestRng) -> Self { + let secret_key = SecretKey::random(rng); + FinalitySignatureV1::create(block_hash, era_id, &secret_key) + } + + fn bytes_to_sign(block_hash: &BlockHash, era_id: EraId) -> Vec { + let mut bytes = block_hash.inner().into_vec(); + bytes.extend_from_slice(&era_id.to_le_bytes()); + bytes + } + + fn verify(&self) -> Result<(), crypto::Error> { + let bytes = Self::bytes_to_sign(&self.block_hash, self.era_id); + crypto::verify(bytes, &self.signature, &self.public_key) + } +} + +impl Hash for FinalitySignatureV1 { + fn hash(&self, state: &mut H) { + // Ensure we initialize self.is_verified field. + let is_verified = self.is_verified().is_ok(); + // Destructure to make sure we don't accidentally omit fields. + #[cfg(any(feature = "once_cell", test))] + let FinalitySignatureV1 { + block_hash, + era_id, + signature, + public_key, + is_verified: _, + } = self; + #[cfg(not(any(feature = "once_cell", test)))] + let FinalitySignatureV1 { + block_hash, + era_id, + signature, + public_key, + } = self; + block_hash.hash(state); + era_id.hash(state); + signature.hash(state); + public_key.hash(state); + is_verified.hash(state); + } +} + +impl PartialEq for FinalitySignatureV1 { + fn eq(&self, other: &FinalitySignatureV1) -> bool { + // Ensure we initialize self.is_verified field. + let is_verified = self.is_verified().is_ok(); + // Destructure to make sure we don't accidentally omit fields. + #[cfg(any(feature = "once_cell", test))] + let FinalitySignatureV1 { + block_hash, + era_id, + signature, + public_key, + is_verified: _, + } = self; + #[cfg(not(any(feature = "once_cell", test)))] + let FinalitySignatureV1 { + block_hash, + era_id, + signature, + public_key, + } = self; + *block_hash == other.block_hash + && *era_id == other.era_id + && *signature == other.signature + && *public_key == other.public_key + && is_verified == other.is_verified().is_ok() + } +} + +impl Ord for FinalitySignatureV1 { + fn cmp(&self, other: &FinalitySignatureV1) -> Ordering { + // Ensure we initialize self.is_verified field. + let is_verified = self.is_verified().is_ok(); + // Destructure to make sure we don't accidentally omit fields. + #[cfg(any(feature = "once_cell", test))] + let FinalitySignatureV1 { + block_hash, + era_id, + signature, + public_key, + is_verified: _, + } = self; + #[cfg(not(any(feature = "once_cell", test)))] + let FinalitySignatureV1 { + block_hash, + era_id, + signature, + public_key, + } = self; + block_hash + .cmp(&other.block_hash) + .then_with(|| era_id.cmp(&other.era_id)) + .then_with(|| signature.cmp(&other.signature)) + .then_with(|| public_key.cmp(&other.public_key)) + .then_with(|| is_verified.cmp(&other.is_verified().is_ok())) + } +} + +impl PartialOrd for FinalitySignatureV1 { + fn partial_cmp(&self, other: &FinalitySignatureV1) -> Option { + Some(self.cmp(other)) + } +} + +impl Display for FinalitySignatureV1 { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!( + formatter, + "finality signature for {}, from {}", + self.block_hash, self.public_key + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::TestBlockBuilder; + + #[test] + fn finality_signature() { + let rng = &mut TestRng::new(); + let block = TestBlockBuilder::new().build(rng); + // Signature should be over both block hash and era id. + let secret_key = SecretKey::random(rng); + let public_key = PublicKey::from(&secret_key); + let era_id = EraId::from(1); + let finality_signature = FinalitySignatureV1::create(*block.hash(), era_id, &secret_key); + finality_signature.is_verified().unwrap(); + let signature = finality_signature.signature; + // Verify that signature includes era id. + let invalid_finality_signature = FinalitySignatureV1 { + block_hash: *block.hash(), + era_id: EraId::from(2), + signature, + public_key, + is_verified: OnceCell::new(), + }; + // Test should fail b/c `signature` is over `era_id=1` and here we're using `era_id=2`. + assert!(invalid_finality_signature.is_verified().is_err()); + } +} diff --git a/types/src/block/finality_signature/finality_signature_v2.rs b/types/src/block/finality_signature/finality_signature_v2.rs new file mode 100644 index 0000000000..c08a38d32d --- /dev/null +++ b/types/src/block/finality_signature/finality_signature_v2.rs @@ -0,0 +1,351 @@ +use alloc::vec::Vec; +use core::{ + cmp::Ordering, + fmt::{self, Display, Formatter}, + hash::{Hash, Hasher}, +}; + +#[cfg(feature = "datasize")] +use datasize::DataSize; +#[cfg(any(feature = "once_cell", test))] +use once_cell::sync::OnceCell; +#[cfg(feature = "json-schema")] +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[cfg(any(feature = "testing", test))] +use crate::testing::TestRng; +use crate::{crypto, BlockHash, ChainNameDigest, EraId, PublicKey, SecretKey, Signature}; +#[cfg(any(feature = "testing", test))] +use rand::Rng; + +/// A validator's signature of a block, confirming it is finalized. +/// +/// Clients and joining nodes should wait until the signers' combined weight exceeds the fault +/// tolerance threshold before accepting the block as finalized. +#[derive(Clone, Eq, Serialize, Deserialize, Debug)] +#[cfg_attr( + feature = "json-schema", + derive(JsonSchema), + schemars(description = "A validator's signature of a block, confirming it is finalized.") +)] +#[cfg_attr(feature = "datasize", derive(DataSize))] +pub struct FinalitySignatureV2 { + /// The block hash of the associated block. + pub(crate) block_hash: BlockHash, + /// The height of the associated block. + pub(crate) block_height: u64, + /// The era in which the associated block was created. + pub(crate) era_id: EraId, + /// The hash of the chain name of the associated block. + pub(crate) chain_name_hash: ChainNameDigest, + /// The signature over the block hash of the associated block. + pub(crate) signature: Signature, + /// The public key of the signing validator. + pub(crate) public_key: PublicKey, + #[serde(skip)] + #[cfg_attr( + all(any(feature = "once_cell", test), feature = "datasize"), + data_size(skip) + )] + #[cfg(any(feature = "once_cell", test))] + pub(crate) is_verified: OnceCell>, +} + +impl FinalitySignatureV2 { + /// Constructs a new `FinalitySignatureV2`. + pub fn create( + block_hash: BlockHash, + block_height: u64, + era_id: EraId, + chain_name_hash: ChainNameDigest, + secret_key: &SecretKey, + ) -> Self { + let bytes = Self::bytes_to_sign(block_hash, block_height, era_id, chain_name_hash); + let public_key = PublicKey::from(secret_key); + let signature = crypto::sign(bytes, secret_key, &public_key); + FinalitySignatureV2 { + block_hash, + block_height, + era_id, + chain_name_hash, + signature, + public_key, + #[cfg(any(feature = "once_cell", test))] + is_verified: OnceCell::with_value(Ok(())), + } + } + + /// Returns the block hash of the associated block. + pub fn block_hash(&self) -> &BlockHash { + &self.block_hash + } + + /// Returns the height of the associated block. + pub fn block_height(&self) -> u64 { + self.block_height + } + + /// Returns the era in which the associated block was created. + pub fn era_id(&self) -> EraId { + self.era_id + } + + /// Returns the hash of the chain name of the associated block. + pub fn chain_name_hash(&self) -> ChainNameDigest { + self.chain_name_hash + } + + /// Returns the signature over the block hash of the associated block. + pub fn signature(&self) -> &Signature { + &self.signature + } + + /// Returns the public key of the signing validator. + pub fn public_key(&self) -> &PublicKey { + &self.public_key + } + + /// Returns `Ok` if the signature is cryptographically valid. + pub fn is_verified(&self) -> Result<(), crypto::Error> { + #[cfg(any(feature = "once_cell", test))] + return self.is_verified.get_or_init(|| self.verify()).clone(); + + #[cfg(not(any(feature = "once_cell", test)))] + self.verify() + } + + /// Constructs a new `FinalitySignatureV2`. + #[cfg(any(feature = "testing", test))] + pub fn new( + block_hash: BlockHash, + block_height: u64, + era_id: EraId, + chain_name_hash: ChainNameDigest, + signature: Signature, + public_key: PublicKey, + ) -> Self { + FinalitySignatureV2 { + block_hash, + block_height, + era_id, + chain_name_hash, + signature, + public_key, + #[cfg(any(feature = "once_cell", test))] + is_verified: OnceCell::new(), + } + } + + /// Returns a random `FinalitySignatureV2`. + #[cfg(any(feature = "testing", test))] + pub fn random(rng: &mut TestRng) -> Self { + FinalitySignatureV2::random_for_block( + BlockHash::random(rng), + rng.gen(), + EraId::random(rng), + ChainNameDigest::random(rng), + rng, + ) + } + + /// Returns a random `FinalitySignatureV2` for the provided `block_hash`, `block_height`, + /// `era_id`, and `chain_name_hash`. + #[cfg(any(feature = "testing", test))] + pub fn random_for_block( + block_hash: BlockHash, + block_height: u64, + era_id: EraId, + chain_name_hash: ChainNameDigest, + rng: &mut TestRng, + ) -> Self { + let secret_key = SecretKey::random(rng); + FinalitySignatureV2::create( + block_hash, + block_height, + era_id, + chain_name_hash, + &secret_key, + ) + } + + fn bytes_to_sign( + block_hash: BlockHash, + block_height: u64, + era_id: EraId, + chain_name_hash: ChainNameDigest, + ) -> Vec { + let mut bytes = block_hash.inner().into_vec(); + bytes.extend_from_slice(&block_height.to_le_bytes()); + bytes.extend_from_slice(&era_id.to_le_bytes()); + bytes.extend_from_slice(chain_name_hash.inner().as_ref()); + bytes + } + + fn verify(&self) -> Result<(), crypto::Error> { + let bytes = Self::bytes_to_sign( + self.block_hash, + self.block_height, + self.era_id, + self.chain_name_hash, + ); + crypto::verify(bytes, &self.signature, &self.public_key) + } +} + +impl Hash for FinalitySignatureV2 { + fn hash(&self, state: &mut H) { + // Ensure we initialize self.is_verified field. + let is_verified = self.is_verified().is_ok(); + // Destructure to make sure we don't accidentally omit fields. + #[cfg(any(feature = "once_cell", test))] + let FinalitySignatureV2 { + block_hash, + block_height, + era_id, + chain_name_hash, + signature, + public_key, + is_verified: _, + } = self; + #[cfg(not(any(feature = "once_cell", test)))] + let FinalitySignatureV2 { + block_hash, + block_height, + era_id, + chain_name_hash, + signature, + public_key, + } = self; + block_hash.hash(state); + block_height.hash(state); + era_id.hash(state); + chain_name_hash.hash(state); + signature.hash(state); + public_key.hash(state); + is_verified.hash(state); + } +} + +impl PartialEq for FinalitySignatureV2 { + fn eq(&self, other: &FinalitySignatureV2) -> bool { + // Ensure we initialize self.is_verified field. + let is_verified = self.is_verified().is_ok(); + // Destructure to make sure we don't accidentally omit fields. + #[cfg(any(feature = "once_cell", test))] + let FinalitySignatureV2 { + block_hash, + block_height, + era_id, + chain_name_hash, + signature, + public_key, + is_verified: _, + } = self; + #[cfg(not(any(feature = "once_cell", test)))] + let FinalitySignatureV2 { + block_hash, + block_height, + era_id, + chain_name_hash, + signature, + public_key, + } = self; + *block_hash == other.block_hash + && *block_height == other.block_height + && *era_id == other.era_id + && *chain_name_hash == other.chain_name_hash + && *signature == other.signature + && *public_key == other.public_key + && is_verified == other.is_verified().is_ok() + } +} + +impl Ord for FinalitySignatureV2 { + fn cmp(&self, other: &FinalitySignatureV2) -> Ordering { + // Ensure we initialize self.is_verified field. + let is_verified = self.is_verified().is_ok(); + // Destructure to make sure we don't accidentally omit fields. + #[cfg(any(feature = "once_cell", test))] + let FinalitySignatureV2 { + block_hash, + block_height, + era_id, + chain_name_hash, + signature, + public_key, + is_verified: _, + } = self; + #[cfg(not(any(feature = "once_cell", test)))] + let FinalitySignatureV2 { + block_hash, + block_height, + era_id, + chain_name_hash, + signature, + public_key, + } = self; + block_hash + .cmp(&other.block_hash) + .then_with(|| block_height.cmp(&other.block_height)) + .then_with(|| era_id.cmp(&other.era_id)) + .then_with(|| chain_name_hash.cmp(&other.chain_name_hash)) + .then_with(|| signature.cmp(&other.signature)) + .then_with(|| public_key.cmp(&other.public_key)) + .then_with(|| is_verified.cmp(&other.is_verified().is_ok())) + } +} + +impl PartialOrd for FinalitySignatureV2 { + fn partial_cmp(&self, other: &FinalitySignatureV2) -> Option { + Some(self.cmp(other)) + } +} + +impl Display for FinalitySignatureV2 { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!( + formatter, + "finality signature for {}, from {}", + self.block_hash, self.public_key + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::TestBlockBuilder; + + #[test] + fn finality_signature() { + let rng = &mut TestRng::new(); + let block = TestBlockBuilder::new().build(rng); + // Signature should be over both block hash and era id. + let secret_key = SecretKey::random(rng); + let public_key = PublicKey::from(&secret_key); + let era_id = EraId::from(1); + let chain_name_hash = ChainNameDigest::random(rng); + let finality_signature = FinalitySignatureV2::create( + *block.hash(), + block.height(), + era_id, + chain_name_hash, + &secret_key, + ); + finality_signature.is_verified().unwrap(); + let signature = finality_signature.signature; + // Verify that signature includes era id. + let invalid_finality_signature = FinalitySignatureV2 { + block_hash: *block.hash(), + block_height: block.height(), + era_id: EraId::from(2), + chain_name_hash, + signature, + public_key, + is_verified: OnceCell::new(), + }; + // Test should fail b/c `signature` is over `era_id=1` and here we're using `era_id=2`. + assert!(invalid_finality_signature.is_verified().is_err()); + } +} diff --git a/types/src/block/json_compatibility/json_block_with_signatures.rs b/types/src/block/json_compatibility/json_block_with_signatures.rs index 71d472ea1a..daf08270c9 100644 --- a/types/src/block/json_compatibility/json_block_with_signatures.rs +++ b/types/src/block/json_compatibility/json_block_with_signatures.rs @@ -40,7 +40,7 @@ impl JsonBlockWithSignatures { /// Constructs a new `JsonBlock`. pub fn new(block: Block, maybe_signatures: Option) -> Self { let proofs = maybe_signatures - .map(|signatures| signatures.proofs) + .map(|signatures| signatures.into_proofs()) .unwrap_or_default(); JsonBlockWithSignatures { block, proofs } @@ -70,15 +70,33 @@ impl KeyValueJsonSchema for BlockProofLabels { #[cfg(test)] mod tests { - use crate::{testing::TestRng, TestBlockBuilder}; + use crate::{ + testing::TestRng, BlockSignaturesV1, BlockSignaturesV2, ChainNameDigest, TestBlockBuilder, + }; use super::*; #[test] - fn block_to_and_from_json_block_with_signatures() { + fn block_to_and_from_json_block_with_signatures_v1() { let rng = &mut TestRng::new(); let block: Block = TestBlockBuilder::new().build(rng).into(); - let empty_signatures = BlockSignatures::new(*block.hash(), block.era_id()); + let empty_signatures = + BlockSignatures::V1(BlockSignaturesV1::new(*block.hash(), block.era_id())); + let json_block = JsonBlockWithSignatures::new(block.clone(), Some(empty_signatures)); + let recovered_block = Block::from(json_block); + assert_eq!(block, recovered_block); + } + + #[test] + fn block_to_and_from_json_block_with_signatures_v2() { + let rng = &mut TestRng::new(); + let block: Block = TestBlockBuilder::new().build(rng).into(); + let empty_signatures = BlockSignatures::V2(BlockSignaturesV2::new( + *block.hash(), + block.height(), + block.era_id(), + ChainNameDigest::random(rng), + )); let json_block = JsonBlockWithSignatures::new(block.clone(), Some(empty_signatures)); let recovered_block = Block::from(json_block); assert_eq!(block, recovered_block); diff --git a/types/src/block/signed_block_header.rs b/types/src/block/signed_block_header.rs index a478314df6..c616da87f1 100644 --- a/types/src/block/signed_block_header.rs +++ b/types/src/block/signed_block_header.rs @@ -9,8 +9,6 @@ use serde::{Deserialize, Serialize}; use super::{BlockHash, BlockHeader, BlockSignatures}; use crate::EraId; -#[cfg(any(feature = "testing", test))] -use crate::Signature; /// An error which can result from validating a [`SignedBlockHeader`]. #[derive(Copy, Clone, Eq, PartialEq, Debug)] @@ -116,7 +114,7 @@ impl SignedBlockHeader { /// the max value). #[cfg(any(feature = "testing", test))] pub fn invalidate_era(&mut self) { - self.block_signatures.era_id = EraId::new(u64::MAX); + self.block_signatures.invalidate_era() } /// Replaces the signature field of the last `block_signatures` entry with the `System` variant @@ -127,12 +125,7 @@ impl SignedBlockHeader { /// performed. #[cfg(any(feature = "testing", test))] pub fn invalidate_last_signature(&mut self) { - let last_proof = self - .block_signatures - .proofs - .last_entry() - .expect("should have at least one signature"); - *last_proof.into_mut() = Signature::System; + self.block_signatures.invalidate_last_signature() } } diff --git a/types/src/chainspec.rs b/types/src/chainspec.rs index 6e8727c8ff..9885910af3 100644 --- a/types/src/chainspec.rs +++ b/types/src/chainspec.rs @@ -27,7 +27,7 @@ use tracing::error; use crate::testing::TestRng; use crate::{ bytesrepr::{self, FromBytes, ToBytes}, - Digest, EraId, ProtocolVersion, + ChainNameDigest, Digest, EraId, ProtocolVersion, }; pub use accounts_config::{ AccountConfig, AccountsConfig, AdministratorAccount, DelegatorConfig, GenesisAccount, @@ -104,6 +104,11 @@ pub struct Chainspec { } impl Chainspec { + /// Returns the hash of the chainspec's name. + pub fn name_hash(&self) -> ChainNameDigest { + ChainNameDigest::new(Digest::hash(self.network_config.name.as_bytes())) + } + /// Serializes `self` and hashes the resulting bytes. pub fn hash(&self) -> Digest { let serialized_chainspec = self.to_bytes().unwrap_or_else(|error| { diff --git a/types/src/lib.rs b/types/src/lib.rs index 67619bce53..2cec6910a9 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -89,9 +89,10 @@ pub use api_error::ApiError; pub use block::JsonBlockWithSignatures; pub use block::{ Block, BlockBody, BlockBodyV1, BlockBodyV2, BlockHash, BlockHeader, BlockHeaderV1, - BlockHeaderV2, BlockSignatures, BlockSignaturesMergeError, BlockV1, BlockV2, - BlockValidationError, EraEnd, EraEndV1, EraEndV2, EraReport, FinalitySignature, - FinalitySignatureId, RewardedSignatures, Rewards, SignedBlockHeader, + BlockHeaderV2, BlockSignatures, BlockSignaturesMergeError, BlockSignaturesV1, + BlockSignaturesV2, BlockV1, BlockV2, BlockValidationError, ChainNameDigest, EraEnd, EraEndV1, + EraEndV2, EraReport, FinalitySignature, FinalitySignatureId, FinalitySignatureV1, + FinalitySignatureV2, RewardedSignatures, Rewards, SignedBlockHeader, SignedBlockHeaderValidationError, SingleBlockRewardedSignatures, }; #[cfg(any(feature = "testing", test))] From 1d90e7109639dd82e83f4d6d3e7cdefeeba06137 Mon Sep 17 00:00:00 2001 From: Jacek Malec <145967538+jacek-casper@users.noreply.github.com> Date: Wed, 7 Feb 2024 19:47:48 +0000 Subject: [PATCH 2/7] Fix tests --- .../src/components/block_accumulator/tests.rs | 127 ++++-------------- node/src/components/storage.rs | 2 +- 2 files changed, 27 insertions(+), 102 deletions(-) diff --git a/node/src/components/block_accumulator/tests.rs b/node/src/components/block_accumulator/tests.rs index 8da2cb6f76..a2c18e318c 100644 --- a/node/src/components/block_accumulator/tests.rs +++ b/node/src/components/block_accumulator/tests.rs @@ -15,9 +15,9 @@ use thiserror::Error as ThisError; use tokio::time; use casper_types::{ - generate_ed25519_keypair, testing::TestRng, ActivationPoint, BlockSignaturesV2, BlockV2, - ChainNameDigest, Chainspec, ChainspecRawBytes, FinalitySignatureV2, ProtocolVersion, PublicKey, - SecretKey, Signature, TestBlockBuilder, U512, + generate_ed25519_keypair, testing::TestRng, ActivationPoint, BlockV2, ChainNameDigest, + Chainspec, ChainspecRawBytes, FinalitySignatureV1, FinalitySignatureV2, ProtocolVersion, + PublicKey, SecretKey, Signature, TestBlockBuilder, U512, }; use reactor::ReactorEvent; @@ -53,21 +53,12 @@ fn meta_block_with_default_state(block: Arc) -> ForwardMetaBlock { .unwrap() } -fn signatures_for_block( - block: &BlockV2, - signatures: &[FinalitySignatureV2], - chain_name_hash: ChainNameDigest, -) -> BlockSignatures { - let mut block_signatures = BlockSignaturesV2::new( - *block.hash(), - block.height(), - block.era_id(), - chain_name_hash, - ); +fn signatures_for_block(block: &BlockV2, signatures: &[FinalitySignatureV1]) -> BlockSignatures { + let mut block_signatures = BlockSignaturesV1::new(*block.hash(), block.era_id()); for signature in signatures { block_signatures.insert_signature(signature.public_key().clone(), *signature.signature()); } - BlockSignatures::V2(block_signatures) + BlockSignatures::V1(block_signatures) } /// Top-level event for the reactor. @@ -662,7 +653,6 @@ fn acceptor_should_store_block() { let mut rng = TestRng::new(); // Create a block and an acceptor for it. let block = Arc::new(TestBlockBuilder::new().build(&mut rng)); - let chain_name_hash = ChainNameDigest::random(&mut rng); let mut meta_block = meta_block_with_default_state(block.clone()); let mut acceptor = BlockAcceptor::new(*block.hash(), vec![]); @@ -706,13 +696,7 @@ fn acceptor_should_store_block() { let mut signatures = vec![]; // Create the first validator's signature. - let fin_sig = FinalitySignatureV2::create( - *block.hash(), - block.height(), - block.era_id(), - chain_name_hash, - &keys[0].0, - ); + let fin_sig = FinalitySignatureV1::create(*block.hash(), block.era_id(), &keys[0].0); signatures.push(fin_sig.clone()); // First signature with 40% weight brings the block to weak finality. acceptor @@ -727,13 +711,7 @@ fn acceptor_should_store_block() { assert_eq!(should_store, ShouldStore::Nothing); // Create the third validator's signature. - let fin_sig = FinalitySignatureV2::create( - *block.hash(), - block.height(), - block.era_id(), - chain_name_hash, - &keys[2].0, - ); + let fin_sig = FinalitySignatureV1::create(*block.hash(), block.era_id(), &keys[2].0); // The third signature with weight 10% doesn't make the block go to // strict finality. signatures.push(fin_sig.clone()); @@ -746,13 +724,8 @@ fn acceptor_should_store_block() { // Create a bogus signature from a non-validator for this era. let non_validator_keys = generate_ed25519_keypair(); let faulty_peer = NodeId::random(&mut rng); - let bogus_sig = FinalitySignatureV2::create( - *block.hash(), - block.height(), - block.era_id(), - chain_name_hash, - &non_validator_keys.0, - ); + let bogus_sig = + FinalitySignatureV1::create(*block.hash(), block.era_id(), &non_validator_keys.0); acceptor .register_finality_signature(bogus_sig.into(), Some(faulty_peer), VALIDATOR_SLOTS) .unwrap(); @@ -763,20 +736,14 @@ fn acceptor_should_store_block() { assert_eq!(offenders[0].0, faulty_peer); // Create the second validator's signature. - let fin_sig = FinalitySignatureV2::create( - *block.hash(), - block.height(), - block.era_id(), - chain_name_hash, - &keys[1].0, - ); + let fin_sig = FinalitySignatureV1::create(*block.hash(), block.era_id(), &keys[1].0); signatures.push(fin_sig.clone()); // Second signature with 40% weight brings the block to strict finality. acceptor .register_finality_signature(fin_sig.into(), None, VALIDATOR_SLOTS) .unwrap(); let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); - let block_signatures = signatures_for_block(&block, &signatures, chain_name_hash); + let block_signatures = signatures_for_block(&block, &signatures); let mut meta_block_with_expected_state = meta_block.clone(); meta_block_with_expected_state.state.register_as_stored(); meta_block_with_expected_state @@ -791,13 +758,7 @@ fn acceptor_should_store_block() { ); // Create the fourth validator's signature. - let fin_sig = FinalitySignatureV2::create( - *block.hash(), - block.height(), - block.era_id(), - chain_name_hash, - &keys[3].0, - ); + let fin_sig = FinalitySignatureV1::create(*block.hash(), block.era_id(), &keys[3].0); // Already have sufficient finality signatures, so we're not supposed to // store anything else. acceptor @@ -1633,24 +1594,12 @@ async fn block_accumulator_reactor_flow() { let peer_1 = NodeId::random(&mut rng); let peer_2 = NodeId::random(&mut rng); - let chain_name_hash = ChainNameDigest::random(&mut rng); - // One finality signature from our only validator for block 1. - let fin_sig_1 = FinalitySignatureV2::create( - *block_1.hash(), - block_1.height(), - block_1.era_id(), - chain_name_hash, - &ALICE_SECRET_KEY, - ); + let fin_sig_1 = + FinalitySignatureV1::create(*block_1.hash(), block_1.era_id(), &ALICE_SECRET_KEY); // One finality signature from our only validator for block 2. - let fin_sig_2 = FinalitySignatureV2::create( - *block_2.hash(), - block_2.height(), - block_2.era_id(), - chain_name_hash, - &ALICE_SECRET_KEY, - ); + let fin_sig_2 = + FinalitySignatureV1::create(*block_2.hash(), block_2.era_id(), &ALICE_SECRET_KEY); // Register the eras in the validator matrix so the blocks are valid. { @@ -1933,13 +1882,8 @@ async fn block_accumulator_reactor_flow() { .contains_key(older_block.hash())); } - let older_block_signature = FinalitySignatureV2::create( - *older_block.hash(), - older_block.height(), - older_block.era_id(), - chain_name_hash, - &ALICE_SECRET_KEY, - ); + let older_block_signature = + FinalitySignatureV1::create(*older_block.hash(), older_block.era_id(), &ALICE_SECRET_KEY); // Register a signature for an older block. { let effect_builder = runner.effect_builder(); @@ -1967,11 +1911,9 @@ async fn block_accumulator_reactor_flow() { .switch_block(false) .build(&mut rng); - let old_era_signature = FinalitySignatureV2::create( + let old_era_signature = FinalitySignatureV1::create( *old_era_block.hash(), - old_era_block.height(), old_era_block.era_id(), - chain_name_hash, &ALICE_SECRET_KEY, ); // Register a signature for a block in an old era. @@ -2015,31 +1957,14 @@ async fn block_accumulator_doesnt_purge_with_delayed_block_execution() { let peer_1 = NodeId::random(&mut rng); let peer_2 = NodeId::random(&mut rng); - let chain_name_hash = ChainNameDigest::random(&mut rng); - - let fin_sig_bob = FinalitySignatureV2::create( - *block_1.hash(), - block_1.height(), - block_1.era_id(), - chain_name_hash, - &BOB_SECRET_KEY, - ); + let fin_sig_bob = + FinalitySignatureV1::create(*block_1.hash(), block_1.era_id(), &BOB_SECRET_KEY); - let fin_sig_carol = FinalitySignatureV2::create( - *block_1.hash(), - block_1.height(), - block_1.era_id(), - chain_name_hash, - &CAROL_SECRET_KEY, - ); + let fin_sig_carol = + FinalitySignatureV1::create(*block_1.hash(), block_1.era_id(), &CAROL_SECRET_KEY); - let fin_sig_alice = FinalitySignatureV2::create( - *block_1.hash(), - block_1.height(), - block_1.era_id(), - chain_name_hash, - &ALICE_SECRET_KEY, - ); + let fin_sig_alice = + FinalitySignatureV1::create(*block_1.hash(), block_1.era_id(), &ALICE_SECRET_KEY); // Register the era in the validator matrix so the block is valid. { diff --git a/node/src/components/storage.rs b/node/src/components/storage.rs index 4b8b99977c..4eef11e693 100644 --- a/node/src/components/storage.rs +++ b/node/src/components/storage.rs @@ -125,7 +125,7 @@ const STORAGE_DB_FILENAME: &str = "storage.lmdb"; const MAX_TRANSACTIONS: u32 = 1; /// Maximum number of allowed dbs. -const MAX_DB_COUNT: u32 = 15; +const MAX_DB_COUNT: u32 = 16; /// Key under which completed blocks are to be stored. const COMPLETED_BLOCKS_STORAGE_KEY: &[u8] = b"completed_blocks_disjoint_sequences"; /// Name of the file created when initializing a force resync. From 9c32193dc3dfc27c34bbc9821dd2d60972da35d8 Mon Sep 17 00:00:00 2001 From: Jacek Malec <145967538+jacek-casper@users.noreply.github.com> Date: Wed, 14 Feb 2024 10:19:18 +0000 Subject: [PATCH 3/7] Apply suggested changes --- node/src/components/block_accumulator.rs | 34 ++- .../block_accumulator/block_acceptor.rs | 49 ++-- .../src/components/block_accumulator/event.rs | 8 +- .../src/components/block_accumulator/tests.rs | 222 ++++++++++++------ node/src/components/fetcher/tests.rs | 4 +- .../finality_signature_provider.rs | 20 +- node/src/components/gossiper/tests.rs | 4 +- node/src/components/storage.rs | 76 +++++- node/src/components/storage/tests.rs | 56 +++-- node/src/effect.rs | 7 +- node/src/effect/announcements.rs | 6 +- node/src/effect/incoming.rs | 4 +- node/src/protocol.rs | 8 +- node/src/reactor/main_reactor.rs | 54 +++-- node/src/reactor/main_reactor/event.rs | 12 +- node/src/types/validator_matrix.rs | 23 +- node/src/utils/specimen.rs | 10 +- resources/test/sse_data_schema.json | 99 ++++++++ types/src/block/block_signatures.rs | 46 ++-- 19 files changed, 506 insertions(+), 236 deletions(-) diff --git a/node/src/components/block_accumulator.rs b/node/src/components/block_accumulator.rs index 408fad90cf..7c73cd49bf 100644 --- a/node/src/components/block_accumulator.rs +++ b/node/src/components/block_accumulator.rs @@ -23,8 +23,8 @@ use prometheus::Registry; use tracing::{debug, error, info, warn}; use casper_types::{ - ActivationPoint, Block, BlockHash, BlockSignatures, BlockSignaturesV1, EraId, - FinalitySignature, TimeDiff, Timestamp, + ActivationPoint, Block, BlockHash, BlockSignaturesV2, EraId, FinalitySignatureV2, TimeDiff, + Timestamp, }; use crate::{ @@ -294,7 +294,8 @@ impl BlockAccumulator { match acceptor.register_block(meta_block, sender) { Ok(_) => match self.validator_matrix.validator_weights(era_id) { Some(evw) => { - let (should_store, faulty_senders) = acceptor.should_store_block(&evw); + let (should_store, faulty_senders) = + acceptor.should_store_block(&evw, self.validator_matrix.chain_name_hash()); self.store_block_and_finality_signatures( effect_builder, should_store, @@ -366,7 +367,7 @@ impl BlockAccumulator { fn register_finality_signature( &mut self, effect_builder: EffectBuilder, - finality_signature: FinalitySignature, + finality_signature: FinalitySignatureV2, sender: Option, ) -> Effects where @@ -404,7 +405,8 @@ impl BlockAccumulator { ), Ok(None) => match self.validator_matrix.validator_weights(era_id) { Some(evw) => { - let (should_store, faulty_senders) = acceptor.should_store_block(&evw); + let (should_store, faulty_senders) = + acceptor.should_store_block(&evw, self.validator_matrix.chain_name_hash()); self.store_block_and_finality_signatures( effect_builder, should_store, @@ -480,7 +482,7 @@ impl BlockAccumulator { &self, effect_builder: EffectBuilder, maybe_meta_block: Option, - maybe_block_signatures: Option, + maybe_block_signatures: Option, ) -> Effects where REv: From @@ -698,7 +700,9 @@ impl BlockAccumulator { let block: Block = (*meta_block.block).clone().into(); effect_builder .put_block_to_storage(Arc::new(block)) - .then(move |_| effect_builder.put_signatures_to_storage(cloned_signatures)) + .then(move |_| { + effect_builder.put_signatures_to_storage(cloned_signatures.into()) + }) .event(move |_| Event::Stored { maybe_meta_block: Some(meta_block), maybe_block_signatures: Some(block_signatures), @@ -716,7 +720,7 @@ impl BlockAccumulator { // we mark it as complete. let block_height = meta_block.block.height(); effect_builder - .put_signatures_to_storage(block_signatures.clone()) + .put_signatures_to_storage(block_signatures.clone().into()) .then(move |_| effect_builder.mark_block_completed(block_height)) .event(move |_| Event::Stored { maybe_meta_block: Some(meta_block), @@ -736,15 +740,19 @@ impl BlockAccumulator { } ShouldStore::SingleSignature(signature) => { debug!(%signature, "storing finality signature"); - let mut block_signatures = - BlockSignaturesV1::new(*signature.block_hash(), signature.era_id()); + let mut block_signatures = BlockSignaturesV2::new( + *signature.block_hash(), + signature.block_height(), + signature.era_id(), + signature.chain_name_hash(), + ); block_signatures .insert_signature(signature.public_key().clone(), *signature.signature()); effect_builder - .put_finality_signature_to_storage(signature) + .put_finality_signature_to_storage(signature.into()) .event(move |_| Event::Stored { maybe_meta_block: None, - maybe_block_signatures: Some(block_signatures.into()), + maybe_block_signatures: Some(block_signatures), }) } ShouldStore::Nothing => { @@ -861,7 +869,7 @@ impl ValidatorBoundComponent for BlockAccumulator { .filter_map(|acceptor| { let era_id = acceptor.era_id()?; let evw = validator_matrix.validator_weights(era_id)?; - Some(acceptor.should_store_block(&evw)) + Some(acceptor.should_store_block(&evw, validator_matrix.chain_name_hash())) }) .collect_vec(); should_stores diff --git a/node/src/components/block_accumulator/block_acceptor.rs b/node/src/components/block_accumulator/block_acceptor.rs index 440f65ddfc..2b80a455fd 100644 --- a/node/src/components/block_accumulator/block_acceptor.rs +++ b/node/src/components/block_accumulator/block_acceptor.rs @@ -5,7 +5,7 @@ use itertools::Itertools; use tracing::{debug, error, warn}; use casper_types::{ - ActivationPoint, BlockHash, BlockSignatures, BlockSignaturesV1, EraId, FinalitySignature, + ActivationPoint, BlockHash, BlockSignaturesV2, ChainNameDigest, EraId, FinalitySignatureV2, PublicKey, Timestamp, }; @@ -18,10 +18,10 @@ use crate::{ pub(super) struct BlockAcceptor { block_hash: BlockHash, meta_block: Option, - signatures: BTreeMap)>, + signatures: BTreeMap)>, peers: BTreeSet, last_progress: Timestamp, - our_signature: Option, + our_signature: Option, } #[derive(Debug, PartialEq)] @@ -29,14 +29,14 @@ pub(super) struct BlockAcceptor { pub(super) enum ShouldStore { SufficientlySignedBlock { meta_block: ForwardMetaBlock, - block_signatures: BlockSignatures, + block_signatures: BlockSignaturesV2, }, CompletedBlock { meta_block: ForwardMetaBlock, - block_signatures: BlockSignatures, + block_signatures: BlockSignaturesV2, }, MarkComplete(ForwardMetaBlock), - SingleSignature(FinalitySignature), + SingleSignature(FinalitySignatureV2), Nothing, } @@ -111,10 +111,10 @@ impl BlockAcceptor { pub(super) fn register_finality_signature( &mut self, - finality_signature: FinalitySignature, + finality_signature: FinalitySignatureV2, peer: Option, validator_slots: u32, - ) -> Result, AcceptorError> { + ) -> Result, AcceptorError> { if self.block_hash != *finality_signature.block_hash() { return Err(AcceptorError::BlockHashMismatch { expected: self.block_hash, @@ -207,6 +207,7 @@ impl BlockAcceptor { pub(super) fn should_store_block( &mut self, era_validator_weights: &EraValidatorWeights, + chain_name_hash: ChainNameDigest, ) -> (ShouldStore, Vec<(NodeId, AcceptorError)>) { let block_hash = self.block_hash; let no_block = self.meta_block.is_none(); @@ -241,8 +242,12 @@ impl BlockAcceptor { if SignatureWeight::Strict == signature_weight { self.touch(); if let Some(meta_block) = self.meta_block.as_mut() { - let mut block_signatures = - BlockSignaturesV1::new(*meta_block.block.hash(), meta_block.block.era_id()); + let mut block_signatures = BlockSignaturesV2::new( + *meta_block.block.hash(), + meta_block.block.height(), + meta_block.block.era_id(), + chain_name_hash, + ); self.signatures.values().for_each(|(signature, _)| { block_signatures .insert_signature(signature.public_key().clone(), *signature.signature()); @@ -277,7 +282,7 @@ impl BlockAcceptor { return ( ShouldStore::CompletedBlock { meta_block: meta_block.clone(), - block_signatures: block_signatures.into(), + block_signatures, }, faulty_senders, ); @@ -297,7 +302,7 @@ impl BlockAcceptor { return ( ShouldStore::SufficientlySignedBlock { meta_block: meta_block.clone(), - block_signatures: block_signatures.into(), + block_signatures, }, faulty_senders, ); @@ -363,11 +368,11 @@ impl BlockAcceptor { self.last_progress } - pub(super) fn our_signature(&self) -> Option<&FinalitySignature> { + pub(super) fn our_signature(&self) -> Option<&FinalitySignatureV2> { self.our_signature.as_ref() } - pub(super) fn set_our_signature(&mut self, signature: FinalitySignature) { + pub(super) fn set_our_signature(&mut self, signature: FinalitySignatureV2) { self.our_signature = Some(signature); } @@ -429,7 +434,7 @@ impl BlockAcceptor { fn check_signatures_from_peer_bound( limit: u32, peer: NodeId, - signatures: &BTreeMap)>, + signatures: &BTreeMap)>, ) -> Result<(), AcceptorError> { let signatures_for_peer = signatures .values() @@ -471,13 +476,15 @@ impl BlockAcceptor { } } - pub(super) fn signatures(&self) -> &BTreeMap)> { + pub(super) fn signatures( + &self, + ) -> &BTreeMap)> { &self.signatures } pub(super) fn signatures_mut( &mut self, - ) -> &mut BTreeMap)> { + ) -> &mut BTreeMap)> { &mut self.signatures } } @@ -499,7 +506,7 @@ mod tests { // Insert only the peer to check: signatures.insert( PublicKey::random(rng), - (FinalitySignature::random(rng), { + (FinalitySignatureV2::random(rng), { let mut nodes = BTreeSet::new(); nodes.insert(peer_to_check); nodes @@ -508,7 +515,7 @@ mod tests { // Insert an unrelated peer: signatures.insert( PublicKey::random(rng), - (FinalitySignature::random(rng), { + (FinalitySignatureV2::random(rng), { let mut nodes = BTreeSet::new(); nodes.insert(NodeId::random(rng)); nodes @@ -517,7 +524,7 @@ mod tests { // Insert both the peer to check and an unrelated one: signatures.insert( PublicKey::random(rng), - (FinalitySignature::random(rng), { + (FinalitySignatureV2::random(rng), { let mut nodes = BTreeSet::new(); nodes.insert(NodeId::random(rng)); nodes.insert(peer_to_check); @@ -534,7 +541,7 @@ mod tests { // Let's insert once again both the peer to check and an unrelated one: signatures.insert( PublicKey::random(rng), - (FinalitySignature::random(rng), { + (FinalitySignatureV2::random(rng), { let mut nodes = BTreeSet::new(); nodes.insert(NodeId::random(rng)); nodes.insert(peer_to_check); diff --git a/node/src/components/block_accumulator/event.rs b/node/src/components/block_accumulator/event.rs index d4ac572b12..3774a7cb8a 100644 --- a/node/src/components/block_accumulator/event.rs +++ b/node/src/components/block_accumulator/event.rs @@ -5,7 +5,7 @@ use std::{ use derive_more::From; -use casper_types::{BlockHash, BlockSignatures, BlockV2, EraId, FinalitySignature}; +use casper_types::{BlockHash, BlockSignaturesV2, BlockV2, EraId, FinalitySignatureV2}; use crate::{ effect::requests::BlockAccumulatorRequest, @@ -26,10 +26,10 @@ pub(crate) enum Event { sender: NodeId, }, CreatedFinalitySignature { - finality_signature: Box, + finality_signature: Box, }, ReceivedFinalitySignature { - finality_signature: Box, + finality_signature: Box, sender: NodeId, }, ExecutedBlock { @@ -37,7 +37,7 @@ pub(crate) enum Event { }, Stored { maybe_meta_block: Option, - maybe_block_signatures: Option, + maybe_block_signatures: Option, }, } diff --git a/node/src/components/block_accumulator/tests.rs b/node/src/components/block_accumulator/tests.rs index a2c18e318c..1f99985d5f 100644 --- a/node/src/components/block_accumulator/tests.rs +++ b/node/src/components/block_accumulator/tests.rs @@ -16,7 +16,7 @@ use tokio::time; use casper_types::{ generate_ed25519_keypair, testing::TestRng, ActivationPoint, BlockV2, ChainNameDigest, - Chainspec, ChainspecRawBytes, FinalitySignatureV1, FinalitySignatureV2, ProtocolVersion, + Chainspec, ChainspecRawBytes, FinalitySignature, FinalitySignatureV2, ProtocolVersion, PublicKey, SecretKey, Signature, TestBlockBuilder, U512, }; use reactor::ReactorEvent; @@ -53,12 +53,21 @@ fn meta_block_with_default_state(block: Arc) -> ForwardMetaBlock { .unwrap() } -fn signatures_for_block(block: &BlockV2, signatures: &[FinalitySignatureV1]) -> BlockSignatures { - let mut block_signatures = BlockSignaturesV1::new(*block.hash(), block.era_id()); +fn signatures_for_block( + block: &BlockV2, + signatures: &[FinalitySignatureV2], + chain_name_hash: ChainNameDigest, +) -> BlockSignaturesV2 { + let mut block_signatures = BlockSignaturesV2::new( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + ); for signature in signatures { block_signatures.insert_signature(signature.public_key().clone(), *signature.signature()); } - BlockSignatures::V1(block_signatures) + block_signatures } /// Top-level event for the reactor. @@ -406,7 +415,7 @@ fn acceptor_register_finality_signature() { let mut acceptor = BlockAcceptor::new(*block.hash(), vec![]); // Create a finality signature with the wrong block hash. - let wrong_fin_sig = FinalitySignature::random_for_block( + let wrong_fin_sig = FinalitySignatureV2::random_for_block( BlockHash::random(rng), rng.gen(), EraId::new(0), @@ -436,7 +445,7 @@ fn acceptor_register_finality_signature() { // reached an invalid state. assert!(matches!( acceptor - .register_finality_signature(invalid_fin_sig.clone().into(), None, VALIDATOR_SLOTS) + .register_finality_signature(invalid_fin_sig.clone(), None, VALIDATOR_SLOTS) .unwrap_err(), Error::InvalidConfiguration )); @@ -444,12 +453,12 @@ fn acceptor_register_finality_signature() { let first_peer = NodeId::random(rng); assert!(matches!( acceptor - .register_finality_signature(invalid_fin_sig.into(), Some(first_peer), VALIDATOR_SLOTS) + .register_finality_signature(invalid_fin_sig, Some(first_peer), VALIDATOR_SLOTS) .unwrap_err(), Error::InvalidGossip(_) )); // Create a valid finality signature and register it. - let fin_sig = FinalitySignature::random_for_block( + let fin_sig = FinalitySignatureV2::random_for_block( *block.hash(), block.height(), block.era_id(), @@ -471,7 +480,7 @@ fn acceptor_register_finality_signature() { assert_eq!(*sig, fin_sig); assert_eq!(*senders, BTreeSet::from([first_peer, second_peer])); // Create a second finality signature and register it. - let second_fin_sig = FinalitySignature::random_for_block( + let second_fin_sig = FinalitySignatureV2::random_for_block( *block.hash(), block.height(), block.era_id(), @@ -504,7 +513,7 @@ fn acceptor_register_finality_signature() { .unwrap(); // Registering invalid signatures should still yield an error. let wrong_era = EraId::from(u64::MAX ^ u64::from(block.era_id())); - let invalid_fin_sig = FinalitySignature::random_for_block( + let invalid_fin_sig = FinalitySignatureV2::random_for_block( *block.hash(), block.height(), wrong_era, @@ -543,7 +552,7 @@ fn acceptor_register_finality_signature() { .1 .contains(&second_peer)); // Register a new valid signature which should be yielded by the function. - let third_fin_sig = FinalitySignature::random_for_block( + let third_fin_sig = FinalitySignatureV2::random_for_block( *block.hash(), block.height(), block.era_id(), @@ -652,6 +661,7 @@ fn acceptor_register_block() { fn acceptor_should_store_block() { let mut rng = TestRng::new(); // Create a block and an acceptor for it. + let chain_name_hash = ChainNameDigest::random(&mut rng); let block = Arc::new(TestBlockBuilder::new().build(&mut rng)); let mut meta_block = meta_block_with_default_state(block.clone()); let mut acceptor = BlockAcceptor::new(*block.hash(), vec![]); @@ -684,66 +694,96 @@ fn acceptor_should_store_block() { // With the sufficient finality flag set, nothing else should matter and we // should not store anything. acceptor.set_sufficient_finality(true); - let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); + let (should_store, _offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); assert_eq!(should_store, ShouldStore::Nothing); // Reset the flag. acceptor.set_sufficient_finality(false); - let (should_store, offenders) = acceptor.should_store_block(&era_validator_weights); + let (should_store, offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); assert_eq!(should_store, ShouldStore::Nothing); assert!(offenders.is_empty()); let mut signatures = vec![]; // Create the first validator's signature. - let fin_sig = FinalitySignatureV1::create(*block.hash(), block.era_id(), &keys[0].0); + let fin_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &keys[0].0, + ); signatures.push(fin_sig.clone()); // First signature with 40% weight brings the block to weak finality. acceptor - .register_finality_signature(fin_sig.into(), None, VALIDATOR_SLOTS) + .register_finality_signature(fin_sig, None, VALIDATOR_SLOTS) .unwrap(); - let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); + let (should_store, _offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); assert_eq!(should_store, ShouldStore::Nothing); // Registering the block now. acceptor.register_block(meta_block.clone(), None).unwrap(); - let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); + let (should_store, _offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); assert_eq!(should_store, ShouldStore::Nothing); // Create the third validator's signature. - let fin_sig = FinalitySignatureV1::create(*block.hash(), block.era_id(), &keys[2].0); + let fin_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &keys[2].0, + ); // The third signature with weight 10% doesn't make the block go to // strict finality. signatures.push(fin_sig.clone()); acceptor - .register_finality_signature(fin_sig.into(), None, VALIDATOR_SLOTS) + .register_finality_signature(fin_sig, None, VALIDATOR_SLOTS) .unwrap(); - let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); + let (should_store, _offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); assert_eq!(should_store, ShouldStore::Nothing); // Create a bogus signature from a non-validator for this era. let non_validator_keys = generate_ed25519_keypair(); let faulty_peer = NodeId::random(&mut rng); - let bogus_sig = - FinalitySignatureV1::create(*block.hash(), block.era_id(), &non_validator_keys.0); + let bogus_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &non_validator_keys.0, + ); acceptor - .register_finality_signature(bogus_sig.into(), Some(faulty_peer), VALIDATOR_SLOTS) + .register_finality_signature(bogus_sig, Some(faulty_peer), VALIDATOR_SLOTS) .unwrap(); - let (should_store, offenders) = acceptor.should_store_block(&era_validator_weights); + let (should_store, offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); assert_eq!(should_store, ShouldStore::Nothing); // Make sure the peer who sent us this bogus signature is marked as an // offender. assert_eq!(offenders[0].0, faulty_peer); // Create the second validator's signature. - let fin_sig = FinalitySignatureV1::create(*block.hash(), block.era_id(), &keys[1].0); + let fin_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &keys[1].0, + ); signatures.push(fin_sig.clone()); // Second signature with 40% weight brings the block to strict finality. acceptor - .register_finality_signature(fin_sig.into(), None, VALIDATOR_SLOTS) + .register_finality_signature(fin_sig, None, VALIDATOR_SLOTS) .unwrap(); - let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); - let block_signatures = signatures_for_block(&block, &signatures); + let (should_store, _offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); + let block_signatures = signatures_for_block(&block, &signatures, chain_name_hash); let mut meta_block_with_expected_state = meta_block.clone(); meta_block_with_expected_state.state.register_as_stored(); meta_block_with_expected_state @@ -758,26 +798,35 @@ fn acceptor_should_store_block() { ); // Create the fourth validator's signature. - let fin_sig = FinalitySignatureV1::create(*block.hash(), block.era_id(), &keys[3].0); + let fin_sig = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + chain_name_hash, + &keys[3].0, + ); // Already have sufficient finality signatures, so we're not supposed to // store anything else. acceptor - .register_finality_signature(fin_sig.into(), None, VALIDATOR_SLOTS) + .register_finality_signature(fin_sig, None, VALIDATOR_SLOTS) .unwrap(); - let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); + let (should_store, _offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); assert_eq!(should_store, ShouldStore::Nothing); // Without the block, even with sufficient signatures we should not store anything. acceptor.set_meta_block(None); acceptor.set_sufficient_finality(false); - let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); + let (should_store, _offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); assert_eq!(should_store, ShouldStore::Nothing); // Without any signatures, we should not store anything. meta_block.state.register_has_sufficient_finality(); acceptor.set_meta_block(Some(meta_block)); acceptor.signatures_mut().retain(|_, _| false); - let (should_store, _offenders) = acceptor.should_store_block(&era_validator_weights); + let (should_store, _offenders) = + acceptor.should_store_block(&era_validator_weights, chain_name_hash); assert_eq!(should_store, ShouldStore::Nothing); } @@ -794,7 +843,7 @@ fn acceptor_should_correctly_bound_the_signatures() { // Fill the signatures map: for fin_sig in (0..validator_slots * 2).map(|_| { - FinalitySignature::random_for_block( + FinalitySignatureV2::random_for_block( *block.hash(), block.height(), block.era_id(), @@ -808,7 +857,7 @@ fn acceptor_should_correctly_bound_the_signatures() { .is_none()); } - let fin_sig = FinalitySignature::random_for_block( + let fin_sig = FinalitySignatureV2::random_for_block( *block.hash(), block.height(), block.era_id(), @@ -835,7 +884,7 @@ fn acceptor_signatures_bound_should_not_be_triggered_if_peers_are_different() { // Fill the signatures map: for fin_sig in (0..validator_slots).map(|_| { - FinalitySignature::random_for_block( + FinalitySignatureV2::random_for_block( *block.hash(), block.height(), block.era_id(), @@ -850,7 +899,7 @@ fn acceptor_signatures_bound_should_not_be_triggered_if_peers_are_different() { } // This should pass, because it is another peer: - let fin_sig = FinalitySignature::random_for_block( + let fin_sig = FinalitySignatureV2::random_for_block( *block.hash(), block.height(), block.era_id(), @@ -1047,8 +1096,7 @@ fn block_acceptor(block: BlockV2, chain_name_hash: ChainNameDigest) -> BlockAcce block.era_id(), chain_name_hash, &ALICE_SECRET_KEY, - ) - .into(), + ), None, VALIDATOR_SLOTS, ) @@ -1144,7 +1192,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(fin_sig_1.into(), Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature(fin_sig_1, Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, None).unwrap(); } @@ -1163,7 +1211,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(fin_sig_2.into(), Some(peer_2), VALIDATOR_SLOTS) + .register_finality_signature(fin_sig_2, Some(peer_2), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, None).unwrap(); } @@ -1182,7 +1230,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(fin_sig_3.into(), Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature(fin_sig_3, Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1304,7 +1352,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(in_range_block_sig.into(), Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature(in_range_block_sig, Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1343,11 +1391,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature( - out_of_range_block_sig.into(), - Some(peer_1), - VALIDATOR_SLOTS, - ) + .register_finality_signature(out_of_range_block_sig, Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1432,7 +1476,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature(future_block_sig.into(), Some(peer_1), VALIDATOR_SLOTS) + .register_finality_signature(future_block_sig, Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1471,11 +1515,7 @@ fn accumulator_purge() { .try_into() .unwrap(); acceptor - .register_finality_signature( - future_unsigned_block_sig.into(), - Some(peer_1), - VALIDATOR_SLOTS, - ) + .register_finality_signature(future_unsigned_block_sig, Some(peer_1), VALIDATOR_SLOTS) .unwrap(); acceptor.register_block(meta_block, Some(peer_2)).unwrap(); } @@ -1577,6 +1617,7 @@ async fn block_accumulator_reactor_flow() { let mut rng = TestRng::new(); let (chainspec, chainspec_raw_bytes) = <(Chainspec, ChainspecRawBytes)>::from_resources("local"); + let chain_name_hash = chainspec.name_hash(); let mut runner: Runner = Runner::new( (), Arc::new(chainspec), @@ -1595,11 +1636,21 @@ async fn block_accumulator_reactor_flow() { let peer_2 = NodeId::random(&mut rng); // One finality signature from our only validator for block 1. - let fin_sig_1 = - FinalitySignatureV1::create(*block_1.hash(), block_1.era_id(), &ALICE_SECRET_KEY); + let fin_sig_1 = FinalitySignatureV2::create( + *block_1.hash(), + block_1.height(), + block_1.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // One finality signature from our only validator for block 2. - let fin_sig_2 = - FinalitySignatureV1::create(*block_2.hash(), block_2.era_id(), &ALICE_SECRET_KEY); + let fin_sig_2 = FinalitySignatureV2::create( + *block_2.hash(), + block_2.height(), + block_2.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // Register the eras in the validator matrix so the blocks are valid. { @@ -1617,7 +1668,7 @@ async fn block_accumulator_reactor_flow() { block_accumulator.register_local_tip(0, 0.into()); let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(fin_sig_1.clone().into()), + finality_signature: Box::new(fin_sig_1.clone()), sender: peer_1, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); @@ -1681,7 +1732,7 @@ async fn block_accumulator_reactor_flow() { runner .process_injected_effects(|effect_builder| { let event = super::Event::CreatedFinalitySignature { - finality_signature: Box::new(fin_sig_2.clone().into()), + finality_signature: Box::new(fin_sig_2.clone()), }; effect_builder .into_inner() @@ -1882,8 +1933,13 @@ async fn block_accumulator_reactor_flow() { .contains_key(older_block.hash())); } - let older_block_signature = - FinalitySignatureV1::create(*older_block.hash(), older_block.era_id(), &ALICE_SECRET_KEY); + let older_block_signature = FinalitySignatureV2::create( + *older_block.hash(), + older_block.height(), + older_block.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // Register a signature for an older block. { let effect_builder = runner.effect_builder(); @@ -1891,7 +1947,7 @@ async fn block_accumulator_reactor_flow() { let block_accumulator = &mut reactor.block_accumulator; let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(older_block_signature.into()), + finality_signature: Box::new(older_block_signature), sender: peer_2, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); @@ -1911,9 +1967,11 @@ async fn block_accumulator_reactor_flow() { .switch_block(false) .build(&mut rng); - let old_era_signature = FinalitySignatureV1::create( + let old_era_signature = FinalitySignatureV2::create( *old_era_block.hash(), + old_era_block.height(), old_era_block.era_id(), + chain_name_hash, &ALICE_SECRET_KEY, ); // Register a signature for a block in an old era. @@ -1923,7 +1981,7 @@ async fn block_accumulator_reactor_flow() { let block_accumulator = &mut reactor.block_accumulator; let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(old_era_signature.into()), + finality_signature: Box::new(old_era_signature), sender: peer_2, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); @@ -1941,6 +1999,7 @@ async fn block_accumulator_doesnt_purge_with_delayed_block_execution() { let mut rng = TestRng::new(); let (chainspec, chainspec_raw_bytes) = <(Chainspec, ChainspecRawBytes)>::from_resources("local"); + let chain_name_hash = chainspec.name_hash(); let mut runner: Runner = Runner::new( (), Arc::new(chainspec), @@ -1957,14 +2016,29 @@ async fn block_accumulator_doesnt_purge_with_delayed_block_execution() { let peer_1 = NodeId::random(&mut rng); let peer_2 = NodeId::random(&mut rng); - let fin_sig_bob = - FinalitySignatureV1::create(*block_1.hash(), block_1.era_id(), &BOB_SECRET_KEY); + let fin_sig_bob = FinalitySignatureV2::create( + *block_1.hash(), + block_1.height(), + block_1.era_id(), + chain_name_hash, + &BOB_SECRET_KEY, + ); - let fin_sig_carol = - FinalitySignatureV1::create(*block_1.hash(), block_1.era_id(), &CAROL_SECRET_KEY); + let fin_sig_carol = FinalitySignatureV2::create( + *block_1.hash(), + block_1.height(), + block_1.era_id(), + chain_name_hash, + &CAROL_SECRET_KEY, + ); - let fin_sig_alice = - FinalitySignatureV1::create(*block_1.hash(), block_1.era_id(), &ALICE_SECRET_KEY); + let fin_sig_alice = FinalitySignatureV2::create( + *block_1.hash(), + block_1.height(), + block_1.era_id(), + chain_name_hash, + &ALICE_SECRET_KEY, + ); // Register the era in the validator matrix so the block is valid. { @@ -1991,14 +2065,14 @@ async fn block_accumulator_doesnt_purge_with_delayed_block_execution() { block_accumulator.register_local_tip(0, 0.into()); let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(fin_sig_bob.clone().into()), + finality_signature: Box::new(fin_sig_bob.clone()), sender: peer_1, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); assert!(effects.is_empty()); let event = super::Event::ReceivedFinalitySignature { - finality_signature: Box::new(fin_sig_carol.clone().into()), + finality_signature: Box::new(fin_sig_carol.clone()), sender: peer_1, }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); @@ -2007,7 +2081,7 @@ async fn block_accumulator_doesnt_purge_with_delayed_block_execution() { // Register the finality signature created by Alice (this validator) after executing the // block. let event = super::Event::CreatedFinalitySignature { - finality_signature: Box::new(fin_sig_alice.clone().into()), + finality_signature: Box::new(fin_sig_alice.clone()), }; let effects = block_accumulator.handle_event(effect_builder, &mut rng, event); assert!(effects.is_empty()); diff --git a/node/src/components/fetcher/tests.rs b/node/src/components/fetcher/tests.rs index 39f171c339..f466dd9934 100644 --- a/node/src/components/fetcher/tests.rs +++ b/node/src/components/fetcher/tests.rs @@ -12,7 +12,7 @@ use tempfile::TempDir; use thiserror::Error; use casper_types::{ - testing::TestRng, BlockV2, Chainspec, ChainspecRawBytes, FinalitySignature, Transaction, + testing::TestRng, BlockV2, Chainspec, ChainspecRawBytes, FinalitySignatureV2, Transaction, TransactionHash, TransactionId, }; @@ -127,7 +127,7 @@ enum Event { #[from] GossiperIncomingBlock(GossiperIncoming), #[from] - GossiperIncomingFinalitySignature(GossiperIncoming), + GossiperIncomingFinalitySignature(GossiperIncoming), #[from] GossiperIncomingGossipedAddress(GossiperIncoming), #[from] diff --git a/node/src/components/gossiper/provider_impls/finality_signature_provider.rs b/node/src/components/gossiper/provider_impls/finality_signature_provider.rs index 4d15ee2c31..566b0219b1 100644 --- a/node/src/components/gossiper/provider_impls/finality_signature_provider.rs +++ b/node/src/components/gossiper/provider_impls/finality_signature_provider.rs @@ -1,13 +1,13 @@ use async_trait::async_trait; -use casper_types::{FinalitySignature, FinalitySignatureId}; +use casper_types::{FinalitySignature, FinalitySignatureId, FinalitySignatureV2}; use crate::{ components::gossiper::{GossipItem, GossipTarget, Gossiper, ItemProvider, LargeGossipItem}, effect::{requests::StorageRequest, EffectBuilder}, }; -impl GossipItem for FinalitySignature { +impl GossipItem for FinalitySignatureV2 { type Id = Box; const ID_IS_COMPLETE_ITEM: bool = false; @@ -26,11 +26,11 @@ impl GossipItem for FinalitySignature { } } -impl LargeGossipItem for FinalitySignature {} +impl LargeGossipItem for FinalitySignatureV2 {} #[async_trait] -impl ItemProvider - for Gossiper<{ FinalitySignature::ID_IS_COMPLETE_ITEM }, FinalitySignature> +impl ItemProvider + for Gossiper<{ FinalitySignatureV2::ID_IS_COMPLETE_ITEM }, FinalitySignatureV2> { async fn is_stored + Send>( effect_builder: EffectBuilder, @@ -42,11 +42,15 @@ impl ItemProvider async fn get_from_storage + Send>( effect_builder: EffectBuilder, item_id: Box, - ) -> Option> { + ) -> Option> { // TODO: Make `get_finality_signature_from_storage` return a boxed copy instead. - effect_builder + if let Some(FinalitySignature::V2(sig)) = effect_builder .get_finality_signature_from_storage(item_id) .await - .map(Box::new) + { + Some(Box::new(sig)) + } else { + None + } } } diff --git a/node/src/components/gossiper/tests.rs b/node/src/components/gossiper/tests.rs index 212b1bcd39..cda8259d91 100644 --- a/node/src/components/gossiper/tests.rs +++ b/node/src/components/gossiper/tests.rs @@ -18,7 +18,7 @@ use tokio::time; use tracing::debug; use casper_types::{ - testing::TestRng, BlockV2, Chainspec, ChainspecRawBytes, EraId, FinalitySignature, + testing::TestRng, BlockV2, Chainspec, ChainspecRawBytes, EraId, FinalitySignatureV2, ProtocolVersion, TimeDiff, Transaction, }; @@ -113,7 +113,7 @@ impl Unhandled for ControlAnnouncement {} impl Unhandled for FatalAnnouncement {} impl Unhandled for ConsensusMessageIncoming {} impl Unhandled for GossiperIncoming {} -impl Unhandled for GossiperIncoming {} +impl Unhandled for GossiperIncoming {} impl Unhandled for GossiperIncoming {} impl Unhandled for NetRequestIncoming {} impl Unhandled for NetResponseIncoming {} diff --git a/node/src/components/storage.rs b/node/src/components/storage.rs index 4eef11e693..f5b970865f 100644 --- a/node/src/components/storage.rs +++ b/node/src/components/storage.rs @@ -75,10 +75,11 @@ use casper_types::{ execution::{ execution_result_v1, ExecutionResult, ExecutionResultV1, ExecutionResultV2, TransformKind, }, - Block, BlockBody, BlockHash, BlockHeader, BlockSignatures, BlockSignaturesV1, BlockV2, - DeployApprovalsHash, DeployHash, Digest, EraId, FinalitySignature, ProtocolVersion, PublicKey, - SignedBlockHeader, StoredValue, Timestamp, Transaction, TransactionApprovalsHash, - TransactionHash, TransactionHeader, TransactionId, TransactionV1ApprovalsHash, Transfer, + Block, BlockBody, BlockHash, BlockHeader, BlockSignatures, BlockSignaturesV1, + BlockSignaturesV2, BlockV2, ChainNameDigest, DeployApprovalsHash, DeployHash, Digest, EraId, + FinalitySignature, ProtocolVersion, PublicKey, SignedBlockHeader, StoredValue, Timestamp, + Transaction, TransactionApprovalsHash, TransactionHash, TransactionHeader, TransactionId, + TransactionV1ApprovalsHash, Transfer, }; use crate::{ @@ -203,6 +204,8 @@ pub struct Storage { metrics: Option, /// The maximum TTL of a deploy. max_ttl: MaxTtl, + /// The hash of the chain name. + chain_name_hash: ChainNameDigest, } pub(crate) enum HighestOrphanedBlockResult { @@ -474,6 +477,7 @@ impl Storage { recent_era_count, max_ttl, metrics, + chain_name_hash: ChainNameDigest::new(Digest::hash(network_name.as_bytes())), }; if force_resync { @@ -950,7 +954,7 @@ impl Storage { } let block_signatures = match self.get_block_signatures(&mut txn, &block_hash)? { Some(signatures) => signatures, - None => BlockSignaturesV1::new(block_hash, block.era_id()).into(), + None => self.get_default_block_signatures(&block), }; if block_signatures.is_verified().is_err() { error!(?block, "invalid block signatures for block"); @@ -1002,7 +1006,7 @@ impl Storage { let hash = block.hash(); let block_signatures = match self.get_block_signatures(&mut txn, hash)? { Some(signatures) => signatures, - None => BlockSignaturesV1::new(*hash, block.era_id()).into(), + None => self.get_default_block_signatures(&block), }; responder .respond(Some(BlockWithMetadata { @@ -1033,7 +1037,7 @@ impl Storage { let hash = block.hash(); let block_signatures = match self.get_block_signatures(&mut txn, hash)? { Some(signatures) => signatures, - None => BlockSignaturesV1::new(*hash, block.era_id()).into(), + None => self.get_default_block_signatures(&block), }; responder .respond(Some(SignedBlock { @@ -1063,7 +1067,7 @@ impl Storage { let hash = highest_block.hash(); let block_signatures = match self.get_block_signatures(&mut txn, hash)? { Some(signatures) => signatures, - None => BlockSignaturesV1::new(*hash, highest_block.era_id()).into(), + None => self.get_default_block_signatures(&highest_block), }; responder .respond(Some(SignedBlock { @@ -1283,10 +1287,34 @@ impl Storage { let mut block_signatures = self .block_metadata_dbs .get(&mut txn, signature.block_hash())? - .unwrap_or_else(|| { - BlockSignaturesV1::new(*signature.block_hash(), signature.era_id()).into() + .unwrap_or_else(|| match &*signature { + FinalitySignature::V1(signature) => { + BlockSignaturesV1::new(*signature.block_hash(), signature.era_id()).into() + } + FinalitySignature::V2(signature) => BlockSignaturesV2::new( + *signature.block_hash(), + signature.block_height(), + signature.era_id(), + signature.chain_name_hash(), + ) + .into(), }); - block_signatures.insert_signature(signature.public_key().clone(), *signature.signature()); + + match (&mut block_signatures, *signature) { + (BlockSignatures::V1(ref mut block_signatures), FinalitySignature::V1(signature)) => { + block_signatures + .insert_signature(signature.public_key().clone(), *signature.signature()); + } + (BlockSignatures::V2(ref mut block_signatures), FinalitySignature::V2(signature)) => { + block_signatures + .insert_signature(signature.public_key().clone(), *signature.signature()); + } + (_, signature) => { + return Err(FatalStorageError::VariantMismatch(VariantMismatch( + Box::new(*signature.block_hash()), + ))); + } + } let outcome = self.block_metadata_dbs.put( &mut txn, block_signatures.block_hash(), @@ -2051,7 +2079,18 @@ impl Storage { let block_signatures = match self.get_block_signatures(txn, &block_header_hash)? { Some(signatures) => signatures, - None => BlockSignaturesV1::new(block_header_hash, block_header.era_id()).into(), + None => match &block_header { + BlockHeader::V1(header) => BlockSignatures::V1(BlockSignaturesV1::new( + header.block_hash(), + header.era_id(), + )), + BlockHeader::V2(header) => BlockSignatures::V2(BlockSignaturesV2::new( + header.block_hash(), + header.height(), + header.era_id(), + self.chain_name_hash, + )), + }, }; Ok(Some(SignedBlockHeader::new(block_header, block_signatures))) @@ -2658,6 +2697,19 @@ impl Storage { )) } + fn get_default_block_signatures(&self, block: &Block) -> BlockSignatures { + match block { + Block::V1(block) => BlockSignaturesV1::new(*block.hash(), block.era_id()).into(), + Block::V2(block) => BlockSignaturesV2::new( + *block.hash(), + block.height(), + block.era_id(), + self.chain_name_hash, + ) + .into(), + } + } + fn update_chain_height_metrics(&self) { if let Some(metrics) = self.metrics.as_ref() { if let Some(sequence) = self.completed_blocks.highest_sequence() { diff --git a/node/src/components/storage/tests.rs b/node/src/components/storage/tests.rs index ec8bb40361..5e5baf5c35 100644 --- a/node/src/components/storage/tests.rs +++ b/node/src/components/storage/tests.rs @@ -2352,14 +2352,14 @@ fn should_initialize_block_metadata_db() { let chain_name_hash = ChainNameDigest::random(&mut harness.rng); let block_1 = TestBlockBuilder::new().build(&mut harness.rng); - let fs_1_1 = FinalitySignature::random_for_block( + let fs_1_1 = FinalitySignatureV2::random_for_block( *block_1.hash(), block_1.height(), block_1.header().era_id(), chain_name_hash, &mut harness.rng, ); - let fs_1_2 = FinalitySignature::random_for_block( + let fs_1_2 = FinalitySignatureV2::random_for_block( *block_1.hash(), block_1.height(), block_1.header().era_id(), @@ -2368,14 +2368,14 @@ fn should_initialize_block_metadata_db() { ); let block_2 = TestBlockBuilder::new().build(&mut harness.rng); - let fs_2_1 = FinalitySignature::random_for_block( + let fs_2_1 = FinalitySignatureV2::random_for_block( *block_2.hash(), block_2.height(), block_2.header().era_id(), chain_name_hash, &mut harness.rng, ); - let fs_2_2 = FinalitySignature::random_for_block( + let fs_2_2 = FinalitySignatureV2::random_for_block( *block_2.hash(), block_2.height(), block_2.header().era_id(), @@ -2384,14 +2384,14 @@ fn should_initialize_block_metadata_db() { ); let block_3 = TestBlockBuilder::new().build(&mut harness.rng); - let fs_3_1 = FinalitySignature::random_for_block( + let fs_3_1 = FinalitySignatureV2::random_for_block( *block_3.hash(), block_3.height(), block_3.header().era_id(), chain_name_hash, &mut harness.rng, ); - let fs_3_2 = FinalitySignature::random_for_block( + let fs_3_2 = FinalitySignatureV2::random_for_block( *block_3.hash(), block_3.height(), block_3.header().era_id(), @@ -2401,43 +2401,47 @@ fn should_initialize_block_metadata_db() { let block_4 = TestBlockBuilder::new().build(&mut harness.rng); - let _ = storage.put_finality_signature(Box::new(fs_1_1.clone())); - let _ = storage.put_finality_signature(Box::new(fs_1_2.clone())); - let _ = storage.put_finality_signature(Box::new(fs_2_1.clone())); - let _ = storage.put_finality_signature(Box::new(fs_2_2.clone())); - let _ = storage.put_finality_signature(Box::new(fs_3_1.clone())); - let _ = storage.put_finality_signature(Box::new(fs_3_2.clone())); + let _ = storage.put_finality_signature(Box::new(fs_1_1.clone().into())); + let _ = storage.put_finality_signature(Box::new(fs_1_2.clone().into())); + let _ = storage.put_finality_signature(Box::new(fs_2_1.clone().into())); + let _ = storage.put_finality_signature(Box::new(fs_2_2.clone().into())); + let _ = storage.put_finality_signature(Box::new(fs_3_1.clone().into())); + let _ = storage.put_finality_signature(Box::new(fs_3_2.clone().into())); assert_signatures( &storage, *block_1.hash(), - vec![fs_1_1.clone(), fs_1_2.clone()], + vec![fs_1_1.clone().into(), fs_1_2.clone().into()], ); assert_signatures( &storage, *block_2.hash(), - vec![fs_2_1.clone(), fs_2_2.clone()], + vec![fs_2_1.clone().into(), fs_2_2.clone().into()], ); assert_signatures( &storage, *block_3.hash(), - vec![fs_3_1.clone(), fs_3_2.clone()], + vec![fs_3_1.clone().into(), fs_3_2.clone().into()], ); assert_signatures(&storage, *block_4.hash(), vec![]); // Purging empty set of blocks should not change state. let to_be_purged = HashSet::new(); let _ = initialize_block_metadata_dbs(&storage.env, storage.block_metadata_dbs, to_be_purged); - assert_signatures(&storage, *block_1.hash(), vec![fs_1_1, fs_1_2]); + assert_signatures( + &storage, + *block_1.hash(), + vec![fs_1_1.into(), fs_1_2.into()], + ); assert_signatures( &storage, *block_2.hash(), - vec![fs_2_1.clone(), fs_2_2.clone()], + vec![fs_2_1.clone().into(), fs_2_2.clone().into()], ); assert_signatures( &storage, *block_3.hash(), - vec![fs_3_1.clone(), fs_3_2.clone()], + vec![fs_3_1.clone().into(), fs_3_2.clone().into()], ); // Purging for block_1 should leave sigs for block_2 and block_3 intact. @@ -2447,12 +2451,12 @@ fn should_initialize_block_metadata_db() { assert_signatures( &storage, *block_2.hash(), - vec![fs_2_1.clone(), fs_2_2.clone()], + vec![fs_2_1.clone().into(), fs_2_2.clone().into()], ); assert_signatures( &storage, *block_3.hash(), - vec![fs_3_1.clone(), fs_3_2.clone()], + vec![fs_3_1.clone().into(), fs_3_2.clone().into()], ); assert_signatures(&storage, *block_4.hash(), vec![]); @@ -2460,8 +2464,16 @@ fn should_initialize_block_metadata_db() { let to_be_purged = HashSet::from_iter([*block_4.hash()]); let _ = initialize_block_metadata_dbs(&storage.env, storage.block_metadata_dbs, to_be_purged); assert_signatures(&storage, *block_1.hash(), vec![]); - assert_signatures(&storage, *block_2.hash(), vec![fs_2_1, fs_2_2]); - assert_signatures(&storage, *block_3.hash(), vec![fs_3_1, fs_3_2]); + assert_signatures( + &storage, + *block_2.hash(), + vec![fs_2_1.into(), fs_2_2.into()], + ); + assert_signatures( + &storage, + *block_3.hash(), + vec![fs_3_1.into(), fs_3_2.into()], + ); assert_signatures(&storage, *block_4.hash(), vec![]); // Purging for all blocks should leave no signatures. diff --git a/node/src/effect.rs b/node/src/effect.rs index 19f019ab3d..bf493fb167 100644 --- a/node/src/effect.rs +++ b/node/src/effect.rs @@ -127,8 +127,9 @@ use casper_types::{ package::Package, system::auction::EraValidators, AddressableEntity, Block, BlockHash, BlockHeader, BlockSignatures, BlockV2, ChainspecRawBytes, - DeployHash, Digest, EraId, FinalitySignature, FinalitySignatureId, Key, PublicKey, TimeDiff, - Timestamp, Transaction, TransactionHash, TransactionHeader, TransactionId, Transfer, U512, + DeployHash, Digest, EraId, FinalitySignature, FinalitySignatureId, FinalitySignatureV2, Key, + PublicKey, TimeDiff, Timestamp, Transaction, TransactionHash, TransactionHeader, TransactionId, + Transfer, U512, }; use crate::{ @@ -866,7 +867,7 @@ impl EffectBuilder { /// Announces that the block accumulator has received and stored a new finality signature. pub(crate) async fn announce_finality_signature_accepted( self, - finality_signature: Box, + finality_signature: Box, ) where REv: From, { diff --git a/node/src/effect/announcements.rs b/node/src/effect/announcements.rs index 64179e384d..376af0644c 100644 --- a/node/src/effect/announcements.rs +++ b/node/src/effect/announcements.rs @@ -15,8 +15,8 @@ use itertools::Itertools; use serde::Serialize; use casper_types::{ - execution::Effects, Block, DeployHash, EraId, FinalitySignature, PublicKey, Timestamp, - Transaction, U512, + execution::Effects, Block, DeployHash, EraId, FinalitySignature, FinalitySignatureV2, + PublicKey, Timestamp, Transaction, U512, }; use crate::{ @@ -402,7 +402,7 @@ pub(crate) enum BlockAccumulatorAnnouncement { /// A finality signature which wasn't previously stored on this node has been accepted and /// stored. AcceptedNewFinalitySignature { - finality_signature: Box, + finality_signature: Box, }, } diff --git a/node/src/effect/incoming.rs b/node/src/effect/incoming.rs index 7e8f20f868..3572371d47 100644 --- a/node/src/effect/incoming.rs +++ b/node/src/effect/incoming.rs @@ -10,7 +10,7 @@ use std::{ use datasize::DataSize; use serde::Serialize; -use casper_types::FinalitySignature; +use casper_types::FinalitySignatureV2; use super::AutoClosingResponder; use crate::{ @@ -80,7 +80,7 @@ pub(crate) type ConsensusDemand = DemandIncoming; /// A new finality signature arrived over the network. -pub(crate) type FinalitySignatureIncoming = MessageIncoming; +pub(crate) type FinalitySignatureIncoming = MessageIncoming; /// A request for an object out of storage arrived. /// diff --git a/node/src/protocol.rs b/node/src/protocol.rs index 0bb7ef8b56..c5fb582d7c 100644 --- a/node/src/protocol.rs +++ b/node/src/protocol.rs @@ -12,7 +12,7 @@ use hex_fmt::HexFmt; use serde::{Deserialize, Serialize}; use strum::EnumDiscriminants; -use casper_types::{BlockV2, FinalitySignature, Transaction}; +use casper_types::{BlockV2, FinalitySignatureV2, Transaction}; use crate::{ components::{ @@ -49,7 +49,7 @@ pub(crate) enum Message { #[from] TransactionGossiper(gossiper::Message), #[from] - FinalitySignatureGossiper(gossiper::Message), + FinalitySignatureGossiper(gossiper::Message), /// Address gossiper component message. #[from] AddressGossiper(gossiper::Message), @@ -69,7 +69,7 @@ pub(crate) enum Message { }, /// Finality signature. #[from] - FinalitySignature(Box), + FinalitySignature(Box), } impl Payload for Message { @@ -302,7 +302,7 @@ where + From + From> + From> - + From> + + From> + From> + From + From diff --git a/node/src/reactor/main_reactor.rs b/node/src/reactor/main_reactor.rs index 4abadcdfca..03bb3764b1 100644 --- a/node/src/reactor/main_reactor.rs +++ b/node/src/reactor/main_reactor.rs @@ -27,8 +27,8 @@ use tracing::{debug, error, info, warn}; use casper_types::{ Block, BlockHash, BlockV2, Chainspec, ChainspecRawBytes, DeployId, EraId, FinalitySignature, - PublicKey, TimeDiff, Timestamp, Transaction, TransactionHash, TransactionHeader, TransactionId, - U512, + FinalitySignatureV2, PublicKey, TimeDiff, Timestamp, Transaction, TransactionHash, + TransactionHeader, TransactionId, U512, }; #[cfg(test)] @@ -161,7 +161,7 @@ pub(crate) struct MainReactor { transaction_gossiper: Gossiper<{ Transaction::ID_IS_COMPLETE_ITEM }, Transaction>, block_gossiper: Gossiper<{ BlockV2::ID_IS_COMPLETE_ITEM }, BlockV2>, finality_signature_gossiper: - Gossiper<{ FinalitySignature::ID_IS_COMPLETE_ITEM }, FinalitySignature>, + Gossiper<{ FinalitySignatureV2::ID_IS_COMPLETE_ITEM }, FinalitySignatureV2>, // record retrieval sync_leaper: SyncLeaper, @@ -512,7 +512,9 @@ impl reactor::Reactor for MainReactor { self.event_stream_server.handle_event( effect_builder, rng, - event_stream_server::Event::FinalitySignature(finality_signature), + event_stream_server::Event::FinalitySignature(Box::new( + (*finality_signature).into(), + )), ), )); @@ -668,17 +670,25 @@ impl reactor::Reactor for MainReactor { finality_signature, peer, }, - ) => reactor::wrap_effects( - MainEvent::BlockAccumulator, - self.block_accumulator.handle_event( - effect_builder, - rng, - block_accumulator::Event::ReceivedFinalitySignature { - finality_signature, - sender: peer, - }, - ), - ), + ) => { + // If the signature is not convertible to the current version it means + // that it is historical. + if let FinalitySignature::V2(sig) = *finality_signature { + reactor::wrap_effects( + MainEvent::BlockAccumulator, + self.block_accumulator.handle_event( + effect_builder, + rng, + block_accumulator::Event::ReceivedFinalitySignature { + finality_signature: Box::new(sig), + sender: peer, + }, + ), + ) + } else { + Effects::new() + } + } // DEPLOYS MainEvent::TransactionAcceptor(event) => reactor::wrap_effects( @@ -1121,12 +1131,12 @@ impl reactor::Reactor for MainReactor { config.gossip, registry, )?; - let finality_signature_gossiper = - Gossiper::<{ FinalitySignature::ID_IS_COMPLETE_ITEM }, _>::new( - "finality_signature_gossiper", - config.gossip, - registry, - )?; + let finality_signature_gossiper = Gossiper::< + { FinalitySignatureV2::ID_IS_COMPLETE_ITEM }, + _, + >::new( + "finality_signature_gossiper", config.gossip, registry + )?; // consensus let consensus = EraSupervisor::new( @@ -1395,7 +1405,7 @@ impl MainReactor { effects.extend(reactor::wrap_effects( MainEvent::Storage, effect_builder - .put_finality_signature_to_storage(finality_signature.clone()) + .put_finality_signature_to_storage(finality_signature.clone().into()) .ignore(), )); diff --git a/node/src/reactor/main_reactor/event.rs b/node/src/reactor/main_reactor/event.rs index 0a2f915219..af0570141f 100644 --- a/node/src/reactor/main_reactor/event.rs +++ b/node/src/reactor/main_reactor/event.rs @@ -8,7 +8,7 @@ use serde::Serialize; use casper_types::{ system::auction::EraValidators, Block, BlockHeader, BlockV2, EraId, FinalitySignature, - Transaction, + FinalitySignatureV2, Transaction, }; use crate::{ @@ -168,12 +168,12 @@ pub(crate) enum MainEvent { #[from] FinalitySignatureIncoming(FinalitySignatureIncoming), #[from] - FinalitySignatureGossiper(#[serde(skip_serializing)] gossiper::Event), + FinalitySignatureGossiper(#[serde(skip_serializing)] gossiper::Event), #[from] - FinalitySignatureGossiperIncoming(GossiperIncoming), + FinalitySignatureGossiperIncoming(GossiperIncoming), #[from] FinalitySignatureGossiperAnnouncement( - #[serde(skip_serializing)] GossiperAnnouncement, + #[serde(skip_serializing)] GossiperAnnouncement, ), #[from] FinalitySignatureFetcher(#[serde(skip_serializing)] fetcher::Event), @@ -611,8 +611,8 @@ impl From>> for MainEvent { } } -impl From>> for MainEvent { - fn from(request: NetworkRequest>) -> Self { +impl From>> for MainEvent { + fn from(request: NetworkRequest>) -> Self { MainEvent::NetworkRequest(request.map_payload(Message::from)) } } diff --git a/node/src/types/validator_matrix.rs b/node/src/types/validator_matrix.rs index 644fb579d4..616140ca6a 100644 --- a/node/src/types/validator_matrix.rs +++ b/node/src/types/validator_matrix.rs @@ -14,8 +14,7 @@ use static_assertions::const_assert; use tracing::info; use casper_types::{ - BlockHeaderV2, ChainNameDigest, EraId, FinalitySignature, FinalitySignatureV2, PublicKey, - SecretKey, U512, + BlockHeaderV2, ChainNameDigest, EraId, FinalitySignatureV2, PublicKey, SecretKey, U512, }; const MAX_VALIDATOR_MATRIX_ENTRIES: usize = 6; @@ -276,21 +275,18 @@ impl ValidatorMatrix { pub(crate) fn create_finality_signature( &self, block_header: &BlockHeaderV2, - ) -> Option { + ) -> Option { if self .is_self_validator_in_era(block_header.era_id()) .unwrap_or(false) { - return Some( - FinalitySignatureV2::create( - block_header.block_hash(), - block_header.height(), - block_header.era_id(), - self.chainspec_name_hash, - &self.secret_signing_key, - ) - .into(), - ); + return Some(FinalitySignatureV2::create( + block_header.block_hash(), + block_header.height(), + block_header.era_id(), + self.chainspec_name_hash, + &self.secret_signing_key, + )); } None } @@ -303,7 +299,6 @@ impl ValidatorMatrix { self.read_inner().keys().copied().collect_vec() } - #[cfg(test)] pub fn chain_name_hash(&self) -> ChainNameDigest { self.chainspec_name_hash } diff --git a/node/src/utils/specimen.rs b/node/src/utils/specimen.rs index 828feba897..34883409e3 100644 --- a/node/src/utils/specimen.rs +++ b/node/src/utils/specimen.rs @@ -735,14 +735,20 @@ impl LargestSpecimen for FinalizedBlock { impl LargestSpecimen for FinalitySignature { fn largest_specimen(estimator: &E, cache: &mut Cache) -> Self { - FinalitySignature::V2(FinalitySignatureV2::new( + FinalitySignature::V2(LargestSpecimen::largest_specimen(estimator, cache)) + } +} + +impl LargestSpecimen for FinalitySignatureV2 { + fn largest_specimen(estimator: &E, cache: &mut Cache) -> Self { + FinalitySignatureV2::new( LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), LargestSpecimen::largest_specimen(estimator, cache), - )) + ) } } diff --git a/resources/test/sse_data_schema.json b/resources/test/sse_data_schema.json index eea6de5cf9..ad100a989b 100644 --- a/resources/test/sse_data_schema.json +++ b/resources/test/sse_data_schema.json @@ -3421,10 +3421,87 @@ "type": "string" }, "FinalitySignature": { + "description": "A validator's signature of a block, confirming it is finalized.", + "oneOf": [ + { + "description": "Version 1 of the finality signature.", + "type": "object", + "required": [ + "V1" + ], + "properties": { + "V1": { + "$ref": "#/definitions/FinalitySignatureV1" + } + }, + "additionalProperties": false + }, + { + "description": "Version 2 of the finality signature.", + "type": "object", + "required": [ + "V2" + ], + "properties": { + "V2": { + "$ref": "#/definitions/FinalitySignatureV2" + } + }, + "additionalProperties": false + } + ] + }, + "FinalitySignatureV1": { + "description": "A validator's signature of a block, confirming it is finalized.", + "type": "object", + "required": [ + "block_hash", + "era_id", + "public_key", + "signature" + ], + "properties": { + "block_hash": { + "description": "The block hash of the associated block.", + "allOf": [ + { + "$ref": "#/definitions/BlockHash" + } + ] + }, + "era_id": { + "description": "The era in which the associated block was created.", + "allOf": [ + { + "$ref": "#/definitions/EraId" + } + ] + }, + "signature": { + "description": "The signature over the block hash of the associated block.", + "allOf": [ + { + "$ref": "#/definitions/Signature" + } + ] + }, + "public_key": { + "description": "The public key of the signing validator.", + "allOf": [ + { + "$ref": "#/definitions/PublicKey" + } + ] + } + } + }, + "FinalitySignatureV2": { "description": "A validator's signature of a block, confirming it is finalized.", "type": "object", "required": [ "block_hash", + "block_height", + "chain_name_hash", "era_id", "public_key", "signature" @@ -3438,6 +3515,12 @@ } ] }, + "block_height": { + "description": "The height of the associated block.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, "era_id": { "description": "The era in which the associated block was created.", "allOf": [ @@ -3446,6 +3529,14 @@ } ] }, + "chain_name_hash": { + "description": "The hash of the chain name of the associated block.", + "allOf": [ + { + "$ref": "#/definitions/ChainNameDigest" + } + ] + }, "signature": { "description": "The signature over the block hash of the associated block.", "allOf": [ @@ -3463,6 +3554,14 @@ ] } } + }, + "ChainNameDigest": { + "description": "Hex-encoded cryptographic hash of a chain name.", + "allOf": [ + { + "$ref": "#/definitions/Digest" + } + ] } } } \ No newline at end of file diff --git a/types/src/block/block_signatures.rs b/types/src/block/block_signatures.rs index 6881c29acd..afb2d93688 100644 --- a/types/src/block/block_signatures.rs +++ b/types/src/block/block_signatures.rs @@ -150,36 +150,30 @@ impl BlockSignatures { }); } - if let (BlockSignatures::V2(self_), BlockSignatures::V2(other)) = (&self, &other) { - if self_.block_height != other.block_height { - return Err(BlockSignaturesMergeError::BlockHeightMismatch { - self_height: self_.block_height, - other_height: other.block_height, - }); - } - - if self_.chain_name_hash != other.chain_name_hash { - return Err(BlockSignaturesMergeError::ChainNameHashMismatch { - self_chain_name_hash: self_.chain_name_hash, - other_chain_name_hash: other.chain_name_hash, - }); - } - } - match (self, &mut other) { (BlockSignatures::V1(self_), BlockSignatures::V1(other)) => { self_.proofs.append(&mut other.proofs); } (BlockSignatures::V2(self_), BlockSignatures::V2(other)) => { + if self_.block_height != other.block_height { + return Err(BlockSignaturesMergeError::BlockHeightMismatch { + self_height: self_.block_height, + other_height: other.block_height, + }); + } + + if self_.chain_name_hash != other.chain_name_hash { + return Err(BlockSignaturesMergeError::ChainNameHashMismatch { + self_chain_name_hash: self_.chain_name_hash, + other_chain_name_hash: other.chain_name_hash, + }); + } + self_.proofs.append(&mut other.proofs); } - (BlockSignatures::V1(self_), BlockSignatures::V2(other)) => { - self_.proofs.append(&mut other.proofs); - } - (BlockSignatures::V2(self_), BlockSignatures::V1(other)) => { - self_.proofs.append(&mut other.proofs); - } + _ => return Err(BlockSignaturesMergeError::VersionMismatch), } + Ok(()) } @@ -336,6 +330,8 @@ pub enum BlockSignaturesMergeError { /// The `other` chain name hash. other_chain_name_hash: ChainNameDigest, }, + /// A mismatch between the versions of the block signatures. + VersionMismatch, } impl Display for BlockSignaturesMergeError { @@ -385,6 +381,12 @@ impl Display for BlockSignaturesMergeError { self_chain_name_hash, other_chain_name_hash ) } + BlockSignaturesMergeError::VersionMismatch => { + write!( + formatter, + "mismatch between versions of block signatures while merging" + ) + } } } } From 84a2d911fac334c73c38846d27b29b5965b82512 Mon Sep 17 00:00:00 2001 From: Jacek Malec <145967538+jacek-casper@users.noreply.github.com> Date: Wed, 14 Feb 2024 17:00:29 +0000 Subject: [PATCH 4/7] Update storage.json --- .../storage/1.5.2/storage-1/storage_info.json | 1080 +++++++++-------- 1 file changed, 600 insertions(+), 480 deletions(-) diff --git a/resources/test/storage/1.5.2/storage-1/storage_info.json b/resources/test/storage/1.5.2/storage-1/storage_info.json index 7a038bdff9..f7065c5419 100644 --- a/resources/test/storage/1.5.2/storage-1/storage_info.json +++ b/resources/test/storage/1.5.2/storage-1/storage_info.json @@ -11,14 +11,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "a0d2b616b99812e49553852118012173bf190dcac8299be9d319773a7405e7ac", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "017bbb6f24b706b7a16c44dbe75c8fad2cd7701db361225ad296b06aa66853ece94804e8cecee76f61828ebad3422706b278da46845150265664091aaec62a890a", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01fc09409ba0e990d22eebb79bf1c85d27b2d145ee110541420a059497b9114fa17b8ab486cddbd7a927d638d61d8edff424284525638e14c0f76d3fcde225d10b", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0120f0ca080c2237c1e04470057959ff3b165e2547d8821f857fafbb238073d5327d46b587136ccf8a4733d53f0996baa11153ad25cfb97ae3a6ffb50433254a0c", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "016c5d7bfdb97e82ed4e30c39c434cbd3458e33c35c5a31800820afee42efc35fb4f37d044adf049fc82db00773ad517fe411e58cac579b7a12143b39e4d30ec09", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0154d4c6d16afb98ff1720369d741aa884a5ba785ff862a34050902e67a28d564e64b0ab26b47ab268c17a7c91853184d0b4184035faa99b4e5cab038e2f3dea0c" + "V1": { + "block_hash": "a0d2b616b99812e49553852118012173bf190dcac8299be9d319773a7405e7ac", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "017bbb6f24b706b7a16c44dbe75c8fad2cd7701db361225ad296b06aa66853ece94804e8cecee76f61828ebad3422706b278da46845150265664091aaec62a890a", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01fc09409ba0e990d22eebb79bf1c85d27b2d145ee110541420a059497b9114fa17b8ab486cddbd7a927d638d61d8edff424284525638e14c0f76d3fcde225d10b", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0120f0ca080c2237c1e04470057959ff3b165e2547d8821f857fafbb238073d5327d46b587136ccf8a4733d53f0996baa11153ad25cfb97ae3a6ffb50433254a0c", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "016c5d7bfdb97e82ed4e30c39c434cbd3458e33c35c5a31800820afee42efc35fb4f37d044adf049fc82db00773ad517fe411e58cac579b7a12143b39e4d30ec09", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0154d4c6d16afb98ff1720369d741aa884a5ba785ff862a34050902e67a28d564e64b0ab26b47ab268c17a7c91853184d0b4184035faa99b4e5cab038e2f3dea0c" + } } }, "deploy_hashes": [] @@ -28,14 +30,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "cb8148f82ff933b3653fbd63faf7c7c212bd34e1f7654364a56b129f73cdefaf", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01cb46f48eafdde8d963bd1c19e4a81935eb95865bb09613eb1994ff4fc92ab3de29acdfea42a7d3f03a7131164751512a6704fa7e9a05d4d0b3531943abfee20d", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01953d4b92fd808c0821865b29b20a52b04c1dd3857d2b12e9a33ad3baf2e12b7a9245a93b82043f96bf11f7b3dacf2176b992c74cd893bfd97a199647e50bc105", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01325850bdcc15a8b59d629d04c909f2864c1b24969ea1b6dc8c0c6d5e57b6fe1d7f92a58fd145cf076c291440807e89299a7687e8eb0c53aa0de846d7a6fc9505", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f6affd41cedaa733f855f249804563a1b7fc061a163bf1d1b9aba04a31409f2a8b50ad947f52597f046f5a2135c978608b838f871898ae0db0f221e4faee4307", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "015fcd0f05be54b0df41151bd91b8e0eabb525b4808e9c96a166298dda9233cb229b85c5f5fd5e7f91af1d525c9bb6bf7114f36223893220770c31d32f9b206302" + "V1": { + "block_hash": "cb8148f82ff933b3653fbd63faf7c7c212bd34e1f7654364a56b129f73cdefaf", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01cb46f48eafdde8d963bd1c19e4a81935eb95865bb09613eb1994ff4fc92ab3de29acdfea42a7d3f03a7131164751512a6704fa7e9a05d4d0b3531943abfee20d", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01953d4b92fd808c0821865b29b20a52b04c1dd3857d2b12e9a33ad3baf2e12b7a9245a93b82043f96bf11f7b3dacf2176b992c74cd893bfd97a199647e50bc105", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01325850bdcc15a8b59d629d04c909f2864c1b24969ea1b6dc8c0c6d5e57b6fe1d7f92a58fd145cf076c291440807e89299a7687e8eb0c53aa0de846d7a6fc9505", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f6affd41cedaa733f855f249804563a1b7fc061a163bf1d1b9aba04a31409f2a8b50ad947f52597f046f5a2135c978608b838f871898ae0db0f221e4faee4307", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "015fcd0f05be54b0df41151bd91b8e0eabb525b4808e9c96a166298dda9233cb229b85c5f5fd5e7f91af1d525c9bb6bf7114f36223893220770c31d32f9b206302" + } } }, "deploy_hashes": [] @@ -45,14 +49,16 @@ "era": 8, "approvals_hashes": null, "signatures": { - "block_hash": "1021135eeec9fa9b32bf3e06b2689f44bb9ffdb34665542c2d117b0b0a9731fb", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c1cb9ed59ea1eae441cdefc7307f451da29bde85d4f49c258edef8e4dac09209b1902aed3fb1a5321c83c883515337b010226f8682d88e61dcb7a55a1391e205", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d404d4ab96399e749e6b4c5d3b334aa8084d7b48a7e5c80705cfb7aa8b47f4c2742200425f214ed7777c0fbd4d273c7a8656b79c2812731a206010e93fe17207", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0189356a822c83edfe5e417047a67b48ffe5c045d49fa1881b4b182a5c2e046f9d68eb3907c982215f7cceca592fe39a282250c17b689caddebb5d37e857a5db08", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01568a9c0f3a5f170bb9885a25920e894103bf178812696af7194e33d1a0c50d80e56ab2497019e32dbfb81b6cdb152e4eceac304667045010e375ec053a71f00a", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01754e08049770f2952fed60192b3b6a2a65829255585be04590ef460142a4d60ca677ffd14a1dc9257675e5a841965e08fef7f35c8f294d4ea3878f55128b3309" + "V1": { + "block_hash": "1021135eeec9fa9b32bf3e06b2689f44bb9ffdb34665542c2d117b0b0a9731fb", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c1cb9ed59ea1eae441cdefc7307f451da29bde85d4f49c258edef8e4dac09209b1902aed3fb1a5321c83c883515337b010226f8682d88e61dcb7a55a1391e205", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d404d4ab96399e749e6b4c5d3b334aa8084d7b48a7e5c80705cfb7aa8b47f4c2742200425f214ed7777c0fbd4d273c7a8656b79c2812731a206010e93fe17207", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0189356a822c83edfe5e417047a67b48ffe5c045d49fa1881b4b182a5c2e046f9d68eb3907c982215f7cceca592fe39a282250c17b689caddebb5d37e857a5db08", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01568a9c0f3a5f170bb9885a25920e894103bf178812696af7194e33d1a0c50d80e56ab2497019e32dbfb81b6cdb152e4eceac304667045010e375ec053a71f00a", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01754e08049770f2952fed60192b3b6a2a65829255585be04590ef460142a4d60ca677ffd14a1dc9257675e5a841965e08fef7f35c8f294d4ea3878f55128b3309" + } } }, "deploy_hashes": [] @@ -62,14 +68,16 @@ "era": 8, "approvals_hashes": null, "signatures": { - "block_hash": "faf8913c012d445d4dc7af178d15aa8b041a3b45e63980995bd7a62da5d8673f", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0178f5aca8508cea6c6f9b22b99e5ed66c183c3c9909ffa77d29e658b0310ed58a854a11fad7789c8a4e7ddc89a342443a411f3e152bf3cbce715604db636a2205", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013ce1a805d847b5b949176c60a68dba2360536caf0583c5c20bedb7226c56c97cb5462c516b852ea801284f06005c77a4fbe3391712bfb6ab935bef6bd740610f", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "016e767114f25421c8856718447372737dfb8b967041fba6a263df12af41ec80d643c3897493757d2b7033768b02334eee786141ac128e82dae77b10d196f26407", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "013b74f945aab7f55c14d5bd5d1b72c6a901b909bb02ae96cf598ef56669d03adca45a0e841851988a2dcbe4d2425a24fc3746a5f8468245f31beaad032188ff0d", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01fc10350304daba32973ad769db4f25c19236032df95b725ee8c024aaa811ec5d296a2a34043d769562bece9a193d40cceda9f5ccfbf0a707de1dd67b779bc106" + "V1": { + "block_hash": "faf8913c012d445d4dc7af178d15aa8b041a3b45e63980995bd7a62da5d8673f", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0178f5aca8508cea6c6f9b22b99e5ed66c183c3c9909ffa77d29e658b0310ed58a854a11fad7789c8a4e7ddc89a342443a411f3e152bf3cbce715604db636a2205", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013ce1a805d847b5b949176c60a68dba2360536caf0583c5c20bedb7226c56c97cb5462c516b852ea801284f06005c77a4fbe3391712bfb6ab935bef6bd740610f", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "016e767114f25421c8856718447372737dfb8b967041fba6a263df12af41ec80d643c3897493757d2b7033768b02334eee786141ac128e82dae77b10d196f26407", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "013b74f945aab7f55c14d5bd5d1b72c6a901b909bb02ae96cf598ef56669d03adca45a0e841851988a2dcbe4d2425a24fc3746a5f8468245f31beaad032188ff0d", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01fc10350304daba32973ad769db4f25c19236032df95b725ee8c024aaa811ec5d296a2a34043d769562bece9a193d40cceda9f5ccfbf0a707de1dd67b779bc106" + } } }, "deploy_hashes": [] @@ -90,14 +98,16 @@ "78985db9f0d30a91a6f3ca643888f33a09e2d5d58a45a84e5d09012535b962f3" ], "signatures": { - "block_hash": "2d8b530265d358bd58fcf0c9b61f21d2eb308113816839a86d28a6ab11831337", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01986f42e383aa51382402f99edfdf4c43751229d4c29e8cd0cd3f47bad40baa2e1e4c5980f8408c8eda7cdd71ad41f2ae65cfc27dcbbf7697ad87499638da4709", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0177d63b478b1bfef60caba68703cf28b925a87f5b541af969e641fdc198659f5a4c75dc452ee77a86d05851facdc121fd43dccc20508b741b9a04c95e0e9ebe06", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "019ec6d148d34914a34ec0159e49d5e48f7a64f3677b9d2895d9831ce83b9d412d81debfbd683e903fc16c365684398e2fcad892d862a524fac8e93e9f0d970a09", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01d80f7bcc382e4e777256d70d2f5bf3a57872c959f70c9724ed565472171e51e08bc0a27a561f4d3f99a8b1e54f8a4c5fc7ba82891471f69b6715000ee3bc870b", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "019b4a46d9af2f49c70e6969bf02c2a63f7d0e257255e09c7444fe281efa00351376d4962ae412dcac2b8532d372603075e6e38e51f834420b5255aa0224f0a101" + "V1": { + "block_hash": "2d8b530265d358bd58fcf0c9b61f21d2eb308113816839a86d28a6ab11831337", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01986f42e383aa51382402f99edfdf4c43751229d4c29e8cd0cd3f47bad40baa2e1e4c5980f8408c8eda7cdd71ad41f2ae65cfc27dcbbf7697ad87499638da4709", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0177d63b478b1bfef60caba68703cf28b925a87f5b541af969e641fdc198659f5a4c75dc452ee77a86d05851facdc121fd43dccc20508b741b9a04c95e0e9ebe06", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "019ec6d148d34914a34ec0159e49d5e48f7a64f3677b9d2895d9831ce83b9d412d81debfbd683e903fc16c365684398e2fcad892d862a524fac8e93e9f0d970a09", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01d80f7bcc382e4e777256d70d2f5bf3a57872c959f70c9724ed565472171e51e08bc0a27a561f4d3f99a8b1e54f8a4c5fc7ba82891471f69b6715000ee3bc870b", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "019b4a46d9af2f49c70e6969bf02c2a63f7d0e257255e09c7444fe281efa00351376d4962ae412dcac2b8532d372603075e6e38e51f834420b5255aa0224f0a101" + } } }, "deploy_hashes": [ @@ -118,14 +128,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "a7e8a96a2608a249a831fc57607507f7fe6873afcf0c8af8f61ff05f5e2c8394", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01735a315b9a6ce63741e84a34b9e27e2245235eb9184573b016b5b6eb7a0038a0badbc19e709eeecd9f7ece2b26b89f00655dc5be57032ca7fc4fb33e5f29b106", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0141977992a0317989ad9b774c49a1cbf3751b402b6b32d2de48add0f8a863e61a2c1a711636a7bb609f79a830ac31cb770d0f3a2b83b186d98c1d8ac6c455ec07", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "019c8898f2368e6ce797ddf4d400526f43de91b66b6717fad9c305e3c5931e10dfad523bd154e7d6e6a3861847f4fa956746a3578f15b193ea621938acf8e4a509", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01ac6142980c8e91e26ac54634ba97390faa4501961d7a120b099cbf4184ae055ae2dc72352d371628fb84b02d1df20d1f191cacb84350941cbdf94873471a9a03", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0195bd1a586ccc900162d525ddcf6649002979b15eff3972b7ba1d3ae1369b78d9c8226910dc911f2076a636cc3502514d3dc57ba21b12020a3867755a009bf10b" + "V1": { + "block_hash": "a7e8a96a2608a249a831fc57607507f7fe6873afcf0c8af8f61ff05f5e2c8394", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01735a315b9a6ce63741e84a34b9e27e2245235eb9184573b016b5b6eb7a0038a0badbc19e709eeecd9f7ece2b26b89f00655dc5be57032ca7fc4fb33e5f29b106", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0141977992a0317989ad9b774c49a1cbf3751b402b6b32d2de48add0f8a863e61a2c1a711636a7bb609f79a830ac31cb770d0f3a2b83b186d98c1d8ac6c455ec07", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "019c8898f2368e6ce797ddf4d400526f43de91b66b6717fad9c305e3c5931e10dfad523bd154e7d6e6a3861847f4fa956746a3578f15b193ea621938acf8e4a509", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01ac6142980c8e91e26ac54634ba97390faa4501961d7a120b099cbf4184ae055ae2dc72352d371628fb84b02d1df20d1f191cacb84350941cbdf94873471a9a03", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0195bd1a586ccc900162d525ddcf6649002979b15eff3972b7ba1d3ae1369b78d9c8226910dc911f2076a636cc3502514d3dc57ba21b12020a3867755a009bf10b" + } } }, "deploy_hashes": [] @@ -135,14 +147,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "938b44fa8b62572a4820cf285f8aa3c695b03e2ebc1e6cba754523504f01831c", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01f5e877256c046b04c8f52d4346c89801b29ab02e639259f9a0fed5a8e2dc3b3ef543914fa3592356ce9b2246982615708306592409ddc70808237fc926b09f0a", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018b01cf26c7f550ce26f1ef5611d0df09da556d2611c3dcc1c4ddf5762da0c30e6374349c3206d9083fff4377537f2f79e97a7e266ddfdfe06c87ba7d326df70f", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ef1752923dedaf0a815ead66d49f2cf889fafb52542014d396a97e415768122b05cdff8f8ceb21680b350ada7004564b20a4d351fd26241c121e54f0a6c3b109", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "015068e11c1963cf5c06fc37589a348873b823228b9185146d04f9cda469578b41fe617a5ab442654437bbca398ccebf43290c1497d6f77e1b05bf166a64cb0c0c", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01eace705660fd13b1a10e6a0f03e14763acd1d4109397c07febd4a6f481ae73a26c30422cbf9418229820a9e2d5c35caac9cf2a05665e65de4fcf37a9caffef08" + "V1": { + "block_hash": "938b44fa8b62572a4820cf285f8aa3c695b03e2ebc1e6cba754523504f01831c", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01f5e877256c046b04c8f52d4346c89801b29ab02e639259f9a0fed5a8e2dc3b3ef543914fa3592356ce9b2246982615708306592409ddc70808237fc926b09f0a", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018b01cf26c7f550ce26f1ef5611d0df09da556d2611c3dcc1c4ddf5762da0c30e6374349c3206d9083fff4377537f2f79e97a7e266ddfdfe06c87ba7d326df70f", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ef1752923dedaf0a815ead66d49f2cf889fafb52542014d396a97e415768122b05cdff8f8ceb21680b350ada7004564b20a4d351fd26241c121e54f0a6c3b109", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "015068e11c1963cf5c06fc37589a348873b823228b9185146d04f9cda469578b41fe617a5ab442654437bbca398ccebf43290c1497d6f77e1b05bf166a64cb0c0c", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01eace705660fd13b1a10e6a0f03e14763acd1d4109397c07febd4a6f481ae73a26c30422cbf9418229820a9e2d5c35caac9cf2a05665e65de4fcf37a9caffef08" + } } }, "deploy_hashes": [] @@ -152,14 +166,16 @@ "era": 6, "approvals_hashes": null, "signatures": { - "block_hash": "c01371740d9b2883c92b5c519469cae84f82f6057586f33735c58f6e0db40e79", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "017230f32818eef81ef2596462de3d2a5f5cfc9d73e30c8ceb757750383e78a3da1bd5f887b71b81a862ec5a01b8e219b03df294817c873f608f3ae61b6ab93e09", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ab097d5ca951b9fc1abc56956c98456b0c704a72fe8f94775b6e4a263db67a644547d12f28b66d3eb7b36582aaee9c8ddfbf9633885fb703aeb0a2e72be8280c", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "018e374c4989aee1e44574d7d22cf07cb776f7110c3f7c9b1bdae00051f2b8fb8dc7502011048979a55a0514d9be5e800f6cb24df250aa0a297a122b69d33d6f0f", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0161529228a54d9decee38997411c5a8a2a027c2230e264a8ac58a01d6165d69a5a8ee36daa60ec380659a3d7655dc3d6846e621ad12a50a3959439130cad4150a", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01ac20ebeb1438ab507eeee56d9475a8c9fd9254fc76c3852191f0c877be362e4a86fb832c35502feb570c02642deec0ae664d2308f9bb0c2be9166d3e3e42cb0a" + "V1": { + "block_hash": "c01371740d9b2883c92b5c519469cae84f82f6057586f33735c58f6e0db40e79", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "017230f32818eef81ef2596462de3d2a5f5cfc9d73e30c8ceb757750383e78a3da1bd5f887b71b81a862ec5a01b8e219b03df294817c873f608f3ae61b6ab93e09", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ab097d5ca951b9fc1abc56956c98456b0c704a72fe8f94775b6e4a263db67a644547d12f28b66d3eb7b36582aaee9c8ddfbf9633885fb703aeb0a2e72be8280c", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "018e374c4989aee1e44574d7d22cf07cb776f7110c3f7c9b1bdae00051f2b8fb8dc7502011048979a55a0514d9be5e800f6cb24df250aa0a297a122b69d33d6f0f", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0161529228a54d9decee38997411c5a8a2a027c2230e264a8ac58a01d6165d69a5a8ee36daa60ec380659a3d7655dc3d6846e621ad12a50a3959439130cad4150a", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01ac20ebeb1438ab507eeee56d9475a8c9fd9254fc76c3852191f0c877be362e4a86fb832c35502feb570c02642deec0ae664d2308f9bb0c2be9166d3e3e42cb0a" + } } }, "deploy_hashes": [] @@ -169,14 +185,16 @@ "era": 8, "approvals_hashes": null, "signatures": { - "block_hash": "021aaf989b2159ff7c551ccab2108dec6d2b846f0c9207e9cf0667b357be5659", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01b82b9d6a43f06068d4aa0a0d7e2e1f255766c5a6cb88508a2c7460acb652b98ee8a5f04418d39c412ed29be6cf4edfe503bc71557ee62bffa7184999c652440e", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ac8e62376c5f50d2ea8bbb8af8eb482cf9e6e113d337ba9153416be5c4495e5d6c9a80be220ece312e2aec26cbfba6a3263ea3903f6b5f881d6d04d48ccf3b07", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0119db4e2beb2724955ce91715cd71e949313c0f171bdb726eae621d60f9e27df2588a0cddc4ba368bd6264b31e50ef1bdcb8ec88a84ae6af6ab6ac00a10a0a800", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "011719bb72ac094fe584d06049b4392f2ed846365153ba656d808408b6c78234cb269e63b33f64fdab1554a3069cf3e86f394a24b805cc1c91db118e9d74cf9903", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01759a3353032a34b28413e46d7267119d6e9d7f82e8a4bf90823dc7750d84d47070b18adcede5f3bb799df1560b5b47d946265c0b703f3bc9f8e6322412101c04" + "V1": { + "block_hash": "021aaf989b2159ff7c551ccab2108dec6d2b846f0c9207e9cf0667b357be5659", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01b82b9d6a43f06068d4aa0a0d7e2e1f255766c5a6cb88508a2c7460acb652b98ee8a5f04418d39c412ed29be6cf4edfe503bc71557ee62bffa7184999c652440e", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ac8e62376c5f50d2ea8bbb8af8eb482cf9e6e113d337ba9153416be5c4495e5d6c9a80be220ece312e2aec26cbfba6a3263ea3903f6b5f881d6d04d48ccf3b07", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0119db4e2beb2724955ce91715cd71e949313c0f171bdb726eae621d60f9e27df2588a0cddc4ba368bd6264b31e50ef1bdcb8ec88a84ae6af6ab6ac00a10a0a800", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "011719bb72ac094fe584d06049b4392f2ed846365153ba656d808408b6c78234cb269e63b33f64fdab1554a3069cf3e86f394a24b805cc1c91db118e9d74cf9903", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01759a3353032a34b28413e46d7267119d6e9d7f82e8a4bf90823dc7750d84d47070b18adcede5f3bb799df1560b5b47d946265c0b703f3bc9f8e6322412101c04" + } } }, "deploy_hashes": [] @@ -186,14 +204,16 @@ "era": 7, "approvals_hashes": null, "signatures": { - "block_hash": "4d050f8a53cb8e171c63a865bea6dfb25608c14c561c675fc09a863544e19415", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "015ab8f04b55a396f6e409dfaf6d228ff912a7eead71425961ea3c9bfd891056187a6ca0081947e87d58fa4cea6f99c4a1751c7638536752a12397a983049d320c", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013a71c907808ff9c27f28af23703ff3add6f8a97b5c350c711a9c7a5d3d359ceb9afcce84a48ecd065fc8ac26b9afa4f92462472e3d9afb4a8666bcb924e83103", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "017666860f8f4f90d4381edb09fcce00e029a2cd3bafecbdd7525a485d3a864404b7a8c167fafc02d88d0050b7e78ae3793d33860adae5584906d3fad15155480f", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01acb4b4cda08418052eb283ec2cb16b950e6658fe0bda574575448005e6238f46cc266219e0bfa8d4590db4f2283438c596e20817e03145e5e7da6373a2f70e0f", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01fd7f47f38b47cb2731d85a2b11147a9520c69663fcec65d6303a485317d8ccc3e1a79402048cf1210956a02facc27bf1af18b6ce2aeeeb98e0d14c5f7900fc0e" + "V1": { + "block_hash": "4d050f8a53cb8e171c63a865bea6dfb25608c14c561c675fc09a863544e19415", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "015ab8f04b55a396f6e409dfaf6d228ff912a7eead71425961ea3c9bfd891056187a6ca0081947e87d58fa4cea6f99c4a1751c7638536752a12397a983049d320c", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013a71c907808ff9c27f28af23703ff3add6f8a97b5c350c711a9c7a5d3d359ceb9afcce84a48ecd065fc8ac26b9afa4f92462472e3d9afb4a8666bcb924e83103", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "017666860f8f4f90d4381edb09fcce00e029a2cd3bafecbdd7525a485d3a864404b7a8c167fafc02d88d0050b7e78ae3793d33860adae5584906d3fad15155480f", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01acb4b4cda08418052eb283ec2cb16b950e6658fe0bda574575448005e6238f46cc266219e0bfa8d4590db4f2283438c596e20817e03145e5e7da6373a2f70e0f", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01fd7f47f38b47cb2731d85a2b11147a9520c69663fcec65d6303a485317d8ccc3e1a79402048cf1210956a02facc27bf1af18b6ce2aeeeb98e0d14c5f7900fc0e" + } } }, "deploy_hashes": [] @@ -203,14 +223,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "bb75eabb9db28f69281325959e32149faeaeebbd122df7c5157c7f2b06f80ebe", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01ab2546144a84918f9020045a663b643c248e21fb5d15fac4e242f7c159938e6b7b3b604403ebe7a85f4dee4cb6c263c6c1900e29b3451a3c3d55df017c40d70e", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01bc20e0dc59e54176b7da3351939e8dd8f4056dc1708505bc2a86be5dbf20459afcc16629aa3460ab8dbfd259a4fbd0d0a6e7b1bc72083cef12c790d119d3070a", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01e1e64bfc0685927602d2e1b46a6112a00c38316b82190518bb8302c5aeb3daf6c592e49c595e8f9f54d5d1269a201181edd34dfe400eaef3fc47d32e2b86a80c", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "014c63ade982bb75e47057ac48fd6b710f02fa174d9671e6cfb0fbfdd90e85d2e6e302e74ad3cba017a3e4fbfb9fcb17327548341b5cebde32ac1a80d5d6b3b001", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01baa09af7100c9b383668543ef9789a4989bdb0cb91a943cb605cfcbe33da7381e2f6441f503ec926fce6536ea4d8fa3469320133f73e2845c4fd0e7bc5cc5a09" + "V1": { + "block_hash": "bb75eabb9db28f69281325959e32149faeaeebbd122df7c5157c7f2b06f80ebe", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01ab2546144a84918f9020045a663b643c248e21fb5d15fac4e242f7c159938e6b7b3b604403ebe7a85f4dee4cb6c263c6c1900e29b3451a3c3d55df017c40d70e", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01bc20e0dc59e54176b7da3351939e8dd8f4056dc1708505bc2a86be5dbf20459afcc16629aa3460ab8dbfd259a4fbd0d0a6e7b1bc72083cef12c790d119d3070a", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01e1e64bfc0685927602d2e1b46a6112a00c38316b82190518bb8302c5aeb3daf6c592e49c595e8f9f54d5d1269a201181edd34dfe400eaef3fc47d32e2b86a80c", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "014c63ade982bb75e47057ac48fd6b710f02fa174d9671e6cfb0fbfdd90e85d2e6e302e74ad3cba017a3e4fbfb9fcb17327548341b5cebde32ac1a80d5d6b3b001", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01baa09af7100c9b383668543ef9789a4989bdb0cb91a943cb605cfcbe33da7381e2f6441f503ec926fce6536ea4d8fa3469320133f73e2845c4fd0e7bc5cc5a09" + } } }, "deploy_hashes": [] @@ -220,14 +242,16 @@ "era": 6, "approvals_hashes": null, "signatures": { - "block_hash": "d1d65bdbdc1fe4e7301ab4d921bc504772c3dbab47310be453bd606edf286efd", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01ec296f2a7a748b81b4773fcb253e422cbfcfca3fd1cabe95104df7f942683e2c4ad86a9fc63c6f6c59c7b04ef95276b8574dc8c71a475f60109af51342492e0f", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "014e5cc193ce3eac79bfd2f2369bdaf7a6eb748a507a4e7c5fde0b1a6b6f05267a3df285f40d44c3c4753af2ab7c7f88cada326fb85c413f5ad506d29f8053a40d", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0132b18719d4d9b64ca4e92af2e0fa47562af672e7c017e9256dfb784e31cc8195ef410fb31bf1a05adcf5f029e3b1bee6634c5c4f80d383afad09512156f7560b", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0157d8d02e9f4f619bc0a8a95f3bc61cc6521b744263b31889f6da4fdb3ffadb033e57ced766e231d0bbbdc7e3ba9ef662ea1f14cbd85dea9f6f0f058e1d943607", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "013ae0332623ebd4c86ba3c087ef2c68e9ae08e851afd56557398d33cee5e39391ff8b879cdf815de544d6df7e703522e1006040880a9893a1c7f53e873e3c0f00" + "V1": { + "block_hash": "d1d65bdbdc1fe4e7301ab4d921bc504772c3dbab47310be453bd606edf286efd", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01ec296f2a7a748b81b4773fcb253e422cbfcfca3fd1cabe95104df7f942683e2c4ad86a9fc63c6f6c59c7b04ef95276b8574dc8c71a475f60109af51342492e0f", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "014e5cc193ce3eac79bfd2f2369bdaf7a6eb748a507a4e7c5fde0b1a6b6f05267a3df285f40d44c3c4753af2ab7c7f88cada326fb85c413f5ad506d29f8053a40d", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0132b18719d4d9b64ca4e92af2e0fa47562af672e7c017e9256dfb784e31cc8195ef410fb31bf1a05adcf5f029e3b1bee6634c5c4f80d383afad09512156f7560b", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0157d8d02e9f4f619bc0a8a95f3bc61cc6521b744263b31889f6da4fdb3ffadb033e57ced766e231d0bbbdc7e3ba9ef662ea1f14cbd85dea9f6f0f058e1d943607", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "013ae0332623ebd4c86ba3c087ef2c68e9ae08e851afd56557398d33cee5e39391ff8b879cdf815de544d6df7e703522e1006040880a9893a1c7f53e873e3c0f00" + } } }, "deploy_hashes": [] @@ -237,14 +261,16 @@ "era": 7, "approvals_hashes": null, "signatures": { - "block_hash": "20855b7a61e36df78070a1b697b8b187b20efc49ecf450554283e384ff0e5902", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01603fde1ea29deb3a5e35bc20c1544ffc5fbd8f58e6a0b4ad9a738ccae97274b023d6ea40cdc177f1ddfa8d10e0ec6c6645e8d854c36408e51b8229df48bfa50e", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01122abfa228c75a8b1bd71099678eacb2f8cc62cf95121ff058076bd0da5ccced23332e7426dad453a6305e44c1ca4c294a5086a1f0da267a21534bba51a8650d", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01bab63348e6be0f65c9af7d6b9ab92cca90779b9960818c908667e79508a065d87cf13ced784a43fc716bc8973e28a40d65a98c23cbe3ab3caedafd970bdf290d", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01768af65f974975528b23eae96a5f7739b806d32e56e6509057e9b0d96f089ad80d6e719d4367cafb6aeb5c8e05b5e1d211b52fde31092e04e363ac8242ba010e", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "012eae04c947c8c3335d5542c33da1f93a2202fdb03aeae04ce30d28393ad7f94f80a5d164f1370126b80b7a3d26cf213b5c0940a50cc6e2f0f58198231b02fa07" + "V1": { + "block_hash": "20855b7a61e36df78070a1b697b8b187b20efc49ecf450554283e384ff0e5902", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01603fde1ea29deb3a5e35bc20c1544ffc5fbd8f58e6a0b4ad9a738ccae97274b023d6ea40cdc177f1ddfa8d10e0ec6c6645e8d854c36408e51b8229df48bfa50e", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01122abfa228c75a8b1bd71099678eacb2f8cc62cf95121ff058076bd0da5ccced23332e7426dad453a6305e44c1ca4c294a5086a1f0da267a21534bba51a8650d", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01bab63348e6be0f65c9af7d6b9ab92cca90779b9960818c908667e79508a065d87cf13ced784a43fc716bc8973e28a40d65a98c23cbe3ab3caedafd970bdf290d", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01768af65f974975528b23eae96a5f7739b806d32e56e6509057e9b0d96f089ad80d6e719d4367cafb6aeb5c8e05b5e1d211b52fde31092e04e363ac8242ba010e", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "012eae04c947c8c3335d5542c33da1f93a2202fdb03aeae04ce30d28393ad7f94f80a5d164f1370126b80b7a3d26cf213b5c0940a50cc6e2f0f58198231b02fa07" + } } }, "deploy_hashes": [] @@ -254,14 +280,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "ddb95006ea8d3293555af637f0fde53e5d14f6b8b9c61d1c433155af734d6498", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "014d867980ef65c933c3e4e6b50dfd2e83223530b5d6eac8650daf2079e00eda0fce2dc222c7d3fb50bac6098dd20b208bcf424ab88c2c3aa2d73d20ab228a3909", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a2b3aaba8ed701ef46ec55e0b8c5e7b35a8f980497025238687b2129b80cb3198c3195c7d21913f72b234728a5e9698b073c0f0b26062df2d62161c8f41e9606", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "015dc3a199f4998b3edd8b32d8c432bd2efd149425781b5a6892e9a5d51ed9e9f23b4538c2685d8c304c3ff3e953b7b038b68ef950309bbc9e99391fee626bee0e", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "019885590c89a861bf6f05fd00b2821f940b8442a9a50eb808bd8d1149791ef76200680c8afa1e68889fcf47d180949949309a1ba3b15cc1c4d6a865f937e22a0b", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "018a70d0003eba0f4a99bc1d22113e0d25877e9ae0f090617458e9b069c93d3a27f003265517b04f984139d3d207c4e641e32289359c8bf1e5f0c256f65c29c005" + "V1": { + "block_hash": "ddb95006ea8d3293555af637f0fde53e5d14f6b8b9c61d1c433155af734d6498", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "014d867980ef65c933c3e4e6b50dfd2e83223530b5d6eac8650daf2079e00eda0fce2dc222c7d3fb50bac6098dd20b208bcf424ab88c2c3aa2d73d20ab228a3909", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a2b3aaba8ed701ef46ec55e0b8c5e7b35a8f980497025238687b2129b80cb3198c3195c7d21913f72b234728a5e9698b073c0f0b26062df2d62161c8f41e9606", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "015dc3a199f4998b3edd8b32d8c432bd2efd149425781b5a6892e9a5d51ed9e9f23b4538c2685d8c304c3ff3e953b7b038b68ef950309bbc9e99391fee626bee0e", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "019885590c89a861bf6f05fd00b2821f940b8442a9a50eb808bd8d1149791ef76200680c8afa1e68889fcf47d180949949309a1ba3b15cc1c4d6a865f937e22a0b", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "018a70d0003eba0f4a99bc1d22113e0d25877e9ae0f090617458e9b069c93d3a27f003265517b04f984139d3d207c4e641e32289359c8bf1e5f0c256f65c29c005" + } } }, "deploy_hashes": [] @@ -271,14 +299,16 @@ "era": 6, "approvals_hashes": null, "signatures": { - "block_hash": "42a656756c7b5bbfcdf32db19cf177361e9c0a6705a16a0d494e320175f09224", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0173857a991249ccb028f8cb1f52324b4bb5a67ef3a3a60f6e7df61086c5ea8956519a288133d024cd76ab9b0bcd3958f85b26001322f9714d3159e1288fea7d0b", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a0f04275b62ae0a12982c9b86785f71d4567c6f44f6757b7dbbb9b932cf00c8ea6e4c3131b81380d29b5fd91e25695c77f198ce8c397c103695aca73faf97f0c", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01e2170db2b4270bbd43861eeaad31bc76c1b4099f3d6ec827b15575d65f6f933d6bcd2a303396ae0bb617632dc00a89698c63dc280f689943aaefdc5782111009", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01725c203217ba1e454dbbcca334604a1df68f416169fd566d1d0e8821a066e39098236b43cb1a77d8f3a1b447287400dcaf3d5beddcba4c8f2e2fe222c63feb0a", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01375999d63755c55b80bcd79c3647fa9e52f945b2824ce848e5094d439455765876c66b88b641c26622b649009ee41722746b26dd024d55bfcffc497ccc312304" + "V1": { + "block_hash": "42a656756c7b5bbfcdf32db19cf177361e9c0a6705a16a0d494e320175f09224", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0173857a991249ccb028f8cb1f52324b4bb5a67ef3a3a60f6e7df61086c5ea8956519a288133d024cd76ab9b0bcd3958f85b26001322f9714d3159e1288fea7d0b", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a0f04275b62ae0a12982c9b86785f71d4567c6f44f6757b7dbbb9b932cf00c8ea6e4c3131b81380d29b5fd91e25695c77f198ce8c397c103695aca73faf97f0c", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01e2170db2b4270bbd43861eeaad31bc76c1b4099f3d6ec827b15575d65f6f933d6bcd2a303396ae0bb617632dc00a89698c63dc280f689943aaefdc5782111009", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01725c203217ba1e454dbbcca334604a1df68f416169fd566d1d0e8821a066e39098236b43cb1a77d8f3a1b447287400dcaf3d5beddcba4c8f2e2fe222c63feb0a", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01375999d63755c55b80bcd79c3647fa9e52f945b2824ce848e5094d439455765876c66b88b641c26622b649009ee41722746b26dd024d55bfcffc497ccc312304" + } } }, "deploy_hashes": [] @@ -288,14 +318,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "4013cc057d7774fd5aaef3e8062d3cf3786cb094d7109ebfce2d5f86903ec736", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0160c30d9f4d76b1fa89f3f130afbd930953921931daae3dea5053adba02a9203b9542a586061c798be54d017bae4c51dcd675389a14ccdb00694236d599cdb507", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01bb81d1b641fc92acce550af000f764563fa553c71079aa66be8511d42da68892506c64257a3147427908bfc6398243c92856c8ee965c92e63924b7503f7a000f", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01500a006a8fcf834465929d0f60f4f38ee2212f5f6b98c92afe2ff39329050e973ded4afff955f853301b12cb4e7c6c3cf174d904cefc8b1d704a11dc16ad3e0a", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "016c66db6b6b65e87bef11e4b8284b7f30a62f6080e0303fd79669f1e4a0be83a0133248062ec7fab1c166d0c7de33a5eec9093681fac72253d4422517bde88a0f", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0164d80fe439397439efac06962f3233bdffd4bd2620af6eb42c34c7388d52d8e4b1f8499ff185a4fa58ebdc9b54d57a255d8bd903ed5c0d7f7bbaccb04dcbdd0b" + "V1": { + "block_hash": "4013cc057d7774fd5aaef3e8062d3cf3786cb094d7109ebfce2d5f86903ec736", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0160c30d9f4d76b1fa89f3f130afbd930953921931daae3dea5053adba02a9203b9542a586061c798be54d017bae4c51dcd675389a14ccdb00694236d599cdb507", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01bb81d1b641fc92acce550af000f764563fa553c71079aa66be8511d42da68892506c64257a3147427908bfc6398243c92856c8ee965c92e63924b7503f7a000f", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01500a006a8fcf834465929d0f60f4f38ee2212f5f6b98c92afe2ff39329050e973ded4afff955f853301b12cb4e7c6c3cf174d904cefc8b1d704a11dc16ad3e0a", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "016c66db6b6b65e87bef11e4b8284b7f30a62f6080e0303fd79669f1e4a0be83a0133248062ec7fab1c166d0c7de33a5eec9093681fac72253d4422517bde88a0f", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0164d80fe439397439efac06962f3233bdffd4bd2620af6eb42c34c7388d52d8e4b1f8499ff185a4fa58ebdc9b54d57a255d8bd903ed5c0d7f7bbaccb04dcbdd0b" + } } }, "deploy_hashes": [] @@ -305,14 +337,16 @@ "era": 6, "approvals_hashes": null, "signatures": { - "block_hash": "1bbba85fdaa53289c5a5ef5a10e264aecfc23b2cf385883c38f0afeb3430bfc2", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0137c87dfc36d74d40e3454751acc46d95cbb8501cf892024ceee50455681a4368815d99a7d5a924ce8cf551be8c57d980e69d101a9559f305621aa733294ce200", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d7ba75b022046120ca777a9bb07d6b12d5be56738f1e63a83f8d529c1e352adc3bd66ec2611e83895cfccbfe0526b088de6fc1f44dcb70c9f111126f89335903", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f317117ff091da876d47f9e836e3e716725fd41a5ace99a91903807fe0424056aa0ba43aea4bfdd1ffb39b18fc3ed262b88a0b4c099d867d26060c956c03c404", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0105c51cfa823470fe3527c6836295b04e97499a4ca9789b77c9cc8131136245311794d085f7226c362876f8c68a731c96fc9feaaebe511072ad5119c7e3293e0a", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01ad671b04cd47e3a57dcd42d0be5a630b6e67f6f796998f6b72cb19f948911cf61ae4b0cc7283b683cd9f22edf5bbe6f3f84022cebb8d6a8c688ef23f9001690e" + "V1": { + "block_hash": "1bbba85fdaa53289c5a5ef5a10e264aecfc23b2cf385883c38f0afeb3430bfc2", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0137c87dfc36d74d40e3454751acc46d95cbb8501cf892024ceee50455681a4368815d99a7d5a924ce8cf551be8c57d980e69d101a9559f305621aa733294ce200", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d7ba75b022046120ca777a9bb07d6b12d5be56738f1e63a83f8d529c1e352adc3bd66ec2611e83895cfccbfe0526b088de6fc1f44dcb70c9f111126f89335903", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f317117ff091da876d47f9e836e3e716725fd41a5ace99a91903807fe0424056aa0ba43aea4bfdd1ffb39b18fc3ed262b88a0b4c099d867d26060c956c03c404", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0105c51cfa823470fe3527c6836295b04e97499a4ca9789b77c9cc8131136245311794d085f7226c362876f8c68a731c96fc9feaaebe511072ad5119c7e3293e0a", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01ad671b04cd47e3a57dcd42d0be5a630b6e67f6f796998f6b72cb19f948911cf61ae4b0cc7283b683cd9f22edf5bbe6f3f84022cebb8d6a8c688ef23f9001690e" + } } }, "deploy_hashes": [] @@ -322,14 +356,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "5d27c40448a47e4dea45466443471a7782c0a562124bf7a153ec54e90271f20c", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01fe941f1c097daf47b2713344f452bcfe348a6efde20bf12235f0da754973c1dcf1107151990b14597c9bcce46e2058b0867bf06e5b1a6d12e9855f645c99170f", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013760f3af9afe14eaef1327b6d7d1c021e29fb9a6d17f9592fced143a1bda881d7a273c76174ad83105ea0e314cf46351e19dd9e8fe4f8e4b5e7815be38c0c90d", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01b10ae47b777786bb666a137ba4fd027ac31b8ca005eaa0ec5518346f24f1b5148e35f899593ad6a24132cff3a2fd1e1983eac6bb25e747067464dc2d93062205", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01894ec9959620928f5799d796c38ad1d2000f6e9a6f6dbcfd38351d6b6464ec21f76442f8774f1bf368914be0e967c2be4b991443eae3de3d5df60807dc826600", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "015027a55452e3ac79c60cf9a4baf581631351f7dd9761a52256fdec17c15c1a42901d40814fdc2379b79220c3995337d887048d3035549dc9ad14c631949cdb06" + "V1": { + "block_hash": "5d27c40448a47e4dea45466443471a7782c0a562124bf7a153ec54e90271f20c", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01fe941f1c097daf47b2713344f452bcfe348a6efde20bf12235f0da754973c1dcf1107151990b14597c9bcce46e2058b0867bf06e5b1a6d12e9855f645c99170f", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013760f3af9afe14eaef1327b6d7d1c021e29fb9a6d17f9592fced143a1bda881d7a273c76174ad83105ea0e314cf46351e19dd9e8fe4f8e4b5e7815be38c0c90d", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01b10ae47b777786bb666a137ba4fd027ac31b8ca005eaa0ec5518346f24f1b5148e35f899593ad6a24132cff3a2fd1e1983eac6bb25e747067464dc2d93062205", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01894ec9959620928f5799d796c38ad1d2000f6e9a6f6dbcfd38351d6b6464ec21f76442f8774f1bf368914be0e967c2be4b991443eae3de3d5df60807dc826600", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "015027a55452e3ac79c60cf9a4baf581631351f7dd9761a52256fdec17c15c1a42901d40814fdc2379b79220c3995337d887048d3035549dc9ad14c631949cdb06" + } } }, "deploy_hashes": [] @@ -339,14 +375,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "63a250af208974b970f7c2328bfab4aa3740023b43d29ca34012ea6afe585ca7", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01850a1fba8ea4a524cad7239db5a7de0360f899d54f5dea1cec06d8a3071eb95f49a9758deb9649118576405c323b0c95d8b736adf9102baed075a0d5bf623408", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "010055bd55638a89aa31b7e67cb0966bd6b13dd38677f9ba9cb4d5ff74061d4c9f792dc044df008d7dab9b6ef83f706d1bb6c70481e9b00ac16827c11a334e3a05", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "011a3864d9e55d38771119cb8bae3f645528bb5fe8231bf67c7b6bc6b7915c18227041a8307190e7250ebc95b20a2a645294484a4032c65380525f7f7258f38b0f", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01d141af946b2d80b91f0a3f42a599023713934329e15573b0df41e2fe7691049214780b23c72a75f54a9e04d4f6e11654c50475b195de1efd02c3ec62c875ea06", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01ceb94402ce8a411b40e7ed0be769cc2c56261965fdfea963a1c06ca6c6499e49fd706313c534740ad46add89f4b89b6bce3119733ab58b7ad7c7c6c56643b103" + "V1": { + "block_hash": "63a250af208974b970f7c2328bfab4aa3740023b43d29ca34012ea6afe585ca7", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01850a1fba8ea4a524cad7239db5a7de0360f899d54f5dea1cec06d8a3071eb95f49a9758deb9649118576405c323b0c95d8b736adf9102baed075a0d5bf623408", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "010055bd55638a89aa31b7e67cb0966bd6b13dd38677f9ba9cb4d5ff74061d4c9f792dc044df008d7dab9b6ef83f706d1bb6c70481e9b00ac16827c11a334e3a05", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "011a3864d9e55d38771119cb8bae3f645528bb5fe8231bf67c7b6bc6b7915c18227041a8307190e7250ebc95b20a2a645294484a4032c65380525f7f7258f38b0f", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01d141af946b2d80b91f0a3f42a599023713934329e15573b0df41e2fe7691049214780b23c72a75f54a9e04d4f6e11654c50475b195de1efd02c3ec62c875ea06", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01ceb94402ce8a411b40e7ed0be769cc2c56261965fdfea963a1c06ca6c6499e49fd706313c534740ad46add89f4b89b6bce3119733ab58b7ad7c7c6c56643b103" + } } }, "deploy_hashes": [] @@ -356,14 +394,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "774bb86933d8150611299b63e4e8b6a3d38c074dd3867f4b66acfa91f903c9fc", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "011f7e0806092aea798b88e1ba3d37064c95cbdc3859376f4fd547b13789af4f7f3dd9c986493fd54a79fdacadab767779e6d209111b54c73bfa7e3f6923bee102", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01450fc312565737a0dfc1ac94ab7a38d778a7255233642448f3165b299e0b3710a855cb45156638de7c95c09b3c7d629813414fba8c944bec5a0cfcfa5753d90e", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ccd464f69ef99cf714011427c62ceeb2e5ec46b03ca26b13298117377a9c5b17c79c498d44572cf4f911ee196a6560ec7d4652808268a92bc7fab706939f5d07", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0178ad515b357cc1475759362c718fda98c774c962eeefb41147518193575f852cd62b48e3e4b5186db55b0a5db52f2502bd84f9f9007ba6f02e520ab67fcc130c", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01353b0a9e972ea1c5c644966a30d07c89ad11395ddd0a2dbe008c1fee8d6a8803a1cb66e50e90eb6fb774aebff644f49d9b28eb3c7958b66fc522ba5fec172e04" + "V1": { + "block_hash": "774bb86933d8150611299b63e4e8b6a3d38c074dd3867f4b66acfa91f903c9fc", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "011f7e0806092aea798b88e1ba3d37064c95cbdc3859376f4fd547b13789af4f7f3dd9c986493fd54a79fdacadab767779e6d209111b54c73bfa7e3f6923bee102", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01450fc312565737a0dfc1ac94ab7a38d778a7255233642448f3165b299e0b3710a855cb45156638de7c95c09b3c7d629813414fba8c944bec5a0cfcfa5753d90e", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ccd464f69ef99cf714011427c62ceeb2e5ec46b03ca26b13298117377a9c5b17c79c498d44572cf4f911ee196a6560ec7d4652808268a92bc7fab706939f5d07", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0178ad515b357cc1475759362c718fda98c774c962eeefb41147518193575f852cd62b48e3e4b5186db55b0a5db52f2502bd84f9f9007ba6f02e520ab67fcc130c", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01353b0a9e972ea1c5c644966a30d07c89ad11395ddd0a2dbe008c1fee8d6a8803a1cb66e50e90eb6fb774aebff644f49d9b28eb3c7958b66fc522ba5fec172e04" + } } }, "deploy_hashes": [] @@ -373,14 +413,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "2d890cf5edce165cf1362bc54bb8e4b14e9a3a42f412980d9cf5f688ab7ed431", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018acfc82599e1947af1f45403226cfc3e27d11243bf372ef4ed99290bab7de2e2719f0df7427c73cc76c67f96279503f7a2cf28643d5907dff3c55369e96e1103", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01fbde4d5d3d57828919d518de6cab2650860a4aee8c651ea841e280233014c56a9bd01b43e2b7b04e8a6daf6b9994ca24b699a0feb62365263a51d7b6a3c6570b", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01177c37af6d7db73303f6b4bcb0f7cabb801e6e83520eba88511fc82dc92d28fb2e99af7f5787bf4131603ef92ef09806e96c710e322572566e33aae5e4706502", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "012c9cf741bca2447c8b31bae1f23c12d354c46bcde06114d7b5dfb138dfe497bf32aefe6547835c3bf5ab34203828433d3c49ed822ea8cab64f738fe298d51d0f", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01e788ff68add1ec4ba30ad2473a1e1914f49145069baf70b727ab3d85f1870196fc61347d4e763d41dbc4e84f958f7343149704b9c022893d4e043a51e536a30e" + "V1": { + "block_hash": "2d890cf5edce165cf1362bc54bb8e4b14e9a3a42f412980d9cf5f688ab7ed431", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018acfc82599e1947af1f45403226cfc3e27d11243bf372ef4ed99290bab7de2e2719f0df7427c73cc76c67f96279503f7a2cf28643d5907dff3c55369e96e1103", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01fbde4d5d3d57828919d518de6cab2650860a4aee8c651ea841e280233014c56a9bd01b43e2b7b04e8a6daf6b9994ca24b699a0feb62365263a51d7b6a3c6570b", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01177c37af6d7db73303f6b4bcb0f7cabb801e6e83520eba88511fc82dc92d28fb2e99af7f5787bf4131603ef92ef09806e96c710e322572566e33aae5e4706502", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "012c9cf741bca2447c8b31bae1f23c12d354c46bcde06114d7b5dfb138dfe497bf32aefe6547835c3bf5ab34203828433d3c49ed822ea8cab64f738fe298d51d0f", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01e788ff68add1ec4ba30ad2473a1e1914f49145069baf70b727ab3d85f1870196fc61347d4e763d41dbc4e84f958f7343149704b9c022893d4e043a51e536a30e" + } } }, "deploy_hashes": [] @@ -390,14 +432,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "a7099f4d3a5735ec54e833b0dab9d2f38e02bfbbfd8bbf00d3d4f59bd62e1ba3", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01600ce47d211a19cd35d543e960351f55c36cea88d414500da0aebeefec27a829049cac0c52aae955b9d44dc8d94c3f984b379c06ff4365a062c96bf269238104", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ba1784f771ef81b9d5240291e4ac119e080d779b1c1a6298405b26a30bac98330c08ebded884d38abf969fd9c31d4a85d9b0fce19a244bf68b3d9d8693cf3d0f", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01b18d572138b3617b3109d4a0023e8cd9f8f21b565daefcdc8a4b4f628a528af78543f46030e617510f8d922d5031d9b93574c0bacaec8929b1b0c8d3c5006a0d", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01100026f933d94a640238e4fd855ff863c3a38a7e2641deac6684aad30a5c3152236cd8a8111c310ac412a22dbcb62e02e24343b7567da67aadaf74a360d62f02", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0118037852b59d1ec371b72d76cd8c5cdad48eb80c129da9b5a318a6ab8016d10db39d4d5348280bc2edab04562c5c900f316ddd60cf9a8a5863087e6054fc5c05" + "V1": { + "block_hash": "a7099f4d3a5735ec54e833b0dab9d2f38e02bfbbfd8bbf00d3d4f59bd62e1ba3", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01600ce47d211a19cd35d543e960351f55c36cea88d414500da0aebeefec27a829049cac0c52aae955b9d44dc8d94c3f984b379c06ff4365a062c96bf269238104", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ba1784f771ef81b9d5240291e4ac119e080d779b1c1a6298405b26a30bac98330c08ebded884d38abf969fd9c31d4a85d9b0fce19a244bf68b3d9d8693cf3d0f", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01b18d572138b3617b3109d4a0023e8cd9f8f21b565daefcdc8a4b4f628a528af78543f46030e617510f8d922d5031d9b93574c0bacaec8929b1b0c8d3c5006a0d", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01100026f933d94a640238e4fd855ff863c3a38a7e2641deac6684aad30a5c3152236cd8a8111c310ac412a22dbcb62e02e24343b7567da67aadaf74a360d62f02", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0118037852b59d1ec371b72d76cd8c5cdad48eb80c129da9b5a318a6ab8016d10db39d4d5348280bc2edab04562c5c900f316ddd60cf9a8a5863087e6054fc5c05" + } } }, "deploy_hashes": [] @@ -407,14 +451,16 @@ "era": 8, "approvals_hashes": null, "signatures": { - "block_hash": "cac38102cd15c1e21fea483838849d63d8b3510045f759a6b8a020e1286b1416", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01853926a0fb42bcb00a01e4df9e7584e1db64363a4ef6d859e3a5d073e9164f819667201f920e9ecb39daf9b05ccb41ce6a829b12d50d800a042e0d1dc718f402", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d881f0de6381836da827f110f01b7a17c34a62c588abb0c066fbfc687a5704418d778fb37527fd9bfa73ba76dca33f5f5ba966b087d340a9a792ed88182fe005", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ca0ca0c7f0dade288f21449ab4bf242e227cd8165f60c21949198f8142d98284240d6134f26cdba9dde60aee3c3a017f71470fd0632f8283e25de82cbd3fa108", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "011a92c7a2c0daf8b15a71cfc8adc0401a5b071df843fd725a5bf66051cf02e3c8df4b60ae56dc091a2049e1a8f9e8cd51116f851264109efcc081c9d9b06bc400", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01940c4473f9845daff31c33ac9c3165110cecff7d58911816faa3643f2965f9e31f79995b475c501d69cae782bdfd1f1ed66b51ff64188de83a4fd3213a877e00" + "V1": { + "block_hash": "cac38102cd15c1e21fea483838849d63d8b3510045f759a6b8a020e1286b1416", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01853926a0fb42bcb00a01e4df9e7584e1db64363a4ef6d859e3a5d073e9164f819667201f920e9ecb39daf9b05ccb41ce6a829b12d50d800a042e0d1dc718f402", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d881f0de6381836da827f110f01b7a17c34a62c588abb0c066fbfc687a5704418d778fb37527fd9bfa73ba76dca33f5f5ba966b087d340a9a792ed88182fe005", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ca0ca0c7f0dade288f21449ab4bf242e227cd8165f60c21949198f8142d98284240d6134f26cdba9dde60aee3c3a017f71470fd0632f8283e25de82cbd3fa108", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "011a92c7a2c0daf8b15a71cfc8adc0401a5b071df843fd725a5bf66051cf02e3c8df4b60ae56dc091a2049e1a8f9e8cd51116f851264109efcc081c9d9b06bc400", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01940c4473f9845daff31c33ac9c3165110cecff7d58911816faa3643f2965f9e31f79995b475c501d69cae782bdfd1f1ed66b51ff64188de83a4fd3213a877e00" + } } }, "deploy_hashes": [] @@ -424,14 +470,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "8813bc48aab46912eb829f5d8c4d0b1803c3be64e2fe6feab5d7b5a7c10b03fa", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c168ebc69fa7514b8c206ac889ba92877fe4223f1665360815dcca4ae958bb488bcc43d2401829555a0eee623732add264bdd36ce0c6356b492c024c3d64b905", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ce66ce24e35a47e834f780f8cd1223bc1929e48bac474efc4a6c12adbbaa401656f7e8ed2df1806220a464979ac5c9b7fc4e4e2494d595b666941a2a40003b04", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01bb83f0fb82cda0243c0bad4e517dbaf97502e482eeb38bbd5655e71508983dc55078a7bd1738c342c20fe41932ee0e352a95de4923b87a5648ab823c5cd0a106", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01ea32550e0f59532718629577bac54e50e23124dc128dd30b93ce18cb13add5ba55c483b2bb56bb34aeded9c8f777451cc563d56d71370ef728180cad11cc5705", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "019d1e480814b691626f18759e9db54b66e594d2b6ad1d3870b6b1e487877e5d9426b87f68bb4d86e258f6decf30c32fb8896051c716726120a59a4e45656b0906" + "V1": { + "block_hash": "8813bc48aab46912eb829f5d8c4d0b1803c3be64e2fe6feab5d7b5a7c10b03fa", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c168ebc69fa7514b8c206ac889ba92877fe4223f1665360815dcca4ae958bb488bcc43d2401829555a0eee623732add264bdd36ce0c6356b492c024c3d64b905", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ce66ce24e35a47e834f780f8cd1223bc1929e48bac474efc4a6c12adbbaa401656f7e8ed2df1806220a464979ac5c9b7fc4e4e2494d595b666941a2a40003b04", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01bb83f0fb82cda0243c0bad4e517dbaf97502e482eeb38bbd5655e71508983dc55078a7bd1738c342c20fe41932ee0e352a95de4923b87a5648ab823c5cd0a106", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01ea32550e0f59532718629577bac54e50e23124dc128dd30b93ce18cb13add5ba55c483b2bb56bb34aeded9c8f777451cc563d56d71370ef728180cad11cc5705", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "019d1e480814b691626f18759e9db54b66e594d2b6ad1d3870b6b1e487877e5d9426b87f68bb4d86e258f6decf30c32fb8896051c716726120a59a4e45656b0906" + } } }, "deploy_hashes": [] @@ -441,14 +489,16 @@ "era": 4, "approvals_hashes": null, "signatures": { - "block_hash": "945da24b9d3ea9dcc6272a6b4bb5902f3d420950a24bab1cb8bfd83a2bb04431", - "era_id": 4, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01fc1b2e5e932457f0442aa46a1ab1217ae6f8a9d67526276cfd22515960b94e696a9be191fe41aca5f4e939c7c7ab9201ce09457d077da8bfd75bbd9b0d01e102", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01cee51ed263f70fb33d95490cd51838bc049c215c83067fa95bb345f0ffc1a0b2774ba4ed7c9f68e69010702f4007766b12a7fcb556acbf2fa2dcad165da6f608", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f4d6df04b1c154cc18213ad42e0e10990b0ddbecc100673f07ed0b09a27ae84e88d5d1b2b223bc6bd3ccb779d1c6096bc837f8ac40522c4773bbe916bc4b870f", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01482bd61421bd6a6728a3197c70de900ce34915796f515ac2782a41c6026bd9ade2d0ee9b8e3a48cc395236f48f043260dd2541ad1079be63aa557d639af0490b", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "012b1cdbea5b8c9325218264e82c6883aa18724de24b4c87fcbce8a34a240520db70e3d388b39cf01de6bd1511680a5f19ddf47bb2cad440b0cdd9adbda98ca907" + "V1": { + "block_hash": "945da24b9d3ea9dcc6272a6b4bb5902f3d420950a24bab1cb8bfd83a2bb04431", + "era_id": 4, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01fc1b2e5e932457f0442aa46a1ab1217ae6f8a9d67526276cfd22515960b94e696a9be191fe41aca5f4e939c7c7ab9201ce09457d077da8bfd75bbd9b0d01e102", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01cee51ed263f70fb33d95490cd51838bc049c215c83067fa95bb345f0ffc1a0b2774ba4ed7c9f68e69010702f4007766b12a7fcb556acbf2fa2dcad165da6f608", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f4d6df04b1c154cc18213ad42e0e10990b0ddbecc100673f07ed0b09a27ae84e88d5d1b2b223bc6bd3ccb779d1c6096bc837f8ac40522c4773bbe916bc4b870f", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01482bd61421bd6a6728a3197c70de900ce34915796f515ac2782a41c6026bd9ade2d0ee9b8e3a48cc395236f48f043260dd2541ad1079be63aa557d639af0490b", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "012b1cdbea5b8c9325218264e82c6883aa18724de24b4c87fcbce8a34a240520db70e3d388b39cf01de6bd1511680a5f19ddf47bb2cad440b0cdd9adbda98ca907" + } } }, "deploy_hashes": [] @@ -458,14 +508,16 @@ "era": 7, "approvals_hashes": null, "signatures": { - "block_hash": "f620ad616351b9dcb82ca5fb430db0d11aed4328e6be83382b27ff5157500b78", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01138febb7d549d35448dfa542d7aec5da50ca025b9f4f503e875198ce097b67d3c1e43877fde83e74a50c6097c3e7e6eba4dcc6a60104cc9f998f8b2c2a557f07", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d4982bc2d7ab129dd6192d6ea54292b1c783f08f46fae7c3c4a75344f220113693a44395e6d1ac76c2c41a5ff4f78084e94d5419413f8494eae22402afa6f503", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ec9ee13ff765d09d6c490c2e52959a94f5b02398303610851e60205b3d07dee8c61e4f907ed5e7fe091fc4c0b557c2484e77dbce68d4d9a164d6ac239068ec08", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f7961cef7d6c84414783e36e80e11c1944667b9b9eb68962203db212ecca702367e3a1554d450cbfe40b9fec97dfb8698d658f6cd20b6e792576ff2cd197b80d", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "014219be42f2b95b5110c6aa038a70b885fec984f5ad6ffc2a2611571c6685b46fcea00c3f2868492aa73b2e6b6129ddf84ea1f8dab889d69e433f888c7faeb10f" + "V1": { + "block_hash": "f620ad616351b9dcb82ca5fb430db0d11aed4328e6be83382b27ff5157500b78", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01138febb7d549d35448dfa542d7aec5da50ca025b9f4f503e875198ce097b67d3c1e43877fde83e74a50c6097c3e7e6eba4dcc6a60104cc9f998f8b2c2a557f07", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d4982bc2d7ab129dd6192d6ea54292b1c783f08f46fae7c3c4a75344f220113693a44395e6d1ac76c2c41a5ff4f78084e94d5419413f8494eae22402afa6f503", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ec9ee13ff765d09d6c490c2e52959a94f5b02398303610851e60205b3d07dee8c61e4f907ed5e7fe091fc4c0b557c2484e77dbce68d4d9a164d6ac239068ec08", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f7961cef7d6c84414783e36e80e11c1944667b9b9eb68962203db212ecca702367e3a1554d450cbfe40b9fec97dfb8698d658f6cd20b6e792576ff2cd197b80d", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "014219be42f2b95b5110c6aa038a70b885fec984f5ad6ffc2a2611571c6685b46fcea00c3f2868492aa73b2e6b6129ddf84ea1f8dab889d69e433f888c7faeb10f" + } } }, "deploy_hashes": [] @@ -475,14 +527,16 @@ "era": 4, "approvals_hashes": null, "signatures": { - "block_hash": "0665324472c593720b2a5cb9c81f2ec6a40401a7c22396addb1ddca4a8d56292", - "era_id": 4, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01eff1532f2df9481408adf43453e5bb88823eb8f297a6b35001099225cd95035a18fcbe5e0508d6829245d036137edf8944465ae7803b772a741ae91876033c03", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d94cb2df59468ded1a195e71ef8f024c0d783fa16e81e595f7e3c2476e29920159f549774ced5fec64cc1d015f832fc5d6a5cc963a5fc4d2cb5012a8313af204", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0166d01aa11620ec909866f23f326c87104253c4e63a639ae174ae1aab3d1957bb3bff80dabd28f0e5259cd683fd4572bc71f7075fb49d621af04002bf6bf10d01", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01145e7bc9d3338f4cf8ee44043e0f3882fa5ef7dc9314d020ac032011a5dd578eec1414f0e1651c5cf752f1e04360bff3db8bf237c51a99622800941bafc4f60f", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "011d699445ef39cba40f288b4a90beea58b45d9320123abaf275f844393eb6c1a0123f75b55fa2a769d9faf39f99cb245cb96402221aa743f9d538195d8b78160f" + "V1": { + "block_hash": "0665324472c593720b2a5cb9c81f2ec6a40401a7c22396addb1ddca4a8d56292", + "era_id": 4, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01eff1532f2df9481408adf43453e5bb88823eb8f297a6b35001099225cd95035a18fcbe5e0508d6829245d036137edf8944465ae7803b772a741ae91876033c03", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d94cb2df59468ded1a195e71ef8f024c0d783fa16e81e595f7e3c2476e29920159f549774ced5fec64cc1d015f832fc5d6a5cc963a5fc4d2cb5012a8313af204", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0166d01aa11620ec909866f23f326c87104253c4e63a639ae174ae1aab3d1957bb3bff80dabd28f0e5259cd683fd4572bc71f7075fb49d621af04002bf6bf10d01", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01145e7bc9d3338f4cf8ee44043e0f3882fa5ef7dc9314d020ac032011a5dd578eec1414f0e1651c5cf752f1e04360bff3db8bf237c51a99622800941bafc4f60f", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "011d699445ef39cba40f288b4a90beea58b45d9320123abaf275f844393eb6c1a0123f75b55fa2a769d9faf39f99cb245cb96402221aa743f9d538195d8b78160f" + } } }, "deploy_hashes": [] @@ -492,14 +546,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "b9cf69f0fa345fcc557db5d8db68268f2f6d35101c61f1098318fb26286d6c7c", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01e2c28c8dcbb67c069370425d841593721d366f12193eef17b99bc4d34f151cb19b00079da647e040735bb08877636b2c960357c012a7806ac587ac79688fbd08", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01fb5b99658b031151fac010eeedabb53a1c1420832e536ce91d8b61ab34a237f764b90e6e51944de94c3c4a98591268997a53bbc85968bc14289ad5d9994e2e0b", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01057a3cd15979ebb7bb7d634e5ccacde8ddb4981ea2681754caf37ff045d97035220b5f3770db73b3a9fbf1f2e295a84ec5dac308f331bae6bbaed0ecfbff6407", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01dff3ef0b5d35b93efb64cdc90389be98731b23bbfb35b31b95c9d2f97f729599731bbe1cfb34c1bbc16dc3acd9cc0a97c2eb9b0936ffa77bbaaa77fe4bb16008", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01c3037327b46b9468a95494ad1a4b6d18f35021e4c908751a37cfb5fcea6b93048e875affc68338abb75f9ae83767d719505cc26bf7e385c8f430101f03214f01" + "V1": { + "block_hash": "b9cf69f0fa345fcc557db5d8db68268f2f6d35101c61f1098318fb26286d6c7c", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01e2c28c8dcbb67c069370425d841593721d366f12193eef17b99bc4d34f151cb19b00079da647e040735bb08877636b2c960357c012a7806ac587ac79688fbd08", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01fb5b99658b031151fac010eeedabb53a1c1420832e536ce91d8b61ab34a237f764b90e6e51944de94c3c4a98591268997a53bbc85968bc14289ad5d9994e2e0b", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01057a3cd15979ebb7bb7d634e5ccacde8ddb4981ea2681754caf37ff045d97035220b5f3770db73b3a9fbf1f2e295a84ec5dac308f331bae6bbaed0ecfbff6407", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01dff3ef0b5d35b93efb64cdc90389be98731b23bbfb35b31b95c9d2f97f729599731bbe1cfb34c1bbc16dc3acd9cc0a97c2eb9b0936ffa77bbaaa77fe4bb16008", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01c3037327b46b9468a95494ad1a4b6d18f35021e4c908751a37cfb5fcea6b93048e875affc68338abb75f9ae83767d719505cc26bf7e385c8f430101f03214f01" + } } }, "deploy_hashes": [] @@ -530,14 +586,16 @@ "fbe260ce449087a7d19074be566722bd980504bb810b59c9b1edb7292b9bf8d6" ], "signatures": { - "block_hash": "7408c61539684ee7746e96dbb9f16345034152e8c651a73b04f26b9f2d360d15", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c4ad89a993e09c8e673098d63ac8ab280c71ee5a47247fa422c7696788ce26bdb781f3f9034978ff97845363efbe80ece80d37d19a4615b431015715d4088307", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01de890ce9f6248fa04bbc6ff75ed76fd75cfa33da54a423a985d8fb437dc7c1513cc0b07c1832c81dc08538a1bcef31be87d0590d1267b7866a0f087aa9c9fa0c", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01847e68664fa01e189075e8753d76c96fd998ae9c2bca94bdde83ac24c400ba75d7d75e3e9eecd14443bacafaae57de873f17cd19cc63cf1c2519942b6893d80d", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01813c754eb967477728d33535f423516f88ea2bd5e4b63b215ba35a9e1111b38013616dce39acb9377c2b6d739c92067b70ce28dff54ce9245cd90b058364fa00", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "019d74e99365f3888cdf80ae1c8123afae2c8623b412eed9d6f7127c20a4cbc7d1d918efc8f32c65e5ed93133468b410baee70d72d00a33dd070fbd1d44c16bc01" + "V1": { + "block_hash": "7408c61539684ee7746e96dbb9f16345034152e8c651a73b04f26b9f2d360d15", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c4ad89a993e09c8e673098d63ac8ab280c71ee5a47247fa422c7696788ce26bdb781f3f9034978ff97845363efbe80ece80d37d19a4615b431015715d4088307", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01de890ce9f6248fa04bbc6ff75ed76fd75cfa33da54a423a985d8fb437dc7c1513cc0b07c1832c81dc08538a1bcef31be87d0590d1267b7866a0f087aa9c9fa0c", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01847e68664fa01e189075e8753d76c96fd998ae9c2bca94bdde83ac24c400ba75d7d75e3e9eecd14443bacafaae57de873f17cd19cc63cf1c2519942b6893d80d", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01813c754eb967477728d33535f423516f88ea2bd5e4b63b215ba35a9e1111b38013616dce39acb9377c2b6d739c92067b70ce28dff54ce9245cd90b058364fa00", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "019d74e99365f3888cdf80ae1c8123afae2c8623b412eed9d6f7127c20a4cbc7d1d918efc8f32c65e5ed93133468b410baee70d72d00a33dd070fbd1d44c16bc01" + } } }, "deploy_hashes": [ @@ -576,14 +634,16 @@ "8d2fb469089235c04cc11987aec5cc9a6c60e53d81a91b7ecfd9ee6e6b257869" ], "signatures": { - "block_hash": "36f0f62d44b2471a6e2cfd45c0aa1d7eba737857a09735cee3252c65cc83217a", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01a79f9284083f38c817015c8b6be19c621a424ae128a84d4ca795a94f019db74a7c1c656cf05881a5751f23a8bf98284b82c21d099608e2337b8529d0bee3e30b", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01c9bc50cd5bbbf9827a859ca1726af5f417dd03243971a6e2747f789a5149552eaefdcd8fc31ee9539bdea8df6a11a035af5e4a92b08cb5063db17f7c96fb2906", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0134b3d37a02fd2f5d8071be3c7f96c4d9ed701c5b36b1f1bbd3c1ddcac5470c3d4eb53b49695ddc5e05e9e7f7177a183167b7795f565e5b2b69f29e71edecb006", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0129b3ae0d98a771adba2d71b5289683cd07b032d5ea63962598eb5b46924cb9c40687553edf024f9cb0da7b7ce1c97a70224fc404d814523e1b8191f6001da10f", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0177c18ff2a970d84e16d26b1310f4331fec9ce0adfeeb9151851bfde2a78e08f8e7f520031daab513ecdd57f53203c0a0e393190e01999dac20171b0c48ba1f0b" + "V1": { + "block_hash": "36f0f62d44b2471a6e2cfd45c0aa1d7eba737857a09735cee3252c65cc83217a", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01a79f9284083f38c817015c8b6be19c621a424ae128a84d4ca795a94f019db74a7c1c656cf05881a5751f23a8bf98284b82c21d099608e2337b8529d0bee3e30b", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01c9bc50cd5bbbf9827a859ca1726af5f417dd03243971a6e2747f789a5149552eaefdcd8fc31ee9539bdea8df6a11a035af5e4a92b08cb5063db17f7c96fb2906", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0134b3d37a02fd2f5d8071be3c7f96c4d9ed701c5b36b1f1bbd3c1ddcac5470c3d4eb53b49695ddc5e05e9e7f7177a183167b7795f565e5b2b69f29e71edecb006", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0129b3ae0d98a771adba2d71b5289683cd07b032d5ea63962598eb5b46924cb9c40687553edf024f9cb0da7b7ce1c97a70224fc404d814523e1b8191f6001da10f", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0177c18ff2a970d84e16d26b1310f4331fec9ce0adfeeb9151851bfde2a78e08f8e7f520031daab513ecdd57f53203c0a0e393190e01999dac20171b0c48ba1f0b" + } } }, "deploy_hashes": [ @@ -601,14 +661,16 @@ "era": 8, "approvals_hashes": null, "signatures": { - "block_hash": "29936b2e3e9920b624bb1539840949fcfb21e27bf347f0433d73861da6f9d608", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018ef77cb741d610411cf2e1d54ec63c63adc87449557c3adc200812e8d263c5b550a928dacbbad43738b0847d1acffcbafa75bc2ba352d2fee3a431d6e947eb00", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018382f4d0d690c2efd8a6178cd35c1c60beec2a9a8e9acd1b296e90fc9c15f8cc26e6e9864bd5c1bb74533b6969876274dab437183a7640ec2eb0ac7776abc108", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "015c86bf7799ca7ed974fabcaba50a0a210fb393d09a0e259a82458adbb1c50e1450abf4483255e55b1850c2a5734263d7db68228903e8560a634483e4641aed01", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "010a1709e850f9878452e17427780a884ff4203a217d91c8e2b1d4dac5467eda84048433bf61c8094f747a62a219572308cc1cafd93ec13ef462e6711ae99ee600", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0137567bf30d37f7cfa272df1441867a714e1a1eb63e6a360a7db59e4e95b7ca37cd3343f20006364279f2942559bdb4448c161752b05c07e6806730dc9b2d3c06" + "V1": { + "block_hash": "29936b2e3e9920b624bb1539840949fcfb21e27bf347f0433d73861da6f9d608", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018ef77cb741d610411cf2e1d54ec63c63adc87449557c3adc200812e8d263c5b550a928dacbbad43738b0847d1acffcbafa75bc2ba352d2fee3a431d6e947eb00", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018382f4d0d690c2efd8a6178cd35c1c60beec2a9a8e9acd1b296e90fc9c15f8cc26e6e9864bd5c1bb74533b6969876274dab437183a7640ec2eb0ac7776abc108", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "015c86bf7799ca7ed974fabcaba50a0a210fb393d09a0e259a82458adbb1c50e1450abf4483255e55b1850c2a5734263d7db68228903e8560a634483e4641aed01", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "010a1709e850f9878452e17427780a884ff4203a217d91c8e2b1d4dac5467eda84048433bf61c8094f747a62a219572308cc1cafd93ec13ef462e6711ae99ee600", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0137567bf30d37f7cfa272df1441867a714e1a1eb63e6a360a7db59e4e95b7ca37cd3343f20006364279f2942559bdb4448c161752b05c07e6806730dc9b2d3c06" + } } }, "deploy_hashes": [] @@ -618,14 +680,16 @@ "era": 6, "approvals_hashes": null, "signatures": { - "block_hash": "c06cad6478773686dd1fb7d9658f9e91fadfa222464d0403ddea9f6430f93146", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0107c592e78c968908a5cd06395b0c2f4d866b72221f3aa301695d215c66e9a9970cfe4b6bda6b918d9771ebaee0dc57577dd6b6e58af77fab78bd718636b2bd0a", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a849ed4d48ae86b377c419117d2db755be4f84fde5a0659cd925049f504b5180bb67a29eac411b2406a7ed95016bf46da619719dad187d2d0894593687bdab0e", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "018381440af0fcc446d7bf2edd6f059b9ae107c344b0c4e2f4c8df509a353f0363c91ec8607ed813a9cd4d03c5b14e16bd4788d008f04546713f70578898ef8904", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "013e79ba6d2de29b15a021ddc4f7eedea643d12a088cefb60e8b6bcad8fa7fc7da39264799efd94764aeb5d039f62d015a2c702a973c91d48c96da605c21a1900f", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01dd0c290c1c8a973856a80360e4913a027daca1bee0f6f58fd2049c9b4fa9ffd323f81a891701a1c5961f38a789ef049310e99593de0d5a6954a065d1e072ad00" + "V1": { + "block_hash": "c06cad6478773686dd1fb7d9658f9e91fadfa222464d0403ddea9f6430f93146", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0107c592e78c968908a5cd06395b0c2f4d866b72221f3aa301695d215c66e9a9970cfe4b6bda6b918d9771ebaee0dc57577dd6b6e58af77fab78bd718636b2bd0a", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a849ed4d48ae86b377c419117d2db755be4f84fde5a0659cd925049f504b5180bb67a29eac411b2406a7ed95016bf46da619719dad187d2d0894593687bdab0e", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "018381440af0fcc446d7bf2edd6f059b9ae107c344b0c4e2f4c8df509a353f0363c91ec8607ed813a9cd4d03c5b14e16bd4788d008f04546713f70578898ef8904", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "013e79ba6d2de29b15a021ddc4f7eedea643d12a088cefb60e8b6bcad8fa7fc7da39264799efd94764aeb5d039f62d015a2c702a973c91d48c96da605c21a1900f", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01dd0c290c1c8a973856a80360e4913a027daca1bee0f6f58fd2049c9b4fa9ffd323f81a891701a1c5961f38a789ef049310e99593de0d5a6954a065d1e072ad00" + } } }, "deploy_hashes": [] @@ -635,14 +699,16 @@ "era": 7, "approvals_hashes": null, "signatures": { - "block_hash": "81230f3a7a613e48bcbc2b0c4edfb4681e03eee92b096498452a13c0bdc8abfd", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01effc516754793d6a5c005a8174b127d7efdf49c9d3eb20996a5271a29284e7769096a8343e4e4d3004540c75b18332910c51e8a7b0c82ca8862175144ad98307", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013035aa4e7638186e8bead9684406b51bbb85964c1666a11de3a6bdc72cde5494b4c10a94a06d94a5b3e4f8ebafd5c9363deee7909e5101e47f32cddde295b500", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f34639e11f292ab50f4aa54760771dee89868c6a52cee726d5dc2f936ce77375276647dceefa45ad01dfd747541dab17bcf04114f1c03047443e8e167f66e005", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01b24a0876a2397467050e3d94ad046c40513237ec1dd73680dd8628773fcb07b2b1f5162b0451a6a5bae93dd9b068e4733098efad3c68fa6099d85e1e1f37e50a", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0178d98ec1b7133e4a330744368f46864e14362f48abe874982017113df6254e0252fb12216820e4b895f200546e25d545d5361fae2081d29ab5a33a445ed53101" + "V1": { + "block_hash": "81230f3a7a613e48bcbc2b0c4edfb4681e03eee92b096498452a13c0bdc8abfd", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01effc516754793d6a5c005a8174b127d7efdf49c9d3eb20996a5271a29284e7769096a8343e4e4d3004540c75b18332910c51e8a7b0c82ca8862175144ad98307", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013035aa4e7638186e8bead9684406b51bbb85964c1666a11de3a6bdc72cde5494b4c10a94a06d94a5b3e4f8ebafd5c9363deee7909e5101e47f32cddde295b500", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f34639e11f292ab50f4aa54760771dee89868c6a52cee726d5dc2f936ce77375276647dceefa45ad01dfd747541dab17bcf04114f1c03047443e8e167f66e005", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01b24a0876a2397467050e3d94ad046c40513237ec1dd73680dd8628773fcb07b2b1f5162b0451a6a5bae93dd9b068e4733098efad3c68fa6099d85e1e1f37e50a", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0178d98ec1b7133e4a330744368f46864e14362f48abe874982017113df6254e0252fb12216820e4b895f200546e25d545d5361fae2081d29ab5a33a445ed53101" + } } }, "deploy_hashes": [] @@ -652,14 +718,16 @@ "era": 6, "approvals_hashes": null, "signatures": { - "block_hash": "f3643655bbbcd415f479d538dd91b44cc22f2bdfa5ad46dac3b73f825fe80891", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018fed3db8814f9995c64246d0ce76d48c588c13e7278f08ce3a389c954aa039b751f4680f822c2bb33b3ebc1629c417f77a24183c290e378ec0dc983c619a060f", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d8e641443bc14227e9113f8cb70406e42375f1a43acb324252742a9acd04aa08f825f4da9df9c2dc3d0a4ca81c9bdbb632cfe7211e147666e16542df824a3006", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "011a8608ace69f02910d465277af8567620b7041f72a1e7f9549493b2e7cfa3b78cbafe8fddd01d210021b3a992c07a1050b6f970db7d1a9ef56915b52cb3f8c0a", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01b3a798b231ee2ca7088e73b09dfdb8373b50fc82299d5cf84c56a3ff8838ee5a35e97c874c5b717f5cf6c264f89f45c2a28e75d19788e235dda343536f3ea509", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01badf5a3f14073def89b4b9bbc7f84082eaf40cac5cd004321962485e6050d3241a87eb85650de8cdaa9d02cbfc8a126728738638a10c8c640209c0590102d706" + "V1": { + "block_hash": "f3643655bbbcd415f479d538dd91b44cc22f2bdfa5ad46dac3b73f825fe80891", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018fed3db8814f9995c64246d0ce76d48c588c13e7278f08ce3a389c954aa039b751f4680f822c2bb33b3ebc1629c417f77a24183c290e378ec0dc983c619a060f", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01d8e641443bc14227e9113f8cb70406e42375f1a43acb324252742a9acd04aa08f825f4da9df9c2dc3d0a4ca81c9bdbb632cfe7211e147666e16542df824a3006", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "011a8608ace69f02910d465277af8567620b7041f72a1e7f9549493b2e7cfa3b78cbafe8fddd01d210021b3a992c07a1050b6f970db7d1a9ef56915b52cb3f8c0a", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01b3a798b231ee2ca7088e73b09dfdb8373b50fc82299d5cf84c56a3ff8838ee5a35e97c874c5b717f5cf6c264f89f45c2a28e75d19788e235dda343536f3ea509", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01badf5a3f14073def89b4b9bbc7f84082eaf40cac5cd004321962485e6050d3241a87eb85650de8cdaa9d02cbfc8a126728738638a10c8c640209c0590102d706" + } } }, "deploy_hashes": [] @@ -669,14 +737,16 @@ "era": 9, "approvals_hashes": null, "signatures": { - "block_hash": "dc27efe32e93fa37926307465eaaecf460ab5d286f5f891995055b661619fa7f", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c2f572ada6b53c50a439ee9ddb5ae17100af1eb676e7a35f940bd2f25b0dd8b00e715c8db34ff573d067d6f446e552faa15895be3117337b9047fd4e0b4d2901", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0163481871dc8147578d9c2ebafc2cfd69cd908b8c820dc9a1d2a318e55df7917cac5c855eaced0c72f1bca45aa45faca557395494c404d399fc1ac84303ff420a", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "013afb0d0731d39e793433e949478dcfd88eddf64410183cb5703895cec51f59015c4103e8f4ca8da1a8771e0e5bf62c8dcdb82d12a50ab016c14c5e0c3670f80b", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0113f14644afc884a7b9149c7b83b3f69efb4c557bbc34140bcac7396768a81caa4b53fb3d483a8692e7d230ee1505a2d7984510d1b1eba3322e83ae4bbbc8cc0f", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01752cf4c4f4c2d1688b10727229575bba62ca400b6c56994d06c77c8b3a66190c1bf6356a2c0c3609b85ff419b839c3997287b7077e86215fe09fa158a5bf3501" + "V1": { + "block_hash": "dc27efe32e93fa37926307465eaaecf460ab5d286f5f891995055b661619fa7f", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c2f572ada6b53c50a439ee9ddb5ae17100af1eb676e7a35f940bd2f25b0dd8b00e715c8db34ff573d067d6f446e552faa15895be3117337b9047fd4e0b4d2901", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0163481871dc8147578d9c2ebafc2cfd69cd908b8c820dc9a1d2a318e55df7917cac5c855eaced0c72f1bca45aa45faca557395494c404d399fc1ac84303ff420a", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "013afb0d0731d39e793433e949478dcfd88eddf64410183cb5703895cec51f59015c4103e8f4ca8da1a8771e0e5bf62c8dcdb82d12a50ab016c14c5e0c3670f80b", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0113f14644afc884a7b9149c7b83b3f69efb4c557bbc34140bcac7396768a81caa4b53fb3d483a8692e7d230ee1505a2d7984510d1b1eba3322e83ae4bbbc8cc0f", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01752cf4c4f4c2d1688b10727229575bba62ca400b6c56994d06c77c8b3a66190c1bf6356a2c0c3609b85ff419b839c3997287b7077e86215fe09fa158a5bf3501" + } } }, "deploy_hashes": [] @@ -686,14 +756,16 @@ "era": 10, "approvals_hashes": [], "signatures": { - "block_hash": "50e9cffa88931fb44296172cbe2d2989a94ec2d5b2cbb80ab7364d4ce6ffd0a6", - "era_id": 10, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01b1af9625ea93e953a48a2223dac3c9f5c014037c22d8de356a0f4337c325afa838614f54b575210602f01a08a4e87b52117f64fe9cb540fecb839dda05764101", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018c5c0b7d36458ec0e4b6b7677104c91ddb6e29efb3d9c2df0ce945d835269f9635e6cbf8661fdd0332a5e085fcd56b092ed81ea03bc66ba761397d3fb14e0a08", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ab069545602645cab96be41e6bf0d6925a209caee37cab1025f7cf9befe19cd2f676c14671fd2a230895cc23eb712acfbe04d6c94f27431915a0c8528f2a4402", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01a7082345c330f2a6b19b5f13f9e3ba18a00de5363c589ab3cd17512b9881cb160c6396d8eacb4fb8c8d000f2d8c7cea802cea79cbe2a057dcb76e0f60ec9940c", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0143ff53b152977e00cc68ca3f1710d112c691295e28dd02fb025019a1a50bc4d0fc0723617085544d67d58153933dae9d02eb85e0f453065ca926c8d91f2edb0e" + "V1": { + "block_hash": "50e9cffa88931fb44296172cbe2d2989a94ec2d5b2cbb80ab7364d4ce6ffd0a6", + "era_id": 10, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01b1af9625ea93e953a48a2223dac3c9f5c014037c22d8de356a0f4337c325afa838614f54b575210602f01a08a4e87b52117f64fe9cb540fecb839dda05764101", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018c5c0b7d36458ec0e4b6b7677104c91ddb6e29efb3d9c2df0ce945d835269f9635e6cbf8661fdd0332a5e085fcd56b092ed81ea03bc66ba761397d3fb14e0a08", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01ab069545602645cab96be41e6bf0d6925a209caee37cab1025f7cf9befe19cd2f676c14671fd2a230895cc23eb712acfbe04d6c94f27431915a0c8528f2a4402", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01a7082345c330f2a6b19b5f13f9e3ba18a00de5363c589ab3cd17512b9881cb160c6396d8eacb4fb8c8d000f2d8c7cea802cea79cbe2a057dcb76e0f60ec9940c", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0143ff53b152977e00cc68ca3f1710d112c691295e28dd02fb025019a1a50bc4d0fc0723617085544d67d58153933dae9d02eb85e0f453065ca926c8d91f2edb0e" + } } }, "deploy_hashes": [] @@ -703,14 +775,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "18a51771a0a694e7602c53b4510c4b63b63086c926256a635f84e4ef017f800e", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "015038be26fff75bb8725e496f7de8d2c1f04e697f3e9fa9427df75f631574340c36ef605dc9cf1d27aafcdf42e9b5a9e03719a6ae86b3a6151d905988b1e61b04", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01c554f533d5ef7e9ba1432ef3350783f9e709a4c4414aac6a3f23d9ccf51f8893e4373147e54cf27619792d8dbc1403aafe12f3d8c06b821bfa7d9a94a12a8706", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "017db5d39ae7841c10f510cffb2945f9850287c30f3515f81fb49cb1488f3378cceb127af16c8f29d1e115521aa942f1eee0522dbd884c34ea9c95fba63d40520e", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "018a27a18d0020ee7ee8479d2964886dc4509cd4f3f7704b847d403c9c63d1fae4c78851f26b1e89e2f6c2222dd6c5c2fe62236d8063ddd065899e63dd5b93a10b", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0116b448374a553ad4223c18a2cdb7f65905e7917e28c3c90cd53c8dacd330f6da62d0f9b8d9a86f15e1a1c0fa819ee849e6c5de3beb33ceea7f973b505c56480e" + "V1": { + "block_hash": "18a51771a0a694e7602c53b4510c4b63b63086c926256a635f84e4ef017f800e", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "015038be26fff75bb8725e496f7de8d2c1f04e697f3e9fa9427df75f631574340c36ef605dc9cf1d27aafcdf42e9b5a9e03719a6ae86b3a6151d905988b1e61b04", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01c554f533d5ef7e9ba1432ef3350783f9e709a4c4414aac6a3f23d9ccf51f8893e4373147e54cf27619792d8dbc1403aafe12f3d8c06b821bfa7d9a94a12a8706", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "017db5d39ae7841c10f510cffb2945f9850287c30f3515f81fb49cb1488f3378cceb127af16c8f29d1e115521aa942f1eee0522dbd884c34ea9c95fba63d40520e", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "018a27a18d0020ee7ee8479d2964886dc4509cd4f3f7704b847d403c9c63d1fae4c78851f26b1e89e2f6c2222dd6c5c2fe62236d8063ddd065899e63dd5b93a10b", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0116b448374a553ad4223c18a2cdb7f65905e7917e28c3c90cd53c8dacd330f6da62d0f9b8d9a86f15e1a1c0fa819ee849e6c5de3beb33ceea7f973b505c56480e" + } } }, "deploy_hashes": [] @@ -720,14 +794,16 @@ "era": 8, "approvals_hashes": null, "signatures": { - "block_hash": "329b31a78a7df60a673962a768736c58f32df95a8d15c3ed64cfde1fd4d0c2d9", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01268e33fc72093ef389abe40d03173f535fb2dfd7c2421f276e6ed79ef7fbc76b9f305f789175ca049c39ce2e8a27e0972858120e84ef9b3633df6681d329b70c", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a01bb0ac13f5134863c1fd170dee15f712f5289e3f16ea33baba305a246aace391cc6cb3980282a09a464724302d8973ec00efd53bd623377ce793be21bb340c", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "012a931e60a1d7753eabe8ec2f60ee83606aff2892dd52dc1b756e093a54631a99484e6d9a45c72d0669528b1b84af123d2040b6ce79988433dfd74b14c033f103", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f7645dbd75afccff1583fad3f534105d62ad2766d87ff3fc574994b5f16f4726ac851566545bde8db635fd5b4a86bb01a7f0e19123ef961e8082350ea3954b05", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01c6cc33a7555c4aa29fbd5a110a3ac238f2beee5f047a91a19c484a48ecd2fdb6b70370ab863c39be8474578d7a747bde4ace519f8a0f4dc824b2dd7c6dc8fd05" + "V1": { + "block_hash": "329b31a78a7df60a673962a768736c58f32df95a8d15c3ed64cfde1fd4d0c2d9", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01268e33fc72093ef389abe40d03173f535fb2dfd7c2421f276e6ed79ef7fbc76b9f305f789175ca049c39ce2e8a27e0972858120e84ef9b3633df6681d329b70c", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a01bb0ac13f5134863c1fd170dee15f712f5289e3f16ea33baba305a246aace391cc6cb3980282a09a464724302d8973ec00efd53bd623377ce793be21bb340c", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "012a931e60a1d7753eabe8ec2f60ee83606aff2892dd52dc1b756e093a54631a99484e6d9a45c72d0669528b1b84af123d2040b6ce79988433dfd74b14c033f103", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f7645dbd75afccff1583fad3f534105d62ad2766d87ff3fc574994b5f16f4726ac851566545bde8db635fd5b4a86bb01a7f0e19123ef961e8082350ea3954b05", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01c6cc33a7555c4aa29fbd5a110a3ac238f2beee5f047a91a19c484a48ecd2fdb6b70370ab863c39be8474578d7a747bde4ace519f8a0f4dc824b2dd7c6dc8fd05" + } } }, "deploy_hashes": [] @@ -741,14 +817,16 @@ "3bb65a1cd0eefd75ee0ec864ad65d2bb6844391b645812887779f680a2097694" ], "signatures": { - "block_hash": "8846f414cfecd61e3a405cbf1aece1fe1c98fb55dbaa33480d2222158254bbdd", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "014ded5a73f5a4ffc0ba7d074fd40a768ff3b6cad345b5c588b2811536d5cc653ea3964cbe8f281c4d99dedfcf1dcab08de4ebb98046b4011b941cdd4aa70a7702", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01638a6ca05e18e467e070a652d8220835be3a3f61c1f06e40d316ebd97c3b59ca612264b26617ece9f0f00aa73ae2e31e0cc4e09ebc732cace053ce7cc359490b", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "018bcca0710e6298a14eee2b4d997d55d46c8cd8c048662073f3d10dda3ca5123b41c622205bccf42601c47fcd7594ee35d39170d5499b6ce129d953529fed9903", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0143a0c296853f95679687b58a6d6e84e7dec9864428c5f689b0941f0965fd05fc196521d3e20879d156d80cd849d202f8d62c772272e989765290d28036751303", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01678054f97cb18785d59a7b4f5adafa916449e42f30759d90aa70dbb51bd5843d3395baf8cf9796cc4b0423d115d772d1e87b78e4e41340ec3f24fdff0b763607" + "V1": { + "block_hash": "8846f414cfecd61e3a405cbf1aece1fe1c98fb55dbaa33480d2222158254bbdd", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "014ded5a73f5a4ffc0ba7d074fd40a768ff3b6cad345b5c588b2811536d5cc653ea3964cbe8f281c4d99dedfcf1dcab08de4ebb98046b4011b941cdd4aa70a7702", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01638a6ca05e18e467e070a652d8220835be3a3f61c1f06e40d316ebd97c3b59ca612264b26617ece9f0f00aa73ae2e31e0cc4e09ebc732cace053ce7cc359490b", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "018bcca0710e6298a14eee2b4d997d55d46c8cd8c048662073f3d10dda3ca5123b41c622205bccf42601c47fcd7594ee35d39170d5499b6ce129d953529fed9903", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0143a0c296853f95679687b58a6d6e84e7dec9864428c5f689b0941f0965fd05fc196521d3e20879d156d80cd849d202f8d62c772272e989765290d28036751303", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01678054f97cb18785d59a7b4f5adafa916449e42f30759d90aa70dbb51bd5843d3395baf8cf9796cc4b0423d115d772d1e87b78e4e41340ec3f24fdff0b763607" + } } }, "deploy_hashes": [ @@ -762,14 +840,16 @@ "era": 4, "approvals_hashes": null, "signatures": { - "block_hash": "a62654b2f9a65e0591e38015b617c6fe37e3a50dba474223030d75129d4adaf6", - "era_id": 4, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01efe56d094104ede2a186932c26d733d512313a1e57866732ca4cdc554ef1b5c7b09a869f81ae1ab100f22d5facd4255642dadc0a08da4454b0034f3bcde6b308", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018067e568f86370ec5cac5b2d229300d5b4629ef3ee3e3347a7cb5f33770ebbeec9a0ce415db388572b99f1f53fc5c256149561e088646b99140358d56e808f0b", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "015054092a62bed9e1ea285f35bc310fabf9d3f96c79ce5976a3e3735b83c05bd4fb41e02b80d15c7ff5f50f5cae79c177d067131698cae07310e69b4c9c553f09", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01a1145c92db74488261224c0db0d9427df46206c16e0b1fff899aac7b5125b4dce0e716e8aa4a6c6042feb3674ccf4f081318ca7488e2cda456c32d03ae11410d", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "011821e258815fe27b80d20c86ad666f9d1b0b6aedd5ccef1d94048b7a530b552e30e0b7497ec18ae0f1738602392be9d2f6f1128c2b0006309ce2f340eff2ad0b" + "V1": { + "block_hash": "a62654b2f9a65e0591e38015b617c6fe37e3a50dba474223030d75129d4adaf6", + "era_id": 4, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01efe56d094104ede2a186932c26d733d512313a1e57866732ca4cdc554ef1b5c7b09a869f81ae1ab100f22d5facd4255642dadc0a08da4454b0034f3bcde6b308", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018067e568f86370ec5cac5b2d229300d5b4629ef3ee3e3347a7cb5f33770ebbeec9a0ce415db388572b99f1f53fc5c256149561e088646b99140358d56e808f0b", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "015054092a62bed9e1ea285f35bc310fabf9d3f96c79ce5976a3e3735b83c05bd4fb41e02b80d15c7ff5f50f5cae79c177d067131698cae07310e69b4c9c553f09", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01a1145c92db74488261224c0db0d9427df46206c16e0b1fff899aac7b5125b4dce0e716e8aa4a6c6042feb3674ccf4f081318ca7488e2cda456c32d03ae11410d", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "011821e258815fe27b80d20c86ad666f9d1b0b6aedd5ccef1d94048b7a530b552e30e0b7497ec18ae0f1738602392be9d2f6f1128c2b0006309ce2f340eff2ad0b" + } } }, "deploy_hashes": [] @@ -779,14 +859,16 @@ "era": 4, "approvals_hashes": null, "signatures": { - "block_hash": "18c1d3267d5cd2f311a501760704f262a12996a589623f7f73903ea28bc3b21f", - "era_id": 4, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01b9eb76556d4919712a797c40dbb42446622cd6f10ee55af8d2f06e41fa72176bb60d32489dce6512586382d6ea39aa3d4fcef0570e63eb29db57d60e95acf309", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01aeb94eb2d7c54e7e533c89de372f97016dbdf6bae5d6baa3c19ce065f2ef353bedced4c0e5263e0c636b7aa2ac8a06a5402676830aa9683bf9200793c420bd03", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "013f8b80fa31c7a3db73852912ac31188c5660a327d6a370e2db6ee70fd569b56a3511178ac54b597b2cca47e5b268f449c7b84d19f186e7bc13909f0e305e4f06", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f375e17bdda7fb9125c3a0d768f88846debf1af07e9ef2466ee94cf9db5e0af088d41a08cb6970e55d1a7c8167fa63ee12edea54c59fa8be9ad04e9b11c8ca07", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01b97099e25cb2df1caf813236a7ae4d1dc64f1487ffbfa696fe7c1bf663001bda78e127df1f3b1838c0e73715b72f64f9152021a98d645bc297fb6442e45df101" + "V1": { + "block_hash": "18c1d3267d5cd2f311a501760704f262a12996a589623f7f73903ea28bc3b21f", + "era_id": 4, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01b9eb76556d4919712a797c40dbb42446622cd6f10ee55af8d2f06e41fa72176bb60d32489dce6512586382d6ea39aa3d4fcef0570e63eb29db57d60e95acf309", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01aeb94eb2d7c54e7e533c89de372f97016dbdf6bae5d6baa3c19ce065f2ef353bedced4c0e5263e0c636b7aa2ac8a06a5402676830aa9683bf9200793c420bd03", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "013f8b80fa31c7a3db73852912ac31188c5660a327d6a370e2db6ee70fd569b56a3511178ac54b597b2cca47e5b268f449c7b84d19f186e7bc13909f0e305e4f06", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f375e17bdda7fb9125c3a0d768f88846debf1af07e9ef2466ee94cf9db5e0af088d41a08cb6970e55d1a7c8167fa63ee12edea54c59fa8be9ad04e9b11c8ca07", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01b97099e25cb2df1caf813236a7ae4d1dc64f1487ffbfa696fe7c1bf663001bda78e127df1f3b1838c0e73715b72f64f9152021a98d645bc297fb6442e45df101" + } } }, "deploy_hashes": [] @@ -796,14 +878,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "f517a95ec6050156a8537bc4ab6b2b2a115dbf8583d92bff986a94ae6cb2ff09", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0156cca848f711896442a5e1a46526b0b0015f4edf74d3e6c332b3df999b98db476dfde8e3fc0dc8e0d66eb8aa22855c07b76b05c37980c743071c7c711445fd09", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01bda830c252d5ecf66653a5dd9a7f2a5fcf6e6778adabf66d106d302a109682898649dd9bb64c54fc6669392bfbbdc641921b2fe48c38f483c84de22892f78d0c", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0149bbc7f26f0e5a76b0cd21131d3945c81e3fe8332b6279a0fa4d7e6d3f53ba2390f4a509dbf31b65a1876da9e0ac29a4e73cba637b24353934f026eae9d7fa04", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "015b962326367032127bd44a645fc0ca36307399c5fc433e7b386782170aaff64680133312cd870146a626643fed8a29ee3a6f814b9938ccf67ddf499adc51ca07", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01d3c8f430aacda4738b6d785ca0e83a8dfaa9ad7c940bbc8bd52938f0caf2629316581cf7c72e5499f160f9a33883d7d43258893a2b43abd0882a272e04ef160a" + "V1": { + "block_hash": "f517a95ec6050156a8537bc4ab6b2b2a115dbf8583d92bff986a94ae6cb2ff09", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0156cca848f711896442a5e1a46526b0b0015f4edf74d3e6c332b3df999b98db476dfde8e3fc0dc8e0d66eb8aa22855c07b76b05c37980c743071c7c711445fd09", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01bda830c252d5ecf66653a5dd9a7f2a5fcf6e6778adabf66d106d302a109682898649dd9bb64c54fc6669392bfbbdc641921b2fe48c38f483c84de22892f78d0c", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0149bbc7f26f0e5a76b0cd21131d3945c81e3fe8332b6279a0fa4d7e6d3f53ba2390f4a509dbf31b65a1876da9e0ac29a4e73cba637b24353934f026eae9d7fa04", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "015b962326367032127bd44a645fc0ca36307399c5fc433e7b386782170aaff64680133312cd870146a626643fed8a29ee3a6f814b9938ccf67ddf499adc51ca07", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01d3c8f430aacda4738b6d785ca0e83a8dfaa9ad7c940bbc8bd52938f0caf2629316581cf7c72e5499f160f9a33883d7d43258893a2b43abd0882a272e04ef160a" + } } }, "deploy_hashes": [] @@ -813,14 +897,16 @@ "era": 7, "approvals_hashes": null, "signatures": { - "block_hash": "1a9bf2c6bcb799136040ee0dafd44b5eb126220e098161f82641aeb6ae85461e", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01cf50f3a4e5ec2b55ff33c893669b243c7127208c30396cbefa7303b7eb46f466d9b282f3bd4d55c2a65acd5242eeadb35cea9c23adfb750a162631cfe293c50d", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01b3d4d4e7c7e52d8869d0ff74952621b665beebf7ad9e7783dfbcf0c24f586de55ede57086afd2551f60b0baba2b7d8b8cd06134bf12f464d592eda6c6b69bc03", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01e85321fdb3f9f38ce4b60e1f57d737ebaa608b7055d109a6556bcd0543f8ed828e68231d2fa178ce01b4e6ba5b72704ab486e0c4f3ef70f87eae337549db6c03", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01e4613eb3e6923f89c4e405145ce388320303acfa708813038f1a68c2ceeeba20138a3c3c2014243970b8ec88d265c30d459a8677fd14c338e7bb365ec7acf70d", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01cfb8a99e19d240745dcf9f27e8e0e2c35df90508b50d827165cf188e78b21a49694db6216eb438334686f803c2f4fd45ca64fd0edcd10e8a8f410bdfd11dcf01" + "V1": { + "block_hash": "1a9bf2c6bcb799136040ee0dafd44b5eb126220e098161f82641aeb6ae85461e", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01cf50f3a4e5ec2b55ff33c893669b243c7127208c30396cbefa7303b7eb46f466d9b282f3bd4d55c2a65acd5242eeadb35cea9c23adfb750a162631cfe293c50d", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01b3d4d4e7c7e52d8869d0ff74952621b665beebf7ad9e7783dfbcf0c24f586de55ede57086afd2551f60b0baba2b7d8b8cd06134bf12f464d592eda6c6b69bc03", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01e85321fdb3f9f38ce4b60e1f57d737ebaa608b7055d109a6556bcd0543f8ed828e68231d2fa178ce01b4e6ba5b72704ab486e0c4f3ef70f87eae337549db6c03", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01e4613eb3e6923f89c4e405145ce388320303acfa708813038f1a68c2ceeeba20138a3c3c2014243970b8ec88d265c30d459a8677fd14c338e7bb365ec7acf70d", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01cfb8a99e19d240745dcf9f27e8e0e2c35df90508b50d827165cf188e78b21a49694db6216eb438334686f803c2f4fd45ca64fd0edcd10e8a8f410bdfd11dcf01" + } } }, "deploy_hashes": [] @@ -830,14 +916,16 @@ "era": 4, "approvals_hashes": null, "signatures": { - "block_hash": "b77cbbd252fa04e3685e3b22331670fcbe2215bd1dba06e2e49d9d9e4f055557", - "era_id": 4, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c3ae7049e70e00ad85842d10b4b38e5da8abac966bf429cd8f8bed8a567b6f2a54668db968a4d0aa734e57d660341a68b14ecb482f4628d8c2121c432c41e909", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018d6291632d14c7b0a1c55b9f5a41c99125d2437828bf36e1805b5247dad90a312e3aab3045393d1d5861a028461853a90fd96279eb7a09e8e77262a830e5ca0d", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f195903943eb942244027e30431d523c886aad058edf781294f4860378aea569e7ba3c76df3b46db2439e21c05a7f1eb3e0fe21a54dff09789fea7cc16f2aa09", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "019e56d1429f3151d1eea1f113184e6a254880c14bd28dece3a9c5130dc7e53b867462fc8c948cb1c65749f5fb99d0eade89e37961a4ffd6f48570b872eb3eb80c", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01364daea728bc656324c9251559af5629667645c7b45c0189d653819a837f86ed1e1745622f581c589fadb138032b49fa4365a8c443b0f99695f99c8af552b106" + "V1": { + "block_hash": "b77cbbd252fa04e3685e3b22331670fcbe2215bd1dba06e2e49d9d9e4f055557", + "era_id": 4, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01c3ae7049e70e00ad85842d10b4b38e5da8abac966bf429cd8f8bed8a567b6f2a54668db968a4d0aa734e57d660341a68b14ecb482f4628d8c2121c432c41e909", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018d6291632d14c7b0a1c55b9f5a41c99125d2437828bf36e1805b5247dad90a312e3aab3045393d1d5861a028461853a90fd96279eb7a09e8e77262a830e5ca0d", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f195903943eb942244027e30431d523c886aad058edf781294f4860378aea569e7ba3c76df3b46db2439e21c05a7f1eb3e0fe21a54dff09789fea7cc16f2aa09", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "019e56d1429f3151d1eea1f113184e6a254880c14bd28dece3a9c5130dc7e53b867462fc8c948cb1c65749f5fb99d0eade89e37961a4ffd6f48570b872eb3eb80c", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01364daea728bc656324c9251559af5629667645c7b45c0189d653819a837f86ed1e1745622f581c589fadb138032b49fa4365a8c443b0f99695f99c8af552b106" + } } }, "deploy_hashes": [] @@ -847,14 +935,16 @@ "era": 8, "approvals_hashes": null, "signatures": { - "block_hash": "89f42a9616f94d71f1c31589ab89ac38a600ec58fad8713fd3c28b8c1f4e7ec8", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "011e94d090a77c80e296a516664a577558c58242504b77002e049cebacfe0bd9801f54efcee0521d4a8088ec23eb1c55ecc165d9438840bf0ac0d1d711544be603", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01423220f2b56273e6abb6fe5460bde496a7ebf12e998e0bf049d31324d899a5260195db7740a8f7c724ea65cf1114471dc393f380ce7231327e013db74fbb5102", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01050b83336eff034207c4f40164132059755162ed52d3959f573c8c456b66ed70e249a914b98099954034a3ad7373c8688e29f77164341037ece4cbd44fa5cc0b", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "015e98ea39d87ed3e310ad12282b2f59dd61d2668d9a22bdf97b9d58f1a2f15b8764ef0593642b4121602699ae87011398551f0db115e872e8a4c0b02a0c362b03", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01e5fbcd676f616e7b4b7ded48d651346361dd0e7eddad6ea78705d056068d089e5fec73439a075f5ddb26326012163159bb8aa5ae7bc12f89ff05875604b25f0a" + "V1": { + "block_hash": "89f42a9616f94d71f1c31589ab89ac38a600ec58fad8713fd3c28b8c1f4e7ec8", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "011e94d090a77c80e296a516664a577558c58242504b77002e049cebacfe0bd9801f54efcee0521d4a8088ec23eb1c55ecc165d9438840bf0ac0d1d711544be603", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01423220f2b56273e6abb6fe5460bde496a7ebf12e998e0bf049d31324d899a5260195db7740a8f7c724ea65cf1114471dc393f380ce7231327e013db74fbb5102", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01050b83336eff034207c4f40164132059755162ed52d3959f573c8c456b66ed70e249a914b98099954034a3ad7373c8688e29f77164341037ece4cbd44fa5cc0b", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "015e98ea39d87ed3e310ad12282b2f59dd61d2668d9a22bdf97b9d58f1a2f15b8764ef0593642b4121602699ae87011398551f0db115e872e8a4c0b02a0c362b03", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01e5fbcd676f616e7b4b7ded48d651346361dd0e7eddad6ea78705d056068d089e5fec73439a075f5ddb26326012163159bb8aa5ae7bc12f89ff05875604b25f0a" + } } }, "deploy_hashes": [] @@ -864,14 +954,16 @@ "era": 10, "approvals_hashes": [], "signatures": { - "block_hash": "96607840ea4a72f4cc942fec7a10a902e19ae1bf2513acced2787e972eb209f4", - "era_id": 10, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0172af335870196156ad1bfff98728b613bdb1c09a37a06ebacdf5fcce47bd763298bb0449141641793184418263c0d5c186e9f060bf897939edbf7e8860c3fe06", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01e0bdaa0d179740660606aa662eeabfbc5024ff5cac6b3a8df1bb66133fc6ab722ee61bfd70b50437de820103f7b0b0b0c0625658de2cd05c7c35d57d4c79bb02", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01fb60bd2cd3c17c2d1f2439b88571024d3ce70dfdd0aaad41ba7a6e5e29601ae555aa9720b865c3269638c009de6ab6b8814bed9a079a9f9b2b762c9c3becc507", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "015a909ae323a4ee11c86946bb760fd3f391a430861a9ed2f4baf97bbce48980f073d51bcd36fbeba42e1df0c12b21c0be0b98dfae00d7241ad1991205df474f06", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01d7ad431bee6078c51a13c278ffeff0118007c7c65d15a5db2d501d563227cac967b4b2ce5b707b16954a0187a5c15a06f975abc5afe78f30100e145fcb77610b" + "V1": { + "block_hash": "96607840ea4a72f4cc942fec7a10a902e19ae1bf2513acced2787e972eb209f4", + "era_id": 10, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0172af335870196156ad1bfff98728b613bdb1c09a37a06ebacdf5fcce47bd763298bb0449141641793184418263c0d5c186e9f060bf897939edbf7e8860c3fe06", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01e0bdaa0d179740660606aa662eeabfbc5024ff5cac6b3a8df1bb66133fc6ab722ee61bfd70b50437de820103f7b0b0b0c0625658de2cd05c7c35d57d4c79bb02", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01fb60bd2cd3c17c2d1f2439b88571024d3ce70dfdd0aaad41ba7a6e5e29601ae555aa9720b865c3269638c009de6ab6b8814bed9a079a9f9b2b762c9c3becc507", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "015a909ae323a4ee11c86946bb760fd3f391a430861a9ed2f4baf97bbce48980f073d51bcd36fbeba42e1df0c12b21c0be0b98dfae00d7241ad1991205df474f06", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01d7ad431bee6078c51a13c278ffeff0118007c7c65d15a5db2d501d563227cac967b4b2ce5b707b16954a0187a5c15a06f975abc5afe78f30100e145fcb77610b" + } } }, "deploy_hashes": [] @@ -881,14 +973,16 @@ "era": 4, "approvals_hashes": null, "signatures": { - "block_hash": "846bda8fbf66660999eebe45678129278147be95efe5d919640ebe0eab6efabc", - "era_id": 4, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01fb136aa412c3b925ac255aa80b06d8bb3800bc89c7c1a349cb4b92f2153a9d1bec2d5b2c67be7f4c7fe767be9978801042ca7e0e0f474b700898d9209c83ad00", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0124438488b90c154e048fc88d983ea130b04f56ca9e7153d9eebca7c0745c6f110e1a77cc5198754c35230adb02051caf7692083c8a7390830023d6abc9603201", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0110dbfcf752496964d5b48518e5a135740e53f09aa6bad6ee42ba67771a314ed5ce502ec5275a5aa908cdb68e0a49428928f2bcff517e4c76a4d34df69ba34a05", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "016c4fcda8a74bc271ad1125a409b2e8b285334f1fc201c0a289878043b55ef36871099f9490493e34de35eb501aa377787fff971ba9c393e1c422becfad7b1a01", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "011fc6a840c70999ceb9a0ff937f5b0cd5dbfea15129c086b19fd77b01c28b702a810d6bbaed3b2780c25a3c00bafe6f14ecca250a3947112013438cd68805d800" + "V1": { + "block_hash": "846bda8fbf66660999eebe45678129278147be95efe5d919640ebe0eab6efabc", + "era_id": 4, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01fb136aa412c3b925ac255aa80b06d8bb3800bc89c7c1a349cb4b92f2153a9d1bec2d5b2c67be7f4c7fe767be9978801042ca7e0e0f474b700898d9209c83ad00", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0124438488b90c154e048fc88d983ea130b04f56ca9e7153d9eebca7c0745c6f110e1a77cc5198754c35230adb02051caf7692083c8a7390830023d6abc9603201", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0110dbfcf752496964d5b48518e5a135740e53f09aa6bad6ee42ba67771a314ed5ce502ec5275a5aa908cdb68e0a49428928f2bcff517e4c76a4d34df69ba34a05", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "016c4fcda8a74bc271ad1125a409b2e8b285334f1fc201c0a289878043b55ef36871099f9490493e34de35eb501aa377787fff971ba9c393e1c422becfad7b1a01", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "011fc6a840c70999ceb9a0ff937f5b0cd5dbfea15129c086b19fd77b01c28b702a810d6bbaed3b2780c25a3c00bafe6f14ecca250a3947112013438cd68805d800" + } } }, "deploy_hashes": [] @@ -898,14 +992,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "aa88cfaee3c7993f8d30a0dbb6039d2d009b34725d747b7c639a29de810ab274", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018ac0475e0c87be0df6dcd945ad05ec8bbc57dc2dae6c464e66c760e2bdcc817315b98f14dc254b2890a7ca42dcbd31de1bae0d00187b55807fc9e894b64b860a", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01e72790907e1802bb1640bd4630a97d9c92dc8b478cff92e2b9d567b6fd83802e779c4c4d27a340079dc86aa3681e51b95b6428dc39534136fe419e1d8ebea303", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "018a4ddc2606619dc1be1cbf0b00fd30b06ac95e844e6822d1d970160aa0f83eab5b8a751d4ea6c5c4b67460246cf6dab88d878d102a0be81cf905aa0e4bd6b10b", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "017f349109f4e27147947ed81825d88cfd17ca95e9ea98b4eee836edf8502a5c4eb92ac6b29096c3664a31b3089090d0a1e6d2a4fd4f21ef64186fd7496d5b5f0c", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "016d5e2c01638072e25bfa793347fab8595b74f35bb8c8730c26b1ffaa39b1d684b6d0ed42267217b6a4d7b634d0f14db84476b8ad1572eb2fc110ecea6b71710d" + "V1": { + "block_hash": "aa88cfaee3c7993f8d30a0dbb6039d2d009b34725d747b7c639a29de810ab274", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018ac0475e0c87be0df6dcd945ad05ec8bbc57dc2dae6c464e66c760e2bdcc817315b98f14dc254b2890a7ca42dcbd31de1bae0d00187b55807fc9e894b64b860a", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01e72790907e1802bb1640bd4630a97d9c92dc8b478cff92e2b9d567b6fd83802e779c4c4d27a340079dc86aa3681e51b95b6428dc39534136fe419e1d8ebea303", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "018a4ddc2606619dc1be1cbf0b00fd30b06ac95e844e6822d1d970160aa0f83eab5b8a751d4ea6c5c4b67460246cf6dab88d878d102a0be81cf905aa0e4bd6b10b", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "017f349109f4e27147947ed81825d88cfd17ca95e9ea98b4eee836edf8502a5c4eb92ac6b29096c3664a31b3089090d0a1e6d2a4fd4f21ef64186fd7496d5b5f0c", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "016d5e2c01638072e25bfa793347fab8595b74f35bb8c8730c26b1ffaa39b1d684b6d0ed42267217b6a4d7b634d0f14db84476b8ad1572eb2fc110ecea6b71710d" + } } }, "deploy_hashes": [] @@ -919,14 +1015,16 @@ "5c9387c7727ef45134fbf420c99bdb17dd0020b995589f781101b56e71a6a071" ], "signatures": { - "block_hash": "6f386926f07ad93d0a9330d20ddea32f22596cb5c6ac96e81fcc32dc164c26a9", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018ff5d691f249abbbecbb932e09f5b6875ddab8ffac2784ddf2c268e2a2ea1ceab1e35def2d81293227d91da1ffc2504fc2101711dccc47242c5aabab811dfc04", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01edee50b7f072fc34dd6b337cbc25f31b38ad4b76609ca05d3e0ed464bfcce43eaf9ff5d5685bd20f6be191177fb3ef48ce892c89c16540e67da8face85702f00", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f37a1537b47a5c258984acf00724d0166b09a7c282ecb5facb355aaab659d1c1d66aee63fb1dab6eb39667462aefbbcff2c037a9069eeee95d710fe603c96c0c", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01dd313aa8cf069742b71a7607052aaaed0eb0c5a1b853caf9d4cb4620eaf6922859c33745f27e206a032cc9b4dd8e58cb767c7fdda1533ead09f22a0e42560f01", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "012f6a17c7ce971c07ce80b3a9f145e90ff25162e1b87b75b9e3f7469dd353cef6ca7b4e7551d1a63453042bbd054306773a67ce3e406204cfec42338d5d7f4a05" + "V1": { + "block_hash": "6f386926f07ad93d0a9330d20ddea32f22596cb5c6ac96e81fcc32dc164c26a9", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "018ff5d691f249abbbecbb932e09f5b6875ddab8ffac2784ddf2c268e2a2ea1ceab1e35def2d81293227d91da1ffc2504fc2101711dccc47242c5aabab811dfc04", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01edee50b7f072fc34dd6b337cbc25f31b38ad4b76609ca05d3e0ed464bfcce43eaf9ff5d5685bd20f6be191177fb3ef48ce892c89c16540e67da8face85702f00", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f37a1537b47a5c258984acf00724d0166b09a7c282ecb5facb355aaab659d1c1d66aee63fb1dab6eb39667462aefbbcff2c037a9069eeee95d710fe603c96c0c", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01dd313aa8cf069742b71a7607052aaaed0eb0c5a1b853caf9d4cb4620eaf6922859c33745f27e206a032cc9b4dd8e58cb767c7fdda1533ead09f22a0e42560f01", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "012f6a17c7ce971c07ce80b3a9f145e90ff25162e1b87b75b9e3f7469dd353cef6ca7b4e7551d1a63453042bbd054306773a67ce3e406204cfec42338d5d7f4a05" + } } }, "deploy_hashes": [ @@ -940,14 +1038,16 @@ "era": 7, "approvals_hashes": null, "signatures": { - "block_hash": "5bcd384899f8d5a0c05a73b8e77e7276084b06a0d18e8b8196bbc79886d36408", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01e5706817fe115d655ce3bdbcc39d3205ab630cb7de6022596156971d9e114990415a957060d43963df17147473ace84263eea39a4b24858967dc0a4bfaa4e105", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01dc75709ba51fb806fc2b5e58af0be5e3c7f324a4dae46a70145eac0e3fe6fda1420ba7f4c8de2d5e9782870e157fd0a663f3cbd465edeb66ce324dd030a9b60e", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f38c71752cece41707687655c25baa20da9312bbfc975f9006cfba58a1c7133228291347e7e1bc2188eac4332bca8dca7bbe3877bac4efee1d3a485bc59d5c05", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "019aae6cd225ef80c5bda0459cc7537b856b814b7eac74d9751072474534fc9b4179ef740d65b067e2329da274ea1adbb4f29964c83914600a51e6fe0ed5c5f004", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01c88ef5480217a1a3877a1b173867993134174ade09d47689b70903a8f7b373df9e9ccb79867f96db7b6312148fa2a975617cd3249c9da25bbaa8709803d3ea09" + "V1": { + "block_hash": "5bcd384899f8d5a0c05a73b8e77e7276084b06a0d18e8b8196bbc79886d36408", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01e5706817fe115d655ce3bdbcc39d3205ab630cb7de6022596156971d9e114990415a957060d43963df17147473ace84263eea39a4b24858967dc0a4bfaa4e105", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01dc75709ba51fb806fc2b5e58af0be5e3c7f324a4dae46a70145eac0e3fe6fda1420ba7f4c8de2d5e9782870e157fd0a663f3cbd465edeb66ce324dd030a9b60e", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01f38c71752cece41707687655c25baa20da9312bbfc975f9006cfba58a1c7133228291347e7e1bc2188eac4332bca8dca7bbe3877bac4efee1d3a485bc59d5c05", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "019aae6cd225ef80c5bda0459cc7537b856b814b7eac74d9751072474534fc9b4179ef740d65b067e2329da274ea1adbb4f29964c83914600a51e6fe0ed5c5f004", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01c88ef5480217a1a3877a1b173867993134174ade09d47689b70903a8f7b373df9e9ccb79867f96db7b6312148fa2a975617cd3249c9da25bbaa8709803d3ea09" + } } }, "deploy_hashes": [] @@ -957,14 +1057,16 @@ "era": 4, "approvals_hashes": null, "signatures": { - "block_hash": "7438b956bfcde6a2d7ba7dfc16877f6a317350e6dfec7242c6213988770b1b36", - "era_id": 4, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0109106bc12a79112245151aa5aa8d0f2c9c988cb2dc6d620288c58686e6a523372579b3dac27401e59765e0dc491fc0dedb0e3aa989bb0a2a8f50cb312fbfe507", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013aac1eb740575433812580497dd9ce79a9d7c88233a75f8bfda086973539a91f47eba7f473c175af5b53945b5c7f717e52604fcd45d9fda02a4f3e381ce7ad07", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01d5644ed7210c70c4f43f48b309928e90142b460baca1cc1c37228120d97ccc5c63b057b75ff58c4bc97ed25358aefa563ac27aa4f390b28f172bce1be66c560a", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "010ea241ab144f62c7d527fc61bd95e32a2c3ab0a63a2356d1422c5ad99b49b83a76b7b771ebfedd3324436bd877b7f9753b5eee5ed8e1e667017d3c56484f400a", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "012bbb276ec8b5badbf2bc05517c12d7807db0aa5d01f133ebc33c4f1d783a5cbcbf51b6ca6355ae26d06e0166f02f42584ec46ba8f4368a519f492d2124e6d30d" + "V1": { + "block_hash": "7438b956bfcde6a2d7ba7dfc16877f6a317350e6dfec7242c6213988770b1b36", + "era_id": 4, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0109106bc12a79112245151aa5aa8d0f2c9c988cb2dc6d620288c58686e6a523372579b3dac27401e59765e0dc491fc0dedb0e3aa989bb0a2a8f50cb312fbfe507", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "013aac1eb740575433812580497dd9ce79a9d7c88233a75f8bfda086973539a91f47eba7f473c175af5b53945b5c7f717e52604fcd45d9fda02a4f3e381ce7ad07", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01d5644ed7210c70c4f43f48b309928e90142b460baca1cc1c37228120d97ccc5c63b057b75ff58c4bc97ed25358aefa563ac27aa4f390b28f172bce1be66c560a", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "010ea241ab144f62c7d527fc61bd95e32a2c3ab0a63a2356d1422c5ad99b49b83a76b7b771ebfedd3324436bd877b7f9753b5eee5ed8e1e667017d3c56484f400a", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "012bbb276ec8b5badbf2bc05517c12d7807db0aa5d01f133ebc33c4f1d783a5cbcbf51b6ca6355ae26d06e0166f02f42584ec46ba8f4368a519f492d2124e6d30d" + } } }, "deploy_hashes": [] @@ -974,14 +1076,16 @@ "era": 7, "approvals_hashes": null, "signatures": { - "block_hash": "327321d3af7a7c7ab1a71ba11bc72f144be0c87a09d92cce6adc4be37f7877e0", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0133a8c2e506191a0851cdbee9ba3723a5437786c313c1e2b29f7f6218babd36aa003dfc3ec8a9e579720f96bc6fe55e30c5d01e9fe2f6b3ed74d671437a41060a", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0138afc27d809fd593127b76fc806750183f0ecf975b2cf8035357c129cbe4992afc333eeda56ee80a950df8537a581658e3a79e139dafcdee4514ce7014620801", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "019f96974fd00d6f42de44ec0fbae92a6b994a9ccb76e2dd6704faa99abfaadf2017ea44ee5e7da6f83d920828319052e99a0d8351223b6da084da425930e6af0e", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f02c2a88fddda27a7f71248a2bd3660e38670079b51ef93df19a78dca7f1e0dfacb2dbd3b372393463673f57189185d9b36140f0695b3e1fffff0f7b195d4c07", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "016805140ea5322148483659d822673c4740c56d8af711049fc6fa5e612286847cef550dea8853b46e2cc73d3994f051ed86c18f65251fbbec2eb78e7a5d74660a" + "V1": { + "block_hash": "327321d3af7a7c7ab1a71ba11bc72f144be0c87a09d92cce6adc4be37f7877e0", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "0133a8c2e506191a0851cdbee9ba3723a5437786c313c1e2b29f7f6218babd36aa003dfc3ec8a9e579720f96bc6fe55e30c5d01e9fe2f6b3ed74d671437a41060a", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0138afc27d809fd593127b76fc806750183f0ecf975b2cf8035357c129cbe4992afc333eeda56ee80a950df8537a581658e3a79e139dafcdee4514ce7014620801", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "019f96974fd00d6f42de44ec0fbae92a6b994a9ccb76e2dd6704faa99abfaadf2017ea44ee5e7da6f83d920828319052e99a0d8351223b6da084da425930e6af0e", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01f02c2a88fddda27a7f71248a2bd3660e38670079b51ef93df19a78dca7f1e0dfacb2dbd3b372393463673f57189185d9b36140f0695b3e1fffff0f7b195d4c07", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "016805140ea5322148483659d822673c4740c56d8af711049fc6fa5e612286847cef550dea8853b46e2cc73d3994f051ed86c18f65251fbbec2eb78e7a5d74660a" + } } }, "deploy_hashes": [] @@ -991,14 +1095,16 @@ "era": 8, "approvals_hashes": null, "signatures": { - "block_hash": "f50447de37b23c28f4133fc2cde2c772bce0af1e49d76690532b614af1d0e33c", - "era_id": 8, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01ff02b2ddda99b82fdf9be6215156af4eb61f8e43d0a4039969499352ac1eaee59ef9e435cb6a0128af12b11408e19f1377416c2851daab569f93ea09ec68ab03", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a9baa6a882daa9f3b71ba60a833a67509f1f29234b2645db1fa611907690677d840691692c263cec187bf017755cdc3193fe85e8f4c2209633d02459c3b1e10b", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01be743da4a9a8185972a40e46b624aa9e979f50d8153bb82a19db559abfc25823cae65d9e1beb0d5399c9ba5c6f3902025d524e46bccb6799cd5fec4c83687f06", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01c08b376e860b67b7f1fd81e5f631d8d9b2fa12652153b4d4f7495d12875cd6ef5db500a4c899113b0fc3ba2c0c0f5d0044064b7d94c9c411abea58e72129450a", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0199ec9093a7114f833fad696893d9ef4d2d98b11491b0fb7add9ae5b3801bc0d9caf471a3e4baf08e78563810f32da0615118c579261a057126abcf8ea447d10a" + "V1": { + "block_hash": "f50447de37b23c28f4133fc2cde2c772bce0af1e49d76690532b614af1d0e33c", + "era_id": 8, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01ff02b2ddda99b82fdf9be6215156af4eb61f8e43d0a4039969499352ac1eaee59ef9e435cb6a0128af12b11408e19f1377416c2851daab569f93ea09ec68ab03", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01a9baa6a882daa9f3b71ba60a833a67509f1f29234b2645db1fa611907690677d840691692c263cec187bf017755cdc3193fe85e8f4c2209633d02459c3b1e10b", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01be743da4a9a8185972a40e46b624aa9e979f50d8153bb82a19db559abfc25823cae65d9e1beb0d5399c9ba5c6f3902025d524e46bccb6799cd5fec4c83687f06", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01c08b376e860b67b7f1fd81e5f631d8d9b2fa12652153b4d4f7495d12875cd6ef5db500a4c899113b0fc3ba2c0c0f5d0044064b7d94c9c411abea58e72129450a", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0199ec9093a7114f833fad696893d9ef4d2d98b11491b0fb7add9ae5b3801bc0d9caf471a3e4baf08e78563810f32da0615118c579261a057126abcf8ea447d10a" + } } }, "deploy_hashes": [] @@ -1012,14 +1118,16 @@ "04379f664120d7d140880706c6b3bac23211376e792e02343339b6e89c8fc524" ], "signatures": { - "block_hash": "d08662b263ca4651b9bd64fbcd3f70f47b5c6ce9ee64115cc52b8b03852bd41f", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "016f901233dc957cb9cacd2d90007997afc8a7bd63d937e7690d69eefeb9d5eeb1505a201ff67aa4f4990f71cb2f8b0668b9b9b37d56e5141071c76e0a6bc55a0f", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0152826f8a87e6209ccb6f19710e932c21fd1bfd1ce35a23eb5122c5128ddbc22987df7808e9ba183f0443fbbd7d492fb1416b07ec6ff464dea68f1c4c377f5903", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "012260ca9f54fc49cf678608f7b7182ed837054ee7845f981c3c246ca4bc309452727c727eef5cd8361002f8e83b1e527b947eacb78721259ed3760e4cb858c902", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0140301844864cac3b64377783c7eeb72f5fcf25390d14aabc8395fc78eb42d5d392ffc7d782bdbaf630dac750cc41520a6ca7476e61bc00dc69e4e35967915c0f", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0168af3aef7194e69365d59426af9febec01748061139f9e871e49f07ff8bb556c48bdd6b964b52a3e7c15f79e736cf26d2a112465c6f55b14282afc501e0d930e" + "V1": { + "block_hash": "d08662b263ca4651b9bd64fbcd3f70f47b5c6ce9ee64115cc52b8b03852bd41f", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "016f901233dc957cb9cacd2d90007997afc8a7bd63d937e7690d69eefeb9d5eeb1505a201ff67aa4f4990f71cb2f8b0668b9b9b37d56e5141071c76e0a6bc55a0f", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0152826f8a87e6209ccb6f19710e932c21fd1bfd1ce35a23eb5122c5128ddbc22987df7808e9ba183f0443fbbd7d492fb1416b07ec6ff464dea68f1c4c377f5903", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "012260ca9f54fc49cf678608f7b7182ed837054ee7845f981c3c246ca4bc309452727c727eef5cd8361002f8e83b1e527b947eacb78721259ed3760e4cb858c902", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0140301844864cac3b64377783c7eeb72f5fcf25390d14aabc8395fc78eb42d5d392ffc7d782bdbaf630dac750cc41520a6ca7476e61bc00dc69e4e35967915c0f", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0168af3aef7194e69365d59426af9febec01748061139f9e871e49f07ff8bb556c48bdd6b964b52a3e7c15f79e736cf26d2a112465c6f55b14282afc501e0d930e" + } } }, "deploy_hashes": [ @@ -1033,14 +1141,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "d760a41123785884162e45edfb1401603c60714c6cc79cad915387640b3c7c80", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "014a69d3c75ca2cff5cc25aed853d355adbae83609646c26b19c6837a4905db46e15064751a4a2253ddb231ca1ae18c8f5b88dcd48dd7ea9385b0d9befd6f4e40b", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01162d57c9602c3bc3387e1d01cfd9f112dc592ad7d763505962c57753e5f2bceeb8fe3766e17b0dcb9e059e127263c12415b08a75a7cafb03a1736c521c7b2e0d", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "013e252c82dd7f7deee6afa749a24cbd0792364d79354b1a1cc7b364a42d518d681ea15ca18a61dd90ae3cd2c3107996b1c59218c341ab400ad09ce54f12dae608", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "013c5fe5a70327570dc4f6a835ca353b95939a3e96678151d7e7d49bc7401feac63916c6d4a86dff1f97e5cc83e70fdafaef455cc0666bc73505b6e8a192c2f70d", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01e4cc1ec44a703b1a0b8a7b93f75ef0023f38c33e545b1263637470f8c2804c5d09bac20ae122dafca70a439353cc69f5e8518b9f8065bbd95371dcf97f892d02" + "V1": { + "block_hash": "d760a41123785884162e45edfb1401603c60714c6cc79cad915387640b3c7c80", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "014a69d3c75ca2cff5cc25aed853d355adbae83609646c26b19c6837a4905db46e15064751a4a2253ddb231ca1ae18c8f5b88dcd48dd7ea9385b0d9befd6f4e40b", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01162d57c9602c3bc3387e1d01cfd9f112dc592ad7d763505962c57753e5f2bceeb8fe3766e17b0dcb9e059e127263c12415b08a75a7cafb03a1736c521c7b2e0d", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "013e252c82dd7f7deee6afa749a24cbd0792364d79354b1a1cc7b364a42d518d681ea15ca18a61dd90ae3cd2c3107996b1c59218c341ab400ad09ce54f12dae608", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "013c5fe5a70327570dc4f6a835ca353b95939a3e96678151d7e7d49bc7401feac63916c6d4a86dff1f97e5cc83e70fdafaef455cc0666bc73505b6e8a192c2f70d", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01e4cc1ec44a703b1a0b8a7b93f75ef0023f38c33e545b1263637470f8c2804c5d09bac20ae122dafca70a439353cc69f5e8518b9f8065bbd95371dcf97f892d02" + } } }, "deploy_hashes": [] @@ -1050,14 +1160,16 @@ "era": 6, "approvals_hashes": null, "signatures": { - "block_hash": "8af440e30a8a0f3959f6504b19fe387a62d2b021c28862afbfd97707f6e1ef6c", - "era_id": 6, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01a93fa7ed0fa5008c81ddca9dc760875a9bd84eba5c4ca561bb8e7434bb1a89b6d22fe129dd5bac3c68fa941e6d4dd0fc8f29bec15a0d78c9862db91b0a0b2e0f", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01407ba0fe0b7e70211bef8b39fd27f5edf4d2e3aff02194dbefcf9f734821255f3fb9cd0662f1192197375ca22c56499935e0fc5816df9df1bdefa67d62cdc00c", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0140f7c24cd4ee18805778359f799451d5a4da6b70026a92144e60bacdc6b603b884d486fc2072e13616049f56974823fc5d1e07553d08fbda583e1118eccc2404", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01ec88cba12e12a6de4e49e81cb5bbcafaae69b5a9e25991cc848700586920aa1aebe78a1545ef59929e37575d6211fdd9f660dbea6a692a669d82457b419f9802", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0135ab7477aed57f31f7211ef9302e963a4b071346fe6956ad5518241f472b3fb3d469df0aae58b3c27e396775a908ea9a60ddb94c7bc3c0689f04fb3d65f92200" + "V1": { + "block_hash": "8af440e30a8a0f3959f6504b19fe387a62d2b021c28862afbfd97707f6e1ef6c", + "era_id": 6, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01a93fa7ed0fa5008c81ddca9dc760875a9bd84eba5c4ca561bb8e7434bb1a89b6d22fe129dd5bac3c68fa941e6d4dd0fc8f29bec15a0d78c9862db91b0a0b2e0f", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01407ba0fe0b7e70211bef8b39fd27f5edf4d2e3aff02194dbefcf9f734821255f3fb9cd0662f1192197375ca22c56499935e0fc5816df9df1bdefa67d62cdc00c", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "0140f7c24cd4ee18805778359f799451d5a4da6b70026a92144e60bacdc6b603b884d486fc2072e13616049f56974823fc5d1e07553d08fbda583e1118eccc2404", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01ec88cba12e12a6de4e49e81cb5bbcafaae69b5a9e25991cc848700586920aa1aebe78a1545ef59929e37575d6211fdd9f660dbea6a692a669d82457b419f9802", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0135ab7477aed57f31f7211ef9302e963a4b071346fe6956ad5518241f472b3fb3d469df0aae58b3c27e396775a908ea9a60ddb94c7bc3c0689f04fb3d65f92200" + } } }, "deploy_hashes": [] @@ -1067,14 +1179,16 @@ "era": 7, "approvals_hashes": null, "signatures": { - "block_hash": "8952435b382f2e66462b4e04cc17b67b80a978bfef4a57b2fdc465839890f240", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "012a5ae2665f218cbe7e70e0a5a3da0e612b93eba6abb900a77279b98121ea26ebbf973e44e6dacfcf3c028d04c061ff31023f63af0b50705dd6b2d845a438e80a", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018241745d90073634de1705af754d7227a4d37056077c4d2b136309feccd7faa0c76174a185b9a2b69cc1d03fff38debcb34bfeeb2088f6a2204eaac480748608", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01bfdce3909d4474e2cb2feea13de1d4597d1ad0cdee56713fe48aac8e2550267eff2032ff1a34b9454398f0c9685e10ee9bddff9ff2e6edb27dbb0dfd91df610e", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01cfbaba578f82a6f6f5bb3336b6d2c7288d6e704a5b1d92348a2ece3cbe1b52258424dfbf414905f415a9a10469b1d117e582c4bb97c19bdc4c5b4a6063468808", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01844e70fea67d5a715dc65d099fcd25e7bc60bf98f884bc416f735514596dba83d1fbceaebb29768ef1075d941cb66806f19634ccde8f777aa7408d319410fe0d" + "V1": { + "block_hash": "8952435b382f2e66462b4e04cc17b67b80a978bfef4a57b2fdc465839890f240", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "012a5ae2665f218cbe7e70e0a5a3da0e612b93eba6abb900a77279b98121ea26ebbf973e44e6dacfcf3c028d04c061ff31023f63af0b50705dd6b2d845a438e80a", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "018241745d90073634de1705af754d7227a4d37056077c4d2b136309feccd7faa0c76174a185b9a2b69cc1d03fff38debcb34bfeeb2088f6a2204eaac480748608", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01bfdce3909d4474e2cb2feea13de1d4597d1ad0cdee56713fe48aac8e2550267eff2032ff1a34b9454398f0c9685e10ee9bddff9ff2e6edb27dbb0dfd91df610e", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01cfbaba578f82a6f6f5bb3336b6d2c7288d6e704a5b1d92348a2ece3cbe1b52258424dfbf414905f415a9a10469b1d117e582c4bb97c19bdc4c5b4a6063468808", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01844e70fea67d5a715dc65d099fcd25e7bc60bf98f884bc416f735514596dba83d1fbceaebb29768ef1075d941cb66806f19634ccde8f777aa7408d319410fe0d" + } } }, "deploy_hashes": [] @@ -1084,14 +1198,16 @@ "era": 7, "approvals_hashes": null, "signatures": { - "block_hash": "ee09fa098a05f4fb6db77d700805389d4c099e09a7fe44cda0ca3baacf78c150", - "era_id": 7, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01bcab36324f166cfe835ac4e7e3b87798eba274c89aa27f89f694382f6aed169ec15b9c2326b9ac57ec2a020a6c75ebb258000a6a16f7fcb2a659f293c51b480a", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ad6e3cdbcba3ba61cb69d7fe0849765554cde2b6ab03ca1bd5efc4a87ad9347d131b55b15e312e768702625d9a7784ba3091e062d038a2fc7ece027b5d96740b", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "013520068954881e81331a299ad2143b6dfb3ce929e01f8f1ac2927a571fbcd28867cbaf9cb029571e59206b9f508644b9ef200ce0cd26eadfd62cd2767f213209", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "014fe6a703b2dd02d13b33fe43b3d8684ad71c98f543778aec5365c61a1ae0a0646bc29a52c268d2a3dcde9d7f61cd82a4ab4e3f8df94309a277b1b77536ba610e", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0153e3f03cd865894151085dcbb843837e909bc9145196ee4334b1b40fcfb91c12a950fdb0fd56d56344d03eb921750da89bce51e15b3314103a2b6e7a17364e04" + "V1": { + "block_hash": "ee09fa098a05f4fb6db77d700805389d4c099e09a7fe44cda0ca3baacf78c150", + "era_id": 7, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01bcab36324f166cfe835ac4e7e3b87798eba274c89aa27f89f694382f6aed169ec15b9c2326b9ac57ec2a020a6c75ebb258000a6a16f7fcb2a659f293c51b480a", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "01ad6e3cdbcba3ba61cb69d7fe0849765554cde2b6ab03ca1bd5efc4a87ad9347d131b55b15e312e768702625d9a7784ba3091e062d038a2fc7ece027b5d96740b", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "013520068954881e81331a299ad2143b6dfb3ce929e01f8f1ac2927a571fbcd28867cbaf9cb029571e59206b9f508644b9ef200ce0cd26eadfd62cd2767f213209", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "014fe6a703b2dd02d13b33fe43b3d8684ad71c98f543778aec5365c61a1ae0a0646bc29a52c268d2a3dcde9d7f61cd82a4ab4e3f8df94309a277b1b77536ba610e", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "0153e3f03cd865894151085dcbb843837e909bc9145196ee4334b1b40fcfb91c12a950fdb0fd56d56344d03eb921750da89bce51e15b3314103a2b6e7a17364e04" + } } }, "deploy_hashes": [] @@ -1101,14 +1217,16 @@ "era": 5, "approvals_hashes": null, "signatures": { - "block_hash": "89af4615b4254df1d8af49becad7e998e4b296d1cb0cfea07524a0fd1589223b", - "era_id": 5, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "015e07a579305638638cfe266b6e2e1f11d1bc8b07a615173f688cf9e7df0584b8265a689d722b52ed10bc7f0d75fa0e7c1036f35392fd3ea6439c40e241157203", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0187f05e9224380f0f81fa77d36f74c36cd39eaa711b46bb4b4b8978ec5690adc1208052ba43b5755368817290615481a09d044da2b9872cad2fcc024392138a03", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01115c591b8f77c142304e682b0517dac6128eb27bbcf83f849f9f77a67480410cf7948bd48f956fe18628224cf2bc319b50fb1916d979068990fc8892774dde09", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01816d3e9cf8836ece45c7a54dd2372deffc416ef0af03f508f5fe210b78debb7196f01d28e5a92cc0c9b5919eecdb48d1ed87698ae1b210ca06a3596f2f6b320e", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "019cc260438112197ff50d777a2d4bf83920ecc317a293affe5cafbf6794bb09d9b32d6515cab233668d76d8efea5c53c018c75a82a73fc86f9c7add1e4ba82602" + "V1": { + "block_hash": "89af4615b4254df1d8af49becad7e998e4b296d1cb0cfea07524a0fd1589223b", + "era_id": 5, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "015e07a579305638638cfe266b6e2e1f11d1bc8b07a615173f688cf9e7df0584b8265a689d722b52ed10bc7f0d75fa0e7c1036f35392fd3ea6439c40e241157203", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "0187f05e9224380f0f81fa77d36f74c36cd39eaa711b46bb4b4b8978ec5690adc1208052ba43b5755368817290615481a09d044da2b9872cad2fcc024392138a03", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "01115c591b8f77c142304e682b0517dac6128eb27bbcf83f849f9f77a67480410cf7948bd48f956fe18628224cf2bc319b50fb1916d979068990fc8892774dde09", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "01816d3e9cf8836ece45c7a54dd2372deffc416ef0af03f508f5fe210b78debb7196f01d28e5a92cc0c9b5919eecdb48d1ed87698ae1b210ca06a3596f2f6b320e", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "019cc260438112197ff50d777a2d4bf83920ecc317a293affe5cafbf6794bb09d9b32d6515cab233668d76d8efea5c53c018c75a82a73fc86f9c7add1e4ba82602" + } } }, "deploy_hashes": [] @@ -1118,14 +1236,16 @@ "era": 9, "approvals_hashes": [], "signatures": { - "block_hash": "3de15c392cd63c17e53fcbdbb6ff544d86016bcee9b79e79f63f33ac14c489f9", - "era_id": 9, - "proofs": { - "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01f9c5bd4be0acf631e5bf9cfb1e9588aeef2fe0d6965d79b5496257dc06d4261e85e9ff0960a95d13313c268d2adb49b57bd77b34185d3636f22e89cb7fed3508", - "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "011561b7700db49c4d2c4915c7af51c8c018b29d5180b954db947b51c095915e322698dbdd035cf82aac82e3f415256eb728ccd5e1e9fce91517320f38bf4e8b05", - "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "017498f7a7c23d2205f47fe8cb1492bf7975ed80ad81e9b9e4e6de97de685cdeb7b0a422114a84b10e025d90f61327010b0c9644ec12a689dbb07fc1eccb340a0e", - "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0156a5c0ef6d96b450d16248a65c68668852fc32429a859b8af29d81c9c28839f6ad2f2b872434cb6d6a6a447b21364f9b79d5026c44113d131152725a1dc6f10f", - "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01fa32312fadb626abc4ff34692e05016d71b2cc5586332060c94cdacd1bd2060af1694f9cb42514b4816aea1ea6e644160bcf5b8bce67b505107e9220565ba901" + "V1": { + "block_hash": "3de15c392cd63c17e53fcbdbb6ff544d86016bcee9b79e79f63f33ac14c489f9", + "era_id": 9, + "proofs": { + "0141a6deb6cb64ff1cfd2c1e1c360253f916f6f26f0e1e056571ab27dfac988f92": "01f9c5bd4be0acf631e5bf9cfb1e9588aeef2fe0d6965d79b5496257dc06d4261e85e9ff0960a95d13313c268d2adb49b57bd77b34185d3636f22e89cb7fed3508", + "016fd7ba314c3ecf97dd518a94a6e087eafe8456bf1760e50b6e3e8e633149987c": "011561b7700db49c4d2c4915c7af51c8c018b29d5180b954db947b51c095915e322698dbdd035cf82aac82e3f415256eb728ccd5e1e9fce91517320f38bf4e8b05", + "019714c55306f3870ae7f781885eef9de8239da028205c6d18b90598e6637b7523": "017498f7a7c23d2205f47fe8cb1492bf7975ed80ad81e9b9e4e6de97de685cdeb7b0a422114a84b10e025d90f61327010b0c9644ec12a689dbb07fc1eccb340a0e", + "01ac4faea6049265220b355cf81cc3dff9ffdfe8a050525815e14d5cfe82a14cc4": "0156a5c0ef6d96b450d16248a65c68668852fc32429a859b8af29d81c9c28839f6ad2f2b872434cb6d6a6a447b21364f9b79d5026c44113d131152725a1dc6f10f", + "01e048d866c65abc1d83b632dfd1760d43581e1109d52837e6d4679cc298387fca": "01fa32312fadb626abc4ff34692e05016d71b2cc5586332060c94cdacd1bd2060af1694f9cb42514b4816aea1ea6e644160bcf5b8bce67b505107e9220565ba901" + } } }, "deploy_hashes": [] From 8302a6255184fb5a16e5e7b5ee124508d2896be8 Mon Sep 17 00:00:00 2001 From: Jacek Malec <145967538+jacek-casper@users.noreply.github.com> Date: Thu, 22 Feb 2024 12:37:48 +0000 Subject: [PATCH 5/7] Address comments --- .../components/block_synchronizer/tests.rs | 2 +- node/src/components/network/limiter.rs | 4 +- node/src/components/storage.rs | 9 ++--- node/src/types/validator_matrix.rs | 4 +- node/src/utils/specimen.rs | 5 ++- types/src/block/block_signatures.rs | 26 ++++++++++++ .../block_signatures/block_signatures_v1.rs | 36 +++++++++++++++++ .../block_signatures/block_signatures_v2.rs | 40 +++++++++++++++++++ types/src/block/chain_name_digest.rs | 14 +++---- .../finality_signature_v2.rs | 4 +- types/src/chainspec.rs | 2 +- 11 files changed, 123 insertions(+), 23 deletions(-) diff --git a/node/src/components/block_synchronizer/tests.rs b/node/src/components/block_synchronizer/tests.rs index d95c9099ad..15fec86711 100644 --- a/node/src/components/block_synchronizer/tests.rs +++ b/node/src/components/block_synchronizer/tests.rs @@ -147,7 +147,7 @@ impl TestEnv { // Set up a validator matrix for the era in which our test block was created let mut validator_matrix = ValidatorMatrix::new( Ratio::new(1, 3), - ChainNameDigest::new(Digest::hash(b"casper-example")), + ChainNameDigest::from_chain_name("casper-example"), None, EraId::from(0), self.validator_keys[0].clone(), diff --git a/node/src/components/network/limiter.rs b/node/src/components/network/limiter.rs index 4bc0c4256a..8bd616f3da 100644 --- a/node/src/components/network/limiter.rs +++ b/node/src/components/network/limiter.rs @@ -293,7 +293,7 @@ struct ConsumerId { mod tests { use std::{sync::Arc, time::Duration}; - use casper_types::{ChainNameDigest, Digest, EraId, SecretKey}; + use casper_types::{ChainNameDigest, EraId, SecretKey}; use num_rational::Ratio; use prometheus::Counter; use tokio::time::Instant; @@ -460,7 +460,7 @@ mod tests { wait_metric.clone(), ValidatorMatrix::new( Ratio::new(1, 3), - ChainNameDigest::new(Digest::hash(b"casper-example")), + ChainNameDigest::from_chain_name("casper-example"), None, EraId::from(0), Arc::new(secret_key), diff --git a/node/src/components/storage.rs b/node/src/components/storage.rs index f5b970865f..48e81ae9ba 100644 --- a/node/src/components/storage.rs +++ b/node/src/components/storage.rs @@ -477,7 +477,7 @@ impl Storage { recent_era_count, max_ttl, metrics, - chain_name_hash: ChainNameDigest::new(Digest::hash(network_name.as_bytes())), + chain_name_hash: ChainNameDigest::from_chain_name(network_name), }; if force_resync { @@ -1309,10 +1309,9 @@ impl Storage { block_signatures .insert_signature(signature.public_key().clone(), *signature.signature()); } - (_, signature) => { - return Err(FatalStorageError::VariantMismatch(VariantMismatch( - Box::new(*signature.block_hash()), - ))); + (block_signatures, signature) => { + let mismatch = VariantMismatch(Box::new((block_signatures.clone(), signature))); + return Err(FatalStorageError::from(mismatch)); } } let outcome = self.block_metadata_dbs.put( diff --git a/node/src/types/validator_matrix.rs b/node/src/types/validator_matrix.rs index 616140ca6a..aef7e27ecc 100644 --- a/node/src/types/validator_matrix.rs +++ b/node/src/types/validator_matrix.rs @@ -81,8 +81,6 @@ impl ValidatorMatrix { /// Creates a new validator matrix with just a single validator. #[cfg(test)] pub(crate) fn new_with_validator(secret_signing_key: Arc) -> Self { - use casper_types::Digest; - let public_signing_key = PublicKey::from(&*secret_signing_key); let finality_threshold_fraction = Ratio::new(1, 3); let era_id = EraId::new(0); @@ -93,7 +91,7 @@ impl ValidatorMatrix { ); ValidatorMatrix { inner: Arc::new(RwLock::new(iter::once((era_id, weights)).collect())), - chainspec_name_hash: ChainNameDigest::new(Digest::hash(b"casper-example")), + chainspec_name_hash: ChainNameDigest::from_chain_name("casper-example"), chainspec_validators: None, chainspec_activation_era: EraId::from(0), finality_threshold_fraction, diff --git a/node/src/utils/specimen.rs b/node/src/utils/specimen.rs index 34883409e3..9e4dc9f62e 100644 --- a/node/src/utils/specimen.rs +++ b/node/src/utils/specimen.rs @@ -779,8 +779,9 @@ impl LargestSpecimen for BlockHash { } impl LargestSpecimen for ChainNameDigest { - fn largest_specimen(estimator: &E, cache: &mut Cache) -> Self { - ChainNameDigest::new(LargestSpecimen::largest_specimen(estimator, cache)) + fn largest_specimen(_estimator: &E, _cache: &mut Cache) -> Self { + // ChainNameDigest is fixed size by definition, so any value will do. + ChainNameDigest::from_chain_name("") } } diff --git a/types/src/block/block_signatures.rs b/types/src/block/block_signatures.rs index afb2d93688..df9fde4f85 100644 --- a/types/src/block/block_signatures.rs +++ b/types/src/block/block_signatures.rs @@ -15,9 +15,13 @@ use std::error::Error as StdError; #[cfg(feature = "datasize")] use datasize::DataSize; +#[cfg(any(feature = "testing", test))] +use rand::Rng; #[cfg(any(feature = "std", test))] use serde::{Deserialize, Serialize}; +#[cfg(any(feature = "testing", test))] +use crate::testing::TestRng; use crate::{ bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH}, crypto, BlockHash, ChainNameDigest, EraId, FinalitySignature, PublicKey, Signature, @@ -228,6 +232,16 @@ impl BlockSignatures { .expect("should have at least one signature"); *last_proof.into_mut() = Signature::System; } + + /// Returns a random `BlockSignatures`. + #[cfg(any(feature = "testing", test))] + pub fn random(rng: &mut TestRng) -> Self { + if rng.gen() { + BlockSignatures::V1(BlockSignaturesV1::random(rng)) + } else { + BlockSignatures::V2(BlockSignaturesV2::random(rng)) + } + } } impl Display for BlockSignatures { @@ -393,3 +407,15 @@ impl Display for BlockSignaturesMergeError { #[cfg(feature = "std")] impl StdError for BlockSignaturesMergeError {} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bytesrepr_roundtrip() { + let rng = &mut TestRng::new(); + let hash = BlockSignatures::random(rng); + bytesrepr::test_serialization_roundtrip(&hash); + } +} diff --git a/types/src/block/block_signatures/block_signatures_v1.rs b/types/src/block/block_signatures/block_signatures_v1.rs index 2bdcfa0efc..46ee155b3c 100644 --- a/types/src/block/block_signatures/block_signatures_v1.rs +++ b/types/src/block/block_signatures/block_signatures_v1.rs @@ -3,10 +3,14 @@ use core::fmt::{self, Display, Formatter}; #[cfg(feature = "datasize")] use datasize::DataSize; +#[cfg(any(feature = "testing", test))] +use rand::Rng; #[cfg(any(feature = "std", test))] use serde::{Deserialize, Serialize}; use super::BlockHash; +#[cfg(any(feature = "testing", test))] +use crate::testing::TestRng; use crate::{ bytesrepr::{self, FromBytes, ToBytes}, crypto, EraId, FinalitySignatureV1, PublicKey, Signature, @@ -114,6 +118,26 @@ impl BlockSignaturesV1 { } Ok(()) } + + /// Returns a random `BlockSignaturesV1`. + #[cfg(any(feature = "testing", test))] + pub fn random(rng: &mut TestRng) -> Self { + let block_hash = BlockHash::random(rng); + let era_id = EraId::random(rng); + let proofs = (0..rng.gen_range(0..10)) + .map(|_| { + let public_key = PublicKey::random(rng); + let bytes = std::array::from_fn(|_| rng.gen()); + let signature = Signature::ed25519(bytes).unwrap(); + (public_key, signature) + }) + .collect(); + Self { + block_hash, + era_id, + proofs, + } + } } impl Display for BlockSignaturesV1 { @@ -163,3 +187,15 @@ impl FromBytes for BlockSignaturesV1 { )) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bytesrepr_roundtrip() { + let rng = &mut TestRng::new(); + let hash = BlockSignaturesV1::random(rng); + bytesrepr::test_serialization_roundtrip(&hash); + } +} diff --git a/types/src/block/block_signatures/block_signatures_v2.rs b/types/src/block/block_signatures/block_signatures_v2.rs index 1bdc1861f7..19371381c6 100644 --- a/types/src/block/block_signatures/block_signatures_v2.rs +++ b/types/src/block/block_signatures/block_signatures_v2.rs @@ -3,9 +3,13 @@ use core::fmt::{self, Display, Formatter}; #[cfg(feature = "datasize")] use datasize::DataSize; +#[cfg(any(feature = "testing", test))] +use rand::Rng; #[cfg(any(feature = "std", test))] use serde::{Deserialize, Serialize}; +#[cfg(any(feature = "testing", test))] +use crate::testing::TestRng; use crate::{ bytesrepr::{self, FromBytes, ToBytes}, crypto, BlockHash, ChainNameDigest, EraId, FinalitySignatureV2, PublicKey, Signature, @@ -140,6 +144,30 @@ impl BlockSignaturesV2 { } Ok(()) } + + /// Returns a random `BlockSignaturesV2`. + #[cfg(any(feature = "testing", test))] + pub fn random(rng: &mut TestRng) -> Self { + let block_hash = BlockHash::random(rng); + let block_height = rng.gen(); + let era_id = EraId::random(rng); + let chain_name_hash = ChainNameDigest::random(rng); + let proofs = (0..rng.gen_range(0..10)) + .map(|_| { + let public_key = PublicKey::random(rng); + let bytes = std::array::from_fn(|_| rng.gen()); + let signature = Signature::ed25519(bytes).unwrap(); + (public_key, signature) + }) + .collect(); + Self { + block_hash, + block_height, + era_id, + chain_name_hash, + proofs, + } + } } impl Display for BlockSignaturesV2 { @@ -198,3 +226,15 @@ impl FromBytes for BlockSignaturesV2 { )) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bytesrepr_roundtrip() { + let rng = &mut TestRng::new(); + let hash = BlockSignaturesV2::random(rng); + bytesrepr::test_serialization_roundtrip(&hash); + } +} diff --git a/types/src/block/chain_name_digest.rs b/types/src/block/chain_name_digest.rs index 7f2d92234e..1dd9a70fe7 100644 --- a/types/src/block/chain_name_digest.rs +++ b/types/src/block/chain_name_digest.rs @@ -34,9 +34,9 @@ impl ChainNameDigest { /// The number of bytes in a `ChainNameDigest` digest. pub const LENGTH: usize = Digest::LENGTH; - /// Constructs a new `ChainNameDigest`. - pub const fn new(hash: Digest) -> Self { - ChainNameDigest(hash) + /// Constructs a new `ChainNameDigest` from the given chain name. + pub fn from_chain_name(name: &str) -> Self { + ChainNameDigest(Digest::hash(name.as_bytes())) } /// Returns the wrapped inner digest. @@ -44,11 +44,11 @@ impl ChainNameDigest { &self.0 } - /// Returns a new `ChainNameDigest` directly initialized with the provided bytes; no hashing is - /// done. + /// Returns a new `ChainNameDigest` directly initialized with the provided `Digest`; + /// no hashing is done. #[cfg(any(feature = "testing", test))] - pub const fn from_raw(raw_digest: [u8; Self::LENGTH]) -> Self { - ChainNameDigest(Digest::from_raw(raw_digest)) + pub const fn from_digest(digest: Digest) -> Self { + ChainNameDigest(digest) } /// Returns a random `ChainNameDigest`. diff --git a/types/src/block/finality_signature/finality_signature_v2.rs b/types/src/block/finality_signature/finality_signature_v2.rs index c08a38d32d..b368b1d793 100644 --- a/types/src/block/finality_signature/finality_signature_v2.rs +++ b/types/src/block/finality_signature/finality_signature_v2.rs @@ -9,6 +9,8 @@ use core::{ use datasize::DataSize; #[cfg(any(feature = "once_cell", test))] use once_cell::sync::OnceCell; +#[cfg(any(feature = "testing", test))] +use rand::Rng; #[cfg(feature = "json-schema")] use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -16,8 +18,6 @@ use serde::{Deserialize, Serialize}; #[cfg(any(feature = "testing", test))] use crate::testing::TestRng; use crate::{crypto, BlockHash, ChainNameDigest, EraId, PublicKey, SecretKey, Signature}; -#[cfg(any(feature = "testing", test))] -use rand::Rng; /// A validator's signature of a block, confirming it is finalized. /// diff --git a/types/src/chainspec.rs b/types/src/chainspec.rs index 920395ba7d..f0808c7779 100644 --- a/types/src/chainspec.rs +++ b/types/src/chainspec.rs @@ -114,7 +114,7 @@ pub struct Chainspec { impl Chainspec { /// Returns the hash of the chainspec's name. pub fn name_hash(&self) -> ChainNameDigest { - ChainNameDigest::new(Digest::hash(self.network_config.name.as_bytes())) + ChainNameDigest::from_chain_name(&self.network_config.name) } /// Serializes `self` and hashes the resulting bytes. From a17f0de1dea8535445984cd902f4bd44e1f9232e Mon Sep 17 00:00:00 2001 From: Jacek Malec <145967538+jacek-casper@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:35:28 +0000 Subject: [PATCH 6/7] Update finality signature test --- .../finality_signature_v2.rs | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/types/src/block/finality_signature/finality_signature_v2.rs b/types/src/block/finality_signature/finality_signature_v2.rs index b368b1d793..8f2ae43c77 100644 --- a/types/src/block/finality_signature/finality_signature_v2.rs +++ b/types/src/block/finality_signature/finality_signature_v2.rs @@ -321,11 +321,10 @@ mod tests { fn finality_signature() { let rng = &mut TestRng::new(); let block = TestBlockBuilder::new().build(rng); - // Signature should be over both block hash and era id. + // Signature should be over block hash, block height, era id and chain name hash. let secret_key = SecretKey::random(rng); - let public_key = PublicKey::from(&secret_key); let era_id = EraId::from(1); - let chain_name_hash = ChainNameDigest::random(rng); + let chain_name_hash = ChainNameDigest::from_chain_name("example"); let finality_signature = FinalitySignatureV2::create( *block.hash(), block.height(), @@ -334,18 +333,26 @@ mod tests { &secret_key, ); finality_signature.is_verified().unwrap(); - let signature = finality_signature.signature; - // Verify that signature includes era id. + // Verify that changing era causes verification to fail. let invalid_finality_signature = FinalitySignatureV2 { - block_hash: *block.hash(), - block_height: block.height(), era_id: EraId::from(2), - chain_name_hash, - signature, - public_key, is_verified: OnceCell::new(), + ..finality_signature.clone() + }; + assert!(invalid_finality_signature.is_verified().is_err()); + // Verify that changing block height causes verification to fail. + let invalid_finality_signature = FinalitySignatureV2 { + block_height: block.height() + 1, + is_verified: OnceCell::new(), + ..finality_signature.clone() + }; + assert!(invalid_finality_signature.is_verified().is_err()); + // Verify that changing chain name hash causes verification to fail. + let invalid_finality_signature = FinalitySignatureV2 { + chain_name_hash: ChainNameDigest::from_chain_name("different"), + is_verified: OnceCell::new(), + ..finality_signature }; - // Test should fail b/c `signature` is over `era_id=1` and here we're using `era_id=2`. assert!(invalid_finality_signature.is_verified().is_err()); } } From 61bedb731560058f62cf79cdf9ee017faed25a8c Mon Sep 17 00:00:00 2001 From: Jacek Malec <145967538+jacek-casper@users.noreply.github.com> Date: Fri, 23 Feb 2024 10:40:46 +0000 Subject: [PATCH 7/7] Post-merge fixes --- node/src/components/block_validator/tests.rs | 36 ++++++++++++++------ node/src/types/validator_matrix.rs | 1 + 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/node/src/components/block_validator/tests.rs b/node/src/components/block_validator/tests.rs index 1fc678d0e9..2133f6d1d2 100644 --- a/node/src/components/block_validator/tests.rs +++ b/node/src/components/block_validator/tests.rs @@ -6,8 +6,8 @@ use rand::Rng; use casper_types::{ bytesrepr::Bytes, runtime_args, system::standard_payment::ARG_AMOUNT, testing::TestRng, Block, - BlockSignatures, Chainspec, ChainspecRawBytes, Deploy, ExecutableDeployItem, RuntimeArgs, - SecretKey, TestBlockBuilder, TimeDiff, Transaction, U512, + BlockSignatures, BlockSignaturesV2, Chainspec, ChainspecRawBytes, Deploy, ExecutableDeployItem, + FinalitySignatureV2, RuntimeArgs, SecretKey, TestBlockBuilder, TimeDiff, Transaction, U512, }; use crate::{ @@ -237,7 +237,7 @@ struct ValidationContext { deploys: HashMap, transfers: HashMap, // map of block height → signatures for the block - signatures: HashMap>, + signatures: HashMap>, // map of signatures that aren't stored, but are fetchable fetchable_signatures: HashMap, @@ -342,8 +342,13 @@ impl ValidationContext { .secret_keys .get(validator) .expect("should have validator"); - let signature = - FinalitySignature::create(*block.hash(), block.era_id(), secret_key); + let signature = FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + self.chainspec.name_hash(), + secret_key, + ); self.signatures .entry(height) .or_default() @@ -366,8 +371,13 @@ impl ValidationContext { .secret_keys .get(validator) .expect("should have validator"); - let signature = - FinalitySignature::create(*block.hash(), block.era_id(), secret_key); + let signature = FinalitySignature::V2(FinalitySignatureV2::create( + *block.hash(), + block.height(), + block.era_id(), + self.chainspec.name_hash(), + secret_key, + )); self.fetchable_signatures .insert(*signature.fetch_id(), signature); } @@ -457,13 +467,19 @@ impl ValidationContext { self.past_blocks.get(&block_height).map(|block| { let empty_hashmap = HashMap::new(); let signatures = self.signatures.get(&block_height).unwrap_or(&empty_hashmap); - let mut block_signatures = BlockSignatures::new(*block.hash(), block.era_id()); + let mut block_signatures = BlockSignaturesV2::new( + *block.hash(), + block.height(), + block.era_id(), + self.chainspec.name_hash(), + ); for signature in signatures.values() { - block_signatures.insert_signature(signature.clone()); + block_signatures + .insert_signature(signature.public_key().clone(), *signature.signature()); } BlockWithMetadata { block: block.clone(), - block_signatures, + block_signatures: BlockSignatures::V2(block_signatures), } }) } diff --git a/node/src/types/validator_matrix.rs b/node/src/types/validator_matrix.rs index 3776ce1496..461a6c78ac 100644 --- a/node/src/types/validator_matrix.rs +++ b/node/src/types/validator_matrix.rs @@ -121,6 +121,7 @@ impl ValidatorMatrix { ); ValidatorMatrix { inner: Arc::new(RwLock::new(iter::once((era_id, weights)).collect())), + chainspec_name_hash: ChainNameDigest::from_chain_name("casper-example"), chainspec_validators: None, chainspec_activation_era: EraId::from(0), finality_threshold_fraction,