Skip to content

Commit

Permalink
Add flag to publish block with ssz (#598)
Browse files Browse the repository at this point in the history
* Add flag to publish block with ssz

* profiling

* Update beaconclient/prod_beacon_instance.go

Co-authored-by: Chris Hager <chris@linuxuser.at>

* Update beaconclient/prod_beacon_instance.go

Co-authored-by: Chris Hager <chris@linuxuser.at>

* Update beaconclient/prod_beacon_instance.go

Co-authored-by: Chris Hager <chris@linuxuser.at>

* Update beaconclient/prod_beacon_instance.go

Co-authored-by: Chris Hager <chris@linuxuser.at>

* Update beaconclient/prod_beacon_instance.go

Co-authored-by: Chris Hager <chris@linuxuser.at>

* Update beaconclient/prod_beacon_instance.go

Co-authored-by: Chris Hager <chris@linuxuser.at>

* fix naming

* add slot to log

* New http client for every beacon request (#603)

* New http client for every beacon request

* use milliseconds for timeout

---------

Co-authored-by: Chris Hager <chris@linuxuser.at>
  • Loading branch information
avalonche and metachris committed Apr 11, 2024
1 parent 71ebb23 commit 59549f6
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 42 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ redis-cli DEL boost-relay/sepolia:validators-registration boost-relay/sepolia:va
* `FORCE_GET_HEADER_204` - force 204 as getHeader response
* `ENABLE_IGNORABLE_VALIDATION_ERRORS` - enable ignorable validation errors
* `USE_V1_PUBLISH_BLOCK_ENDPOINT` - uses the v1 publish block endpoint on the beacon node
* `USE_SSZ_ENCODING_PUBLISH_BLOCK` - uses the SSZ encoding for the publish block endpoint

#### Development Environment Variables

Expand Down
42 changes: 39 additions & 3 deletions beaconclient/prod_beacon_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ type ProdBeaconInstance struct {
beaconURI string

// feature flags
ffUseV1PublishBlockEndpoint bool
ffUseV1PublishBlockEndpoint bool
ffUseSSZEncodingPublishBlock bool
}

func NewProdBeaconInstance(log *logrus.Entry, beaconURI string) *ProdBeaconInstance {
Expand All @@ -28,14 +29,19 @@ func NewProdBeaconInstance(log *logrus.Entry, beaconURI string) *ProdBeaconInsta
"beaconURI": beaconURI,
})

client := &ProdBeaconInstance{_log, beaconURI, false}
client := &ProdBeaconInstance{_log, beaconURI, false, false}

// feature flags
if os.Getenv("USE_V1_PUBLISH_BLOCK_ENDPOINT") != "" {
_log.Warn("env: USE_V1_PUBLISH_BLOCK_ENDPOINT: use the v1 publish block endpoint")
client.ffUseV1PublishBlockEndpoint = true
}

if os.Getenv("USE_SSZ_ENCODING_PUBLISH_BLOCK") != "" {
_log.Warn("env: USE_SSZ_ENCODING_PUBLISH_BLOCK: using SSZ encoding to publish blocks")
client.ffUseSSZEncodingPublishBlock = true
}

return client
}

Expand Down Expand Up @@ -251,7 +257,37 @@ func (c *ProdBeaconInstance) PublishBlock(block *common.VersionedSignedProposal,
}
headers := http.Header{}
headers.Add("Eth-Consensus-Version", strings.ToLower(block.Version.String())) // optional in v1, required in v2
return fetchBeacon(http.MethodPost, uri, block, nil, nil, headers, false)

slot, err := block.Slot()
if err != nil {
slot = 0
}

var payloadBytes []byte
useSSZ := c.ffUseSSZEncodingPublishBlock
log := c.log
encodeStartTime := time.Now().UTC()
if useSSZ {
log = log.WithField("publishContentType", "ssz")
payloadBytes, err = block.MarshalSSZ()
} else {
log = log.WithField("publishContentType", "json")
payloadBytes, err = json.Marshal(block)
}
if err != nil {
return 0, fmt.Errorf("could not marshal request: %w", err)
}
publishingStartTime := time.Now().UTC()
encodeDurationMs := publishingStartTime.Sub(encodeStartTime).Milliseconds()
code, err = fetchBeacon(http.MethodPost, uri, payloadBytes, nil, nil, headers, useSSZ)
publishDurationMs := time.Now().UTC().Sub(publishingStartTime).Milliseconds()
log.WithFields(logrus.Fields{
"slot": slot,
"encodeDurationMs": encodeDurationMs,
"publishDurationMs": publishDurationMs,
"payloadBytes": len(payloadBytes),
}).Info("finished publish block request")
return code, err
}

type GetGenesisResponse struct {
Expand Down
50 changes: 11 additions & 39 deletions beaconclient/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,61 +31,33 @@ func parseBroadcastModeString(s string) (BroadcastMode, bool) {
return b, ok
}

func makeJSONRequest(method, url string, payload any) (*http.Request, error) {
payloadBytes, err := json.Marshal(payload)
if err != nil {
return nil, fmt.Errorf("could not marshal request: %w", err)
}
req, err := http.NewRequest(method, url, bytes.NewReader(payloadBytes))
if err != nil {
return nil, fmt.Errorf("invalid request for %s: %w", url, err)
}
// Set content-type
req.Header.Add("Content-Type", "application/json")
return req, nil
}

func makeSSZRequest(method, url string, payload any) (*http.Request, error) {
payloadBytes, ok := payload.([]byte)
if !ok {
return nil, fmt.Errorf("invalid payload type for SSZ request: %w", ErrInvalidRequestPayload)
}
req, err := http.NewRequest(method, url, bytes.NewReader(payloadBytes))
if err != nil {
return nil, fmt.Errorf("invalid request for %s: %w", url, err)
}
// Set content-type
req.Header.Add("Content-Type", "application/octet-stream")
return req, nil
}

func fetchBeacon(method, url string, payload, dst any, timeout *time.Duration, headers http.Header, ssz bool) (code int, err error) {
func fetchBeacon(method, url string, payload []byte, dst any, timeout *time.Duration, headers http.Header, ssz bool) (code int, err error) {
var req *http.Request

if payload == nil {
req, err = http.NewRequest(method, url, nil)
} else {
if ssz {
req, err = makeSSZRequest(method, url, payload)
} else {
req, err = makeJSONRequest(method, url, payload)
}
req, err = http.NewRequest(method, url, bytes.NewReader(payload))
}

if err != nil {
return 0, fmt.Errorf("invalid request for %s: %w", url, err)
}

if ssz {
req.Header.Add("Content-Type", "application/octet-stream")
} else {
req.Header.Add("Content-Type", "application/json")
}

for k, v := range headers {
req.Header.Add(k, v[0])
}
req.Header.Set("accept", "application/json")

client := http.DefaultClient
if timeout != nil && timeout.Seconds() > 0 {
client = &http.Client{ //nolint:exhaustruct
Timeout: *timeout,
}
client := &http.Client{}
if timeout != nil && timeout.Milliseconds() > 0 {
client.Timeout = *timeout
}
resp, err := client.Do(req)
if err != nil {
Expand Down

0 comments on commit 59549f6

Please sign in to comment.