Skip to content

Commit 4cbf71c

Browse files
committed
Further improve DRY adherence and coverage
1 parent b4f330f commit 4cbf71c

6 files changed

Lines changed: 633 additions & 144 deletions

File tree

pkg/dirksigner/dirk-signer.go

Lines changed: 68 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ import (
1010
"strconv"
1111
"sync"
1212

13-
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
14-
"github.com/attestantio/go-eth2-client/spec/phase0"
1513
ssz "github.com/ferranbt/fastssz"
16-
"github.com/herumi/bls-eth-go-binary/bls"
1714
"github.com/jshufro/remote-signer-dirk-interop/generated/api"
1815
"github.com/jshufro/remote-signer-dirk-interop/pkg/dirksigner/dirk"
1916
"github.com/jshufro/remote-signer-dirk-interop/pkg/domains"
@@ -23,6 +20,8 @@ import (
2320
tlsprovider "github.com/jshufro/remote-signer-dirk-interop/pkg/tls"
2421
"github.com/jshufro/remote-signer-dirk-interop/pkg/typeconv"
2522

23+
"github.com/attestantio/go-eth2-client/spec/phase0"
24+
"github.com/herumi/bls-eth-go-binary/bls"
2625
e2t "github.com/wealdtech/go-eth2-types/v2"
2726
e2wd "github.com/wealdtech/go-eth2-wallet-dirk"
2827
e2wt "github.com/wealdtech/go-eth2-wallet-types/v2"
@@ -81,6 +80,7 @@ func (d *DirkSigner) Open(ctx context.Context, logLevel slog.Level) error {
8180

8281
// Prime the account pubkey map
8382
_ = d.getPublicKeys(ctx)
83+
8484
return nil
8585
}
8686

@@ -93,6 +93,7 @@ func (d *DirkSigner) getPublicKeys(ctx context.Context) [][48]byte {
9393
out = append(out, pubkeyBytes)
9494
d.accounts.Store(pubkeyBytes, account)
9595
}
96+
9697
return out
9798
}
9899

@@ -107,52 +108,53 @@ func (d *DirkSigner) GetAccountForPubkey(ctx context.Context, pubkey [48]byte) (
107108
aps, ok := account.(e2wt.AccountProtectingSigner)
108109
if !ok {
109110
d.log.Error("account is not a protecting signer", "pubkey", hex.EncodeToString(pubkey[:]))
110-
return nil, errors.BadRequest("account is not a protecting signer")
111+
return nil, errors.InternalServerError()
111112
}
112113
return aps, nil
113114
}
114115

115116
return nil, errors.PublicKeyNotFound("account not found for pubkey: %s", hex.EncodeToString(pubkey[:]))
116117
}
117118

