referrerpolicy=no-referrer-when-downgrade
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.

// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.

//! Weight-related utilities.

use crate::weights::{BridgeWeight, WeightInfo};

use bp_runtime::Size;
use frame_support::weights::{RuntimeDbWeight, Weight};

/// Size of the regular parachain head.
///
/// It's not that we are expecting all parachain heads to share the same size or that we would
/// reject all heads that have larger/lesser size. It is about head size that we use in benchmarks.
/// Relayer would need to pay additional fee for extra bytes.
///
/// 384 is a bit larger (1.3 times) than the size of the randomly chosen Polkadot block.
pub const DEFAULT_PARACHAIN_HEAD_SIZE: u32 = 384;

/// Number of extra bytes (excluding size of storage value itself) of storage proof, built at
/// some generic chain.
pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024;

/// Extended weight info.
pub trait WeightInfoExt: WeightInfo {
	// Our configuration assumes that the runtime has special signed extensions used to:
	//
	// 1) boost priority of `submit_parachain_heads` transactions;
	//
	// 2) slash relayer if he submits an invalid transaction.
	//
	// We read and update storage values of other pallets (`pallet-bridge-relayers` and
	// balances/assets pallet). So we need to add this weight to the weight of our call.
	// Hence two following methods.

	/// Extra weight that is added to the `submit_finality_proof` call weight by signed extensions
	/// that are declared at runtime level.
	fn submit_parachain_heads_overhead_from_runtime() -> Weight;

	/// Storage proof overhead, that is included in every storage proof.
	///
	/// The relayer would pay some extra fee for additional proof bytes, since they mean
	/// more hashing operations.
	fn expected_extra_storage_proof_size() -> u32;

	/// Weight of the parachain heads delivery extrinsic.
	fn submit_parachain_heads_weight(
		db_weight: RuntimeDbWeight,
		proof: &impl Size,
		parachains_count: u32,
	) -> Weight {
		// weight of the `submit_parachain_heads` with exactly `parachains_count` parachain
		// heads of the default size (`DEFAULT_PARACHAIN_HEAD_SIZE`)
		let base_weight = Self::submit_parachain_heads_with_n_parachains(parachains_count);

		// overhead because of extra storage proof bytes
		let expected_proof_size = parachains_count
			.saturating_mul(DEFAULT_PARACHAIN_HEAD_SIZE)
			.saturating_add(Self::expected_extra_storage_proof_size());
		let actual_proof_size = proof.size();
		let proof_size_overhead = Self::storage_proof_size_overhead(
			actual_proof_size.saturating_sub(expected_proof_size),
		);

		// potential pruning weight (refunded if hasn't happened)
		let pruning_weight =
			Self::parachain_head_pruning_weight(db_weight).saturating_mul(parachains_count as u64);

		base_weight
			.saturating_add(proof_size_overhead)
			.saturating_add(pruning_weight)
			.saturating_add(Self::submit_parachain_heads_overhead_from_runtime())
	}

	/// Returns weight of single parachain head storage update.
	///
	/// This weight only includes db write operations that happens if parachain head is actually
	/// updated. All extra weights (weight of storage proof validation, additional checks, ...) is
	/// not included.
	fn parachain_head_storage_write_weight(db_weight: RuntimeDbWeight) -> Weight {
		// it's just a couple of operations - we need to write the hash (`ImportedParaHashes`) and
		// the head itself (`ImportedParaHeads`. Pruning is not included here
		db_weight.writes(2)
	}

	/// Returns weight of single parachain head pruning.
	fn parachain_head_pruning_weight(db_weight: RuntimeDbWeight) -> Weight {
		// it's just one write operation, we don't want any benchmarks for that
		db_weight.writes(1)
	}

	/// Returns weight that needs to be accounted when storage proof of given size is received.
	fn storage_proof_size_overhead(extra_proof_bytes: u32) -> Weight {
		let extra_byte_weight = (Self::submit_parachain_heads_with_16kb_proof() -
			Self::submit_parachain_heads_with_1kb_proof()) /
			(15 * 1024);
		extra_byte_weight.saturating_mul(extra_proof_bytes as u64)
	}
}

impl WeightInfoExt for () {
	fn submit_parachain_heads_overhead_from_runtime() -> Weight {
		Weight::zero()
	}

	fn expected_extra_storage_proof_size() -> u32 {
		EXTRA_STORAGE_PROOF_SIZE
	}
}

impl<T: frame_system::Config> WeightInfoExt for BridgeWeight<T> {
	fn submit_parachain_heads_overhead_from_runtime() -> Weight {
		Weight::zero()
	}

	fn expected_extra_storage_proof_size() -> u32 {
		EXTRA_STORAGE_PROOF_SIZE
	}
}