mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-21 19:20:39 +00:00
refac some (#9185)
This commit is contained in:
parent
ac9f9e0a25
commit
8d4d4d802c
@ -73,7 +73,6 @@ func HandleEndpoint[T any](h EndpointHandler[T]) http.HandlerFunc {
|
||||
ans, err := h.Handle(w, r)
|
||||
log.Debug("beacon api request", "endpoint", r.URL.Path, "duration", time.Since(start))
|
||||
if err != nil {
|
||||
log.Error("beacon api request error", "err", err)
|
||||
var endpointError *EndpointError
|
||||
if e, ok := err.(*EndpointError); ok {
|
||||
endpointError = e
|
||||
|
176
cl/beacon/beaconhttp/args.go
Normal file
176
cl/beacon/beaconhttp/args.go
Normal file
@ -0,0 +1,176 @@
|
||||
package beaconhttp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/ledgerwatch/erigon-lib/common"
|
||||
)
|
||||
|
||||
type chainTag int
|
||||
|
||||
var (
|
||||
Head chainTag = 0
|
||||
Finalized chainTag = 1
|
||||
Justified chainTag = 2
|
||||
Genesis chainTag = 3
|
||||
)
|
||||
|
||||
// Represent either state id or block id
|
||||
type SegmentID struct {
|
||||
tag chainTag
|
||||
slot *uint64
|
||||
root *common.Hash
|
||||
}
|
||||
|
||||
func (c *SegmentID) Head() bool {
|
||||
return c.tag == Head && c.slot == nil && c.root == nil
|
||||
}
|
||||
|
||||
func (c *SegmentID) Finalized() bool {
|
||||
return c.tag == Finalized
|
||||
}
|
||||
|
||||
func (c *SegmentID) Justified() bool {
|
||||
return c.tag == Justified
|
||||
}
|
||||
|
||||
func (c *SegmentID) Genesis() bool {
|
||||
return c.tag == Genesis
|
||||
}
|
||||
|
||||
func (c *SegmentID) GetSlot() *uint64 {
|
||||
return c.slot
|
||||
}
|
||||
|
||||
func (c *SegmentID) GetRoot() *common.Hash {
|
||||
return c.root
|
||||
}
|
||||
|
||||
func EpochFromRequest(r *http.Request) (uint64, error) {
|
||||
// Must only be a number
|
||||
regex := regexp.MustCompile(`^\d+$`)
|
||||
epoch := chi.URLParam(r, "epoch")
|
||||
if !regex.MatchString(epoch) {
|
||||
return 0, fmt.Errorf("invalid path variable: {epoch}")
|
||||
}
|
||||
epochMaybe, err := strconv.ParseUint(epoch, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return epochMaybe, nil
|
||||
}
|
||||
|
||||
func StringFromRequest(r *http.Request, name string) (string, error) {
|
||||
str := chi.URLParam(r, name)
|
||||
if str == "" {
|
||||
return "", nil
|
||||
}
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func BlockIdFromRequest(r *http.Request) (*SegmentID, error) {
|
||||
regex := regexp.MustCompile(`^(?:0x[0-9a-fA-F]{64}|head|finalized|genesis|\d+)$`)
|
||||
|
||||
blockId := chi.URLParam(r, "block_id")
|
||||
if !regex.MatchString(blockId) {
|
||||
return nil, fmt.Errorf("invalid path variable: {block_id}")
|
||||
}
|
||||
|
||||
if blockId == "head" {
|
||||
return &SegmentID{tag: Head}, nil
|
||||
}
|
||||
if blockId == "finalized" {
|
||||
return &SegmentID{tag: Finalized}, nil
|
||||
}
|
||||
if blockId == "genesis" {
|
||||
return &SegmentID{tag: Genesis}, nil
|
||||
}
|
||||
slotMaybe, err := strconv.ParseUint(blockId, 10, 64)
|
||||
if err == nil {
|
||||
return &SegmentID{slot: &slotMaybe}, nil
|
||||
}
|
||||
root := common.HexToHash(blockId)
|
||||
return &SegmentID{
|
||||
root: &root,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func StateIdFromRequest(r *http.Request) (*SegmentID, error) {
|
||||
regex := regexp.MustCompile(`^(?:0x[0-9a-fA-F]{64}|head|finalized|genesis|justified|\d+)$`)
|
||||
|
||||
stateId := chi.URLParam(r, "state_id")
|
||||
if !regex.MatchString(stateId) {
|
||||
return nil, fmt.Errorf("invalid path variable: {state_id}")
|
||||
}
|
||||
|
||||
if stateId == "head" {
|
||||
return &SegmentID{tag: Head}, nil
|
||||
}
|
||||
if stateId == "finalized" {
|
||||
return &SegmentID{tag: Finalized}, nil
|
||||
}
|
||||
if stateId == "genesis" {
|
||||
return &SegmentID{tag: Genesis}, nil
|
||||
}
|
||||
if stateId == "justified" {
|
||||
return &SegmentID{tag: Justified}, nil
|
||||
}
|
||||
slotMaybe, err := strconv.ParseUint(stateId, 10, 64)
|
||||
if err == nil {
|
||||
return &SegmentID{slot: &slotMaybe}, nil
|
||||
}
|
||||
root := common.HexToHash(stateId)
|
||||
return &SegmentID{
|
||||
root: &root,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func HashFromQueryParams(r *http.Request, name string) (*common.Hash, error) {
|
||||
hashStr := r.URL.Query().Get(name)
|
||||
if hashStr == "" {
|
||||
return nil, nil
|
||||
}
|
||||
// check if hashstr is an hex string
|
||||
if len(hashStr) != 2+2*32 {
|
||||
return nil, fmt.Errorf("invalid hash length")
|
||||
}
|
||||
if hashStr[:2] != "0x" {
|
||||
return nil, fmt.Errorf("invalid hash prefix")
|
||||
}
|
||||
notHex, err := regexp.MatchString("[^0-9A-Fa-f]", hashStr[2:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if notHex {
|
||||
return nil, fmt.Errorf("invalid hash characters")
|
||||
}
|
||||
|
||||
hash := common.HexToHash(hashStr)
|
||||
return &hash, nil
|
||||
}
|
||||
|
||||
// uint64FromQueryParams retrieves a number from the query params, in base 10.
|
||||
func Uint64FromQueryParams(r *http.Request, name string) (*uint64, error) {
|
||||
str := r.URL.Query().Get(name)
|
||||
if str == "" {
|
||||
return nil, nil
|
||||
}
|
||||
num, err := strconv.ParseUint(str, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &num, nil
|
||||
}
|
||||
|
||||
// decode a list of strings from the query params
|
||||
func StringListFromQueryParams(r *http.Request, name string) ([]string, error) {
|
||||
str := r.URL.Query().Get(name)
|
||||
if str == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return regexp.MustCompile(`\s*,\s*`).Split(str, -1), nil
|
||||
}
|
95
cl/beacon/beaconhttp/beacon_response.go
Normal file
95
cl/beacon/beaconhttp/beacon_response.go
Normal file
@ -0,0 +1,95 @@
|
||||
package beaconhttp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/ledgerwatch/erigon-lib/types/ssz"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
)
|
||||
|
||||
type BeaconResponse struct {
|
||||
Data any
|
||||
Finalized *bool
|
||||
Version *clparams.StateVersion
|
||||
ExecutionOptimistic *bool
|
||||
|
||||
Extra map[string]any
|
||||
}
|
||||
|
||||
func NewBeaconResponse(data any) *BeaconResponse {
|
||||
return &BeaconResponse{
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *BeaconResponse) With(key string, value any) (out *BeaconResponse) {
|
||||
out = new(BeaconResponse)
|
||||
*out = *r
|
||||
out.Extra[key] = value
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *BeaconResponse) WithFinalized(finalized bool) (out *BeaconResponse) {
|
||||
out = new(BeaconResponse)
|
||||
*out = *r
|
||||
out.Finalized = new(bool)
|
||||
out.ExecutionOptimistic = new(bool)
|
||||
out.Finalized = &finalized
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *BeaconResponse) WithOptimistic(optimistic bool) (out *BeaconResponse) {
|
||||
out = new(BeaconResponse)
|
||||
*out = *r
|
||||
out.ExecutionOptimistic = new(bool)
|
||||
out.ExecutionOptimistic = &optimistic
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *BeaconResponse) WithVersion(version clparams.StateVersion) (out *BeaconResponse) {
|
||||
out = new(BeaconResponse)
|
||||
*out = *r
|
||||
out.Version = new(clparams.StateVersion)
|
||||
out.Version = &version
|
||||
return out
|
||||
}
|
||||
|
||||
func (b *BeaconResponse) MarshalJSON() ([]byte, error) {
|
||||
o := map[string]any{
|
||||
"data": b.Data,
|
||||
}
|
||||
if b.Finalized != nil {
|
||||
o["finalized"] = *b.Finalized
|
||||
}
|
||||
if b.Version != nil {
|
||||
o["version"] = *b.Version
|
||||
}
|
||||
if b.ExecutionOptimistic != nil {
|
||||
o["execution_optimistic"] = *b.ExecutionOptimistic
|
||||
}
|
||||
for k, v := range b.Extra {
|
||||
o[k] = v
|
||||
}
|
||||
return json.Marshal(o)
|
||||
}
|
||||
|
||||
func (b *BeaconResponse) EncodeSSZ(xs []byte) ([]byte, error) {
|
||||
marshaler, ok := b.Data.(ssz.Marshaler)
|
||||
if !ok {
|
||||
return nil, NewEndpointError(http.StatusBadRequest, "This endpoint does not support SSZ response")
|
||||
}
|
||||
encoded, err := marshaler.EncodeSSZ(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
func (b *BeaconResponse) EncodingSizeSSZ() int {
|
||||
marshaler, ok := b.Data.(ssz.Marshaler)
|
||||
if !ok {
|
||||
return 9
|
||||
}
|
||||
return marshaler.EncodingSizeSSZ()
|
||||
}
|
8
cl/beacon/beacontest/errors.go
Normal file
8
cl/beacon/beacontest/errors.go
Normal file
@ -0,0 +1,8 @@
|
||||
package beacontest
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrExpressionMustReturnBool = errors.New("cel expression must return bool")
|
||||
ErrUnknownType = errors.New("unknown type")
|
||||
)
|
436
cl/beacon/beacontest/harness.go
Normal file
436
cl/beacon/beacontest/harness.go
Normal file
@ -0,0 +1,436 @@
|
||||
package beacontest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type HarnessOption func(*Harness) error
|
||||
|
||||
func WithTesting(t *testing.T) func(*Harness) error {
|
||||
return func(h *Harness) error {
|
||||
h.t = t
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithTests(name string, xs []Test) func(*Harness) error {
|
||||
return func(h *Harness) error {
|
||||
h.tests[name] = xs
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithHandler(name string, handler http.Handler) func(*Harness) error {
|
||||
return func(h *Harness) error {
|
||||
h.handlers[name] = handler
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithFilesystem(name string, handler afero.Fs) func(*Harness) error {
|
||||
return func(h *Harness) error {
|
||||
h.fss[name] = handler
|
||||
return nil
|
||||
}
|
||||
}
|
||||
func WithTestFromFs(fs afero.Fs, name string) func(*Harness) error {
|
||||
return func(h *Harness) error {
|
||||
filename := name
|
||||
for _, fn := range []string{name, name + ".yaml", name + ".yml", name + ".json"} {
|
||||
// check if file exists
|
||||
_, err := fs.Stat(fn)
|
||||
if err == nil {
|
||||
filename = fn
|
||||
break
|
||||
}
|
||||
}
|
||||
xs, err := afero.ReadFile(fs, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return WithTestFromBytes(name, xs)(h)
|
||||
}
|
||||
}
|
||||
|
||||
type Extra struct {
|
||||
Vars map[string]any `json:"vars"`
|
||||
|
||||
RawBodyZZZZ json.RawMessage `json:"tests"`
|
||||
}
|
||||
|
||||
func WithTestFromBytes(name string, xs []byte) func(*Harness) error {
|
||||
return func(h *Harness) error {
|
||||
var t struct {
|
||||
T []Test `json:"tests"`
|
||||
}
|
||||
x := &Extra{}
|
||||
s := md5.New()
|
||||
s.Write(xs)
|
||||
hsh := hex.EncodeToString(s.Sum(nil))
|
||||
// unmarshal just the extra data
|
||||
err := yaml.Unmarshal(xs, &x, yaml.JSONOpt(func(d *json.Decoder) *json.Decoder {
|
||||
return d
|
||||
}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpl := template.Must(template.New(hsh).Funcs(sprig.FuncMap()).Parse(string(xs)))
|
||||
// execute the template using the extra data as the provided top level object
|
||||
// we can use the original buffer as the output since the original buffer has already been copied when it was passed into template
|
||||
buf := bytes.NewBuffer(xs)
|
||||
buf.Reset()
|
||||
err = tmpl.Execute(buf, x)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = yaml.Unmarshal(buf.Bytes(), &t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(t.T) == 0 {
|
||||
return fmt.Errorf("suite with name %s had no tests", name)
|
||||
}
|
||||
h.tests[name] = t.T
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type Harness struct {
|
||||
tests map[string][]Test
|
||||
t *testing.T
|
||||
|
||||
handlers map[string]http.Handler
|
||||
fss map[string]afero.Fs
|
||||
}
|
||||
|
||||
func Execute(options ...HarnessOption) {
|
||||
h := &Harness{
|
||||
handlers: map[string]http.Handler{},
|
||||
tests: map[string][]Test{},
|
||||
fss: map[string]afero.Fs{
|
||||
"": afero.NewOsFs(),
|
||||
},
|
||||
}
|
||||
for _, v := range options {
|
||||
err := v(h)
|
||||
if err != nil {
|
||||
h.t.Error(err)
|
||||
}
|
||||
}
|
||||
h.Execute()
|
||||
}
|
||||
|
||||
func (h *Harness) Execute() {
|
||||
ctx := context.Background()
|
||||
for suiteName, tests := range h.tests {
|
||||
for idx, v := range tests {
|
||||
v.Actual.h = h
|
||||
v.Expect.h = h
|
||||
name := v.Name
|
||||
if name == "" {
|
||||
name = "test"
|
||||
}
|
||||
fullname := fmt.Sprintf("%s_%s_%d", suiteName, name, idx)
|
||||
h.t.Run(fullname, func(t *testing.T) {
|
||||
err := v.Execute(ctx, t)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Test struct {
|
||||
Name string `json:"name"`
|
||||
Expect Source `json:"expect"`
|
||||
Actual Source `json:"actual"`
|
||||
Compare Comparison `json:"compare"`
|
||||
}
|
||||
|
||||
func (c *Test) Execute(ctx context.Context, t *testing.T) error {
|
||||
a, aCode, err := c.Expect.Execute(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get expect data: %w", err)
|
||||
}
|
||||
b, bCode, err := c.Actual.Execute(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get actual data: %w", err)
|
||||
}
|
||||
err = c.Compare.Compare(t, a, b, aCode, bCode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("compare: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Comparison struct {
|
||||
Expr string `json:"expr"`
|
||||
Exprs []string `json:"exprs"`
|
||||
Literal bool `json:"literal"`
|
||||
}
|
||||
|
||||
func (c *Comparison) Compare(t *testing.T, aRaw, bRaw json.RawMessage, aCode, bCode int) error {
|
||||
var err error
|
||||
var a, b any
|
||||
var aType, bType *types.Type
|
||||
|
||||
if !c.Literal {
|
||||
var aMap, bMap any
|
||||
err = yaml.Unmarshal(aRaw, &aMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = yaml.Unmarshal(bRaw, &bMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a = aMap
|
||||
b = bMap
|
||||
if a != nil {
|
||||
switch reflect.TypeOf(a).Kind() {
|
||||
case reflect.Slice:
|
||||
aType = cel.ListType(cel.MapType(cel.StringType, cel.DynType))
|
||||
default:
|
||||
aType = cel.MapType(cel.StringType, cel.DynType)
|
||||
}
|
||||
} else {
|
||||
aType = cel.MapType(cel.StringType, cel.DynType)
|
||||
}
|
||||
if b != nil {
|
||||
switch reflect.TypeOf(b).Kind() {
|
||||
case reflect.Slice:
|
||||
bType = cel.ListType(cel.MapType(cel.StringType, cel.DynType))
|
||||
default:
|
||||
bType = cel.MapType(cel.StringType, cel.DynType)
|
||||
}
|
||||
} else {
|
||||
bType = cel.MapType(cel.StringType, cel.DynType)
|
||||
}
|
||||
} else {
|
||||
a = string(aRaw)
|
||||
b = string(bRaw)
|
||||
aType = cel.StringType
|
||||
bType = cel.StringType
|
||||
}
|
||||
|
||||
exprs := []string{}
|
||||
// if no default expr set and no exprs are set, then add the default expr
|
||||
if len(c.Exprs) == 0 && c.Expr == "" {
|
||||
exprs = append(exprs, "actual_code == 200", "actual == expect")
|
||||
}
|
||||
env, err := cel.NewEnv(
|
||||
cel.Variable("expect", aType),
|
||||
cel.Variable("actual", bType),
|
||||
cel.Variable("expect_code", cel.IntType),
|
||||
cel.Variable("actual_code", cel.IntType),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, expr := range append(c.Exprs, exprs...) {
|
||||
ast, issues := env.Compile(expr)
|
||||
if issues != nil && issues.Err() != nil {
|
||||
return issues.Err()
|
||||
}
|
||||
prg, err := env.Program(ast)
|
||||
if err != nil {
|
||||
return fmt.Errorf("program construction error: %w", err)
|
||||
}
|
||||
res, _, err := prg.Eval(map[string]any{
|
||||
"expect": a,
|
||||
"actual": b,
|
||||
"expect_code": aCode,
|
||||
"actual_code": bCode,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.Type() != cel.BoolType {
|
||||
return ErrExpressionMustReturnBool
|
||||
}
|
||||
bres, ok := res.Value().(bool)
|
||||
if !ok {
|
||||
return ErrExpressionMustReturnBool
|
||||
}
|
||||
if !assert.Equal(t, bres, true, `expr: %s`, expr) {
|
||||
if os.Getenv("HIDE_HARNESS_LOG") != "1" {
|
||||
t.Logf(`name: %s
|
||||
expect%d: %v
|
||||
actual%d: %v
|
||||
expr: %s
|
||||
`, t.Name(), aCode, a, bCode, b, expr)
|
||||
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Source struct {
|
||||
// backref to the harness
|
||||
h *Harness `json:"-"`
|
||||
|
||||
// remote type
|
||||
Remote *string `json:"remote,omitempty"`
|
||||
Handler *string `json:"handler,omitempty"`
|
||||
Method string `json:"method"`
|
||||
Path string `json:"path"`
|
||||
Query map[string]string `json:"query"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
Body *Source `json:"body,omitempty"`
|
||||
|
||||
// data type
|
||||
Data any `json:"data,omitempty"`
|
||||
|
||||
// file type
|
||||
File *string `json:"file,omitempty"`
|
||||
Fs string `json:"fs,omitempty"`
|
||||
|
||||
// for raw type
|
||||
Raw *string `json:"raw,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Source) Execute(ctx context.Context) (json.RawMessage, int, error) {
|
||||
if s.Raw != nil {
|
||||
return s.executeRaw(ctx)
|
||||
}
|
||||
if s.File != nil {
|
||||
return s.executeFile(ctx)
|
||||
}
|
||||
if s.Remote != nil || s.Handler != nil {
|
||||
return s.executeRemote(ctx)
|
||||
}
|
||||
if s.Data != nil {
|
||||
return s.executeData(ctx)
|
||||
}
|
||||
return s.executeEmpty(ctx)
|
||||
}
|
||||
func (s *Source) executeRemote(ctx context.Context) (json.RawMessage, int, error) {
|
||||
method := "GET"
|
||||
if s.Method != "" {
|
||||
method = s.Method
|
||||
}
|
||||
method = strings.ToUpper(method)
|
||||
var body io.Reader
|
||||
// hydrate the harness
|
||||
if s.Body != nil {
|
||||
s.Body.h = s.h
|
||||
msg, _, err := s.Body.Execute(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("getting body: %w", err)
|
||||
}
|
||||
body = bytes.NewBuffer(msg)
|
||||
}
|
||||
var purl *url.URL
|
||||
if s.Remote != nil {
|
||||
niceUrl, err := url.Parse(*s.Remote)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
purl = niceUrl
|
||||
|
||||
} else if s.Handler != nil {
|
||||
handler, ok := s.h.handlers[*s.Handler]
|
||||
if !ok {
|
||||
return nil, 0, fmt.Errorf("handler not registered: %s", *s.Handler)
|
||||
}
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
niceUrl, err := url.Parse(server.URL)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
purl = niceUrl
|
||||
} else {
|
||||
panic("impossible code path. bug? source.Execute() should ensure this never happens")
|
||||
}
|
||||
|
||||
purl = purl.JoinPath(s.Path)
|
||||
q := purl.Query()
|
||||
for k, v := range s.Query {
|
||||
q.Add(k, v)
|
||||
}
|
||||
purl.RawQuery = q.Encode()
|
||||
request, err := http.NewRequest(method, purl.String(), body)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
for k, v := range s.Headers {
|
||||
request.Header.Set(k, v)
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, resp.StatusCode, nil
|
||||
}
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, 200, err
|
||||
}
|
||||
return json.RawMessage(out), 200, nil
|
||||
}
|
||||
|
||||
func (s *Source) executeData(ctx context.Context) (json.RawMessage, int, error) {
|
||||
ans, err := json.Marshal(s.Data)
|
||||
if err != nil {
|
||||
return nil, 400, nil
|
||||
}
|
||||
return ans, 200, nil
|
||||
}
|
||||
|
||||
func (s *Source) executeFile(ctx context.Context) (json.RawMessage, int, error) {
|
||||
afs, ok := s.h.fss[s.Fs]
|
||||
if !ok {
|
||||
return nil, 404, fmt.Errorf("filesystem %s not defined", s.Fs)
|
||||
}
|
||||
name := *s.File
|
||||
filename := name
|
||||
for _, fn := range []string{name, name + ".yaml", name + ".yml", name + ".json"} {
|
||||
// check if file exists
|
||||
_, err := afs.Stat(fn)
|
||||
if err == nil {
|
||||
filename = fn
|
||||
break
|
||||
}
|
||||
}
|
||||
fileBytes, err := afero.ReadFile(afs, filename)
|
||||
if err != nil {
|
||||
return nil, 404, err
|
||||
}
|
||||
return json.RawMessage(fileBytes), 200, nil
|
||||
}
|
||||
func (s *Source) executeRaw(ctx context.Context) (json.RawMessage, int, error) {
|
||||
return json.RawMessage(*s.Raw), 200, nil
|
||||
}
|
||||
|
||||
func (s *Source) executeEmpty(ctx context.Context) (json.RawMessage, int, error) {
|
||||
return []byte("{}"), 200, nil
|
||||
}
|
19
cl/beacon/beacontest/harness_test.go
Normal file
19
cl/beacon/beacontest/harness_test.go
Normal file
@ -0,0 +1,19 @@
|
||||
package beacontest_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/beacontest"
|
||||
)
|
||||
|
||||
//go:embed harness_test_data.yml
|
||||
var testData []byte
|
||||
|
||||
func TestSimpleHarness(t *testing.T) {
|
||||
beacontest.Execute(
|
||||
beacontest.WithTesting(t),
|
||||
beacontest.WithTestFromBytes("test", testData),
|
||||
)
|
||||
}
|
62
cl/beacon/beacontest/harness_test_data.yml
Normal file
62
cl/beacon/beacontest/harness_test_data.yml
Normal file
@ -0,0 +1,62 @@
|
||||
tests:
|
||||
- name: "equality expression"
|
||||
expect:
|
||||
data:
|
||||
hello: world
|
||||
actual:
|
||||
data:
|
||||
hello: world
|
||||
compare:
|
||||
type: "expr"
|
||||
expr: "actual == expect"
|
||||
- name: "neg equality expr"
|
||||
expect:
|
||||
data:
|
||||
hello: world
|
||||
actual:
|
||||
data:
|
||||
hello: worlds
|
||||
compare:
|
||||
expr: "actual != expect"
|
||||
- name: "subkey world"
|
||||
expect:
|
||||
data:
|
||||
hi: world
|
||||
actual:
|
||||
data:
|
||||
hello: world
|
||||
compare:
|
||||
expr: "actual.hello == expect.hi"
|
||||
- name: "default compare"
|
||||
expect:
|
||||
data:
|
||||
hello: world
|
||||
actual:
|
||||
data:
|
||||
hello: world
|
||||
- name: "default neg compare"
|
||||
expect:
|
||||
data:
|
||||
hello: world
|
||||
actual:
|
||||
data:
|
||||
hello: worlds
|
||||
compare:
|
||||
expr: "actual != expect"
|
||||
- name: "key order doesnt matter for non literal"
|
||||
expect:
|
||||
data:
|
||||
a: 1
|
||||
b: 2
|
||||
actual:
|
||||
raw: '{"b":2,"a":1}'
|
||||
- name: "key order does matter for literal"
|
||||
expect:
|
||||
data:
|
||||
a: 1
|
||||
b: 2
|
||||
actual:
|
||||
raw: '{"b":2,"a":1}'
|
||||
compare:
|
||||
literal: true
|
||||
expr: "actual != expect"
|
252
cl/beacon/beacontest/linux_basepathfs.go
Normal file
252
cl/beacon/beacontest/linux_basepathfs.go
Normal file
@ -0,0 +1,252 @@
|
||||
package beacontest
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
var (
|
||||
_ afero.Lstater = (*BasePathFs)(nil)
|
||||
_ fs.ReadDirFile = (*BasePathFile)(nil)
|
||||
)
|
||||
|
||||
// This is a version of the afero basepathfs that uses path instead of filepath.
|
||||
// this is needed to work with things like zipfs and embedfs on windows
|
||||
type BasePathFs struct {
|
||||
source afero.Fs
|
||||
path string
|
||||
}
|
||||
|
||||
type BasePathFile struct {
|
||||
afero.File
|
||||
path string
|
||||
}
|
||||
|
||||
func (f *BasePathFile) Name() string {
|
||||
sourcename := f.File.Name()
|
||||
return strings.TrimPrefix(sourcename, path.Clean(f.path))
|
||||
}
|
||||
|
||||
func (f *BasePathFile) ReadDir(n int) ([]fs.DirEntry, error) {
|
||||
if rdf, ok := f.File.(fs.ReadDirFile); ok {
|
||||
return rdf.ReadDir(n)
|
||||
}
|
||||
return readDirFile{f.File}.ReadDir(n)
|
||||
}
|
||||
|
||||
func NewBasePathFs(source afero.Fs, path string) afero.Fs {
|
||||
return &BasePathFs{source: source, path: path}
|
||||
}
|
||||
|
||||
// on a file outside the base path it returns the given file name and an error,
|
||||
// else the given file with the base path prepended
|
||||
func (b *BasePathFs) RealPath(name string) (p string, err error) {
|
||||
if err := validateBasePathName(name); err != nil {
|
||||
return name, err
|
||||
}
|
||||
|
||||
bpath := path.Clean(b.path)
|
||||
p = path.Clean(path.Join(bpath, name))
|
||||
if !strings.HasPrefix(p, bpath) {
|
||||
return name, os.ErrNotExist
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func validateBasePathName(name string) error {
|
||||
if runtime.GOOS != "windows" {
|
||||
// Not much to do here;
|
||||
// the virtual file paths all look absolute on *nix.
|
||||
return nil
|
||||
}
|
||||
|
||||
// On Windows a common mistake would be to provide an absolute OS path
|
||||
// We could strip out the base part, but that would not be very portable.
|
||||
if path.IsAbs(name) {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Chtimes(name string, atime, mtime time.Time) (err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return &os.PathError{Op: "chtimes", Path: name, Err: err}
|
||||
}
|
||||
return b.source.Chtimes(name, atime, mtime)
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Chmod(name string, mode os.FileMode) (err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return &os.PathError{Op: "chmod", Path: name, Err: err}
|
||||
}
|
||||
return b.source.Chmod(name, mode)
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Chown(name string, uid, gid int) (err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return &os.PathError{Op: "chown", Path: name, Err: err}
|
||||
}
|
||||
return b.source.Chown(name, uid, gid)
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Name() string {
|
||||
return "BasePathFs"
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Stat(name string) (fi os.FileInfo, err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return nil, &os.PathError{Op: "stat", Path: name, Err: err}
|
||||
}
|
||||
return b.source.Stat(name)
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Rename(oldname, newname string) (err error) {
|
||||
if oldname, err = b.RealPath(oldname); err != nil {
|
||||
return &os.PathError{Op: "rename", Path: oldname, Err: err}
|
||||
}
|
||||
if newname, err = b.RealPath(newname); err != nil {
|
||||
return &os.PathError{Op: "rename", Path: newname, Err: err}
|
||||
}
|
||||
return b.source.Rename(oldname, newname)
|
||||
}
|
||||
|
||||
func (b *BasePathFs) RemoveAll(name string) (err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return &os.PathError{Op: "remove_all", Path: name, Err: err}
|
||||
}
|
||||
return b.source.RemoveAll(name)
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Remove(name string) (err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return &os.PathError{Op: "remove", Path: name, Err: err}
|
||||
}
|
||||
return b.source.Remove(name)
|
||||
}
|
||||
|
||||
func (b *BasePathFs) OpenFile(name string, flag int, mode os.FileMode) (f afero.File, err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return nil, &os.PathError{Op: "openfile", Path: name, Err: err}
|
||||
}
|
||||
sourcef, err := b.source.OpenFile(name, flag, mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BasePathFile{sourcef, b.path}, nil
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Open(name string) (f afero.File, err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return nil, &os.PathError{Op: "open", Path: name, Err: err}
|
||||
}
|
||||
sourcef, err := b.source.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BasePathFile{File: sourcef, path: b.path}, nil
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Mkdir(name string, mode os.FileMode) (err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return &os.PathError{Op: "mkdir", Path: name, Err: err}
|
||||
}
|
||||
return b.source.Mkdir(name, mode)
|
||||
}
|
||||
|
||||
func (b *BasePathFs) MkdirAll(name string, mode os.FileMode) (err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return &os.PathError{Op: "mkdir", Path: name, Err: err}
|
||||
}
|
||||
return b.source.MkdirAll(name, mode)
|
||||
}
|
||||
|
||||
func (b *BasePathFs) Create(name string) (f afero.File, err error) {
|
||||
if name, err = b.RealPath(name); err != nil {
|
||||
return nil, &os.PathError{Op: "create", Path: name, Err: err}
|
||||
}
|
||||
sourcef, err := b.source.Create(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BasePathFile{File: sourcef, path: b.path}, nil
|
||||
}
|
||||
|
||||
func (b *BasePathFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||
name, err := b.RealPath(name)
|
||||
if err != nil {
|
||||
return nil, false, &os.PathError{Op: "lstat", Path: name, Err: err}
|
||||
}
|
||||
if lstater, ok := b.source.(afero.Lstater); ok {
|
||||
return lstater.LstatIfPossible(name)
|
||||
}
|
||||
fi, err := b.source.Stat(name)
|
||||
return fi, false, err
|
||||
}
|
||||
|
||||
func (b *BasePathFs) SymlinkIfPossible(oldname, newname string) error {
|
||||
oldname, err := b.RealPath(oldname)
|
||||
if err != nil {
|
||||
return &os.LinkError{Op: "symlink", Old: oldname, New: newname, Err: err}
|
||||
}
|
||||
newname, err = b.RealPath(newname)
|
||||
if err != nil {
|
||||
return &os.LinkError{Op: "symlink", Old: oldname, New: newname, Err: err}
|
||||
}
|
||||
if linker, ok := b.source.(afero.Linker); ok {
|
||||
return linker.SymlinkIfPossible(oldname, newname)
|
||||
}
|
||||
return &os.LinkError{Op: "symlink", Old: oldname, New: newname, Err: afero.ErrNoSymlink}
|
||||
}
|
||||
|
||||
func (b *BasePathFs) ReadlinkIfPossible(name string) (string, error) {
|
||||
name, err := b.RealPath(name)
|
||||
if err != nil {
|
||||
return "", &os.PathError{Op: "readlink", Path: name, Err: err}
|
||||
}
|
||||
if reader, ok := b.source.(afero.LinkReader); ok {
|
||||
return reader.ReadlinkIfPossible(name)
|
||||
}
|
||||
return "", &os.PathError{Op: "readlink", Path: name, Err: afero.ErrNoReadlink}
|
||||
}
|
||||
|
||||
// the readDirFile helper is requried
|
||||
|
||||
// readDirFile provides adapter from afero.File to fs.ReadDirFile needed for correct Open
|
||||
type readDirFile struct {
|
||||
afero.File
|
||||
}
|
||||
|
||||
var _ fs.ReadDirFile = readDirFile{}
|
||||
|
||||
func (r readDirFile) ReadDir(n int) ([]fs.DirEntry, error) {
|
||||
items, err := r.File.Readdir(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]fs.DirEntry, len(items))
|
||||
for i := range items {
|
||||
ret[i] = fileInfoDirEntry{FileInfo: items[i]}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// FileInfoDirEntry provides an adapter from os.FileInfo to fs.DirEntry
|
||||
type fileInfoDirEntry struct {
|
||||
fs.FileInfo
|
||||
}
|
||||
|
||||
var _ fs.DirEntry = fileInfoDirEntry{}
|
||||
|
||||
func (d fileInfoDirEntry) Type() fs.FileMode { return d.FileInfo.Mode().Type() }
|
||||
|
||||
func (d fileInfoDirEntry) Info() (fs.FileInfo, error) { return d.FileInfo, nil }
|
@ -40,7 +40,7 @@ type attestationsRewardsResponse struct {
|
||||
TotalRewards []TotalReward `json:"total_rewards"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getAttestationsRewards(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getAttestationsRewards(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -49,7 +49,7 @@ func (a *ApiHandler) getAttestationsRewards(w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
epoch, err := epochFromRequest(r)
|
||||
epoch, err := beaconhttp.EpochFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -180,7 +180,7 @@ func (a *ApiHandler) baseReward(version clparams.StateVersion, effectiveBalance,
|
||||
return effectiveBalance * a.beaconChainCfg.BaseRewardFactor / activeBalanceRoot / a.beaconChainCfg.BaseRewardsPerEpoch
|
||||
}
|
||||
|
||||
func (a *ApiHandler) computeAttestationsRewardsForAltair(validatorSet *solid.ValidatorSet, inactivityScores solid.Uint64ListSSZ, previousParticipation *solid.BitList, inactivityLeak bool, filterIndicies []uint64, epoch uint64) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) computeAttestationsRewardsForAltair(validatorSet *solid.ValidatorSet, inactivityScores solid.Uint64ListSSZ, previousParticipation *solid.BitList, inactivityLeak bool, filterIndicies []uint64, epoch uint64) (*beaconhttp.BeaconResponse, error) {
|
||||
totalActiveBalance := uint64(0)
|
||||
flagsUnslashedIndiciesSet := statechange.GetUnslashedIndiciesSet(a.beaconChainCfg, epoch, validatorSet, previousParticipation)
|
||||
weights := a.beaconChainCfg.ParticipationWeights()
|
||||
@ -289,7 +289,7 @@ func (a *ApiHandler) computeAttestationsRewardsForAltair(validatorSet *solid.Val
|
||||
}
|
||||
|
||||
// processRewardsAndPenaltiesPhase0 process rewards and penalties for phase0 state.
|
||||
func (a *ApiHandler) computeAttestationsRewardsForPhase0(s *state.CachingBeaconState, filterIndicies []uint64, epoch uint64) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) computeAttestationsRewardsForPhase0(s *state.CachingBeaconState, filterIndicies []uint64, epoch uint64) (*beaconhttp.BeaconResponse, error) {
|
||||
response := &attestationsRewardsResponse{}
|
||||
beaconConfig := s.BeaconConfig()
|
||||
if epoch == beaconConfig.GenesisEpoch {
|
||||
|
File diff suppressed because one or more lines are too long
@ -23,18 +23,18 @@ type getHeadersRequest struct {
|
||||
ParentRoot *libcommon.Hash `json:"root,omitempty"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) rootFromBlockId(ctx context.Context, tx kv.Tx, blockId *segmentID) (root libcommon.Hash, err error) {
|
||||
func (a *ApiHandler) rootFromBlockId(ctx context.Context, tx kv.Tx, blockId *beaconhttp.SegmentID) (root libcommon.Hash, err error) {
|
||||
switch {
|
||||
case blockId.head():
|
||||
case blockId.Head():
|
||||
root, _, err = a.forkchoiceStore.GetHead()
|
||||
if err != nil {
|
||||
return libcommon.Hash{}, err
|
||||
}
|
||||
case blockId.finalized():
|
||||
case blockId.Finalized():
|
||||
root = a.forkchoiceStore.FinalizedCheckpoint().BlockRoot()
|
||||
case blockId.justified():
|
||||
case blockId.Justified():
|
||||
root = a.forkchoiceStore.JustifiedCheckpoint().BlockRoot()
|
||||
case blockId.genesis():
|
||||
case blockId.Genesis():
|
||||
root, err = beacon_indicies.ReadCanonicalBlockRoot(tx, 0)
|
||||
if err != nil {
|
||||
return libcommon.Hash{}, err
|
||||
@ -42,24 +42,24 @@ func (a *ApiHandler) rootFromBlockId(ctx context.Context, tx kv.Tx, blockId *seg
|
||||
if root == (libcommon.Hash{}) {
|
||||
return libcommon.Hash{}, beaconhttp.NewEndpointError(http.StatusNotFound, "genesis block not found")
|
||||
}
|
||||
case blockId.getSlot() != nil:
|
||||
root, err = beacon_indicies.ReadCanonicalBlockRoot(tx, *blockId.getSlot())
|
||||
case blockId.GetSlot() != nil:
|
||||
root, err = beacon_indicies.ReadCanonicalBlockRoot(tx, *blockId.GetSlot())
|
||||
if err != nil {
|
||||
return libcommon.Hash{}, err
|
||||
}
|
||||
if root == (libcommon.Hash{}) {
|
||||
return libcommon.Hash{}, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Sprintf("block not found %d", *blockId.getSlot()))
|
||||
return libcommon.Hash{}, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Sprintf("block not found %d", *blockId.GetSlot()))
|
||||
}
|
||||
case blockId.getRoot() != nil:
|
||||
case blockId.GetRoot() != nil:
|
||||
// first check if it exists
|
||||
root = *blockId.getRoot()
|
||||
root = *blockId.GetRoot()
|
||||
default:
|
||||
return libcommon.Hash{}, beaconhttp.NewEndpointError(http.StatusInternalServerError, "cannot parse block id")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getBlock(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getBlock(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
if err != nil {
|
||||
@ -67,7 +67,7 @@ func (a *ApiHandler) getBlock(w http.ResponseWriter, r *http.Request) (*beaconRe
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := blockIdFromRequest(r)
|
||||
blockId, err := beaconhttp.BlockIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -90,11 +90,11 @@ func (a *ApiHandler) getBlock(w http.ResponseWriter, r *http.Request) (*beaconRe
|
||||
return nil, err
|
||||
}
|
||||
return newBeaconResponse(blk).
|
||||
withFinalized(root == canonicalRoot && blk.Block.Slot <= a.forkchoiceStore.FinalizedSlot()).
|
||||
withVersion(blk.Version()), nil
|
||||
WithFinalized(root == canonicalRoot && blk.Block.Slot <= a.forkchoiceStore.FinalizedSlot()).
|
||||
WithVersion(blk.Version()), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getBlindedBlock(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getBlindedBlock(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
if err != nil {
|
||||
@ -102,7 +102,7 @@ func (a *ApiHandler) getBlindedBlock(w http.ResponseWriter, r *http.Request) (*b
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := blockIdFromRequest(r)
|
||||
blockId, err := beaconhttp.BlockIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -129,18 +129,18 @@ func (a *ApiHandler) getBlindedBlock(w http.ResponseWriter, r *http.Request) (*b
|
||||
return nil, err
|
||||
}
|
||||
return newBeaconResponse(blinded).
|
||||
withFinalized(root == canonicalRoot && blk.Block.Slot <= a.forkchoiceStore.FinalizedSlot()).
|
||||
withVersion(blk.Version()), nil
|
||||
WithFinalized(root == canonicalRoot && blk.Block.Slot <= a.forkchoiceStore.FinalizedSlot()).
|
||||
WithVersion(blk.Version()), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getBlockAttestations(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getBlockAttestations(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
blockId, err := blockIdFromRequest(r)
|
||||
blockId, err := beaconhttp.BlockIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -160,18 +160,19 @@ func (a *ApiHandler) getBlockAttestations(w http.ResponseWriter, r *http.Request
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newBeaconResponse(blk.Block.Body.Attestations).withFinalized(root == canonicalRoot && blk.Block.Slot <= a.forkchoiceStore.FinalizedSlot()).
|
||||
withVersion(blk.Version()), nil
|
||||
return newBeaconResponse(blk.Block.Body.Attestations).
|
||||
WithFinalized(root == canonicalRoot && blk.Block.Slot <= a.forkchoiceStore.FinalizedSlot()).
|
||||
WithVersion(blk.Version()), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getBlockRoot(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getBlockRoot(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
blockId, err := blockIdFromRequest(r)
|
||||
blockId, err := beaconhttp.BlockIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -195,5 +196,5 @@ func (a *ApiHandler) getBlockRoot(w http.ResponseWriter, r *http.Request) (*beac
|
||||
}
|
||||
return newBeaconResponse(struct {
|
||||
Root libcommon.Hash `json:"root"`
|
||||
}{Root: root}).withFinalized(canonicalRoot == root && *slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
}{Root: root}).WithFinalized(canonicalRoot == root && *slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -10,7 +10,7 @@ import (
|
||||
"github.com/ledgerwatch/erigon/cl/phase1/core/state"
|
||||
)
|
||||
|
||||
func (a *ApiHandler) GetEth1V1BuilderStatesExpectedWit(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) GetEth1V1BuilderStatesExpectedWit(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -19,7 +19,7 @@ func (a *ApiHandler) GetEth1V1BuilderStatesExpectedWit(w http.ResponseWriter, r
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -44,7 +44,7 @@ func (a *ApiHandler) GetEth1V1BuilderStatesExpectedWit(w http.ResponseWriter, r
|
||||
if root == headRoot {
|
||||
s, cn := a.syncedData.HeadState()
|
||||
defer cn()
|
||||
return newBeaconResponse(state.ExpectedWithdrawals(s)).withFinalized(false), nil
|
||||
return newBeaconResponse(state.ExpectedWithdrawals(s)).WithFinalized(false), nil
|
||||
}
|
||||
lookAhead := 1024
|
||||
for currSlot := *slot + 1; currSlot < *slot+uint64(lookAhead); currSlot++ {
|
||||
@ -62,7 +62,7 @@ func (a *ApiHandler) GetEth1V1BuilderStatesExpectedWit(w http.ResponseWriter, r
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newBeaconResponse(blk.Block.Body.ExecutionPayload.Withdrawals).withFinalized(false), nil
|
||||
return newBeaconResponse(blk.Block.Body.ExecutionPayload.Withdrawals).WithFinalized(false), nil
|
||||
}
|
||||
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, "state not found")
|
||||
|
@ -1,169 +0,0 @@
|
||||
//go:build integration
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
||||
"github.com/ledgerwatch/erigon/common"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetCommitteesAntiquated(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, postState, handler, _, _, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
postRoot, err := postState.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadVal, err = blocks[len(blocks)-1].Block.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
fcu.FinalizedSlotVal = math.MaxUint64
|
||||
|
||||
fcu.StateAtBlockRootVal[fcu.HeadVal] = postState
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
blockID string
|
||||
code int
|
||||
query string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "slot",
|
||||
blockID: "0x" + common.Bytes2Hex(postRoot[:]),
|
||||
code: http.StatusOK,
|
||||
query: "?slot=" + strconv.FormatUint(fcu.HeadSlotVal, 10),
|
||||
expected: `{"data":[{"index":"0","slot":"8322","validators":["0","104","491","501","379","318","275","504","75","280","105","399","35","401"]}],"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "empty-index",
|
||||
blockID: "0x" + common.Bytes2Hex(postRoot[:]),
|
||||
code: http.StatusOK,
|
||||
query: "?index=1",
|
||||
expected: `{"data":[],"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "all-queries",
|
||||
blockID: "0x" + common.Bytes2Hex(postRoot[:]),
|
||||
code: http.StatusOK,
|
||||
query: "?index=0&slot=" + strconv.FormatUint(fcu.HeadSlotVal-32, 10) + "&epoch=" + strconv.FormatUint((fcu.HeadSlotVal/32)-1, 10),
|
||||
expected: `{"data":[{"index":"0","slot":"8290","validators":["127","377","274","85","309","420","423","398","153","480","273","429","374","260"]}],"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
blockID: "0x" + common.Bytes2Hex(make([]byte, 32)),
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// Query the block in the handler with /eth/v2/beacon/states/{block_id} with content-type octet-stream
|
||||
req, err := http.NewRequest("GET", server.URL+"/eth/v1/beacon/states/"+c.blockID+"/committees"+c.query, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
// read the all of the octect
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.expected, string(out))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCommitteesNonAntiquated(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, postState, handler, _, sm, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
postRoot, err := postState.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadVal, err = blocks[len(blocks)-1].Block.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
fcu.FinalizedSlotVal = 0
|
||||
|
||||
fcu.StateAtBlockRootVal[fcu.HeadVal] = postState
|
||||
require.NoError(t, sm.OnHeadState(postState))
|
||||
cases := []struct {
|
||||
name string
|
||||
blockID string
|
||||
code int
|
||||
query string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "slot",
|
||||
blockID: "0x" + common.Bytes2Hex(postRoot[:]),
|
||||
code: http.StatusOK,
|
||||
query: "?slot=" + strconv.FormatUint(fcu.HeadSlotVal, 10),
|
||||
expected: `{"data":[{"index":"0","slot":"8322","validators":["0","104","491","501","379","318","275","504","75","280","105","399","35","401"]}],"finalized":false,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "empty-index",
|
||||
blockID: "0x" + common.Bytes2Hex(postRoot[:]),
|
||||
code: http.StatusOK,
|
||||
query: "?index=1",
|
||||
expected: `{"data":[],"finalized":false,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "all-queries",
|
||||
blockID: "0x" + common.Bytes2Hex(postRoot[:]),
|
||||
code: http.StatusOK,
|
||||
query: "?index=0&slot=" + strconv.FormatUint(fcu.HeadSlotVal-32, 10) + "&epoch=" + strconv.FormatUint((fcu.HeadSlotVal/32)-1, 10),
|
||||
expected: `{"data":[{"index":"0","slot":"8290","validators":["127","377","274","85","309","420","423","398","153","480","273","429","374","260"]}],"finalized":false,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
blockID: "0x" + common.Bytes2Hex(make([]byte, 32)),
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// Query the block in the handler with /eth/v2/beacon/states/{block_id} with content-type octet-stream
|
||||
req, err := http.NewRequest("GET", server.URL+"/eth/v1/beacon/states/"+c.blockID+"/committees"+c.query, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
// read the all of the octect
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.expected, string(out))
|
||||
})
|
||||
}
|
||||
}
|
@ -17,20 +17,20 @@ type committeeResponse struct {
|
||||
Validators []string `json:"validators"` // do string directly but it is still a base10 number
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getCommittees(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getCommittees(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
epochReq, err := uint64FromQueryParams(r, "epoch")
|
||||
epochReq, err := beaconhttp.Uint64FromQueryParams(r, "epoch")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
index, err := uint64FromQueryParams(r, "index")
|
||||
index, err := beaconhttp.Uint64FromQueryParams(r, "index")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
slotFilter, err := uint64FromQueryParams(r, "slot")
|
||||
slotFilter, err := beaconhttp.Uint64FromQueryParams(r, "slot")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -40,7 +40,7 @@ func (a *ApiHandler) getCommittees(w http.ResponseWriter, r *http.Request) (*bea
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -100,7 +100,7 @@ func (a *ApiHandler) getCommittees(w http.ResponseWriter, r *http.Request) (*bea
|
||||
resp = append(resp, data)
|
||||
}
|
||||
}
|
||||
return newBeaconResponse(resp).withFinalized(isFinalized), nil
|
||||
return newBeaconResponse(resp).WithFinalized(isFinalized), nil
|
||||
}
|
||||
// finality case
|
||||
activeIdxs, err := state_accessors.ReadActiveIndicies(tx, epoch*a.beaconChainCfg.SlotsPerEpoch)
|
||||
@ -143,5 +143,5 @@ func (a *ApiHandler) getCommittees(w http.ResponseWriter, r *http.Request) (*bea
|
||||
resp = append(resp, data)
|
||||
}
|
||||
}
|
||||
return newBeaconResponse(resp).withFinalized(isFinalized), nil
|
||||
return newBeaconResponse(resp).WithFinalized(isFinalized), nil
|
||||
}
|
||||
|
@ -6,14 +6,15 @@ import (
|
||||
"sort"
|
||||
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/beaconhttp"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes"
|
||||
)
|
||||
|
||||
func (a *ApiHandler) getSpec(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getSpec(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
return newBeaconResponse(a.beaconChainCfg), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getDepositContract(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getDepositContract(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
return newBeaconResponse(struct {
|
||||
ChainId uint64 `json:"chain_id,string"`
|
||||
DepositContract string `json:"address"`
|
||||
@ -21,7 +22,7 @@ func (a *ApiHandler) getDepositContract(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getForkSchedule(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getForkSchedule(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
response := []cltypes.Fork{}
|
||||
// create first response (unordered and incomplete)
|
||||
for currentVersion, epoch := range a.beaconChainCfg.ForkVersionSchedule {
|
||||
|
@ -1,83 +0,0 @@
|
||||
//go:build integration
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetSpec(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get(server.URL + "/eth/v1/config/spec")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
out := make(map[string]interface{})
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
data := out["data"].(map[string]interface{})
|
||||
require.Equal(t, data["SlotsPerEpoch"], float64(32))
|
||||
require.Equal(t, data["SlotsPerHistoricalRoot"], float64(8192))
|
||||
}
|
||||
|
||||
func TestGetForkSchedule(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get(server.URL + "/eth/v1/config/fork_schedule")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
out := make(map[string]interface{})
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Greater(t, len(out["data"].([]interface{})), 2)
|
||||
for _, v := range out["data"].([]interface{}) {
|
||||
data := v.(map[string]interface{})
|
||||
require.NotNil(t, data["current_version"])
|
||||
require.NotNil(t, data["epoch"])
|
||||
require.NotNil(t, data["previous_version"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositContract(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get(server.URL + "/eth/v1/config/deposit_contract")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
out := make(map[string]interface{})
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
data := out["data"].(map[string]interface{})
|
||||
require.Equal(t, data["address"], "0x00000000219ab540356cBB839Cbe05303d7705Fa")
|
||||
require.Equal(t, data["chain_id"], "1")
|
||||
}
|
98
cl/beacon/handler/data_test.go
Normal file
98
cl/beacon/handler/data_test.go
Normal file
@ -0,0 +1,98 @@
|
||||
package handler_test
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/beacontest"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
||||
"github.com/ledgerwatch/erigon/cl/phase1/forkchoice"
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
//go:embed test_data/*
|
||||
var testData embed.FS
|
||||
|
||||
var TestDatae = beacontest.NewBasePathFs(afero.FromIOFS{FS: testData}, "test_data")
|
||||
|
||||
//go:embed harness/*
|
||||
var testHarness embed.FS
|
||||
|
||||
var Harnesses = beacontest.NewBasePathFs(afero.FromIOFS{FS: testHarness}, "harness")
|
||||
|
||||
type harnessConfig struct {
|
||||
t *testing.T
|
||||
v clparams.StateVersion
|
||||
finalized bool
|
||||
forkmode int
|
||||
}
|
||||
|
||||
func defaultHarnessOpts(c harnessConfig) []beacontest.HarnessOption {
|
||||
logger := log.New()
|
||||
for _, v := range os.Args {
|
||||
if !strings.Contains(v, "test.v") || strings.Contains(v, "test.v=false") {
|
||||
logger.SetHandler(log.DiscardHandler())
|
||||
}
|
||||
}
|
||||
_, blocks, _, _, postState, handler, _, sm, fcu := setupTestingHandler(c.t, c.v, logger)
|
||||
var err error
|
||||
|
||||
if c.forkmode == 0 {
|
||||
fcu.HeadVal, err = blocks[len(blocks)-1].Block.HashSSZ()
|
||||
require.NoError(c.t, err)
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
|
||||
fcu.JustifiedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
if c.finalized {
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
fcu.FinalizedSlotVal = math.MaxUint64
|
||||
} else {
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
fcu.FinalizedSlotVal = 0
|
||||
fcu.StateAtBlockRootVal[fcu.HeadVal] = postState
|
||||
require.NoError(c.t, sm.OnHeadState(postState))
|
||||
}
|
||||
}
|
||||
|
||||
if c.forkmode == 1 {
|
||||
sm.OnHeadState(postState)
|
||||
s, cancel := sm.HeadState()
|
||||
s.SetSlot(789274827847783)
|
||||
cancel()
|
||||
|
||||
fcu.HeadSlotVal = 128
|
||||
fcu.HeadVal = common.Hash{1, 2, 3}
|
||||
|
||||
fcu.WeightsMock = []forkchoice.ForkNode{
|
||||
{
|
||||
BlockRoot: common.Hash{1, 2, 3},
|
||||
ParentRoot: common.Hash{1, 2, 3},
|
||||
Slot: 128,
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
BlockRoot: common.Hash{1, 2, 2, 4, 5, 3},
|
||||
ParentRoot: common.Hash{1, 2, 5},
|
||||
Slot: 128,
|
||||
Weight: 2,
|
||||
},
|
||||
}
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(common.Hash{1, 2, 3}, 1)
|
||||
fcu.JustifiedCheckpointVal = solid.NewCheckpointFromParameters(common.Hash{1, 2, 3}, 2)
|
||||
|
||||
}
|
||||
|
||||
return []beacontest.HarnessOption{
|
||||
beacontest.WithTesting(c.t),
|
||||
beacontest.WithFilesystem("td", TestDatae),
|
||||
beacontest.WithHandler("i", handler),
|
||||
}
|
||||
}
|
@ -22,8 +22,8 @@ type attesterDutyResponse struct {
|
||||
Slot uint64 `json:"slot,string"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getAttesterDuties(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
epoch, err := epochFromRequest(r)
|
||||
func (a *ApiHandler) getAttesterDuties(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
epoch, err := beaconhttp.EpochFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -33,7 +33,7 @@ func (a *ApiHandler) getAttesterDuties(w http.ResponseWriter, r *http.Request) (
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, fmt.Errorf("could not decode request body: %w. request body is required", err).Error())
|
||||
}
|
||||
if len(idxsStr) == 0 {
|
||||
return newBeaconResponse([]string{}).withOptimistic(false), nil
|
||||
return newBeaconResponse([]string{}).WithOptimistic(false), nil
|
||||
}
|
||||
idxSet := map[int]struct{}{}
|
||||
// convert the request to uint64
|
||||
@ -100,7 +100,7 @@ func (a *ApiHandler) getAttesterDuties(w http.ResponseWriter, r *http.Request) (
|
||||
}
|
||||
}
|
||||
}
|
||||
return newBeaconResponse(resp).withOptimistic(false), nil
|
||||
return newBeaconResponse(resp).WithOptimistic(false), nil
|
||||
}
|
||||
|
||||
stageStateProgress, err := state_accessors.GetStateProcessingProgress(tx)
|
||||
@ -159,5 +159,5 @@ func (a *ApiHandler) getAttesterDuties(w http.ResponseWriter, r *http.Request) (
|
||||
}
|
||||
}
|
||||
}
|
||||
return newBeaconResponse(resp).withOptimistic(false), nil
|
||||
return newBeaconResponse(resp).WithOptimistic(false), nil
|
||||
}
|
||||
|
@ -1,153 +0,0 @@
|
||||
//go:build integration
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDutiesAttesterAntiquated(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, postState, handler, _, _, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
fcu.FinalizedSlotVal = math.MaxUint64
|
||||
|
||||
fcu.StateAtBlockRootVal[fcu.HeadVal] = postState
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
epoch string
|
||||
code int
|
||||
reqBody string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "non-empty-indicies",
|
||||
epoch: strconv.FormatUint(fcu.HeadSlotVal/32, 10),
|
||||
code: http.StatusOK,
|
||||
reqBody: `["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]`,
|
||||
expected: `{"data":[{"pubkey":"0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb","validator_index":"0","committee_index":"0","committee_length":"14","validator_committee_index":"0","committees_at_slot":"1","slot":"8322"},{"pubkey":"0xb0e7791fb972fe014159aa33a98622da3cdc98ff707965e536d8636b5fcc5ac7a91a8c46e59a00dca575af0f18fb13dc","validator_index":"4","committee_index":"0","committee_length":"13","validator_committee_index":"5","committees_at_slot":"1","slot":"8327"},{"pubkey":"0xb928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb7","validator_index":"6","committee_index":"0","committee_length":"13","validator_committee_index":"10","committees_at_slot":"1","slot":"8327"},{"pubkey":"0xa6e82f6da4520f85c5d27d8f329eccfa05944fd1096b20734c894966d12a9e2a9a9744529d7212d33883113a0cadb909","validator_index":"5","committee_index":"0","committee_length":"14","validator_committee_index":"10","committees_at_slot":"1","slot":"8329"},{"pubkey":"0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224","validator_index":"2","committee_index":"0","committee_length":"14","validator_committee_index":"11","committees_at_slot":"1","slot":"8331"},{"pubkey":"0xaf81da25ecf1c84b577fefbedd61077a81dc43b00304015b2b596ab67f00e41c86bb00ebd0f90d4b125eb0539891aeed","validator_index":"9","committee_index":"0","committee_length":"14","validator_committee_index":"8","committees_at_slot":"1","slot":"8342"},{"pubkey":"0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60","validator_index":"3","committee_index":"0","committee_length":"13","validator_committee_index":"6","committees_at_slot":"1","slot":"8348"}],"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "empty-index",
|
||||
epoch: strconv.FormatUint(fcu.HeadSlotVal/32, 10),
|
||||
code: http.StatusOK,
|
||||
reqBody: `[]`,
|
||||
expected: `{"data":[],"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "404",
|
||||
reqBody: `["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]`,
|
||||
epoch: `999999999`,
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
//
|
||||
body := bytes.Buffer{}
|
||||
body.WriteString(c.reqBody)
|
||||
// Query the block in the handler with /eth/v2/beacon/states/{block_id} with content-type octet-stream
|
||||
req, err := http.NewRequest("POST", server.URL+"/eth/v1/validator/duties/attester/"+c.epoch, &body)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
// read the all of the octect
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.expected, string(out))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDutiesAttesterNonAntiquated(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, postState, handler, _, sm, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
fcu.FinalizedSlotVal = 0
|
||||
|
||||
fcu.StateAtBlockRootVal[fcu.HeadVal] = postState
|
||||
require.NoError(t, sm.OnHeadState(postState))
|
||||
cases := []struct {
|
||||
name string
|
||||
epoch string
|
||||
code int
|
||||
reqBody string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "non-empty-indicies",
|
||||
epoch: strconv.FormatUint(fcu.HeadSlotVal/32, 10),
|
||||
code: http.StatusOK,
|
||||
reqBody: `["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]`,
|
||||
expected: `{"data":[{"pubkey":"0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb","validator_index":"0","committee_index":"0","committee_length":"14","validator_committee_index":"0","committees_at_slot":"1","slot":"8322"},{"pubkey":"0xb0e7791fb972fe014159aa33a98622da3cdc98ff707965e536d8636b5fcc5ac7a91a8c46e59a00dca575af0f18fb13dc","validator_index":"4","committee_index":"0","committee_length":"13","validator_committee_index":"5","committees_at_slot":"1","slot":"8327"},{"pubkey":"0xb928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb7","validator_index":"6","committee_index":"0","committee_length":"13","validator_committee_index":"10","committees_at_slot":"1","slot":"8327"},{"pubkey":"0xa6e82f6da4520f85c5d27d8f329eccfa05944fd1096b20734c894966d12a9e2a9a9744529d7212d33883113a0cadb909","validator_index":"5","committee_index":"0","committee_length":"14","validator_committee_index":"10","committees_at_slot":"1","slot":"8329"},{"pubkey":"0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224","validator_index":"2","committee_index":"0","committee_length":"14","validator_committee_index":"11","committees_at_slot":"1","slot":"8331"},{"pubkey":"0xaf81da25ecf1c84b577fefbedd61077a81dc43b00304015b2b596ab67f00e41c86bb00ebd0f90d4b125eb0539891aeed","validator_index":"9","committee_index":"0","committee_length":"14","validator_committee_index":"8","committees_at_slot":"1","slot":"8342"},{"pubkey":"0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60","validator_index":"3","committee_index":"0","committee_length":"13","validator_committee_index":"6","committees_at_slot":"1","slot":"8348"}],"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "empty-index",
|
||||
epoch: strconv.FormatUint(fcu.HeadSlotVal/32, 10),
|
||||
code: http.StatusOK,
|
||||
reqBody: `[]`,
|
||||
expected: `{"data":[],"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "404",
|
||||
reqBody: `["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]`,
|
||||
epoch: `999999999`,
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
//
|
||||
body := bytes.Buffer{}
|
||||
body.WriteString(c.reqBody)
|
||||
// Query the block in the handler with /eth/v2/beacon/states/{block_id} with content-type octet-stream
|
||||
req, err := http.NewRequest("POST", server.URL+"/eth/v1/validator/duties/attester/"+c.epoch, &body)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
// read the all of the octect
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.expected, string(out))
|
||||
})
|
||||
}
|
||||
}
|
@ -21,8 +21,8 @@ type proposerDuties struct {
|
||||
Slot uint64 `json:"slot,string"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getDutiesProposer(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
epoch, err := epochFromRequest(r)
|
||||
func (a *ApiHandler) getDutiesProposer(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
epoch, err := beaconhttp.EpochFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -55,7 +55,7 @@ func (a *ApiHandler) getDutiesProposer(w http.ResponseWriter, r *http.Request) (
|
||||
Slot: epoch*a.beaconChainCfg.SlotsPerEpoch + i,
|
||||
}
|
||||
}
|
||||
return newBeaconResponse(duties).withFinalized(true).withVersion(a.beaconChainCfg.GetCurrentStateVersion(epoch)), nil
|
||||
return newBeaconResponse(duties).WithFinalized(true).WithVersion(a.beaconChainCfg.GetCurrentStateVersion(epoch)), nil
|
||||
}
|
||||
|
||||
// We need to compute our duties
|
||||
@ -118,5 +118,5 @@ func (a *ApiHandler) getDutiesProposer(w http.ResponseWriter, r *http.Request) (
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return newBeaconResponse(duties).withFinalized(false).withVersion(a.beaconChainCfg.GetCurrentStateVersion(epoch)), nil
|
||||
return newBeaconResponse(duties).WithFinalized(false).WithVersion(a.beaconChainCfg.GetCurrentStateVersion(epoch)), nil
|
||||
}
|
||||
|
@ -1,114 +0,0 @@
|
||||
//go:build integration
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestProposerDutiesProposerFcu(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, postState, _, handler, _, syncedDataManager, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
epoch := blocks[len(blocks)-1].Block.Slot / 32
|
||||
|
||||
require.NoError(t, syncedDataManager.OnHeadState(postState))
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(common.Hash{}, epoch)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get(server.URL + "/eth/v1/validator/duties/proposer/" + strconv.FormatUint(epoch, 10))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
out := make(map[string]interface{})
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
data := out["data"].([]interface{})
|
||||
require.Equal(t, len(data), 32)
|
||||
for _, v := range data {
|
||||
d := v.(map[string]interface{})
|
||||
require.NotNil(t, d["pubkey"])
|
||||
require.NotNil(t, d["validator_index"])
|
||||
require.NotNil(t, d["slot"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestProposerDutiesProposerBadEpoch(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, _, _, postState, _, handler, _, syncedDataManager, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
require.NoError(t, syncedDataManager.OnHeadState(postState))
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(common.Hash{}, 1)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get(server.URL + "/eth/v1/validator/duties/proposer/abc")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestProposerDutiesNotSynced(t *testing.T) {
|
||||
_, _, _, _, _, handler, _, _, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(common.Hash{}, 1)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get(server.URL + "/eth/v1/validator/duties/proposer/1")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusServiceUnavailable, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestProposerDutiesProposerFcuHistorical(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, postState, _, handler, _, syncedDataManager, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
epoch := blocks[len(blocks)-1].Block.Slot / 32
|
||||
|
||||
require.NoError(t, syncedDataManager.OnHeadState(postState))
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(common.Hash{}, epoch)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get(server.URL + "/eth/v1/validator/duties/proposer/" + strconv.FormatUint(epoch-1, 10))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
out := make(map[string]interface{})
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
data := out["data"].([]interface{})
|
||||
require.Equal(t, len(data), 32)
|
||||
for _, v := range data {
|
||||
d := v.(map[string]interface{})
|
||||
require.NotNil(t, d["pubkey"])
|
||||
require.NotNil(t, d["validator_index"])
|
||||
require.NotNil(t, d["slot"])
|
||||
}
|
||||
}
|
@ -20,8 +20,8 @@ type syncDutyResponse struct {
|
||||
ValidatorSyncCommitteeIndicies []string `json:"validator_sync_committee_indicies"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getSyncDuties(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
epoch, err := epochFromRequest(r)
|
||||
func (a *ApiHandler) getSyncDuties(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
epoch, err := beaconhttp.EpochFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -34,7 +34,7 @@ func (a *ApiHandler) getSyncDuties(w http.ResponseWriter, r *http.Request) (*bea
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, fmt.Errorf("could not decode request body: %w. request body is required.", err).Error())
|
||||
}
|
||||
if len(idxsStr) == 0 {
|
||||
return newBeaconResponse([]string{}).withOptimistic(false), nil
|
||||
return newBeaconResponse([]string{}).WithOptimistic(false), nil
|
||||
}
|
||||
duplicates := map[int]struct{}{}
|
||||
// convert the request to uint64
|
||||
@ -142,5 +142,5 @@ func (a *ApiHandler) getSyncDuties(w http.ResponseWriter, r *http.Request) (*bea
|
||||
return duties[i].ValidatorIndex < duties[j].ValidatorIndex
|
||||
})
|
||||
|
||||
return newBeaconResponse(duties).withOptimistic(false), nil
|
||||
return newBeaconResponse(duties).WithOptimistic(false), nil
|
||||
}
|
||||
|
@ -1,87 +0,0 @@
|
||||
//go:build integration
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDutiesSync(t *testing.T) {
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, postState, handler, _, _, fcu := setupTestingHandler(t, clparams.BellatrixVersion)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
fcu.FinalizedSlotVal = math.MaxUint64
|
||||
|
||||
fcu.StateAtBlockRootVal[fcu.HeadVal] = postState
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
epoch string
|
||||
code int
|
||||
reqBody string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "non-empty-indicies",
|
||||
epoch: strconv.FormatUint(fcu.HeadSlotVal/32, 10),
|
||||
code: http.StatusOK,
|
||||
reqBody: `["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]`,
|
||||
expected: `{"data":[{"pubkey":"0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb","validator_index":"0","validator_sync_committee_indicies":["30","286"]},{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","validator_index":"1","validator_sync_committee_indicies":["120","376"]},{"pubkey":"0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224","validator_index":"2","validator_sync_committee_indicies":["138","394"]},{"pubkey":"0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60","validator_index":"3","validator_sync_committee_indicies":["10","266"]},{"pubkey":"0xb0e7791fb972fe014159aa33a98622da3cdc98ff707965e536d8636b5fcc5ac7a91a8c46e59a00dca575af0f18fb13dc","validator_index":"4","validator_sync_committee_indicies":["114","370"]},{"pubkey":"0xa6e82f6da4520f85c5d27d8f329eccfa05944fd1096b20734c894966d12a9e2a9a9744529d7212d33883113a0cadb909","validator_index":"5","validator_sync_committee_indicies":["103","359"]},{"pubkey":"0xb928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb7","validator_index":"6","validator_sync_committee_indicies":["163","419"]},{"pubkey":"0xa85ae765588126f5e860d019c0e26235f567a9c0c0b2d8ff30f3e8d436b1082596e5e7462d20f5be3764fd473e57f9cf","validator_index":"7","validator_sync_committee_indicies":["197","453"]},{"pubkey":"0x99cdf3807146e68e041314ca93e1fee0991224ec2a74beb2866816fd0826ce7b6263ee31e953a86d1b72cc2215a57793","validator_index":"8","validator_sync_committee_indicies":["175","431"]},{"pubkey":"0xaf81da25ecf1c84b577fefbedd61077a81dc43b00304015b2b596ab67f00e41c86bb00ebd0f90d4b125eb0539891aeed","validator_index":"9","validator_sync_committee_indicies":["53","309"]}],"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "empty-index",
|
||||
epoch: strconv.FormatUint(fcu.HeadSlotVal/32, 10),
|
||||
code: http.StatusOK,
|
||||
reqBody: `[]`,
|
||||
expected: `{"data":[],"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
name: "404",
|
||||
reqBody: `["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]`,
|
||||
epoch: `999999999`,
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
//
|
||||
body := bytes.Buffer{}
|
||||
body.WriteString(c.reqBody)
|
||||
// Query the block in the handler with /eth/v2/beacon/states/{block_id} with content-type octet-stream
|
||||
req, err := http.NewRequest("POST", server.URL+"/eth/v1/validator/duties/sync/"+c.epoch, &body)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
// read the all of the octect
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
if string(out) != c.expected {
|
||||
panic(string(out))
|
||||
}
|
||||
require.Equal(t, c.expected, string(out))
|
||||
})
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import (
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/beaconhttp"
|
||||
)
|
||||
|
||||
func (a *ApiHandler) GetEthV2DebugBeaconHeads(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) GetEthV2DebugBeaconHeads(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
if a.syncedData.Syncing() {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusServiceUnavailable, "beacon node is syncing")
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
||||
"github.com/ledgerwatch/erigon/cl/phase1/forkchoice"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetHeads(t *testing.T) {
|
||||
// find server
|
||||
_, _, _, _, p, handler, _, sm, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
sm.OnHeadState(p)
|
||||
s, cancel := sm.HeadState()
|
||||
s.SetSlot(789274827847783)
|
||||
cancel()
|
||||
|
||||
fcu.HeadSlotVal = 128
|
||||
fcu.HeadVal = libcommon.Hash{1, 2, 3}
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
// get heads
|
||||
resp, err := server.Client().Get(server.URL + "/eth/v2/debug/beacon/heads")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, `{"data":[{"execution_optimistic":false,"root":"0x0102030000000000000000000000000000000000000000000000000000000000","slot":128}]}`+"\n", string(out))
|
||||
}
|
||||
|
||||
func TestGetForkchoice(t *testing.T) {
|
||||
// find server
|
||||
_, _, _, _, p, handler, _, sm, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
sm.OnHeadState(p)
|
||||
s, cancel := sm.HeadState()
|
||||
s.SetSlot(789274827847783)
|
||||
cancel()
|
||||
|
||||
fcu.HeadSlotVal = 128
|
||||
fcu.HeadVal = libcommon.Hash{1, 2, 3}
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
fcu.WeightsMock = []forkchoice.ForkNode{
|
||||
{
|
||||
BlockRoot: libcommon.Hash{1, 2, 3},
|
||||
ParentRoot: libcommon.Hash{1, 2, 3},
|
||||
Slot: 128,
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
BlockRoot: libcommon.Hash{1, 2, 2, 4, 5, 3},
|
||||
ParentRoot: libcommon.Hash{1, 2, 5},
|
||||
Slot: 128,
|
||||
Weight: 2,
|
||||
},
|
||||
}
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(libcommon.Hash{1, 2, 3}, 1)
|
||||
fcu.JustifiedCheckpointVal = solid.NewCheckpointFromParameters(libcommon.Hash{1, 2, 3}, 2)
|
||||
|
||||
// get heads
|
||||
resp, err := server.Client().Get(server.URL + "/eth/v1/debug/fork_choice")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `{"finalized_checkpoint":{"epoch":"1","root":"0x0102030000000000000000000000000000000000000000000000000000000000"},"fork_choice_nodes":[{"slot":"128","block_root":"0x0102030000000000000000000000000000000000000000000000000000000000","parent_root":"0x0102030000000000000000000000000000000000000000000000000000000000","justified_epoch":"0","finalized_epoch":"0","weight":"1","validity":"","execution_block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000"},{"slot":"128","block_root":"0x0102020405030000000000000000000000000000000000000000000000000000","parent_root":"0x0102050000000000000000000000000000000000000000000000000000000000","justified_epoch":"0","finalized_epoch":"0","weight":"2","validity":"","execution_block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000"}],"justified_checkpoint":{"epoch":"2","root":"0x0102030000000000000000000000000000000000000000000000000000000000"}}`+"\n", string(out))
|
||||
}
|
@ -1,242 +1,9 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon-lib/types/ssz"
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/beaconhttp"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
)
|
||||
|
||||
type apiError struct {
|
||||
code int
|
||||
err error
|
||||
}
|
||||
|
||||
type beaconResponse struct {
|
||||
Data any `json:"data,omitempty"`
|
||||
Finalized *bool `json:"finalized,omitempty"`
|
||||
Version *clparams.StateVersion `json:"version,omitempty"`
|
||||
ExecutionOptimistic *bool `json:"execution_optimistic,omitempty"`
|
||||
}
|
||||
|
||||
func (b *beaconResponse) EncodeSSZ(xs []byte) ([]byte, error) {
|
||||
marshaler, ok := b.Data.(ssz.Marshaler)
|
||||
if !ok {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, "This endpoint does not support SSZ response")
|
||||
}
|
||||
encoded, err := marshaler.EncodeSSZ(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
func (b *beaconResponse) EncodingSizeSSZ() int {
|
||||
marshaler, ok := b.Data.(ssz.Marshaler)
|
||||
if !ok {
|
||||
return 9
|
||||
}
|
||||
return marshaler.EncodingSizeSSZ()
|
||||
}
|
||||
|
||||
func newBeaconResponse(data any) *beaconResponse {
|
||||
return &beaconResponse{
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *beaconResponse) withFinalized(finalized bool) (out *beaconResponse) {
|
||||
out = new(beaconResponse)
|
||||
*out = *r
|
||||
out.Finalized = new(bool)
|
||||
out.ExecutionOptimistic = new(bool)
|
||||
out.Finalized = &finalized
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *beaconResponse) withOptimistic(optimistic bool) (out *beaconResponse) {
|
||||
out = new(beaconResponse)
|
||||
*out = *r
|
||||
out.ExecutionOptimistic = new(bool)
|
||||
out.ExecutionOptimistic = &optimistic
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *beaconResponse) withVersion(version clparams.StateVersion) (out *beaconResponse) {
|
||||
out = new(beaconResponse)
|
||||
*out = *r
|
||||
out.Version = new(clparams.StateVersion)
|
||||
out.Version = &version
|
||||
return out
|
||||
}
|
||||
|
||||
type chainTag int
|
||||
|
||||
var (
|
||||
Head chainTag = 0
|
||||
Finalized chainTag = 1
|
||||
Justified chainTag = 2
|
||||
Genesis chainTag = 3
|
||||
)
|
||||
|
||||
// Represent either state id or block id
|
||||
type segmentID struct {
|
||||
tag chainTag
|
||||
slot *uint64
|
||||
root *libcommon.Hash
|
||||
}
|
||||
|
||||
func (c *segmentID) head() bool {
|
||||
return c.tag == Head && c.slot == nil && c.root == nil
|
||||
}
|
||||
|
||||
func (c *segmentID) finalized() bool {
|
||||
return c.tag == Finalized
|
||||
}
|
||||
|
||||
func (c *segmentID) justified() bool {
|
||||
return c.tag == Justified
|
||||
}
|
||||
|
||||
func (c *segmentID) genesis() bool {
|
||||
return c.tag == Genesis
|
||||
}
|
||||
|
||||
func (c *segmentID) getSlot() *uint64 {
|
||||
return c.slot
|
||||
}
|
||||
|
||||
func (c *segmentID) getRoot() *libcommon.Hash {
|
||||
return c.root
|
||||
}
|
||||
|
||||
func epochFromRequest(r *http.Request) (uint64, error) {
|
||||
// Must only be a number
|
||||
regex := regexp.MustCompile(`^\d+$`)
|
||||
epoch := chi.URLParam(r, "epoch")
|
||||
if !regex.MatchString(epoch) {
|
||||
return 0, fmt.Errorf("invalid path variable: {epoch}")
|
||||
}
|
||||
epochMaybe, err := strconv.ParseUint(epoch, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return epochMaybe, nil
|
||||
}
|
||||
|
||||
func stringFromRequest(r *http.Request, name string) (string, error) {
|
||||
str := chi.URLParam(r, name)
|
||||
if str == "" {
|
||||
return "", nil
|
||||
}
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func blockIdFromRequest(r *http.Request) (*segmentID, error) {
|
||||
regex := regexp.MustCompile(`^(?:0x[0-9a-fA-F]{64}|head|finalized|genesis|\d+)$`)
|
||||
|
||||
blockId := chi.URLParam(r, "block_id")
|
||||
if !regex.MatchString(blockId) {
|
||||
return nil, fmt.Errorf("invalid path variable: {block_id}")
|
||||
}
|
||||
|
||||
if blockId == "head" {
|
||||
return &segmentID{tag: Head}, nil
|
||||
}
|
||||
if blockId == "finalized" {
|
||||
return &segmentID{tag: Finalized}, nil
|
||||
}
|
||||
if blockId == "genesis" {
|
||||
return &segmentID{tag: Genesis}, nil
|
||||
}
|
||||
slotMaybe, err := strconv.ParseUint(blockId, 10, 64)
|
||||
if err == nil {
|
||||
return &segmentID{slot: &slotMaybe}, nil
|
||||
}
|
||||
root := libcommon.HexToHash(blockId)
|
||||
return &segmentID{
|
||||
root: &root,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func stateIdFromRequest(r *http.Request) (*segmentID, error) {
|
||||
regex := regexp.MustCompile(`^(?:0x[0-9a-fA-F]{64}|head|finalized|genesis|justified|\d+)$`)
|
||||
|
||||
stateId := chi.URLParam(r, "state_id")
|
||||
if !regex.MatchString(stateId) {
|
||||
return nil, fmt.Errorf("invalid path variable: {state_id}")
|
||||
}
|
||||
|
||||
if stateId == "head" {
|
||||
return &segmentID{tag: Head}, nil
|
||||
}
|
||||
if stateId == "finalized" {
|
||||
return &segmentID{tag: Finalized}, nil
|
||||
}
|
||||
if stateId == "genesis" {
|
||||
return &segmentID{tag: Genesis}, nil
|
||||
}
|
||||
if stateId == "justified" {
|
||||
return &segmentID{tag: Justified}, nil
|
||||
}
|
||||
slotMaybe, err := strconv.ParseUint(stateId, 10, 64)
|
||||
if err == nil {
|
||||
return &segmentID{slot: &slotMaybe}, nil
|
||||
}
|
||||
root := libcommon.HexToHash(stateId)
|
||||
return &segmentID{
|
||||
root: &root,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func hashFromQueryParams(r *http.Request, name string) (*libcommon.Hash, error) {
|
||||
hashStr := r.URL.Query().Get(name)
|
||||
if hashStr == "" {
|
||||
return nil, nil
|
||||
}
|
||||
// check if hashstr is an hex string
|
||||
if len(hashStr) != 2+2*32 {
|
||||
return nil, fmt.Errorf("invalid hash length")
|
||||
}
|
||||
if hashStr[:2] != "0x" {
|
||||
return nil, fmt.Errorf("invalid hash prefix")
|
||||
}
|
||||
notHex, err := regexp.MatchString("[^0-9A-Fa-f]", hashStr[2:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if notHex {
|
||||
return nil, fmt.Errorf("invalid hash characters")
|
||||
}
|
||||
|
||||
hash := libcommon.HexToHash(hashStr)
|
||||
return &hash, nil
|
||||
}
|
||||
|
||||
// uint64FromQueryParams retrieves a number from the query params, in base 10.
|
||||
func uint64FromQueryParams(r *http.Request, name string) (*uint64, error) {
|
||||
str := r.URL.Query().Get(name)
|
||||
if str == "" {
|
||||
return nil, nil
|
||||
}
|
||||
num, err := strconv.ParseUint(str, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &num, nil
|
||||
}
|
||||
|
||||
// decode a list of strings from the query params
|
||||
func stringListFromQueryParams(r *http.Request, name string) ([]string, error) {
|
||||
str := r.URL.Query().Get(name)
|
||||
if str == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return regexp.MustCompile(`\s*,\s*`).Split(str, -1), nil
|
||||
func newBeaconResponse(data any) *beaconhttp.BeaconResponse {
|
||||
return beaconhttp.NewBeaconResponse(data)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ type genesisResponse struct {
|
||||
GenesisForkVersion libcommon.Bytes4 `json:"genesis_fork_version"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getGenesis(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getGenesis(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
if a.genesisCfg == nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, "Genesis Config is missing")
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetGenesis(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get(server.URL + "/eth/v1/beacon/genesis")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
out := make(map[string]interface{})
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
data := out["data"].(map[string]interface{})
|
||||
genesisTime := data["genesis_time"].(string)
|
||||
require.Equal(t, genesisTime, "1606824023")
|
||||
require.Equal(t, data["genesis_fork_version"], "0xbba4da96")
|
||||
require.Equal(t, data["genesis_validators_root"], "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95")
|
||||
}
|
@ -44,6 +44,11 @@ func NewApiHandler(genesisConfig *clparams.GenesisConfig, beaconChainConfig *clp
|
||||
}}, sentinel: sentinel, version: version}
|
||||
}
|
||||
|
||||
func (a *ApiHandler) Init() {
|
||||
a.o.Do(func() {
|
||||
a.init()
|
||||
})
|
||||
}
|
||||
func (a *ApiHandler) init() {
|
||||
r := chi.NewRouter()
|
||||
a.mux = r
|
||||
|
31
cl/beacon/handler/harness/attestation_rewards_bellatrix.yml
Normal file
31
cl/beacon/handler/harness/attestation_rewards_bellatrix.yml
Normal file
@ -0,0 +1,31 @@
|
||||
vars:
|
||||
finalized_epoch: "99999999"
|
||||
justified_slot: "160"
|
||||
justified_epoch: "4"
|
||||
tests:
|
||||
## blocks
|
||||
- name: all validators
|
||||
expect:
|
||||
file: "attestations_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
method: post
|
||||
path: /eth/v1/beacon/rewards/attestations/{{.Vars.justified_epoch}}
|
||||
- name: two validators
|
||||
expect:
|
||||
file: "attestations_2"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
method: post
|
||||
path: /eth/v1/beacon/rewards/attestations/{{.Vars.justified_epoch}}
|
||||
body:
|
||||
data: ["1","4"]
|
||||
- name: not found
|
||||
actual:
|
||||
handler: i
|
||||
method: post
|
||||
path: /eth/v1/beacon/rewards/attestations/{{.Vars.finalized_epoch}}
|
||||
compare:
|
||||
expr: "actual_code == 404"
|
33
cl/beacon/handler/harness/attestation_rewards_phase0.yml
Normal file
33
cl/beacon/handler/harness/attestation_rewards_phase0.yml
Normal file
@ -0,0 +1,33 @@
|
||||
vars:
|
||||
head_hash: '0xeffdd8ef40c3c901f0724d48e04ce257967cf1da31929f3b6db614f89ef8d660'
|
||||
bad_hash: '0xbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeef'
|
||||
finalized_epoch: "99999999"
|
||||
justified_slot: "8322"
|
||||
justified_epoch: "259"
|
||||
tests:
|
||||
## blocks
|
||||
- name: all validators
|
||||
expect:
|
||||
file: "attestations_3"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
method: post
|
||||
path: /eth/v1/beacon/rewards/attestations/{{.Vars.justified_epoch}}
|
||||
- name: two validators
|
||||
expect:
|
||||
file: "attestations_4"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/rewards/attestations/{{.Vars.justified_epoch}}
|
||||
method: post
|
||||
body:
|
||||
data: ["1","4"]
|
||||
- name: not found
|
||||
actual:
|
||||
handler: i
|
||||
method: post
|
||||
path: /eth/v1/beacon/rewards/attestations/{{.Vars.finalized_epoch}}
|
||||
compare:
|
||||
expr: "actual_code == 404"
|
100
cl/beacon/handler/harness/blocks.yml
Normal file
100
cl/beacon/handler/harness/blocks.yml
Normal file
@ -0,0 +1,100 @@
|
||||
vars:
|
||||
head_hash: '0xeffdd8ef40c3c901f0724d48e04ce257967cf1da31929f3b6db614f89ef8d660'
|
||||
bad_hash: '0xbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeef'
|
||||
tests:
|
||||
## blocks
|
||||
- name: by hash
|
||||
expect:
|
||||
file: "block_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v2/beacon/blocks/{{.Vars.head_hash}}
|
||||
- name: by head
|
||||
expect:
|
||||
file: "block_1"
|
||||
fs: td
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- actual == expect
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v2/beacon/blocks/head
|
||||
- name: not found
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v2/beacon/blocks/{{.Vars.bad_hash}}
|
||||
compare:
|
||||
expr: "actual_code == 404"
|
||||
## blinded blocks
|
||||
- name: blinded by hash
|
||||
expect:
|
||||
file: "blinded_block_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/blinded_blocks/{{.Vars.head_hash}}
|
||||
- name: blinded by head
|
||||
expect:
|
||||
file: "blinded_block_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/blinded_blocks/head
|
||||
- name: blinded not found
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/blinded_blocks/{{.Vars.bad_hash}}
|
||||
compare:
|
||||
expr: "actual_code == 404"
|
||||
### attestations
|
||||
- name: attestations by hash
|
||||
expect:
|
||||
file: "block_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/blocks/{{.Vars.head_hash}}/attestations
|
||||
compare:
|
||||
expr: "size(actual.data) == size(expect.data.message.body.attestations)"
|
||||
- name: attestions by head
|
||||
expect:
|
||||
file: "block_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/blocks/head/attestations
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- size(actual.data) == size(expect.data.message.body.attestations)
|
||||
- name: attestions not found
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/blocks/{{.Vars.bad_hash}}/attestations
|
||||
compare:
|
||||
expr: "actual_code == 404"
|
||||
### root
|
||||
- name: root by hash
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/blocks/{{.Vars.head_hash}}/root
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- actual.data.root == "{{.Vars.head_hash}}"
|
||||
- name: root by head
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/blocks/head/root
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- actual.data.root == "{{.Vars.head_hash}}"
|
||||
- name: root not found
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/blocks/19912929/root
|
||||
compare:
|
||||
expr: "actual_code == 404"
|
55
cl/beacon/handler/harness/committees.yml
Normal file
55
cl/beacon/handler/harness/committees.yml
Normal file
@ -0,0 +1,55 @@
|
||||
vars:
|
||||
head_hash: '0xeffdd8ef40c3c901f0724d48e04ce257967cf1da31929f3b6db614f89ef8d660'
|
||||
bad_hash: '0xbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeef'
|
||||
post_root: '0x933d6650f2999f17012e781f5012981edb549e5935de1c981fce81cdd241d4e1'
|
||||
head_slot: 8322
|
||||
head_epoch: "260"
|
||||
tests:
|
||||
- name: slot non antiquated
|
||||
expect:
|
||||
file: "committees_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/states/{{.Vars.post_root}}/committees
|
||||
query:
|
||||
slot: "8322"
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[3] == actual"
|
||||
- name: empty index non antiquated
|
||||
expect:
|
||||
file: "committees_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/states/{{.Vars.post_root}}/committees
|
||||
query:
|
||||
index: "1"
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[4] == actual"
|
||||
- name: all queries non antiquated
|
||||
expect:
|
||||
file: "committees_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/states/{{.Vars.post_root}}/committees
|
||||
query:
|
||||
index: "0"
|
||||
slot: "{{sub .Vars.head_slot 32}}"
|
||||
epoch: "{{sub .Vars.head_epoch 1}}"
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[5] == actual"
|
||||
- name: 404 non antiquated
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/states/{{.Vars.bad_hash}}/committees
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 404"
|
55
cl/beacon/handler/harness/committees_f.yml
Normal file
55
cl/beacon/handler/harness/committees_f.yml
Normal file
@ -0,0 +1,55 @@
|
||||
vars:
|
||||
head_hash: '0xeffdd8ef40c3c901f0724d48e04ce257967cf1da31929f3b6db614f89ef8d660'
|
||||
bad_hash: '0xbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeef'
|
||||
post_root: '0x933d6650f2999f17012e781f5012981edb549e5935de1c981fce81cdd241d4e1'
|
||||
head_slot: 8322
|
||||
head_epoch: "260"
|
||||
tests:
|
||||
- name: slot
|
||||
expect:
|
||||
file: "committees_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/states/{{.Vars.post_root}}/committees
|
||||
query:
|
||||
slot: "8322"
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[0] == actual"
|
||||
- name: empty index
|
||||
expect:
|
||||
file: "committees_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/states/{{.Vars.post_root}}/committees
|
||||
query:
|
||||
index: "1"
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[1] == actual"
|
||||
- name: all queries
|
||||
expect:
|
||||
file: "committees_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/states/{{.Vars.post_root}}/committees
|
||||
query:
|
||||
index: "0"
|
||||
slot: "{{sub .Vars.head_slot 32}}"
|
||||
epoch: "{{sub .Vars.head_epoch 1}}"
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[2] == actual"
|
||||
- name: "404"
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/states/{{.Vars.bad_hash}}/committees
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 404"
|
32
cl/beacon/handler/harness/config.yml
Normal file
32
cl/beacon/handler/harness/config.yml
Normal file
@ -0,0 +1,32 @@
|
||||
tests:
|
||||
- name: spec
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/config/spec
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- actual.data.SlotsPerEpoch == 32
|
||||
- actual.data.SlotsPerHistoricalRoot == 8192
|
||||
- name: fork schedule
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/config/fork_schedule
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- has(actual.data[0].current_version)
|
||||
- has(actual.data[0].previous_version)
|
||||
- has(actual.data[0].epoch)
|
||||
- has(actual.data[1].current_version)
|
||||
- has(actual.data[1].previous_version)
|
||||
- has(actual.data[1].epoch)
|
||||
- name: deposit contract
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/config/deposit_contract
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- actual.data.address == "0x00000000219ab540356cBB839Cbe05303d7705Fa"
|
||||
- actual.data.chain_id == "1"
|
45
cl/beacon/handler/harness/duties_attester.yml
Normal file
45
cl/beacon/handler/harness/duties_attester.yml
Normal file
@ -0,0 +1,45 @@
|
||||
vars:
|
||||
head_hash: '0xeffdd8ef40c3c901f0724d48e04ce257967cf1da31929f3b6db614f89ef8d660'
|
||||
bad_hash: '0xbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeef'
|
||||
post_root: '0x933d6650f2999f17012e781f5012981edb549e5935de1c981fce81cdd241d4e1'
|
||||
head_slot: 8322
|
||||
head_epoch: "260"
|
||||
tests:
|
||||
- name: non empty indices
|
||||
expect:
|
||||
file: "duties_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/attester/{{.Vars.head_epoch}}
|
||||
method: post
|
||||
body:
|
||||
data: ["0","1","2","3","4","5","6","7","8","9"]
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[0] == actual"
|
||||
- name: empty index
|
||||
expect:
|
||||
file: "duties_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/attester/{{.Vars.head_epoch}}
|
||||
method: post
|
||||
body:
|
||||
data: []
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[1] == actual"
|
||||
- name: 400 non antiquated
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/attester/999999999
|
||||
method: post
|
||||
body:
|
||||
data: ["0","1","2","3","4","5","6","7","8","9"]
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 400"
|
45
cl/beacon/handler/harness/duties_attester_f.yml
Normal file
45
cl/beacon/handler/harness/duties_attester_f.yml
Normal file
@ -0,0 +1,45 @@
|
||||
vars:
|
||||
head_hash: '0xeffdd8ef40c3c901f0724d48e04ce257967cf1da31929f3b6db614f89ef8d660'
|
||||
bad_hash: '0xbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeef'
|
||||
post_root: '0x933d6650f2999f17012e781f5012981edb549e5935de1c981fce81cdd241d4e1'
|
||||
head_slot: 8322
|
||||
head_epoch: "260"
|
||||
tests:
|
||||
- name: non empty indices
|
||||
expect:
|
||||
file: "duties_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/attester/{{.Vars.head_epoch}}
|
||||
method: post
|
||||
body:
|
||||
data: ["0","1","2","3","4","5","6","7","8","9"]
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[0] == actual"
|
||||
- name: empty index
|
||||
expect:
|
||||
file: "duties_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/attester/{{.Vars.head_epoch}}
|
||||
method: post
|
||||
body:
|
||||
data: []
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[1] == actual"
|
||||
- name: 400 non antiquated
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/attester/999999999
|
||||
method: post
|
||||
body:
|
||||
data: ["0","1","2","3","4","5","6","7","8","9"]
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 400"
|
42
cl/beacon/handler/harness/duties_proposer.yml
Normal file
42
cl/beacon/handler/harness/duties_proposer.yml
Normal file
@ -0,0 +1,42 @@
|
||||
vars:
|
||||
head_hash: '0xeffdd8ef40c3c901f0724d48e04ce257967cf1da31929f3b6db614f89ef8d660'
|
||||
bad_hash: '0xbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeef'
|
||||
post_root: '0x933d6650f2999f17012e781f5012981edb549e5935de1c981fce81cdd241d4e1'
|
||||
head_slot: 8322
|
||||
head_epoch: "260"
|
||||
tests:
|
||||
- name: proposer duties
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/proposer/{{.Vars.head_epoch}}
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- size(actual.data) == 32
|
||||
- has(actual.data[0].pubkey)
|
||||
- has(actual.data[0].validator_index)
|
||||
- has(actual.data[0].slot)
|
||||
- name: proposer bad epoch
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/proposer/abc
|
||||
compare:
|
||||
expr: "actual_code == 400"
|
||||
|
||||
- name: proposer duties not synced
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/proposer/1
|
||||
compare:
|
||||
expr: "actual_code == 503"
|
||||
- name: fcu historical
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/proposer/{{sub .Vars.head_epoch 1}}
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- size(actual.data) == 32
|
||||
- has(actual.data[0].pubkey)
|
||||
- has(actual.data[0].validator_index)
|
||||
- has(actual.data[0].slot)
|
43
cl/beacon/handler/harness/duties_sync_bellatrix.yml
Normal file
43
cl/beacon/handler/harness/duties_sync_bellatrix.yml
Normal file
@ -0,0 +1,43 @@
|
||||
vars:
|
||||
finalized_epoch: 99999999
|
||||
head_slot: 160
|
||||
head_epoch: 4
|
||||
tests:
|
||||
- name: non empty indices
|
||||
expect:
|
||||
file: "duties_sync_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/sync/{{.Vars.head_epoch}}
|
||||
method: post
|
||||
body:
|
||||
data: ["0","1","2","3","4","5","6","7","8","9"]
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[0] == actual"
|
||||
- name: empty index
|
||||
expect:
|
||||
file: "duties_sync_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/sync/{{.Vars.head_epoch}}
|
||||
method: post
|
||||
body:
|
||||
data: []
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "expect[1] == actual"
|
||||
- name: "404 giant epoch"
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/duties/sync/999999999
|
||||
method: post
|
||||
body:
|
||||
data: ["0","1","2","3","4","5","6","7","8","9"]
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 404"
|
24
cl/beacon/handler/harness/fork_choice.yml
Normal file
24
cl/beacon/handler/harness/fork_choice.yml
Normal file
@ -0,0 +1,24 @@
|
||||
vars:
|
||||
tests:
|
||||
- name: get fork choice
|
||||
expect:
|
||||
file: "forkchoice_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v2/debug/beacon/heads
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "actual == expect[0]"
|
||||
- name: get heads
|
||||
expect:
|
||||
file: "forkchoice_1"
|
||||
fs: td
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/debug/fork_choice
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code == 200"
|
||||
- "actual == expect[1]"
|
38
cl/beacon/handler/harness/headers.yml
Normal file
38
cl/beacon/handler/harness/headers.yml
Normal file
@ -0,0 +1,38 @@
|
||||
vars:
|
||||
head_hash: '0xeffdd8ef40c3c901f0724d48e04ce257967cf1da31929f3b6db614f89ef8d660'
|
||||
post_root: '0x933d6650f2999f17012e781f5012981edb549e5935de1c981fce81cdd241d4e1'
|
||||
bad_hash: '0xbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeef'
|
||||
head_slot: 8322
|
||||
first_slot: 8288
|
||||
head_epoch: "260"
|
||||
body_root_1: "0x8d07005613673b3684b527f9c4dab5191403177e79b0e0bc1d58f15021abab19"
|
||||
body_root_2: "0xa6957819a5055b6d760c1b2ec034522cc033a7dd94c743ed936d8f8d0eb5ccce"
|
||||
block_1_hash: "0x86979f6f6dc7626064ef0d38d4dffb89e91d1d4c18492e3fb7d7ee93cedca3ed"
|
||||
tests:
|
||||
- name: not head
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/headers/{{.Vars.block_1_hash}}
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- actual.data.canonical == true
|
||||
- actual.data.header.message.body_root == "{{.Vars.body_root_1}}"
|
||||
- actual.data.header.message.slot == "{{.Vars.first_slot}}"
|
||||
- name: head
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/headers/head
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 200
|
||||
- actual.data.canonical == true
|
||||
- actual.data.header.message.body_root == "{{.Vars.body_root_2}}"
|
||||
- actual.data.header.message.slot == "{{.Vars.head_slot}}"
|
||||
- name: not head
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/beacon/headers/{{.Vars.bad_hash}}
|
||||
compare:
|
||||
exprs:
|
||||
- actual_code == 404
|
13
cl/beacon/handler/harness/liveness.yml
Normal file
13
cl/beacon/handler/harness/liveness.yml
Normal file
@ -0,0 +1,13 @@
|
||||
tests:
|
||||
- name: spec
|
||||
actual:
|
||||
handler: i
|
||||
path: /eth/v1/validator/liveness/260
|
||||
method: post
|
||||
body:
|
||||
data: ["0","1","2","3","4","5","6","7","8","9","10"]
|
||||
compare:
|
||||
exprs:
|
||||
- "actual_code==200"
|
||||
- "size(actual.data) == 11"
|
||||
- "actual.data.all(x,has(x.is_live) && has(x.index))"
|
53
cl/beacon/handler/harness_test.go
Normal file
53
cl/beacon/handler/harness_test.go
Normal file
@ -0,0 +1,53 @@
|
||||
package handler_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/beacontest"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
func TestHarnessPhase0(t *testing.T) {
|
||||
beacontest.Execute(
|
||||
append(
|
||||
defaultHarnessOpts(harnessConfig{t: t, v: clparams.Phase0Version}),
|
||||
beacontest.WithTestFromFs(Harnesses, "blocks"),
|
||||
beacontest.WithTestFromFs(Harnesses, "config"),
|
||||
beacontest.WithTestFromFs(Harnesses, "headers"),
|
||||
beacontest.WithTestFromFs(Harnesses, "attestation_rewards_phase0"),
|
||||
beacontest.WithTestFromFs(Harnesses, "committees"),
|
||||
beacontest.WithTestFromFs(Harnesses, "duties_attester"),
|
||||
beacontest.WithTestFromFs(Harnesses, "duties_proposer"),
|
||||
)...,
|
||||
)
|
||||
}
|
||||
func TestHarnessPhase0Finalized(t *testing.T) {
|
||||
beacontest.Execute(
|
||||
append(
|
||||
defaultHarnessOpts(harnessConfig{t: t, v: clparams.Phase0Version, finalized: true}),
|
||||
beacontest.WithTestFromFs(Harnesses, "liveness"),
|
||||
beacontest.WithTestFromFs(Harnesses, "duties_attester_f"),
|
||||
beacontest.WithTestFromFs(Harnesses, "committees_f"),
|
||||
)...,
|
||||
)
|
||||
}
|
||||
|
||||
func TestHarnessBellatrix(t *testing.T) {
|
||||
beacontest.Execute(
|
||||
append(
|
||||
defaultHarnessOpts(harnessConfig{t: t, v: clparams.BellatrixVersion, finalized: true}),
|
||||
beacontest.WithTestFromFs(Harnesses, "attestation_rewards_bellatrix"),
|
||||
beacontest.WithTestFromFs(Harnesses, "duties_sync_bellatrix"),
|
||||
)...,
|
||||
)
|
||||
}
|
||||
func TestHarnessForkChoice(t *testing.T) {
|
||||
beacontest.Execute(
|
||||
append(
|
||||
defaultHarnessOpts(harnessConfig{t: t, v: clparams.BellatrixVersion, forkmode: 1}),
|
||||
beacontest.WithTestFromFs(Harnesses, "fork_choice"),
|
||||
)...,
|
||||
)
|
||||
}
|
@ -9,14 +9,14 @@ import (
|
||||
"github.com/ledgerwatch/erigon/cl/persistence/beacon_indicies"
|
||||
)
|
||||
|
||||
func (a *ApiHandler) getHeaders(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getHeaders(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
querySlot, err := uint64FromQueryParams(r, "slot")
|
||||
querySlot, err := beaconhttp.Uint64FromQueryParams(r, "slot")
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
queryParentHash, err := hashFromQueryParams(r, "parent_root")
|
||||
queryParentHash, err := beaconhttp.HashFromQueryParams(r, "parent_root")
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -89,14 +89,14 @@ func (a *ApiHandler) getHeaders(w http.ResponseWriter, r *http.Request) (*beacon
|
||||
return newBeaconResponse(headers), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getHeader(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getHeader(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
blockId, err := blockIdFromRequest(r)
|
||||
blockId, err := beaconhttp.BlockIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -125,5 +125,5 @@ func (a *ApiHandler) getHeader(w http.ResponseWriter, r *http.Request) (*beaconR
|
||||
Root: root,
|
||||
Canonical: canonicalRoot == root,
|
||||
Header: signedHeader,
|
||||
}).withFinalized(canonicalRoot == root && signedHeader.Header.Slot <= a.forkchoiceStore.FinalizedSlot()).withVersion(version), nil
|
||||
}).WithFinalized(canonicalRoot == root && signedHeader.Header.Slot <= a.forkchoiceStore.FinalizedSlot()).WithVersion(version), nil
|
||||
}
|
||||
|
@ -1,180 +0,0 @@
|
||||
//go:build integration
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/common"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetHeader(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, _, handler, _, _, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
// Start by testing
|
||||
rootBlock1, err := blocks[0].Block.HashSSZ()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fcu.HeadVal, err = blocks[len(blocks)-1].Block.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
|
||||
bodyRoot1, err := blocks[0].Block.Body.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
bodyRoot2, err := blocks[len(blocks)-1].Block.Body.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
cases := []struct {
|
||||
blockID string
|
||||
code int
|
||||
slot uint64
|
||||
bodyRoot string
|
||||
}{
|
||||
{
|
||||
blockID: "0x" + common.Bytes2Hex(rootBlock1[:]),
|
||||
code: http.StatusOK,
|
||||
slot: blocks[0].Block.Slot,
|
||||
bodyRoot: "0x" + common.Bytes2Hex(bodyRoot1[:]),
|
||||
},
|
||||
{
|
||||
blockID: "head",
|
||||
code: http.StatusOK,
|
||||
slot: blocks[len(blocks)-1].Block.Slot,
|
||||
bodyRoot: "0x" + common.Bytes2Hex(bodyRoot2[:]),
|
||||
},
|
||||
{
|
||||
blockID: "0x" + common.Bytes2Hex(make([]byte, 32)),
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.blockID, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// Query the block in the handler with /eth/v2/beacon/blocks/{block_id}
|
||||
resp, err := http.Get(server.URL + "/eth/v1/beacon/headers/" + c.blockID)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
jsonVal := make(map[string]interface{})
|
||||
// unmarshal the json
|
||||
require.NoError(t, json.NewDecoder(resp.Body).Decode(&jsonVal))
|
||||
data := jsonVal["data"].(map[string]interface{})
|
||||
header := data["header"].(map[string]interface{})
|
||||
message := header["message"].(map[string]interface{})
|
||||
|
||||
// compare the block
|
||||
require.Equal(t, message["slot"], strconv.FormatInt(int64(c.slot), 10))
|
||||
require.Equal(t, message["body_root"], c.bodyRoot)
|
||||
require.Equal(t, data["canonical"], true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHeaders(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, _, handler, _, _, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
var err error
|
||||
|
||||
fcu.HeadVal, err = blocks[len(blocks)-1].Block.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
|
||||
bodyRoot1, err := blocks[0].Block.Body.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
bodyRoot2, err := blocks[len(blocks)-1].Block.Body.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
code int
|
||||
slotReq *uint64
|
||||
parentRoot *libcommon.Hash
|
||||
slot uint64
|
||||
bodyRoot string
|
||||
count int
|
||||
}{
|
||||
{
|
||||
count: 1,
|
||||
name: "slot",
|
||||
code: http.StatusOK,
|
||||
slotReq: &blocks[0].Block.Slot,
|
||||
slot: blocks[0].Block.Slot,
|
||||
bodyRoot: "0x" + common.Bytes2Hex(bodyRoot1[:]),
|
||||
},
|
||||
{
|
||||
count: 0,
|
||||
name: "none",
|
||||
code: http.StatusOK,
|
||||
slot: blocks[len(blocks)-1].Block.Slot,
|
||||
bodyRoot: "0x" + common.Bytes2Hex(bodyRoot2[:]),
|
||||
},
|
||||
{
|
||||
count: 0,
|
||||
name: "parent",
|
||||
code: http.StatusOK,
|
||||
slotReq: &blocks[0].Block.Slot,
|
||||
slot: blocks[0].Block.Slot,
|
||||
parentRoot: &blocks[0].Block.ParentRoot,
|
||||
bodyRoot: "0x" + common.Bytes2Hex(bodyRoot1[:]),
|
||||
},
|
||||
{
|
||||
count: 0,
|
||||
name: "wtf",
|
||||
code: http.StatusOK,
|
||||
slotReq: new(uint64),
|
||||
slot: blocks[0].Block.Slot,
|
||||
parentRoot: &blocks[0].Block.ParentRoot,
|
||||
bodyRoot: "0x" + common.Bytes2Hex(bodyRoot1[:]),
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
url := server.URL + "/eth/v1/beacon/headers?lol=0" // lol is a random query param
|
||||
|
||||
if c.slotReq != nil {
|
||||
url += "&slot=" + strconv.FormatInt(int64(*c.slotReq), 10)
|
||||
}
|
||||
if c.parentRoot != nil {
|
||||
url += "&parent_root=" + "0x" + common.Bytes2Hex(c.parentRoot[:])
|
||||
}
|
||||
// Query the block in the handler with /eth/v2/beacon/blocks/{block_id}
|
||||
resp, err := http.Get(url)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
jsonVal := make(map[string]interface{})
|
||||
// unmarshal the json
|
||||
require.NoError(t, json.NewDecoder(resp.Body).Decode(&jsonVal))
|
||||
data := jsonVal["data"].([]interface{})
|
||||
require.Equal(t, len(data), c.count)
|
||||
})
|
||||
}
|
||||
}
|
@ -20,8 +20,8 @@ type live struct {
|
||||
IsLive bool `json:"is_live"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) liveness(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
epoch, err := epochFromRequest(r)
|
||||
func (a *ApiHandler) liveness(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
epoch, err := beaconhttp.EpochFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLiveness(t *testing.T) {
|
||||
// i just want the correct schema to be generated
|
||||
_, blocks, _, _, _, handler, _, _, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
fcu.FinalizedSlotVal = math.MaxUint64
|
||||
reqBody := `["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]`
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
//
|
||||
body := bytes.Buffer{}
|
||||
body.WriteString(reqBody)
|
||||
// Query the block in the handler with /eth/v2/beacon/states/{block_id} with content-type octet-stream
|
||||
req, err := http.NewRequest("POST", server.URL+"/eth/v1/validator/liveness/"+strconv.FormatUint(fcu.HeadSlotVal/32, 10), &body)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
out := map[string]interface{}{}
|
||||
require.NoError(t, json.NewDecoder(resp.Body).Decode(&out))
|
||||
data := out["data"].([]interface{})
|
||||
require.Equal(t, 11, len(data))
|
||||
// check that is has is_live (bool) and index (stringifed int)
|
||||
for _, d := range data {
|
||||
d := d.(map[string]interface{})
|
||||
require.Equal(t, 2, len(d))
|
||||
isLive, ok := d["is_live"]
|
||||
require.True(t, ok)
|
||||
_, ok = isLive.(bool)
|
||||
require.True(t, ok)
|
||||
i1, ok := d["index"]
|
||||
require.True(t, ok)
|
||||
strIndex, ok := i1.(string)
|
||||
require.True(t, ok)
|
||||
_, err := strconv.ParseUint(strIndex, 10, 64)
|
||||
require.NoError(t, err)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -5,10 +5,12 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/beaconhttp"
|
||||
)
|
||||
|
||||
func (a *ApiHandler) GetEthV1NodeHealth(w http.ResponseWriter, r *http.Request) {
|
||||
syncingStatus, err := uint64FromQueryParams(r, "syncing_status")
|
||||
syncingStatus, err := beaconhttp.Uint64FromQueryParams(r, "syncing_status")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
@ -1,71 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNodeHealthSyncing(t *testing.T) {
|
||||
// i just want the correct schema to be generated
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
// Call GET /eth/v1/node/health
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
req, err := http.NewRequest("GET", server.URL+"/eth/v1/node/health?syncing_status=666", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, 666, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestNodeHealthSyncingTip(t *testing.T) {
|
||||
// i just want the correct schema to be generated
|
||||
_, _, _, _, post, handler, _, sm, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
// Call GET /eth/v1/node/health
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
req, err := http.NewRequest("GET", server.URL+"/eth/v1/node/health?syncing_status=666", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, sm.OnHeadState(post))
|
||||
s, cancel := sm.HeadState()
|
||||
s.SetSlot(999999999999999)
|
||||
cancel()
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestNodeVersion(t *testing.T) {
|
||||
// i just want the correct schema to be generated
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
// Call GET /eth/v1/node/health
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
|
||||
req, err := http.NewRequest("GET", server.URL+"/eth/v1/node/version", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
out := map[string]interface{}{}
|
||||
require.NoError(t, json.NewDecoder(resp.Body).Decode(&out))
|
||||
v := out["data"].(map[string]interface{})["version"].(string)
|
||||
require.True(t, strings.Contains(v, "Caplin"))
|
||||
}
|
@ -11,29 +11,29 @@ import (
|
||||
"github.com/ledgerwatch/erigon/cl/gossip"
|
||||
)
|
||||
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolVoluntaryExits(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolVoluntaryExits(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
return newBeaconResponse(a.operationsPool.VoluntaryExistsPool.Raw()), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolAttesterSlashings(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolAttesterSlashings(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
fmt.Println("GetEthV1BeaconPoolAttesterSlashings", a.operationsPool.AttesterSlashingsPool.Raw())
|
||||
return newBeaconResponse(a.operationsPool.AttesterSlashingsPool.Raw()), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolProposerSlashings(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolProposerSlashings(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
return newBeaconResponse(a.operationsPool.ProposerSlashingsPool.Raw()), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolBLSExecutionChanges(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolBLSExecutionChanges(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
return newBeaconResponse(a.operationsPool.BLSToExecutionChangesPool.Raw()), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolAttestations(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
slot, err := uint64FromQueryParams(r, "slot")
|
||||
func (a *ApiHandler) GetEthV1BeaconPoolAttestations(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
slot, err := beaconhttp.Uint64FromQueryParams(r, "slot")
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
committeeIndex, err := uint64FromQueryParams(r, "committee_index")
|
||||
committeeIndex, err := beaconhttp.Uint64FromQueryParams(r, "committee_index")
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
@ -1,248 +0,0 @@
|
||||
//go:build integration
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPoolAttesterSlashings(t *testing.T) {
|
||||
attesterSlashing := &cltypes.AttesterSlashing{
|
||||
Attestation_1: &cltypes.IndexedAttestation{
|
||||
AttestingIndices: solid.NewRawUint64List(2048, []uint64{2, 3, 4, 5, 6}),
|
||||
Data: solid.NewAttestationData(),
|
||||
},
|
||||
Attestation_2: &cltypes.IndexedAttestation{
|
||||
AttestingIndices: solid.NewRawUint64List(2048, []uint64{2, 3, 4, 1, 6}),
|
||||
Data: solid.NewAttestationData(),
|
||||
},
|
||||
}
|
||||
// find server
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// json
|
||||
req, err := json.Marshal(attesterSlashing)
|
||||
require.NoError(t, err)
|
||||
// post attester slashing
|
||||
resp, err := server.Client().Post(server.URL+"/eth/v1/beacon/pool/attester_slashings", "application/json", bytes.NewBuffer(req))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
// get attester slashings
|
||||
resp, err = server.Client().Get(server.URL + "/eth/v1/beacon/pool/attester_slashings")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
out := struct {
|
||||
Data []*cltypes.AttesterSlashing `json:"data"`
|
||||
}{
|
||||
Data: []*cltypes.AttesterSlashing{
|
||||
cltypes.NewAttesterSlashing(),
|
||||
},
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(out.Data))
|
||||
require.Equal(t, attesterSlashing, out.Data[0])
|
||||
}
|
||||
|
||||
func TestPoolProposerSlashings(t *testing.T) {
|
||||
proposerSlashing := &cltypes.ProposerSlashing{
|
||||
Header1: &cltypes.SignedBeaconBlockHeader{
|
||||
Header: &cltypes.BeaconBlockHeader{
|
||||
Slot: 1,
|
||||
ProposerIndex: 3,
|
||||
},
|
||||
},
|
||||
Header2: &cltypes.SignedBeaconBlockHeader{
|
||||
Header: &cltypes.BeaconBlockHeader{
|
||||
Slot: 2,
|
||||
ProposerIndex: 4,
|
||||
},
|
||||
},
|
||||
}
|
||||
// find server
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// json
|
||||
req, err := json.Marshal(proposerSlashing)
|
||||
require.NoError(t, err)
|
||||
|
||||
// post attester slashing
|
||||
resp, err := server.Client().Post(server.URL+"/eth/v1/beacon/pool/proposer_slashings", "application/json", bytes.NewBuffer(req))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
// get attester slashings
|
||||
resp, err = server.Client().Get(server.URL + "/eth/v1/beacon/pool/proposer_slashings")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
out := struct {
|
||||
Data []*cltypes.ProposerSlashing `json:"data"`
|
||||
}{
|
||||
Data: []*cltypes.ProposerSlashing{},
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(out.Data))
|
||||
require.Equal(t, proposerSlashing, out.Data[0])
|
||||
}
|
||||
|
||||
func TestPoolVoluntaryExits(t *testing.T) {
|
||||
voluntaryExit := &cltypes.SignedVoluntaryExit{
|
||||
VoluntaryExit: &cltypes.VoluntaryExit{
|
||||
Epoch: 1,
|
||||
ValidatorIndex: 3,
|
||||
},
|
||||
}
|
||||
// find server
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// json
|
||||
req, err := json.Marshal(voluntaryExit)
|
||||
require.NoError(t, err)
|
||||
// post attester slashing
|
||||
resp, err := server.Client().Post(server.URL+"/eth/v1/beacon/pool/voluntary_exits", "application/json", bytes.NewBuffer(req))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
// get attester slashings
|
||||
resp, err = server.Client().Get(server.URL + "/eth/v1/beacon/pool/voluntary_exits")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
out := struct {
|
||||
Data []*cltypes.SignedVoluntaryExit `json:"data"`
|
||||
}{
|
||||
Data: []*cltypes.SignedVoluntaryExit{},
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(out.Data))
|
||||
require.Equal(t, voluntaryExit, out.Data[0])
|
||||
}
|
||||
|
||||
func TestPoolBlsToExecutionChainges(t *testing.T) {
|
||||
msg := []*cltypes.SignedBLSToExecutionChange{
|
||||
{
|
||||
Message: &cltypes.BLSToExecutionChange{
|
||||
ValidatorIndex: 45,
|
||||
},
|
||||
Signature: libcommon.Bytes96{2},
|
||||
},
|
||||
{
|
||||
Message: &cltypes.BLSToExecutionChange{
|
||||
ValidatorIndex: 46,
|
||||
},
|
||||
},
|
||||
}
|
||||
// find server
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// json
|
||||
req, err := json.Marshal(msg)
|
||||
require.NoError(t, err)
|
||||
// post attester slashing
|
||||
resp, err := server.Client().Post(server.URL+"/eth/v1/beacon/pool/bls_to_execution_changes", "application/json", bytes.NewBuffer(req))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
// get attester slashings
|
||||
resp, err = server.Client().Get(server.URL + "/eth/v1/beacon/pool/bls_to_execution_changes")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
out := struct {
|
||||
Data []*cltypes.SignedBLSToExecutionChange `json:"data"`
|
||||
}{
|
||||
Data: []*cltypes.SignedBLSToExecutionChange{},
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 2, len(out.Data))
|
||||
require.Equal(t, msg[0], out.Data[0])
|
||||
require.Equal(t, msg[1], out.Data[1])
|
||||
}
|
||||
|
||||
func TestPoolAggregatesAndProofs(t *testing.T) {
|
||||
msg := []*cltypes.SignedAggregateAndProof{
|
||||
{
|
||||
Message: &cltypes.AggregateAndProof{
|
||||
Aggregate: solid.NewAttestionFromParameters([]byte{1, 2}, solid.NewAttestationData(), libcommon.Bytes96{3, 45, 6}),
|
||||
},
|
||||
Signature: libcommon.Bytes96{2},
|
||||
},
|
||||
{
|
||||
Message: &cltypes.AggregateAndProof{
|
||||
Aggregate: solid.NewAttestionFromParameters([]byte{1, 2, 5, 6}, solid.NewAttestationData(), libcommon.Bytes96{3, 0, 6}),
|
||||
},
|
||||
Signature: libcommon.Bytes96{2, 3, 5},
|
||||
},
|
||||
}
|
||||
// find server
|
||||
_, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// json
|
||||
req, err := json.Marshal(msg)
|
||||
require.NoError(t, err)
|
||||
// post attester slashing
|
||||
resp, err := server.Client().Post(server.URL+"/eth/v1/validator/aggregate_and_proofs", "application/json", bytes.NewBuffer(req))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
// get attester slashings
|
||||
resp, err = server.Client().Get(server.URL + "/eth/v1/beacon/pool/attestations")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
out := struct {
|
||||
Data []*solid.Attestation `json:"data"`
|
||||
}{
|
||||
Data: []*solid.Attestation{},
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 2, len(out.Data))
|
||||
require.Equal(t, msg[0].Message.Aggregate, out.Data[0])
|
||||
require.Equal(t, msg[1].Message.Aggregate, out.Data[1])
|
||||
}
|
@ -23,7 +23,7 @@ type blockRewardsResponse struct {
|
||||
Total uint64 `json:"total,string"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getBlockRewards(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getBlockRewards(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
if err != nil {
|
||||
@ -31,7 +31,7 @@ func (a *ApiHandler) getBlockRewards(w http.ResponseWriter, r *http.Request) (*b
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := blockIdFromRequest(r)
|
||||
blockId, err := beaconhttp.BlockIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -61,7 +61,7 @@ func (a *ApiHandler) getBlockRewards(w http.ResponseWriter, r *http.Request) (*b
|
||||
AttesterSlashings: blkRewards.AttesterSlashings,
|
||||
SyncAggregate: blkRewards.SyncAggregate,
|
||||
Total: blkRewards.Attestations + blkRewards.ProposerSlashings + blkRewards.AttesterSlashings + blkRewards.SyncAggregate,
|
||||
}).withFinalized(isFinalized), nil
|
||||
}).WithFinalized(isFinalized), nil
|
||||
}
|
||||
slotData, err := state_accessors.ReadSlotData(tx, slot)
|
||||
if err != nil {
|
||||
@ -77,7 +77,7 @@ func (a *ApiHandler) getBlockRewards(w http.ResponseWriter, r *http.Request) (*b
|
||||
AttesterSlashings: slotData.AttesterSlashings,
|
||||
SyncAggregate: slotData.SyncAggregateRewards,
|
||||
Total: slotData.AttestationsRewards + slotData.ProposerSlashings + slotData.AttesterSlashings + slotData.SyncAggregateRewards,
|
||||
}).withFinalized(isFinalized), nil
|
||||
}).WithFinalized(isFinalized), nil
|
||||
}
|
||||
|
||||
type syncCommitteeReward struct {
|
||||
@ -85,7 +85,7 @@ type syncCommitteeReward struct {
|
||||
Reward int64 `json:"reward,string"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getSyncCommitteesRewards(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getSyncCommitteesRewards(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -111,7 +111,7 @@ func (a *ApiHandler) getSyncCommitteesRewards(w http.ResponseWriter, r *http.Req
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blockId, err := blockIdFromRequest(r)
|
||||
blockId, err := beaconhttp.BlockIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -220,7 +220,7 @@ func (a *ApiHandler) getSyncCommitteesRewards(w http.ResponseWriter, r *http.Req
|
||||
sort.Slice(rewards, func(i, j int) bool {
|
||||
return rewards[i].ValidatorIndex < rewards[j].ValidatorIndex
|
||||
})
|
||||
return newBeaconResponse(rewards).withFinalized(isFinalized), nil
|
||||
return newBeaconResponse(rewards).WithFinalized(isFinalized), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) syncPartecipantReward(activeBalance uint64) uint64 {
|
||||
|
File diff suppressed because one or more lines are too long
@ -17,21 +17,21 @@ import (
|
||||
"github.com/ledgerwatch/erigon/cl/utils"
|
||||
)
|
||||
|
||||
func (a *ApiHandler) blockRootFromStateId(ctx context.Context, tx kv.Tx, stateId *segmentID) (root libcommon.Hash, httpStatusErr int, err error) {
|
||||
func (a *ApiHandler) blockRootFromStateId(ctx context.Context, tx kv.Tx, stateId *beaconhttp.SegmentID) (root libcommon.Hash, httpStatusErr int, err error) {
|
||||
switch {
|
||||
case stateId.head():
|
||||
case stateId.Head():
|
||||
root, _, err = a.forkchoiceStore.GetHead()
|
||||
if err != nil {
|
||||
return libcommon.Hash{}, http.StatusInternalServerError, err
|
||||
}
|
||||
return
|
||||
case stateId.finalized():
|
||||
case stateId.Finalized():
|
||||
root = a.forkchoiceStore.FinalizedCheckpoint().BlockRoot()
|
||||
return
|
||||
case stateId.justified():
|
||||
case stateId.Justified():
|
||||
root = a.forkchoiceStore.JustifiedCheckpoint().BlockRoot()
|
||||
return
|
||||
case stateId.genesis():
|
||||
case stateId.Genesis():
|
||||
root, err = beacon_indicies.ReadCanonicalBlockRoot(tx, 0)
|
||||
if err != nil {
|
||||
return libcommon.Hash{}, http.StatusInternalServerError, err
|
||||
@ -40,17 +40,17 @@ func (a *ApiHandler) blockRootFromStateId(ctx context.Context, tx kv.Tx, stateId
|
||||
return libcommon.Hash{}, http.StatusNotFound, fmt.Errorf("genesis block not found")
|
||||
}
|
||||
return
|
||||
case stateId.getSlot() != nil:
|
||||
root, err = beacon_indicies.ReadCanonicalBlockRoot(tx, *stateId.getSlot())
|
||||
case stateId.GetSlot() != nil:
|
||||
root, err = beacon_indicies.ReadCanonicalBlockRoot(tx, *stateId.GetSlot())
|
||||
if err != nil {
|
||||
return libcommon.Hash{}, http.StatusInternalServerError, err
|
||||
}
|
||||
if root == (libcommon.Hash{}) {
|
||||
return libcommon.Hash{}, http.StatusNotFound, fmt.Errorf("block not found %d", *stateId.getSlot())
|
||||
return libcommon.Hash{}, http.StatusNotFound, fmt.Errorf("block not found %d", *stateId.GetSlot())
|
||||
}
|
||||
return
|
||||
case stateId.getRoot() != nil:
|
||||
root, err = beacon_indicies.ReadBlockRootByStateRoot(tx, *stateId.getRoot())
|
||||
case stateId.GetRoot() != nil:
|
||||
root, err = beacon_indicies.ReadBlockRootByStateRoot(tx, *stateId.GetRoot())
|
||||
if err != nil {
|
||||
return libcommon.Hash{}, http.StatusInternalServerError, err
|
||||
}
|
||||
@ -71,7 +71,7 @@ func previousVersion(v clparams.StateVersion) clparams.StateVersion {
|
||||
return v - 1
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getStateFork(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getStateFork(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -80,7 +80,7 @@ func (a *ApiHandler) getStateFork(w http.ResponseWriter, r *http.Request) (*beac
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -110,7 +110,7 @@ func (a *ApiHandler) getStateFork(w http.ResponseWriter, r *http.Request) (*beac
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getStateRoot(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getStateRoot(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -119,7 +119,7 @@ func (a *ApiHandler) getStateRoot(w http.ResponseWriter, r *http.Request) (*beac
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -149,10 +149,10 @@ func (a *ApiHandler) getStateRoot(w http.ResponseWriter, r *http.Request) (*beac
|
||||
}
|
||||
|
||||
return newBeaconResponse(&rootResponse{Root: stateRoot}).
|
||||
withFinalized(canonicalRoot == root && *slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
WithFinalized(canonicalRoot == root && *slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getFullState(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getFullState(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -161,7 +161,7 @@ func (a *ApiHandler) getFullState(w http.ResponseWriter, r *http.Request) (*beac
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -198,10 +198,10 @@ func (a *ApiHandler) getFullState(w http.ResponseWriter, r *http.Request) (*beac
|
||||
if state == nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Sprintf("could not read state: %x", blockRoot))
|
||||
}
|
||||
return newBeaconResponse(state).withFinalized(true).withVersion(state.Version()), nil
|
||||
return newBeaconResponse(state).WithFinalized(true).WithVersion(state.Version()), nil
|
||||
}
|
||||
|
||||
return newBeaconResponse(state).withFinalized(false).withVersion(state.Version()), nil
|
||||
return newBeaconResponse(state).WithFinalized(false).WithVersion(state.Version()), nil
|
||||
}
|
||||
|
||||
type finalityCheckpointsResponse struct {
|
||||
@ -210,7 +210,7 @@ type finalityCheckpointsResponse struct {
|
||||
PreviousJustifiedCheckpoint solid.Checkpoint `json:"previous_justified_checkpoint"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getFinalityCheckpoints(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getFinalityCheckpoints(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -218,7 +218,7 @@ func (a *ApiHandler) getFinalityCheckpoints(w http.ResponseWriter, r *http.Reque
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -259,7 +259,7 @@ func (a *ApiHandler) getFinalityCheckpoints(w http.ResponseWriter, r *http.Reque
|
||||
FinalizedCheckpoint: finalizedCheckpoint,
|
||||
CurrentJustifiedCheckpoint: currentJustifiedCheckpoint,
|
||||
PreviousJustifiedCheckpoint: previousJustifiedCheckpoint,
|
||||
}).withFinalized(canonicalRoot == blockRoot && *slot <= a.forkchoiceStore.FinalizedSlot()).withVersion(version), nil
|
||||
}).WithFinalized(canonicalRoot == blockRoot && *slot <= a.forkchoiceStore.FinalizedSlot()).WithVersion(version), nil
|
||||
}
|
||||
|
||||
type syncCommitteesResponse struct {
|
||||
@ -267,7 +267,7 @@ type syncCommitteesResponse struct {
|
||||
ValidatorAggregates [][]string `json:"validator_aggregates"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getSyncCommittees(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getSyncCommittees(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -275,7 +275,7 @@ func (a *ApiHandler) getSyncCommittees(w http.ResponseWriter, r *http.Request) (
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -312,7 +312,7 @@ func (a *ApiHandler) getSyncCommittees(w http.ResponseWriter, r *http.Request) (
|
||||
}
|
||||
// Now fetch the data we need
|
||||
statePeriod := a.beaconChainCfg.SyncCommitteePeriod(*slot)
|
||||
queryEpoch, err := uint64FromQueryParams(r, "epoch")
|
||||
queryEpoch, err := beaconhttp.Uint64FromQueryParams(r, "epoch")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -355,14 +355,14 @@ func (a *ApiHandler) getSyncCommittees(w http.ResponseWriter, r *http.Request) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newBeaconResponse(response).withFinalized(canonicalRoot == blockRoot && *slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
return newBeaconResponse(response).WithFinalized(canonicalRoot == blockRoot && *slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
}
|
||||
|
||||
type randaoResponse struct {
|
||||
Randao libcommon.Hash `json:"randao"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getRandao(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getRandao(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -370,7 +370,7 @@ func (a *ApiHandler) getRandao(w http.ResponseWriter, r *http.Request) (*beaconR
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -380,7 +380,7 @@ func (a *ApiHandler) getRandao(w http.ResponseWriter, r *http.Request) (*beaconR
|
||||
return nil, beaconhttp.NewEndpointError(httpStatus, err.Error())
|
||||
}
|
||||
|
||||
epochReq, err := uint64FromQueryParams(r, "epoch")
|
||||
epochReq, err := beaconhttp.Uint64FromQueryParams(r, "epoch")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -401,7 +401,7 @@ func (a *ApiHandler) getRandao(w http.ResponseWriter, r *http.Request) (*beaconR
|
||||
|
||||
if a.forkchoiceStore.RandaoMixes(blockRoot, randaoMixes) {
|
||||
mix := randaoMixes.Get(int(epoch % a.beaconChainCfg.EpochsPerHistoricalVector))
|
||||
return newBeaconResponse(randaoResponse{Randao: mix}).withFinalized(slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
return newBeaconResponse(randaoResponse{Randao: mix}).WithFinalized(slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
}
|
||||
// check if the block is canonical
|
||||
canonicalRoot, err := beacon_indicies.ReadCanonicalBlockRoot(tx, slot)
|
||||
@ -415,5 +415,5 @@ func (a *ApiHandler) getRandao(w http.ResponseWriter, r *http.Request) (*beaconR
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newBeaconResponse(randaoResponse{Randao: mix}).withFinalized(slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
return newBeaconResponse(randaoResponse{Randao: mix}).WithFinalized(slot <= a.forkchoiceStore.FinalizedSlot()), nil
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
1
cl/beacon/handler/test_data/attestations_1.json
Normal file
1
cl/beacon/handler/test_data/attestations_1.json
Normal file
File diff suppressed because one or more lines are too long
1
cl/beacon/handler/test_data/attestations_2.json
Normal file
1
cl/beacon/handler/test_data/attestations_2.json
Normal file
@ -0,0 +1 @@
|
||||
{"data":{"ideal_rewards":[{"effective_balance":"32000000000","head":"0","target":"290680","source":"0","inclusion_delay":"0","inactivity":"0"},{"effective_balance":"32000000000","head":"0","target":"290680","source":"0","inclusion_delay":"0","inactivity":"0"}],"total_rewards":[{"validator_index":"1","head":"0","target":"290680","source":"-156520","inclusion_delay":"0","inactivity":"0"},{"validator_index":"4","head":"0","target":"290680","source":"-156520","inclusion_delay":"0","inactivity":"0"}]}}
|
1
cl/beacon/handler/test_data/attestations_3.json
Normal file
1
cl/beacon/handler/test_data/attestations_3.json
Normal file
File diff suppressed because one or more lines are too long
1
cl/beacon/handler/test_data/attestations_4.json
Normal file
1
cl/beacon/handler/test_data/attestations_4.json
Normal file
@ -0,0 +1 @@
|
||||
{"data":{"ideal_rewards":[{"effective_balance":"20000000000","head":"0","target":"0","source":"0","inclusion_delay":"0","inactivity":"0"},{"effective_balance":"17000000000","head":"57360","target":"57360","source":"57360","inclusion_delay":"14217","inactivity":"0"}],"total_rewards":[{"validator_index":"1","head":"0","target":"0","source":"0","inclusion_delay":"0","inactivity":"0"},{"validator_index":"4","head":"57360","target":"57360","source":"57360","inclusion_delay":"14217","inactivity":"0"}]}}
|
1975
cl/beacon/handler/test_data/blinded_block_1.json
Normal file
1975
cl/beacon/handler/test_data/blinded_block_1.json
Normal file
File diff suppressed because it is too large
Load Diff
1974
cl/beacon/handler/test_data/block_1.json
Normal file
1974
cl/beacon/handler/test_data/block_1.json
Normal file
File diff suppressed because it is too large
Load Diff
6
cl/beacon/handler/test_data/committees_1.yaml
Normal file
6
cl/beacon/handler/test_data/committees_1.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
- {"data":[{"index":"0","slot":"8322","validators":["0","104","491","501","379","318","275","504","75","280","105","399","35","401"]}],"execution_optimistic":false,"finalized":true}
|
||||
- {"data":[],"finalized":true,"execution_optimistic":false}
|
||||
- {"data":[{"index":"0","slot":"8290","validators":["127","377","274","85","309","420","423","398","153","480","273","429","374","260"]}],"execution_optimistic":false,"finalized":true}
|
||||
- {"data":[{"index":"0","slot":"8322","validators":["0","104","491","501","379","318","275","504","75","280","105","399","35","401"]}],"finalized":false,"execution_optimistic":false}
|
||||
- {"data":[],"finalized":false,"execution_optimistic":false}
|
||||
- {"data":[{"index":"0","slot":"8290","validators":["127","377","274","85","309","420","423","398","153","480","273","429","374","260"]}],"finalized":false,"execution_optimistic":false}
|
2
cl/beacon/handler/test_data/duties_1.yaml
Normal file
2
cl/beacon/handler/test_data/duties_1.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
- {"data":[{"pubkey":"0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb","validator_index":"0","committee_index":"0","committee_length":"14","validator_committee_index":"0","committees_at_slot":"1","slot":"8322"},{"pubkey":"0xb0e7791fb972fe014159aa33a98622da3cdc98ff707965e536d8636b5fcc5ac7a91a8c46e59a00dca575af0f18fb13dc","validator_index":"4","committee_index":"0","committee_length":"13","validator_committee_index":"5","committees_at_slot":"1","slot":"8327"},{"pubkey":"0xb928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb7","validator_index":"6","committee_index":"0","committee_length":"13","validator_committee_index":"10","committees_at_slot":"1","slot":"8327"},{"pubkey":"0xa6e82f6da4520f85c5d27d8f329eccfa05944fd1096b20734c894966d12a9e2a9a9744529d7212d33883113a0cadb909","validator_index":"5","committee_index":"0","committee_length":"14","validator_committee_index":"10","committees_at_slot":"1","slot":"8329"},{"pubkey":"0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224","validator_index":"2","committee_index":"0","committee_length":"14","validator_committee_index":"11","committees_at_slot":"1","slot":"8331"},{"pubkey":"0xaf81da25ecf1c84b577fefbedd61077a81dc43b00304015b2b596ab67f00e41c86bb00ebd0f90d4b125eb0539891aeed","validator_index":"9","committee_index":"0","committee_length":"14","validator_committee_index":"8","committees_at_slot":"1","slot":"8342"},{"pubkey":"0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60","validator_index":"3","committee_index":"0","committee_length":"13","validator_committee_index":"6","committees_at_slot":"1","slot":"8348"}],"execution_optimistic":false}
|
||||
- {"data":[],"execution_optimistic":false}
|
2
cl/beacon/handler/test_data/duties_sync_1.yaml
Normal file
2
cl/beacon/handler/test_data/duties_sync_1.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
- {"data":[{"pubkey":"0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb","validator_index":"0","validator_sync_committee_indicies":["30","286"]},{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","validator_index":"1","validator_sync_committee_indicies":["120","376"]},{"pubkey":"0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224","validator_index":"2","validator_sync_committee_indicies":["138","394"]},{"pubkey":"0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60","validator_index":"3","validator_sync_committee_indicies":["10","266"]},{"pubkey":"0xb0e7791fb972fe014159aa33a98622da3cdc98ff707965e536d8636b5fcc5ac7a91a8c46e59a00dca575af0f18fb13dc","validator_index":"4","validator_sync_committee_indicies":["114","370"]},{"pubkey":"0xa6e82f6da4520f85c5d27d8f329eccfa05944fd1096b20734c894966d12a9e2a9a9744529d7212d33883113a0cadb909","validator_index":"5","validator_sync_committee_indicies":["103","359"]},{"pubkey":"0xb928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb7","validator_index":"6","validator_sync_committee_indicies":["163","419"]},{"pubkey":"0xa85ae765588126f5e860d019c0e26235f567a9c0c0b2d8ff30f3e8d436b1082596e5e7462d20f5be3764fd473e57f9cf","validator_index":"7","validator_sync_committee_indicies":["197","453"]},{"pubkey":"0x99cdf3807146e68e041314ca93e1fee0991224ec2a74beb2866816fd0826ce7b6263ee31e953a86d1b72cc2215a57793","validator_index":"8","validator_sync_committee_indicies":["175","431"]},{"pubkey":"0xaf81da25ecf1c84b577fefbedd61077a81dc43b00304015b2b596ab67f00e41c86bb00ebd0f90d4b125eb0539891aeed","validator_index":"9","validator_sync_committee_indicies":["53","309"]}],"execution_optimistic":false}
|
||||
- {"data":[],"execution_optimistic":false}
|
2
cl/beacon/handler/test_data/forkchoice_1.yaml
Normal file
2
cl/beacon/handler/test_data/forkchoice_1.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
- {"data":[{"execution_optimistic":false,"root":"0x0102030000000000000000000000000000000000000000000000000000000000","slot":128}]}
|
||||
- {"finalized_checkpoint":{"epoch":"1","root":"0x0102030000000000000000000000000000000000000000000000000000000000"},"fork_choice_nodes":[{"slot":"128","block_root":"0x0102030000000000000000000000000000000000000000000000000000000000","parent_root":"0x0102030000000000000000000000000000000000000000000000000000000000","justified_epoch":"0","finalized_epoch":"0","weight":"1","validity":"","execution_block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000"},{"slot":"128","block_root":"0x0102020405030000000000000000000000000000000000000000000000000000","parent_root":"0x0102050000000000000000000000000000000000000000000000000000000000","justified_epoch":"0","finalized_epoch":"0","weight":"2","validity":"","execution_block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000"}],"justified_checkpoint":{"epoch":"2","root":"0x0102030000000000000000000000000000000000000000000000000000000000"}}
|
3
cl/beacon/handler/test_data/rewards_1.yaml
Normal file
3
cl/beacon/handler/test_data/rewards_1.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
- {"data":{"proposer_index":"203","attestations":"332205","proposer_slashings":"0","attester_slashings":"0","sync_aggregate":"0","total":"332205"},"finalized":true,"execution_optimistic":false}
|
||||
- {"data":{"proposer_index":"98","attestations":"332205","proposer_slashings":"0","attester_slashings":"0","sync_aggregate":"0","total":"332205"},"finalized":true,"execution_optimistic":false}
|
||||
- {"data":[{"validator_index":"1","reward":"-698"},{"validator_index":"4","reward":"-698"}],"execution_optimistic":false,"finalized":true}
|
1
cl/beacon/handler/test_data/rewards_2.json
Normal file
1
cl/beacon/handler/test_data/rewards_2.json
Normal file
File diff suppressed because one or more lines are too long
2
cl/beacon/handler/test_data/states_1.yaml
Normal file
2
cl/beacon/handler/test_data/states_1.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
finality_checkpoint: {"data":{"finalized_checkpoint":{"epoch":"1","root":"0xde46b0f2ed5e72f0cec20246403b14c963ec995d7c2825f3532b0460c09d5693"},"current_justified_checkpoint":{"epoch":"3","root":"0xa6e47f164b1a3ca30ea3b2144bd14711de442f51e5b634750a12a1734e24c987"},"previous_justified_checkpoint":{"epoch":"2","root":"0x4c3ee7969e485696669498a88c17f70e6999c40603e2f4338869004392069063"}},"finalized":false,"version":2,"execution_optimistic":false}
|
||||
randao: {"data":{"randao":"0xdeec617717272914bfd73e02ca1da113a83cf4cf33cd4939486509e2da4ccf4e"},"finalized":false,"execution_optimistic":false}
|
1
cl/beacon/handler/test_data/sync_committees_1.json
Normal file
1
cl/beacon/handler/test_data/sync_committees_1.json
Normal file
File diff suppressed because one or more lines are too long
9
cl/beacon/handler/test_data/validators_1.yaml
Normal file
9
cl/beacon/handler/test_data/validators_1.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
- {"data":[{"index":"1","status":"withdrawal_possible","balance":"20125000000","validator":{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","withdrawal_credentials":"0x001f09ed305c0767d56f1b3bdb25f301298027f8e98a8e0cd2dcbcc660723d7b","effective_balance":"20000000000","slashed":false,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"253","withdrawable_epoch":"257"}},{"index":"2","status":"active_slashed","balance":"25678253779","validator":{"pubkey":"0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224","withdrawal_credentials":"0x006adc4a1e4caba37c54d56d2411fd0df3a102f8489a4c1be535f4fd5f8810c9","effective_balance":"25000000000","slashed":true,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"261","withdrawable_epoch":"8448"}},{"index":"3","status":"active_slashed","balance":"35998164834","validator":{"pubkey":"0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60","withdrawal_credentials":"0x0081c852078a2ad430d438d7eaefc39646f53895292596bbe199e2d7d1884ab8","effective_balance":"32000000000","slashed":true,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"261","withdrawable_epoch":"8448"}}],"finalized":true,"execution_optimistic":false}
|
||||
- {"data":[{"index":"2","status":"active_slashed","balance":"25678253779","validator":{"pubkey":"0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224","withdrawal_credentials":"0x006adc4a1e4caba37c54d56d2411fd0df3a102f8489a4c1be535f4fd5f8810c9","effective_balance":"25000000000","slashed":true,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"261","withdrawable_epoch":"8448"}},{"index":"3","status":"active_slashed","balance":"35998164834","validator":{"pubkey":"0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60","withdrawal_credentials":"0x0081c852078a2ad430d438d7eaefc39646f53895292596bbe199e2d7d1884ab8","effective_balance":"32000000000","slashed":true,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"261","withdrawable_epoch":"8448"}}],"finalized":true,"execution_optimistic":false}
|
||||
- {"data":[{"index":"1","status":"withdrawal_possible","balance":"20125000000","validator":{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","withdrawal_credentials":"0x001f09ed305c0767d56f1b3bdb25f301298027f8e98a8e0cd2dcbcc660723d7b","effective_balance":"20000000000","slashed":false,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"253","withdrawable_epoch":"257"}}],"finalized":true,"execution_optimistic":false}
|
||||
|
||||
- {"data":[{"index":"1","balance":"20125000000"},{"index":"2","balance":"25678253779"},{"index":"3","balance":"35998164834"}],"finalized":true,"execution_optimistic":false}
|
||||
- {"data":[{"index":"1","balance":"20125000000"}],"finalized":true,"execution_optimistic":false}
|
||||
|
||||
- {"data":{"index":"1","status":"withdrawal_possible","balance":"20125000000","validator":{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","withdrawal_credentials":"0x001f09ed305c0767d56f1b3bdb25f301298027f8e98a8e0cd2dcbcc660723d7b","effective_balance":"20000000000","slashed":false,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"253","withdrawable_epoch":"257"}},"finalized":true,"execution_optimistic":false}
|
||||
- {"data":{"index":"1","status":"withdrawal_possible","balance":"20125000000","validator":{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","withdrawal_credentials":"0x001f09ed305c0767d56f1b3bdb25f301298027f8e98a8e0cd2dcbcc660723d7b","effective_balance":"20000000000","slashed":false,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"253","withdrawable_epoch":"257"}},"finalized":true,"execution_optimistic":false}
|
@ -1,4 +1,4 @@
|
||||
package handler
|
||||
package handler_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"github.com/ledgerwatch/erigon-lib/kv/memdb"
|
||||
"github.com/ledgerwatch/erigon/cl/antiquary"
|
||||
"github.com/ledgerwatch/erigon/cl/antiquary/tests"
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/handler"
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/synced_data"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes"
|
||||
@ -23,7 +24,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func setupTestingHandler(t *testing.T, v clparams.StateVersion) (db kv.RwDB, blocks []*cltypes.SignedBeaconBlock, f afero.Fs, preState, postState *state.CachingBeaconState, handler *ApiHandler, opPool pool.OperationsPool, syncedData *synced_data.SyncedDataManager, fcu *forkchoice.ForkChoiceStorageMock) {
|
||||
func setupTestingHandler(t *testing.T, v clparams.StateVersion, logger log.Logger) (db kv.RwDB, blocks []*cltypes.SignedBeaconBlock, f afero.Fs, preState, postState *state.CachingBeaconState, h *handler.ApiHandler, opPool pool.OperationsPool, syncedData *synced_data.SyncedDataManager, fcu *forkchoice.ForkChoiceStorageMock) {
|
||||
bcfg := clparams.MainnetBeaconConfig
|
||||
if v == clparams.Phase0Version {
|
||||
blocks, preState, postState = tests.GetPhase0Random()
|
||||
@ -44,7 +45,7 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion) (db kv.RwDB, blo
|
||||
|
||||
ctx := context.Background()
|
||||
vt := state_accessors.NewStaticValidatorTable()
|
||||
a := antiquary.NewAntiquary(ctx, preState, vt, &bcfg, datadir.New("/tmp"), nil, db, nil, reader, nil, log.New(), true, true, f)
|
||||
a := antiquary.NewAntiquary(ctx, preState, vt, &bcfg, datadir.New("/tmp"), nil, db, nil, reader, nil, logger, true, true, f)
|
||||
require.NoError(t, a.IncrementBeaconState(ctx, blocks[len(blocks)-1].Block.Slot+33))
|
||||
// historical states reader below
|
||||
statesReader := historical_states_reader.NewHistoricalStatesReader(&bcfg, reader, vt, f, preState)
|
||||
@ -52,7 +53,7 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion) (db kv.RwDB, blo
|
||||
fcu.Pool = opPool
|
||||
syncedData = synced_data.NewSyncedDataManager(true, &bcfg)
|
||||
gC := clparams.GenesisConfigs[clparams.MainnetNetwork]
|
||||
handler = NewApiHandler(
|
||||
h = handler.NewApiHandler(
|
||||
&gC,
|
||||
&bcfg,
|
||||
rawDB,
|
||||
@ -64,6 +65,6 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion) (db kv.RwDB, blo
|
||||
statesReader,
|
||||
nil,
|
||||
"test-version")
|
||||
handler.init()
|
||||
h.Init()
|
||||
return
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ func checkValidValidatorId(s string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getAllValidators(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getAllValidators(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -193,7 +193,7 @@ func (a *ApiHandler) getAllValidators(w http.ResponseWriter, r *http.Request) (*
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -203,12 +203,12 @@ func (a *ApiHandler) getAllValidators(w http.ResponseWriter, r *http.Request) (*
|
||||
return nil, beaconhttp.NewEndpointError(httpStatus, err.Error())
|
||||
}
|
||||
|
||||
queryFilters, err := stringListFromQueryParams(r, "status")
|
||||
queryFilters, err := beaconhttp.StringListFromQueryParams(r, "status")
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
validatorIds, err := stringListFromQueryParams(r, "id")
|
||||
validatorIds, err := beaconhttp.StringListFromQueryParams(r, "id")
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -226,7 +226,7 @@ func (a *ApiHandler) getAllValidators(w http.ResponseWriter, r *http.Request) (*
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if blockId.head() { // Lets see if we point to head, if yes then we need to look at the head state we always keep.
|
||||
if blockId.Head() { // Lets see if we point to head, if yes then we need to look at the head state we always keep.
|
||||
s, cn := a.syncedData.HeadState()
|
||||
defer cn()
|
||||
if s == nil {
|
||||
@ -308,7 +308,7 @@ func parseQueryValidatorIndicies(tx kv.Tx, ids []string) ([]uint64, error) {
|
||||
return filterIndicies, nil
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getSingleValidator(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getSingleValidator(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -317,7 +317,7 @@ func (a *ApiHandler) getSingleValidator(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -327,7 +327,7 @@ func (a *ApiHandler) getSingleValidator(w http.ResponseWriter, r *http.Request)
|
||||
return nil, beaconhttp.NewEndpointError(httpStatus, err.Error())
|
||||
}
|
||||
|
||||
validatorId, err := stringFromRequest(r, "validator_id")
|
||||
validatorId, err := beaconhttp.StringFromRequest(r, "validator_id")
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -337,11 +337,11 @@ func (a *ApiHandler) getSingleValidator(w http.ResponseWriter, r *http.Request)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if blockId.head() { // Lets see if we point to head, if yes then we need to look at the head state we always keep.
|
||||
if blockId.Head() { // Lets see if we point to head, if yes then we need to look at the head state we always keep.
|
||||
s, cn := a.syncedData.HeadState()
|
||||
defer cn()
|
||||
if s.ValidatorLength() <= int(validatorIndex) {
|
||||
return newBeaconResponse([]int{}).withFinalized(false), nil
|
||||
return newBeaconResponse([]int{}).WithFinalized(false), nil
|
||||
}
|
||||
if s == nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, "node is not synced")
|
||||
@ -375,7 +375,7 @@ func (a *ApiHandler) getSingleValidator(w http.ResponseWriter, r *http.Request)
|
||||
return responseValidator(validatorIndex, stateEpoch, state.Balances(), state.Validators(), *slot <= a.forkchoiceStore.FinalizedSlot())
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getAllValidatorsBalances(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) {
|
||||
func (a *ApiHandler) getAllValidatorsBalances(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
tx, err := a.indiciesDB.BeginRo(ctx)
|
||||
@ -384,7 +384,7 @@ func (a *ApiHandler) getAllValidatorsBalances(w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
blockId, err := stateIdFromRequest(r)
|
||||
blockId, err := beaconhttp.StateIdFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -394,7 +394,7 @@ func (a *ApiHandler) getAllValidatorsBalances(w http.ResponseWriter, r *http.Req
|
||||
return nil, beaconhttp.NewEndpointError(httpStatus, err.Error())
|
||||
}
|
||||
|
||||
validatorIds, err := stringListFromQueryParams(r, "id")
|
||||
validatorIds, err := beaconhttp.StringListFromQueryParams(r, "id")
|
||||
if err != nil {
|
||||
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
@ -407,7 +407,7 @@ func (a *ApiHandler) getAllValidatorsBalances(w http.ResponseWriter, r *http.Req
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if blockId.head() { // Lets see if we point to head, if yes then we need to look at the head state we always keep.
|
||||
if blockId.Head() { // Lets see if we point to head, if yes then we need to look at the head state we always keep.
|
||||
s, cn := a.syncedData.HeadState()
|
||||
defer cn()
|
||||
if s == nil {
|
||||
@ -444,7 +444,7 @@ func (d directString) MarshalJSON() ([]byte, error) {
|
||||
return []byte(d), nil
|
||||
}
|
||||
|
||||
func responseValidators(filterIndicies []uint64, filterStatuses []validatorStatus, stateEpoch uint64, balances solid.Uint64ListSSZ, validators *solid.ValidatorSet, finalized bool) (*beaconResponse, error) {
|
||||
func responseValidators(filterIndicies []uint64, filterStatuses []validatorStatus, stateEpoch uint64, balances solid.Uint64ListSSZ, validators *solid.ValidatorSet, finalized bool) (*beaconhttp.BeaconResponse, error) {
|
||||
var b strings.Builder
|
||||
b.WriteString("[")
|
||||
first := true
|
||||
@ -474,14 +474,14 @@ func responseValidators(filterIndicies []uint64, filterStatuses []validatorStatu
|
||||
|
||||
_, err = b.WriteString("]\n")
|
||||
|
||||
return newBeaconResponse(directString(b.String())).withFinalized(finalized), err
|
||||
return newBeaconResponse(directString(b.String())).WithFinalized(finalized), err
|
||||
}
|
||||
|
||||
func responseValidator(idx uint64, stateEpoch uint64, balances solid.Uint64ListSSZ, validators *solid.ValidatorSet, finalized bool) (*beaconResponse, error) {
|
||||
func responseValidator(idx uint64, stateEpoch uint64, balances solid.Uint64ListSSZ, validators *solid.ValidatorSet, finalized bool) (*beaconhttp.BeaconResponse, error) {
|
||||
var b strings.Builder
|
||||
var err error
|
||||
if validators.Length() <= int(idx) {
|
||||
return newBeaconResponse([]int{}).withFinalized(finalized), nil
|
||||
return newBeaconResponse([]int{}).WithFinalized(finalized), nil
|
||||
}
|
||||
|
||||
v := validators.Get(int(idx))
|
||||
@ -493,10 +493,10 @@ func responseValidator(idx uint64, stateEpoch uint64, balances solid.Uint64ListS
|
||||
|
||||
_, err = b.WriteString("\n")
|
||||
|
||||
return newBeaconResponse(directString(b.String())).withFinalized(finalized), err
|
||||
return newBeaconResponse(directString(b.String())).WithFinalized(finalized), err
|
||||
}
|
||||
|
||||
func responseValidatorsBalances(filterIndicies []uint64, stateEpoch uint64, balances solid.Uint64ListSSZ, finalized bool) (*beaconResponse, error) {
|
||||
func responseValidatorsBalances(filterIndicies []uint64, stateEpoch uint64, balances solid.Uint64ListSSZ, finalized bool) (*beaconhttp.BeaconResponse, error) {
|
||||
var b strings.Builder
|
||||
b.WriteString("[")
|
||||
jsonTemplate := "{\"index\":\"%d\",\"balance\":\"%d\"}"
|
||||
@ -524,7 +524,7 @@ func responseValidatorsBalances(filterIndicies []uint64, stateEpoch uint64, bala
|
||||
|
||||
_, err = b.WriteString("]\n")
|
||||
|
||||
return newBeaconResponse(directString(b.String())).withFinalized(finalized), err
|
||||
return newBeaconResponse(directString(b.String())).WithFinalized(finalized), err
|
||||
}
|
||||
|
||||
func shouldStatusBeFiltered(status validatorStatus, statuses []validatorStatus) bool {
|
||||
|
@ -1,201 +0,0 @@
|
||||
//go:build integration
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
||||
"github.com/ledgerwatch/erigon/common"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetAllValidators(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, postState, handler, _, _, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
postRoot, err := postState.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadVal, err = blocks[len(blocks)-1].Block.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
|
||||
cases := []struct {
|
||||
blockID string
|
||||
code int
|
||||
queryParams string
|
||||
expectedResp string
|
||||
}{
|
||||
{
|
||||
blockID: "0x" + common.Bytes2Hex(postRoot[:]),
|
||||
code: http.StatusOK,
|
||||
queryParams: "?id=1,2,3",
|
||||
expectedResp: `{"data":[{"index":"1","status":"withdrawal_possible","balance":"20125000000","validator":{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","withdrawal_credentials":"0x001f09ed305c0767d56f1b3bdb25f301298027f8e98a8e0cd2dcbcc660723d7b","effective_balance":"20000000000","slashed":false,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"253","withdrawable_epoch":"257"}},{"index":"2","status":"active_slashed","balance":"25678253779","validator":{"pubkey":"0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224","withdrawal_credentials":"0x006adc4a1e4caba37c54d56d2411fd0df3a102f8489a4c1be535f4fd5f8810c9","effective_balance":"25000000000","slashed":true,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"261","withdrawable_epoch":"8448"}},{"index":"3","status":"active_slashed","balance":"35998164834","validator":{"pubkey":"0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60","withdrawal_credentials":"0x0081c852078a2ad430d438d7eaefc39646f53895292596bbe199e2d7d1884ab8","effective_balance":"32000000000","slashed":true,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"261","withdrawable_epoch":"8448"}}],"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
blockID: "finalized",
|
||||
code: http.StatusOK,
|
||||
queryParams: "?status=active&id=1,2,3",
|
||||
expectedResp: `{"data":[{"index":"2","status":"active_slashed","balance":"25678253779","validator":{"pubkey":"0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224","withdrawal_credentials":"0x006adc4a1e4caba37c54d56d2411fd0df3a102f8489a4c1be535f4fd5f8810c9","effective_balance":"25000000000","slashed":true,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"261","withdrawable_epoch":"8448"}},{"index":"3","status":"active_slashed","balance":"35998164834","validator":{"pubkey":"0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60","withdrawal_credentials":"0x0081c852078a2ad430d438d7eaefc39646f53895292596bbe199e2d7d1884ab8","effective_balance":"32000000000","slashed":true,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"261","withdrawable_epoch":"8448"}}],"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
blockID: "finalized",
|
||||
code: http.StatusOK,
|
||||
queryParams: "?id=0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e",
|
||||
expectedResp: `{"data":[{"index":"1","status":"withdrawal_possible","balance":"20125000000","validator":{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","withdrawal_credentials":"0x001f09ed305c0767d56f1b3bdb25f301298027f8e98a8e0cd2dcbcc660723d7b","effective_balance":"20000000000","slashed":false,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"253","withdrawable_epoch":"257"}}],"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
blockID: "alabama",
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.blockID, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// Query the block in the handler with /eth/v2/beacon/blocks/{block_id}
|
||||
resp, err := http.Get(server.URL + "/eth/v1/beacon/states/" + c.blockID + "/validators" + c.queryParams)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
|
||||
// unmarshal the json
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.expectedResp, string(out))
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetValidatorsBalances(t *testing.T) {
|
||||
t.Skip("FIXME: oom")
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, postState, handler, _, _, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
postRoot, err := postState.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadVal, err = blocks[len(blocks)-1].Block.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
|
||||
cases := []struct {
|
||||
blockID string
|
||||
code int
|
||||
queryParams string
|
||||
expectedResp string
|
||||
}{
|
||||
{
|
||||
blockID: "0x" + common.Bytes2Hex(postRoot[:]),
|
||||
code: http.StatusOK,
|
||||
queryParams: "?id=1,2,3",
|
||||
expectedResp: `{"data":[{"index":"1","balance":"20125000000"},{"index":"2","balance":"25678253779"},{"index":"3","balance":"35998164834"}],"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
blockID: "finalized",
|
||||
code: http.StatusOK,
|
||||
queryParams: "?id=0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e",
|
||||
expectedResp: `{"data":[{"index":"1","balance":"20125000000"}],"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
blockID: "alabama",
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.blockID, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// Query the block in the handler with /eth/v2/beacon/blocks/{block_id}
|
||||
resp, err := http.Get(server.URL + "/eth/v1/beacon/states/" + c.blockID + "/validator_balances" + c.queryParams)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
// unmarshal the json
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.expectedResp, string(out))
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSingleValidator(t *testing.T) {
|
||||
|
||||
// setupTestingHandler(t, clparams.Phase0Version)
|
||||
_, blocks, _, _, postState, handler, _, _, fcu := setupTestingHandler(t, clparams.Phase0Version)
|
||||
|
||||
postRoot, err := postState.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadVal, err = blocks[len(blocks)-1].Block.HashSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
fcu.HeadSlotVal = blocks[len(blocks)-1].Block.Slot
|
||||
fcu.FinalizedCheckpointVal = solid.NewCheckpointFromParameters(fcu.HeadVal, fcu.HeadSlotVal/32)
|
||||
|
||||
cases := []struct {
|
||||
blockID string
|
||||
code int
|
||||
validatorIdx string
|
||||
expectedResp string
|
||||
}{
|
||||
{
|
||||
blockID: "0x" + common.Bytes2Hex(postRoot[:]),
|
||||
code: http.StatusOK,
|
||||
validatorIdx: "1",
|
||||
expectedResp: `{"data":{"index":"1","status":"withdrawal_possible","balance":"20125000000","validator":{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","withdrawal_credentials":"0x001f09ed305c0767d56f1b3bdb25f301298027f8e98a8e0cd2dcbcc660723d7b","effective_balance":"20000000000","slashed":false,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"253","withdrawable_epoch":"257"}},"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
blockID: "finalized",
|
||||
code: http.StatusOK,
|
||||
validatorIdx: "0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e",
|
||||
expectedResp: `{"data":{"index":"1","status":"withdrawal_possible","balance":"20125000000","validator":{"pubkey":"0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e","withdrawal_credentials":"0x001f09ed305c0767d56f1b3bdb25f301298027f8e98a8e0cd2dcbcc660723d7b","effective_balance":"20000000000","slashed":false,"activation_eligibility_epoch":"0","activation_epoch":"0","exit_epoch":"253","withdrawable_epoch":"257"}},"finalized":true,"execution_optimistic":false}` + "\n",
|
||||
},
|
||||
{
|
||||
blockID: "alabama",
|
||||
code: http.StatusBadRequest,
|
||||
validatorIdx: "3",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.blockID, func(t *testing.T) {
|
||||
server := httptest.NewServer(handler.mux)
|
||||
defer server.Close()
|
||||
// Query the block in the handler with /eth/v2/beacon/blocks/{block_id}
|
||||
resp, err := http.Get(server.URL + "/eth/v1/beacon/states/" + c.blockID + "/validators/" + c.validatorIdx)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, c.code, resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
// unmarshal the json
|
||||
out, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.expectedResp, string(out))
|
||||
|
||||
})
|
||||
}
|
||||
}
|
13
go.mod
13
go.mod
@ -15,6 +15,7 @@ require (
|
||||
gfx.cafe/util/go/generic v0.0.0-20230721185457-c559e86c829c
|
||||
github.com/99designs/gqlgen v0.17.40
|
||||
github.com/Giulio2002/bls v0.0.0-20230906201036-c2330c97dc7d
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/RoaringBitmap/roaring v1.2.3
|
||||
github.com/VictoriaMetrics/fastcache v1.12.2
|
||||
github.com/alecthomas/kong v0.8.0
|
||||
@ -45,6 +46,7 @@ require (
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
|
||||
github.com/google/btree v1.1.2
|
||||
github.com/google/cel-go v0.18.2
|
||||
github.com/google/gofuzz v1.2.0
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||
@ -103,9 +105,12 @@ require (
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.28.0
|
||||
pgregory.net/rapid v1.1.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||
github.com/agnivade/levenshtein v1.1.1 // indirect
|
||||
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect
|
||||
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
|
||||
@ -122,6 +127,7 @@ require (
|
||||
github.com/anacrolix/stm v0.4.1-0.20221221005312-96d17df0e496 // indirect
|
||||
github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 // indirect
|
||||
github.com/anacrolix/utp v0.1.0 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.21.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.19.0 // indirect
|
||||
@ -178,6 +184,7 @@ require (
|
||||
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20220405231054-a1ae3e4bba26 // indirect
|
||||
github.com/imdario/mergo v0.3.11 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/ipfs/go-cid v0.4.1 // indirect
|
||||
github.com/ipfs/go-log/v2 v2.5.1 // indirect
|
||||
@ -207,7 +214,9 @@ require (
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
@ -256,9 +265,12 @@ require (
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/sosodev/duration v1.1.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||
github.com/supranational/blst v0.3.11 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
@ -270,6 +282,7 @@ require (
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
|
34
go.sum
34
go.sum
@ -55,6 +55,12 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Giulio2002/bls v0.0.0-20230906201036-c2330c97dc7d h1:fAztVLpjcVcd2al4GL8xYr9Yp7LmXXSTuLqu83U8hKo=
|
||||
github.com/Giulio2002/bls v0.0.0-20230906201036-c2330c97dc7d/go.mod h1:nCQrFU6/QsJtLS+SBLWRn9UG2nds1f3hQKfWHCrtUqw=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
|
||||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||
@ -137,6 +143,8 @@ github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4=
|
||||
github.com/anacrolix/utp v0.1.0/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
@ -407,6 +415,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/cel-go v0.18.2 h1:L0B6sNBSVmt0OyECi8v6VOS74KOc9W/tLiWKfZABvf4=
|
||||
github.com/google/cel-go v0.18.2/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@ -419,6 +429,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@ -443,6 +454,7 @@ github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBB
|
||||
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
@ -480,6 +492,7 @@ github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63
|
||||
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
|
||||
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY=
|
||||
@ -488,6 +501,8 @@ github.com/ianlancetaylor/cgosymbolizer v0.0.0-20220405231054-a1ae3e4bba26 h1:UT
|
||||
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20220405231054-a1ae3e4bba26/go.mod h1:DvXTE/K/RtHehxU8/GtDs4vFtfw64jJ3PaCnFri8CRg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
|
||||
@ -611,8 +626,12 @@ github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8Rv
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
||||
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
|
||||
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
|
||||
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
|
||||
@ -808,6 +827,8 @@ github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5P
|
||||
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
@ -848,10 +869,14 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@ -955,6 +980,7 @@ golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
@ -1051,6 +1077,7 @@ golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
@ -1151,6 +1178,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -1162,6 +1190,7 @@ golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
@ -1174,6 +1203,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
@ -1321,6 +1351,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
@ -1429,6 +1461,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
|
||||
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
zombiezen.com/go/sqlite v0.13.1 h1:qDzxyWWmMtSSEH5qxamqBFmqA2BLSSbtODi3ojaE02o=
|
||||
|
Loading…
Reference in New Issue
Block a user