github.com/prysmaticlabs/prysm@v1.4.4/endtoend/evaluators/node.go (about) 1 // Package evaluators defines functions which can peer into end to end 2 // tests to determine if a chain is running as required. 3 package evaluators 4 5 import ( 6 "bytes" 7 "context" 8 "fmt" 9 "io/ioutil" 10 "net/http" 11 "time" 12 13 "github.com/pkg/errors" 14 types "github.com/prysmaticlabs/eth2-types" 15 e2e "github.com/prysmaticlabs/prysm/endtoend/params" 16 "github.com/prysmaticlabs/prysm/endtoend/policies" 17 e2etypes "github.com/prysmaticlabs/prysm/endtoend/types" 18 eth "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 19 "google.golang.org/grpc" 20 "google.golang.org/protobuf/types/known/emptypb" 21 ) 22 23 // Allow a very short delay after disconnecting to prevent connection refused issues. 24 var connTimeDelay = 50 * time.Millisecond 25 26 // PeersConnect checks all beacon nodes and returns whether they are connected to each other as peers. 27 var PeersConnect = e2etypes.Evaluator{ 28 Name: "peers_connect_epoch_%d", 29 Policy: policies.OnEpoch(0), 30 Evaluation: peersConnect, 31 } 32 33 // HealthzCheck pings healthz and errors if it doesn't have the expected OK status. 34 var HealthzCheck = e2etypes.Evaluator{ 35 Name: "healthz_check_epoch_%d", 36 Policy: policies.AfterNthEpoch(0), 37 Evaluation: healthzCheck, 38 } 39 40 // FinishedSyncing returns whether the beacon node with the given rpc port has finished syncing. 41 var FinishedSyncing = e2etypes.Evaluator{ 42 Name: "finished_syncing", 43 Policy: policies.AllEpochs, 44 Evaluation: finishedSyncing, 45 } 46 47 // AllNodesHaveSameHead ensures all nodes have the same head epoch. Checks finality and justification as well. 48 // Not checking head block root as it may change irregularly for the validator connected nodes. 49 var AllNodesHaveSameHead = e2etypes.Evaluator{ 50 Name: "all_nodes_have_same_head", 51 Policy: policies.AllEpochs, 52 Evaluation: allNodesHaveSameHead, 53 } 54 55 func healthzCheck(conns ...*grpc.ClientConn) error { 56 count := len(conns) 57 for i := 0; i < count; i++ { 58 resp, err := http.Get(fmt.Sprintf("http://localhost:%d/healthz", e2e.TestParams.BeaconNodeMetricsPort+i)) 59 if err != nil { 60 // Continue if the connection fails, regular flake. 61 continue 62 } 63 if resp.StatusCode != http.StatusOK { 64 body, err := ioutil.ReadAll(resp.Body) 65 if err != nil { 66 return err 67 } 68 return fmt.Errorf("expected status code OK for beacon node %d, received %v with body %s", i, resp.StatusCode, body) 69 } 70 if err = resp.Body.Close(); err != nil { 71 return err 72 } 73 time.Sleep(connTimeDelay) 74 } 75 76 for i := 0; i < count; i++ { 77 resp, err := http.Get(fmt.Sprintf("http://localhost:%d/healthz", e2e.TestParams.ValidatorMetricsPort+i)) 78 if err != nil { 79 // Continue if the connection fails, regular flake. 80 continue 81 } 82 if resp.StatusCode != http.StatusOK { 83 body, err := ioutil.ReadAll(resp.Body) 84 if err != nil { 85 return err 86 } 87 return fmt.Errorf("expected status code OK for validator client %d, received %v with body %s", i, resp.StatusCode, body) 88 } 89 if err = resp.Body.Close(); err != nil { 90 return err 91 } 92 time.Sleep(connTimeDelay) 93 } 94 return nil 95 } 96 97 func peersConnect(conns ...*grpc.ClientConn) error { 98 if len(conns) == 1 { 99 return nil 100 } 101 ctx := context.Background() 102 for _, conn := range conns { 103 nodeClient := eth.NewNodeClient(conn) 104 peersResp, err := nodeClient.ListPeers(ctx, &emptypb.Empty{}) 105 if err != nil { 106 return err 107 } 108 expectedPeers := len(conns) - 1 109 if expectedPeers != len(peersResp.Peers) { 110 return fmt.Errorf("unexpected amount of peers, expected %d, received %d", expectedPeers, len(peersResp.Peers)) 111 } 112 time.Sleep(connTimeDelay) 113 } 114 return nil 115 } 116 117 func finishedSyncing(conns ...*grpc.ClientConn) error { 118 conn := conns[0] 119 syncNodeClient := eth.NewNodeClient(conn) 120 syncStatus, err := syncNodeClient.GetSyncStatus(context.Background(), &emptypb.Empty{}) 121 if err != nil { 122 return err 123 } 124 if syncStatus.Syncing { 125 return errors.New("expected node to have completed sync") 126 } 127 return nil 128 } 129 130 func allNodesHaveSameHead(conns ...*grpc.ClientConn) error { 131 headEpochs := make([]types.Epoch, len(conns)) 132 justifiedRoots := make([][]byte, len(conns)) 133 prevJustifiedRoots := make([][]byte, len(conns)) 134 finalizedRoots := make([][]byte, len(conns)) 135 for i, conn := range conns { 136 beaconClient := eth.NewBeaconChainClient(conn) 137 chainHead, err := beaconClient.GetChainHead(context.Background(), &emptypb.Empty{}) 138 if err != nil { 139 return err 140 } 141 headEpochs[i] = chainHead.HeadEpoch 142 justifiedRoots[i] = chainHead.JustifiedBlockRoot 143 prevJustifiedRoots[i] = chainHead.PreviousJustifiedBlockRoot 144 finalizedRoots[i] = chainHead.FinalizedBlockRoot 145 time.Sleep(connTimeDelay) 146 } 147 148 for i := 0; i < len(conns); i++ { 149 if headEpochs[0] != headEpochs[i] { 150 return fmt.Errorf( 151 "received conflicting head epochs on node %d, expected %d, received %d", 152 i, 153 headEpochs[0], 154 headEpochs[i], 155 ) 156 } 157 if !bytes.Equal(justifiedRoots[0], justifiedRoots[i]) { 158 return fmt.Errorf( 159 "received conflicting justified block roots on node %d, expected %#x, received %#x", 160 i, 161 justifiedRoots[0], 162 justifiedRoots[i], 163 ) 164 } 165 if !bytes.Equal(prevJustifiedRoots[0], prevJustifiedRoots[i]) { 166 return fmt.Errorf( 167 "received conflicting previous justified block roots on node %d, expected %#x, received %#x", 168 i, 169 prevJustifiedRoots[0], 170 prevJustifiedRoots[i], 171 ) 172 } 173 if !bytes.Equal(finalizedRoots[0], finalizedRoots[i]) { 174 return fmt.Errorf( 175 "received conflicting finalized epoch roots on node %d, expected %#x, received %#x", 176 i, 177 finalizedRoots[0], 178 finalizedRoots[i], 179 ) 180 } 181 } 182 183 return nil 184 }