prysm-pulse/beacon-chain/node/node_test.go
Sammy Rosso 3bd116db16
Blob filesystem add pruning at startup (#13253)
* Add Save blob and tests

* Remove locks

* Remove test cleanup

* Fix go mod

* Cleanup

* Add checksum

* Add file hashing to fileutil

* Move test

* Check data when exists

* Add one more test

* Rename

* Gaz

* Add packaged level comment

* Fix block proposals in the REST validator client (#13116)

* Fix block proposals in the REST validator client

* fix graffiti test

* return empty graffiti

* fallback to old endpoints

* logs

* handle 404

* everything passes

* review from James

* log undecoded value

* test fixes and additions

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>

* fix head slot in log (#13139)

* zig: Update zig to recent main branch commit (#13142)

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>

* Fix Pending Queue Deadline Bug (#13145)

* rearrange deadline

* naming

* Add pruning

* Gaz

* Gaz

* Update pruning

* Cleanup

* Making a mess

* Benchmarking

* Forgot to add the file + fixes

* Fixes

* Pruning from DB fixed

* Add prune by file data

* Fix pruning

* Prune fixes

* Cleanup db blockRoot filter

* Handle file close error

* Fix deletion

* Change read at + remove retentionEpich from bs

* Gaz

* Seperate logic + add detailed comments

* Add tests

* Add retention slot when creating blobStorage

* Fix tests

* Gaz

* Fix testonly import

* Add pruning at startup

* Add nil check

* Fix merge errors

* Fix test

* Fix test

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
Co-authored-by: Potuz <potuz@prysmaticlabs.com>
Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
Co-authored-by: Nishant Das <nishdas93@gmail.com>
2023-12-11 17:08:52 +00:00

275 lines
9.8 KiB
Go

package node
import (
"context"
"flag"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strconv"
"testing"
"time"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/builder"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db/filesystem"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/execution"
mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/monitor"
"github.com/prysmaticlabs/prysm/v4/cmd"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v4/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/runtime"
"github.com/prysmaticlabs/prysm/v4/runtime/interop"
"github.com/prysmaticlabs/prysm/v4/testing/require"
logTest "github.com/sirupsen/logrus/hooks/test"
"github.com/urfave/cli/v2"
)
// Ensure BeaconNode implements interfaces.
var _ statefeed.Notifier = (*BeaconNode)(nil)
func newCliContextWithCancel(app *cli.App, set *flag.FlagSet) (*cli.Context, context.CancelFunc) {
context, cancel := context.WithCancel(context.Background())
parent := &cli.Context{Context: context}
return cli.NewContext(app, set, parent), cancel
}
// Test that beacon chain node can close.
func TestNodeClose_OK(t *testing.T) {
hook := logTest.NewGlobal()
tmp := fmt.Sprintf("%s/datadirtest2", t.TempDir())
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.Bool("test-skip-pow", true, "skip pow dial")
set.String("datadir", tmp, "node data directory")
set.String("p2p-encoding", "ssz", "p2p encoding scheme")
set.Bool("demo-config", true, "demo configuration")
set.String("deposit-contract", "0x0000000000000000000000000000000000000000", "deposit contract address")
set.String("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A", "fee recipient")
require.NoError(t, set.Set("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A"))
cmd.ValidatorMonitorIndicesFlag.Value = &cli.IntSlice{}
cmd.ValidatorMonitorIndicesFlag.Value.SetInt(1)
ctx, cancel := newCliContextWithCancel(&app, set)
node, err := New(ctx, cancel, WithBlobStorage(filesystem.NewEphemeralBlobStorage(t)))
require.NoError(t, err)
node.Close()
require.LogsContain(t, hook, "Stopping beacon node")
}
func TestNodeStart_Ok(t *testing.T) {
hook := logTest.NewGlobal()
app := cli.App{}
tmp := fmt.Sprintf("%s/datadirtest2", t.TempDir())
set := flag.NewFlagSet("test", 0)
set.String("datadir", tmp, "node data directory")
set.String("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A", "fee recipient")
require.NoError(t, set.Set("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A"))
ctx, cancel := newCliContextWithCancel(&app, set)
node, err := New(ctx, cancel, WithBlockchainFlagOptions([]blockchain.Option{}),
WithBuilderFlagOptions([]builder.Option{}),
WithExecutionChainOptions([]execution.Option{}),
WithBlobStorage(filesystem.NewEphemeralBlobStorage(t)))
require.NoError(t, err)
node.services = &runtime.ServiceRegistry{}
go func() {
node.Start()
}()
time.Sleep(3 * time.Second)
node.Close()
require.LogsContain(t, hook, "Starting beacon node")
}
func TestNodeStart_Ok_registerDeterministicGenesisService(t *testing.T) {
numValidators := uint64(1)
hook := logTest.NewGlobal()
app := cli.App{}
tmp := fmt.Sprintf("%s/datadirtest2", t.TempDir())
set := flag.NewFlagSet("test", 0)
set.String("datadir", tmp, "node data directory")
set.Uint64(flags.InteropNumValidatorsFlag.Name, numValidators, "")
set.String("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A", "fee recipient")
require.NoError(t, set.Set("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A"))
genesisState, _, err := interop.GenerateGenesisState(context.Background(), 0, numValidators)
require.NoError(t, err, "Could not generate genesis beacon state")
for i := uint64(1); i < 2; i++ {
var someRoot [32]byte
var someKey [fieldparams.BLSPubkeyLength]byte
copy(someRoot[:], strconv.Itoa(int(i)))
copy(someKey[:], strconv.Itoa(int(i)))
genesisState.Validators = append(genesisState.Validators, &ethpb.Validator{
PublicKey: someKey[:],
WithdrawalCredentials: someRoot[:],
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
Slashed: false,
ActivationEligibilityEpoch: 1,
ActivationEpoch: 1,
ExitEpoch: 1,
WithdrawableEpoch: 1,
})
genesisState.Balances = append(genesisState.Balances, params.BeaconConfig().MaxEffectiveBalance)
}
genesisBytes, err := genesisState.MarshalSSZ()
require.NoError(t, err)
require.NoError(t, os.WriteFile("genesis_ssz.json", genesisBytes, 0666))
set.String("genesis-state", "genesis_ssz.json", "")
ctx, cancel := newCliContextWithCancel(&app, set)
node, err := New(ctx, cancel, WithBlockchainFlagOptions([]blockchain.Option{}),
WithBuilderFlagOptions([]builder.Option{}),
WithExecutionChainOptions([]execution.Option{}),
WithBlobStorage(filesystem.NewEphemeralBlobStorage(t)))
require.NoError(t, err)
node.services = &runtime.ServiceRegistry{}
go func() {
node.Start()
}()
time.Sleep(3 * time.Second)
node.Close()
require.LogsContain(t, hook, "Starting beacon node")
require.NoError(t, os.Remove("genesis_ssz.json"))
}
// TestClearDB tests clearing the database
func TestClearDB(t *testing.T) {
hook := logTest.NewGlobal()
srv, endpoint, err := mockExecution.SetupRPCServer()
require.NoError(t, err)
t.Cleanup(func() {
srv.Stop()
})
tmp := filepath.Join(t.TempDir(), "datadirtest")
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String("datadir", tmp, "node data directory")
set.Bool(cmd.ForceClearDB.Name, true, "force clear db")
set.String("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A", "fee recipient")
require.NoError(t, set.Set("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A"))
context, cancel := newCliContextWithCancel(&app, set)
options := []Option{
WithExecutionChainOptions([]execution.Option{execution.WithHttpEndpoint(endpoint)}),
WithBlobStorage(filesystem.NewEphemeralBlobStorage(t)),
}
_, err = New(context, cancel, options...)
require.NoError(t, err)
require.LogsContain(t, hook, "Removing database")
}
func TestMonitor_RegisteredCorrectly(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
require.NoError(t, cmd.ValidatorMonitorIndicesFlag.Apply(set))
cliCtx := cli.NewContext(&app, set, nil)
require.NoError(t, cliCtx.Set(cmd.ValidatorMonitorIndicesFlag.Name, "1,2"))
n := &BeaconNode{ctx: context.Background(), cliCtx: cliCtx, services: runtime.NewServiceRegistry()}
require.NoError(t, n.services.RegisterService(&blockchain.Service{}))
require.NoError(t, n.registerValidatorMonitorService(make(chan struct{})))
var mService *monitor.Service
require.NoError(t, n.services.FetchService(&mService))
require.Equal(t, true, mService.TrackedValidators[1])
require.Equal(t, true, mService.TrackedValidators[2])
require.Equal(t, false, mService.TrackedValidators[100])
}
func Test_hasNetworkFlag(t *testing.T) {
tests := []struct {
name string
networkName string
networkValue string
want bool
}{
{
name: "Prater testnet",
networkName: features.PraterTestnet.Name,
networkValue: "prater",
want: true,
},
{
name: "Mainnet",
networkName: features.Mainnet.Name,
networkValue: "mainnet",
want: true,
},
{
name: "No network flag",
networkName: "",
networkValue: "",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.String(tt.networkName, tt.networkValue, tt.name)
cliCtx := cli.NewContext(&cli.App{}, set, nil)
err := cliCtx.Set(tt.networkName, tt.networkValue)
require.NoError(t, err)
if got := hasNetworkFlag(cliCtx); got != tt.want {
t.Errorf("hasNetworkFlag() = %v, want %v", got, tt.want)
}
})
}
}
func TestCORS(t *testing.T) {
// Mock CLI context with a test CORS domain
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String(flags.GPRCGatewayCorsDomain.Name, "http://allowed-example.com", "")
cliCtx := cli.NewContext(&app, set, nil)
require.NoError(t, cliCtx.Set(flags.GPRCGatewayCorsDomain.Name, "http://allowed-example.com"))
router := newRouter(cliCtx)
// Ensure a test route exists
router.HandleFunc("/some-path", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}).Methods(http.MethodGet)
// Define test cases
tests := []struct {
name string
origin string
expectAllow bool
}{
{"AllowedOrigin", "http://allowed-example.com", true},
{"DisallowedOrigin", "http://disallowed-example.com", false},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// Create a request and response recorder
req := httptest.NewRequest("GET", "http://example.com/some-path", nil)
req.Header.Set("Origin", tc.origin)
rr := httptest.NewRecorder()
// Serve HTTP
router.ServeHTTP(rr, req)
// Check the CORS headers based on the expected outcome
if tc.expectAllow && rr.Header().Get("Access-Control-Allow-Origin") != tc.origin {
t.Errorf("Expected Access-Control-Allow-Origin header to be %v, got %v", tc.origin, rr.Header().Get("Access-Control-Allow-Origin"))
}
if !tc.expectAllow && rr.Header().Get("Access-Control-Allow-Origin") != "" {
t.Errorf("Expected Access-Control-Allow-Origin header to be empty for disallowed origin, got %v", rr.Header().Get("Access-Control-Allow-Origin"))
}
})
}
}