118-
func (d *DirkSigner) calculateDomain(
119-
domainType domains.DomainType,
120-
forkInfo *fork.ForkInfo,
121-
epoch uint64,
122-
) ([]byte, error) {
123-
out, err := forkInfo.ComputeDomain(domainType, epoch)
119+
func (d *DirkSigner) signature(signature e2t.Signature) ([96]byte, error) {
120+
b, err := typeconv.SignatureToBytes(signature)
124121
if err != nil {
125-
d.log.Error("failed to compute domain", "error", err)
126-
return nil, errors.InternalServerError()
122+
return d.returnUnexpectedFailure("produced invalid signature", err)
127123
}
128-
d.log.Debug("computed domain", "domain", fmt.Sprintf("%#x", out))
129-
return out, nil
130-
}
131124

132-
func (d *DirkSigner) returnSignature(signature e2t.Signature) ([96]byte, error) {
133-
b := signature.Marshal()
134-
if len(b) != 96 {
135-
return d.returnUnexpectedFailure("produced signature is not 96 bytes", fmt.Errorf("signature is %d bytes", len(b)))
136-
}
137-
return [96]byte(b), nil
125+
return b, nil
138126
}
139127

140-
func (d *DirkSigner) returnSignGeneric(ctx context.Context, account e2wt.AccountProtectingSigner, htr [32]byte, domain []byte) ([96]byte, error) {
128+
func (d *DirkSigner) sign(
129+
ctx context.Context,
130+
account e2wt.AccountProtectingSigner,
131+
htr [32]byte,
132+
domainProvider domains.DomainProvider,
133+
) ([96]byte, error) {
134+
domain, err := domainProvider.ComputeDomain()
135+
if err != nil {
136+
return d.returnUnexpectedFailure("failed to compute domain", err)
137+
}
141138
signature, err := account.SignGeneric(ctx, htr[:], domain)
142139
if err != nil {
143-
d.log.Warn("failed to sign generic", "error", err)
144-
return [96]byte{}, errors.InternalServerError()
140+
return d.returnUnexpectedFailure("failed to sign generic", err)
145141
}
146-
return d.returnSignature(signature)
142+
143+
return d.signature(signature)
147144
}
148145

149-
func (d *DirkSigner) sign(ctx context.Context, account e2wt.AccountProtectingSigner, htr [32]byte, domainType domains.DomainType, forkInfo *fork.ForkInfo, epoch uint64) ([96]byte, error) {
150-
domain, err := d.calculateDomain(domainType, forkInfo, epoch)
146+
func (d *DirkSigner) signHashRoot(
147+
ctx context.Context,
148+
account e2wt.AccountProtectingSigner,
149+
htr ssz.HashRoot,
150+
domainProvider domains.DomainProvider,
151+
) ([96]byte, error) {
152+
htrResult, err := htr.HashTreeRoot()
151153
if err != nil {
152-
d.log.Warn("failed to compute domain", "error", err)
153-
return [96]byte{}, errors.InternalServerError()
154+
return d.returnUnexpectedFailure("failed to compute hash tree root", err)
154155
}
155-
return d.returnSignGeneric(ctx, account, htr, domain)
156+
157+
return d.sign(ctx, account, htrResult, domainProvider)
156158
}
157159

158160
func (d *DirkSigner) returnUnexpectedFailure(msg string, err error) ([96]byte, error) {
@@ -172,17 +174,14 @@ func (d *DirkSigner) AggregationSlotSigning(
172174
if err != nil {
173175
return [96]byte{}, errors.BadRequest("failed to parse slot: %w", err)
174176
}
175-
hasher := ssz.NewHasher()
176-
hasher.AppendUint64(slot)
177-
hasher.FillUpTo32()
178-
hashTreeRoot, err := hasher.HashRoot()
179-
if err != nil {
180-
return d.returnUnexpectedFailure("failed to compute hash tree root", err)
181-
}
177+
// Simply right-pad the slot to 32 bytes
178+
hashTreeRoot := typeconv.Uint64ToHashTreeRoot(slot)
182179

183180
epoch := slot / 32
184181

185-
return d.sign(ctx, account, hashTreeRoot, domains.DomainSelectionProof, forkInfo, epoch)
182+
domainProvider := forkInfo.WithDomainType(domains.DomainSelectionProof).DomainProvider(epoch)
183+
184+
return d.sign(ctx, account, hashTreeRoot, domainProvider)
186185
}
187186

188187
func (d *DirkSigner) AggregateAndProofSigningV2(
@@ -198,7 +197,7 @@ func (d *DirkSigner) AggregateAndProofSigningV2(
198197
return [96]byte{}, errors.BadRequest("failed to get discriminator: %w", err)
199198
}
200199

201-
var htr func() ([32]byte, error)
200+
var htr ssz.HashRoot
202201
var epoch uint64
203202
switch discriminator {
204203
case "PHASE0", "ALTAIR", "BELLATRIX", "CAPELLA", "DENEB":
@@ -207,25 +206,22 @@ func (d *DirkSigner) AggregateAndProofSigningV2(
207206
return [96]byte{}, errors.BadRequest("failed to get phase0 aggregate and proof: %w", err)
208207
}
209208
epoch = uint64(phase0AggregateAndProof.Data.Aggregate.Data.Slot / 32)
210-
htr = phase0AggregateAndProof.Data.HashTreeRoot
209+
htr = &phase0AggregateAndProof.Data
211210
case "ELECTRA", "FULU":
212211
electraAggregateAndProof, err := aggregateAndProof.AsAggregateAndProofRequestElectra()
213212
if err != nil {
214213
return [96]byte{}, errors.BadRequest("failed to get electra aggregate and proof: %w", err)
215214
}
216215
epoch = uint64(electraAggregateAndProof.Data.Aggregate.Data.Slot / 32)
217-
htr = electraAggregateAndProof.Data.HashTreeRoot
216+
htr = &electraAggregateAndProof.Data
218217
default:
219218
d.log.Warn("unknown aggregate and proof type", "discriminator", discriminator)
220219
return [96]byte{}, errors.BadRequest("unknown aggregate and proof type: %s", discriminator)
221220
}
222221

223-
hashTreeRoot, err := htr()
224-
if err != nil {
225-
return d.returnUnexpectedFailure("failed to compute hash tree root", err)
226-
}
222+
domainProvider := forkInfo.WithDomainType(domains.DomainAggregateAndProof).DomainProvider(epoch)
227223

228-
return d.sign(ctx, account, hashTreeRoot, domains.DomainAggregateAndProof, forkInfo, epoch)
224+
return d.signHashRoot(ctx, account, htr, domainProvider)
229225
}
230226

231227
func (d *DirkSigner) AttestationSigning(
@@ -236,11 +232,8 @@ func (d *DirkSigner) AttestationSigning(
236232
) ([96]byte, error) {
237233
attestation := obj.Attestation
238234
epoch := uint64(attestation.Slot / 32)
239-
domain, err := d.calculateDomain(
240-
domains.DomainBeaconAttester,
241-
forkInfo,
242-
epoch,
243-
)
235+
domainProvider := forkInfo.WithDomainType(domains.DomainBeaconAttester).DomainProvider(epoch)
236+
domain, err := domainProvider.ComputeDomain()
244237
if err != nil {
245238
return d.returnUnexpectedFailure("failed to compute domain", err)
246239
}
@@ -259,7 +252,8 @@ func (d *DirkSigner) AttestationSigning(
259252
if err != nil {
260253
return d.returnUnexpectedFailure("failed to sign beacon attestation", err)
261254
}
262-
return d.returnSignature(signature)
255+
256+
return d.signature(signature)
263257
}
264258

265259
func (d *DirkSigner) BeaconBlockSigning(
@@ -348,11 +342,8 @@ func (d *DirkSigner) BeaconBlockSigning(
348342
}
349343

350344
epoch := uint64(header.Slot / 32)
351-
domain, err := d.calculateDomain(
352-
domains.DomainBeaconProposer,
353-
forkInfo,
354-
epoch,
355-
)
345+
domainProvider := forkInfo.WithDomainType(domains.DomainBeaconProposer).DomainProvider(epoch)
346+
domain, err := domainProvider.ComputeDomain()
356347
if err != nil {
357348
return d.returnUnexpectedFailure("failed to compute domain", err)
358349
}
@@ -368,7 +359,8 @@ func (d *DirkSigner) BeaconBlockSigning(
368359
if err != nil {
369360
return d.returnUnexpectedFailure("failed to sign beacon proposal", err)
370361
}
371-
return d.returnSignature(signature)
362+
363+
return d.signature(signature)
372364
}
373365

374366
func (d *DirkSigner) DepositSigning(
@@ -385,7 +377,7 @@ func (d *DirkSigner) DepositSigning(
385377
return [96]byte{}, errors.BadRequest("genesis fork version is not 4 bytes")
386378
}
387379
// Round-trip the obj.Deposit to a phase0.DepositMessage via json
388-
// The payload to this api has an extra field and this is removes it plus gives us
380+
// The payload to this api has an extra field and this removes it plus gives us
389381
// a type that implements ssz.HashRoot
390382
depositMessageJson, err := json.Marshal(obj.Deposit)
391383
if err != nil {
@@ -397,23 +389,9 @@ func (d *DirkSigner) DepositSigning(
397389
return [96]byte{}, errors.BadRequest("failed to unmarshal deposit: %w", err)
398390
}
399391

400-
hashTreeRoot, err := deposit.HashTreeRoot()
401-
if err != nil {
402-
return [96]byte{}, errors.InternalServerError()
403-
}
404-
405-
// For deposits, only genesis fork version is needed
406-
// genesis validators root must be nil
407-
domain, err := signing.ComputeDomain(
408-
domains.DomainDeposit,
409-
genesisForkVersion,
410-
nil, /* genesis validators root */
411-
)
412-
if err != nil {
413-
return d.returnUnexpectedFailure("failed to compute domain", err)
414-
}
392+
domainProvider := domains.DepositDomainProvider(genesisForkVersion)
415393

416-
return d.returnSignGeneric(ctx, account, hashTreeRoot, domain)
394+
return d.signHashRoot(ctx, account, deposit, domainProvider)
417395
}
418396

419397
func (d *DirkSigner) RandaoRevealSigning(
@@ -428,15 +406,11 @@ func (d *DirkSigner) RandaoRevealSigning(
428406
if err != nil {
429407
return [96]byte{}, errors.BadRequest("failed to parse epoch: %w", err)
430408
}
431-
hasher := ssz.NewHasher()
432-
hasher.AppendUint64(epoch)
433-
hasher.FillUpTo32()
434-
hashTreeRoot, err := hasher.HashRoot()
435-
if err != nil {
436-
return d.returnUnexpectedFailure("failed to compute hash tree root", err)
437-
}
438409

439-
return d.sign(ctx, account, hashTreeRoot, domains.DomainRandao, forkInfo, epoch)
410+
hashTreeRoot := typeconv.Uint64ToHashTreeRoot(epoch)
411+
domainProvider := forkInfo.WithDomainType(domains.DomainRandao).DomainProvider(epoch)
412+
413+
return d.sign(ctx, account, hashTreeRoot, domainProvider)
440414
}
441415

442416
func (d *DirkSigner) VoluntaryExitSigning(
@@ -445,14 +419,10 @@ func (d *DirkSigner) VoluntaryExitSigning(
445419
obj *api.VoluntaryExitSigning,
446420
forkInfo *fork.ForkInfo,
447421
) ([96]byte, error) {
448-
hashTreeRoot, err := obj.VoluntaryExit.HashTreeRoot()
449-
if err != nil {
450-
return d.returnUnexpectedFailure("failed to compute hash tree root", err)
451-
}
452-
453422
epoch := uint64(obj.VoluntaryExit.Epoch)
423+
domainProvider := forkInfo.WithDomainType(domains.DomainVoluntaryExit).DomainProvider(epoch)
454424

455-
return d.sign(ctx, account, hashTreeRoot, domains.DomainVoluntaryExit, forkInfo, epoch)
425+
return d.signHashRoot(ctx, account, &obj.VoluntaryExit, domainProvider)
456426
}
457427

458428
func (d *DirkSigner) SyncCommitteeMessageSigning(
@@ -479,7 +449,9 @@ func (d *DirkSigner) SyncCommitteeMessageSigning(
479449

480450
epoch := slot / 32
481451

482-
return d.sign(ctx, account, htr, domains.DomainSyncCommittee, forkInfo, epoch)
452+
domainProvider := forkInfo.WithDomainType(domains.DomainSyncCommittee).DomainProvider(epoch)
453+
454+
return d.sign(ctx, account, htr, domainProvider)
483455
}
484456

485457
func (d *DirkSigner) SyncCommitteeSelectionProofSigning(
@@ -488,14 +460,10 @@ func (d *DirkSigner) SyncCommitteeSelectionProofSigning(
488460
obj *api.SyncCommitteeSelectionProofSigning,
489461
forkInfo *fork.ForkInfo,
490462
) ([96]byte, error) {
491-
hashTreeRoot, err := obj.SyncAggregatorSelectionData.HashTreeRoot()
492-
if err != nil {
493-
return d.returnUnexpectedFailure("failed to compute hash tree root", err)
494-
}
495-
496463
epoch := uint64(obj.SyncAggregatorSelectionData.Slot / 32)
464+
domainProvider := forkInfo.WithDomainType(domains.DomainSyncCommiteeSelectionProof).DomainProvider(epoch)
497465

498-
return d.sign(ctx, account, hashTreeRoot, domains.DomainSyncCommiteeSelectionProof, forkInfo, epoch)
466+
return d.signHashRoot(ctx, account, &obj.SyncAggregatorSelectionData, domainProvider)
499467
}
500468

501469
func (d *DirkSigner) SyncCommitteeContributionAndProofSigning(
@@ -504,38 +472,18 @@ func (d *DirkSigner) SyncCommitteeContributionAndProofSigning(
504472
obj *api.SyncCommitteeContributionAndProofSigning,
505473
forkInfo *fork.ForkInfo,
506474
) ([96]byte, error) {
507-
hashTreeRoot, err := obj.ContributionAndProof.HashTreeRoot()
508-
if err != nil {
509-
return d.returnUnexpectedFailure("failed to compute hash tree root", err)
510-
}
511-
512475
epoch := uint64(obj.ContributionAndProof.Contribution.Slot / 32)
476+
domainProvider := forkInfo.WithDomainType(domains.DomainSyncContributionAndProof).DomainProvider(epoch)
513477

514-
return d.sign(ctx, account, hashTreeRoot, domains.DomainSyncContributionAndProof, forkInfo, epoch)
478+
return d.signHashRoot(ctx, account, &obj.ContributionAndProof, domainProvider)
515479
}
516480

517481
func (d *DirkSigner) ValidatorRegistrationSigning(
518482
ctx context.Context,
519483
account e2wt.AccountProtectingSigner,
520484
obj *api.ValidatorRegistrationSigning,
521485
) ([96]byte, error) {
486+
domainProvider := domains.ValidatorRegistrationDomainProvider(d.genesisForkVersion)
522487

523-
hashTreeRoot, err := obj.ValidatorRegistration.HashTreeRoot()
524-
if err != nil {
525-
return d.returnUnexpectedFailure("failed to compute hash tree root", err)
526-
}
527-
528-
// Compute the domain
529-
// For validator registrations, only genesis fork version is needed
530-
// genesis validators root must be nil
531-
domain, err := signing.ComputeDomain(
532-
domains.DomainApplicationBuilder,
533-
d.genesisForkVersion,
534-
nil, /* genesis validators root */
535-
)
536-
if err != nil {
537-
return d.returnUnexpectedFailure("failed to compute domain", err)
538-
}
539-
540-
return d.returnSignGeneric(ctx, account, hashTreeRoot, domain)
488+
return d.signHashRoot(ctx, account, &obj.ValidatorRegistration, domainProvider)
541489
}

0 commit comments

Comments
 (0)