Skip to content

Commit

Permalink
Merge pull request #609 from node-real/upstream-v3.0.0-beta2
Browse files Browse the repository at this point in the history
Upstream v3.0.0 beta2
  • Loading branch information
MatusKysel authored Feb 13, 2025
2 parents 82ef56f + 4554722 commit 7c42f0b
Show file tree
Hide file tree
Showing 58 changed files with 3,333 additions and 330 deletions.
7 changes: 0 additions & 7 deletions .github/workflows/qa-sync-from-scratch-minimal-node.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,6 @@ jobs:
# Save the subsection reached status
echo "::set-output name=test_executed::true"
# Clean up Erigon process if it's still running
if kill -0 $ERIGON_PID 2> /dev/null; then
echo "Terminating Erigon"
kill $ERIGON_PID
wait $ERIGON_PID
fi
# Check test runner script exit status
if [ $test_exit_status -eq 0 ]; then
echo "Tests completed successfully"
Expand Down
7 changes: 0 additions & 7 deletions .github/workflows/qa-sync-from-scratch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,6 @@ jobs:
# Save the subsection reached status
echo "::set-output name=test_executed::true"
# Clean up Erigon process if it's still running
if kill -0 $ERIGON_PID 2> /dev/null; then
echo "Terminating Erigon"
kill $ERIGON_PID
wait $ERIGON_PID
fi
# Check test runner script exit status
if [ $test_exit_status -eq 0 ]; then
echo "Tests completed successfully"
Expand Down
102 changes: 102 additions & 0 deletions .github/workflows/qa-sync-with-externalcl.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: QA - Sync with external CL

on:
# schedule:
# - cron: '0 0 * * *' # Run every night at 00:00 AM UTC
workflow_dispatch: # Run manually

jobs:
prysm-minimal-node-sync-from-scratch-test:
runs-on: self-hosted
timeout-minutes: 360 # 6 hours
env:
ERIGON_DATA_DIR: ${{ github.workspace }}/erigon_data
ERIGON_QA_PATH: /home/qarunner/erigon-qa
TRACKING_TIME_SECONDS: 7200 # 2 hours
TOTAL_TIME_SECONDS: 18000 # 5 hours
CHAIN: mainnet

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Clean Erigon Build & Data Directories
run: |
make clean
rm -rf $ERIGON_DATA_DIR
- name: Build Erigon
run: |
make erigon
working-directory: ${{ github.workspace }}

- name: Pause the Erigon instance dedicated to db maintenance
run: |
python3 $ERIGON_QA_PATH/test_system/db-producer/pause_production.py || true
- name: Run Erigon and monitor chain sync
id: test_step
run: |
set +e # Disable exit on error
# Run Erigon, wait sync and check ability to maintain sync
python3 $ERIGON_QA_PATH/test_system/qa-tests/tip-tracking/run_and_check_tip_tracking.py \
${{ github.workspace }}/build/bin $ERIGON_DATA_DIR $TRACKING_TIME_SECONDS $TOTAL_TIME_SECONDS Erigon3 $CHAIN minimal_node no_statistics prysm
# Capture monitoring script exit status
test_exit_status=$?
# Save the subsection reached status
echo "::set-output name=test_executed::true"
# Check test runner script exit status
if [ $test_exit_status -eq 0 ]; then
echo "Tests completed successfully"
echo "TEST_RESULT=success" >> "$GITHUB_OUTPUT"
else
echo "Error detected during tests"
echo "TEST_RESULT=failure" >> "$GITHUB_OUTPUT"
fi
- name: Save test results
if: steps.test_step.outputs.test_executed == 'true'
env:
TEST_RESULT: ${{ steps.test_step.outputs.TEST_RESULT }}
run: |
python3 $ERIGON_QA_PATH/test_system/qa-tests/uploads/upload_test_results.py \
--repo erigon \
--commit $(git rev-parse HEAD) \
--branch ${{ github.ref_name }} \
--test_name sync-from-scratch-prysm-minimal-node \
--chain $CHAIN \
--runner ${{ runner.name }} \
--outcome $TEST_RESULT \
--result_file ${{ github.workspace }}/result-$CHAIN.json
- name: Upload test results
if: steps.test_step.outputs.test_executed == 'true'
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
${{ github.workspace }}/result-${{ env.CHAIN }}.json
${{ github.workspace }}/erigon_data/logs/erigon.log
- name: Clean up Erigon data directory
if: always()
run: |
rm -rf $ERIGON_DATA_DIR
- name: Resume the Erigon instance dedicated to db maintenance
run: |
python3 $ERIGON_QA_PATH/test_system/db-producer/resume_production.py || true
- name: Action for Success
if: steps.test_step.outputs.TEST_RESULT == 'success'
run: echo "::notice::Tests completed successfully"

