5
5
"fmt"
6
6
"math/big"
7
7
"math/rand"
8
+ "slices"
8
9
"sync"
9
10
"sync/atomic"
10
11
"time"
@@ -41,6 +42,7 @@ import (
41
42
"github.com/Fantom-foundation/go-opera/gossip/blockproc/sealmodule"
42
43
"github.com/Fantom-foundation/go-opera/gossip/blockproc/verwatcher"
43
44
"github.com/Fantom-foundation/go-opera/gossip/emitter"
45
+ "github.com/Fantom-foundation/go-opera/gossip/evmstore"
44
46
"github.com/Fantom-foundation/go-opera/gossip/filters"
45
47
"github.com/Fantom-foundation/go-opera/gossip/gasprice"
46
48
"github.com/Fantom-foundation/go-opera/gossip/proclogger"
@@ -60,6 +62,15 @@ type ServiceFeed struct {
60
62
newEmittedEvent notify.Feed
61
63
newBlock notify.Feed
62
64
newLogs notify.Feed
65
+
66
+ incomingUpdates chan <- feedUpdate // < channel to send updates to the background feed loop
67
+ stopFeeder chan <- struct {} // < if closed, the background feed loop will stop
68
+ feederDone <- chan struct {} // < if closed, the background feed loop has stopped
69
+ }
70
+
71
+ type feedUpdate struct {
72
+ block * evmcore.EvmBlock
73
+ logs []* types.Log
63
74
}
64
75
65
76
func (f * ServiceFeed ) SubscribeNewEpoch (ch chan <- idx.Epoch ) notify.Subscription {
@@ -78,6 +89,77 @@ func (f *ServiceFeed) SubscribeNewLogs(ch chan<- []*types.Log) notify.Subscripti
78
89
return f .scope .Track (f .newLogs .Subscribe (ch ))
79
90
}
80
91
92
+ func (f * ServiceFeed ) Start (store * evmstore.Store ) {
93
+ incoming := make (chan feedUpdate , 1024 )
94
+ f .incomingUpdates = incoming
95
+ stop := make (chan struct {})
96
+ done := make (chan struct {})
97
+ f .stopFeeder = stop
98
+ f .feederDone = done
99
+ go func () {
100
+ defer close (done )
101
+ ticker := time .NewTicker (10 * time .Millisecond )
102
+ defer ticker .Stop ()
103
+ pending := []feedUpdate {}
104
+ for {
105
+ select {
106
+ case <- stop :
107
+ return
108
+ case update := <- incoming :
109
+ pending = append (pending , update )
110
+ // sorting could be replaced by a heap or skipped if updates
111
+ // are guaranteed to be delivered in order.
112
+ slices .SortFunc (pending , func (a , b feedUpdate ) int {
113
+ return a .block .Number .Cmp (b .block .Number )
114
+ })
115
+
116
+ case <- ticker .C :
117
+ }
118
+
119
+ if len (pending ) == 0 {
120
+ continue
121
+ }
122
+
123
+ height , empty , err := store .GetArchiveBlockHeight ()
124
+ if err != nil {
125
+ log .Error ("failed to get archive block height" , "err" , err )
126
+ continue
127
+ }
128
+ if empty {
129
+ continue
130
+ }
131
+ for _ , update := range pending {
132
+ if update .block .Number .Uint64 () > height {
133
+ break
134
+ }
135
+ f .newBlock .Send (evmcore.ChainHeadNotify {Block : update .block })
136
+ f .newLogs .Send (update .logs )
137
+ pending = pending [1 :]
138
+ }
139
+ }
140
+ }()
141
+ }
142
+
143
+ func (f * ServiceFeed ) notifyAboutNewBlock (
144
+ block * evmcore.EvmBlock ,
145
+ logs []* types.Log ,
146
+ ) {
147
+ f .incomingUpdates <- feedUpdate {
148
+ block : block ,
149
+ logs : logs ,
150
+ }
151
+ }
152
+
153
+ func (f * ServiceFeed ) Stop () {
154
+ if f .stopFeeder == nil {
155
+ return
156
+ }
157
+ close (f .stopFeeder )
158
+ f .stopFeeder = nil
159
+ <- f .feederDone
160
+ f .scope .Close ()
161
+ }
162
+
81
163
type BlockProc struct {
82
164
SealerModule blockproc.SealerModule
83
165
TxListenerModule blockproc.TxListenerModule
@@ -131,7 +213,7 @@ type Service struct {
131
213
blockBusyFlag uint32
132
214
eventBusyFlag uint32
133
215
134
- feed ServiceFeed
216
+ feed ServiceFeed
135
217
136
218
gpo * gasprice.Oracle
137
219
@@ -250,11 +332,11 @@ func newService(config Config, store *Store, blockProc BlockProc, engine lachesi
250
332
defer done ()
251
333
return svc .processEvent (event )
252
334
},
253
- SwitchEpochTo : svc .SwitchEpochTo ,
254
- BVs : svc .ProcessBlockVotes ,
255
- BR : svc .ProcessFullBlockRecord ,
256
- EV : svc .ProcessEpochVote ,
257
- ER : svc .ProcessFullEpochRecord ,
335
+ SwitchEpochTo : svc .SwitchEpochTo ,
336
+ BVs : svc .ProcessBlockVotes ,
337
+ BR : svc .ProcessFullBlockRecord ,
338
+ EV : svc .ProcessEpochVote ,
339
+ ER : svc .ProcessFullEpochRecord ,
258
340
},
259
341
})
260
342
if err != nil {
@@ -435,6 +517,8 @@ func (s *Service) Start() error {
435
517
if s .store .evm .CheckLiveStateHash (blockState .LastBlock .Idx , blockState .FinalizedStateRoot ) != nil {
436
518
return errors .New ("fullsync isn't possible because state root is missing" )
437
519
}
520
+ // start notification feeder
521
+ s .feed .Start (s .store .evm )
438
522
439
523
// start blocks processor
440
524
s .blockProcTasks .Start (1 )
@@ -475,7 +559,7 @@ func (s *Service) Stop() error {
475
559
s .operaDialCandidates .Close ()
476
560
477
561
s .handler .Stop ()
478
- s .feed .scope . Close ()
562
+ s .feed .Stop ()
479
563
s .gpo .Stop ()
480
564
// it's safe to stop tflusher only before locking engineMu
481
565
s .tflusher .Stop ()
0 commit comments