Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add flag to publish block with ssz #598

Merged
merged 11 commits into from
Apr 11, 2024
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
Loading