Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

360 support confirm scp messages in the stellar relay when proving transaction validity #362

51 changes: 32 additions & 19 deletions .maintain/frame-weight-template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//! Autogenerated weights for {{pallet}}
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}}
//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: {{cmd.repeat}}, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}`
//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}`
//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}`
//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}`
//! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}}

Expand All @@ -14,10 +15,10 @@
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(clippy::unnecessary_cast)]
#![allow(missing_docs)]

use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use sp_std::marker::PhantomData;
use core::marker::PhantomData;

/// Weight functions needed for {{pallet}}.
pub trait WeightInfo {
Expand All @@ -39,7 +40,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
{{/if}}
{{#each benchmarks as |benchmark|}}
{{#each benchmark.comments as |comment|}}
// {{comment}}
/// {{comment}}
{{/each}}
{{#each benchmark.component_ranges as |range|}}
/// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`.
Expand All @@ -49,23 +50,29 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
{{~#each benchmark.components as |c| ~}}
{{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}}
) -> Weight {
// Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds.
Weight::from_ref_time({{underscore benchmark.base_weight}} as u64)
// Proof Size summary in bytes:
// Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}`
// Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}`
// Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds.
Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}})
{{#each benchmark.component_weight as |cw|}}
// Standard Error: {{underscore cw.error}}
.saturating_add(Weight::from_ref_time({{underscore cw.slope}} as u64).saturating_mul({{cw.name}} as u64))
.saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into()))
{{/each}}
{{#if (ne benchmark.base_reads "0")}}
.saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as u64))
.saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}}_u64))
{{/if}}
{{#each benchmark.component_reads as |cr|}}
.saturating_add(T::DbWeight::get().reads(({{cr.slope}} as u64).saturating_mul({{cr.name}} as u64)))
.saturating_add(T::DbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into())))
{{/each}}
{{#if (ne benchmark.base_writes "0")}}
.saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as u64))
.saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}}_u64))
{{/if}}
{{#each benchmark.component_writes as |cw|}}
.saturating_add(T::DbWeight::get().writes(({{cw.slope}} as u64).saturating_mul({{cw.name}} as u64)))
.saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into())))
{{/each}}
{{#each benchmark.component_calculated_proof_size as |cp|}}
.saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into()))
{{/each}}
}
{{/each}}
Expand All @@ -75,7 +82,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
impl WeightInfo for () {
{{#each benchmarks as |benchmark|}}
{{#each benchmark.comments as |comment|}}
// {{comment}}
/// {{comment}}
{{/each}}
{{#each benchmark.component_ranges as |range|}}
/// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`.
Expand All @@ -85,23 +92,29 @@ impl WeightInfo for () {
{{~#each benchmark.components as |c| ~}}
{{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}}
) -> Weight {
// Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds.
Weight::from_ref_time({{underscore benchmark.base_weight}} as u64)
// Proof Size summary in bytes:
// Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}`
// Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}`
// Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds.
Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}})
{{#each benchmark.component_weight as |cw|}}
// Standard Error: {{underscore cw.error}}
.saturating_add(Weight::from_ref_time({{underscore cw.slope}} as u64).saturating_mul({{cw.name}} as u64))
.saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into()))
{{/each}}
{{#if (ne benchmark.base_reads "0")}}
.saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as u64))
.saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}}_u64))
{{/if}}
{{#each benchmark.component_reads as |cr|}}
.saturating_add(RocksDbWeight::get().reads(({{cr.slope}} as u64).saturating_mul({{cr.name}} as u64)))
.saturating_add(RocksDbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into())))
{{/each}}
{{#if (ne benchmark.base_writes "0")}}
.saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}} as u64))
.saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}}_u64))
{{/if}}
{{#each benchmark.component_writes as |cw|}}
.saturating_add(RocksDbWeight::get().writes(({{cw.slope}} as u64).saturating_mul({{cw.name}} as u64)))
.saturating_add(RocksDbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into())))
{{/each}}
{{#each benchmark.component_calculated_proof_size as |cp|}}
.saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into()))
{{/each}}
}
{{/each}}
Expand Down
1 change: 1 addition & 0 deletions pallets/stellar-relay/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Run the benchmarking for a pallet:
--steps=100 \
--repeat=10 \
--wasm-execution=compiled \
--execution=wasm \
--output=pallets/stellar-relay/src/default_weights.rs \
--template=./.maintain/frame-weight-template.hbs
```
63 changes: 42 additions & 21 deletions pallets/stellar-relay/src/default_weights.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@

//! Autogenerated weights for `stellar_relay`
//! Autogenerated weights for stellar_relay
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-05-24, STEPS: `100`, REPEAT: `10`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2023-06-14, STEPS: `100`, REPEAT: `10`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `Bs-MacBook-Pro.local`, CPU: `<UNKNOWN>`
//! HOSTNAME: `Marcels-MBP`, CPU: `<UNKNOWN>`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024

// Executed Command:
// ./target/release/spacewalk-standalone
// benchmark
// pallet
// --chain
// dev
// --execution=wasm
// --wasm-execution=compiled
// --pallet
// *
// --extrinsic
// *
// --chain=dev
// --pallet=stellar-relay
// --extrinsic=*
// --steps=100
// --repeat=10
// --output
// pallets
// --wasm-execution=compiled
// --execution=wasm
// --output=pallets/stellar-relay/src/default_weights.rs
// --template=./.maintain/frame-weight-template.hbs

#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]

use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use core::marker::PhantomData;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe revert back to sp_std ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this matters? It changed because the latest template file uses core::


/// Weight functions for `stellar_relay`.
/// Weight functions needed for stellar_relay.
pub trait WeightInfo {
fn update_tier_1_validator_set() -> Weight;
}

/// Weights for stellar_relay using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: StellarRelay Validators (r:1 w:1)
Expand All @@ -52,10 +51,32 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Proof Size summary in bytes:
// Measured: `428`
// Estimated: `110584`
// Minimum execution time: 156_000_000 picoseconds.
Weight::from_parts(159_000_000, 0)
.saturating_add(Weight::from_parts(0, 110584))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(5))
// Minimum execution time: 154_000_000 picoseconds.
Weight::from_parts(155_000_000, 110584)
.saturating_add(T::DbWeight::get().reads(2_u64))
.saturating_add(T::DbWeight::get().writes(5_u64))
}
}

// For backwards compatibility and tests
impl WeightInfo for () {
/// Storage: StellarRelay Validators (r:1 w:1)
/// Proof: StellarRelay Validators (max_values: Some(1), max_size: Some(70382), added: 70877, mode: MaxEncodedLen)
/// Storage: StellarRelay Organizations (r:1 w:1)
/// Proof: StellarRelay Organizations (max_values: Some(1), max_size: Some(37232), added: 37727, mode: MaxEncodedLen)
/// Storage: StellarRelay OldValidators (r:0 w:1)
/// Proof: StellarRelay OldValidators (max_values: Some(1), max_size: Some(70382), added: 70877, mode: MaxEncodedLen)
/// Storage: StellarRelay NewValidatorsEnactmentBlockHeight (r:0 w:1)
/// Proof: StellarRelay NewValidatorsEnactmentBlockHeight (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
/// Storage: StellarRelay OldOrganizations (r:0 w:1)
/// Proof: StellarRelay OldOrganizations (max_values: Some(1), max_size: Some(37232), added: 37727, mode: MaxEncodedLen)
fn update_tier_1_validator_set() -> Weight {
// Proof Size summary in bytes:
// Measured: `428`
// Estimated: `110584`
// Minimum execution time: 154_000_000 picoseconds.
Weight::from_parts(155_000_000, 110584)
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(5_u64))
}
}
92 changes: 68 additions & 24 deletions pallets/stellar-relay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@ pub mod pallet {
use substrate_stellar_sdk::{
compound_types::UnlimitedVarArray,
network::{Network, PUBLIC_NETWORK, TEST_NETWORK},
types::{
NodeId, ScpEnvelope, ScpStatementExternalize, ScpStatementPledges, StellarValue,
TransactionSet,
},
types::{NodeId, ScpEnvelope, ScpStatementPledges, StellarValue, TransactionSet, Value},
Hash, TransactionEnvelope, XdrCodec,
};

Expand Down Expand Up @@ -102,27 +99,34 @@ pub mod pallet {
pub enum Error<T> {
Base64DecodeError,
BoundedVecCreationFailed,
DuplicateOrganizationId,
DuplicateValidatorPublicKey,
EmptyEnvelopeSet,
EnvelopeSignedByUnknownValidator,
EnvelopeSlotIndexMismatch,
ExternalizedNHMismatch,
ExternalizedValueMismatch,
ExternalizedValueNotFound,
FailedToComputeNonGenericTxSetContentHash,
InvalidEnvelopeSignature,
InvalidQuorumSetNotEnoughOrganizations,
InvalidQuorumSetNotEnoughValidators,
InvalidScpPledge,
InvalidEnvelopeSignature,
InvalidXDR,
NoOrganizationsRegisteredForNetwork,
NoValidatorsRegisteredForNetwork,
InvalidTransactionSet,
InvalidTransactionXDR,
InvalidXDR,
MissingExternalizedMessage,
NoOrganizationsRegistered,
NoOrganizationsRegisteredForNetwork,
NoValidatorsRegistered,
NoValidatorsRegisteredForNetwork,
OrganizationLimitExceeded,
SlotIndexIsNone,
TransactionMemoDoesNotMatch,
TransactionNotInTransactionSet,
TransactionSetHashCreationFailed,
TransactionSetHashMismatch,
ValidatorLimitExceeded,
DuplicateOrganizationId,
DuplicateValidatorPublicKey,
FailedToComputenonGenericTxSetContentHash,
}

#[pallet::storage]
Expand Down Expand Up @@ -557,6 +561,21 @@ pub mod pallet {
// Make sure that at least one validator is registered
ensure!(!validators.is_empty(), Error::<T>::NoValidatorsRegistered);

// Make sure that the envelope set is not empty
ensure!(!envelopes.len() > 0, Error::<T>::EmptyEnvelopeSet);

let externalized_envelope = envelopes
.get_vec()
.iter()
.find(|envelope| match envelope.statement.pledges {
ScpStatementPledges::ScpStExternalize(_) => true,
_ => false,
})
.ok_or(Error::<T>::MissingExternalizedMessage)?;

// Variable used to check if all envelopes are using the same slot index
let slot_index: u64 = externalized_envelope.statement.slot_index;

for envelope in envelopes.get_vec() {
let node_id = envelope.statement.node_id.clone();
let node_id_found = validators
Expand All @@ -565,25 +584,51 @@ pub mod pallet {

ensure!(node_id_found, Error::<T>::EnvelopeSignedByUnknownValidator);
ebma marked this conversation as resolved.
Show resolved Hide resolved

// Check if all envelopes are using the same slot index
ensure!(
slot_index == envelope.statement.slot_index,
Error::<T>::EnvelopeSlotIndexMismatch
);

let signature_valid = verify_signature(envelope, &node_id, network);
ensure!(signature_valid, Error::<T>::InvalidEnvelopeSignature);
}

// Check if transaction set matches tx_set_hash included in the ScpEnvelopes
let expected_tx_set_hash = compute_non_generic_tx_set_content_hash(transaction_set)
.ok_or(Error::<T>::FailedToComputenonGenericTxSetContentHash)?;
.ok_or(Error::<T>::FailedToComputeNonGenericTxSetContentHash)?;

// We store the externalized value in a variable so that we can check if it's the same
// for all envelopes. We don't distinguish between externalized and confirmed values as
// it should be the same value regardless.
let (externalized_value, externalized_n_h) =
match &externalized_envelope.statement.pledges {
ScpStatementPledges::ScpStExternalize(externalized_statement) =>
(&externalized_statement.commit.value, externalized_statement.n_h),
ScpStatementPledges::ScpStConfirm(confirmed_statement) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case cannot happen as externalized_envelope is define in line 567 to be an ScpStExternalize message.

(&confirmed_statement.ballot.value, confirmed_statement.n_h),
_ => return Err(Error::<T>::ExternalizedValueNotFound),
};

for envelope in envelopes.get_vec() {
match envelope.clone().statement.pledges {
ScpStatementPledges::ScpStExternalize(externalized_statement) => {
let tx_set_hash = Self::get_tx_set_hash(&externalized_statement)?;
ensure!(
tx_set_hash == expected_tx_set_hash,
Error::<T>::TransactionSetHashMismatch
);
},
let (value, n_h) = match &envelope.statement.pledges {
ScpStatementPledges::ScpStExternalize(externalized_statement) =>
(&externalized_statement.commit.value, externalized_statement.n_h),
ScpStatementPledges::ScpStConfirm(confirmed_statement) =>
(&confirmed_statement.ballot.value, confirmed_statement.n_h),
_ => return Err(Error::<T>::InvalidScpPledge),
TorstenStueber marked this conversation as resolved.
Show resolved Hide resolved
}
};

// Check if the tx_set_hash matches the one included in the envelope
let tx_set_hash = Self::get_tx_set_hash(&value)?;
ensure!(
tx_set_hash == expected_tx_set_hash,
Error::<T>::TransactionSetHashMismatch
);

// Check if the externalized value is the same for all envelopes
ensure!(externalized_value == value, Error::<T>::ExternalizedValueMismatch);
ensure!(externalized_n_h == n_h, Error::<T>::ExternalizedNHMismatch);
}

// ---- Check that externalized messages build valid quorum set ----
Expand Down Expand Up @@ -656,9 +701,8 @@ pub mod pallet {
Ok(())
}

fn get_tx_set_hash(x: &ScpStatementExternalize) -> Result<Hash, Error<T>> {
let scp_value = x.commit.value.get_vec();
let tx_set_hash = StellarValue::from_xdr(scp_value)
fn get_tx_set_hash(scp_value: &Value) -> Result<Hash, Error<T>> {
let tx_set_hash = StellarValue::from_xdr(scp_value.get_vec())
.map(|stellar_value| stellar_value.tx_set_hash)
.map_err(|_| Error::<T>::TransactionSetHashCreationFailed)?;
Ok(tx_set_hash)
Expand Down
Loading