prysm-pulse/testing/endtoend/helpers/helpers.go
james-prysm aed6e13498
Web3Signer: CLI implementation (#10056)
* initial commit for cli integration of web3signer

* resolving conflicts and execution

* remove aggregation slot from proto

* rem aggregation slot

* define a sync message block root struct

* fix sync message name

* sync message block root struct

* amend where sync committee block root is used

* altered switch statement to return correct json request by type

* fixing fork data import, types, and unit tests

* reverting unwanted changes

* reverting more unwanted changes

* fixing deepsource issues

* fixing formatting

* more fixes for deepsource and code clean up

* only want to fetch once for fetch validating public keys

* adding more comments

* new unit tests for requests and fixing a mapper issue

* Update validator/client/validator.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update validator/accounts/wallet/wallet.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* adjusting comment

* adjusting comment

* fixing import organization

* including more unit tests

* adding new cli edit

* adding in checks for wallet initialize

* adding web3signer flags to main.go

* some how resolved files did not save correctly

* adding in check to make sure web flag only works with types imported and derived

* Update validator/client/sync_committee.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update validator/client/aggregate.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update validator/accounts/wallet/wallet.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update cmd/validator/wallet/wallet.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update cmd/validator/wallet/wallet.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update cmd/validator/main.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update cmd/validator/flags/flags.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update cmd/validator/flags/flags.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update cmd/validator/wallet/wallet.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update cmd/validator/wallet/wallet.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* reverting changes that accidently got checked in

* reverting

* reverting

* continuing to revert unintenteded changes

* reverting

* removing more unneeded changes

* addressing review comment

* initial refactor

* adding in more clarifying comments

* fixing mock

* resolving desource issues

* addressing gosec scan for helper go file

* addressing gosec

* trying to fix bazel build

* removal of interface to fix build

* fixing maligned struct

* addressing deepsource

* fixing deepsource

* addressing efficiency of type checking

* fixing bazel test failure

* fixing go linter errors

* gaz

* web changes

* add w3signer

* new kind

* proper use

* align

* adding prysm validator flags to help flags list

* addressing root comment

* ci lint

* fixing standardapi tests

* fixing accounts_test after removal of keymanager from rpc server

* fixing more unit tests

* Update cmd/validator/flags/flags.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update cmd/validator/flags/flags.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update validator/client/service.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update validator/client/service.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* addressing missed err checks

* fixing mock tests

* fixing gofmt

* unskipping minimal e2e test and removing related TODOs

* Update testing/endtoend/components/validator.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update testing/endtoend/components/validator.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* adding some error wrapers to clarify failure point

* fixing bazel build with new error checks

* taking preston's advice to make test fail faster to understand what's going on with the test

* checking if genesis validators root is not zero hash

* adding check for genesis validators root giving zero hash

* fixing missing dependency

* adding check for wallet

* log all

* fixing errors for http responses

* switching marshal to pretty print

* adding pretty sign request test

* fixing base url setting

* adding in check for web3signer and temporary wallet instead of having to open the wallet

* refactoring web3signer to not require wallet

* bazel build fix

* fixing gazelle build

* adding content type of request

* fixing more bazel

* removing unused code

* removing unused comments

* adding skip test back in

* addressing a validation and error message

* fix parse

* body

* fixing logic for datadir

* improving error handling

* show resp

* fix

* sign resp as str

* point of pointer remove

* sign resp

* unmarshal sig resp

* read body as str

* adding more verbose logging

* removing unused result

* fixing unit test

* reconfiguring files to properly nest code and mocks

* fix build issue

* using context when using client function calls

* fixing based on suggestion

* addressing comments

* gaz

* removing defined max timeout

* reverting json print pretty

* Update validator/accounts/wallet_edit.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* removing unneeded code restrictions

* should not introduce new code that may impact existing key manager types

* adjusting comments

* adding in json validation

* running go mod tidy

* some logging

* more logs

* fixing typo

* remove logs

* testing without byte trim

* fixing order or properties

* gaz

* tidy

* reverting some logs

* removing the confusing comments

* Update validator/client/aggregate.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update validator/client/aggregate.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* addressing pr comments

* editing bytes test

* Run gazelle update-repos

* run gazelle

* improving unit test coverage

* fixing text

* fixing a potential escaped error

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
2022-01-31 10:44:17 -06:00

277 lines
7.9 KiB
Go

// Package helpers defines helper functions to peer into
// end to end processes and kill processes as needed.
package helpers
import (
"bufio"
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"testing"
"time"
"github.com/prysmaticlabs/prysm/config/params"
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
e2e "github.com/prysmaticlabs/prysm/testing/endtoend/params"
e2etypes "github.com/prysmaticlabs/prysm/testing/endtoend/types"
"github.com/prysmaticlabs/prysm/time/slots"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
)
const (
maxPollingWaitTime = 60 * time.Second // A minute so timing out doesn't take very long.
filePollingInterval = 500 * time.Millisecond
memoryHeapFileName = "node_heap_%d.pb.gz"
cpuProfileFileName = "node_cpu_profile_%d.pb.gz"
fileBufferSize = 64 * 1024
maxFileBufferSize = 1024 * 1024
AltairE2EForkEpoch = 6
)
// Graffiti is a list of sample graffiti strings.
var Graffiti = []string{"Sushi", "Ramen", "Takoyaki"}
// DeleteAndCreateFile checks if the file path given exists, if it does, it deletes it and creates a new file.
// If not, it just creates the requested file.
func DeleteAndCreateFile(tmpPath, fileName string) (*os.File, error) {
filePath := path.Join(tmpPath, fileName)
if _, err := os.Stat(filePath); os.IsExist(err) {
if err = os.Remove(filePath); err != nil {
return nil, err
}
}
newFile, err := os.Create(filepath.Clean(path.Join(tmpPath, fileName)))
if err != nil {
return nil, err
}
return newFile, nil
}
// WaitForTextInFile checks a file every polling interval for the text requested.
func WaitForTextInFile(file *os.File, text string) error {
d := time.Now().Add(maxPollingWaitTime)
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
// Use a ticker with a deadline to poll a given file.
ticker := time.NewTicker(filePollingInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
contents, err := ioutil.ReadAll(file)
if err != nil {
return err
}
return fmt.Errorf("could not find requested text \"%s\" in logs:\n%s", text, contents)
case <-ticker.C:
fileScanner := bufio.NewScanner(file)
buf := make([]byte, 0, fileBufferSize)
fileScanner.Buffer(buf, maxFileBufferSize)
for fileScanner.Scan() {
scanned := fileScanner.Text()
if strings.Contains(scanned, text) {
return nil
}
}
if err := fileScanner.Err(); err != nil {
return err
}
_, err := file.Seek(0, io.SeekStart)
if err != nil {
return err
}
}
}
}
// GraffitiYamlFile outputs graffiti YAML file into a testing directory.
func GraffitiYamlFile(testDir string) (string, error) {
b := []byte(`default: "Rice"
random:
- "Sushi"
- "Ramen"
- "Takoyaki"
`)
f := filepath.Join(testDir, "graffiti.yaml")
if err := ioutil.WriteFile(f, b, os.ModePerm); err != nil {
return "", err
}
return f, nil
}
// LogOutput logs the output of all log files made.
func LogOutput(t *testing.T) {
// Log out errors from beacon chain nodes.
for i := 0; i < e2e.TestParams.BeaconNodeCount; i++ {
beaconLogFile, err := os.Open(path.Join(e2e.TestParams.LogPath, fmt.Sprintf(e2e.BeaconNodeLogFileName, i)))
if err != nil {
t.Fatal(err)
}
LogErrorOutput(t, beaconLogFile, "beacon chain node", i)
validatorLogFile, err := os.Open(path.Join(e2e.TestParams.LogPath, fmt.Sprintf(e2e.ValidatorLogFileName, i)))
if err != nil {
t.Fatal(err)
}
LogErrorOutput(t, validatorLogFile, "validator client", i)
}
t.Logf("Ending time: %s\n", time.Now().String())
}
// LogErrorOutput logs the output of a specific file.
func LogErrorOutput(t *testing.T, file io.Reader, title string, index int) {
var errorLines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
currentLine := scanner.Text()
if strings.Contains(currentLine, "level=error") {
errorLines = append(errorLines, currentLine)
}
}
if len(errorLines) < 1 {
return
}
t.Logf("==================== Start of %s %d error output ==================\n", title, index)
for _, err := range errorLines {
t.Log(err)
}
}
// WritePprofFiles writes the memory heap and cpu profile files to the test path.
func WritePprofFiles(testDir string, index int) error {
url := fmt.Sprintf("http://127.0.0.1:%d/debug/pprof/heap", e2e.TestParams.BeaconNodeRPCPort+50+index)
filePath := filepath.Join(testDir, fmt.Sprintf(memoryHeapFileName, index))
if err := writeURLRespAtPath(url, filePath); err != nil {
return err
}
url = fmt.Sprintf("http://127.0.0.1:%d/debug/pprof/profile", e2e.TestParams.BeaconNodeRPCPort+50+index)
filePath = filepath.Join(testDir, fmt.Sprintf(cpuProfileFileName, index))
return writeURLRespAtPath(url, filePath)
}
func writeURLRespAtPath(url, fp string) error {
resp, err := http.Get(url) // #nosec G107 -- Safe, used internally
if err != nil {
return err
}
defer func() {
if err = resp.Body.Close(); err != nil {
return
}
}()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
file, err := os.Create(filepath.Clean(fp))
if err != nil {
return err
}
if _, err = file.Write(body); err != nil {
return err
}
return nil
}
// NewLocalConnection creates and returns GRPC connection on a given localhost port.
func NewLocalConnection(ctx context.Context, port int) (*grpc.ClientConn, error) {
endpoint := fmt.Sprintf("127.0.0.1:%d", port)
dialOpts := []grpc.DialOption{
grpc.WithInsecure(),
}
conn, err := grpc.DialContext(ctx, endpoint, dialOpts...)
if err != nil {
return nil, err
}
return conn, nil
}
// NewLocalConnections returns number of GRPC connections, along with function to close all of them.
func NewLocalConnections(ctx context.Context, numConns int) ([]*grpc.ClientConn, func(), error) {
conns := make([]*grpc.ClientConn, numConns)
for i := 0; i < len(conns); i++ {
conn, err := NewLocalConnection(ctx, e2e.TestParams.BeaconNodeRPCPort+i)
if err != nil {
return nil, nil, err
}
conns[i] = conn
}
return conns, func() {
for _, conn := range conns {
if err := conn.Close(); err != nil {
log.Error(err)
}
}
}, nil
}
// ComponentsStarted checks, sequentially, each provided component, blocks until all of the components are ready.
func ComponentsStarted(ctx context.Context, comps []e2etypes.ComponentRunner) error {
for _, comp := range comps {
select {
case <-ctx.Done():
return ctx.Err()
case <-comp.Started():
continue
}
}
return nil
}
// EpochTickerStartTime calculates the best time to start epoch ticker for a given genesis.
func EpochTickerStartTime(genesis *eth.Genesis) time.Time {
epochSeconds := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
epochSecondsHalf := time.Duration(int64(epochSeconds*1000)/2) * time.Millisecond
// Adding a half slot here to ensure the requests are in the middle of an epoch.
middleOfEpoch := epochSecondsHalf + slots.DivideSlotBy(2 /* half a slot */)
genesisTime := time.Unix(genesis.GenesisTime.Seconds, 0)
// Offsetting the ticker from genesis so it ticks in the middle of an epoch, in order to keep results consistent.
return genesisTime.Add(middleOfEpoch)
}
// WaitOnNodes waits on nodes to complete execution, accepts function that will be called when all nodes are ready.
func WaitOnNodes(ctx context.Context, nodes []e2etypes.ComponentRunner, nodesStarted func()) error {
// Start nodes.
g, ctx := errgroup.WithContext(ctx)
for _, node := range nodes {
node := node
g.Go(func() error {
return node.Start(ctx)
})
}
// Mark set as ready (happens when all contained nodes report as started).
go func() {
for _, node := range nodes {
select {
case <-ctx.Done():
return
case <-node.Started():
continue
}
}
// When all nodes are done, signal the client. Client handles unresponsive components by setting up
// a deadline for passed in context, and this ensures that nothing breaks if function below is never called.
nodesStarted()
}()
return g.Wait()
}