Skip to content

Commit d96ec5f

Browse files
metachrisilyaluk
andauthored
Avoid type conversion in json registerValidator cache check (#729)
* trying faster json parsing by avoiding type conversion before cache check * simplify code a bit We can parse most of the types, except pubkey and signature without any performance issues. This way we do not need to store second form in local cache --------- Co-authored-by: Ilya Lukyanov <[email protected]>
1 parent c71fc35 commit d96ec5f

File tree

5 files changed

+244
-163
lines changed

5 files changed

+244
-163
lines changed

.claudeignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.github/
2+
/scripts/
3+
/static/
4+
/docs/

common/errors.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@ var (
77
ErrInvalidHash = errors.New("invalid hash")
88
ErrInvalidPubkey = errors.New("invalid pubkey")
99
ErrInvalidSignature = errors.New("invalid signature")
10+
11+
ErrTimestampNegative = errors.New("timestamp is negative")
12+
ErrTimestampTooEarly = errors.New("timestamp too early")
13+
ErrTimestampTooFarInFuture = errors.New("timestamp too far in the future")
1014
)

common/types.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@ import (
77
"os"
88
"strconv"
99
"strings"
10+
"time"
1011

1112
builderApiV1 "github.com/attestantio/go-builder-client/api/v1"
1213
"github.com/attestantio/go-eth2-client/spec/bellatrix"
1314
"github.com/attestantio/go-eth2-client/spec/capella"
1415
"github.com/attestantio/go-eth2-client/spec/deneb"
1516
"github.com/attestantio/go-eth2-client/spec/electra"
1617
"github.com/attestantio/go-eth2-client/spec/phase0"
18+
"github.com/buger/jsonparser"
1719
ssz "github.com/ferranbt/fastssz"
1820
boostSsz "github.com/flashbots/go-boost-utils/ssz"
21+
"github.com/flashbots/go-boost-utils/utils"
1922
)
2023

2124
var (
@@ -218,6 +221,8 @@ func (e *EthNetworkDetails) String() string {
218221
e.DomainBeaconProposerElectra)
219222
}
220223

224+
// PubkeyHex represents a hex-encoded public key.
225+
// It is lowercased on creation and is not validated/parsed.
221226
type PubkeyHex string
222227

223228
func NewPubkeyHex(pk string) PubkeyHex {
@@ -228,6 +233,10 @@ func (p PubkeyHex) String() string {
228233
return string(p)
229234
}
230235

236+
func (p PubkeyHex) ToPubkey() (ret phase0.BLSPubKey, err error) {
237+
return utils.HexToPubkey(string(p))
238+
}
239+
231240
type BuilderGetValidatorsResponseEntry struct {
232241
Slot uint64 `json:"slot,string"`
233242
ValidatorIndex uint64 `json:"validator_index,string"`
@@ -728,3 +737,68 @@ func (s *SubmitBlockRequestV2Optimistic) SizeSSZ() (size int) {
728737

729738
return
730739
}
740+
741+
// SimpleValidatorRegistration is a helper type for fast JSON decoding
742+
type SimpleValidatorRegistration struct {
743+
FeeRecipient bellatrix.ExecutionAddress
744+
GasLimit uint64
745+
Timestamp time.Time
746+
747+
// These two are intentionally left unparsed due to heavy parsing maths
748+
Pubkey PubkeyHex
749+
Signature string
750+
}
751+
752+
func (r *SimpleValidatorRegistration) UnmarshalJSON(value []byte) error {
753+
_feeRecipient, err := jsonparser.GetUnsafeString(value, "message", "fee_recipient")
754+
if err != nil {
755+
return fmt.Errorf("registration message error (fee_recipient): %w", err)
756+
}
757+
758+
// this one is fast, it's hex decode, no fancy crypto maths
759+
feeRecipient, err := utils.HexToAddress(_feeRecipient)
760+
if err != nil {
761+
return fmt.Errorf("registration message error (fee_recipient): %w", err)
762+
}
763+
764+
_gasLimit, err := jsonparser.GetUnsafeString(value, "message", "gas_limit")
765+
if err != nil {
766+
return fmt.Errorf("registration message error (gasLimit): %w", err)
767+
}
768+
769+
gasLimit, err := strconv.ParseUint(_gasLimit, 10, 64)
770+
if err != nil {
771+
return fmt.Errorf("invalid gasLimit: %w", err)
772+
}
773+
774+
_timestamp, err := jsonparser.GetUnsafeString(value, "message", "timestamp")
775+
if err != nil {
776+
return fmt.Errorf("registration message error (timestamp): %w", err)
777+
}
778+
779+
timestamp, err := strconv.ParseInt(_timestamp, 10, 64)
780+
if err != nil {
781+
return fmt.Errorf("invalid timestamp: %w", err)
782+
}
783+
if timestamp < 0 {
784+
return ErrTimestampNegative
785+
}
786+
787+
pubkey, err := jsonparser.GetUnsafeString(value, "message", "pubkey")
788+
if err != nil {
789+
return fmt.Errorf("registration message error (pubkey): %w", err)
790+
}
791+
792+
signature, err := jsonparser.GetUnsafeString(value, "signature")
793+
if err != nil {
794+
return fmt.Errorf("registration message error (signature): %w", err)
795+
}
796+
797+
r.FeeRecipient = feeRecipient
798+
r.GasLimit = gasLimit
799+
r.Timestamp = time.Unix(timestamp, 0)
800+
r.Pubkey = NewPubkeyHex(pubkey)
801+
r.Signature = signature
802+
803+
return nil
804+
}

datastore/redis.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ func (r *RedisCache) HSetObj(key, field string, value any, expiration time.Durat
242242

243243
func (r *RedisCache) GetValidatorRegistrationData(proposerPubkey common.PubkeyHex) (*builderApiV1.ValidatorRegistration, error) {
244244
data := new(builderApiV1.ValidatorRegistration)
245-
pk := strings.ToLower(proposerPubkey.String())
246245

247-
dataRaw, err := r.client.HGet(context.Background(), r.keyValidatorRegistrationData, pk).Result()
246+
// common.PubkeyHex is lowercase at the time of creation
247+
dataRaw, err := r.client.HGet(context.Background(), r.keyValidatorRegistrationData, proposerPubkey.String()).Result()
248248
if errors.Is(err, redis.Nil) {
249249
return nil, nil
250250
}

0 commit comments

Comments
 (0)