Skip to content

Instantly share code, notes, and snippets.

@rauljordan
Created February 2, 2022 02:38
Show Gist options
  • Save rauljordan/4b18de3ec74df6c25cdb1eefe1510b66 to your computer and use it in GitHub Desktop.
Save rauljordan/4b18de3ec74df6c25cdb1eefe1510b66 to your computer and use it in GitHub Desktop.
Prysm gRPC Indexed Attestation Parsing
module github.com/rauljordan/attestation-parse
go 1.17
require (
github.com/golang/protobuf v1.5.2
github.com/prysmaticlabs/prysm/v2 v2.0.1
google.golang.org/grpc v1.37.0
)
require (
github.com/btcsuite/btcd v0.22.0-beta // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
github.com/dgraph-io/ristretto v0.0.4-0.20210318174700-74754f61e018 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/ethereum/go-ethereum v1.9.25 // indirect
github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect
github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect
github.com/klauspost/cpuid/v2 v2.0.8 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prysmaticlabs/eth2-types v0.0.0-20210303084904-c9735a06829d // indirect
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/supranational/blst v0.3.5 // indirect
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect
github.com/urfave/cli/v2 v2.3.0 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
golang.org/x/net v0.0.0-20210716203947-853a461950ff // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/genproto v0.0.0-20210426193834-eac7f76ac494 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
package main
import (
"context"
"fmt"
"sort"
"github.com/golang/protobuf/ptypes/empty"
ethpb "github.com/prysmaticlabs/prysm/v2/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v2/proto/prysm/v1alpha1/attestation"
"google.golang.org/grpc"
)
func main() {
client, err := grpc.Dial("localhost:4000", grpc.WithInsecure())
if err != nil {
panic(err)
}
beaconClient := ethpb.NewBeaconChainClient(client)
ctx := context.Background()
head, err := beaconClient.GetChainHead(ctx, &empty.Empty{})
if err != nil {
panic(err)
}
fmt.Printf("Head slot %d, epoch %d\n", head.HeadSlot, head.HeadEpoch)
fmt.Println("Fetching beacon committees (this can take a min)...")
committeesResp, err := beaconClient.ListBeaconCommittees(ctx, &ethpb.ListCommitteesRequest{
QueryFilter: &ethpb.ListCommitteesRequest_Epoch{
Epoch: head.HeadEpoch,
},
})
slots := make([]uint64, 0)
for k := range committeesResp.Committees {
slots = append(slots, k)
}
sort.SliceStable(slots, func(i, j int) bool {
return slots[i] < slots[j]
})
fmt.Printf("Committee lowest slot %d and highest %d\n", slots[0], slots[len(slots)-1])
fmt.Printf("Fetching beacon blocks for head epoch %d...\n", head.HeadEpoch)
blocksResp, err := beaconClient.ListBeaconBlocks(ctx, &ethpb.ListBlocksRequest{
QueryFilter: &ethpb.ListBlocksRequest_Epoch{
Epoch: head.HeadEpoch,
},
})
// TODO: Get the last few epochs worth of committees, as some attestations could be from committees in past epochs.
fmt.Printf("Found %d blocks in epoch %d\n", len(blocksResp.BlockContainers), head.HeadEpoch)
attestationsInEpoch := make([]*ethpb.Attestation, 0)
for _, blk := range blocksResp.BlockContainers {
cntr, ok := blk.Block.(*ethpb.BeaconBlockContainer_AltairBlock)
if !ok {
panic("not an altair block")
}
signedBlock := cntr.AltairBlock
block := signedBlock.Block
attestationsInEpoch = append(attestationsInEpoch, block.Body.Attestations...)
}
fmt.Printf("Found %d attestations in epoch %d\n", len(attestationsInEpoch), head.HeadEpoch)
indexedAttestations := make([]*ethpb.IndexedAttestation, len(attestationsInEpoch))
for _, att := range attestationsInEpoch {
committeesForSlot, ok := committeesResp.Committees[uint64(att.Data.Slot)]
if !ok {
// We should get at least 2 epochs worth of committees so this should not happen.
continue
}
committeeForAttestation := committeesForSlot.Committees[att.Data.CommitteeIndex]
indexedAtt, err := attestation.ConvertToIndexed(ctx, att, committeeForAttestation.ValidatorIndices)
if err != nil {
panic(err)
}
indexedAttestations = append(indexedAttestations, indexedAtt)
}
fmt.Printf("Converted %d attestations to indexed form\n", len(indexedAttestations))
_ = indexedAttestations // Do something with the validator indices within.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment