@@ -20,6 +20,7 @@ import (
20
20
"bytes"
21
21
"fmt"
22
22
"math/big"
23
+ "sync"
23
24
"testing"
24
25
"time"
25
26
@@ -277,10 +278,12 @@ func TestEth2NewBlock(t *testing.T) {
277
278
t .Fatalf ("Failed to convert executable data to block %v" , err )
278
279
}
279
280
newResp , err := api .NewPayloadV1 (* execData )
280
- if err != nil || newResp .Status != "VALID" {
281
+ switch {
282
+ case err != nil :
281
283
t .Fatalf ("Failed to insert block: %v" , err )
282
- }
283
- if ethservice .BlockChain ().CurrentBlock ().NumberU64 () != block .NumberU64 ()- 1 {
284
+ case newResp .Status != "VALID" :
285
+ t .Fatalf ("Failed to insert block: %v" , newResp .Status )
286
+ case ethservice .BlockChain ().CurrentBlock ().NumberU64 () != block .NumberU64 ()- 1 :
284
287
t .Fatalf ("Chain head shouldn't be updated" )
285
288
}
286
289
checkLogEvents (t , newLogCh , rmLogsCh , 0 , 0 )
@@ -292,8 +295,8 @@ func TestEth2NewBlock(t *testing.T) {
292
295
if _ , err := api .ForkchoiceUpdatedV1 (fcState , nil ); err != nil {
293
296
t .Fatalf ("Failed to insert block: %v" , err )
294
297
}
295
- if ethservice .BlockChain ().CurrentBlock ().NumberU64 () != block .NumberU64 () {
296
- t .Fatalf ("Chain head should be updated" )
298
+ if have , want := ethservice .BlockChain ().CurrentBlock ().NumberU64 (), block .NumberU64 (); have != want {
299
+ t .Fatalf ("Chain head should be updated, have %d want %d" , have , want )
297
300
}
298
301
checkLogEvents (t , newLogCh , rmLogsCh , 1 , 0 )
299
302
@@ -855,3 +858,102 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
855
858
t .Fatalf ("error sending invalid forkchoice, invalid status: %v" , resp .PayloadStatus .Status )
856
859
}
857
860
}
861
+
862
+ // TestSimultaneousNewBlock does several parallel inserts, both as
863
+ // newPayLoad and forkchoiceUpdate. This is to test that the api behaves
864
+ // well even of the caller is not being 'serial'.
865
+ func TestSimultaneousNewBlock (t * testing.T ) {
866
+ genesis , preMergeBlocks := generatePreMergeChain (10 )
867
+ n , ethservice := startEthService (t , genesis , preMergeBlocks )
868
+ defer n .Close ()
869
+
870
+ var (
871
+ api = NewConsensusAPI (ethservice )
872
+ parent = preMergeBlocks [len (preMergeBlocks )- 1 ]
873
+ )
874
+ for i := 0 ; i < 10 ; i ++ {
875
+ statedb , _ := ethservice .BlockChain ().StateAt (parent .Root ())
876
+ ethservice .TxPool ().AddLocal (types .MustSignNewTx (testKey , types .LatestSigner (ethservice .BlockChain ().Config ()),
877
+ & types.DynamicFeeTx {
878
+ Nonce : statedb .GetNonce (testAddr ),
879
+ Value : big .NewInt (0 ),
880
+ GasFeeCap : big .NewInt (2 * params .InitialBaseFee ),
881
+ GasTipCap : big .NewInt (2 * params .InitialBaseFee ),
882
+ ChainID : genesis .Config .ChainID ,
883
+ Gas : 1000000 ,
884
+ To : & common.Address {99 },
885
+ }))
886
+ execData , err := assembleBlock (api , parent .Hash (), & beacon.PayloadAttributesV1 {
887
+ Timestamp : parent .Time () + 5 ,
888
+ })
889
+ if err != nil {
890
+ t .Fatalf ("Failed to create the executable data %v" , err )
891
+ }
892
+ // Insert it 10 times in parallel. Should be ignored.
893
+ {
894
+ var (
895
+ wg sync.WaitGroup
896
+ testErr error
897
+ errMu sync.Mutex
898
+ )
899
+ wg .Add (10 )
900
+ for ii := 0 ; ii < 10 ; ii ++ {
901
+ go func () {
902
+ defer wg .Done ()
903
+ if newResp , err := api .NewPayloadV1 (* execData ); err != nil {
904
+ errMu .Lock ()
905
+ testErr = fmt .Errorf ("Failed to insert block: %w" , err )
906
+ errMu .Unlock ()
907
+ } else if newResp .Status != "VALID" {
908
+ errMu .Lock ()
909
+ testErr = fmt .Errorf ("Failed to insert block: %v" , newResp .Status )
910
+ errMu .Unlock ()
911
+ }
912
+ }()
913
+ }
914
+ wg .Wait ()
915
+ if testErr != nil {
916
+ t .Fatal (testErr )
917
+ }
918
+ }
919
+ block , err := beacon .ExecutableDataToBlock (* execData )
920
+ if err != nil {
921
+ t .Fatalf ("Failed to convert executable data to block %v" , err )
922
+ }
923
+ if ethservice .BlockChain ().CurrentBlock ().NumberU64 () != block .NumberU64 ()- 1 {
924
+ t .Fatalf ("Chain head shouldn't be updated" )
925
+ }
926
+ fcState := beacon.ForkchoiceStateV1 {
927
+ HeadBlockHash : block .Hash (),
928
+ SafeBlockHash : block .Hash (),
929
+ FinalizedBlockHash : block .Hash (),
930
+ }
931
+ {
932
+ var (
933
+ wg sync.WaitGroup
934
+ testErr error
935
+ errMu sync.Mutex
936
+ )
937
+ wg .Add (10 )
938
+ // Do each FCU 10 times
939
+ for ii := 0 ; ii < 10 ; ii ++ {
940
+ go func () {
941
+ defer wg .Done ()
942
+ if _ , err := api .ForkchoiceUpdatedV1 (fcState , nil ); err != nil {
943
+ errMu .Lock ()
944
+ testErr = fmt .Errorf ("Failed to insert block: %w" , err )
945
+ errMu .Unlock ()
946
+ }
947
+ }()
948
+ }
949
+ wg .Wait ()
950
+ if testErr != nil {
951
+ t .Fatal (testErr )
952
+ }
953
+ }
954
+ if have , want := ethservice .BlockChain ().CurrentBlock ().NumberU64 (), block .NumberU64 (); have != want {
955
+ t .Fatalf ("Chain head should be updated, have %d want %d" , have , want )
956
+ }
957
+ parent = block
958
+ }
959
+ }
0 commit comments