- name: Action for Not Success
if: steps.test_step.outputs.TEST_RESULT != 'success'
run: |
echo "::error::Error detected during tests"
exit 1
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ChangeLog
- `pos sync failed: fork choice update failure: status=5, validationErr=''` - should be fixed
- `external rpc daemon getting stuck` - should be fixed
- `process not exiting in a clean way (getting stuck) upon astrid errs` - should be fixed
- `very rare chance of bridge deadlock while at chain tip due to forking` - should be fixed

### TODO

Expand Down
13 changes: 12 additions & 1 deletion cl/beacon/handler/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,22 @@ import (

libcommon "github.com/erigontech/erigon-lib/common"
"github.com/erigontech/erigon/cl/beacon/beaconhttp"
"github.com/erigontech/erigon/cl/clparams"
"github.com/erigontech/erigon/cl/cltypes"
)

func (a *ApiHandler) getSpec(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
return newBeaconResponse(a.beaconChainCfg), nil
outSpec := struct {
*clparams.BeaconChainConfig
*clparams.NetworkConfig
MinEpochsForBlockRequests uint64 `json:"MIN_EPOCHS_FOR_BLOCK_REQUESTS,string"`
}{
BeaconChainConfig: a.beaconChainCfg,
NetworkConfig: a.netConfig,
MinEpochsForBlockRequests: a.beaconChainCfg.MinEpochsForBlockRequests(),
}

return newBeaconResponse(outSpec), nil
}

func (a *ApiHandler) getDepositContract(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
Expand Down
4 changes: 2 additions & 2 deletions cl/beacon/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ func (a *ApiHandler) init() {
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("/attestations", a.PostEthV1BeaconPoolAttestations)
r.Post("/attestations", a.PostEthV1BeaconPoolAttestations) // deprecate after electra fork
r.Post("/sync_committees", a.PostEthV1BeaconPoolSyncCommittees)
})
r.Route("/light_client", func(r chi.Router) {
Expand Down Expand Up @@ -349,7 +349,7 @@ func (a *ApiHandler) init() {
})
r.Route("/pool", func(r chi.Router) {
r.Get("/attestations", beaconhttp.HandleEndpointFunc(a.GetEthV2BeaconPoolAttestations))
r.Post("/attestations", a.PostEthV1BeaconPoolAttestations) // reuse
r.Post("/attestations", a.PostEthV2BeaconPoolAttestations)
r.Get("/attester_slashings", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconPoolAttesterSlashings)) // reuse
r.Post("/attester_slashings", a.PostEthV1BeaconPoolAttesterSlashings) // resue
})
Expand Down
3 changes: 0 additions & 3 deletions cl/beacon/handler/headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,10 @@ func (a *ApiHandler) getHeader(w http.ResponseWriter, r *http.Request) (*beaconh
return nil, err
}

version := a.beaconChainCfg.GetCurrentStateVersion(signedHeader.Header.Slot / a.beaconChainCfg.SlotsPerEpoch)

return newBeaconResponse(&headerResponse{
Root: root,
Canonical: canonicalRoot == root,
Header: signedHeader,
}).WithFinalized(canonicalRoot == root && signedHeader.Header.Slot <= a.forkchoiceStore.FinalizedSlot()).
WithVersion(version).
WithOptimistic(a.forkchoiceStore.IsRootOptimistic(root)), nil
}
99 changes: 81 additions & 18 deletions cl/beacon/handler/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ func (a *ApiHandler) GetEthV2BeaconPoolAttestations(w http.ResponseWriter, r *ht

return newBeaconResponse(ret), nil
}

