1+ // This file is part of Substrate.
2+
3+ // Copyright (C) 2020 Parity Technologies (UK) Ltd.
4+ // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5+
6+ // This program is free software: you can redistribute it and/or modify
7+ // it under the terms of the GNU General Public License as published by
8+ // the Free Software Foundation, either version 3 of the License, or
9+ // (at your option) any later version.
10+
11+ // This program is distributed in the hope that it will be useful,
12+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ // GNU General Public License for more details.
15+
16+ // You should have received a copy of the GNU General Public License
17+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
19+ //! Block construction benchmark.
20+ //!
21+ //! This benchmark is expected to measure block construction.
22+ //! We want to protect against cold-cache attacks, and so this
23+ //! benchmark should not rely on any caching (except those entries that
24+ //! DO NOT depend on user input). Thus transaction generation should be
25+ //! based on randomized data.
26+
27+ use std:: {
28+ borrow:: Cow ,
29+ collections:: HashMap ,
30+ pin:: Pin ,
31+ sync:: Arc ,
32+ } ;
33+ use futures:: Future ;
34+
35+ use node_primitives:: Block ;
36+ use node_testing:: bench:: { BenchDb , Profile , BlockType , KeyTypes , DatabaseType } ;
37+ use sp_runtime:: {
38+ generic:: BlockId ,
39+ traits:: NumberFor ,
40+ OpaqueExtrinsic ,
41+ } ;
42+ use sp_transaction_pool:: {
43+ ImportNotificationStream ,
44+ PoolFuture ,
45+ PoolStatus ,
46+ TransactionFor ,
47+ TransactionSource ,
48+ TransactionStatusStreamFor ,
49+ TxHash ,
50+ } ;
51+ use sp_consensus:: { Environment , Proposer , RecordProof } ;
52+
53+ use crate :: {
54+ common:: SizeType ,
55+ core:: { self , Path , Mode } ,
56+ } ;
57+
58+ pub struct ConstructionBenchmarkDescription {
59+ pub profile : Profile ,
60+ pub key_types : KeyTypes ,
61+ pub block_type : BlockType ,
62+ pub size : SizeType ,
63+ pub database_type : DatabaseType ,
64+ }
65+
66+ pub struct ConstructionBenchmark {
67+ profile : Profile ,
68+ database : BenchDb ,
69+ transactions : Transactions ,
70+ }
71+
72+ impl core:: BenchmarkDescription for ConstructionBenchmarkDescription {
73+ fn path ( & self ) -> Path {
74+
75+ let mut path = Path :: new ( & [ "node" , "proposer" ] ) ;
76+
77+ match self . profile {
78+ Profile :: Wasm => path. push ( "wasm" ) ,
79+ Profile :: Native => path. push ( "native" ) ,
80+ }
81+
82+ match self . key_types {
83+ KeyTypes :: Sr25519 => path. push ( "sr25519" ) ,
84+ KeyTypes :: Ed25519 => path. push ( "ed25519" ) ,
85+ }
86+
87+ match self . block_type {
88+ BlockType :: RandomTransfersKeepAlive => path. push ( "transfer" ) ,
89+ BlockType :: RandomTransfersReaping => path. push ( "transfer_reaping" ) ,
90+ BlockType :: Noop => path. push ( "noop" ) ,
91+ }
92+
93+ match self . database_type {
94+ DatabaseType :: RocksDb => path. push ( "rocksdb" ) ,
95+ DatabaseType :: ParityDb => path. push ( "paritydb" ) ,
96+ }
97+
98+ path. push ( & format ! ( "{}" , self . size) ) ;
99+
100+ path
101+ }
102+
103+ fn setup ( self : Box < Self > ) -> Box < dyn core:: Benchmark > {
104+ let mut extrinsics: Vec < Arc < PoolTransaction > > = Vec :: new ( ) ;
105+
106+ let mut bench_db = BenchDb :: with_key_types (
107+ self . database_type ,
108+ 50_000 ,
109+ self . key_types
110+ ) ;
111+
112+ let client = bench_db. client ( ) ;
113+
114+ let content_type = self . block_type . to_content ( self . size . transactions ( ) ) ;
115+ for transaction in bench_db. block_content ( content_type, & client) {
116+ extrinsics. push ( Arc :: new ( transaction. into ( ) ) ) ;
117+ }
118+
119+ Box :: new ( ConstructionBenchmark {
120+ profile : self . profile ,
121+ database : bench_db,
122+ transactions : Transactions ( extrinsics) ,
123+ } )
124+ }
125+
126+ fn name ( & self ) -> Cow < ' static , str > {
127+ format ! (
128+ "Block construction ({:?}/{}, {:?}, {:?} backend)" ,
129+ self . block_type,
130+ self . size,
131+ self . profile,
132+ self . database_type,
133+ ) . into ( )
134+ }
135+ }
136+
137+ impl core:: Benchmark for ConstructionBenchmark {
138+ fn run ( & mut self , mode : Mode ) -> std:: time:: Duration {
139+ let context = self . database . create_context ( self . profile ) ;
140+
141+ let _ = context. client . runtime_version_at ( & BlockId :: Number ( 0 ) )
142+ . expect ( "Failed to get runtime version" )
143+ . spec_version ;
144+
145+ if mode == Mode :: Profile {
146+ std:: thread:: park_timeout ( std:: time:: Duration :: from_secs ( 3 ) ) ;
147+ }
148+
149+ let mut proposer_factory = sc_basic_authorship:: ProposerFactory :: new (
150+ context. client . clone ( ) ,
151+ self . transactions . clone ( ) . into ( ) ,
152+ None ,
153+ ) ;
154+ let inherent_data_providers = sp_inherents:: InherentDataProviders :: new ( ) ;
155+ inherent_data_providers
156+ . register_provider ( sp_timestamp:: InherentDataProvider )
157+ . expect ( "Failed to register timestamp data provider" ) ;
158+
159+ let start = std:: time:: Instant :: now ( ) ;
160+
161+ let proposer = futures:: executor:: block_on ( proposer_factory. init (
162+ & context. client . header ( & BlockId :: number ( 0 ) )
163+ . expect ( "Database error querying block #0" )
164+ . expect ( "Block #0 should exist" ) ,
165+ ) ) . expect ( "Proposer initialization failed" ) ;
166+
167+ let _block = futures:: executor:: block_on (
168+ proposer. propose (
169+ inherent_data_providers. create_inherent_data ( ) . expect ( "Create inherent data failed" ) ,
170+ Default :: default ( ) ,
171+ std:: time:: Duration :: from_secs ( 20 ) ,
172+ RecordProof :: Yes ,
173+ ) ,
174+ ) . map ( |r| r. block ) . expect ( "Proposing failed" ) ;
175+
176+ let elapsed = start. elapsed ( ) ;
177+
178+ if mode == Mode :: Profile {
179+ std:: thread:: park_timeout ( std:: time:: Duration :: from_secs ( 1 ) ) ;
180+ }
181+
182+ elapsed
183+ }
184+ }
185+
186+ #[ derive( Clone , Debug ) ]
187+ pub struct PoolTransaction {
188+ data : OpaqueExtrinsic ,
189+ hash : node_primitives:: Hash ,
190+ }
191+
192+ impl From < OpaqueExtrinsic > for PoolTransaction {
193+ fn from ( e : OpaqueExtrinsic ) -> Self {
194+ PoolTransaction {
195+ data : e,
196+ hash : node_primitives:: Hash :: zero ( ) ,
197+ }
198+ }
199+ }
200+
201+ impl sp_transaction_pool:: InPoolTransaction for PoolTransaction {
202+ type Transaction = OpaqueExtrinsic ;
203+ type Hash = node_primitives:: Hash ;
204+
205+ fn data ( & self ) -> & Self :: Transaction {
206+ & self . data
207+ }
208+
209+ fn hash ( & self ) -> & Self :: Hash {
210+ & self . hash
211+ }
212+
213+ fn priority ( & self ) -> & u64 { unimplemented ! ( ) }
214+
215+ fn longevity ( & self ) -> & u64 { unimplemented ! ( ) }
216+
217+ fn requires ( & self ) -> & [ Vec < u8 > ] { unimplemented ! ( ) }
218+
219+ fn provides ( & self ) -> & [ Vec < u8 > ] { unimplemented ! ( ) }
220+
221+ fn is_propagable ( & self ) -> bool { unimplemented ! ( ) }
222+ }
223+
224+ #[ derive( Clone , Debug ) ]
225+ pub struct Transactions ( Vec < Arc < PoolTransaction > > ) ;
226+
227+ impl sp_transaction_pool:: TransactionPool for Transactions {
228+ type Block = Block ;
229+ type Hash = node_primitives:: Hash ;
230+ type InPoolTransaction = PoolTransaction ;
231+ type Error = sp_transaction_pool:: error:: Error ;
232+
233+ /// Returns a future that imports a bunch of unverified transactions to the pool.
234+ fn submit_at (
235+ & self ,
236+ _at : & BlockId < Self :: Block > ,
237+ _source : TransactionSource ,
238+ _xts : Vec < TransactionFor < Self > > ,
239+ ) -> PoolFuture < Vec < Result < node_primitives:: Hash , Self :: Error > > , Self :: Error > {
240+ unimplemented ! ( )
241+ }
242+
243+ /// Returns a future that imports one unverified transaction to the pool.
244+ fn submit_one (
245+ & self ,
246+ _at : & BlockId < Self :: Block > ,
247+ _source : TransactionSource ,
248+ _xt : TransactionFor < Self > ,
249+ ) -> PoolFuture < TxHash < Self > , Self :: Error > {
250+ unimplemented ! ( )
251+ }
252+
253+ fn submit_and_watch (
254+ & self ,
255+ _at : & BlockId < Self :: Block > ,
256+ _source : TransactionSource ,
257+ _xt : TransactionFor < Self > ,
258+ ) -> PoolFuture < Box < TransactionStatusStreamFor < Self > > , Self :: Error > {
259+ unimplemented ! ( )
260+ }
261+
262+ fn ready_at ( & self , _at : NumberFor < Self :: Block > )
263+ -> Pin < Box < dyn Future < Output =Box < dyn Iterator < Item =Arc < Self :: InPoolTransaction > > + Send > > + Send > >
264+ {
265+ let iter: Box < dyn Iterator < Item =Arc < PoolTransaction > > + Send > = Box :: new ( self . 0 . clone ( ) . into_iter ( ) ) ;
266+ Box :: pin ( futures:: future:: ready ( iter) )
267+ }
268+
269+ fn ready ( & self ) -> Box < dyn Iterator < Item =Arc < Self :: InPoolTransaction > > + Send > {
270+ unimplemented ! ( )
271+ }
272+
273+ fn remove_invalid ( & self , _hashes : & [ TxHash < Self > ] ) -> Vec < Arc < Self :: InPoolTransaction > > {
274+ Default :: default ( )
275+ }
276+
277+ fn status ( & self ) -> PoolStatus {
278+ unimplemented ! ( )
279+ }
280+
281+ fn import_notification_stream ( & self ) -> ImportNotificationStream < TxHash < Self > > {
282+ unimplemented ! ( )
283+ }
284+
285+ fn on_broadcasted ( & self , _propagations : HashMap < TxHash < Self > , Vec < String > > ) {
286+ unimplemented ! ( )
287+ }
288+
289+ fn hash_of ( & self , _xt : & TransactionFor < Self > ) -> TxHash < Self > {
290+ unimplemented ! ( )
291+ }
292+
293+ fn ready_transaction ( & self , _hash : & TxHash < Self > ) -> Option < Arc < Self :: InPoolTransaction > > {
294+ unimplemented ! ( )
295+ }
296+ }
0 commit comments