mirror of
https://github.com/wealdtech/ethdo.git
synced 2026-01-09 14:07:56 -05:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b450e96dde | ||
|
|
30d7f6989a | ||
|
|
00ea75e5c8 | ||
|
|
34647927ab | ||
|
|
44cfb68e2c | ||
|
|
70df67e6ab | ||
|
|
08fb16ff9e | ||
|
|
903ecc8581 | ||
|
|
93f4f6d68c | ||
|
|
1eee5a1349 | ||
|
|
9c4e9bcb2f | ||
|
|
83a950e5d1 | ||
|
|
b2c0ae3fa2 |
55
.github/workflows/docker.yml
vendored
55
.github/workflows/docker.yml
vendored
@@ -1,58 +1,45 @@
|
|||||||
name: Docker
|
name: Docker
|
||||||
|
|
||||||
|
# This workflow is triggered on a push to a tag that follows semantic versioning
|
||||||
|
# e.g., v1.2.3, v2.0.0-rc1
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v[0-9]+.[0-9]+.[0-9]+**'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Set variables that will be available to all builds.
|
# Build and push the Docker image
|
||||||
env_vars:
|
build-and-push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
|
||||||
release_version: ${{ steps.release_version.outputs.release_version }}
|
|
||||||
binary: ${{ steps.binary.outputs.binary }}
|
|
||||||
steps:
|
steps:
|
||||||
- id: release_version
|
- name: Check out repository
|
||||||
run: |
|
uses: actions/checkout@v4
|
||||||
RELEASE_VERSION=$(echo ${{ github.ref_name }} | sed -e 's/^[vt]//')
|
|
||||||
echo "release_version=${RELEASE_VERSION}" >> $GITHUB_OUTPUT
|
|
||||||
- id: binary
|
|
||||||
run: |
|
|
||||||
BINARY=$(basename ${{ github.repository }})
|
|
||||||
echo "binary=${BINARY}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Build.
|
# This step extracts the version number from the tag
|
||||||
build:
|
# e.g., if the tag is 'v1.2.3', this will output '1.2.3'
|
||||||
runs-on: ubuntu-latest
|
- name: Extract release version
|
||||||
needs: [env_vars]
|
id: release_version
|
||||||
steps:
|
run: |
|
||||||
- name: Check out repository into the Go module directory
|
echo "version=$(echo ${{ github.ref_name }} | sed -e 's/^v//')" >> $GITHUB_OUTPUT
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
push: true
|
push: true
|
||||||
tags: wealdtech/ethdo:latest
|
tags: |
|
||||||
|
wealdtech/ethdo:${{ steps.release_version.outputs.version }}
|
||||||
- name: build and push on release
|
wealdtech/ethdo:latest
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
if: ${{ github.event.release.tag_name != '' }}
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
|
||||||
push: true
|
|
||||||
tags: wealdtech/ethdo:${{ github.event.release.tag_name }}
|
|
||||||
|
|||||||
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,4 +1,14 @@
|
|||||||
dev:
|
dev:
|
||||||
|
|
||||||
|
1.39.0:
|
||||||
|
- support Fulu
|
||||||
|
|
||||||
|
1.38.0:
|
||||||
|
- update latest version of go-eth2-client to support complex Spec types
|
||||||
|
- adapt event handling to use new event handler structures in go-eth2-client
|
||||||
|
|
||||||
|
1.37.4:
|
||||||
|
- add support for eip-7044 in exit verify command
|
||||||
- provide ETH values as well as validator numbers in "epoch summary"
|
- provide ETH values as well as validator numbers in "epoch summary"
|
||||||
|
|
||||||
1.37.3:
|
1.37.3:
|
||||||
|
|||||||
@@ -528,6 +528,13 @@ func (c *command) analyzeSyncCommittees(_ context.Context, block *spec.Versioned
|
|||||||
c.analysis.SyncCommitee.Value = c.analysis.SyncCommitee.Score * float64(c.analysis.SyncCommitee.Contributions)
|
c.analysis.SyncCommitee.Value = c.analysis.SyncCommitee.Score * float64(c.analysis.SyncCommitee.Contributions)
|
||||||
c.analysis.Value += c.analysis.SyncCommitee.Value
|
c.analysis.Value += c.analysis.SyncCommitee.Value
|
||||||
return nil
|
return nil
|
||||||
|
case spec.DataVersionFulu:
|
||||||
|
c.analysis.SyncCommitee.Contributions = int(block.Fulu.Message.Body.SyncAggregate.SyncCommitteeBits.Count())
|
||||||
|
c.analysis.SyncCommitee.PossibleContributions = int(block.Fulu.Message.Body.SyncAggregate.SyncCommitteeBits.Len())
|
||||||
|
c.analysis.SyncCommitee.Score = float64(c.syncRewardWeight) / float64(c.weightDenominator)
|
||||||
|
c.analysis.SyncCommitee.Value = c.analysis.SyncCommitee.Score * float64(c.analysis.SyncCommitee.Contributions)
|
||||||
|
c.analysis.Value += c.analysis.SyncCommitee.Value
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported block version %d", block.Version)
|
return fmt.Errorf("unsupported block version %d", block.Version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
|
|||||||
err = processDenebBlock(ctx, data, block)
|
err = processDenebBlock(ctx, data, block)
|
||||||
case spec.DataVersionElectra:
|
case spec.DataVersionElectra:
|
||||||
err = processElectraBlock(ctx, data, block)
|
err = processElectraBlock(ctx, data, block)
|
||||||
|
case spec.DataVersionFulu:
|
||||||
|
err = processFuluBlock(ctx, data, block)
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unknown block version")
|
return nil, errors.New("unknown block version")
|
||||||
}
|
}
|
||||||
@@ -103,7 +105,10 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
|
|||||||
if !jsonOutput && !sszOutput {
|
if !jsonOutput && !sszOutput {
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
}
|
}
|
||||||
err := data.eth2Client.(eth2client.EventsProvider).Events(ctx, []string{"head"}, headEventHandler)
|
err := data.eth2Client.(eth2client.EventsProvider).Events(ctx, &api.EventsOpts{
|
||||||
|
Topics: []string{"head"},
|
||||||
|
HeadHandler: headEventHandler,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to start block stream")
|
return nil, errors.Wrap(err, "failed to start block stream")
|
||||||
}
|
}
|
||||||
@@ -212,15 +217,37 @@ func processElectraBlock(ctx context.Context,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func headEventHandler(event *apiv1.Event) {
|
func processFuluBlock(ctx context.Context,
|
||||||
ctx := context.Background()
|
data *dataIn,
|
||||||
|
block *spec.VersionedSignedBeaconBlock,
|
||||||
// Only interested in head events.
|
) error {
|
||||||
if event.Topic != "head" {
|
var blobSidecars []*deneb.BlobSidecar
|
||||||
return
|
kzgCommitments, err := block.BlobKZGCommitments()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(kzgCommitments) > 0 {
|
||||||
|
blobSidecarsResponse, err := results.eth2Client.(eth2client.BlobSidecarsProvider).BlobSidecars(ctx, &api.BlobSidecarsOpts{
|
||||||
|
Block: data.blockID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
var apiErr *api.Error
|
||||||
|
if errors.As(err, &apiErr) && apiErr.StatusCode != http.StatusNotFound {
|
||||||
|
return errors.Wrap(err, "failed to obtain blob sidecars")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blobSidecars = blobSidecarsResponse.Data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := outputFuluBlock(ctx, data.jsonOutput, data.sszOutput, block.Fulu, blobSidecars); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to output block")
|
||||||
}
|
}
|
||||||
|
|
||||||
blockID := fmt.Sprintf("%#x", event.Data.(*apiv1.HeadEvent).Block[:])
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func headEventHandler(ctx context.Context, headEvent *apiv1.HeadEvent) {
|
||||||
|
blockID := fmt.Sprintf("%#x", headEvent.Block[:])
|
||||||
blockResponse, err := results.eth2Client.(eth2client.SignedBeaconBlockProvider).SignedBeaconBlock(ctx, &api.SignedBeaconBlockOpts{
|
blockResponse, err := results.eth2Client.(eth2client.SignedBeaconBlockProvider).SignedBeaconBlock(ctx, &api.SignedBeaconBlockOpts{
|
||||||
Block: blockID,
|
Block: blockID,
|
||||||
})
|
})
|
||||||
@@ -267,6 +294,46 @@ func headEventHandler(event *apiv1.Event) {
|
|||||||
blobSidecars = blobSidecarsResponse.Data
|
blobSidecars = blobSidecarsResponse.Data
|
||||||
}
|
}
|
||||||
err = outputDenebBlock(context.Background(), jsonOutput, sszOutput, block.Deneb, blobSidecars)
|
err = outputDenebBlock(context.Background(), jsonOutput, sszOutput, block.Deneb, blobSidecars)
|
||||||
|
case spec.DataVersionElectra:
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
err = outputElectraBlock(context.Background(), jsonOutput, sszOutput, block.Electra, blobSidecars)
|
||||||
|
case spec.DataVersionFulu:
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
err = outputFuluBlock(context.Background(), jsonOutput, sszOutput, block.Fulu, blobSidecars)
|
||||||
default:
|
default:
|
||||||
err = errors.New("unknown block version")
|
err = errors.New("unknown block version")
|
||||||
}
|
}
|
||||||
@@ -428,6 +495,35 @@ func outputElectraBlock(ctx context.Context,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func outputFuluBlock(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) {
|
func timeToBlockID(ctx context.Context, eth2Client eth2client.Service, input string) (string, error) {
|
||||||
var timestamp time.Time
|
var timestamp time.Time
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,9 @@ func (c *command) process(ctx context.Context) error {
|
|||||||
case spec.DataVersionElectra:
|
case spec.DataVersionElectra:
|
||||||
c.incumbent = state.Electra.ETH1Data
|
c.incumbent = state.Electra.ETH1Data
|
||||||
c.eth1DataVotes = state.Electra.ETH1DataVotes
|
c.eth1DataVotes = state.Electra.ETH1DataVotes
|
||||||
|
case spec.DataVersionFulu:
|
||||||
|
c.incumbent = state.Fulu.ETH1Data
|
||||||
|
c.eth1DataVotes = state.Fulu.ETH1DataVotes
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unhandled beacon state version %v", state.Version)
|
return fmt.Errorf("unhandled beacon state version %v", state.Version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -529,6 +529,8 @@ func (c *command) processBlobs(ctx context.Context) error {
|
|||||||
c.summary.Blobs += len(block.Deneb.Message.Body.BlobKZGCommitments)
|
c.summary.Blobs += len(block.Deneb.Message.Body.BlobKZGCommitments)
|
||||||
case spec.DataVersionElectra:
|
case spec.DataVersionElectra:
|
||||||
c.summary.Blobs += len(block.Electra.Message.Body.BlobKZGCommitments)
|
c.summary.Blobs += len(block.Electra.Message.Body.BlobKZGCommitments)
|
||||||
|
case spec.DataVersionFulu:
|
||||||
|
c.summary.Blobs += len(block.Fulu.Message.Body.BlobKZGCommitments)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unhandled block version %v", block.Version)
|
return fmt.Errorf("unhandled block version %v", block.Version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
eth2client "github.com/attestantio/go-eth2-client"
|
eth2client "github.com/attestantio/go-eth2-client"
|
||||||
api "github.com/attestantio/go-eth2-client/api/v1"
|
"github.com/attestantio/go-eth2-client/api"
|
||||||
|
apiv1 "github.com/attestantio/go-eth2-client/api/v1"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,7 +29,10 @@ func process(ctx context.Context, data *dataIn) error {
|
|||||||
return errors.New("no data")
|
return errors.New("no data")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := data.eth2Client.(eth2client.EventsProvider).Events(ctx, data.topics, eventHandler)
|
err := data.eth2Client.(eth2client.EventsProvider).Events(ctx, &api.EventsOpts{
|
||||||
|
Topics: data.topics,
|
||||||
|
Handler: eventHandler,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to connect for events")
|
return errors.Wrap(err, "failed to connect for events")
|
||||||
}
|
}
|
||||||
@@ -38,7 +42,7 @@ func process(ctx context.Context, data *dataIn) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func eventHandler(event *api.Event) {
|
func eventHandler(event *apiv1.Event) {
|
||||||
if event.Data == nil {
|
if event.Data == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,13 @@ func (c *command) process(ctx context.Context) error {
|
|||||||
} else {
|
} else {
|
||||||
c.inclusions = append(c.inclusions, 2)
|
c.inclusions = append(c.inclusions, 2)
|
||||||
}
|
}
|
||||||
|
case spec.DataVersionFulu:
|
||||||
|
aggregate = block.Fulu.Message.Body.SyncAggregate
|
||||||
|
if aggregate.SyncCommitteeBits.BitAt(c.committeeIndex) {
|
||||||
|
c.inclusions = append(c.inclusions, 1)
|
||||||
|
} else {
|
||||||
|
c.inclusions = append(c.inclusions, 2)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unhandled block version %v", block.Version)
|
return fmt.Errorf("unhandled block version %v", block.Version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
// ReleaseVersion is the release version of the codebase.
|
// ReleaseVersion is the release version of the codebase.
|
||||||
// Usually overridden by tag names when building binaries.
|
// Usually overridden by tag names when building binaries.
|
||||||
var ReleaseVersion = "local build (latest release 1.37.4)"
|
var ReleaseVersion = "local build (latest release 1.39.0)"
|
||||||
|
|
||||||
// versionCmd represents the version command.
|
// versionCmd represents the version command.
|
||||||
var versionCmd = &cobra.Command{
|
var versionCmd = &cobra.Command{
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -5,7 +5,7 @@ go 1.23.0
|
|||||||
toolchain go1.23.2
|
toolchain go1.23.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/attestantio/go-eth2-client v0.24.1
|
github.com/attestantio/go-eth2-client v0.27.1
|
||||||
github.com/ferranbt/fastssz v0.1.4
|
github.com/ferranbt/fastssz v0.1.4
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible
|
github.com/gofrs/uuid v4.4.0+incompatible
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,5 +1,5 @@
|
|||||||
github.com/attestantio/go-eth2-client v0.24.1 h1:DZ/2O83eUcSfPPs63xF6fdXDe4afA4nlt5j0y2cweOI=
|
github.com/attestantio/go-eth2-client v0.27.1 h1:g7bm+gG/p+gfzYdEuxuAepVWYb8EO+2KojV5/Lo2BxM=
|
||||||
github.com/attestantio/go-eth2-client v0.24.1/go.mod h1:/KTLN3WuH1xrJL7ZZrpBoWM1xCCihnFbzequD5L+83o=
|
github.com/attestantio/go-eth2-client v0.27.1/go.mod h1:fvULSL9WtNskkOB4i+Yyr6BKpNHXvmpGZj9969fCrfY=
|
||||||
github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk=
|
github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk=
|
||||||
github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
|||||||
Reference in New Issue
Block a user