mirror of
https://github.com/wealdtech/ethdo.git
synced 2026-01-10 14:37:57 -05:00
Compare commits
3 Commits
v1.36.4
...
electra-mi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb34776d05 | ||
|
|
e29818340d | ||
|
|
083f484907 |
27
.github/workflows/golangci-lint.yml
vendored
27
.github/workflows/golangci-lint.yml
vendored
@@ -1,24 +1,23 @@
|
||||
name: 'golangci-lint'
|
||||
name: golangci-lint
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
branches:
|
||||
- 'master'
|
||||
workflow_dispatch:
|
||||
|
||||
- master
|
||||
pull_request:
|
||||
permissions:
|
||||
contents: 'read'
|
||||
|
||||
contents: read
|
||||
jobs:
|
||||
golangci:
|
||||
name: 'lint'
|
||||
runs-on: 'ubuntu-24.04'
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: 'actions/setup-go@v5'
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
cache: false
|
||||
go-version: '^1.22'
|
||||
- uses: 'actions/checkout@v4'
|
||||
- uses: 'golangci/golangci-lint-action@v6'
|
||||
go-version: '^1.21'
|
||||
- uses: actions/checkout@v4
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v4
|
||||
with:
|
||||
only-new-issues: true
|
||||
|
||||
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -3,9 +3,8 @@ name: Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
- 't*'
|
||||
workflow_dispatch:
|
||||
- 'v*'
|
||||
- 't*'
|
||||
|
||||
jobs:
|
||||
# Set variables that will be available to all builds.
|
||||
@@ -45,10 +44,9 @@ jobs:
|
||||
needs: [create_release, env_vars]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
cache: false
|
||||
go-version: '^1.22'
|
||||
go-version: '^1.21'
|
||||
|
||||
- name: Check out repository into the Go module directory
|
||||
uses: actions/checkout@v4
|
||||
@@ -121,10 +119,9 @@ jobs:
|
||||
needs: [create_release, env_vars]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
cache: false
|
||||
go-version: '^1.22'
|
||||
go-version: '^1.21'
|
||||
|
||||
- name: Check out repository into the Go module directory
|
||||
uses: actions/checkout@v4
|
||||
@@ -167,10 +164,9 @@ jobs:
|
||||
needs: [create_release, env_vars]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
cache: false
|
||||
go-version: '^1.22'
|
||||
go-version: '^1.21'
|
||||
|
||||
- name: Check out repository into the Go module directory
|
||||
uses: actions/checkout@v4
|
||||
|
||||
13
.github/workflows/test.yml
vendored
13
.github/workflows/test.yml
vendored
@@ -1,18 +1,15 @@
|
||||
name: test
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
- master
|
||||
pull_request:
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
cache: false
|
||||
go-version: '^1.22'
|
||||
go-version: '^1.21'
|
||||
- uses: actions/checkout@v4
|
||||
- uses: n8maninger/action-golang-test@v2
|
||||
- uses: n8maninger/action-golang-test@v1
|
||||
|
||||
@@ -106,11 +106,6 @@ output:
|
||||
|
||||
# All available settings of specific linters.
|
||||
linters-settings:
|
||||
gosec:
|
||||
excludes:
|
||||
# Flags for potentially-unsafe casting of ints, but generates a lot of false positives.
|
||||
- 'G115'
|
||||
|
||||
lll:
|
||||
line-length: 132
|
||||
|
||||
@@ -133,13 +128,15 @@ linters:
|
||||
disable:
|
||||
- contextcheck
|
||||
- cyclop
|
||||
- deadcode
|
||||
- depguard
|
||||
- dupl
|
||||
- err113
|
||||
- errorlint
|
||||
- execinquery
|
||||
- exhaustive
|
||||
- exhaustivestruct
|
||||
- exhaustruct
|
||||
- exportloopref
|
||||
- forbidigo
|
||||
- forcetypeassert
|
||||
- funlen
|
||||
@@ -149,20 +146,29 @@ linters:
|
||||
- gocognit
|
||||
- goconst
|
||||
- goheader
|
||||
- golint
|
||||
- gomnd
|
||||
- ifshort
|
||||
- interfacer
|
||||
- ireturn
|
||||
- lll
|
||||
- maintidx
|
||||
- maligned
|
||||
- mnd
|
||||
- musttag
|
||||
- nestif
|
||||
- nilnil
|
||||
- nlreturn
|
||||
- nolintlint
|
||||
- nosnakecase
|
||||
- perfsprint
|
||||
- promlinter
|
||||
- rowserrcheck
|
||||
- scopelint
|
||||
- sqlclosecheck
|
||||
- structcheck
|
||||
- unparam
|
||||
- varcheck
|
||||
- varnamelen
|
||||
- wastedassign
|
||||
- wrapcheck
|
||||
|
||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,23 +1,4 @@
|
||||
1.36.2:
|
||||
- avoid crash when signing and verifing signatures using keys rather than accounts
|
||||
|
||||
1.36.1:
|
||||
- more JSON data for epoch summary
|
||||
- fix crash when block ifno had no blobs
|
||||
|
||||
1.36.0:
|
||||
- support keystore wallets
|
||||
|
||||
1.35.6:
|
||||
- provide more JSON data in "epoch summary"
|
||||
|
||||
1.35.5:
|
||||
- allow keystore to be output to the console
|
||||
|
||||
1.35.4:
|
||||
- provide consensus and execution client info in block info output
|
||||
|
||||
1.35.3:
|
||||
dev:
|
||||
- provide better error message on context deadlline exceeded
|
||||
- update launchpad output to match latest version
|
||||
- add deposit contract address to "chain info"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.22-bookworm as builder
|
||||
FROM golang:1.21-bookworm as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
10
README.md
10
README.md
@@ -151,13 +151,9 @@ Amazon S3-compatible stores have additional options available, which can be conf
|
||||
{
|
||||
"stores": {
|
||||
"s3": {
|
||||
"region": "us-west-1",
|
||||
"bucket": "my-s3-store",
|
||||
"path": "/wallets",
|
||||
"credentials": {
|
||||
"id": "ABCDEF123",
|
||||
"secret": "XXXXXXXXX"
|
||||
}
|
||||
"bucket":"mybucketname",
|
||||
"path":"path/in/bucket",
|
||||
"passphrase":"secret"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
|
||||
type dataIn struct {
|
||||
quiet bool
|
||||
json bool
|
||||
// Derivation information.
|
||||
mnemonic string
|
||||
path string
|
||||
@@ -38,9 +37,6 @@ func input(_ context.Context) (*dataIn, error) {
|
||||
// Quiet.
|
||||
data.quiet = viper.GetBool("quiet")
|
||||
|
||||
// JSON.
|
||||
data.json = viper.GetBool("json")
|
||||
|
||||
// Mnemonic.
|
||||
if viper.GetString("mnemonic") == "" {
|
||||
return nil, errors.New("mnemonic is required")
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
)
|
||||
|
||||
type dataOut struct {
|
||||
json bool
|
||||
showPrivateKey bool
|
||||
showWithdrawalCredentials bool
|
||||
generateKeystore bool
|
||||
@@ -95,14 +94,10 @@ func outputKeystore(_ context.Context, data *dataOut) (string, error) {
|
||||
return "", errors.Wrap(err, "failed to marshal keystore JSON")
|
||||
}
|
||||
|
||||
if data.json {
|
||||
fmt.Fprintf(os.Stdout, "%s\n", string(out))
|
||||
} else {
|
||||
keystoreFilename := fmt.Sprintf("keystore-%s-%d.json", strings.ReplaceAll(data.path, "/", "_"), time.Now().Unix())
|
||||
keystoreFilename := fmt.Sprintf("keystore-%s-%d.json", strings.ReplaceAll(data.path, "/", "_"), time.Now().Unix())
|
||||
|
||||
if err := os.WriteFile(keystoreFilename, out, 0o600); err != nil {
|
||||
return "", errors.Wrap(err, fmt.Sprintf("failed to write %s", keystoreFilename))
|
||||
}
|
||||
if err := os.WriteFile(keystoreFilename, out, 0o600); err != nil {
|
||||
return "", errors.Wrap(err, fmt.Sprintf("failed to write %s", keystoreFilename))
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
|
||||
}
|
||||
|
||||
results := &dataOut{
|
||||
json: data.json,
|
||||
showPrivateKey: data.showPrivateKey,
|
||||
showWithdrawalCredentials: data.showWithdrawalCredentials,
|
||||
generateKeystore: data.generateKeystore,
|
||||
|
||||
@@ -50,7 +50,6 @@ func init() {
|
||||
accountDeriveCmd.Flags().Bool("show-private-key", false, "show private key for derived account")
|
||||
accountDeriveCmd.Flags().Bool("show-withdrawal-credentials", false, "show withdrawal credentials for derived account")
|
||||
accountDeriveCmd.Flags().Bool("generate-keystore", false, "generate a keystore for the derived account")
|
||||
accountDeriveCmd.Flags().Bool("json", false, "display the JSON keystore for the derived account on stdout")
|
||||
}
|
||||
|
||||
func accountDeriveBindings(cmd *cobra.Command) {
|
||||
@@ -63,7 +62,4 @@ func accountDeriveBindings(cmd *cobra.Command) {
|
||||
if err := viper.BindPFlag("generate-keystore", cmd.Flags().Lookup("generate-keystore")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := viper.BindPFlag("json", cmd.Flags().Lookup("json")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
var accountImportCmd = &cobra.Command{
|
||||
Use: "import",
|
||||
Short: "Import an account",
|
||||
Long: `Import an account from its private key. For example:
|
||||
Long: `Import an account from its private key or keystore. For example:
|
||||
|
||||
ethdo account import --account="primary/testing" --key="0x..." --passphrase="my secret"
|
||||
|
||||
|
||||
@@ -61,10 +61,11 @@ func input(ctx context.Context) (*dataIn, error) {
|
||||
// Ethereum 2 client.
|
||||
var err error
|
||||
data.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !data.quiet,
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !data.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -58,10 +58,11 @@ func input(ctx context.Context) (*dataIn, error) {
|
||||
// Ethereum 2 client.
|
||||
var err error
|
||||
data.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !data.quiet,
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !data.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -93,23 +93,33 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
|
||||
return nil, errors.Wrap(err, "failed to obtain block attestations")
|
||||
}
|
||||
for i, attestation := range attestations {
|
||||
if attestation.Data.Slot == duty.Slot &&
|
||||
attestation.Data.Index == duty.CommitteeIndex &&
|
||||
attestation.AggregationBits.BitAt(duty.ValidatorCommitteeIndex) {
|
||||
attestationData, err := attestation.Data()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain attestation data")
|
||||
}
|
||||
aggregationBits, err := attestation.AggregationBits()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain attestation aggregation bits")
|
||||
}
|
||||
|
||||
if attestationData.Slot == duty.Slot &&
|
||||
attestationData.Index == duty.CommitteeIndex &&
|
||||
aggregationBits.BitAt(duty.ValidatorCommitteeIndex) {
|
||||
headCorrect := false
|
||||
targetCorrect := false
|
||||
if data.verbose {
|
||||
headCorrect, err = calcHeadCorrect(ctx, data, attestation)
|
||||
headCorrect, err = calcHeadCorrect(ctx, data, attestationData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain head correct result")
|
||||
}
|
||||
targetCorrect, err = calcTargetCorrect(ctx, data, attestation)
|
||||
targetCorrect, err = calcTargetCorrect(ctx, data, attestationData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain target correct result")
|
||||
}
|
||||
}
|
||||
results.found = true
|
||||
results.attestation = attestation
|
||||
// TODO fix.
|
||||
// results.attestation = attestation
|
||||
results.slot = slot
|
||||
results.attestationIndex = uint64(i)
|
||||
results.inclusionDelay = slot - duty.Slot
|
||||
@@ -128,8 +138,8 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func calcHeadCorrect(ctx context.Context, data *dataIn, attestation *phase0.Attestation) (bool, error) {
|
||||
slot := attestation.Data.Slot
|
||||
func calcHeadCorrect(ctx context.Context, data *dataIn, attestationData *phase0.AttestationData) (bool, error) {
|
||||
slot := attestationData.Slot
|
||||
for {
|
||||
response, err := data.eth2Client.(eth2client.BeaconBlockHeadersProvider).BeaconBlockHeader(ctx, &api.BeaconBlockHeaderOpts{
|
||||
Block: fmt.Sprintf("%d", slot),
|
||||
@@ -149,13 +159,13 @@ func calcHeadCorrect(ctx context.Context, data *dataIn, attestation *phase0.Atte
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
return bytes.Equal(response.Data.Root[:], attestation.Data.BeaconBlockRoot[:]), nil
|
||||
return bytes.Equal(response.Data.Root[:], attestationData.BeaconBlockRoot[:]), nil
|
||||
}
|
||||
}
|
||||
|
||||
func calcTargetCorrect(ctx context.Context, data *dataIn, attestation *phase0.Attestation) (bool, error) {
|
||||
func calcTargetCorrect(ctx context.Context, data *dataIn, attestationData *phase0.AttestationData) (bool, error) {
|
||||
// Start with first slot of the target epoch.
|
||||
slot := data.chainTime.FirstSlotOfEpoch(attestation.Data.Target.Epoch)
|
||||
slot := data.chainTime.FirstSlotOfEpoch(attestationData.Target.Epoch)
|
||||
for {
|
||||
response, err := data.eth2Client.(eth2client.BeaconBlockHeadersProvider).BeaconBlockHeader(ctx, &api.BeaconBlockHeaderOpts{
|
||||
Block: fmt.Sprintf("%d", slot),
|
||||
@@ -175,7 +185,7 @@ func calcTargetCorrect(ctx context.Context, data *dataIn, attestation *phase0.At
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
return bytes.Equal(response.Data.Root[:], attestation.Data.Target.Root[:]), nil
|
||||
return bytes.Equal(response.Data.Root[:], attestationData.Target.Root[:]), nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Operation.
|
||||
blockID string
|
||||
@@ -124,6 +125,7 @@ func newCommand(_ context.Context) (*command, error) {
|
||||
|
||||
c.connection = viper.GetString("connection")
|
||||
c.allowInsecureConnections = viper.GetBool("allow-insecure-connections")
|
||||
c.customSpecSupport = viper.GetBool("custom-spec")
|
||||
|
||||
c.blockID = viper.GetString("blockid")
|
||||
c.stream = viper.GetBool("stream")
|
||||
|
||||
@@ -17,11 +17,11 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
eth2client "github.com/attestantio/go-eth2-client"
|
||||
"github.com/attestantio/go-eth2-client/api"
|
||||
"github.com/attestantio/go-eth2-client/spec"
|
||||
"github.com/attestantio/go-eth2-client/spec/electra"
|
||||
"github.com/attestantio/go-eth2-client/spec/phase0"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
@@ -40,7 +40,7 @@ func (c *command) process(ctx context.Context) error {
|
||||
})
|
||||
if err != nil {
|
||||
var apiError *api.Error
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == http.StatusNotFound {
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == 404 {
|
||||
return errors.New("empty beacon block")
|
||||
}
|
||||
return errors.Wrap(err, "failed to obtain beacon block")
|
||||
@@ -63,8 +63,12 @@ func (c *command) process(ctx context.Context) error {
|
||||
// Calculate how many parents we need to fetch.
|
||||
minSlot := slot
|
||||
for _, attestation := range attestations {
|
||||
if attestation.Data.Slot < minSlot {
|
||||
minSlot = attestation.Data.Slot
|
||||
attestationData, err := attestation.Data()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if attestationData.Slot < minSlot {
|
||||
minSlot = attestationData.Slot
|
||||
}
|
||||
}
|
||||
if c.debug {
|
||||
@@ -103,72 +107,27 @@ func (c *command) analyzeAttestations(ctx context.Context, block *spec.Versioned
|
||||
if c.debug {
|
||||
fmt.Printf("Processing attestation %d\n", i)
|
||||
}
|
||||
analysis := &attestationAnalysis{
|
||||
Head: attestation.Data.BeaconBlockRoot,
|
||||
Target: attestation.Data.Target.Root,
|
||||
Distance: int(slot - attestation.Data.Slot),
|
||||
}
|
||||
|
||||
root, err := attestation.HashTreeRoot()
|
||||
var analysis *attestationAnalysis
|
||||
switch attestation.Version {
|
||||
case spec.DataVersionPhase0:
|
||||
analysis, err = c.phase0Analysis(ctx, slot, attestation.Phase0, blockVotes, spec.DataVersionPhase0)
|
||||
case spec.DataVersionAltair:
|
||||
analysis, err = c.phase0Analysis(ctx, slot, attestation.Altair, blockVotes, spec.DataVersionAltair)
|
||||
case spec.DataVersionBellatrix:
|
||||
analysis, err = c.phase0Analysis(ctx, slot, attestation.Bellatrix, blockVotes, spec.DataVersionBellatrix)
|
||||
case spec.DataVersionCapella:
|
||||
analysis, err = c.phase0Analysis(ctx, slot, attestation.Capella, blockVotes, spec.DataVersionCapella)
|
||||
case spec.DataVersionDeneb:
|
||||
analysis, err = c.phase0Analysis(ctx, slot, attestation.Deneb, blockVotes, spec.DataVersionDeneb)
|
||||
case spec.DataVersionElectra:
|
||||
analysis, err = c.electraAnalysis(ctx, slot, attestation.Electra, blockVotes, spec.DataVersionElectra)
|
||||
default:
|
||||
return fmt.Errorf("unknown version %s", attestation.Version)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info, exists := c.priorAttestations[fmt.Sprintf("%#x", root)]; exists {
|
||||
analysis.Duplicate = info
|
||||
} else {
|
||||
data := attestation.Data
|
||||
_, exists := blockVotes[data.Slot]
|
||||
if !exists {
|
||||
blockVotes[data.Slot] = make(map[phase0.CommitteeIndex]bitfield.Bitlist)
|
||||
}
|
||||
_, exists = blockVotes[data.Slot][data.Index]
|
||||
if !exists {
|
||||
blockVotes[data.Slot][data.Index] = bitfield.NewBitlist(attestation.AggregationBits.Len())
|
||||
}
|
||||
|
||||
// Count new votes.
|
||||
analysis.PossibleVotes = int(attestation.AggregationBits.Len())
|
||||
for j := range attestation.AggregationBits.Len() {
|
||||
if attestation.AggregationBits.BitAt(j) {
|
||||
analysis.Votes++
|
||||
if blockVotes[data.Slot][data.Index].BitAt(j) {
|
||||
// Already attested to in this block; skip.
|
||||
continue
|
||||
}
|
||||
if c.votes[data.Slot][data.Index].BitAt(j) {
|
||||
// Already attested to in a previous block; skip.
|
||||
continue
|
||||
}
|
||||
analysis.NewVotes++
|
||||
blockVotes[data.Slot][data.Index].SetBitAt(j, true)
|
||||
}
|
||||
}
|
||||
// Calculate head correct.
|
||||
var err error
|
||||
analysis.HeadCorrect, err = c.calcHeadCorrect(ctx, attestation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Calculate head timely.
|
||||
analysis.HeadTimely = analysis.HeadCorrect && attestation.Data.Slot == slot-1
|
||||
|
||||
// Calculate source timely.
|
||||
analysis.SourceTimely = attestation.Data.Slot >= slot-5
|
||||
|
||||
// Calculate target correct.
|
||||
analysis.TargetCorrect, err = c.calcTargetCorrect(ctx, attestation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Calculate target timely.
|
||||
if block.Version < spec.DataVersionDeneb {
|
||||
analysis.TargetTimely = attestation.Data.Slot >= slot-32
|
||||
} else {
|
||||
analysis.TargetTimely = true
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate score and value.
|
||||
if analysis.TargetCorrect && analysis.TargetTimely {
|
||||
@@ -189,6 +148,165 @@ func (c *command) analyzeAttestations(ctx context.Context, block *spec.Versioned
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *command) phase0Analysis(ctx context.Context,
|
||||
slot phase0.Slot,
|
||||
attestation *phase0.Attestation,
|
||||
blockVotes map[phase0.Slot]map[phase0.CommitteeIndex]bitfield.Bitlist,
|
||||
version spec.DataVersion,
|
||||
) (
|
||||
*attestationAnalysis,
|
||||
error,
|
||||
) {
|
||||
analysis := &attestationAnalysis{
|
||||
Head: attestation.Data.BeaconBlockRoot,
|
||||
Target: attestation.Data.Target.Root,
|
||||
Distance: int(slot - attestation.Data.Slot),
|
||||
}
|
||||
|
||||
// TODO.
|
||||
root, err := attestation.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if info, exists := c.priorAttestations[fmt.Sprintf("%#x", root)]; exists {
|
||||
analysis.Duplicate = info
|
||||
} else {
|
||||
data := attestation.Data
|
||||
_, exists := blockVotes[data.Slot]
|
||||
if !exists {
|
||||
blockVotes[data.Slot] = make(map[phase0.CommitteeIndex]bitfield.Bitlist)
|
||||
}
|
||||
_, exists = blockVotes[data.Slot][data.Index]
|
||||
if !exists {
|
||||
blockVotes[data.Slot][data.Index] = bitfield.NewBitlist(attestation.AggregationBits.Len())
|
||||
}
|
||||
|
||||
// Count new votes.
|
||||
analysis.PossibleVotes = int(attestation.AggregationBits.Len())
|
||||
for j := uint64(0); j < attestation.AggregationBits.Len(); j++ {
|
||||
if attestation.AggregationBits.BitAt(j) {
|
||||
analysis.Votes++
|
||||
if blockVotes[data.Slot][data.Index].BitAt(j) {
|
||||
// Already attested to in this block; skip.
|
||||
continue
|
||||
}
|
||||
if c.votes[data.Slot][data.Index].BitAt(j) {
|
||||
// Already attested to in a previous block; skip.
|
||||
continue
|
||||
}
|
||||
analysis.NewVotes++
|
||||
blockVotes[data.Slot][data.Index].SetBitAt(j, true)
|
||||
}
|
||||
}
|
||||
// Calculate head correct.
|
||||
analysis.HeadCorrect, err = c.calcHeadCorrect(ctx, attestation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Calculate head timely.
|
||||
analysis.HeadTimely = analysis.HeadCorrect && attestation.Data.Slot == slot-1
|
||||
|
||||
// Calculate source timely.
|
||||
analysis.SourceTimely = attestation.Data.Slot >= slot-5
|
||||
|
||||
// Calculate target correct.
|
||||
analysis.TargetCorrect, err = c.calcTargetCorrect(ctx, attestation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Calculate target timely.
|
||||
if version < spec.DataVersionDeneb {
|
||||
analysis.TargetTimely = attestation.Data.Slot >= slot-32
|
||||
} else {
|
||||
analysis.TargetTimely = true
|
||||
}
|
||||
}
|
||||
|
||||
return analysis, nil
|
||||
}
|
||||
|
||||
func (c *command) electraAnalysis(ctx context.Context,
|
||||
slot phase0.Slot,
|
||||
attestation *electra.Attestation,
|
||||
blockVotes map[phase0.Slot]map[phase0.CommitteeIndex]bitfield.Bitlist,
|
||||
version spec.DataVersion,
|
||||
) (
|
||||
*attestationAnalysis,
|
||||
error,
|
||||
) {
|
||||
analysis := &attestationAnalysis{
|
||||
Head: attestation.Data.BeaconBlockRoot,
|
||||
Target: attestation.Data.Target.Root,
|
||||
Distance: int(slot - attestation.Data.Slot),
|
||||
}
|
||||
|
||||
// TODO.
|
||||
root, err := attestation.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if info, exists := c.priorAttestations[fmt.Sprintf("%#x", root)]; exists {
|
||||
analysis.Duplicate = info
|
||||
} else {
|
||||
data := attestation.Data
|
||||
_, exists := blockVotes[data.Slot]
|
||||
if !exists {
|
||||
blockVotes[data.Slot] = make(map[phase0.CommitteeIndex]bitfield.Bitlist)
|
||||
}
|
||||
_, exists = blockVotes[data.Slot][data.Index]
|
||||
if !exists {
|
||||
blockVotes[data.Slot][data.Index] = bitfield.NewBitlist(attestation.AggregationBits.Len())
|
||||
}
|
||||
|
||||
// Count new votes.
|
||||
analysis.PossibleVotes = int(attestation.AggregationBits.Len())
|
||||
for j := uint64(0); j < attestation.AggregationBits.Len(); j++ {
|
||||
if attestation.AggregationBits.BitAt(j) {
|
||||
analysis.Votes++
|
||||
if blockVotes[data.Slot][data.Index].BitAt(j) {
|
||||
// Already attested to in this block; skip.
|
||||
continue
|
||||
}
|
||||
if c.votes[data.Slot][data.Index].BitAt(j) {
|
||||
// Already attested to in a previous block; skip.
|
||||
continue
|
||||
}
|
||||
analysis.NewVotes++
|
||||
blockVotes[data.Slot][data.Index].SetBitAt(j, true)
|
||||
}
|
||||
}
|
||||
// Calculate head correct.
|
||||
var err error
|
||||
analysis.HeadCorrect, err = c.calcElectraHeadCorrect(ctx, attestation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Calculate head timely.
|
||||
analysis.HeadTimely = analysis.HeadCorrect && attestation.Data.Slot == slot-1
|
||||
|
||||
// Calculate source timely.
|
||||
analysis.SourceTimely = attestation.Data.Slot >= slot-5
|
||||
|
||||
// Calculate target correct.
|
||||
analysis.TargetCorrect, err = c.calcElectraTargetCorrect(ctx, attestation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Calculate target timely.
|
||||
if version < spec.DataVersionDeneb {
|
||||
analysis.TargetTimely = attestation.Data.Slot >= slot-32
|
||||
} else {
|
||||
analysis.TargetTimely = true
|
||||
}
|
||||
}
|
||||
|
||||
return analysis, nil
|
||||
}
|
||||
|
||||
func (c *command) fetchParents(ctx context.Context, block *spec.VersionedSignedBeaconBlock, minSlot phase0.Slot) error {
|
||||
parentRoot, err := block.ParentRoot()
|
||||
if err != nil {
|
||||
@@ -212,7 +330,7 @@ func (c *command) fetchParents(ctx context.Context, block *spec.VersionedSignedB
|
||||
})
|
||||
if err != nil {
|
||||
var apiError *api.Error
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == http.StatusNotFound {
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == 404 {
|
||||
return errors.New("empty beacon block")
|
||||
}
|
||||
return err
|
||||
@@ -238,10 +356,10 @@ func (c *command) fetchParents(ctx context.Context, block *spec.VersionedSignedB
|
||||
}
|
||||
|
||||
func (c *command) processParentBlock(_ context.Context, block *spec.VersionedSignedBeaconBlock) error {
|
||||
attestations, err := block.Attestations()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// attestations, err := block.Attestations()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
slot, err := block.Slot()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -250,31 +368,40 @@ func (c *command) processParentBlock(_ context.Context, block *spec.VersionedSig
|
||||
fmt.Printf("Processing block %d\n", slot)
|
||||
}
|
||||
|
||||
for i, attestation := range attestations {
|
||||
root, err := attestation.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.priorAttestations[fmt.Sprintf("%#x", root)] = &attestationData{
|
||||
Block: slot,
|
||||
Index: i,
|
||||
}
|
||||
// TODO reinstate.
|
||||
// for i, attestation := range attestations {
|
||||
// root, err := attestation.HashTreeRoot()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// c.priorAttestations[fmt.Sprintf("%#x", root)] = &attestationData{
|
||||
// Block: slot,
|
||||
// Index: i,
|
||||
// }
|
||||
|
||||
data := attestation.Data
|
||||
_, exists := c.votes[data.Slot]
|
||||
if !exists {
|
||||
c.votes[data.Slot] = make(map[phase0.CommitteeIndex]bitfield.Bitlist)
|
||||
}
|
||||
_, exists = c.votes[data.Slot][data.Index]
|
||||
if !exists {
|
||||
c.votes[data.Slot][data.Index] = bitfield.NewBitlist(attestation.AggregationBits.Len())
|
||||
}
|
||||
for j := range attestation.AggregationBits.Len() {
|
||||
if attestation.AggregationBits.BitAt(j) {
|
||||
c.votes[data.Slot][data.Index].SetBitAt(j, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
// data, err := attestation.Data()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// aggregationBits, err := attestation.AggregationBits()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// _, exists := c.votes[data.Slot]
|
||||
// if !exists {
|
||||
// c.votes[data.Slot] = make(map[phase0.CommitteeIndex]bitfield.Bitlist)
|
||||
// }
|
||||
// _, exists = c.votes[data.Slot][data.Index]
|
||||
// if !exists {
|
||||
// c.votes[data.Slot][data.Index] = bitfield.NewBitlist(aggregationBits.Len())
|
||||
// }
|
||||
// for j := uint64(0); j < aggregationBits.Len(); j++ {
|
||||
// if aggregationBits.BitAt(j) {
|
||||
// c.votes[data.Slot][data.Index].SetBitAt(j, true)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -284,10 +411,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to beacon node")
|
||||
@@ -395,7 +523,7 @@ func (c *command) calcHeadCorrect(ctx context.Context, attestation *phase0.Attes
|
||||
})
|
||||
if err != nil {
|
||||
var apiError *api.Error
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == http.StatusNotFound {
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == 404 {
|
||||
if c.debug {
|
||||
fmt.Printf("No block available for slot %d, assuming not in canonical chain", slot)
|
||||
}
|
||||
@@ -433,7 +561,80 @@ func (c *command) calcTargetCorrect(ctx context.Context, attestation *phase0.Att
|
||||
})
|
||||
if err != nil {
|
||||
var apiError *api.Error
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == http.StatusNotFound {
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == 404 {
|
||||
if c.debug {
|
||||
fmt.Printf("No block available for slot %d, assuming not in canonical chain", slot)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
if response.Data == nil {
|
||||
// No block.
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
if !response.Data.Canonical {
|
||||
// Not canonical.
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
c.targetRoots[attestation.Data.Slot] = response.Data.Root
|
||||
root = response.Data.Root
|
||||
break
|
||||
}
|
||||
}
|
||||
return bytes.Equal(root[:], attestation.Data.Target.Root[:]), nil
|
||||
}
|
||||
|
||||
func (c *command) calcElectraHeadCorrect(ctx context.Context, attestation *electra.Attestation) (bool, error) {
|
||||
slot := attestation.Data.Slot
|
||||
root, exists := c.headRoots[slot]
|
||||
if !exists {
|
||||
for {
|
||||
response, err := c.blockHeadersProvider.BeaconBlockHeader(ctx, &api.BeaconBlockHeaderOpts{
|
||||
Block: fmt.Sprintf("%d", slot),
|
||||
})
|
||||
if err != nil {
|
||||
var apiError *api.Error
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == 404 {
|
||||
if c.debug {
|
||||
fmt.Printf("No block available for slot %d, assuming not in canonical chain", slot)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
if response.Data == nil {
|
||||
// No block.
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
if !response.Data.Canonical {
|
||||
// Not canonical.
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
c.headRoots[attestation.Data.Slot] = response.Data.Root
|
||||
root = response.Data.Root
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return bytes.Equal(root[:], attestation.Data.BeaconBlockRoot[:]), nil
|
||||
}
|
||||
|
||||
func (c *command) calcElectraTargetCorrect(ctx context.Context, attestation *electra.Attestation) (bool, error) {
|
||||
root, exists := c.targetRoots[attestation.Data.Slot]
|
||||
if !exists {
|
||||
// Start with first slot of the target epoch.
|
||||
slot := c.chainTime.FirstSlotOfEpoch(attestation.Data.Target.Epoch)
|
||||
for {
|
||||
response, err := c.blockHeadersProvider.BeaconBlockHeader(ctx, &api.BeaconBlockHeaderOpts{
|
||||
Block: fmt.Sprintf("%d", slot),
|
||||
})
|
||||
if err != nil {
|
||||
var apiError *api.Error
|
||||
if errors.As(err, &apiError) && apiError.StatusCode == 404 {
|
||||
if c.debug {
|
||||
fmt.Printf("No block available for slot %d, assuming not in canonical chain", slot)
|
||||
}
|
||||
|
||||
@@ -57,10 +57,11 @@ func input(ctx context.Context) (*dataIn, error) {
|
||||
|
||||
var err error
|
||||
data.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !data.quiet,
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !data.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -32,6 +31,7 @@ import (
|
||||
"github.com/attestantio/go-eth2-client/spec/bellatrix"
|
||||
"github.com/attestantio/go-eth2-client/spec/capella"
|
||||
"github.com/attestantio/go-eth2-client/spec/deneb"
|
||||
"github.com/attestantio/go-eth2-client/spec/electra"
|
||||
"github.com/attestantio/go-eth2-client/spec/phase0"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
@@ -55,7 +55,7 @@ func output(_ context.Context, data *dataOut) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func outputBlockGeneral(ctx context.Context,
|
||||
func outputBlockGeneral(_ context.Context,
|
||||
verbose bool,
|
||||
slot phase0.Slot,
|
||||
proposerIndex phase0.ValidatorIndex,
|
||||
@@ -83,7 +83,14 @@ func outputBlockGeneral(ctx context.Context,
|
||||
res.WriteString(fmt.Sprintf("Parent root: %#x\n", parentRoot))
|
||||
res.WriteString(fmt.Sprintf("State root: %#x\n", stateRoot))
|
||||
}
|
||||
res.WriteString(blockGraffiti(ctx, graffiti))
|
||||
if len(graffiti) > 0 && hex.EncodeToString(graffiti) != "0000000000000000000000000000000000000000000000000000000000000000" {
|
||||
graffiti = bytes.TrimRight(graffiti, "\u0000")
|
||||
if utf8.Valid(graffiti) {
|
||||
res.WriteString(fmt.Sprintf("Graffiti: %s\n", string(graffiti)))
|
||||
} else {
|
||||
res.WriteString(fmt.Sprintf("Graffiti: %#x\n", graffiti))
|
||||
}
|
||||
}
|
||||
|
||||
return res.String(), nil
|
||||
}
|
||||
@@ -198,6 +205,120 @@ func outputBlockAttesterSlashings(ctx context.Context, eth2Client eth2client.Ser
|
||||
return res.String(), nil
|
||||
}
|
||||
|
||||
func outputElectraBlockAttestations(ctx context.Context,
|
||||
eth2Client eth2client.Service,
|
||||
verbose bool,
|
||||
attestations []*electra.Attestation,
|
||||
) (
|
||||
string,
|
||||
error,
|
||||
) {
|
||||
res := strings.Builder{}
|
||||
|
||||
validatorCommittees := make(map[phase0.Slot]map[phase0.CommitteeIndex][]phase0.ValidatorIndex)
|
||||
res.WriteString(fmt.Sprintf("Attestations: %d\n", len(attestations)))
|
||||
if verbose {
|
||||
beaconCommitteesProvider, isProvider := eth2Client.(eth2client.BeaconCommitteesProvider)
|
||||
if isProvider {
|
||||
for i, att := range attestations {
|
||||
res.WriteString(fmt.Sprintf(" %d:\n", i))
|
||||
|
||||
// Fetch committees for this epoch if not already obtained.
|
||||
committees, exists := validatorCommittees[att.Data.Slot]
|
||||
if !exists {
|
||||
response, err := beaconCommitteesProvider.BeaconCommittees(ctx, &api.BeaconCommitteesOpts{
|
||||
State: fmt.Sprintf("%d", att.Data.Slot),
|
||||
})
|
||||
if err != nil {
|
||||
// Failed to get it; create an empty committee to stop us continually attempting to re-fetch.
|
||||
validatorCommittees[att.Data.Slot] = make(map[phase0.CommitteeIndex][]phase0.ValidatorIndex)
|
||||
} else {
|
||||
for _, beaconCommittee := range response.Data {
|
||||
if _, exists := validatorCommittees[beaconCommittee.Slot]; !exists {
|
||||
validatorCommittees[beaconCommittee.Slot] = make(map[phase0.CommitteeIndex][]phase0.ValidatorIndex)
|
||||
}
|
||||
validatorCommittees[beaconCommittee.Slot][beaconCommittee.Index] = beaconCommittee.Validators
|
||||
}
|
||||
}
|
||||
committees = validatorCommittees[att.Data.Slot]
|
||||
}
|
||||
|
||||
res.WriteString(fmt.Sprintf(" Committee index: %d\n", att.Data.Index))
|
||||
res.WriteString(fmt.Sprintf(" Attesters: %d/%d\n", att.AggregationBits.Count(), att.AggregationBits.Len()))
|
||||
res.WriteString(fmt.Sprintf(" Aggregation bits: %s\n", bitlistToString(att.AggregationBits)))
|
||||
if _, exists := committees[att.Data.Index]; exists {
|
||||
res.WriteString(fmt.Sprintf(" Attesting indices: %s\n", attestingIndices(att.AggregationBits, committees[att.Data.Index])))
|
||||
}
|
||||
res.WriteString(fmt.Sprintf(" Slot: %d\n", att.Data.Slot))
|
||||
res.WriteString(fmt.Sprintf(" Beacon block root: %#x\n", att.Data.BeaconBlockRoot))
|
||||
res.WriteString(fmt.Sprintf(" Source epoch: %d\n", att.Data.Source.Epoch))
|
||||
res.WriteString(fmt.Sprintf(" Source root: %#x\n", att.Data.Source.Root))
|
||||
res.WriteString(fmt.Sprintf(" Target epoch: %d\n", att.Data.Target.Epoch))
|
||||
res.WriteString(fmt.Sprintf(" Target root: %#x\n", att.Data.Target.Root))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.String(), nil
|
||||
}
|
||||
|
||||
func outputElectraBlockAttesterSlashings(ctx context.Context,
|
||||
eth2Client eth2client.Service,
|
||||
verbose bool,
|
||||
attesterSlashings []*electra.AttesterSlashing,
|
||||
) (
|
||||
string,
|
||||
error,
|
||||
) {
|
||||
res := strings.Builder{}
|
||||
|
||||
res.WriteString(fmt.Sprintf("Attester slashings: %d\n", len(attesterSlashings)))
|
||||
if verbose {
|
||||
for i, slashing := range attesterSlashings {
|
||||
// Say what was slashed.
|
||||
att1 := slashing.Attestation1
|
||||
att2 := slashing.Attestation2
|
||||
slashedIndices := intersection(att1.AttestingIndices, att2.AttestingIndices)
|
||||
if len(slashedIndices) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
res.WriteString(fmt.Sprintf(" %d:\n", i))
|
||||
res.WriteString(fmt.Sprintln(" Slashed validators:"))
|
||||
response, err := eth2Client.(eth2client.ValidatorsProvider).Validators(ctx, &api.ValidatorsOpts{
|
||||
State: "head",
|
||||
Indices: slashedIndices,
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to obtain beacon committees")
|
||||
}
|
||||
for k, v := range response.Data {
|
||||
res.WriteString(fmt.Sprintf(" %#x (%d)\n", v.Validator.PublicKey[:], k))
|
||||
}
|
||||
|
||||
// Say what caused the slashing.
|
||||
if att1.Data.Target.Epoch == att2.Data.Target.Epoch {
|
||||
res.WriteString(fmt.Sprintf(" Double voted for same target epoch (%d):\n", att1.Data.Target.Epoch))
|
||||
if !bytes.Equal(att1.Data.Target.Root[:], att2.Data.Target.Root[:]) {
|
||||
res.WriteString(fmt.Sprintf(" Attestation 1 target epoch root: %#x\n", att1.Data.Target.Root))
|
||||
res.WriteString(fmt.Sprintf(" Attestation 2target epoch root: %#x\n", att2.Data.Target.Root))
|
||||
}
|
||||
if !bytes.Equal(att1.Data.BeaconBlockRoot[:], att2.Data.BeaconBlockRoot[:]) {
|
||||
res.WriteString(fmt.Sprintf(" Attestation 1 beacon block root: %#x\n", att1.Data.BeaconBlockRoot))
|
||||
res.WriteString(fmt.Sprintf(" Attestation 2 beacon block root: %#x\n", att2.Data.BeaconBlockRoot))
|
||||
}
|
||||
} else if att1.Data.Source.Epoch < att2.Data.Source.Epoch &&
|
||||
att1.Data.Target.Epoch > att2.Data.Target.Epoch {
|
||||
res.WriteString(" Surround voted:\n")
|
||||
res.WriteString(fmt.Sprintf(" Attestation 1 vote: %d->%d\n", att1.Data.Source.Epoch, att1.Data.Target.Epoch))
|
||||
res.WriteString(fmt.Sprintf(" Attestation 2 vote: %d->%d\n", att2.Data.Source.Epoch, att2.Data.Target.Epoch))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.String(), nil
|
||||
}
|
||||
|
||||
func outputBlockDeposits(_ context.Context, verbose bool, deposits []*phase0.Deposit) (string, error) {
|
||||
res := strings.Builder{}
|
||||
|
||||
@@ -289,7 +410,7 @@ func outputBlockSyncAggregate(ctx context.Context, eth2Client eth2client.Service
|
||||
res.WriteString(fmt.Sprintf(" Error: failed to obtain sync committee: %v\n", err))
|
||||
} else {
|
||||
res.WriteString(" Contributing validators:")
|
||||
for i := range syncAggregate.SyncCommitteeBits.Len() {
|
||||
for i := uint64(0); i < syncAggregate.SyncCommitteeBits.Len(); i++ {
|
||||
if syncAggregate.SyncCommitteeBits.BitAt(i) {
|
||||
res.WriteString(fmt.Sprintf(" %d", syncCommitteeResponse.Data.Validators[i]))
|
||||
}
|
||||
@@ -511,6 +632,116 @@ func outputDenebBlockText(ctx context.Context,
|
||||
return res.String(), nil
|
||||
}
|
||||
|
||||
func outputElectraBlockText(ctx context.Context,
|
||||
data *dataOut,
|
||||
signedBlock *electra.SignedBeaconBlock,
|
||||
blobs []*deneb.BlobSidecar,
|
||||
) (
|
||||
string,
|
||||
error,
|
||||
) {
|
||||
if signedBlock == nil {
|
||||
return "", errors.New("no block supplied")
|
||||
}
|
||||
|
||||
body := signedBlock.Message.Body
|
||||
|
||||
res := strings.Builder{}
|
||||
|
||||
// General info.
|
||||
blockRoot, err := signedBlock.Message.HashTreeRoot()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to obtain block root")
|
||||
}
|
||||
bodyRoot, err := signedBlock.Message.Body.HashTreeRoot()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to generate body root")
|
||||
}
|
||||
|
||||
tmp, err := outputBlockGeneral(ctx,
|
||||
data.verbose,
|
||||
signedBlock.Message.Slot,
|
||||
signedBlock.Message.ProposerIndex,
|
||||
blockRoot,
|
||||
bodyRoot,
|
||||
signedBlock.Message.ParentRoot,
|
||||
signedBlock.Message.StateRoot,
|
||||
signedBlock.Message.Body.Graffiti[:],
|
||||
data.genesisTime,
|
||||
data.slotDuration,
|
||||
data.slotsPerEpoch)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
|
||||
// Eth1 data.
|
||||
if data.verbose {
|
||||
tmp, err := outputBlockETH1Data(ctx, body.ETH1Data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
}
|
||||
|
||||
// Sync aggregate.
|
||||
tmp, err = outputBlockSyncAggregate(ctx, data.eth2Client, data.verbose, signedBlock.Message.Body.SyncAggregate, phase0.Epoch(uint64(signedBlock.Message.Slot)/data.slotsPerEpoch))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
|
||||
// Attestations.
|
||||
tmp, err = outputElectraBlockAttestations(ctx, data.eth2Client, data.verbose, signedBlock.Message.Body.Attestations)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
|
||||
// Attester slashings.
|
||||
tmp, err = outputElectraBlockAttesterSlashings(ctx, data.eth2Client, data.verbose, signedBlock.Message.Body.AttesterSlashings)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
|
||||
res.WriteString(fmt.Sprintf("Proposer slashings: %d\n", len(body.ProposerSlashings)))
|
||||
// Add verbose proposer slashings.
|
||||
|
||||
tmp, err = outputBlockDeposits(ctx, data.verbose, signedBlock.Message.Body.Deposits)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
|
||||
// Voluntary exits.
|
||||
tmp, err = outputBlockVoluntaryExits(ctx, data.eth2Client, data.verbose, signedBlock.Message.Body.VoluntaryExits)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
|
||||
tmp, err = outputBlockBLSToExecutionChanges(ctx, data.eth2Client, data.verbose, signedBlock.Message.Body.BLSToExecutionChanges)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
|
||||
tmp, err = outputElectraBlockExecutionPayload(ctx, data.verbose, signedBlock.Message.Body.ExecutionPayload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
|
||||
tmp, err = outputElectraBlobInfo(ctx, data.verbose, signedBlock.Message.Body, blobs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
res.WriteString(tmp)
|
||||
|
||||
return res.String(), nil
|
||||
}
|
||||
|
||||
func outputBellatrixBlockText(ctx context.Context, data *dataOut, signedBlock *bellatrix.SignedBeaconBlock) (string, error) {
|
||||
if signedBlock == nil {
|
||||
return "", errors.New("no block supplied")
|
||||
@@ -791,7 +1022,7 @@ func outputCapellaBlockExecutionPayload(_ context.Context,
|
||||
res.WriteString(" Execution block number: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", payload.BlockNumber))
|
||||
baseFeePerGasBEBytes := make([]byte, len(payload.BaseFeePerGas))
|
||||
for i := range 32 {
|
||||
for i := 0; i < 32; i++ {
|
||||
baseFeePerGasBEBytes[i] = payload.BaseFeePerGas[32-1-i]
|
||||
}
|
||||
baseFeePerGas := new(big.Int).SetBytes(baseFeePerGasBEBytes)
|
||||
@@ -897,6 +1128,71 @@ func outputDenebBlockExecutionPayload(_ context.Context,
|
||||
return res.String(), nil
|
||||
}
|
||||
|
||||
func outputElectraBlockExecutionPayload(_ context.Context,
|
||||
verbose bool,
|
||||
payload *electra.ExecutionPayload,
|
||||
) (
|
||||
string,
|
||||
error,
|
||||
) {
|
||||
if payload == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// If the block number is 0 then we're before the merge.
|
||||
if payload.BlockNumber == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
res := strings.Builder{}
|
||||
if !verbose {
|
||||
res.WriteString("Execution block number: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", payload.BlockNumber))
|
||||
res.WriteString("Transactions: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", len(payload.Transactions)))
|
||||
} else {
|
||||
res.WriteString("Execution payload:\n")
|
||||
res.WriteString(" Execution block number: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", payload.BlockNumber))
|
||||
res.WriteString(" Base fee per gas: ")
|
||||
res.WriteString(string2eth.WeiToString(payload.BaseFeePerGas.ToBig(), true))
|
||||
res.WriteString("\n Block hash: ")
|
||||
res.WriteString(fmt.Sprintf("%#x\n", payload.BlockHash))
|
||||
res.WriteString(" Parent hash: ")
|
||||
res.WriteString(fmt.Sprintf("%#x\n", payload.ParentHash))
|
||||
res.WriteString(" Fee recipient: ")
|
||||
res.WriteString(payload.FeeRecipient.String())
|
||||
res.WriteString(" Gas limit: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", payload.GasLimit))
|
||||
res.WriteString(" Gas used: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", payload.GasUsed))
|
||||
res.WriteString(" Timestamp: ")
|
||||
res.WriteString(fmt.Sprintf("%s (%d)\n", time.Unix(int64(payload.Timestamp), 0).String(), payload.Timestamp))
|
||||
res.WriteString(" Prev RANDAO: ")
|
||||
res.WriteString(fmt.Sprintf("%#x\n", payload.PrevRandao))
|
||||
res.WriteString(" Receipts root: ")
|
||||
res.WriteString(fmt.Sprintf("%#x\n", payload.ReceiptsRoot))
|
||||
res.WriteString(" State root: ")
|
||||
res.WriteString(fmt.Sprintf("%#x\n", payload.StateRoot))
|
||||
res.WriteString(" Extra data: ")
|
||||
if utf8.Valid(payload.ExtraData) {
|
||||
res.WriteString(fmt.Sprintf("%s\n", string(payload.ExtraData)))
|
||||
} else {
|
||||
res.WriteString(fmt.Sprintf("%#x\n", payload.ExtraData))
|
||||
}
|
||||
res.WriteString(" Logs bloom: ")
|
||||
res.WriteString(fmt.Sprintf("%#x\n", payload.LogsBloom))
|
||||
res.WriteString(" Transactions: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", len(payload.Transactions)))
|
||||
res.WriteString(" Withdrawals: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", len(payload.Withdrawals)))
|
||||
res.WriteString(" Excess blob gas: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", payload.ExcessBlobGas))
|
||||
}
|
||||
|
||||
return res.String(), nil
|
||||
}
|
||||
|
||||
func outputDenebBlobInfo(_ context.Context,
|
||||
verbose bool,
|
||||
body *deneb.BeaconBlockBody,
|
||||
@@ -926,6 +1222,35 @@ func outputDenebBlobInfo(_ context.Context,
|
||||
return res.String(), nil
|
||||
}
|
||||
|
||||
func outputElectraBlobInfo(_ context.Context,
|
||||
verbose bool,
|
||||
body *electra.BeaconBlockBody,
|
||||
blobs []*deneb.BlobSidecar,
|
||||
) (
|
||||
string,
|
||||
error,
|
||||
) {
|
||||
if body == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if !verbose {
|
||||
return fmt.Sprintf("Blobs: %d\n", len(body.BlobKZGCommitments)), nil
|
||||
}
|
||||
|
||||
res := strings.Builder{}
|
||||
|
||||
for i, blob := range blobs {
|
||||
if i == 0 {
|
||||
res.WriteString("Blobs\n")
|
||||
}
|
||||
res.WriteString(fmt.Sprintf(" Index: %d\n", blob.Index))
|
||||
res.WriteString(fmt.Sprintf(" KZG commitment: %s\n", body.BlobKZGCommitments[i].String()))
|
||||
}
|
||||
|
||||
return res.String(), nil
|
||||
}
|
||||
|
||||
func outputBellatrixBlockExecutionPayload(_ context.Context,
|
||||
verbose bool,
|
||||
payload *bellatrix.ExecutionPayload,
|
||||
@@ -953,7 +1278,7 @@ func outputBellatrixBlockExecutionPayload(_ context.Context,
|
||||
res.WriteString(" Execution block number: ")
|
||||
res.WriteString(fmt.Sprintf("%d\n", payload.BlockNumber))
|
||||
baseFeePerGasBEBytes := make([]byte, len(payload.BaseFeePerGas))
|
||||
for i := range 32 {
|
||||
for i := 0; i < 32; i++ {
|
||||
baseFeePerGasBEBytes[i] = payload.BaseFeePerGas[32-1-i]
|
||||
}
|
||||
baseFeePerGas := new(big.Int).SetBytes(baseFeePerGasBEBytes)
|
||||
@@ -1016,7 +1341,7 @@ func bitlistToString(input bitfield.Bitlist) string {
|
||||
bits := int(input.Len())
|
||||
|
||||
res := ""
|
||||
for i := range bits {
|
||||
for i := 0; i < bits; i++ {
|
||||
if input.BitAt(uint64(i)) {
|
||||
res = fmt.Sprintf("%s✓", res)
|
||||
} else {
|
||||
@@ -1033,7 +1358,7 @@ func bitvectorToString(input bitfield.Bitvector512) string {
|
||||
bits := int(input.Len())
|
||||
|
||||
res := strings.Builder{}
|
||||
for i := range bits {
|
||||
for i := 0; i < bits; i++ {
|
||||
if input.BitAt(uint64(i)) {
|
||||
res.WriteString("✓")
|
||||
} else {
|
||||
@@ -1049,102 +1374,10 @@ func bitvectorToString(input bitfield.Bitvector512) string {
|
||||
func attestingIndices(input bitfield.Bitlist, indices []phase0.ValidatorIndex) string {
|
||||
bits := int(input.Len())
|
||||
res := ""
|
||||
for i := range bits {
|
||||
for i := 0; i < bits; i++ {
|
||||
if input.BitAt(uint64(i)) {
|
||||
res = fmt.Sprintf("%s%d ", res, indices[i])
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(res)
|
||||
}
|
||||
|
||||
func blockGraffiti(_ context.Context, graffiti []byte) string {
|
||||
if len(graffiti) == 0 || hex.EncodeToString(graffiti) == "0000000000000000000000000000000000000000000000000000000000000000" {
|
||||
// No graffiti.
|
||||
return ""
|
||||
}
|
||||
|
||||
// Remove any trailing null characters.
|
||||
graffiti = bytes.TrimRight(graffiti, "\u0000")
|
||||
|
||||
if !utf8.Valid(graffiti) {
|
||||
// Graffiti is not valid UTF-8, return hex.
|
||||
return fmt.Sprintf("Graffiti: %#x\n", graffiti)
|
||||
}
|
||||
|
||||
// See if there is client identification information present in the graffiti.
|
||||
// The client identification will always be the last entry in the graffiti, with a space beforehand.
|
||||
parts := bytes.Split(graffiti, []byte{' '})
|
||||
|
||||
// Consensus and execution client values come from
|
||||
// https://github.com/ethereum/execution-apis/blob/main/src/engine/identification.md
|
||||
consensusClients := map[string]string{
|
||||
"GR": "grandine",
|
||||
"LH": "lighthouse",
|
||||
"LS": "lodestar",
|
||||
"NB": "nimbus",
|
||||
"PM": "prysm",
|
||||
"TK": "teku",
|
||||
}
|
||||
consensusRegex := regexp.MustCompile(`(GR|LH|LS|NB|PM|TK)([0-9a-f]*)`)
|
||||
consensusData := consensusRegex.Find(parts[len(parts)-1])
|
||||
|
||||
executionClients := map[string]string{
|
||||
"BU": "besu",
|
||||
"EG": "erigon",
|
||||
"EJ": "ethereumJS",
|
||||
"GE": "go-ethereum",
|
||||
"NM": "nethermind",
|
||||
"RH": "reth",
|
||||
"TR": "trin-execution",
|
||||
}
|
||||
executionRegex := regexp.MustCompile(`(BU|EG|EJ|GE|NM|RH|TR)([0-9a-f]*)`)
|
||||
executionData := executionRegex.Find(parts[len(parts)-1])
|
||||
|
||||
if len(consensusData) == 0 && len(executionData) == 0 {
|
||||
// There is no identifier; return the graffiti as-is.
|
||||
return fmt.Sprintf("Graffiti: %s\n", string(graffiti))
|
||||
}
|
||||
|
||||
res := strings.Builder{}
|
||||
|
||||
truncatedGraffiti := bytes.Join(parts[0:len(parts)-1], []byte(" "))
|
||||
if len(truncatedGraffiti) > 0 {
|
||||
res.WriteString(fmt.Sprintf("Graffiti: %s\n", string(truncatedGraffiti)))
|
||||
}
|
||||
|
||||
if len(consensusData) > 0 {
|
||||
consensusClient := consensusData[0:2]
|
||||
consensusHash := ""
|
||||
if len(consensusData) > 2 {
|
||||
consensusHash = string(consensusData[2:])
|
||||
}
|
||||
|
||||
res.WriteString("Consensus client: ")
|
||||
res.WriteString(consensusClients[string(consensusClient)])
|
||||
if consensusHash != "" {
|
||||
res.WriteString(" (version hash ")
|
||||
res.WriteString(consensusHash)
|
||||
res.WriteString(")")
|
||||
}
|
||||
res.WriteString("\n")
|
||||
}
|
||||
|
||||
if len(executionData) > 0 {
|
||||
executionClient := executionData[0:2]
|
||||
executionHash := ""
|
||||
if len(executionData) > 2 {
|
||||
executionHash = string(executionData[2:])
|
||||
}
|
||||
|
||||
res.WriteString("Execution client: ")
|
||||
res.WriteString(executionClients[string(executionClient)])
|
||||
if executionHash != "" {
|
||||
res.WriteString(" (version hash ")
|
||||
res.WriteString(executionHash)
|
||||
res.WriteString(")")
|
||||
}
|
||||
res.WriteString("\n")
|
||||
}
|
||||
|
||||
return res.String()
|
||||
}
|
||||
|
||||
@@ -175,58 +175,3 @@ func TestOutputBlockETH1Data(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockGraffiti(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
graffiti []byte
|
||||
res string
|
||||
}{
|
||||
{
|
||||
name: "Empty",
|
||||
graffiti: []byte(""),
|
||||
},
|
||||
{
|
||||
name: "NoID",
|
||||
graffiti: []byte("No identifier"),
|
||||
res: "Graffiti: No identifier\n",
|
||||
},
|
||||
{
|
||||
name: "SingleClient",
|
||||
graffiti: []byte("Graffiti TK"),
|
||||
res: "Graffiti: Graffiti\nConsensus client: teku\n",
|
||||
},
|
||||
{
|
||||
name: "SingleClientImmediate",
|
||||
graffiti: []byte("TK"),
|
||||
res: "Consensus client: teku\n",
|
||||
},
|
||||
{
|
||||
name: "SingleClientAndHashImmediate",
|
||||
graffiti: []byte("TKa9f98260"),
|
||||
res: "Consensus client: teku (version hash a9f98260)\n",
|
||||
},
|
||||
{
|
||||
name: "DualClients",
|
||||
graffiti: []byte("LHGE"),
|
||||
res: "Consensus client: lighthouse\nExecution client: go-ethereum\n",
|
||||
},
|
||||
{
|
||||
name: "DualClientsReverseOrder",
|
||||
graffiti: []byte("GELH"),
|
||||
res: "Consensus client: lighthouse\nExecution client: go-ethereum\n",
|
||||
},
|
||||
{
|
||||
name: "DualClientsTruncatedHash",
|
||||
graffiti: []byte("Freedom To Transact TKa9f9NM220b"),
|
||||
res: "Graffiti: Freedom To Transact\nConsensus client: teku (version hash a9f9)\nExecution client: nethermind (version hash 220b)\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
res := blockGraffiti(context.Background(), test.graffiti)
|
||||
require.Equal(t, test.res, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
"github.com/attestantio/go-eth2-client/spec/bellatrix"
|
||||
"github.com/attestantio/go-eth2-client/spec/capella"
|
||||
"github.com/attestantio/go-eth2-client/spec/deneb"
|
||||
"github.com/attestantio/go-eth2-client/spec/electra"
|
||||
"github.com/attestantio/go-eth2-client/spec/phase0"
|
||||
"github.com/pkg/errors"
|
||||
standardchaintime "github.com/wealdtech/ethdo/services/chaintime/standard"
|
||||
@@ -114,23 +115,27 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
|
||||
return nil, errors.Wrap(err, "failed to output block")
|
||||
}
|
||||
case spec.DataVersionDeneb:
|
||||
var blobSidecars []*deneb.BlobSidecar
|
||||
kzgCommitments, err := block.BlobKZGCommitments()
|
||||
blobSidecarsResponse, err := results.eth2Client.(eth2client.BlobSidecarsProvider).BlobSidecars(ctx, &api.BlobSidecarsOpts{
|
||||
Block: data.blockID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(kzgCommitments) > 0 {
|
||||
blobSidecarsResponse, err := results.eth2Client.(eth2client.BlobSidecarsProvider).BlobSidecars(ctx, &api.BlobSidecarsOpts{
|
||||
Block: data.blockID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain blob sidecars")
|
||||
}
|
||||
blobSidecars = blobSidecarsResponse.Data
|
||||
return nil, errors.Wrap(err, "failed to obtain blob sidecars")
|
||||
}
|
||||
blobSidecars := blobSidecarsResponse.Data
|
||||
if err := outputDenebBlock(ctx, data.jsonOutput, data.sszOutput, block.Deneb, blobSidecars); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to output block")
|
||||
}
|
||||
case spec.DataVersionElectra:
|
||||
blobSidecarsResponse, err := results.eth2Client.(eth2client.BlobSidecarsProvider).BlobSidecars(ctx, &api.BlobSidecarsOpts{
|
||||
Block: data.blockID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain blob sidecars")
|
||||
}
|
||||
blobSidecars := blobSidecarsResponse.Data
|
||||
if err := outputElectraBlock(ctx, data.jsonOutput, data.sszOutput, block.Electra, blobSidecars); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to output block")
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("unknown block version")
|
||||
}
|
||||
@@ -187,25 +192,21 @@ func headEventHandler(event *apiv1.Event) {
|
||||
case spec.DataVersionCapella:
|
||||
err = outputCapellaBlock(ctx, jsonOutput, sszOutput, block.Capella)
|
||||
case spec.DataVersionDeneb:
|
||||
var blobSidecars []*deneb.BlobSidecar
|
||||
var kzgCommitments []deneb.KZGCommitment
|
||||
kzgCommitments, err = block.BlobKZGCommitments()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain KZG commitments: %v\n", err)
|
||||
return
|
||||
var blobSidecarsResponse *api.Response[[]*deneb.BlobSidecar]
|
||||
blobSidecarsResponse, err = results.eth2Client.(eth2client.BlobSidecarsProvider).BlobSidecars(ctx, &api.BlobSidecarsOpts{
|
||||
Block: blockID,
|
||||
})
|
||||
if err == nil {
|
||||
err = outputDenebBlock(context.Background(), jsonOutput, sszOutput, block.Deneb, blobSidecarsResponse.Data)
|
||||
}
|
||||
if len(kzgCommitments) > 0 {
|
||||
var blobSidecarsResponse *api.Response[[]*deneb.BlobSidecar]
|
||||
blobSidecarsResponse, err = results.eth2Client.(eth2client.BlobSidecarsProvider).BlobSidecars(ctx, &api.BlobSidecarsOpts{
|
||||
Block: blockID,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain blob sidecars: %v\n", err)
|
||||
return
|
||||
}
|
||||
blobSidecars = blobSidecarsResponse.Data
|
||||
case spec.DataVersionElectra:
|
||||
var blobSidecarsResponse *api.Response[[]*deneb.BlobSidecar]
|
||||
blobSidecarsResponse, err = results.eth2Client.(eth2client.BlobSidecarsProvider).BlobSidecars(ctx, &api.BlobSidecarsOpts{
|
||||
Block: blockID,
|
||||
})
|
||||
if err == nil {
|
||||
err = outputElectraBlock(context.Background(), jsonOutput, sszOutput, block.Electra, blobSidecarsResponse.Data)
|
||||
}
|
||||
err = outputDenebBlock(context.Background(), jsonOutput, sszOutput, block.Deneb, blobSidecars)
|
||||
default:
|
||||
err = errors.New("unknown block version")
|
||||
}
|
||||
@@ -338,6 +339,35 @@ func outputDenebBlock(ctx context.Context,
|
||||
return nil
|
||||
}
|
||||
|
||||
func outputElectraBlock(ctx context.Context,
|
||||
jsonOutput bool,
|
||||
sszOutput bool,
|
||||
signedBlock *electra.SignedBeaconBlock,
|
||||
blobs []*deneb.BlobSidecar,
|
||||
) error {
|
||||
switch {
|
||||
case jsonOutput:
|
||||
data, err := json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate JSON")
|
||||
}
|
||||
fmt.Printf("%s\n", string(data))
|
||||
case sszOutput:
|
||||
data, err := signedBlock.MarshalSSZ()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate SSZ")
|
||||
}
|
||||
fmt.Printf("%x\n", data)
|
||||
default:
|
||||
data, err := outputElectraBlockText(ctx, results, signedBlock, blobs)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate text")
|
||||
}
|
||||
fmt.Print(data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func timeToBlockID(ctx context.Context, eth2Client eth2client.Service, input string) (string, error) {
|
||||
var timestamp time.Time
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Input.
|
||||
xepoch string
|
||||
@@ -64,10 +65,11 @@ type vote struct {
|
||||
|
||||
func newCommand(_ context.Context) (*command, error) {
|
||||
c := &command{
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
json: viper.GetBool("json"),
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
json: viper.GetBool("json"),
|
||||
customSpecSupport: viper.GetBool("custom-spec"),
|
||||
}
|
||||
|
||||
// Timeout.
|
||||
|
||||
@@ -97,6 +97,9 @@ func (c *command) process(ctx context.Context) error {
|
||||
case spec.DataVersionDeneb:
|
||||
c.incumbent = state.Deneb.ETH1Data
|
||||
c.eth1DataVotes = state.Deneb.ETH1DataVotes
|
||||
case spec.DataVersionElectra:
|
||||
c.incumbent = state.Electra.ETH1Data
|
||||
c.eth1DataVotes = state.Electra.ETH1DataVotes
|
||||
default:
|
||||
return fmt.Errorf("unhandled beacon state version %v", state.Version)
|
||||
}
|
||||
@@ -124,10 +127,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to beacon node")
|
||||
|
||||
@@ -33,6 +33,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Input.
|
||||
epoch string
|
||||
@@ -49,10 +50,11 @@ type command struct {
|
||||
|
||||
func newCommand(_ context.Context) (*command, error) {
|
||||
c := &command{
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
json: viper.GetBool("json"),
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
json: viper.GetBool("json"),
|
||||
customSpecSupport: viper.GetBool("custom-spec"),
|
||||
}
|
||||
|
||||
// Timeout.
|
||||
|
||||
@@ -62,10 +62,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to beacon node")
|
||||
|
||||
@@ -31,6 +31,7 @@ type dataIn struct {
|
||||
// Input
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
timestamp string
|
||||
slot string
|
||||
epoch string
|
||||
@@ -73,6 +74,7 @@ func input(_ context.Context) (*dataIn, error) {
|
||||
|
||||
data.connection = viper.GetString("connection")
|
||||
data.allowInsecureConnections = viper.GetBool("allow-insecure-connections")
|
||||
data.customSpecSupport = viper.GetBool("custom-spec")
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
@@ -31,10 +31,11 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
|
||||
}
|
||||
|
||||
eth2Client, err := util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: data.connection,
|
||||
Timeout: data.timeout,
|
||||
AllowInsecure: data.allowInsecureConnections,
|
||||
LogFallback: !data.quiet,
|
||||
Address: data.connection,
|
||||
Timeout: data.timeout,
|
||||
AllowInsecure: data.allowInsecureConnections,
|
||||
CustomSpecSupport: data.customSpecSupport,
|
||||
LogFallback: !data.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to connect to Ethereum 2 beacon node")
|
||||
|
||||
@@ -33,6 +33,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Input.
|
||||
data string
|
||||
@@ -60,9 +61,10 @@ type command struct {
|
||||
|
||||
func newCommand(_ context.Context) (*command, error) {
|
||||
c := &command{
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
customSpecSupport: viper.GetBool("custom-spec"),
|
||||
}
|
||||
|
||||
// Timeout.
|
||||
|
||||
@@ -87,10 +87,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to beacon node")
|
||||
@@ -221,7 +222,7 @@ func (c *command) confirmContributionSignature(ctx context.Context) error {
|
||||
|
||||
subCommittee := c.syncCommittee.ValidatorAggregates[c.item.Message.Contribution.SubcommitteeIndex]
|
||||
includedIndices := make([]phase0.ValidatorIndex, 0, len(subCommittee))
|
||||
for i := range c.item.Message.Contribution.AggregationBits.Len() {
|
||||
for i := uint64(0); i < c.item.Message.Contribution.AggregationBits.Len(); i++ {
|
||||
if c.item.Message.Contribution.AggregationBits.BitAt(i) {
|
||||
includedIndices = append(includedIndices, subCommittee[int(i)])
|
||||
}
|
||||
|
||||
@@ -40,10 +40,11 @@ In quiet mode this will return 0 if the chain information can be obtained, other
|
||||
ctx := context.Background()
|
||||
|
||||
eth2Client, err := util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
})
|
||||
errCheck(err, "Failed to connect to Ethereum 2 beacon node")
|
||||
|
||||
|
||||
@@ -41,10 +41,11 @@ In quiet mode this will return 0 if the chain specification can be obtained, oth
|
||||
ctx := context.Background()
|
||||
|
||||
eth2Client, err := util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
})
|
||||
errCheck(err, "Failed to connect to Ethereum consensus node")
|
||||
|
||||
|
||||
@@ -44,10 +44,11 @@ In quiet mode this will return 0 if the chain status can be obtained, otherwise
|
||||
ctx := context.Background()
|
||||
|
||||
eth2Client, err := util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
})
|
||||
errCheck(err, "Failed to connect to Ethereum 2 beacon node")
|
||||
|
||||
|
||||
@@ -29,12 +29,12 @@ func init() {
|
||||
RootCmd.AddCommand(epochCmd)
|
||||
}
|
||||
|
||||
func epochFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().String("epoch", "", "the epoch for which to obtain information (default current, can be 'current', 'last' or a number)")
|
||||
func epochFlags(_ *cobra.Command) {
|
||||
epochSummaryCmd.Flags().String("epoch", "", "the epoch for which to obtain information (default current, can be 'current', 'last' or a number)")
|
||||
}
|
||||
|
||||
func epochBindings(cmd *cobra.Command) {
|
||||
if err := viper.BindPFlag("validators", cmd.Flags().Lookup("validators")); err != nil {
|
||||
if err := viper.BindPFlag("epoch", cmd.Flags().Lookup("epoch")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,13 +34,12 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Operation.
|
||||
epoch string
|
||||
validatorsStr []string
|
||||
validators map[phase0.ValidatorIndex]struct{}
|
||||
stream bool
|
||||
jsonOutput bool
|
||||
epoch string
|
||||
stream bool
|
||||
jsonOutput bool
|
||||
|
||||
// Data access.
|
||||
eth2Client eth2client.Service
|
||||
@@ -60,61 +59,45 @@ type command struct {
|
||||
}
|
||||
|
||||
type epochSummary struct {
|
||||
Epoch phase0.Epoch `json:"epoch"`
|
||||
FirstSlot phase0.Slot `json:"first_slot"`
|
||||
LastSlot phase0.Slot `json:"last_slot"`
|
||||
Blocks int `json:"blocks"`
|
||||
Proposals []*epochProposal `json:"proposals"`
|
||||
SyncCommitteeValidators int `json:"sync_committee_validators"`
|
||||
SyncCommittee []*epochSyncCommittee `json:"sync_committees"`
|
||||
ActiveValidators int `json:"active_validators"`
|
||||
ParticipatingValidators int `json:"participating_validators"`
|
||||
HeadCorrectValidators int `json:"head_correct_validators"`
|
||||
HeadTimelyValidators int `json:"head_timely_validators"`
|
||||
SourceTimelyValidators int `json:"source_timely_validators"`
|
||||
TargetCorrectValidators int `json:"target_correct_validators"`
|
||||
TargetTimelyValidators int `json:"target_timely_validators"`
|
||||
NonParticipatingValidators []*attestingValidator `json:"nonparticipating_validators"`
|
||||
NonHeadCorrectValidators []*attestingValidator `json:"nonheadcorrect_validators"`
|
||||
NonHeadTimelyValidators []*attestingValidator `json:"nonheadtimely_validators"`
|
||||
NonTargetCorrectValidators []*attestingValidator `json:"nontargetcorrect_validators"`
|
||||
NonSourceTimelyValidators []*attestingValidator `json:"nonsourcetimely_validators"`
|
||||
Blobs int `json:"blobs"`
|
||||
Epoch phase0.Epoch `json:"epoch"`
|
||||
FirstSlot phase0.Slot `json:"first_slot"`
|
||||
LastSlot phase0.Slot `json:"last_slot"`
|
||||
Proposals []*epochProposal `json:"proposals"`
|
||||
SyncCommittee []*epochSyncCommittee `json:"sync_committees"`
|
||||
ActiveValidators int `json:"active_validators"`
|
||||
ParticipatingValidators int `json:"participating_validators"`
|
||||
HeadCorrectValidators int `json:"head_correct_validators"`
|
||||
HeadTimelyValidators int `json:"head_timely_validators"`
|
||||
SourceTimelyValidators int `json:"source_timely_validators"`
|
||||
TargetCorrectValidators int `json:"target_correct_validators"`
|
||||
TargetTimelyValidators int `json:"target_timely_validators"`
|
||||
NonParticipatingValidators []*nonParticipatingValidator `json:"nonparticipating_validators"`
|
||||
Blobs int `json:"blobs"`
|
||||
}
|
||||
|
||||
type epochProposal struct {
|
||||
ValidatorIndex phase0.ValidatorIndex `json:"validator_index"`
|
||||
Slot phase0.Slot `json:"slot"`
|
||||
Block bool `json:"block"`
|
||||
Slot phase0.Slot `json:"slot"`
|
||||
Proposer phase0.ValidatorIndex `json:"proposer"`
|
||||
Block bool `json:"block"`
|
||||
}
|
||||
|
||||
type epochSyncCommittee struct {
|
||||
ValidatorIndex phase0.ValidatorIndex `json:"validator_index"`
|
||||
Missed int `json:"missed"`
|
||||
MissedSlots []phase0.Slot `json:"missed_slots"`
|
||||
Index phase0.ValidatorIndex `json:"index"`
|
||||
Missed int `json:"missed"`
|
||||
}
|
||||
|
||||
type attestingValidator struct {
|
||||
Validator phase0.ValidatorIndex `json:"validator_index"`
|
||||
Slot phase0.Slot `json:"slot"`
|
||||
Committee phase0.CommitteeIndex `json:"committee_index"`
|
||||
HeadVote *phase0.Root `json:"head_vote,omitempty"`
|
||||
Head *phase0.Root `json:"head,omitempty"`
|
||||
TargetVote *phase0.Root `json:"target_vote,omitempty"`
|
||||
Target *phase0.Root `json:"target,omitempty"`
|
||||
InclusionSlot phase0.Slot `json:"inclusion_slot,omitempty"`
|
||||
type nonParticipatingValidator struct {
|
||||
Validator phase0.ValidatorIndex `json:"validator_index"`
|
||||
Slot phase0.Slot `json:"slot"`
|
||||
Committee phase0.CommitteeIndex `json:"committee_index"`
|
||||
}
|
||||
|
||||
func newCommand(_ context.Context) (*command, error) {
|
||||
c := &command{
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
validatorsStr: viper.GetStringSlice("validators"),
|
||||
summary: &epochSummary{
|
||||
Proposals: make([]*epochProposal, 0),
|
||||
},
|
||||
validators: make(map[phase0.ValidatorIndex]struct{}),
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
summary: &epochSummary{},
|
||||
blocksCache: make(map[string]*spec.VersionedSignedBeaconBlock),
|
||||
}
|
||||
|
||||
@@ -126,6 +109,7 @@ func newCommand(_ context.Context) (*command, error) {
|
||||
|
||||
c.connection = viper.GetString("connection")
|
||||
c.allowInsecureConnections = viper.GetBool("allow-insecure-connections")
|
||||
c.customSpecSupport = viper.GetBool("custom-spec")
|
||||
|
||||
c.epoch = viper.GetString("epoch")
|
||||
c.stream = viper.GetBool("stream")
|
||||
|
||||
@@ -50,7 +50,7 @@ func (c *command) outputTxt(_ context.Context) (string, error) {
|
||||
missedProposals := make([]string, 0, len(c.summary.Proposals))
|
||||
for _, proposal := range c.summary.Proposals {
|
||||
if !proposal.Block {
|
||||
missedProposals = append(missedProposals, fmt.Sprintf("\n Slot %d (validator %d)", proposal.Slot, proposal.ValidatorIndex))
|
||||
missedProposals = append(missedProposals, fmt.Sprintf("\n Slot %d (validator %d)", proposal.Slot, proposal.Proposer))
|
||||
} else {
|
||||
proposedBlocks++
|
||||
}
|
||||
@@ -64,7 +64,7 @@ func (c *command) outputTxt(_ context.Context) (string, error) {
|
||||
builder.WriteString("\n Slot ")
|
||||
builder.WriteString(fmt.Sprintf("%d (%d/%d)", proposal.Slot, uint64(proposal.Slot)%uint64(len(c.summary.Proposals)), len(c.summary.Proposals)))
|
||||
builder.WriteString(" validator ")
|
||||
builder.WriteString(fmt.Sprintf("%d", proposal.ValidatorIndex))
|
||||
builder.WriteString(fmt.Sprintf("%d", proposal.Proposer))
|
||||
builder.WriteString(" not proposed or not included")
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ func (c *command) outputTxt(_ context.Context) (string, error) {
|
||||
if c.verbose {
|
||||
for _, syncCommittee := range c.summary.SyncCommittee {
|
||||
builder.WriteString("\n Validator ")
|
||||
builder.WriteString(fmt.Sprintf("%d", syncCommittee.ValidatorIndex))
|
||||
builder.WriteString(fmt.Sprintf("%d", syncCommittee.Index))
|
||||
builder.WriteString(" included ")
|
||||
builder.WriteString(fmt.Sprintf("%d/%d", proposedBlocks-syncCommittee.Missed, proposedBlocks))
|
||||
builder.WriteString(fmt.Sprintf(" (%0.2f%%)", 100.0*float64(proposedBlocks-syncCommittee.Missed)/float64(proposedBlocks)))
|
||||
|
||||
@@ -43,14 +43,6 @@ func (c *command) process(ctx context.Context) error {
|
||||
c.summary.FirstSlot = c.chainTime.FirstSlotOfEpoch(c.summary.Epoch)
|
||||
c.summary.LastSlot = c.chainTime.FirstSlotOfEpoch(c.summary.Epoch+1) - 1
|
||||
|
||||
validators, err := util.ParseValidators(ctx, c.validatorsProvider, c.validatorsStr, "head")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse validators")
|
||||
}
|
||||
for _, validator := range validators {
|
||||
c.validators[validator.Index] = struct{}{}
|
||||
}
|
||||
|
||||
if err := c.processProposerDuties(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -60,7 +52,6 @@ func (c *command) process(ctx context.Context) error {
|
||||
if err := c.processSyncCommitteeDuties(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.processBlobs(ctx)
|
||||
}
|
||||
|
||||
@@ -78,20 +69,10 @@ func (c *command) processProposerDuties(ctx context.Context) error {
|
||||
return errors.Wrap(err, fmt.Sprintf("failed to obtain block for slot %d", duty.Slot))
|
||||
}
|
||||
present := block != nil
|
||||
if present {
|
||||
c.summary.Blocks++
|
||||
}
|
||||
|
||||
_, exists := c.validators[duty.ValidatorIndex]
|
||||
if len(c.validators) > 0 && !exists {
|
||||
// Not one of ours.
|
||||
continue
|
||||
}
|
||||
|
||||
c.summary.Proposals = append(c.summary.Proposals, &epochProposal{
|
||||
Slot: duty.Slot,
|
||||
ValidatorIndex: duty.ValidatorIndex,
|
||||
Block: present,
|
||||
Slot: duty.Slot,
|
||||
Proposer: duty.ValidatorIndex,
|
||||
Block: present,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -99,25 +80,14 @@ func (c *command) processProposerDuties(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (c *command) activeValidators(ctx context.Context) (map[phase0.ValidatorIndex]*apiv1.Validator, error) {
|
||||
validatorIndices := make([]phase0.ValidatorIndex, 0, len(c.validators))
|
||||
for validator := range c.validators {
|
||||
validatorIndices = append(validatorIndices, validator)
|
||||
}
|
||||
|
||||
response, err := c.validatorsProvider.Validators(ctx, &api.ValidatorsOpts{
|
||||
State: "head",
|
||||
Indices: validatorIndices,
|
||||
State: fmt.Sprintf("%d", c.chainTime.FirstSlotOfEpoch(c.summary.Epoch)),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain validators for epoch")
|
||||
}
|
||||
activeValidators := make(map[phase0.ValidatorIndex]*apiv1.Validator)
|
||||
for _, validator := range response.Data {
|
||||
_, exists := c.validators[validator.Index]
|
||||
if len(c.validators) > 0 && !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
if validator.Validator.ActivationEpoch <= c.summary.Epoch && validator.Validator.ExitEpoch > c.summary.Epoch {
|
||||
activeValidators[validator.Index] = validator
|
||||
}
|
||||
@@ -142,45 +112,20 @@ func (c *command) processAttesterDuties(ctx context.Context) error {
|
||||
lastSlot = c.chainTime.CurrentSlot()
|
||||
}
|
||||
|
||||
participatingValidators, headCorrectValidators, headTimelyValidators, sourceTimelyValidators, targetCorrectValidators, targetTimelyValidators, participations, err := c.processSlots(ctx, firstSlot, lastSlot)
|
||||
var votes map[phase0.ValidatorIndex]struct{}
|
||||
var participations map[phase0.ValidatorIndex]*nonParticipatingValidator
|
||||
c.summary.ParticipatingValidators, c.summary.HeadCorrectValidators, c.summary.HeadTimelyValidators, c.summary.SourceTimelyValidators, c.summary.TargetCorrectValidators, c.summary.TargetTimelyValidators, votes, participations, err = c.processSlots(ctx, firstSlot, lastSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.summary.ParticipatingValidators = len(participatingValidators)
|
||||
c.summary.HeadCorrectValidators = len(headCorrectValidators)
|
||||
c.summary.HeadTimelyValidators = len(headTimelyValidators)
|
||||
c.summary.SourceTimelyValidators = len(sourceTimelyValidators)
|
||||
c.summary.TargetCorrectValidators = len(targetCorrectValidators)
|
||||
c.summary.TargetTimelyValidators = len(targetTimelyValidators)
|
||||
|
||||
c.summary.NonParticipatingValidators = make([]*attestingValidator, 0, len(activeValidators)-len(participatingValidators))
|
||||
c.summary.NonParticipatingValidators = make([]*nonParticipatingValidator, 0, len(activeValidators)-len(votes))
|
||||
for activeValidatorIndex := range activeValidators {
|
||||
if _, exists := participatingValidators[activeValidatorIndex]; !exists {
|
||||
if _, exists := votes[activeValidatorIndex]; !exists {
|
||||
if _, exists := participations[activeValidatorIndex]; exists {
|
||||
c.summary.NonParticipatingValidators = append(c.summary.NonParticipatingValidators, participations[activeValidatorIndex])
|
||||
}
|
||||
}
|
||||
if _, exists := headCorrectValidators[activeValidatorIndex]; !exists {
|
||||
if _, exists := participations[activeValidatorIndex]; exists {
|
||||
c.summary.NonHeadCorrectValidators = append(c.summary.NonHeadCorrectValidators, participations[activeValidatorIndex])
|
||||
}
|
||||
}
|
||||
if _, exists := headTimelyValidators[activeValidatorIndex]; !exists {
|
||||
if _, exists := participations[activeValidatorIndex]; exists {
|
||||
c.summary.NonHeadTimelyValidators = append(c.summary.NonHeadTimelyValidators, participations[activeValidatorIndex])
|
||||
}
|
||||
}
|
||||
if _, exists := targetCorrectValidators[activeValidatorIndex]; !exists {
|
||||
if _, exists := participations[activeValidatorIndex]; exists {
|
||||
c.summary.NonTargetCorrectValidators = append(c.summary.NonTargetCorrectValidators, participations[activeValidatorIndex])
|
||||
}
|
||||
}
|
||||
if _, exists := sourceTimelyValidators[activeValidatorIndex]; !exists {
|
||||
if _, exists := participations[activeValidatorIndex]; exists {
|
||||
c.summary.NonSourceTimelyValidators = append(c.summary.NonSourceTimelyValidators, participations[activeValidatorIndex])
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(c.summary.NonParticipatingValidators, func(i int, j int) bool {
|
||||
if c.summary.NonParticipatingValidators[i].Slot != c.summary.NonParticipatingValidators[j].Slot {
|
||||
@@ -195,18 +140,18 @@ func (c *command) processAttesterDuties(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (c *command) processSlots(ctx context.Context,
|
||||
firstSlot phase0.Slot,
|
||||
lastSlot phase0.Slot,
|
||||
) (
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
map[phase0.ValidatorIndex]struct{},
|
||||
map[phase0.ValidatorIndex]struct{},
|
||||
map[phase0.ValidatorIndex]struct{},
|
||||
map[phase0.ValidatorIndex]struct{},
|
||||
map[phase0.ValidatorIndex]struct{},
|
||||
map[phase0.ValidatorIndex]struct{},
|
||||
map[phase0.ValidatorIndex]*attestingValidator,
|
||||
map[phase0.ValidatorIndex]*nonParticipatingValidator,
|
||||
error,
|
||||
) {
|
||||
votes := make(map[phase0.ValidatorIndex]struct{})
|
||||
@@ -216,7 +161,7 @@ func (c *command) processSlots(ctx context.Context,
|
||||
targetCorrects := make(map[phase0.ValidatorIndex]struct{})
|
||||
targetTimelys := make(map[phase0.ValidatorIndex]struct{})
|
||||
allCommittees := make(map[phase0.Slot]map[phase0.CommitteeIndex][]phase0.ValidatorIndex)
|
||||
participations := make(map[phase0.ValidatorIndex]*attestingValidator)
|
||||
participations := make(map[phase0.ValidatorIndex]*nonParticipatingValidator)
|
||||
|
||||
// Need a cache of beacon block headers to reduce lookup times.
|
||||
headersCache := util.NewBeaconBlockHeaderCache(c.beaconBlockHeadersProvider)
|
||||
@@ -224,7 +169,7 @@ func (c *command) processSlots(ctx context.Context,
|
||||
for slot := firstSlot; slot <= lastSlot; slot++ {
|
||||
block, err := c.fetchBlock(ctx, fmt.Sprintf("%d", slot))
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, nil, errors.Wrap(err, fmt.Sprintf("failed to obtain block for slot %d", slot))
|
||||
return 0, 0, 0, 0, 0, 0, nil, nil, errors.Wrap(err, fmt.Sprintf("failed to obtain block for slot %d", slot))
|
||||
}
|
||||
if block == nil {
|
||||
// No block at this slot; that's fine.
|
||||
@@ -232,118 +177,90 @@ func (c *command) processSlots(ctx context.Context,
|
||||
}
|
||||
slot, err := block.Slot()
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, nil, err
|
||||
return 0, 0, 0, 0, 0, 0, nil, nil, err
|
||||
}
|
||||
attestations, err := block.Attestations()
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, nil, err
|
||||
return 0, 0, 0, 0, 0, 0, nil, nil, err
|
||||
}
|
||||
for _, attestation := range attestations {
|
||||
if attestation.Data.Slot < c.chainTime.FirstSlotOfEpoch(c.summary.Epoch) || attestation.Data.Slot >= c.chainTime.FirstSlotOfEpoch(c.summary.Epoch+1) {
|
||||
attestationData, err := attestation.Data()
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, 0, 0, nil, nil, errors.Wrap(err, fmt.Sprintf("failed to obtain attestation data for slot %d", slot))
|
||||
}
|
||||
if attestationData.Slot < c.chainTime.FirstSlotOfEpoch(c.summary.Epoch) || attestationData.Slot >= c.chainTime.FirstSlotOfEpoch(c.summary.Epoch+1) {
|
||||
// Outside of this epoch's range.
|
||||
continue
|
||||
}
|
||||
slotCommittees, exists := allCommittees[attestation.Data.Slot]
|
||||
slotCommittees, exists := allCommittees[attestationData.Slot]
|
||||
if !exists {
|
||||
response, err := c.beaconCommitteesProvider.BeaconCommittees(ctx, &api.BeaconCommitteesOpts{
|
||||
State: fmt.Sprintf("%d", attestation.Data.Slot),
|
||||
State: fmt.Sprintf("%d", attestationData.Slot),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, nil, errors.Wrap(err, fmt.Sprintf("failed to obtain committees for slot %d", attestation.Data.Slot))
|
||||
return 0, 0, 0, 0, 0, 0, nil, nil, errors.Wrap(err, fmt.Sprintf("failed to obtain committees for slot %d", attestationData.Slot))
|
||||
}
|
||||
for _, beaconCommittee := range response.Data {
|
||||
if _, exists := allCommittees[beaconCommittee.Slot]; !exists {
|
||||
allCommittees[beaconCommittee.Slot] = make(map[phase0.CommitteeIndex][]phase0.ValidatorIndex)
|
||||
}
|
||||
|
||||
allCommittees[beaconCommittee.Slot][beaconCommittee.Index] = beaconCommittee.Validators
|
||||
|
||||
for _, index := range beaconCommittee.Validators {
|
||||
if len(c.validators) > 0 {
|
||||
if _, exists := c.validators[index]; !exists {
|
||||
// Not one of our validators.
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if _, exists := participations[index]; !exists {
|
||||
participations[index] = &attestingValidator{
|
||||
Validator: index,
|
||||
Slot: beaconCommittee.Slot,
|
||||
Committee: beaconCommittee.Index,
|
||||
}
|
||||
participations[index] = &nonParticipatingValidator{
|
||||
Validator: index,
|
||||
Slot: beaconCommittee.Slot,
|
||||
Committee: beaconCommittee.Index,
|
||||
}
|
||||
}
|
||||
}
|
||||
slotCommittees = allCommittees[attestation.Data.Slot]
|
||||
slotCommittees = allCommittees[attestationData.Slot]
|
||||
}
|
||||
committee := slotCommittees[attestation.Data.Index]
|
||||
committee := slotCommittees[attestationData.Index]
|
||||
|
||||
inclusionDistance := slot - attestation.Data.Slot
|
||||
|
||||
head, err := util.AttestationHead(ctx, headersCache, attestation)
|
||||
inclusionDistance := slot - attestationData.Slot
|
||||
headCorrect, err := util.AttestationHeadCorrect(ctx, headersCache, attestationData)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, nil, err
|
||||
return 0, 0, 0, 0, 0, 0, nil, nil, err
|
||||
}
|
||||
headCorrect, err := util.AttestationHeadCorrect(ctx, headersCache, attestation)
|
||||
targetCorrect, err := util.AttestationTargetCorrect(ctx, headersCache, c.chainTime, attestationData)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, nil, err
|
||||
}
|
||||
target, err := util.AttestationTarget(ctx, headersCache, c.chainTime, attestation)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, nil, err
|
||||
}
|
||||
targetCorrect, err := util.AttestationTargetCorrect(ctx, headersCache, c.chainTime, attestation)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, nil, err
|
||||
return 0, 0, 0, 0, 0, 0, nil, nil, err
|
||||
}
|
||||
|
||||
for i := range attestation.AggregationBits.Len() {
|
||||
if attestation.AggregationBits.BitAt(i) {
|
||||
validatorIndex := committee[int(i)]
|
||||
if len(c.validators) > 0 {
|
||||
if _, exists := c.validators[validatorIndex]; !exists {
|
||||
// Not one of our validators.
|
||||
continue
|
||||
}
|
||||
aggregationBits, err := attestation.AggregationBits()
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, 0, 0, nil, nil, err
|
||||
}
|
||||
for i := uint64(0); i < aggregationBits.Len(); i++ {
|
||||
if aggregationBits.BitAt(i) {
|
||||
votes[committee[int(i)]] = struct{}{}
|
||||
if _, exists := headCorrects[committee[int(i)]]; !exists && headCorrect {
|
||||
headCorrects[committee[int(i)]] = struct{}{}
|
||||
}
|
||||
|
||||
// Only set the information from the first attestation we find for this validator.
|
||||
if participations[validatorIndex].InclusionSlot == 0 {
|
||||
participations[validatorIndex].HeadVote = &attestation.Data.BeaconBlockRoot
|
||||
participations[validatorIndex].Head = &head
|
||||
participations[validatorIndex].TargetVote = &attestation.Data.Target.Root
|
||||
participations[validatorIndex].Target = &target
|
||||
participations[validatorIndex].InclusionSlot = slot
|
||||
if _, exists := headTimelys[committee[int(i)]]; !exists && headCorrect && inclusionDistance == 1 {
|
||||
headTimelys[committee[int(i)]] = struct{}{}
|
||||
}
|
||||
|
||||
votes[validatorIndex] = struct{}{}
|
||||
if _, exists := headCorrects[validatorIndex]; !exists && headCorrect {
|
||||
headCorrects[validatorIndex] = struct{}{}
|
||||
if _, exists := sourceTimelys[committee[int(i)]]; !exists && inclusionDistance <= 5 {
|
||||
sourceTimelys[committee[int(i)]] = struct{}{}
|
||||
}
|
||||
if _, exists := headTimelys[validatorIndex]; !exists && headCorrect && inclusionDistance == 1 {
|
||||
headTimelys[validatorIndex] = struct{}{}
|
||||
if _, exists := targetCorrects[committee[int(i)]]; !exists && targetCorrect {
|
||||
targetCorrects[committee[int(i)]] = struct{}{}
|
||||
}
|
||||
if _, exists := sourceTimelys[validatorIndex]; !exists && inclusionDistance <= 5 {
|
||||
sourceTimelys[validatorIndex] = struct{}{}
|
||||
}
|
||||
if _, exists := targetCorrects[validatorIndex]; !exists && targetCorrect {
|
||||
targetCorrects[validatorIndex] = struct{}{}
|
||||
}
|
||||
if _, exists := targetTimelys[validatorIndex]; !exists && targetCorrect && inclusionDistance <= 32 {
|
||||
targetTimelys[validatorIndex] = struct{}{}
|
||||
if _, exists := targetTimelys[committee[int(i)]]; !exists && targetCorrect && inclusionDistance <= 32 {
|
||||
targetTimelys[committee[int(i)]] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return votes,
|
||||
headCorrects,
|
||||
headTimelys,
|
||||
sourceTimelys,
|
||||
targetCorrects,
|
||||
targetTimelys,
|
||||
return len(votes),
|
||||
len(headCorrects),
|
||||
len(headTimelys),
|
||||
len(sourceTimelys),
|
||||
len(targetCorrects),
|
||||
len(targetTimelys),
|
||||
votes,
|
||||
participations,
|
||||
nil
|
||||
}
|
||||
@@ -365,18 +282,7 @@ func (c *command) processSyncCommitteeDuties(ctx context.Context) error {
|
||||
return errors.Wrap(err, "empty sync committee")
|
||||
}
|
||||
|
||||
for _, validatorIndex := range committee.Validators {
|
||||
if len(c.validators) == 0 {
|
||||
c.summary.SyncCommitteeValidators++
|
||||
} else {
|
||||
if _, exists := c.validators[validatorIndex]; exists {
|
||||
c.summary.SyncCommitteeValidators++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
missed := make(map[phase0.ValidatorIndex]int)
|
||||
missedSlots := make(map[phase0.ValidatorIndex][]phase0.Slot)
|
||||
for _, index := range committee.Validators {
|
||||
missed[index] = 0
|
||||
}
|
||||
@@ -399,15 +305,9 @@ func (c *command) processSyncCommitteeDuties(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to obtain sync aggregate for slot %d", slot)
|
||||
}
|
||||
for i := range aggregate.SyncCommitteeBits.Len() {
|
||||
validatorIndex := committee.Validators[int(i)]
|
||||
if _, exists := c.validators[validatorIndex]; !exists {
|
||||
// Not one of ours.
|
||||
continue
|
||||
}
|
||||
for i := uint64(0); i < aggregate.SyncCommitteeBits.Len(); i++ {
|
||||
if !aggregate.SyncCommitteeBits.BitAt(i) {
|
||||
missed[validatorIndex]++
|
||||
missedSlots[validatorIndex] = append(missedSlots[validatorIndex], slot)
|
||||
missed[committee.Validators[int(i)]]++
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -416,9 +316,8 @@ func (c *command) processSyncCommitteeDuties(ctx context.Context) error {
|
||||
for index, count := range missed {
|
||||
if count > 0 {
|
||||
c.summary.SyncCommittee = append(c.summary.SyncCommittee, &epochSyncCommittee{
|
||||
ValidatorIndex: index,
|
||||
Missed: count,
|
||||
MissedSlots: missedSlots[index],
|
||||
Index: index,
|
||||
Missed: count,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -430,7 +329,7 @@ func (c *command) processSyncCommitteeDuties(ctx context.Context) error {
|
||||
return missedDiff > 0
|
||||
}
|
||||
// Then order by validator index.
|
||||
return c.summary.SyncCommittee[i].ValidatorIndex < c.summary.SyncCommittee[j].ValidatorIndex
|
||||
return c.summary.SyncCommittee[i].Index < c.summary.SyncCommittee[j].Index
|
||||
})
|
||||
|
||||
return nil
|
||||
@@ -441,10 +340,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to beacon node")
|
||||
@@ -488,10 +388,10 @@ func (c *command) setup(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (c *command) processBlobs(ctx context.Context) error {
|
||||
for _, proposal := range c.summary.Proposals {
|
||||
block, err := c.fetchBlock(ctx, fmt.Sprintf("%d", proposal.Slot))
|
||||
for slot := c.summary.FirstSlot; slot <= c.summary.LastSlot; slot++ {
|
||||
block, err := c.fetchBlock(ctx, fmt.Sprintf("%d", slot))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("failed to obtain block for slot %d", proposal.Slot))
|
||||
return errors.Wrap(err, fmt.Sprintf("failed to obtain block for slot %d", slot))
|
||||
}
|
||||
if block == nil {
|
||||
continue
|
||||
@@ -501,6 +401,8 @@ func (c *command) processBlobs(ctx context.Context) error {
|
||||
// No blobs in these forks.
|
||||
case spec.DataVersionDeneb:
|
||||
c.summary.Blobs += len(block.Deneb.Message.Body.BlobKZGCommitments)
|
||||
case spec.DataVersionElectra:
|
||||
c.summary.Blobs += len(block.Electra.Message.Body.BlobKZGCommitments)
|
||||
default:
|
||||
return fmt.Errorf("unhandled block version %v", block.Version)
|
||||
}
|
||||
|
||||
@@ -46,17 +46,9 @@ In quiet mode this will return 0 if information for the epoch is found, otherwis
|
||||
|
||||
func init() {
|
||||
epochCmd.AddCommand(epochSummaryCmd)
|
||||
epochSummaryFlags(epochSummaryCmd)
|
||||
}
|
||||
|
||||
func epochSummaryFlags(cmd *cobra.Command) {
|
||||
epochFlags(cmd)
|
||||
cmd.Flags().StringSlice("validators", nil, "the validators for which to obtain a summary")
|
||||
epochFlags(epochSummaryCmd)
|
||||
}
|
||||
|
||||
func epochSummaryBindings(cmd *cobra.Command) {
|
||||
epochBindings(cmd)
|
||||
if err := viper.BindPFlag("validators", cmd.Flags().Lookup("validators")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,10 +47,11 @@ In quiet mode this will return 0 if the exit is verified correctly, otherwise 1.
|
||||
errCheck(err, "Failed to obtain signed operation")
|
||||
|
||||
eth2Client, err := util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
})
|
||||
errCheck(err, "Failed to connect to Ethereum 2 beacon node")
|
||||
|
||||
|
||||
@@ -51,10 +51,11 @@ func input(ctx context.Context) (*dataIn, error) {
|
||||
|
||||
var err error
|
||||
data.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !data.quiet,
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !data.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -37,10 +37,11 @@ In quiet mode this will return 0 if the node information can be obtained, otherw
|
||||
ctx := context.Background()
|
||||
|
||||
eth2Client, err := util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
})
|
||||
errCheck(err, "Failed to connect to Ethereum 2 beacon node")
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Operation.
|
||||
epoch string
|
||||
@@ -62,6 +63,7 @@ func newCommand(_ context.Context) (*command, error) {
|
||||
timeout: viper.GetDuration("timeout"),
|
||||
connection: viper.GetString("connection"),
|
||||
allowInsecureConnections: viper.GetBool("allow-insecure-connections"),
|
||||
customSpecSupport: viper.GetBool("custom-spec"),
|
||||
epoch: viper.GetString("epoch"),
|
||||
slot: viper.GetString("slot"),
|
||||
jsonOutput: viper.GetBool("json"),
|
||||
|
||||
@@ -88,10 +88,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to beacon node")
|
||||
|
||||
@@ -136,6 +136,7 @@ func init() {
|
||||
addPersistentFlags()
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func addPersistentFlags() {
|
||||
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.ethdo.yaml)")
|
||||
|
||||
@@ -252,6 +253,10 @@ func addPersistentFlags() {
|
||||
if err := viper.BindPFlag("allow-insecure-connections", RootCmd.PersistentFlags().Lookup("allow-insecure-connections")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
RootCmd.PersistentFlags().Bool("custom-spec", false, "allow custom (non-mainnet) beacon node specifications")
|
||||
if err := viper.BindPFlag("custom-spec", RootCmd.PersistentFlags().Lookup("custom-spec")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"os"
|
||||
|
||||
spec "github.com/attestantio/go-eth2-client/spec/phase0"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/wealdtech/ethdo/util"
|
||||
@@ -60,8 +59,6 @@ In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
|
||||
account, err = util.ParseAccount(ctx, viper.GetString("account"), util.GetPassphrases(), true)
|
||||
case viper.GetString("private-key") != "":
|
||||
account, err = util.ParseAccount(ctx, viper.GetString("private-key"), nil, true)
|
||||
default:
|
||||
err = errors.New("account or private key must be supplied")
|
||||
}
|
||||
errCheck(err, "Failed to obtain account")
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"os"
|
||||
|
||||
spec "github.com/attestantio/go-eth2-client/spec/phase0"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/wealdtech/ethdo/util"
|
||||
@@ -72,10 +71,6 @@ In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
|
||||
account, err = util.ParseAccount(ctx, viper.GetString("private-key"), nil, false)
|
||||
case viper.GetString("public-key") != "":
|
||||
account, err = util.ParseAccount(ctx, viper.GetString("public-key"), nil, false)
|
||||
case signatureVerifySigner != "":
|
||||
account, err = util.ParseAccount(ctx, signatureVerifySigner, nil, false)
|
||||
default:
|
||||
err = errors.New("one of account, private-key, public-key, or signer must be supplied")
|
||||
}
|
||||
errCheck(err, "Failed to obtain account")
|
||||
outputIf(viper.GetBool("debug"), fmt.Sprintf("Public key is %#x", account.PublicKey().Marshal()))
|
||||
|
||||
@@ -53,10 +53,11 @@ func input(ctx context.Context) (*dataIn, error) {
|
||||
// Ethereum 2 client.
|
||||
var err error
|
||||
data.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !data.quiet,
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !data.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -33,6 +33,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Input.
|
||||
validator string
|
||||
@@ -51,9 +52,10 @@ type command struct {
|
||||
|
||||
func newCommand(_ context.Context) (*command, error) {
|
||||
c := &command{
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
customSpecSupport: viper.GetBool("custom-spec"),
|
||||
}
|
||||
|
||||
// Timeout.
|
||||
|
||||
@@ -120,6 +120,13 @@ func (c *command) process(ctx context.Context) error {
|
||||
} else {
|
||||
c.inclusions = append(c.inclusions, 2)
|
||||
}
|
||||
case spec.DataVersionElectra:
|
||||
aggregate = block.Electra.Message.Body.SyncAggregate
|
||||
if aggregate.SyncCommitteeBits.BitAt(c.committeeIndex) {
|
||||
c.inclusions = append(c.inclusions, 1)
|
||||
} else {
|
||||
c.inclusions = append(c.inclusions, 2)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unhandled block version %v", block.Version)
|
||||
}
|
||||
@@ -134,10 +141,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -52,10 +52,11 @@ func input(ctx context.Context) (*dataIn, error) {
|
||||
// Ethereum 2 client.
|
||||
var err error
|
||||
data.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !data.quiet,
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !data.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -35,6 +35,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Data access.
|
||||
consensusClient eth2client.Service
|
||||
@@ -46,9 +47,10 @@ type command struct {
|
||||
|
||||
func newCommand(_ context.Context) (*command, error) {
|
||||
c := &command{
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
quiet: viper.GetBool("quiet"),
|
||||
verbose: viper.GetBool("verbose"),
|
||||
debug: viper.GetBool("debug"),
|
||||
customSpecSupport: viper.GetBool("custom-spec"),
|
||||
}
|
||||
|
||||
// Timeout.
|
||||
|
||||
@@ -49,10 +49,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the consensus node.
|
||||
c.consensusClient, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to consensus node")
|
||||
|
||||
@@ -54,6 +54,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Information required to generate the operations.
|
||||
withdrawalAddress bellatrix.ExecutionAddress
|
||||
@@ -78,6 +79,7 @@ func newCommand(_ context.Context) (*command, error) {
|
||||
timeout: viper.GetDuration("timeout"),
|
||||
connection: viper.GetString("connection"),
|
||||
allowInsecureConnections: viper.GetBool("allow-insecure-connections"),
|
||||
customSpecSupport: viper.GetBool("custom-spec"),
|
||||
prepareOffline: viper.GetBool("prepare-offline"),
|
||||
account: viper.GetString("account"),
|
||||
withdrawalAccount: viper.GetString("withdrawal-account"),
|
||||
|
||||
@@ -482,17 +482,17 @@ func (c *command) generateOperationFromSeedAndPath(ctx context.Context,
|
||||
validator, exists := validators[validatorPubkey]
|
||||
if !exists {
|
||||
if c.debug {
|
||||
fmt.Fprintf(os.Stderr, "no validator found with public key %s at path %s\n", validatorPubkey, path)
|
||||
fmt.Fprintf(os.Stderr, "No validator found with public key %s at path %s\n", validatorPubkey, path)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c.verbose {
|
||||
if c.verbose || c.debug {
|
||||
fmt.Fprintf(os.Stderr, "Validator %d found with public key %s at path %s\n", validator.Index, validatorPubkey, path)
|
||||
}
|
||||
|
||||
if validator.WithdrawalCredentials[0] != byte(0) {
|
||||
if c.debug {
|
||||
if c.verbose || c.debug {
|
||||
fmt.Fprintf(os.Stderr, "Validator %s has non-BLS withdrawal credentials %#x\n", validatorPubkey, validator.WithdrawalCredentials)
|
||||
}
|
||||
return false, nil
|
||||
@@ -523,7 +523,7 @@ func (c *command) generateOperationFromSeedAndPath(ctx context.Context,
|
||||
withdrawalCredentials := ethutil.SHA256(withdrawalPubkey)
|
||||
withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX
|
||||
if !bytes.Equal(withdrawalCredentials, validator.WithdrawalCredentials) {
|
||||
if c.verbose && c.privateKey == "" {
|
||||
if (c.verbose || c.debug) && c.privateKey == "" {
|
||||
fmt.Fprintf(os.Stderr, "Validator %s withdrawal credentials %#x do not match expected credentials, cannot update\n", validatorPubkey, validator.WithdrawalCredentials)
|
||||
}
|
||||
return false, nil
|
||||
@@ -538,6 +538,10 @@ func (c *command) generateOperationFromSeedAndPath(ctx context.Context,
|
||||
return false, err
|
||||
}
|
||||
|
||||
if c.verbose || c.debug {
|
||||
fmt.Fprintf(os.Stderr, "Withdrawal credentials change operation generated for validator with public key %s at path %s\n", validatorPubkey, path)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -727,10 +731,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
// Connect to the consensus node.
|
||||
var err error
|
||||
c.consensusClient, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -170,7 +170,7 @@ func validatorDepositDataOutputJSON(datum *dataOut) (string, error) {
|
||||
if datum.depositDataRoot == nil {
|
||||
return "", errors.New("deposit data root required")
|
||||
}
|
||||
if datum.depositMessageRoot == nil {
|
||||
if datum.depositDataRoot == nil {
|
||||
return "", errors.New("deposit message root required")
|
||||
}
|
||||
if datum.forkVersion == nil {
|
||||
|
||||
@@ -28,8 +28,9 @@ type dataIn struct {
|
||||
verbose bool
|
||||
debug bool
|
||||
// Ethereum 2 connection.
|
||||
eth2Client string
|
||||
allowInsecure bool
|
||||
eth2Client string
|
||||
allowInsecure bool
|
||||
customSpecSupport bool
|
||||
// Operation.
|
||||
account string
|
||||
pubKey string
|
||||
@@ -50,6 +51,7 @@ func input(_ context.Context) (*dataIn, error) {
|
||||
// Ethereum 2 connection.
|
||||
data.eth2Client = viper.GetString("connection")
|
||||
data.allowInsecure = viper.GetBool("allow-insecure-connections")
|
||||
data.customSpecSupport = viper.GetBool("custom-spec")
|
||||
|
||||
// Account.
|
||||
data.account = viper.GetString("account")
|
||||
|
||||
@@ -32,10 +32,11 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
|
||||
|
||||
// Ethereum 2 client.
|
||||
eth2Client, err := util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: data.eth2Client,
|
||||
Timeout: data.timeout,
|
||||
AllowInsecure: data.allowInsecure,
|
||||
LogFallback: !data.quiet,
|
||||
Address: data.eth2Client,
|
||||
Timeout: data.timeout,
|
||||
AllowInsecure: data.allowInsecure,
|
||||
CustomSpecSupport: data.customSpecSupport,
|
||||
LogFallback: !data.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -50,6 +50,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Information required to generate the operations.
|
||||
chainInfo *beacon.ChainInfo
|
||||
@@ -73,6 +74,7 @@ func newCommand(_ context.Context) (*command, error) {
|
||||
timeout: viper.GetDuration("timeout"),
|
||||
connection: viper.GetString("connection"),
|
||||
allowInsecureConnections: viper.GetBool("allow-insecure-connections"),
|
||||
customSpecSupport: viper.GetBool("custom-spec"),
|
||||
prepareOffline: viper.GetBool("prepare-offline"),
|
||||
passphrases: util.GetPassphrases(),
|
||||
mnemonic: viper.GetString("mnemonic"),
|
||||
|
||||
@@ -595,10 +595,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
// Connect to the consensus node.
|
||||
var err error
|
||||
c.consensusClient, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -35,6 +35,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Input.
|
||||
validators int64
|
||||
|
||||
@@ -125,10 +125,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to beacon node")
|
||||
|
||||
@@ -101,7 +101,7 @@ func checkMnemonic(ctx context.Context, debug bool, validatorWithdrawalCredentia
|
||||
// Create seed from mnemonic and passphrase.
|
||||
seed := bip39.NewSeed(mnemonic, mnemonicPassphrase)
|
||||
// Check first 1024 indices.
|
||||
for i := range 1024 {
|
||||
for i := 0; i < 1024; i++ {
|
||||
path := fmt.Sprintf("m/12381/3600/%d/0", i)
|
||||
if debug {
|
||||
fmt.Printf("Checking path %s\n", path)
|
||||
|
||||
@@ -34,6 +34,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Operation.
|
||||
epoch string
|
||||
@@ -131,6 +132,7 @@ func newCommand(_ context.Context) (*command, error) {
|
||||
|
||||
c.connection = viper.GetString("connection")
|
||||
c.allowInsecureConnections = viper.GetBool("allow-insecure-connections")
|
||||
c.customSpecSupport = viper.GetBool("custom-spec")
|
||||
|
||||
c.epoch = viper.GetString("epoch")
|
||||
c.validators = viper.GetStringSlice("validators")
|
||||
|
||||
@@ -243,16 +243,24 @@ func (c *command) processAttesterDutiesSlot(ctx context.Context,
|
||||
return err
|
||||
}
|
||||
for _, attestation := range attestations {
|
||||
if _, exists := dutiesBySlot[attestation.Data.Slot]; !exists {
|
||||
attestationData, err := attestation.Data()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
aggregationBits, err := attestation.AggregationBits()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if _, exists := dutiesBySlot[attestationData.Slot]; !exists {
|
||||
// We do not have any attestations for this slot.
|
||||
continue
|
||||
}
|
||||
if _, exists := dutiesBySlot[attestation.Data.Slot][attestation.Data.Index]; !exists {
|
||||
if _, exists := dutiesBySlot[attestationData.Slot][attestationData.Index]; !exists {
|
||||
// We do not have any attestations for this committee.
|
||||
continue
|
||||
}
|
||||
for _, duty := range dutiesBySlot[attestation.Data.Slot][attestation.Data.Index] {
|
||||
if attestation.AggregationBits.BitAt(duty.ValidatorCommitteeIndex) {
|
||||
for _, duty := range dutiesBySlot[attestationData.Slot][attestationData.Index] {
|
||||
if aggregationBits.BitAt(duty.ValidatorCommitteeIndex) {
|
||||
// Found it.
|
||||
if _, exists := votes[duty.ValidatorIndex]; exists {
|
||||
// Duplicate; ignore.
|
||||
@@ -261,17 +269,17 @@ func (c *command) processAttesterDutiesSlot(ctx context.Context,
|
||||
votes[duty.ValidatorIndex] = struct{}{}
|
||||
|
||||
// Update the metrics for the attestation.
|
||||
index := int(attestation.Data.Slot - c.chainTime.FirstSlotOfEpoch(c.summary.Epoch))
|
||||
index := int(attestationData.Slot - c.chainTime.FirstSlotOfEpoch(c.summary.Epoch))
|
||||
c.summary.Slots[index].Attestations.Included++
|
||||
inclusionDelay := slot - duty.Slot
|
||||
|
||||
fault := &validatorFault{
|
||||
Validator: duty.ValidatorIndex,
|
||||
AttestationData: attestation.Data,
|
||||
AttestationData: attestationData,
|
||||
InclusionDistance: int(inclusionDelay),
|
||||
}
|
||||
|
||||
headCorrect, err := util.AttestationHeadCorrect(ctx, headersCache, attestation)
|
||||
headCorrect, err := util.AttestationHeadCorrect(ctx, headersCache, attestationData)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to calculate if attestation had correct head vote")
|
||||
}
|
||||
@@ -295,7 +303,7 @@ func (c *command) processAttesterDutiesSlot(ctx context.Context,
|
||||
c.summary.UntimelySourceValidators = append(c.summary.UntimelySourceValidators, fault)
|
||||
}
|
||||
|
||||
targetCorrect, err := util.AttestationTargetCorrect(ctx, headersCache, c.chainTime, attestation)
|
||||
targetCorrect, err := util.AttestationTargetCorrect(ctx, headersCache, c.chainTime, attestationData)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to calculate if attestation had correct target vote")
|
||||
}
|
||||
@@ -399,10 +407,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to beacon node")
|
||||
|
||||
@@ -39,6 +39,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Processing.
|
||||
consensusClient consensusclient.Service
|
||||
@@ -60,6 +61,7 @@ func newCommand(_ context.Context) (*command, error) {
|
||||
timeout: viper.GetDuration("timeout"),
|
||||
connection: viper.GetString("connection"),
|
||||
allowInsecureConnections: viper.GetBool("allow-insecure-connections"),
|
||||
customSpecSupport: viper.GetBool("custom-spec"),
|
||||
validator: viper.GetString("validator"),
|
||||
res: &res{},
|
||||
}
|
||||
|
||||
@@ -129,10 +129,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
// Connect to the consensus node.
|
||||
var err error
|
||||
c.consensusClient, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -33,6 +33,7 @@ type command struct {
|
||||
timeout time.Duration
|
||||
connection string
|
||||
allowInsecureConnections bool
|
||||
customSpecSupport bool
|
||||
|
||||
// Input.
|
||||
validators string
|
||||
@@ -76,6 +77,7 @@ func newCommand(_ context.Context) (*command, error) {
|
||||
|
||||
c.connection = viper.GetString("connection")
|
||||
c.allowInsecureConnections = viper.GetBool("allow-insecure-connections")
|
||||
c.customSpecSupport = viper.GetBool("custom-spec")
|
||||
|
||||
c.validators = viper.GetString("validators")
|
||||
|
||||
|
||||
@@ -114,10 +114,11 @@ func (c *command) setup(ctx context.Context) error {
|
||||
|
||||
// Connect to the client.
|
||||
c.eth2Client, err = util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
LogFallback: !c.quiet,
|
||||
Address: c.connection,
|
||||
Timeout: c.timeout,
|
||||
AllowInsecure: c.allowInsecureConnections,
|
||||
CustomSpecSupport: c.customSpecSupport,
|
||||
LogFallback: !c.quiet,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to connect to beacon node")
|
||||
|
||||
@@ -47,10 +47,11 @@ In quiet mode this will return 0 if the validator information can be obtained, o
|
||||
ctx := context.Background()
|
||||
|
||||
eth2Client, err := util.ConnectToBeaconNode(ctx, &util.ConnectOpts{
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
Address: viper.GetString("connection"),
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
AllowInsecure: viper.GetBool("allow-insecure-connections"),
|
||||
CustomSpecSupport: viper.GetBool("custom-spec"),
|
||||
LogFallback: !viper.GetBool("quiet"),
|
||||
})
|
||||
errCheck(err, "Failed to connect to Ethereum 2 beacon node")
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
// ReleaseVersion is the release version of the codebase.
|
||||
// Usually overridden by tag names when building binaries.
|
||||
var ReleaseVersion = "local build (latest release 1.36.4)"
|
||||
var ReleaseVersion = "local build (latest release 1.35.3)"
|
||||
|
||||
// versionCmd represents the version command.
|
||||
var versionCmd = &cobra.Command{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2019 - 2024 Weald Technology Trading
|
||||
// Copyright © 2019, 2020 Weald Technology Trading
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
distributed "github.com/wealdtech/go-eth2-wallet-distributed"
|
||||
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
||||
hd "github.com/wealdtech/go-eth2-wallet-hd/v2"
|
||||
keystore "github.com/wealdtech/go-eth2-wallet-keystore"
|
||||
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
)
|
||||
@@ -41,8 +40,6 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
|
||||
return processHD(ctx, data)
|
||||
case "distributed":
|
||||
return processDistributed(ctx, data)
|
||||
case "keystore":
|
||||
return processKeystore(ctx, data)
|
||||
default:
|
||||
return nil, errors.New("wallet type not supported")
|
||||
}
|
||||
@@ -135,16 +132,3 @@ func processDistributed(ctx context.Context, data *dataIn) (*dataOut, error) {
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func processKeystore(ctx context.Context, data *dataIn) (*dataOut, error) {
|
||||
if data == nil {
|
||||
return nil, errors.New("no data")
|
||||
}
|
||||
|
||||
results := &dataOut{}
|
||||
|
||||
if _, err := keystore.CreateWallet(ctx, data.walletName, data.store, keystorev4.New()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ $ ethdo wallet batch --wallet="Validators" ---passphrase="my account secret" --b
|
||||
`ethdo wallet create` creates a new wallet with the given parameters. Options for creating a wallet include:
|
||||
|
||||
- `wallet`: the name of the wallet to create
|
||||
- `type`: the type of wallet to create. This can be either "nd" for a non-deterministic wallet, where private keys are generated randomly, "hd" for a hierarchical deterministic wallet, where private keys are generated from a seed and path as per [EIP-2333](https://eips.ethereum.org/EIPS/eip-2333), "keystore" for a wallet where data is written in the [EIP=2335](https://eips.ethereum.org/EIPS/eip-2335) format, or "distributed" for a wallet used by [Dirk](https://github.com/wealdtech/dirk) (defaults to "nd")
|
||||
- `type`: the type of wallet to create. This can be either "nd" for a non-deterministic wallet, where private keys are generated randomly, or "hd" for a hierarchical deterministic wallet, where private keys are generated from a seed and path as per [EIP-2333](https://eips.ethereum.org/EIPS/eip-2333) (defaults to "nd")
|
||||
- `wallet-passphrase`: the passphrase for of the wallet. This is required for hierarchical deterministic wallets, to protect the seed
|
||||
- `mnemonic`: for hierarchical deterministic wallets only, use a pre-defined 24-word [BIP-39 seed phrase](https://en.bitcoin.it/wiki/Seed_phrase) to create the wallet, along with an additional "seed extension" phrase if required. **Warning** The same mnemonic can be used to create multiple wallets, in which case they will generate the same keys.
|
||||
|
||||
@@ -183,7 +183,6 @@ $ ethdo account create --account="Personal wallet/Operations" --wallet-passphras
|
||||
- `show-private-key`: show the private of the derived account. **Warning** displaying private keys, especially those derived from seeds held on hardware wallets, can expose your Ether to risk of being stolen. Only use this option if you are sure you understand the risks involved
|
||||
- `show-withdrawal-credentials`: show the withdrawal credentials of the derived account
|
||||
- `generate-keystore`: generate a keystore for the account
|
||||
- `json`: output the generated keystore to stdout
|
||||
|
||||
```sh
|
||||
$ ethdo account derive --mnemonic="abandon ... abandon art" --path="m/12381/3600/0/0"
|
||||
|
||||
102
go.mod
102
go.mod
@@ -1,106 +1,106 @@
|
||||
module github.com/wealdtech/ethdo
|
||||
|
||||
go 1.22.7
|
||||
go 1.21
|
||||
|
||||
toolchain go1.23.2
|
||||
toolchain go1.21.6
|
||||
|
||||
require (
|
||||
github.com/attestantio/go-eth2-client v0.22.0
|
||||
github.com/ferranbt/fastssz v0.1.4
|
||||
github.com/attestantio/go-eth2-client v0.21.4-0.20240514220516-2646ce28c3e4
|
||||
github.com/ferranbt/fastssz v0.1.3
|
||||
github.com/gofrs/uuid v4.4.0+incompatible
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b
|
||||
github.com/herumi/bls-eth-go-binary v1.36.1
|
||||
github.com/herumi/bls-eth-go-binary v1.33.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e
|
||||
github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/shopspring/decimal v1.4.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/rs/zerolog v1.32.0
|
||||
github.com/shopspring/decimal v1.3.1
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/spf13/viper v1.18.2
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/tyler-smith/go-bip39 v1.1.0
|
||||
github.com/wealdtech/go-bytesutil v1.2.1
|
||||
github.com/wealdtech/go-ecodec v1.1.4
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.8.2
|
||||
github.com/wealdtech/go-eth2-util v1.8.2
|
||||
github.com/wealdtech/go-eth2-wallet v1.17.0
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.5.1
|
||||
github.com/wealdtech/go-eth2-wallet v1.16.0
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.4.7
|
||||
github.com/wealdtech/go-eth2-wallet-distributed v1.2.1
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.7.0
|
||||
github.com/wealdtech/go-eth2-wallet-keystore v1.0.0
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.5.0
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.18.1
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.12.0
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.7.2
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.12.0
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.11.0
|
||||
github.com/wealdtech/go-string2eth v1.2.1
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/text v0.15.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go v1.55.5 // indirect
|
||||
github.com/aws/aws-sdk-go v1.51.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dgraph-io/ristretto v0.2.0 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emicklei/dot v1.6.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/goccy/go-yaml v1.15.12 // indirect
|
||||
github.com/goccy/go-yaml v1.9.2 // indirect
|
||||
github.com/golang/glog v1.2.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/holiman/uint256 v1.3.2 // indirect
|
||||
github.com/holiman/uint256 v1.2.4 // indirect
|
||||
github.com/huandu/go-clone v1.7.2 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/minio/highwayhash v1.0.3 // indirect
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pk910/dynamic-ssz v0.0.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
||||
github.com/pk910/dynamic-ssz v0.0.4 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.61.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/prometheus/client_golang v1.19.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.0 // indirect
|
||||
github.com/prometheus/common v0.50.0 // indirect
|
||||
github.com/prometheus/procfs v0.13.0 // indirect
|
||||
github.com/protolambda/zssz v0.1.5 // indirect
|
||||
github.com/r3labs/sse/v2 v2.10.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.6.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/wealdtech/eth2-signer-api v1.7.2 // indirect
|
||||
github.com/wealdtech/go-indexer v1.1.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect
|
||||
go.opentelemetry.io/otel v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
|
||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect
|
||||
google.golang.org/grpc v1.69.2 // indirect
|
||||
google.golang.org/protobuf v1.36.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
||||
246
go.sum
246
go.sum
@@ -1,41 +1,56 @@
|
||||
github.com/attestantio/go-eth2-client v0.22.0 h1:KmF9kPNNWWGfE7l1BP7pXps4EOXgKnYeFGR0/WbyFhY=
|
||||
github.com/attestantio/go-eth2-client v0.22.0/go.mod h1:d7ZPNrMX8jLfIgML5u7QZxFo2AukLM+5m08iMaLdqb8=
|
||||
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
|
||||
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/attestantio/go-eth2-client v0.21.4-0.20240514220516-2646ce28c3e4 h1:tvLDLWLMMdo/UzMPCX+a9wh+zdAZzS2NEOqAaq9m5BY=
|
||||
github.com/attestantio/go-eth2-client v0.21.4-0.20240514220516-2646ce28c3e4/go.mod h1:RssbJ8txdfZ+O7cIjOKCvizcTWHzgPuJNByrwtQ6tBQ=
|
||||
github.com/attestantio/go-eth2-client v0.21.4 h1:1QW4f3NXCcbUsxmRBElotTjSIhRwLsmdowUvxJnyaJU=
|
||||
github.com/attestantio/go-eth2-client v0.21.4/go.mod h1:d7ZPNrMX8jLfIgML5u7QZxFo2AukLM+5m08iMaLdqb8=
|
||||
github.com/aws/aws-sdk-go v1.51.1 h1:AFvTihcDPanvptoKS09a4yYmNtPm3+pXlk6uYHmZiFk=
|
||||
github.com/aws/aws-sdk-go v1.51.1/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=
|
||||
github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
|
||||
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/emicklei/dot v1.6.4 h1:cG9ycT67d9Yw22G+mAb4XiuUz6E6H1S0zePp/5Cwe/c=
|
||||
github.com/emicklei/dot v1.6.4/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
|
||||
github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY=
|
||||
github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo=
|
||||
github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/goccy/go-yaml v1.15.12 h1:KLUSwfrUcTU6F8sAkf23OIPYC6aFVMNFSu4btROEm6w=
|
||||
github.com/goccy/go-yaml v1.15.12/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/goccy/go-yaml v1.9.2 h1:2Njwzw+0+pjU2gb805ZC1B/uBuAs2VcZ3K+ZgHwDs7w=
|
||||
github.com/goccy/go-yaml v1.9.2/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
|
||||
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
@@ -48,10 +63,10 @@ github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsD
|
||||
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/herumi/bls-eth-go-binary v1.36.1 h1:SfLjxbO1fWkKtKS7J3Ezd1/5QXrcaTZgWynxdSe10hQ=
|
||||
github.com/herumi/bls-eth-go-binary v1.36.1/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
|
||||
github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA=
|
||||
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/herumi/bls-eth-go-binary v1.33.0 h1:fHoysK+WbL/FQIJoVGECGd2lBLa2De7YjAGZljI2vzQ=
|
||||
github.com/herumi/bls-eth-go-binary v1.33.0/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
|
||||
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
|
||||
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c=
|
||||
github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
|
||||
github.com/huandu/go-clone v1.7.2 h1:3+Aq0Ed8XK+zKkLjE2dfHg0XrpIfcohBE1K+c8Usxoo=
|
||||
@@ -60,103 +75,109 @@ github.com/huandu/go-clone/generic v1.6.0 h1:Wgmt/fUZ28r16F2Y3APotFD59sHk1p78K0X
|
||||
github.com/huandu/go-clone/generic v1.6.0/go.mod h1:xgd9ZebcMsBWWcBx5mVMCoqMX24gLWr5lQicr+nVXNs=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
||||
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
|
||||
github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
|
||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
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/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pk910/dynamic-ssz v0.0.5 h1:VP9heGYUwzlpyhk28P2nCAzhvGsePJOOOO5vQMDh2qQ=
|
||||
github.com/pk910/dynamic-ssz v0.0.5/go.mod h1:b6CrLaB2X7pYA+OSEEbkgXDEcRnjLOZIxZTsMuO/Y9c=
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
||||
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pk910/dynamic-ssz v0.0.3 h1:fCWzFowq9P6SYCc7NtJMkZcIHk+r5hSVD+32zVi6Aio=
|
||||
github.com/pk910/dynamic-ssz v0.0.3/go.mod h1:b6CrLaB2X7pYA+OSEEbkgXDEcRnjLOZIxZTsMuO/Y9c=
|
||||
github.com/pk910/dynamic-ssz v0.0.4 h1:DT29+1055tCEPCaR4V/ez+MOKW7BzBsmjyFvBRqx0ME=
|
||||
github.com/pk910/dynamic-ssz v0.0.4/go.mod h1:b6CrLaB2X7pYA+OSEEbkgXDEcRnjLOZIxZTsMuO/Y9c=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ=
|
||||
github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
|
||||
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
||||
github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ=
|
||||
github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ=
|
||||
github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
|
||||
github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
|
||||
github.com/protolambda/zssz v0.1.5 h1:7fjJjissZIIaa2QcvmhS/pZISMX21zVITt49sW1ouek=
|
||||
github.com/protolambda/zssz v0.1.5/go.mod h1:a4iwOX5FE7/JkKA+J/PH0Mjo9oXftN6P8NZyL28gpag=
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 h1:lC8kiphgdOBTcbTvo8MwkvpKjO0SlAgjv4xIK5FGJ94=
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15/go.mod h1:8svFBIKKu31YriBG/pNizo9N0Jr9i5PQ+dFkxWg3x5k=
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e h1:ATgOe+abbzfx9kCPeXIW4fiWyDdxlwHw07j8UGhdTd4=
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4=
|
||||
github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388 h1:4bD+ujqGfY4zoDUF3q9MhdmpPXzdp03DYUIlXeQ72kk=
|
||||
github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388/go.mod h1:VecIJZrewdAuhVckySLFt2wAAHRME934bSDurP8ftkc=
|
||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4=
|
||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs=
|
||||
github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=
|
||||
github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
|
||||
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
|
||||
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w=
|
||||
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
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/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||
github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10 h1:CQh33pStIp/E30b7TxDlXfM0145bn2e8boI30IxAhTg=
|
||||
github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10/go.mod h1:x/Pa0FF5Te9kdrlZKJK82YmAkvL8+f989USgz6Jiw7M=
|
||||
github.com/wealdtech/eth2-signer-api v1.7.2 h1:9wmwWEstUwukyZmh0OhQfSHm9KrqFHF7oLSlrk0l2Uk=
|
||||
github.com/wealdtech/eth2-signer-api v1.7.2/go.mod h1:HOdnGSKi9z6OkV/UgpKpbsF3HcOAJkIjjjSWTXisnWI=
|
||||
github.com/wealdtech/go-bytesutil v1.2.1 h1:TjuRzcG5KaPwaR5JB7L/OgJqMQWvlrblA1n0GfcXFSY=
|
||||
@@ -167,10 +188,10 @@ github.com/wealdtech/go-eth2-types/v2 v2.8.2 h1:b5aXlNBLKgjAg/Fft9VvGlqAUCQMP5Lz
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.8.2/go.mod h1:IAz9Lz1NVTaHabQa+4zjk2QDKMv8LVYo0n46M9o/TXw=
|
||||
github.com/wealdtech/go-eth2-util v1.8.2 h1:gq+JMrnadifyKadUr75wmfP7+usiqMu9t3VVoob5Dvo=
|
||||
github.com/wealdtech/go-eth2-util v1.8.2/go.mod h1:/80GAK0K/3+PqUBZHvaOPd3b1sjHeimxQh1nrJzgaPk=
|
||||
github.com/wealdtech/go-eth2-wallet v1.17.0 h1:hMjGRjvpk95gguW6UXFDkRHWjYqE0cdrO7cOClF9Ubo=
|
||||
github.com/wealdtech/go-eth2-wallet v1.17.0/go.mod h1:qMmDrx//GrdZ3q+0Jf9SNwCaLsFOxOmXgr1yptpSMIE=
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.5.1 h1:h1wZK31yonLkwddajg+Prhhd2rrvIIxQ3HxwZ3udnaY=
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.5.1/go.mod h1:Yz1Mc+HfbG1CODeBpAQ++/Us76OdXzI5kVs1qGvUiBM=
|
||||
github.com/wealdtech/go-eth2-wallet v1.16.0 h1:syD1xDYB7emk4x+6bTYm5VZp9nx5FLab5Fgm09Eq1Kg=
|
||||
github.com/wealdtech/go-eth2-wallet v1.16.0/go.mod h1:JFA2P7PpPR8quQ/T6Gsr/4VLj5sQVnyzKgfPA+eqmYE=
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.4.7 h1:P9xgaoBB9h1r0OUEE6LHffZ+IbiGE4uniMaNjvP1+D8=
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.4.7/go.mod h1:fP/g7OQQTYCFRg+ZIv6eoTvDdjkZlHnLcf41UgCvrM8=
|
||||
github.com/wealdtech/go-eth2-wallet-distributed v1.2.1 h1:+pbG9i9b5TrWd7GDRX8yq4FKA+D7k7aI6uySEvAZ+Kk=
|
||||
github.com/wealdtech/go-eth2-wallet-distributed v1.2.1/go.mod h1:jYkDax2VhUNKIct6TVlgxAagvR56/eg7y7J+JFq+gDo=
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1 h1:9j7bpwjT9wmwBb54ZkBhTm1uNIlFFcCJXefd/YskZPw=
|
||||
@@ -179,8 +200,6 @@ github.com/wealdtech/go-eth2-wallet-encryptor-unencrypted v1.0.2 h1:IMIyl70hbJlx
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-unencrypted v1.0.2/go.mod h1:T8nyAscWIWNcNa6EG/19PwH/OCt2Ly7Orn5okmiuSP4=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.7.0 h1:5g4emFacTf+sX6zx6SbZIZGR7Jx5Xr/Xdb7sXnEXlWk=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.7.0/go.mod h1:aWgnEi07w1L9wMBRB69sYvoEONppAUly6FDQRWQGqH8=
|
||||
github.com/wealdtech/go-eth2-wallet-keystore v1.0.0 h1:DYR6TAyi7RxXoAanLSPdiufGxCX617BQwWOdCxHqHX4=
|
||||
github.com/wealdtech/go-eth2-wallet-keystore v1.0.0/go.mod h1:6DGINunnasS9y9F7KH3ya2h74fHWgSCfP3dAJWe4A6U=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.5.0 h1:vphAFklkYMRJVo9f5rVWly7PECHrLS4yarjemBa7fRM=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.5.0/go.mod h1:kBZUZogqwvvxulEvXi5l6OjZyd7EBmCKxce5Q+lW7fs=
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.18.1 h1:Ceq74WL57jdBQnrZJFJyGRBKOOFI5wwq9VoxeAbjoEk=
|
||||
@@ -189,59 +208,62 @@ github.com/wealdtech/go-eth2-wallet-store-s3 v1.12.0 h1:noknYCbHw2soPhwke1LvC99K
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.12.0/go.mod h1:1lSVxfQynUAd5u46rCeAI8wCl8S44lZsNYYXlxVAvwU=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.7.2 h1:TwOt7bEHsVe6dKJb7XuUG7m06gaBGPCQlBk24Ql8Mws=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.7.2/go.mod h1:rtIoB34tqL3kUOK+LsLTAHfynxLR8pGScy0lmQmpbKc=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.12.0 h1:w0OrVImtQfjN7XCqALfgVtcmH8FChaUZjwNGKGzqp0E=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.12.0/go.mod h1:m8xsnPZLq1vt7bnMveTc4xxVJUv8mBL21iPU4kALYGE=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.11.0 h1:yX9+FfUXvPDvZ8Q5bhF+64AWrQwh4a3/HpfTx99DnZc=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.11.0/go.mod h1:UVP9YFcnPiIzHqbmCMW3qrQ3TK5FOqr1fmKqNT9JGr8=
|
||||
github.com/wealdtech/go-indexer v1.1.0 h1:vn4gY7nSYSLe0sXVauJgyHvK4NXiDrLKBYYYKWypahk=
|
||||
github.com/wealdtech/go-indexer v1.1.0/go.mod h1:lEFTda1rul1EwWIX3QqXq/KW0tnEEhC41Lup06V7Tlo=
|
||||
github.com/wealdtech/go-string2eth v1.2.1 h1:u9sofvGFkp+uvTg4Nvsvy5xBaiw8AibGLLngfC4F76g=
|
||||
github.com/wealdtech/go-string2eth v1.2.1/go.mod h1:9uwxm18zKZfrReXrGIbdiRYJtbE91iGcj6TezKKEx80=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0=
|
||||
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
|
||||
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
|
||||
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
|
||||
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
|
||||
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
|
||||
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
|
||||
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
|
||||
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
|
||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw=
|
||||
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb h1:B7GIB7sr443wZ/EAEl7VZjmh1V6qzkt5V+RYcUYtS1U=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb h1:3oy2tynMOP1QbTC0MsNNAV+Se8M2Bd0A5+x1QHyw+pI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
|
||||
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
|
||||
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
||||
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
|
||||
google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
|
||||
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc=
|
||||
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
|
||||
|
||||
@@ -75,9 +75,9 @@ func (p *polynomial) evaluate(x uint8) uint8 {
|
||||
func interpolatePolynomial(xSamples, ySamples []uint8, x uint8) uint8 {
|
||||
limit := len(xSamples)
|
||||
var result, basis uint8
|
||||
for i := range limit {
|
||||
for i := 0; i < limit; i++ {
|
||||
basis = 1
|
||||
for j := range limit {
|
||||
for j := 0; j < limit; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
@@ -183,7 +183,7 @@ func Split(secret []byte, parts, threshold int) ([][]byte, error) {
|
||||
// Generate a `parts` number of (x,y) pairs
|
||||
// We cheat by encoding the x value once as the final index,
|
||||
// so that it only needs to be stored once.
|
||||
for i := range parts {
|
||||
for i := 0; i < parts; i++ {
|
||||
x := uint8(xCoordinates[i]) + 1
|
||||
y := p.evaluate(x)
|
||||
out[i][idx] = y
|
||||
|
||||
@@ -21,44 +21,15 @@ import (
|
||||
"github.com/wealdtech/ethdo/services/chaintime"
|
||||
)
|
||||
|
||||
// AttestationHead returns the head for which the attestation should have voted.
|
||||
func AttestationHead(ctx context.Context,
|
||||
headersCache *BeaconBlockHeaderCache,
|
||||
attestation *phase0.Attestation,
|
||||
) (
|
||||
phase0.Root,
|
||||
error,
|
||||
) {
|
||||
slot := attestation.Data.Slot
|
||||
for {
|
||||
header, err := headersCache.Fetch(ctx, slot)
|
||||
if err != nil {
|
||||
return phase0.Root{}, err
|
||||
}
|
||||
if header == nil {
|
||||
// No block.
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
if !header.Canonical {
|
||||
// Not canonical.
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
|
||||
return header.Root, nil
|
||||
}
|
||||
}
|
||||
|
||||
// AttestationHeadCorrect returns true if the given attestation had the correct head.
|
||||
func AttestationHeadCorrect(ctx context.Context,
|
||||
headersCache *BeaconBlockHeaderCache,
|
||||
attestation *phase0.Attestation,
|
||||
attestationData *phase0.AttestationData,
|
||||
) (
|
||||
bool,
|
||||
error,
|
||||
) {
|
||||
slot := attestation.Data.Slot
|
||||
slot := attestationData.Slot
|
||||
for {
|
||||
header, err := headersCache.Fetch(ctx, slot)
|
||||
if err != nil {
|
||||
@@ -74,38 +45,7 @@ func AttestationHeadCorrect(ctx context.Context,
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
return bytes.Equal(header.Root[:], attestation.Data.BeaconBlockRoot[:]), nil
|
||||
}
|
||||
}
|
||||
|
||||
// AttestationTarget returns the target for which the attestation should have voted.
|
||||
func AttestationTarget(ctx context.Context,
|
||||
headersCache *BeaconBlockHeaderCache,
|
||||
chainTime chaintime.Service,
|
||||
attestation *phase0.Attestation,
|
||||
) (
|
||||
phase0.Root,
|
||||
error,
|
||||
) {
|
||||
// Start with first slot of the target epoch.
|
||||
slot := chainTime.FirstSlotOfEpoch(attestation.Data.Target.Epoch)
|
||||
for {
|
||||
header, err := headersCache.Fetch(ctx, slot)
|
||||
if err != nil {
|
||||
return phase0.Root{}, err
|
||||
}
|
||||
if header == nil {
|
||||
// No block.
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
if !header.Canonical {
|
||||
// Not canonical.
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
|
||||
return header.Root, nil
|
||||
return bytes.Equal(header.Root[:], attestationData.BeaconBlockRoot[:]), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,13 +53,13 @@ func AttestationTarget(ctx context.Context,
|
||||
func AttestationTargetCorrect(ctx context.Context,
|
||||
headersCache *BeaconBlockHeaderCache,
|
||||
chainTime chaintime.Service,
|
||||
attestation *phase0.Attestation,
|
||||
attestationData *phase0.AttestationData,
|
||||
) (
|
||||
bool,
|
||||
error,
|
||||
) {
|
||||
// Start with first slot of the target epoch.
|
||||
slot := chainTime.FirstSlotOfEpoch(attestation.Data.Target.Epoch)
|
||||
slot := chainTime.FirstSlotOfEpoch(attestationData.Target.Epoch)
|
||||
for {
|
||||
header, err := headersCache.Fetch(ctx, slot)
|
||||
if err != nil {
|
||||
@@ -135,6 +75,6 @@ func AttestationTargetCorrect(ctx context.Context,
|
||||
slot--
|
||||
continue
|
||||
}
|
||||
return bytes.Equal(header.Root[:], attestation.Data.Target.Root[:]), nil
|
||||
return bytes.Equal(header.Root[:], attestationData.Target.Root[:]), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,11 @@ var defaultBeaconNodeAddresses = []string{
|
||||
var fallbackBeaconNode = "http://mainnet-consensus.attestant.io/"
|
||||
|
||||
type ConnectOpts struct {
|
||||
Address string
|
||||
Timeout time.Duration
|
||||
AllowInsecure bool
|
||||
LogFallback bool
|
||||
Address string
|
||||
Timeout time.Duration
|
||||
AllowInsecure bool
|
||||
LogFallback bool
|
||||
CustomSpecSupport bool
|
||||
}
|
||||
|
||||
// ConnectToBeaconNode connects to a beacon node at the given address.
|
||||
@@ -56,12 +57,12 @@ func ConnectToBeaconNode(ctx context.Context, opts *ConnectOpts) (eth2client.Ser
|
||||
|
||||
if opts.Address != "" {
|
||||
// We have an explicit address; use it.
|
||||
return connectToBeaconNode(ctx, opts.Address, opts.Timeout, opts.AllowInsecure)
|
||||
return connectToBeaconNode(ctx, opts.Address, opts.Timeout, opts.AllowInsecure, opts.CustomSpecSupport)
|
||||
}
|
||||
|
||||
// Try the defaults.
|
||||
for _, address := range defaultBeaconNodeAddresses {
|
||||
client, err := connectToBeaconNode(ctx, address, opts.Timeout, opts.AllowInsecure)
|
||||
client, err := connectToBeaconNode(ctx, address, opts.Timeout, opts.AllowInsecure, opts.CustomSpecSupport)
|
||||
if err == nil {
|
||||
return client, nil
|
||||
}
|
||||
@@ -71,7 +72,7 @@ func ConnectToBeaconNode(ctx context.Context, opts *ConnectOpts) (eth2client.Ser
|
||||
if opts.LogFallback {
|
||||
fmt.Fprintf(os.Stderr, "No connection supplied with --connection parameter and no local beacon node found, attempting to use mainnet fallback\n")
|
||||
}
|
||||
client, err := connectToBeaconNode(ctx, fallbackBeaconNode, opts.Timeout, true)
|
||||
client, err := connectToBeaconNode(ctx, fallbackBeaconNode, opts.Timeout, true, opts.CustomSpecSupport)
|
||||
if err == nil {
|
||||
return client, nil
|
||||
}
|
||||
@@ -79,7 +80,7 @@ func ConnectToBeaconNode(ctx context.Context, opts *ConnectOpts) (eth2client.Ser
|
||||
return nil, errors.New("failed to connect to any beacon node")
|
||||
}
|
||||
|
||||
func connectToBeaconNode(ctx context.Context, address string, timeout time.Duration, allowInsecure bool) (eth2client.Service, error) {
|
||||
func connectToBeaconNode(ctx context.Context, address string, timeout time.Duration, allowInsecure bool, withCustomSpecSupport bool) (eth2client.Service, error) {
|
||||
if !strings.HasPrefix(address, "http") {
|
||||
address = fmt.Sprintf("http://%s", address)
|
||||
}
|
||||
@@ -101,6 +102,7 @@ func connectToBeaconNode(ctx context.Context, address string, timeout time.Durat
|
||||
http.WithLogLevel(zerolog.Disabled),
|
||||
http.WithAddress(address),
|
||||
http.WithTimeout(timeout),
|
||||
http.WithCustomSpecSupport(withCustomSpecSupport),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to connect to beacon node")
|
||||
|
||||
Reference in New Issue
Block a user