func (a *ApiHandler) PostEthV1BeaconPoolAttestations(w http.ResponseWriter, r *http.Request) {
req := []*solid.Attestation{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
Expand All @@ -121,35 +122,97 @@ func (a *ApiHandler) PostEthV1BeaconPoolAttestations(w http.ResponseWriter, r *h
return
}
var (
slot = attestation.Data.Slot
epoch = a.ethClock.GetEpochAtSlot(slot)
attClVersion = a.beaconChainCfg.GetCurrentStateVersion(epoch)
cIndex = attestation.Data.CommitteeIndex
committeeCountPerSlot = a.syncedData.CommitteeCount(slot / a.beaconChainCfg.SlotsPerEpoch)
slot = attestation.Data.Slot
cIndex = attestation.Data.CommitteeIndex
committeeCountPerSlot = a.syncedData.CommitteeCount(slot / a.beaconChainCfg.SlotsPerEpoch)
attestationWithGossipData = &services.AttestationForGossip{
Attestation: attestation,
ImmediateProcess: true, // we want to process attestation immediately
}
)
subnet := subnets.ComputeSubnetForAttestation(committeeCountPerSlot, slot, cIndex, a.beaconChainCfg.SlotsPerEpoch, a.netConfig.AttestationSubnetCount)
encodedSSZ, err := attestation.EncodeSSZ(nil)
if err != nil {
beaconhttp.NewEndpointError(http.StatusInternalServerError, err).WriteTo(w)
return
}

if attClVersion >= clparams.ElectraVersion {
indices := attestation.CommitteeBits.GetOnIndices()
if len(indices) != 1 {
failures = append(failures, poolingFailure{
Index: i,
Message: "invalid number of on bits in committee bits",
})
continue
if err := a.attestationService.ProcessMessage(r.Context(), &subnet, attestationWithGossipData); err != nil && !errors.Is(err, services.ErrIgnore) {
log.Warn("[Beacon REST] failed to process attestation in attestation service", "err", err)
failures = append(failures, poolingFailure{
Index: i,
Message: err.Error(),
})
continue
}
if a.sentinel != nil {
if _, err := a.sentinel.PublishGossip(r.Context(), &sentinel.GossipData{
Data: encodedSSZ,
Name: gossip.TopicNamePrefixBeaconAttestation,
SubnetId: &subnet,
}); err != nil {
a.logger.Debug("[Beacon REST] failed to publish attestation to gossip", "err", err)
}
cIndex = uint64(indices[0])
}
}
if len(failures) > 0 {
errResp := poolingError{
Code: http.StatusBadRequest,
Message: "some failures",
Failures: failures,
}
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(errResp); err != nil {
log.Warn("failed to encode response", "err", err)
}
return
}
w.WriteHeader(http.StatusOK)
}

func (a *ApiHandler) PostEthV2BeaconPoolAttestations(w http.ResponseWriter, r *http.Request) {
v := r.Header.Get("Eth-Consensus-Version")
if v == "" {
beaconhttp.NewEndpointError(http.StatusBadRequest, errors.New("missing version header")).WriteTo(w)
return
}
clVersion, err := clparams.StringToClVersion(v)
if err != nil {
beaconhttp.NewEndpointError(http.StatusBadRequest, err).WriteTo(w)
return
}

if clVersion < clparams.ElectraVersion {
a.PostEthV1BeaconPoolAttestations(w, r)
return
}

req := []*solid.SingleAttestation{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
beaconhttp.NewEndpointError(http.StatusBadRequest, err).WriteTo(w)
return
}
failures := []poolingFailure{}
for i, attestation := range req {
if a.syncedData.Syncing() {
beaconhttp.NewEndpointError(http.StatusServiceUnavailable, errors.New("head state not available")).WriteTo(w)
return
}
var (
slot = attestation.AttestationData().Slot
cIndex = attestation.CommitteeIndex
committeeCountPerSlot = a.syncedData.CommitteeCount(slot / a.beaconChainCfg.SlotsPerEpoch)
attestationWithGossipData = &services.AttestationForGossip{
SingleAttestation: attestation,
ImmediateProcess: true, // we want to process attestation immediately
}
)
subnet := subnets.ComputeSubnetForAttestation(committeeCountPerSlot, slot, cIndex, a.beaconChainCfg.SlotsPerEpoch, a.netConfig.AttestationSubnetCount)
encodedSSZ, err := attestation.EncodeSSZ(nil)
if err != nil {
beaconhttp.NewEndpointError(http.StatusInternalServerError, err).WriteTo(w)
return
}
attestationWithGossipData := &services.AttestationForGossip{
Attestation: attestation,
ImmediateProcess: true, // we want to process attestation immediately
}

if err := a.attestationService.ProcessMessage(r.Context(), &subnet, attestationWithGossipData); err != nil && !errors.Is(err, services.ErrIgnore) {
log.Warn("[Beacon REST] failed to process attestation in attestation service", "err", err)
Expand Down
4 changes: 1 addition & 3 deletions cl/beacon/handler/states.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,6 @@ func (a *ApiHandler) getFinalityCheckpoints(w http.ResponseWriter, r *http.Reque
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Errorf("could not read checkpoints: %x, %d", blockRoot, a.beaconChainCfg.RoundSlotToEpoch(*slot)))
}
}
version := a.beaconChainCfg.GetCurrentStateVersion(*slot / a.beaconChainCfg.SlotsPerEpoch)
canonicalRoot, err := beacon_indicies.ReadCanonicalBlockRoot(tx, *slot)
if err != nil {
return nil, err
Expand All @@ -279,8 +278,7 @@ func (a *ApiHandler) getFinalityCheckpoints(w http.ResponseWriter, r *http.Reque
FinalizedCheckpoint: finalizedCheckpoint,
CurrentJustifiedCheckpoint: currentJustifiedCheckpoint,
PreviousJustifiedCheckpoint: previousJustifiedCheckpoint,
}).WithFinalized(canonicalRoot == blockRoot && *slot <= a.forkchoiceStore.FinalizedSlot()).
WithVersion(version).WithOptimistic(isOptimistic), nil
}).WithFinalized(canonicalRoot == blockRoot && *slot <= a.forkchoiceStore.FinalizedSlot()).WithOptimistic(isOptimistic), nil
}

