@@ -139,3 +139,64 @@ func TestSimulatedBeaconSendWithdrawals(t *testing.T) {
139
139
}
140
140
}
141
141
}
142
+
143
+ func TestSimulatedBeaconAPIDeadlocksInExtremeConditions (t * testing.T ) {
144
+ txs := make (map [common.Hash ]types.Transaction )
145
+
146
+ var (
147
+ // testKey is a private key to use for funding a tester account.
148
+ testKey , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
149
+
150
+ // testAddr is the Ethereum address of the tester account.
151
+ testAddr = crypto .PubkeyToAddress (testKey .PublicKey )
152
+ )
153
+
154
+ // short period (1 second) for testing purposes
155
+ var gasLimit uint64 = 10_000_000
156
+ genesis := core .DeveloperGenesisBlock (gasLimit , & testAddr )
157
+ node , ethService , mock := startSimulatedBeaconEthService (t , genesis )
158
+ _ = mock
159
+ defer node .Close ()
160
+
161
+ // simulated beacon api
162
+ mockApi := & api {mock }
163
+ go mockApi .loop ()
164
+
165
+ chainHeadCh := make (chan core.ChainHeadEvent , 10 )
166
+ subscription := ethService .BlockChain ().SubscribeChainHeadEvent (chainHeadCh )
167
+ defer subscription .Unsubscribe ()
168
+
169
+ // generate a bunch of transactions to overload simulated beacon api
170
+ // current capacity of core.NewTxsEvent channel is 15, we send 30 txs
171
+ signer := types .NewEIP155Signer (ethService .BlockChain ().Config ().ChainID )
172
+ for i := 0 ; i < 30 ; i ++ {
173
+ tx , err := types .SignTx (types .NewTransaction (uint64 (i ), common.Address {}, big .NewInt (1000 ), params .TxGas , big .NewInt (params .InitialBaseFee ), nil ), signer , testKey )
174
+ if err != nil {
175
+ t .Fatalf ("error signing transaction, err=%v" , err )
176
+ }
177
+ txs [tx .Hash ()] = * tx
178
+
179
+ if err := ethService .APIBackend .SendTx (context .Background (), tx ); err != nil {
180
+ t .Fatal ("SendTx failed" , err )
181
+ }
182
+ }
183
+
184
+ includedTxs := make (map [common.Hash ]struct {})
185
+
186
+ timer := time .NewTimer (12 * time .Second )
187
+ for {
188
+ select {
189
+ case evt := <- chainHeadCh :
190
+ for _ , includedTx := range evt .Block .Transactions () {
191
+ includedTxs [includedTx .Hash ()] = struct {}{}
192
+ }
193
+
194
+ // ensure all withdrawals/txs included. this will take two blocks b/c number of withdrawals > 10
195
+ if len (includedTxs ) == len (txs ) {
196
+ t .Fatal ("all txs were included, the simulated beacon api did not deadlock" )
197
+ }
198
+ case <- timer .C :
199
+ return
200
+ }
201
+ }
202
+ }
0 commit comments