From 33e4c7c32496e33cf6c3fa7a83a9455fd0297e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gianguido=20Sor=C3=A0?= Date: Wed, 18 Sep 2024 14:45:02 +0200 Subject: [PATCH 1/5] core/validatorapi: intermediate commit --- core/validatorapi/validatorapi.go | 163 +++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 5 deletions(-) diff --git a/core/validatorapi/validatorapi.go b/core/validatorapi/validatorapi.go index baafe2aeb..a933afd22 100644 --- a/core/validatorapi/validatorapi.go +++ b/core/validatorapi/validatorapi.go @@ -13,8 +13,10 @@ import ( eth2api "github.com/attestantio/go-eth2-client/api" eth2v1 "github.com/attestantio/go-eth2-client/api/v1" + "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/altair" eth2p0 "github.com/attestantio/go-eth2-client/spec/phase0" + ssz "github.com/ferranbt/fastssz" "go.opentelemetry.io/otel/trace" "github.com/obolnetwork/charon/app/errors" @@ -394,19 +396,160 @@ func (c Component) Proposal(ctx context.Context, opts *eth2api.ProposalOpts) (*e return wrapResponse(proposal), nil } +func (c Component) propDataMatchesDuty(ctx context.Context, opts *eth2api.SubmitProposalOpts, prop *eth2api.VersionedProposal) error { + ourPropIdx, err := prop.ProposerIndex() + if err != nil { + return errors.Wrap(err, "cannot fetch validator index from dutydb proposal") + } + + vcPropIdx, err := opts.Proposal.ProposerIndex() + if err != nil { + return errors.Wrap(err, "cannot fetch validator index from VC proposal") + } + + if ourPropIdx != vcPropIdx { + return errors.New( + "dutydb and VC proposals have different index", + z.U64("vc", uint64(vcPropIdx)), + z.U64("dutydb", uint64(ourPropIdx)), + ) + } + + if opts.Proposal.Blinded != prop.Blinded { + return errors.New( + "dutydb and VC proposals have different blinded value", + z.Bool("vc", opts.Proposal.Blinded), + z.Bool("dutydb", prop.Blinded), + ) + } + + if opts.Proposal.Version != prop.Version { + return errors.New( + "dutydb and VC proposals have different version", + z.Str("vc", opts.Proposal.Version.String()), + z.Str("dutydb", prop.Version.String()), + ) + } + + checkHashes := func(d1, d2 ssz.HashRoot) error { + ddb, err := d1.HashTreeRoot() + if err != nil { + return errors.Wrap(err, "hash tree root dutydb") + } + + if d2 == nil { + return errors.New("VC proposal data for the associated dutydb proposal is nil") + } + + vc, err := d2.HashTreeRoot() + if err != nil { + return errors.Wrap(err, "hash tree root dutydb") + } + + if ddb != vc { + return errors.New("dutydb and VC proposal data have different hash tree root") + } + + return nil + } + + switch prop.Version { + case spec.DataVersionPhase0: + return checkHashes(prop.Phase0, opts.Proposal.Phase0.Message) + case spec.DataVersionAltair: + return checkHashes(prop.Altair, opts.Proposal.Altair.Message) + case spec.DataVersionBellatrix: + var ( + ddbData ssz.HashRoot = prop.Bellatrix + vcData ssz.HashRoot = opts.Proposal.Bellatrix + ) + + if prop.Blinded { + ddbData = prop.BellatrixBlinded + vcData = opts.Proposal.BellatrixBlinded + } + + return checkHashes(ddbData, vcData) + case spec.DataVersionCapella: + + var ( + ddbData ssz.HashRoot = prop.Capella + vcData ssz.HashRoot = opts.Proposal.Capella + ) + + if prop.Blinded { + ddbData = prop.CapellaBlinded + vcData = opts.Proposal.CapellaBlinded + } + + return checkHashes(ddbData, vcData) + case spec.DataVersionDeneb: + + var ( + ddbData ssz.HashRoot = prop.Deneb + vcData ssz.HashRoot = opts.Proposal.Deneb + ) + + if prop.Blinded { + ddbData = prop.DenebBlinded + vcData = opts.Proposal.DenebBlinded + } + + return checkHashes(ddbData, vcData) + case spec.DataVersionUnknown: + return errors.New("unexpected block version", z.Str("version", prop.Version.String())) + } + + return nil +} + +// valPubkeyFromProposal returns the public key of the validator associated to this proposal. +// If the validator index does not belong to the configured cluster, this function will return an error. +func (c Component) valPubkeyFromProposal(ctx context.Context, opts *eth2api.SubmitProposalOpts) (core.PubKey, error) { + idx, err := opts.Proposal.ProposerIndex() + if err != nil { + return "", errors.Wrap(err, "cannot fetch validator index from proposal") + } + + activeVals, err := c.eth2Cl.ActiveValidators(ctx) + if err != nil { + return "", errors.Wrap(err, "cannot fetch active validators") + } + + data, ok := activeVals[idx] + if !ok { + return "", errors.New( + "validator index contained in proposal does not belong to this cluster", + z.U64("validator_index", uint64(idx)), + ) + } + + return core.PubKeyFrom48Bytes(data), nil +} + func (c Component) SubmitProposal(ctx context.Context, opts *eth2api.SubmitProposalOpts) error { slot, err := opts.Proposal.Slot() if err != nil { return err } - pubkey, err := c.getProposerPubkey(ctx, core.NewProposerDuty(uint64(slot))) + duty := core.NewProposerDuty(uint64(slot)) + + pubkey, err := c.getProposerPubkey(ctx, duty) if err != nil { return err } + prop, err := c.awaitProposalFunc(ctx, uint64(slot)) + if err != nil { + return errors.Wrap(err, "could not fetch block definition from dutydb") + } + + if err := c.propDataMatchesDuty(ctx, opts, prop); err != nil { + return errors.Wrap(err, "consensus proposal and VC-submitted one do not match") + } + // Save Partially Signed Block to ParSigDB - duty := core.NewProposerDuty(uint64(slot)) ctx = log.WithCtx(ctx, z.Any("duty", duty)) signedData, err := core.NewPartialVersionedSignedProposal(opts.Proposal, c.shareIdx) @@ -440,14 +583,24 @@ func (c Component) SubmitBlindedProposal(ctx context.Context, opts *eth2api.Subm return err } - pubkey, err := c.getProposerPubkey(ctx, core.NewProposerDuty(uint64(slot))) + duty := core.NewProposerDuty(uint64(slot)) + ctx = log.WithCtx(ctx, z.Any("duty", duty)) + + pubkey, err := c.getProposerPubkey(ctx, duty) if err != nil { return err } // Save Partially Signed Blinded Block to ParSigDB - duty := core.NewProposerDuty(uint64(slot)) - ctx = log.WithCtx(ctx, z.Any("duty", duty)) + + prop, err := c.awaitProposalFunc(ctx, uint64(slot)) + if err != nil { + return errors.Wrap(err, "could not fetch block definition from dutydb") + } + + if err := c.propDataMatchesDuty(ctx, opts, prop); err != nil { + return errors.Wrap(err, "consensus proposal and VC-submitted one do not match") + } signedData, err := core.NewPartialVersionedSignedBlindedProposal(opts.Proposal, c.shareIdx) if err != nil { From 752db23bc365f99502407e5501ad84209d83629b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gianguido=20Sor=C3=A0?= Date: Wed, 18 Sep 2024 14:45:02 +0200 Subject: [PATCH 2/5] core/validatorapi: check proposal data against consensus one Instead of blindly accepting VC proposal data, check it for integrity against what we have in DutyDB: if they differ, stop the process. --- core/validatorapi/validatorapi.go | 134 +++++++++++++++- core/validatorapi/validatorapi_test.go | 205 ++++++++++++++++++++++++- 2 files changed, 331 insertions(+), 8 deletions(-) diff --git a/core/validatorapi/validatorapi.go b/core/validatorapi/validatorapi.go index baafe2aeb..5805b1ebf 100644 --- a/core/validatorapi/validatorapi.go +++ b/core/validatorapi/validatorapi.go @@ -13,8 +13,10 @@ import ( eth2api "github.com/attestantio/go-eth2-client/api" eth2v1 "github.com/attestantio/go-eth2-client/api/v1" + eth2spec "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/altair" eth2p0 "github.com/attestantio/go-eth2-client/spec/phase0" + ssz "github.com/ferranbt/fastssz" "go.opentelemetry.io/otel/trace" "github.com/obolnetwork/charon/app/errors" @@ -394,19 +396,120 @@ func (c Component) Proposal(ctx context.Context, opts *eth2api.ProposalOpts) (*e return wrapResponse(proposal), nil } +// propDataMatchesDuty checks that the VC-signed proposal data and prop are the same. +func propDataMatchesDuty(opts *eth2api.SubmitProposalOpts, prop *eth2api.VersionedProposal) error { + ourPropIdx, err := prop.ProposerIndex() + if err != nil { + return errors.Wrap(err, "cannot fetch validator index from dutydb proposal") + } + + vcPropIdx, err := opts.Proposal.ProposerIndex() + if err != nil { + return errors.Wrap(err, "cannot fetch validator index from VC proposal") + } + + if ourPropIdx != vcPropIdx { + return errors.New( + "dutydb and VC proposals have different index", + z.U64("vc", uint64(vcPropIdx)), + z.U64("dutydb", uint64(ourPropIdx)), + ) + } + + if opts.Proposal.Blinded != prop.Blinded { + return errors.New( + "dutydb and VC proposals have different blinded value", + z.Bool("vc", opts.Proposal.Blinded), + z.Bool("dutydb", prop.Blinded), + ) + } + + if opts.Proposal.Version != prop.Version { + return errors.New( + "dutydb and VC proposals have different version", + z.Str("vc", opts.Proposal.Version.String()), + z.Str("dutydb", prop.Version.String()), + ) + } + + checkHashes := func(d1, d2 ssz.HashRoot) error { + ddb, err := d1.HashTreeRoot() + if err != nil { + return errors.Wrap(err, "hash tree root dutydb") + } + + if d2 == nil { + return errors.New("validator client proposal data for the associated dutydb proposal is nil") + } + + vc, err := d2.HashTreeRoot() + if err != nil { + return errors.Wrap(err, "hash tree root dutydb") + } + + if ddb != vc { + return errors.New("dutydb and VC proposal data have different hash tree root") + } + + return nil + } + + switch prop.Version { + case eth2spec.DataVersionPhase0: + return checkHashes(prop.Phase0, opts.Proposal.Phase0.Message) + case eth2spec.DataVersionAltair: + return checkHashes(prop.Altair, opts.Proposal.Altair.Message) + case eth2spec.DataVersionBellatrix: + switch prop.Blinded { + case false: + return checkHashes(prop.Bellatrix, opts.Proposal.Bellatrix.Message) + case true: + return checkHashes(prop.BellatrixBlinded, opts.Proposal.BellatrixBlinded.Message) + } + case eth2spec.DataVersionCapella: + switch prop.Blinded { + case false: + return checkHashes(prop.Capella, opts.Proposal.Capella.Message) + case true: + return checkHashes(prop.CapellaBlinded, opts.Proposal.CapellaBlinded.Message) + } + case eth2spec.DataVersionDeneb: + switch prop.Blinded { + case false: + return checkHashes(prop.Deneb.Block, opts.Proposal.Deneb.SignedBlock.Message) + case true: + return checkHashes(prop.DenebBlinded, opts.Proposal.DenebBlinded.Message) + } + case eth2spec.DataVersionUnknown: + return errors.New("unexpected block version", z.Str("version", prop.Version.String())) + } + + return nil +} + func (c Component) SubmitProposal(ctx context.Context, opts *eth2api.SubmitProposalOpts) error { slot, err := opts.Proposal.Slot() if err != nil { return err } - pubkey, err := c.getProposerPubkey(ctx, core.NewProposerDuty(uint64(slot))) + duty := core.NewProposerDuty(uint64(slot)) + + pubkey, err := c.getProposerPubkey(ctx, duty) if err != nil { return err } + prop, err := c.awaitProposalFunc(ctx, uint64(slot)) + if err != nil { + return errors.Wrap(err, "could not fetch block definition from dutydb") + } + + if err := propDataMatchesDuty(opts, prop); err != nil { + return errors.Wrap(err, "consensus proposal and VC-submitted one do not match") + } + // Save Partially Signed Block to ParSigDB - duty := core.NewProposerDuty(uint64(slot)) ctx = log.WithCtx(ctx, z.Any("duty", duty)) signedData, err := core.NewPartialVersionedSignedProposal(opts.Proposal, c.shareIdx) @@ -440,15 +543,34 @@ func (c Component) SubmitBlindedProposal(ctx context.Context, opts *eth2api.Subm return err } - pubkey, err := c.getProposerPubkey(ctx, core.NewProposerDuty(uint64(slot))) + duty := core.NewProposerDuty(uint64(slot)) + ctx = log.WithCtx(ctx, z.Any("duty", duty)) + + pubkey, err := c.getProposerPubkey(ctx, duty) if err != nil { return err } - // Save Partially Signed Blinded Block to ParSigDB - duty := core.NewProposerDuty(uint64(slot)) - ctx = log.WithCtx(ctx, z.Any("duty", duty)) + prop, err := c.awaitProposalFunc(ctx, uint64(slot)) + if err != nil { + return errors.Wrap(err, "could not fetch block definition from dutydb") + } + + if err := propDataMatchesDuty(ð2api.SubmitProposalOpts{ + Common: opts.Common, + Proposal: ð2api.VersionedSignedProposal{ + Version: opts.Proposal.Version, + Blinded: true, + BellatrixBlinded: opts.Proposal.Bellatrix, + CapellaBlinded: opts.Proposal.Capella, + DenebBlinded: opts.Proposal.Deneb, + }, + BroadcastValidation: opts.BroadcastValidation, + }, prop); err != nil { + return errors.Wrap(err, "consensus proposal and VC-submitted one do not match") + } + // Save Partially Signed Blinded Block to ParSigDB signedData, err := core.NewPartialVersionedSignedBlindedProposal(opts.Proposal, c.shareIdx) if err != nil { return err diff --git a/core/validatorapi/validatorapi_test.go b/core/validatorapi/validatorapi_test.go index 1bea36d83..97c1090df 100644 --- a/core/validatorapi/validatorapi_test.go +++ b/core/validatorapi/validatorapi_test.go @@ -409,6 +409,104 @@ func TestComponent_Proposal(t *testing.T) { require.Equal(t, block1, block2) } +func TestComponent_SubmitProposalsWithWrongVCData(t *testing.T) { + ctx := context.Background() + + // Create keys (just use normal keys, not split tbls) + secret, err := tbls.GenerateSecretKey() + require.NoError(t, err) + + pubkey, err := tbls.SecretToPublicKey(secret) + require.NoError(t, err) + + const ( + vIdx = 1 + shareIdx = 1 + slot = 123 + epoch = eth2p0.Epoch(3) + ) + + // Convert pubkey + corePubKey, err := core.PubKeyFromBytes(pubkey[:]) + require.NoError(t, err) + allPubSharesByKey := map[core.PubKey]map[int]tbls.PublicKey{corePubKey: {shareIdx: pubkey}} // Maps self to self since not tbls + + // Configure beacon mock + bmock, err := beaconmock.New() + require.NoError(t, err) + + // Construct the validator api component + vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, testutil.BuilderFalse, nil) + require.NoError(t, err) + + t.Run("full block fails", func(t *testing.T) { + unsignedBlock := ð2spec.VersionedBeaconBlock{ + Version: eth2spec.DataVersionCapella, + Capella: testutil.RandomCapellaBeaconBlock(), + } + vapi.RegisterGetDutyDefinition(func(ctx context.Context, duty core.Duty) (core.DutyDefinitionSet, error) { + return core.DutyDefinitionSet{corePubKey: nil}, nil + }) + + vapi.RegisterAwaitProposal(func(ctx context.Context, slot uint64) (*eth2api.VersionedProposal, error) { + unsignedBlock := ð2spec.VersionedBeaconBlock{ + Version: eth2spec.DataVersionCapella, + Capella: testutil.RandomCapellaBeaconBlock(), + } + + return ð2api.VersionedProposal{ + Version: unsignedBlock.Version, + Capella: unsignedBlock.Capella, + }, nil + }) + + err = vapi.SubmitProposal(ctx, ð2api.SubmitProposalOpts{ + Proposal: ð2api.VersionedSignedProposal{ + Version: unsignedBlock.Version, + Capella: &capella.SignedBeaconBlock{ + Message: unsignedBlock.Capella, + Signature: eth2p0.BLSSignature{}, + }, + }, + }) + require.ErrorContains(t, err, "consensus proposal and VC-submitted one do not match: dutydb and VC proposal data have different hash tree root") + }) + + t.Run("blinded block fails", func(t *testing.T) { + unsignedBlindedBlock := testutil.RandomCapellaBlindedBeaconBlock() + + vapi.RegisterGetDutyDefinition(func(ctx context.Context, duty core.Duty) (core.DutyDefinitionSet, error) { + return core.DutyDefinitionSet{corePubKey: nil}, nil + }) + + signedBlindedBlock := ð2api.VersionedSignedBlindedProposal{ + Version: eth2spec.DataVersionCapella, + Capella: ð2capella.SignedBlindedBeaconBlock{ + Message: unsignedBlindedBlock, + Signature: eth2p0.BLSSignature{}, + }, + } + + vapi.RegisterAwaitProposal(func(ctx context.Context, slot uint64) (*eth2api.VersionedProposal, error) { + p := ð2api.VersionedProposal{ + Blinded: true, + Version: eth2spec.DataVersionCapella, + CapellaBlinded: testutil.RandomCapellaBlindedBeaconBlock(), + } + + p.CapellaBlinded.ProposerIndex = signedBlindedBlock.Capella.Message.ProposerIndex + + return p, nil + }) + + err = vapi.SubmitBlindedProposal(ctx, ð2api.SubmitBlindedProposalOpts{ + Proposal: signedBlindedBlock, + }) + + require.ErrorContains(t, err, "consensus proposal and VC-submitted one do not match: dutydb and VC proposal data have different hash tree root") + }) +} + func TestComponent_SubmitProposal(t *testing.T) { ctx := context.Background() @@ -478,6 +576,13 @@ func TestComponent_SubmitProposal(t *testing.T) { }, } + vapi.RegisterAwaitProposal(func(ctx context.Context, slot uint64) (*eth2api.VersionedProposal, error) { + return ð2api.VersionedProposal{ + Version: signedBlock.Version, + Capella: unsignedBlock.Capella, + }, nil + }) + // Register subscriber vapi.Subscribe(func(ctx context.Context, duty core.Duty, set core.ParSignedDataSet) error { block, ok := set[corePubKey].SignedData.(core.VersionedSignedProposal) @@ -577,6 +682,17 @@ func TestComponent_SubmitProposal_Gnosis(t *testing.T) { return nil }) + vapi.RegisterAwaitProposal(func(ctx context.Context, slot uint64) (*eth2api.VersionedProposal, error) { + return ð2api.VersionedProposal{ + Version: signedBlock.Version, + Deneb: ð2deneb.BlockContents{ + Block: signedBlock.Deneb.SignedBlock.Message, + KZGProofs: signedBlock.Deneb.KZGProofs, + Blobs: signedBlock.Deneb.Blobs, + }, + }, nil + }) + err = vapi.SubmitProposal(ctx, ð2api.SubmitProposalOpts{ Proposal: signedBlock, }) @@ -638,6 +754,13 @@ func TestComponent_SubmitProposalInvalidSignature(t *testing.T) { }, } + vapi.RegisterAwaitProposal(func(ctx context.Context, slot uint64) (*eth2api.VersionedProposal, error) { + return ð2api.VersionedProposal{ + Version: signedBlock.Version, + Capella: signedBlock.Capella.Message, + }, nil + }) + // Register subscriber vapi.Subscribe(func(ctx context.Context, duty core.Duty, set core.ParSignedDataSet) error { block, ok := set[corePubKey].SignedData.(core.VersionedSignedProposal) @@ -720,8 +843,49 @@ func TestComponent_SubmitProposalInvalidBlock(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { + b := test.block + proposal := ð2api.VersionedProposal{ + Version: b.Version, + Blinded: b.Blinded, + ConsensusValue: b.ConsensusValue, + ExecutionValue: b.ExecutionValue, + } + + if b.Phase0 != nil { + proposal.Phase0 = b.Phase0.Message + } + if b.Altair != nil { + proposal.Altair = b.Altair.Message + } + if b.Bellatrix != nil { + proposal.Bellatrix = b.Bellatrix.Message + } + if b.BellatrixBlinded != nil { + proposal.BellatrixBlinded = b.BellatrixBlinded.Message + } + if b.Capella != nil { + proposal.Capella = b.Capella.Message + } + if b.CapellaBlinded != nil { + proposal.CapellaBlinded = b.CapellaBlinded.Message + } + if b.Deneb != nil { + proposal.Deneb = ð2deneb.BlockContents{ + Block: test.block.Deneb.SignedBlock.Message, + KZGProofs: test.block.Deneb.KZGProofs, + Blobs: test.block.Deneb.Blobs, + } + } + if b.DenebBlinded != nil { + proposal.DenebBlinded = b.DenebBlinded.Message + } + + vapi.RegisterAwaitProposal(func(ctx context.Context, slot uint64) (*eth2api.VersionedProposal, error) { + return proposal, nil + }) + err = vapi.SubmitProposal(ctx, ð2api.SubmitProposalOpts{ - Proposal: test.block, + Proposal: b, }) require.ErrorContains(t, err, test.errMsg) }) @@ -793,6 +957,14 @@ func TestComponent_SubmitBlindedProposal(t *testing.T) { }, } + vapi.RegisterAwaitProposal(func(ctx context.Context, slot uint64) (*eth2api.VersionedProposal, error) { + return ð2api.VersionedProposal{ + Version: signedBlindedBlock.Version, + Blinded: true, + CapellaBlinded: signedBlindedBlock.Capella.Message, + }, nil + }) + // Register subscriber vapi.Subscribe(func(ctx context.Context, duty core.Duty, set core.ParSignedDataSet) error { block, ok := set[corePubKey].SignedData.(core.VersionedSignedProposal) @@ -880,6 +1052,14 @@ func TestComponent_SubmitBlindedProposalInvalidSignature(t *testing.T) { return nil }) + vapi.RegisterAwaitProposal(func(ctx context.Context, slot uint64) (*eth2api.VersionedProposal, error) { + return ð2api.VersionedProposal{ + Version: signedBlindedBlock.Version, + Blinded: true, + CapellaBlinded: signedBlindedBlock.Capella.Message, + }, nil + }) + err = vapi.SubmitBlindedProposal(ctx, ð2api.SubmitBlindedProposalOpts{ Proposal: signedBlindedBlock, }) @@ -970,8 +1150,29 @@ func TestComponent_SubmitBlindedProposalInvalidBlock(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { + b := test.block + proposal := ð2api.VersionedProposal{ + Version: b.Version, + Blinded: true, + } + + if b.Bellatrix != nil { + proposal.BellatrixBlinded = b.Bellatrix.Message + } + if b.Capella != nil { + proposal.CapellaBlinded = b.Capella.Message + } + + if b.Deneb != nil { + proposal.DenebBlinded = b.Deneb.Message + } + + vapi.RegisterAwaitProposal(func(ctx context.Context, slot uint64) (*eth2api.VersionedProposal, error) { + return proposal, nil + }) + err = vapi.SubmitBlindedProposal(ctx, ð2api.SubmitBlindedProposalOpts{ - Proposal: test.block, + Proposal: b, }) require.ErrorContains(t, err, test.errMsg) }) From c0c90baa07e93dbf98ee1cebe9f5caebfaf0712d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gianguido=20Sor=C3=A0?= Date: Fri, 27 Sep 2024 13:20:56 +0200 Subject: [PATCH 3/5] testutil/beaconmock: update static data with latest holesky snapshot Alsop update beaconmock default block from Capella to Deneb. --- testutil/beaconmock/options.go | 2 +- testutil/beaconmock/server_test.go | 5 +- testutil/beaconmock/static.json | 286 +++++++++++++++------------- testutil/integration/simnet_test.go | 4 +- 4 files changed, 160 insertions(+), 137 deletions(-) diff --git a/testutil/beaconmock/options.go b/testutil/beaconmock/options.go index 1e9905530..201648a27 100644 --- a/testutil/beaconmock/options.go +++ b/testutil/beaconmock/options.go @@ -528,7 +528,7 @@ func defaultMock(httpMock HTTPMock, httpServer *http.Server, clock clockwork.Clo return block, nil }, SignedBeaconBlockFunc: func(context.Context, string) (*eth2spec.VersionedSignedBeaconBlock, error) { - return testutil.RandomCapellaVersionedSignedBeaconBlock(), nil // Note the slot is probably wrong. + return testutil.RandomDenebVersionedSignedBeaconBlock(), nil // Note the slot is probably wrong. }, ProposerDutiesFunc: func(context.Context, eth2p0.Epoch, []eth2p0.ValidatorIndex) ([]*eth2v1.ProposerDuty, error) { return []*eth2v1.ProposerDuty{}, nil diff --git a/testutil/beaconmock/server_test.go b/testutil/beaconmock/server_test.go index a022c0958..98f204a55 100644 --- a/testutil/beaconmock/server_test.go +++ b/testutil/beaconmock/server_test.go @@ -25,11 +25,12 @@ func TestStatic(t *testing.T) { configResp, err := eth2Cl.Spec(ctx, ð2api.SpecOpts{}) require.NoError(t, err) - require.Equal(t, uint64(36660), configResp.Data["ALTAIR_FORK_EPOCH"]) + require.Equal(t, uint64(0), configResp.Data["ALTAIR_FORK_EPOCH"]) + require.Equal(t, uint64(29696), configResp.Data["DENEB_FORK_EPOCH"]) contractResp, err := eth2Cl.DepositContract(ctx, ð2api.DepositContractOpts{}) require.NoError(t, err) - require.Equal(t, uint64(5), contractResp.Data.ChainID) + require.Equal(t, uint64(17000), contractResp.Data.ChainID) slotsPerEpoch, err := eth2Cl.SlotsPerEpoch(ctx) require.NoError(t, err) diff --git a/testutil/beaconmock/static.json b/testutil/beaconmock/static.json index 7902ec02a..41ef96e6a 100644 --- a/testutil/beaconmock/static.json +++ b/testutil/beaconmock/static.json @@ -1,176 +1,196 @@ { "/eth/v1/beacon/genesis": { "data": { - "genesis_time": "1616508000", - "genesis_validators_root": "0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb", - "genesis_fork_version": "0x00001020" + "genesis_time": "1695902400", + "genesis_validators_root": "0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1", + "genesis_fork_version": "0x01017000" } }, "/eth/v1/config/deposit_contract": { "data": { - "chain_id": "5", - "address": "0xff50ed3d0ec03aC01D4C79aAd74928BFF48a7b2b" + "chain_id": "17000", + "address": "0x4242424242424242424242424242424242424242" } }, "/eth/v1/config/fork_schedule": { "data": [ { - "previous_version": "0x00001020", - "current_version": "0x00001020", + "previous_version": "0x01017000", + "current_version": "0x01017000", "epoch": "0" }, { - "previous_version": "0x00001020", - "current_version": "0x01001020", - "epoch": "36660" + "previous_version": "0x01017000", + "current_version": "0x02017000", + "epoch": "0" }, { - "previous_version": "0x01001020", - "current_version": "0x02001020", - "epoch": "112260" + "previous_version": "0x02017000", + "current_version": "0x03017000", + "epoch": "0" + }, + { + "previous_version": "0x03017000", + "current_version": "0x04017000", + "epoch": "256" + }, + { + "previous_version": "0x04017000", + "current_version": "0x05017000", + "epoch": "29696" } ] }, "/eth/v1/node/version": { "data": { - "version": "teku/v22.8.0/linux-x86_64/-eclipseadoptium-openjdk64bitservervm-java-17" + "version": "teku/v24.6.1/linux-x86_64/-ubuntu-openjdk64bitservervm-java-21" } }, "/eth/v1/config/spec": { "data": { - "ALTAIR_FORK_EPOCH": "36660", - "ALTAIR_FORK_VERSION": "0x01001020", - "ATTESTATION_PROPAGATION_SLOT_RANGE": "32", - "ATTESTATION_SUBNET_COUNT": "64", - "ATTESTATION_SUBNET_EXTRA_BITS": "0", - "ATTESTATION_SUBNET_PREFIX_BITS": "6", - "BASE_REWARD_FACTOR": "64", - "BELLATRIX_FORK_EPOCH": "112260", - "BELLATRIX_FORK_VERSION": "0x02001020", - "BLS_WITHDRAWAL_PREFIX": "0x00", - "BYTES_PER_LOGS_BLOOM": "256", - "CHURN_LIMIT_QUOTIENT": "65536", - "CONFIG_NAME": "prater", - "DEPOSIT_CHAIN_ID": "5", - "DEPOSIT_CONTRACT_ADDRESS": "0xff50ed3d0ec03aC01D4C79aAd74928BFF48a7b2b", - "DEPOSIT_NETWORK_ID": "5", - "DOMAIN_AGGREGATE_AND_PROOF": "0x06000000", - "DOMAIN_APPLICATION_BUILDER": "0x00000001", - "DOMAIN_BEACON_ATTESTER": "0x01000000", - "DOMAIN_BEACON_PROPOSER": "0x00000000", - "DOMAIN_CONTRIBUTION_AND_PROOF": "0x09000000", - "DOMAIN_DEPOSIT": "0x03000000", - "DOMAIN_RANDAO": "0x02000000", - "DOMAIN_SELECTION_PROOF": "0x05000000", - "DOMAIN_SYNC_COMMITTEE": "0x07000000", - "DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF": "0x08000000", - "DOMAIN_VOLUNTARY_EXIT": "0x04000000", - "EFFECTIVE_BALANCE_INCREMENT": "1000000000", - "EJECTION_BALANCE": "16000000000", - "EPOCHS_PER_ETH1_VOTING_PERIOD": "4", - "EPOCHS_PER_HISTORICAL_VECTOR": "64", - "EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION": "256", - "EPOCHS_PER_SLASHINGS_VECTOR": "64", - "EPOCHS_PER_SUBNET_SUBSCRIPTION": "256", - "EPOCHS_PER_SYNC_COMMITTEE_PERIOD": "256", - "ETH1_FOLLOW_DISTANCE": "2048", - "GOSSIP_MAX_SIZE": "10485760", - "GENESIS_DELAY": "1919188", - "GENESIS_FORK_VERSION": "0x00001020", - "HISTORICAL_ROOTS_LIMIT": "16777216", - "HYSTERESIS_DOWNWARD_MULTIPLIER": "1", - "HYSTERESIS_QUOTIENT": "4", - "HYSTERESIS_UPWARD_MULTIPLIER": "5", - "INACTIVITY_PENALTY_QUOTIENT": "33554432", - "INACTIVITY_PENALTY_QUOTIENT_ALTAIR": "50331648", - "INACTIVITY_PENALTY_QUOTIENT_BELLATRIX": "16777216", + "SLOTS_PER_EPOCH": "32", + "PRESET_BASE": "mainnet", + "TERMINAL_TOTAL_DIFFICULTY": "0", "INACTIVITY_SCORE_BIAS": "4", - "INACTIVITY_SCORE_RECOVERY_RATE": "16", - "MAX_ATTESTATIONS": "128", + "PENDING_BALANCE_DEPOSITS_LIMIT": "134217728", "MAX_ATTESTER_SLASHINGS": "2", - "MAX_CHUNK_SIZE": "10485760", + "MAX_WITHDRAWALS_PER_PAYLOAD": "16", + "INACTIVITY_PENALTY_QUOTIENT_BELLATRIX": "16777216", + "PENDING_PARTIAL_WITHDRAWALS_LIMIT": "134217728", + "INACTIVITY_PENALTY_QUOTIENT": "67108864", + "SAFE_SLOTS_TO_UPDATE_JUSTIFIED": "8", + "SECONDS_PER_ETH1_BLOCK": "14", + "MIN_SEED_LOOKAHEAD": "1", + "VALIDATOR_REGISTRY_LIMIT": "1099511627776", + "REORG_MAX_EPOCHS_SINCE_FINALIZATION": "2", + "SLOTS_PER_HISTORICAL_ROOT": "8192", + "RESP_TIMEOUT": "10", + "DOMAIN_VOLUNTARY_EXIT": "0x04000000", + "MAX_VALIDATORS_PER_COMMITTEE": "2048", + "MIN_GENESIS_TIME": "1695902100", + "ALTAIR_FORK_EPOCH": "0", + "HYSTERESIS_QUOTIENT": "4", + "ALTAIR_FORK_VERSION": "0x02017000", "MAX_BYTES_PER_TRANSACTION": "1073741824", - "MAX_COMMITTEES_PER_SLOT": "4", + "MAX_CHUNK_SIZE": "10485760", + "TTFB_TIMEOUT": "5", + "WHISTLEBLOWER_REWARD_QUOTIENT": "512", + "PROPOSER_REWARD_QUOTIENT": "8", + "MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP": "16384", + "EPOCHS_PER_HISTORICAL_VECTOR": "65536", + "MIN_PER_EPOCH_CHURN_LIMIT": "4", + "MAX_ATTESTER_SLASHINGS_ELECTRA": "1", + "TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE": "16", "MAX_DEPOSITS": "16", - "MAX_EFFECTIVE_BALANCE": "32000000000", + "BELLATRIX_FORK_EPOCH": "0", + "MAX_REQUEST_BLOB_SIDECARS": "768", + "REORG_HEAD_WEIGHT_THRESHOLD": "20", + "TARGET_AGGREGATORS_PER_COMMITTEE": "16", + "DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF": "0x08000000", + "MESSAGE_DOMAIN_INVALID_SNAPPY": "0x00000000", + "EPOCHS_PER_SLASHINGS_VECTOR": "8192", + "MIN_SLASHING_PENALTY_QUOTIENT": "128", + "MAX_BLS_TO_EXECUTION_CHANGES": "16", + "GOSSIP_MAX_SIZE": "10485760", + "DOMAIN_BEACON_ATTESTER": "0x01000000", + "EPOCHS_PER_SUBNET_SUBSCRIPTION": "256", + "MAX_ATTESTATIONS_ELECTRA": "8", + "ATTESTATION_SUBNET_COUNT": "64", + "GENESIS_DELAY": "300", + "MAX_SEED_LOOKAHEAD": "4", + "ETH1_FOLLOW_DISTANCE": "2048", + "SECONDS_PER_SLOT": "12", + "REORG_PARENT_WEIGHT_THRESHOLD": "160", + "MIN_SYNC_COMMITTEE_PARTICIPANTS": "1", + "BELLATRIX_FORK_VERSION": "0x03017000", + "PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX": "3", + "EFFECTIVE_BALANCE_INCREMENT": "1000000000", + "FIELD_ELEMENTS_PER_BLOB": "4096", + "MIN_EPOCHS_TO_INACTIVITY_PENALTY": "4", + "BASE_REWARD_FACTOR": "64", "MAX_EXTRA_DATA_BYTES": "32", + "CONFIG_NAME": "holesky", "MAX_PROPOSER_SLASHINGS": "16", - "MAX_REQUEST_BLOCKS": "1024", - "MAX_SEED_LOOKAHEAD": "4", + "MAX_CONSOLIDATIONS": "1", + "INACTIVITY_SCORE_RECOVERY_RATE": "16", + "MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS": "4096", "MAX_TRANSACTIONS_PER_PAYLOAD": "1048576", - "MAX_VALIDATORS_PER_COMMITTEE": "2048", - "MAX_VOLUNTARY_EXITS": "16", - "MAXIMUM_GOSSIP_CLOCK_DISPARITY": "500", - "MESSAGE_DOMAIN_INVALID_SNAPPY": "0x00000000", - "MESSAGE_DOMAIN_VALID_SNAPPY": "0x01000000", + "DEPOSIT_CONTRACT_ADDRESS": "0x4242424242424242424242424242424242424242", "MIN_ATTESTATION_INCLUSION_DELAY": "1", - "MIN_DEPOSIT_AMOUNT": "1000000000", - "MIN_EPOCHS_FOR_BLOCK_REQUESTS": "33024", - "MIN_EPOCHS_TO_INACTIVITY_PENALTY": "4", - "MIN_GENESIS_ACTIVE_VALIDATOR_COUNT": "16384", - "MIN_GENESIS_TIME": "1614588812", - "MIN_PER_EPOCH_CHURN_LIMIT": "4", - "MIN_SEED_LOOKAHEAD": "1", - "MIN_SLASHING_PENALTY_QUOTIENT": "64", - "MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR": "64", + "SHUFFLE_ROUND_COUNT": "90", + "TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH": "18446744073709551615", + "MAX_EFFECTIVE_BALANCE": "32000000000", + "DOMAIN_BEACON_PROPOSER": "0x00000000", + "DENEB_FORK_EPOCH": "29696", + "DOMAIN_SYNC_COMMITTEE": "0x07000000", + "PROPOSER_SCORE_BOOST": "40", + "DOMAIN_SELECTION_PROOF": "0x05000000", "MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX": "32", - "MIN_SYNC_COMMITTEE_PARTICIPANTS": "1", - "MIN_VALIDATOR_WITHDRAWABILITY_DELAY": "256", - "PRESET_BASE": "minimal", - "PROPORTIONAL_SLASHING_MULTIPLIER": "2", - "PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR": "2", - "PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX": "3", - "PROPOSER_REWARD_QUOTIENT": "8", - "PROPOSER_SCORE_BOOST": "70", - "RANDOM_SUBNETS_PER_VALIDATOR": "1", - "RESP_TIMEOUT": "10", - "SAFE_SLOTS_TO_UPDATE_JUSTIFIED": "8", - "SECONDS_PER_ETH1_BLOCK": "14", - "SECONDS_PER_SLOT": "12", - "SHARD_COMMITTEE_PERIOD": "256", - "SHUFFLE_ROUND_COUNT": "10", - "SLOTS_PER_EPOCH": "32", - "SLOTS_PER_HISTORICAL_ROOT": "64", + "MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT": "8", + "HYSTERESIS_UPWARD_MULTIPLIER": "5", "SUBNETS_PER_NODE": "2", - "SYNC_COMMITTEE_SIZE": "512", - "SYNC_COMMITTEE_SUBNET_COUNT": "4", - "TARGET_AGGREGATORS_PER_COMMITTEE": "16", - "TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE": "16", - "TARGET_COMMITTEE_SIZE": "4", + "MIN_DEPOSIT_AMOUNT": "1000000000", + "MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA": "4096", + "PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR": "2", + "MAX_BLOBS_PER_BLOCK": "6", + "MIN_VALIDATOR_WITHDRAWABILITY_DELAY": "256", + "MAXIMUM_GOSSIP_CLOCK_DISPARITY": "500", + "TARGET_COMMITTEE_SIZE": "128", "TERMINAL_BLOCK_HASH": "0x0000000000000000000000000000000000000000000000000000000000000000", - "TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH": "18446744073709551615", - "TERMINAL_TOTAL_DIFFICULTY": "10790000", - "TTFB_TIMEOUT": "5", + "DOMAIN_DEPOSIT": "0x03000000", + "DOMAIN_CONTRIBUTION_AND_PROOF": "0x09000000", "UPDATE_TIMEOUT": "8192", - "VALIDATOR_REGISTRY_LIMIT": "1099511627776", - "WHISTLEBLOWER_REWARD_QUOTIENT": "512" + "ELECTRA_FORK_EPOCH": "18446744073709551615", + "SYNC_COMMITTEE_BRANCH_LENGTH": "5", + "DEPOSIT_CHAIN_ID": "17000", + "MAX_BLOB_COMMITMENTS_PER_BLOCK": "4096", + "DOMAIN_RANDAO": "0x02000000", + "CAPELLA_FORK_VERSION": "0x04017000", + "MAX_EFFECTIVE_BALANCE_ELECTRA": "2048000000000", + "MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR": "64", + "EPOCHS_PER_ETH1_VOTING_PERIOD": "64", + "MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD": "8192", + "WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA": "4096", + "HISTORICAL_ROOTS_LIMIT": "16777216", + "ATTESTATION_PROPAGATION_SLOT_RANGE": "32", + "SYNC_COMMITTEE_SIZE": "512", + "ATTESTATION_SUBNET_PREFIX_BITS": "6", + "PROPORTIONAL_SLASHING_MULTIPLIER": "1", + "MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD": "16", + "MESSAGE_DOMAIN_VALID_SNAPPY": "0x01000000", + "MAX_VOLUNTARY_EXITS": "16", + "PENDING_CONSOLIDATIONS_LIMIT": "262144", + "HYSTERESIS_DOWNWARD_MULTIPLIER": "1", + "DOMAIN_APPLICATION_BUILDER": "0x00000001", + "MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP": "8", + "EPOCHS_PER_SYNC_COMMITTEE_PERIOD": "256", + "BYTES_PER_LOGS_BLOOM": "256", + "MIN_GENESIS_ACTIVE_VALIDATOR_COUNT": "16384", + "MAX_ATTESTATIONS": "128", + "MIN_EPOCHS_FOR_BLOCK_REQUESTS": "33024", + "DENEB_FORK_VERSION": "0x05017000", + "ELECTRA_FORK_VERSION": "0x06017000", + "MAX_REQUEST_BLOCKS": "1024", + "GENESIS_FORK_VERSION": "0x01017000", + "KZG_COMMITMENT_INCLUSION_PROOF_DEPTH": "17", + "DEPOSIT_NETWORK_ID": "17000", + "MAX_REQUEST_BLOCKS_DENEB": "128", + "BLOB_SIDECAR_SUBNET_COUNT": "6", + "SYNC_COMMITTEE_SUBNET_COUNT": "4", + "CAPELLA_FORK_EPOCH": "256", + "EJECTION_BALANCE": "28000000000", + "ATTESTATION_SUBNET_EXTRA_BITS": "0", + "MAX_COMMITTEES_PER_SLOT": "64", + "SHARD_COMMITTEE_PERIOD": "256", + "INACTIVITY_PENALTY_QUOTIENT_ALTAIR": "50331648", + "DOMAIN_AGGREGATE_AND_PROOF": "0x06000000", + "CHURN_LIMIT_QUOTIENT": "65536", + "BLS_WITHDRAWAL_PREFIX": "0x00", + "MIN_ACTIVATION_BALANCE": "32000000000" } }, "/eth/v2/beacon/blocks/0": { - "version": "phase0", - "execution_optimistic": false, - "data": { - "message": { - "slot": "0", - "proposer_index": "0", - "parent_root": "0x0000000000000000000000000000000000000000000000000000000000000000", - "state_root": "0x895390e92edc03df7096e9f51e51896e8dbe6e7e838180dadbfd869fdd77a659", - "body": { - "randao_reveal": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "eth1_data": { - "deposit_root": "0x0000000000000000000000000000000000000000000000000000000000000000", - "deposit_count": "0", - "block_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" - }, - "graffiti": "0x0000000000000000000000000000000000000000000000000000000000000000", - "proposer_slashings": [], - "attester_slashings": [], - "attestations": [], - "deposits": [], - "voluntary_exits": [] - } - }, - "signature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - } + "code": 404, + "message": "Not found" } } diff --git a/testutil/integration/simnet_test.go b/testutil/integration/simnet_test.go index 5029970b5..2b4ff0378 100644 --- a/testutil/integration/simnet_test.go +++ b/testutil/integration/simnet_test.go @@ -196,7 +196,9 @@ func newSimnetArgs(t *testing.T) simnetArgs { ) seed := 99 random := rand.New(rand.NewSource(int64(seed))) - lock, p2pKeys, secretShares := cluster.NewForT(t, numDVs, n, n, seed, random) + lock, p2pKeys, secretShares := cluster.NewForT(t, numDVs, n, n, seed, random, func(definition *cluster.Definition) { + definition.ForkVersion = []byte{0x01, 0x01, 0x70, 0x00} + }) secrets := secretShares[0] From b1724b8c63a79b00c2679969745c1520fbbf46c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gianguido=20Sor=C3=A0?= Date: Mon, 30 Sep 2024 11:51:57 +0200 Subject: [PATCH 4/5] app/eth2wrap: fix unit tests --- app/eth2wrap/eth2wrap_test.go | 10 +++++----- app/eth2wrap/synthproposer_test.go | 9 ++------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/app/eth2wrap/eth2wrap_test.go b/app/eth2wrap/eth2wrap_test.go index bcb64264e..3e35dfad6 100644 --- a/app/eth2wrap/eth2wrap_test.go +++ b/app/eth2wrap/eth2wrap_test.go @@ -462,27 +462,27 @@ func TestLazyDomain(t *testing.T) { { name: "mainnet fork", in: eth2util.Mainnet.GenesisForkVersionHex[2:], - expRes: "040000008c6ebbceb21209e6af5ab7db4a3027998c412c0eb0e15fbc1ee75617", + expRes: "04000000a39ec13dbafa3a331644f8d3a1513e57898fab998fec78f5ada4b8b0", }, { name: "goerli fork", in: eth2util.Goerli.GenesisForkVersionHex[2:], - expRes: "04000000628941ef21d1fe8c7134720add10bb91e3b02c007e0046d2472c6695", + expRes: "04000000f1e25bda59286379f9a2b3ffeb090d650a4db4cfd089e1cc72388a33", }, { name: "gnosis fork", in: eth2util.Gnosis.GenesisForkVersionHex[2:], - expRes: "04000000398beb768264920602d7d79f88da05cac0550ae4108753fd846408b5", + expRes: "040000007c97bfcba5d28a3cdef2ab010944574e387f4b3c7963c215eed87f32", }, { name: "sepolia fork", in: eth2util.Sepolia.GenesisForkVersionHex[2:], - expRes: "040000007191d9b3c210dbffc7810b6ccb436c1b3897b6772452924b20f6f5f2", + expRes: "0400000005b54270938f654bd779212d3be2a63f806a4f58794d455393d8dad8", }, { name: "holesky fork", in: eth2util.Holesky.GenesisForkVersionHex[2:], - expRes: "040000002b3e2c2d17a0d820f3099580a72d1bc743b17616ff7851f32aa303ad", + expRes: "0400000017e2dad36f1d3595152042a9ad23430197557e2e7e82bc7f7fc72972", }, { name: "unknown fork", diff --git a/app/eth2wrap/synthproposer_test.go b/app/eth2wrap/synthproposer_test.go index 132d41c67..492bd1104 100644 --- a/app/eth2wrap/synthproposer_test.go +++ b/app/eth2wrap/synthproposer_test.go @@ -67,15 +67,10 @@ func TestSynthProposer(t *testing.T) { activeVals++ return cached(ctx) } - signedBeaconBlock := bmock.SignedBeaconBlock bmock.SignedBeaconBlockFunc = func(ctx context.Context, blockID string) (*eth2spec.VersionedSignedBeaconBlock, error) { - opts := ð2api.SignedBeaconBlockOpts{Block: blockID} - resp, err := signedBeaconBlock(ctx, opts) - if err != nil { - return nil, err - } + resp := testutil.RandomCapellaVersionedSignedBeaconBlock() - return resp.Data, nil + return resp, nil } eth2Cl := eth2wrap.WithSyntheticDuties(bmock) From b5ef63536e451b9d36d1349e7eba4f94ba0a22b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gianguido=20Sor=C3=A0?= Date: Thu, 3 Oct 2024 15:43:46 +0200 Subject: [PATCH 5/5] eth2util: fix remaining failing tests --- eth2util/registration/registration_test.go | 20 ++++----- eth2util/signing/signing.go | 5 +++ eth2util/signing/signing_test.go | 51 ++++++++++++---------- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/eth2util/registration/registration_test.go b/eth2util/registration/registration_test.go index 9a22b6ab9..fd67700c2 100644 --- a/eth2util/registration/registration_test.go +++ b/eth2util/registration/registration_test.go @@ -106,21 +106,21 @@ func TestVerifySignedRegistration(t *testing.T) { require.NoError(t, err) registrationJSON := ` - { - "message": { - "fee_recipient": "0x000000000000000000000000000000000000dead", - "gas_limit": "30000000", - "timestamp": "1646092800", - "pubkey": "0x86966350b672bd502bfbdb37a6ea8a7392e8fb7f5ebb5c5e2055f4ee168ebfab0fef63084f28c9f62c3ba71f825e527e" - }, - "signature": "0xb101da0fc08addcc5d010ee569f6bbbdca049a5cb27efad231565bff2e3af504ec2bb87b11ed22843e9c1094f1dfe51a0b2a5ad1808df18530a2f59f004032dbf6281ecf0fc3df86d032da5b9d32a3d282c05923de491381f8f28c2863a00180" - }` + { + "message": { + "fee_recipient": "0x000000000000000000000000000000000000dEaD", + "gas_limit": "30000000", + "timestamp": "1646092800", + "pubkey": "0x86966350b672bd502bfbdb37a6ea8a7392e8fb7f5ebb5c5e2055f4ee168ebfab0fef63084f28c9f62c3ba71f825e527e" + }, + "signature": "0xad393c5b42b382cf93cd14f302b0175b4f9ccb000c201d42c3a6389971b8d910a81333d55ad2944b836a9bb35ba968ab06635dcd706380516ad0c653f48b1c6d52b8771c78d708e943b3ea8da59392fbf909decde262adc944fe3e57120d9bb4" + }` reg := new(eth2v1.SignedValidatorRegistration) err = json.Unmarshal([]byte(registrationJSON), reg) require.NoError(t, err) - forkVersion, err := eth2util.NetworkToForkVersionBytes("goerli") + forkVersion, err := eth2util.NetworkToForkVersionBytes("holesky") require.NoError(t, err) sigRoot, err := registration.GetMessageSigningRoot(reg.Message, eth2p0.Version(forkVersion)) diff --git a/eth2util/signing/signing.go b/eth2util/signing/signing.go index 04effc690..6df16c330 100644 --- a/eth2util/signing/signing.go +++ b/eth2util/signing/signing.go @@ -52,6 +52,11 @@ func GetDomain(ctx context.Context, eth2Cl eth2wrap.Client, name DomainName, epo return eth2p0.Domain{}, errors.New("invalid domain type") } + // Domain needs to be genesis one for DomainApplicationBuilder + if name == DomainApplicationBuilder { + return eth2Cl.GenesisDomain(ctx, domainTyped) + } + return eth2Cl.Domain(ctx, domainTyped, epoch) } diff --git a/eth2util/signing/signing_test.go b/eth2util/signing/signing_test.go index dac379fae..0639a0ecd 100644 --- a/eth2util/signing/signing_test.go +++ b/eth2util/signing/signing_test.go @@ -13,6 +13,8 @@ import ( eth2p0 "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/stretchr/testify/require" + "github.com/obolnetwork/charon/eth2util" + "github.com/obolnetwork/charon/eth2util/registration" "github.com/obolnetwork/charon/eth2util/signing" "github.com/obolnetwork/charon/tbls" "github.com/obolnetwork/charon/tbls/tblsconv" @@ -32,24 +34,27 @@ func TestVerifyRegistrationReference(t *testing.T) { require.NoError(t, err) registrationJSON := ` - { - "message": { - "fee_recipient": "0x000000000000000000000000000000000000dead", - "gas_limit": "30000000", - "timestamp": "1646092800", - "pubkey": "0x86966350b672bd502bfbdb37a6ea8a7392e8fb7f5ebb5c5e2055f4ee168ebfab0fef63084f28c9f62c3ba71f825e527e" - }, - "signature": "0xb101da0fc08addcc5d010ee569f6bbbdca049a5cb27efad231565bff2e3af504ec2bb87b11ed22843e9c1094f1dfe51a0b2a5ad1808df18530a2f59f004032dbf6281ecf0fc3df86d032da5b9d32a3d282c05923de491381f8f28c2863a00180" - }` - - registration := new(eth2v1.SignedValidatorRegistration) - err = json.Unmarshal([]byte(registrationJSON), registration) + { + "message": { + "fee_recipient": "0x000000000000000000000000000000000000dEaD", + "gas_limit": "30000000", + "timestamp": "1646092800", + "pubkey": "0x86966350b672bd502bfbdb37a6ea8a7392e8fb7f5ebb5c5e2055f4ee168ebfab0fef63084f28c9f62c3ba71f825e527e" + }, + "signature": "0xad393c5b42b382cf93cd14f302b0175b4f9ccb000c201d42c3a6389971b8d910a81333d55ad2944b836a9bb35ba968ab06635dcd706380516ad0c653f48b1c6d52b8771c78d708e943b3ea8da59392fbf909decde262adc944fe3e57120d9bb4" + }` + + reg := new(eth2v1.SignedValidatorRegistration) + err = json.Unmarshal([]byte(registrationJSON), reg) require.NoError(t, err) - sigRoot, err := registration.Message.HashTreeRoot() + sigRoot, err := reg.Message.HashTreeRoot() require.NoError(t, err) - sigData, err := signing.GetDataRoot(context.Background(), bmock, signing.DomainApplicationBuilder, 0, sigRoot) + fork, err := eth2util.NetworkToForkVersionBytes("holesky") + require.NoError(t, err) + + sigData, err := registration.GetMessageSigningRoot(reg.Message, eth2p0.Version(fork)) require.NoError(t, err) sig, err := tbls.Sign(secretShare, sigData[:]) @@ -57,7 +62,7 @@ func TestVerifyRegistrationReference(t *testing.T) { sigEth2 := eth2p0.BLSSignature(sig) require.Equal(t, - hex.EncodeToString(registration.Signature[:]), + hex.EncodeToString(reg.Signature[:]), hex.EncodeToString(sigEth2[:]), ) @@ -69,10 +74,10 @@ func TestVerifyRegistrationReference(t *testing.T) { } func TestConstantApplicationBuilder(t *testing.T) { - v0 := eth2p0.Version{0x00, 0x00, 0x10, 0x20} - v1 := eth2p0.Version{0x01, 0x00, 0x10, 0x20} - v2 := eth2p0.Version{0x02, 0x00, 0x10, 0x20} - v3 := eth2p0.Version{0x03, 0x00, 0x10, 0x20} + v0 := eth2p0.Version{0x01, 0x01, 0x70, 0x00} + v1 := eth2p0.Version{0x02, 0x01, 0x70, 0x00} + v2 := eth2p0.Version{0x03, 0x01, 0x70, 0x00} + v3 := eth2p0.Version{0x04, 0x01, 0x70, 0x00} forkSchedule := []*eth2p0.Fork{ {PreviousVersion: v0, CurrentVersion: v0, Epoch: 0}, @@ -97,10 +102,10 @@ func TestConstantApplicationBuilder(t *testing.T) { // Assert genesis domain is used for any fork schedule. expect := eth2p0.Domain{ - 0x00, 0x00, 0x00, 0x01, 0xe4, 0xbe, 0x93, 0x93, - 0xb0, 0x74, 0xca, 0x1f, 0x3e, 0x4a, 0xab, 0xd5, - 0x85, 0xca, 0x4b, 0xea, 0x10, 0x11, 0x70, 0xcc, - 0xfa, 0xf7, 0x1b, 0x89, 0xce, 0x5c, 0x5c, 0x38, + 0x0, 0x0, 0x0, 0x1, 0x5b, 0x83, 0xa2, 0x37, + 0x59, 0xc5, 0x60, 0xb2, 0xd0, 0xc6, 0x45, 0x76, + 0xe1, 0xdc, 0xfc, 0x34, 0xea, 0x94, 0xc4, 0x98, + 0x8f, 0x3e, 0xd, 0x9f, 0x77, 0xf0, 0x53, 0x87, } for i := range len(forkSchedule) {