type syncCommitteesResponse struct {
Expand Down
2 changes: 1 addition & 1 deletion cl/beacon/handler/states_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ func TestGetStateFinalityCheckpoints(t *testing.T) {
code: http.StatusOK,
},
}
expected := `{"data":{"finalized":{"epoch":"1","root":"0xde46b0f2ed5e72f0cec20246403b14c963ec995d7c2825f3532b0460c09d5693"},"current_justified":{"epoch":"3","root":"0xa6e47f164b1a3ca30ea3b2144bd14711de442f51e5b634750a12a1734e24c987"},"previous_justified":{"epoch":"2","root":"0x4c3ee7969e485696669498a88c17f70e6999c40603e2f4338869004392069063"}},"execution_optimistic":false,"finalized":false,"version":"bellatrix"}` + "\n"
expected := `{"data":{"finalized":{"epoch":"1","root":"0xde46b0f2ed5e72f0cec20246403b14c963ec995d7c2825f3532b0460c09d5693"},"current_justified":{"epoch":"3","root":"0xa6e47f164b1a3ca30ea3b2144bd14711de442f51e5b634750a12a1734e24c987"},"previous_justified":{"epoch":"2","root":"0x4c3ee7969e485696669498a88c17f70e6999c40603e2f4338869004392069063"}},"execution_optimistic":false,"finalized":false}` + "\n"
for _, c := range cases {
t.Run(c.blockID, func(t *testing.T) {
server := httptest.NewServer(handler.mux)
Expand Down
2 changes: 1 addition & 1 deletion cl/beacon/handler/test_data/states_1.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
finality_checkpoint: {"data":{"finalized":{"epoch":"1","root":"0xde46b0f2ed5e72f0cec20246403b14c963ec995d7c2825f3532b0460c09d5693"},"current_justified":{"epoch":"3","root":"0xa6e47f164b1a3ca30ea3b2144bd14711de442f51e5b634750a12a1734e24c987"},"previous_justified":{"epoch":"2","root":"0x4c3ee7969e485696669498a88c17f70e6999c40603e2f4338869004392069063"}},"finalized":false,"version":2,"execution_optimistic":false}
finality_checkpoint: {"data":{"finalized":{"epoch":"1","root":"0xde46b0f2ed5e72f0cec20246403b14c963ec995d7c2825f3532b0460c09d5693"},"current_justified":{"epoch":"3","root":"0xa6e47f164b1a3ca30ea3b2144bd14711de442f51e5b634750a12a1734e24c987"},"previous_justified":{"epoch":"2","root":"0x4c3ee7969e485696669498a88c17f70e6999c40603e2f4338869004392069063"}},"finalized":false,"execution_optimistic":false}
randao: {"data":{"randao":"0xdeec617717272914bfd73e02ca1da113a83cf4cf33cd4939486509e2da4ccf4e"},"finalized":false,"execution_optimistic":false}
Loading

0 comments on commit 7c42f0b

Please sign in to comment.