From bdacbed4597af3f09f18fc40dc60981890912237 Mon Sep 17 00:00:00 2001 From: Giulio Date: Wed, 3 Jan 2024 20:09:23 +0100 Subject: [PATCH 1/3] save --- cl/persistence/state/epoch_data.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cl/persistence/state/epoch_data.go b/cl/persistence/state/epoch_data.go index a269360abc0..7b6ed7e963e 100644 --- a/cl/persistence/state/epoch_data.go +++ b/cl/persistence/state/epoch_data.go @@ -33,6 +33,8 @@ func EpochDataFromBeaconState(s *state.CachingBeaconState) *EpochData { CurrentJustifiedCheckpoint: s.CurrentJustifiedCheckpoint(), PreviousJustifiedCheckpoint: s.PreviousJustifiedCheckpoint(), FinalizedCheckpoint: s.FinalizedCheckpoint(), + HistoricalSummariesLength: s.HistoricalSummariesLength(), + HistoricalRootsLength: s.HistoricalRootsLength(), } } From 900a93ad80333fd1b7090ead9e24560d4bee3487 Mon Sep 17 00:00:00 2001 From: Giulio Date: Wed, 3 Jan 2024 20:43:19 +0100 Subject: [PATCH 2/3] save --- cl/antiquary/antiquary.go | 2 +- cl/beacon/handler/handler.go | 13 ++++++----- cl/beacon/handler/pool.go | 37 ++++++++++++++++++++++++++----- cl/beacon/validatorapi/handler.go | 4 +++- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/cl/antiquary/antiquary.go b/cl/antiquary/antiquary.go index 07bdf0f9ad1..a0f97b41fa5 100644 --- a/cl/antiquary/antiquary.go +++ b/cl/antiquary/antiquary.go @@ -249,7 +249,7 @@ func (a *Antiquary) antiquate(version uint8, from, to uint64) error { } // Notify bittorent to seed the new snapshots if _, err := a.downloader.Add(a.ctx, &proto_downloader.AddRequest{Items: downloadItems}); err != nil { - return err + log.Warn("[Antiquary]: Failed to add items to bittorent", "err", err) } tx, err := a.mainDB.BeginRw(a.ctx) diff --git a/cl/beacon/handler/handler.go b/cl/beacon/handler/handler.go index 92b6d07d699..75ace989bb2 100644 --- a/cl/beacon/handler/handler.go +++ b/cl/beacon/handler/handler.go @@ -5,6 +5,7 @@ import ( "sync" "github.com/go-chi/chi/v5" + "github.com/ledgerwatch/erigon-lib/gointerfaces/sentinel" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/cl/beacon/beaconhttp" "github.com/ledgerwatch/erigon/cl/beacon/synced_data" @@ -29,6 +30,7 @@ type ApiHandler struct { operationsPool pool.OperationsPool syncedData *synced_data.SyncedDataManager stateReader *historical_states_reader.HistoricalStatesReader + sentinel sentinel.SentinelClient // pools randaoMixesPool sync.Pool @@ -73,12 +75,11 @@ func (a *ApiHandler) init() { r.Get("/genesis", beaconhttp.HandleEndpointFunc(a.getGenesis)) r.Get("/blinded_blocks/{block_id}", beaconhttp.HandleEndpointFunc(a.getBlindedBlock)) r.Route("/pool", func(r chi.Router) { - r.Post("/attestations", http.NotFound) - r.Get("/voluntary_exits", beaconhttp.HandleEndpointFunc(a.poolVoluntaryExits)) - r.Get("/attester_slashings", beaconhttp.HandleEndpointFunc(a.poolAttesterSlashings)) - r.Get("/proposer_slashings", beaconhttp.HandleEndpointFunc(a.poolProposerSlashings)) - r.Get("/bls_to_execution_changes", beaconhttp.HandleEndpointFunc(a.poolBlsToExecutionChanges)) - r.Get("/attestations", beaconhttp.HandleEndpointFunc(a.poolAttestations)) + r.Get("/voluntary_exits", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolVoluntaryExits)) + r.Get("/attester_slashings", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolAttesterSlashings)) + r.Get("/proposer_slashings", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolProposerSlashings)) + r.Get("/bls_to_execution_changes", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolBLSExecutionChanges)) + r.Get("/attestations", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolAttestations)) r.Post("/sync_committees", http.NotFound) }) r.Get("/node/syncing", http.NotFound) diff --git a/cl/beacon/handler/pool.go b/cl/beacon/handler/pool.go index 8289d2b22a2..f9d10f22393 100644 --- a/cl/beacon/handler/pool.go +++ b/cl/beacon/handler/pool.go @@ -2,24 +2,49 @@ package handler import ( "net/http" + + "github.com/ledgerwatch/erigon/cl/beacon/beaconhttp" ) -func (a *ApiHandler) poolVoluntaryExits(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { +func (a *ApiHandler) GetEthV1BeaconPoolVoluntaryExits(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { return newBeaconResponse(a.operationsPool.VoluntaryExistsPool.Raw()), nil } -func (a *ApiHandler) poolAttesterSlashings(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { +func (a *ApiHandler) GetEthV1BeaconPoolAttesterSlashings(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { return newBeaconResponse(a.operationsPool.AttesterSlashingsPool.Raw()), nil } -func (a *ApiHandler) poolProposerSlashings(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { +func (a *ApiHandler) GetEthV1BeaconPoolProposerSlashings(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { return newBeaconResponse(a.operationsPool.ProposerSlashingsPool.Raw()), nil } -func (a *ApiHandler) poolBlsToExecutionChanges(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { +func (a *ApiHandler) GetEthV1BeaconPoolBLSExecutionChanges(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { return newBeaconResponse(a.operationsPool.BLSToExecutionChangesPool.Raw()), nil } -func (a *ApiHandler) poolAttestations(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { - return newBeaconResponse(a.operationsPool.AttestationsPool.Raw()), nil +func (a *ApiHandler) GetEthV1BeaconPoolAttestations(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { + slot, err := uint64FromQueryParams(r, "slot") + if err != nil { + return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error()) + } + committeeIndex, err := uint64FromQueryParams(r, "committee_index") + if err != nil { + return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err.Error()) + } + atts := a.operationsPool.AttestationsPool.Raw() + if slot == nil && committeeIndex == nil { + return newBeaconResponse(atts), nil + } + ret := make([]any, 0, len(atts)) + for i := range atts { + if slot != nil && atts[i].AttestantionData().Slot() != *slot { + continue + } + if committeeIndex != nil && atts[i].AttestantionData().ValidatorIndex() != *committeeIndex { + continue + } + ret = append(ret, atts[i]) + } + + return newBeaconResponse(ret), nil } diff --git a/cl/beacon/validatorapi/handler.go b/cl/beacon/validatorapi/handler.go index 921d1e607dd..41e9190fa6d 100644 --- a/cl/beacon/validatorapi/handler.go +++ b/cl/beacon/validatorapi/handler.go @@ -48,7 +48,9 @@ func (v *ValidatorApiHandler) Route(r chi.Router) { r.Post("/attestations", beaconhttp.HandleEndpointFunc(v.PostEthV1BeaconPoolAttestations)) r.Post("/sync_committees", beaconhttp.HandleEndpointFunc(v.PostEthV1BeaconPoolAttestations)) }) - r.Get("/node/syncing", beaconhttp.HandleEndpointFunc(v.GetEthV1NodeSyncing)) + }) + r.Route("/node", func(r chi.Router) { + r.Get("/syncing", beaconhttp.HandleEndpointFunc(v.GetEthV1NodeSyncing)) }) r.Get("/events", v.EventSourceGetV1Events) r.Route("/validator", func(r chi.Router) { From 29619fd1e2033e0daea6066aaa642cf1c7359d9d Mon Sep 17 00:00:00 2001 From: Giulio Date: Wed, 3 Jan 2024 22:26:29 +0100 Subject: [PATCH 3/3] save --- cl/beacon/handler/handler.go | 11 +- cl/beacon/handler/pool.go | 143 +++++++++++++++++ cl/beacon/handler/pool_test.go | 197 ++++++++++++++++++++++++ cl/beacon/handler/utils_test.go | 4 +- cl/cltypes/indexed_attestation.go | 7 + cl/cltypes/slashings.go | 7 + cl/cltypes/solid/attestation_data.go | 2 + cl/cltypes/solid/uint64_raw_list.go | 16 ++ cl/phase1/forkchoice/forkchoice_mock.go | 24 ++- cl/phase1/forkchoice/interface.go | 3 + cmd/caplin/caplin1/run.go | 2 +- 11 files changed, 409 insertions(+), 7 deletions(-) create mode 100644 cl/beacon/handler/pool_test.go diff --git a/cl/beacon/handler/handler.go b/cl/beacon/handler/handler.go index 75ace989bb2..fb4e5aa63f6 100644 --- a/cl/beacon/handler/handler.go +++ b/cl/beacon/handler/handler.go @@ -36,10 +36,10 @@ type ApiHandler struct { randaoMixesPool sync.Pool } -func NewApiHandler(genesisConfig *clparams.GenesisConfig, beaconChainConfig *clparams.BeaconChainConfig, source persistence.RawBeaconBlockChain, indiciesDB kv.RoDB, forkchoiceStore forkchoice.ForkChoiceStorage, operationsPool pool.OperationsPool, rcsn freezeblocks.BeaconSnapshotReader, syncedData *synced_data.SyncedDataManager, stateReader *historical_states_reader.HistoricalStatesReader) *ApiHandler { +func NewApiHandler(genesisConfig *clparams.GenesisConfig, beaconChainConfig *clparams.BeaconChainConfig, source persistence.RawBeaconBlockChain, indiciesDB kv.RoDB, forkchoiceStore forkchoice.ForkChoiceStorage, operationsPool pool.OperationsPool, rcsn freezeblocks.BeaconSnapshotReader, syncedData *synced_data.SyncedDataManager, stateReader *historical_states_reader.HistoricalStatesReader, sentinel sentinel.SentinelClient) *ApiHandler { return &ApiHandler{o: sync.Once{}, genesisCfg: genesisConfig, beaconChainCfg: beaconChainConfig, indiciesDB: indiciesDB, forkchoiceStore: forkchoiceStore, operationsPool: operationsPool, blockReader: rcsn, syncedData: syncedData, stateReader: stateReader, randaoMixesPool: sync.Pool{New: func() interface{} { return solid.NewHashVector(int(beaconChainConfig.EpochsPerHistoricalVector)) - }}} + }}, sentinel: sentinel} } func (a *ApiHandler) init() { @@ -76,11 +76,16 @@ func (a *ApiHandler) init() { r.Get("/blinded_blocks/{block_id}", beaconhttp.HandleEndpointFunc(a.getBlindedBlock)) r.Route("/pool", func(r chi.Router) { r.Get("/voluntary_exits", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolVoluntaryExits)) + r.Post("/voluntary_exits", a.PostEthV1BeaconPoolVoluntaryExits) r.Get("/attester_slashings", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolAttesterSlashings)) + r.Post("/attester_slashings", a.PostEthV1BeaconPoolAttesterSlashings) r.Get("/proposer_slashings", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolProposerSlashings)) + r.Post("/proposer_slashings", a.PostEthV1BeaconPoolProposerSlashings) r.Get("/bls_to_execution_changes", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolBLSExecutionChanges)) + r.Post("/bls_to_execution_changes", a.PostEthV1BeaconPoolBlsToExecutionChanges) r.Get("/attestations", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolAttestations)) - r.Post("/sync_committees", http.NotFound) + r.Post("/attestations", http.NotFound) // TODO + r.Post("/sync_committees", http.NotFound) // TODO }) r.Get("/node/syncing", http.NotFound) r.Route("/states", func(r chi.Router) { diff --git a/cl/beacon/handler/pool.go b/cl/beacon/handler/pool.go index f9d10f22393..a628a958ae7 100644 --- a/cl/beacon/handler/pool.go +++ b/cl/beacon/handler/pool.go @@ -1,9 +1,14 @@ package handler import ( + "encoding/json" + "fmt" "net/http" + "github.com/ledgerwatch/erigon-lib/gointerfaces/sentinel" "github.com/ledgerwatch/erigon/cl/beacon/beaconhttp" + "github.com/ledgerwatch/erigon/cl/cltypes" + "github.com/ledgerwatch/erigon/cl/gossip" ) func (a *ApiHandler) GetEthV1BeaconPoolVoluntaryExits(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { @@ -11,6 +16,7 @@ func (a *ApiHandler) GetEthV1BeaconPoolVoluntaryExits(w http.ResponseWriter, r * } func (a *ApiHandler) GetEthV1BeaconPoolAttesterSlashings(w http.ResponseWriter, r *http.Request) (*beaconResponse, error) { + fmt.Println("GetEthV1BeaconPoolAttesterSlashings", a.operationsPool.AttesterSlashingsPool.Raw()) return newBeaconResponse(a.operationsPool.AttesterSlashingsPool.Raw()), nil } @@ -48,3 +54,140 @@ func (a *ApiHandler) GetEthV1BeaconPoolAttestations(w http.ResponseWriter, r *ht return newBeaconResponse(ret), nil } + +func (a *ApiHandler) PostEthV1BeaconPoolVoluntaryExits(w http.ResponseWriter, r *http.Request) { + req := cltypes.SignedVoluntaryExit{} + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if err := a.forkchoiceStore.OnVoluntaryExit(&req, false); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + // Broadcast to gossip + if a.sentinel != nil { + encodedSSZ, err := req.EncodeSSZ(nil) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if _, err := a.sentinel.PublishGossip(r.Context(), &sentinel.GossipData{ + Data: encodedSSZ, + Name: gossip.TopicNameVoluntaryExit, + }); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + a.operationsPool.VoluntaryExistsPool.Insert(req.VoluntaryExit.ValidatorIndex, &req) + } + // Only write 200 + w.WriteHeader(http.StatusOK) +} + +func (a *ApiHandler) PostEthV1BeaconPoolAttesterSlashings(w http.ResponseWriter, r *http.Request) { + req := cltypes.NewAttesterSlashing() + if err := json.NewDecoder(r.Body).Decode(req); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if err := a.forkchoiceStore.OnAttesterSlashing(req, false); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + // Broadcast to gossip + if a.sentinel != nil { + encodedSSZ, err := req.EncodeSSZ(nil) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if _, err := a.sentinel.PublishGossip(r.Context(), &sentinel.GossipData{ + Data: encodedSSZ, + Name: gossip.TopicNameAttesterSlashing, + }); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + // Only write 200 + w.WriteHeader(http.StatusOK) +} + +func (a *ApiHandler) PostEthV1BeaconPoolProposerSlashings(w http.ResponseWriter, r *http.Request) { + req := cltypes.ProposerSlashing{} + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if err := a.forkchoiceStore.OnProposerSlashing(&req, false); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + // Broadcast to gossip + if a.sentinel != nil { + encodedSSZ, err := req.EncodeSSZ(nil) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if _, err := a.sentinel.PublishGossip(r.Context(), &sentinel.GossipData{ + Data: encodedSSZ, + Name: gossip.TopicNameProposerSlashing, + }); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + // Only write 200 + w.WriteHeader(http.StatusOK) +} + +type poolingFailure struct { + Index int `json:"index"` + Message string `json:"message"` +} + +type poolingError struct { + Code int `json:"code"` + Message string `json:"message"` + Failures []poolingFailure `json:"failures"` +} + +func (a *ApiHandler) PostEthV1BeaconPoolBlsToExecutionChanges(w http.ResponseWriter, r *http.Request) { + req := []*cltypes.SignedBLSToExecutionChange{} + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + failures := []poolingFailure{} + for _, v := range req { + if err := a.forkchoiceStore.OnBlsToExecutionChange(v, false); err != nil { + failures = append(failures, poolingFailure{Index: len(failures), Message: err.Error()}) + continue + } + // Broadcast to gossip + if a.sentinel != nil { + encodedSSZ, err := v.EncodeSSZ(nil) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if _, err := a.sentinel.PublishGossip(r.Context(), &sentinel.GossipData{ + Data: encodedSSZ, + Name: gossip.TopicNameBlsToExecutionChange, + }); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + } + + if len(failures) > 0 { + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(poolingError{Code: http.StatusBadRequest, Message: "some failures", Failures: failures}) + return + } + // Only write 200 + w.WriteHeader(http.StatusOK) +} diff --git a/cl/beacon/handler/pool_test.go b/cl/beacon/handler/pool_test.go new file mode 100644 index 00000000000..170f7f564cd --- /dev/null +++ b/cl/beacon/handler/pool_test.go @@ -0,0 +1,197 @@ +package handler + +import ( + "bytes" + "encoding/json" + "net/http/httptest" + "testing" + + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/cl/clparams" + "github.com/ledgerwatch/erigon/cl/cltypes" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" + "github.com/stretchr/testify/require" +) + +func TestPoolAttesterSlashings(t *testing.T) { + attesterSlashing := &cltypes.AttesterSlashing{ + Attestation_1: &cltypes.IndexedAttestation{ + AttestingIndices: solid.NewRawUint64List(2048, []uint64{2, 3, 4, 5, 6}), + Data: solid.NewAttestationData(), + }, + Attestation_2: &cltypes.IndexedAttestation{ + AttestingIndices: solid.NewRawUint64List(2048, []uint64{2, 3, 4, 1, 6}), + Data: solid.NewAttestationData(), + }, + } + // find server + _, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version) + + server := httptest.NewServer(handler.mux) + defer server.Close() + // json + req, err := json.Marshal(attesterSlashing) + require.NoError(t, err) + // post attester slashing + resp, err := server.Client().Post(server.URL+"/eth/v1/beacon/pool/attester_slashings", "application/json", bytes.NewBuffer(req)) + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, 200, resp.StatusCode) + // get attester slashings + resp, err = server.Client().Get(server.URL + "/eth/v1/beacon/pool/attester_slashings") + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, 200, resp.StatusCode) + out := struct { + Data []*cltypes.AttesterSlashing `json:"data"` + }{ + Data: []*cltypes.AttesterSlashing{ + cltypes.NewAttesterSlashing(), + }, + } + + err = json.NewDecoder(resp.Body).Decode(&out) + require.NoError(t, err) + + require.Equal(t, 1, len(out.Data)) + require.Equal(t, attesterSlashing, out.Data[0]) +} + +func TestPoolProposerSlashings(t *testing.T) { + proposerSlashing := &cltypes.ProposerSlashing{ + Header1: &cltypes.SignedBeaconBlockHeader{ + Header: &cltypes.BeaconBlockHeader{ + Slot: 1, + ProposerIndex: 3, + }, + }, + Header2: &cltypes.SignedBeaconBlockHeader{ + Header: &cltypes.BeaconBlockHeader{ + Slot: 2, + ProposerIndex: 4, + }, + }, + } + // find server + _, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version) + + server := httptest.NewServer(handler.mux) + defer server.Close() + // json + req, err := json.Marshal(proposerSlashing) + require.NoError(t, err) + + // post attester slashing + resp, err := server.Client().Post(server.URL+"/eth/v1/beacon/pool/proposer_slashings", "application/json", bytes.NewBuffer(req)) + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, 200, resp.StatusCode) + // get attester slashings + resp, err = server.Client().Get(server.URL + "/eth/v1/beacon/pool/proposer_slashings") + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, 200, resp.StatusCode) + out := struct { + Data []*cltypes.ProposerSlashing `json:"data"` + }{ + Data: []*cltypes.ProposerSlashing{}, + } + + err = json.NewDecoder(resp.Body).Decode(&out) + require.NoError(t, err) + + require.Equal(t, 1, len(out.Data)) + require.Equal(t, proposerSlashing, out.Data[0]) +} + +func TestPoolVoluntaryExits(t *testing.T) { + voluntaryExit := &cltypes.SignedVoluntaryExit{ + VoluntaryExit: &cltypes.VoluntaryExit{ + Epoch: 1, + ValidatorIndex: 3, + }, + } + // find server + _, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version) + + server := httptest.NewServer(handler.mux) + defer server.Close() + // json + req, err := json.Marshal(voluntaryExit) + require.NoError(t, err) + // post attester slashing + resp, err := server.Client().Post(server.URL+"/eth/v1/beacon/pool/voluntary_exits", "application/json", bytes.NewBuffer(req)) + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, 200, resp.StatusCode) + // get attester slashings + resp, err = server.Client().Get(server.URL + "/eth/v1/beacon/pool/voluntary_exits") + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, 200, resp.StatusCode) + out := struct { + Data []*cltypes.SignedVoluntaryExit `json:"data"` + }{ + Data: []*cltypes.SignedVoluntaryExit{}, + } + + err = json.NewDecoder(resp.Body).Decode(&out) + require.NoError(t, err) + + require.Equal(t, 1, len(out.Data)) + require.Equal(t, voluntaryExit, out.Data[0]) +} + +func TestPoolBlsToExecutionChainges(t *testing.T) { + msg := []*cltypes.SignedBLSToExecutionChange{ + { + Message: &cltypes.BLSToExecutionChange{ + ValidatorIndex: 45, + }, + Signature: libcommon.Bytes96{2}, + }, + { + Message: &cltypes.BLSToExecutionChange{ + ValidatorIndex: 46, + }, + }, + } + // find server + _, _, _, _, _, handler, _, _, _ := setupTestingHandler(t, clparams.Phase0Version) + + server := httptest.NewServer(handler.mux) + defer server.Close() + // json + req, err := json.Marshal(msg) + require.NoError(t, err) + // post attester slashing + resp, err := server.Client().Post(server.URL+"/eth/v1/beacon/pool/bls_to_execution_changes", "application/json", bytes.NewBuffer(req)) + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, 200, resp.StatusCode) + // get attester slashings + resp, err = server.Client().Get(server.URL + "/eth/v1/beacon/pool/bls_to_execution_changes") + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, 200, resp.StatusCode) + out := struct { + Data []*cltypes.SignedBLSToExecutionChange `json:"data"` + }{ + Data: []*cltypes.SignedBLSToExecutionChange{}, + } + + err = json.NewDecoder(resp.Body).Decode(&out) + require.NoError(t, err) + + require.Equal(t, 2, len(out.Data)) + require.Equal(t, msg[0], out.Data[0]) + require.Equal(t, msg[1], out.Data[1]) +} diff --git a/cl/beacon/handler/utils_test.go b/cl/beacon/handler/utils_test.go index 9dd231bd83a..f4117fa176f 100644 --- a/cl/beacon/handler/utils_test.go +++ b/cl/beacon/handler/utils_test.go @@ -49,6 +49,7 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion) (db kv.RwDB, blo // historical states reader below statesReader := historical_states_reader.NewHistoricalStatesReader(&bcfg, reader, vt, f, preState) opPool = pool.NewOperationsPool(&bcfg) + fcu.Pool = opPool syncedData = synced_data.NewSyncedDataManager(true, &bcfg) gC := clparams.GenesisConfigs[clparams.MainnetNetwork] handler = NewApiHandler( @@ -60,7 +61,8 @@ func setupTestingHandler(t *testing.T, v clparams.StateVersion) (db kv.RwDB, blo opPool, reader, syncedData, - statesReader) + statesReader, + nil) handler.init() return } diff --git a/cl/cltypes/indexed_attestation.go b/cl/cltypes/indexed_attestation.go index 4173429d8a0..1464c8eb158 100644 --- a/cl/cltypes/indexed_attestation.go +++ b/cl/cltypes/indexed_attestation.go @@ -16,6 +16,13 @@ type IndexedAttestation struct { Signature libcommon.Bytes96 `json:"signature"` } +func NewIndexedAttestation() *IndexedAttestation { + return &IndexedAttestation{ + AttestingIndices: solid.NewRawUint64List(2048, nil), + Data: solid.NewAttestationData(), + } +} + func (i *IndexedAttestation) Static() bool { return false } diff --git a/cl/cltypes/slashings.go b/cl/cltypes/slashings.go index f849b7b50ee..b7ef50dc656 100644 --- a/cl/cltypes/slashings.go +++ b/cl/cltypes/slashings.go @@ -33,6 +33,13 @@ type AttesterSlashing struct { Attestation_2 *IndexedAttestation `json:"attestation_2"` } +func NewAttesterSlashing() *AttesterSlashing { + return &AttesterSlashing{ + Attestation_1: NewIndexedAttestation(), + Attestation_2: NewIndexedAttestation(), + } +} + func (a *AttesterSlashing) EncodeSSZ(dst []byte) ([]byte, error) { return ssz2.MarshalSSZ(dst, a.Attestation_1, a.Attestation_2) } diff --git a/cl/cltypes/solid/attestation_data.go b/cl/cltypes/solid/attestation_data.go index 4c922f5ebb0..188571957ab 100644 --- a/cl/cltypes/solid/attestation_data.go +++ b/cl/cltypes/solid/attestation_data.go @@ -62,6 +62,8 @@ func (a AttestationData) UnmarshalJSON(buf []byte) error { Source Checkpoint `json:"source"` Target Checkpoint `json:"target"` } + tmp.Source = NewCheckpoint() + tmp.Target = NewCheckpoint() if err := json.Unmarshal(buf, &tmp); err != nil { return err } diff --git a/cl/cltypes/solid/uint64_raw_list.go b/cl/cltypes/solid/uint64_raw_list.go index 6461f435b97..e93b580a165 100644 --- a/cl/cltypes/solid/uint64_raw_list.go +++ b/cl/cltypes/solid/uint64_raw_list.go @@ -162,3 +162,19 @@ func (arr *RawUint64List) MarshalJSON() ([]byte, error) { } return json.Marshal(strs) } + +func (arr *RawUint64List) UnmarshalJSON(data []byte) error { + var strs []string + if err := json.Unmarshal(data, &strs); err != nil { + return err + } + arr.u = make([]uint64, len(strs)) + for i, s := range strs { + v, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return err + } + arr.u[i] = v + } + return nil +} diff --git a/cl/phase1/forkchoice/forkchoice_mock.go b/cl/phase1/forkchoice/forkchoice_mock.go index 3b2b35eccc6..16f8ee6b0af 100644 --- a/cl/phase1/forkchoice/forkchoice_mock.go +++ b/cl/phase1/forkchoice/forkchoice_mock.go @@ -6,6 +6,7 @@ import ( "github.com/ledgerwatch/erigon/cl/cltypes/solid" "github.com/ledgerwatch/erigon/cl/phase1/core/state" "github.com/ledgerwatch/erigon/cl/phase1/execution_client" + "github.com/ledgerwatch/erigon/cl/pool" "github.com/ledgerwatch/erigon/cl/transition/impl/eth2" ) @@ -65,6 +66,8 @@ type ForkChoiceStorageMock struct { StateAtSlotVal map[uint64]*state.CachingBeaconState GetSyncCommitteesVal map[common.Hash][2]*solid.SyncCommittee GetFinalityCheckpointsVal map[common.Hash][3]solid.Checkpoint + + Pool pool.OperationsPool } func NewForkChoiceStorageMock() *ForkChoiceStorageMock { @@ -157,11 +160,13 @@ func (f *ForkChoiceStorageMock) Time() uint64 { } func (f *ForkChoiceStorageMock) OnAttestation(attestation *solid.Attestation, fromBlock bool) error { - panic("implement me") + f.Pool.AttestationsPool.Insert(attestation.Signature(), attestation) + return nil } func (f *ForkChoiceStorageMock) OnAttesterSlashing(attesterSlashing *cltypes.AttesterSlashing, test bool) error { - panic("implement me") + f.Pool.AttesterSlashingsPool.Insert(pool.ComputeKeyForAttesterSlashing(attesterSlashing), attesterSlashing) + return nil } func (f *ForkChoiceStorageMock) OnBlock(block *cltypes.SignedBeaconBlock, newPayload bool, fullValidation bool) error { @@ -195,3 +200,18 @@ func (f *ForkChoiceStorageMock) LowestAvaiableSlot() uint64 { func (f *ForkChoiceStorageMock) Partecipation(epoch uint64) (*solid.BitList, bool) { return f.ParticipationVal, f.ParticipationVal != nil } + +func (f *ForkChoiceStorageMock) OnVoluntaryExit(signedVoluntaryExit *cltypes.SignedVoluntaryExit, test bool) error { + f.Pool.VoluntaryExistsPool.Insert(signedVoluntaryExit.VoluntaryExit.ValidatorIndex, signedVoluntaryExit) + return nil +} + +func (f *ForkChoiceStorageMock) OnProposerSlashing(proposerSlashing *cltypes.ProposerSlashing, test bool) error { + f.Pool.ProposerSlashingsPool.Insert(pool.ComputeKeyForProposerSlashing(proposerSlashing), proposerSlashing) + return nil +} + +func (f *ForkChoiceStorageMock) OnBlsToExecutionChange(signedChange *cltypes.SignedBLSToExecutionChange, test bool) error { + f.Pool.BLSToExecutionChangesPool.Insert(signedChange.Signature, signedChange) + return nil +} diff --git a/cl/phase1/forkchoice/interface.go b/cl/phase1/forkchoice/interface.go index 60320b4c715..438db97f32c 100644 --- a/cl/phase1/forkchoice/interface.go +++ b/cl/phase1/forkchoice/interface.go @@ -45,6 +45,9 @@ type ForkChoiceStorageReader interface { type ForkChoiceStorageWriter interface { OnAttestation(attestation *solid.Attestation, fromBlock bool) error OnAttesterSlashing(attesterSlashing *cltypes.AttesterSlashing, test bool) error + OnVoluntaryExit(signedVoluntaryExit *cltypes.SignedVoluntaryExit, test bool) error + OnProposerSlashing(proposerSlashing *cltypes.ProposerSlashing, test bool) error + OnBlsToExecutionChange(signedChange *cltypes.SignedBLSToExecutionChange, test bool) error OnBlock(block *cltypes.SignedBeaconBlock, newPayload bool, fullValidation bool) error OnTick(time uint64) } diff --git a/cmd/caplin/caplin1/run.go b/cmd/caplin/caplin1/run.go index f236622a0f1..7455d911fe3 100644 --- a/cmd/caplin/caplin1/run.go +++ b/cmd/caplin/caplin1/run.go @@ -212,7 +212,7 @@ func RunCaplinPhase1(ctx context.Context, sentinel sentinel.SentinelClient, engi statesReader := historical_states_reader.NewHistoricalStatesReader(beaconConfig, rcsn, vTables, af, genesisState) syncedDataManager := synced_data.NewSyncedDataManager(cfg.Active, beaconConfig) if cfg.Active { - apiHandler := handler.NewApiHandler(genesisConfig, beaconConfig, rawDB, indexDB, forkChoice, pool, rcsn, syncedDataManager, statesReader) + apiHandler := handler.NewApiHandler(genesisConfig, beaconConfig, rawDB, indexDB, forkChoice, pool, rcsn, syncedDataManager, statesReader, sentinel) headApiHandler := &validatorapi.ValidatorApiHandler{ FC: forkChoice, BeaconChainCfg: beaconConfig,