@@ -110,7 +110,7 @@ type ClientForGrandpa[
110110 papi.ProvideRuntimeAPI [primitives.GrandpaAPI [H , N ]]
111111 // api.ExecutorProvider
112112 client_common.BlockImport [H , N , E , Header ]
113- // api.StorageProvider[H, N, Hasher]
113+ api.StorageProvider [H , N , Hasher ]
114114}
115115
116116// Something that one can ask to do a block sync request.
@@ -165,7 +165,7 @@ type LinkHalf[
165165 persistentData persistentData [H , N ]
166166 voterCommandsRx chan voterCommand
167167 justificationSender GrandpaJustificationSender [H , N , Header ]
168- justificationStream GrandpaJustificationStream [H , N , Header ] //nolint: unused
168+ justificationStream GrandpaJustificationStream [H , N , Header ]
169169}
170170
171171// Provider for the Grandpa authority set configured on the genesis block.
@@ -174,6 +174,127 @@ type GenesisAuthoritySetProvider interface {
174174 Get () (primitives.AuthorityList , error )
175175}
176176
177+ // Make block importer and link half necessary to tie the background voter to it.
178+ //
179+ // The justificationImportPeriod sets the minimum period on which justifications will be imported. When importing
180+ // a block, if it includes a justification it will only be processed if it fits within this period, otherwise it will
181+ // be ignored (and won't be validated). This is to avoid slowing down sync by a peer serving us unnecessary
182+ // justifications which aren't trivial to validate.
183+ func BlockImport [
184+ H runtime.Hash ,
185+ N runtime.Number ,
186+ Hasher runtime.Hasher [H ],
187+ Header runtime.Header [N , H ],
188+ E runtime.Extrinsic ,
189+ ](
190+ client ClientForGrandpa [H , N , Hasher , Header , E ],
191+ justificationImportPeriod uint32 ,
192+ genesisAuthoritySetProvider GenesisAuthoritySetProvider ,
193+ selectChain common.SelectChain [H , N , Header ],
194+ // TODO: telemetry
195+ ) (* GrandpaBlockImport [H , N , Hasher , Header , E ], LinkHalf [H , N , Hasher , Header , E ], error ) {
196+ return blockImportWithAuthoritySetHardForks (
197+ client ,
198+ justificationImportPeriod ,
199+ genesisAuthoritySetProvider ,
200+ selectChain ,
201+ nil ,
202+ )
203+ }
204+
205+ // A descriptor for an authority set hard fork. These are authority set changes that are not signalled by the runtime
206+ // and instead are defined off-chain (hence the hard fork).
207+ type AuthoritySetHardFork [H , N any ] struct {
208+ // The new authority set id.
209+ SetID SetID
210+ // The block hash and number at which the hard fork should be applied.
211+ Block HashNumber [H , N ]
212+ // The authorities in the new set.
213+ Authorities primitives.AuthorityList
214+ // The latest block number that was finalized before this authority set hard fork. When defined, the authority set
215+ // change will be forced, i.e. the node won't wait for the block above to be finalized before enacting the change,
216+ // and the given finalized number will be used as a base for voting.
217+ LastFinalized * N
218+ }
219+
220+ // Make block importer and link half necessary to tie the background voter to it. A vector of authority set hard forks
221+ // can be passed, any authority set change signalled at the given block (either already signalled or in a further block
222+ // when importing it) will be replaced by a standard change with the given static authorities.
223+ func blockImportWithAuthoritySetHardForks [
224+ H runtime.Hash ,
225+ N runtime.Number ,
226+ Hasher runtime.Hasher [H ],
227+ Header runtime.Header [N , H ],
228+ E runtime.Extrinsic ,
229+ ](
230+ client ClientForGrandpa [H , N , Hasher , Header , E ],
231+ justificationImportPeriod uint32 ,
232+ genesisAuthoritySetProvider GenesisAuthoritySetProvider ,
233+ selectChain common.SelectChain [H , N , Header ],
234+ authoritySetHardForks []AuthoritySetHardFork [H , N ],
235+ // TODO: telemetry
236+ ) (* GrandpaBlockImport [H , N , Hasher , Header , E ], LinkHalf [H , N , Hasher , Header , E ], error ) {
237+ chainInfo := client .Info ()
238+ genesisHash := chainInfo .GenesisHash
239+
240+ persistentData , err := loadPersistent [H , N ](client , genesisHash , 0 , genesisAuthoritySetProvider .Get )
241+ if err != nil {
242+ return nil , LinkHalf [H , N , Hasher , Header , E ]{}, err
243+ }
244+
245+ voterCommands := make (chan voterCommand , 100000 )
246+
247+ justificationSender , justificationStream := NewGrandpaJustificationSender [H , N , Header ]()
248+
249+ // create pending change objects with 0 delay for each authority set hard fork.
250+ hardForks := make ([]struct {
251+ SetID
252+ PendingChange [H , N ]
253+ }, len (authoritySetHardForks ))
254+ for i , fork := range authoritySetHardForks {
255+ var kind delayKind
256+ if fork .LastFinalized != nil {
257+ kind = delayKindBest [N ]{MedianLastFinalized : * fork .LastFinalized }
258+ } else {
259+ kind = delayKindFinalized {}
260+ }
261+
262+ hardForks [i ] = struct {
263+ SetID
264+ PendingChange [H , N ]
265+ }{
266+ SetID : fork .SetID ,
267+ PendingChange : PendingChange [H , N ]{
268+ NextAuthorities : fork .Authorities ,
269+ Delay : 0 ,
270+ CanonHash : fork .Block .Hash ,
271+ CanonHeight : fork .Block .Number ,
272+ DelayKind : kind ,
273+ },
274+ }
275+ }
276+
277+ blockImport := newGrandpaBlockImport (
278+ client ,
279+ justificationImportPeriod ,
280+ selectChain ,
281+ persistentData .authoritySet ,
282+ voterCommands ,
283+ hardForks ,
284+ justificationSender ,
285+ )
286+
287+ linkHalf := LinkHalf [H , N , Hasher , Header , E ]{
288+ client : client ,
289+ selectChain : selectChain ,
290+ persistentData : * persistentData ,
291+ voterCommandsRx : voterCommands ,
292+ justificationSender : justificationSender ,
293+ justificationStream : justificationStream ,
294+ }
295+ return blockImport , linkHalf , nil
296+ }
297+
177298func globalCommunication [
178299 H runtime.Hash ,
179300 N runtime.Number ,
0 commit comments