-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Derive the default builder auth_data from the URL hostname
#17511
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| ### Changed | ||
|
|
||
| - Derive the default builder `auth_data` from the builder URL's hostname instead of the full URL bytes, per builder-specs#168. | ||
| - Reject builder URLs without a hostname (`https://:8080`) or with a non-ASCII one. Internationalized hostnames must be punycode-encoded. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,14 @@ | ||
| package proposer | ||
|
|
||
| import ( | ||
| "encoding/binary" | ||
| "fmt" | ||
| "net/netip" | ||
| "net/url" | ||
| "slices" | ||
| "strings" | ||
| "sync/atomic" | ||
| "unicode" | ||
|
|
||
| "github.com/OffchainLabs/prysm/v7/config" | ||
| fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams" | ||
|
|
@@ -145,13 +148,42 @@ type BuilderEntry struct { | |
| BuilderBoostFactor *validator.Uint64 `json:"builder_boost_factor,omitempty" yaml:"builder_boost_factor,omitempty"` | ||
| } | ||
|
|
||
| // EffectiveAuthData resolves omitted auth_data to the spec convention: | ||
| // the UTF-8 bytes of the builder's URL. | ||
| // EffectiveAuthData resolves omitted auth_data to the spec default. | ||
| func (be *BuilderEntry) EffectiveAuthData() []byte { | ||
| if len(be.AuthData) != 0 { | ||
| return be.AuthData | ||
| } | ||
| return []byte(be.URL) | ||
| u, err := url.Parse(be.URL) | ||
| if err != nil { | ||
| return nil | ||
| } | ||
| host := strings.ToLower(u.Hostname()) | ||
| addr, err := netip.ParseAddr(host) | ||
| if err != nil || addr.Is4() { | ||
| // a name or an IPv4 literal is used as-is | ||
| return []byte(host) | ||
| } | ||
| if addr.Is4In6() { | ||
| // IPv4-mapped IPv6 address. Hand-wired here to match with the spec. | ||
| // Go's netip renders these in mixed notation (::ffff:192.0.2.1) | ||
| // while spec wants ::ffff:c000:201 (hex groups only). | ||
| // | ||
| // Their 16 bytes are always shaped like this: | ||
| // | ||
| // bytes 0 .. 9 10, 11 12, 13 14, 15 | ||
| // 00 x 10 ff ff |<-- IPv4 4 bytes -->| | ||
| // groups g1..g5=0 g6=ffff g7 g8 | ||
| // | ||
| // so 192.0.2.1 (c0 00 02 01) gives g7=0xc000, g8=0x0201 -> "::ffff:c000:201". | ||
| b := addr.As16() | ||
| return fmt.Appendf( | ||
| nil, | ||
| "[::ffff:%x:%x]", | ||
| binary.BigEndian.Uint16(b[12:14]), // g7 | ||
| binary.BigEndian.Uint16(b[14:16]), // g8 | ||
| ) | ||
| } | ||
| return []byte("[" + addr.String() + "]") | ||
| } | ||
|
|
||
| // Spec limits for builder configuration payloads. | ||
|
|
@@ -171,9 +203,21 @@ func (be *BuilderEntry) Validate() error { | |
| if len(be.URL) > MaxBuilderURLSize { | ||
| return errors.Errorf("url exceeds %d bytes", MaxBuilderURLSize) | ||
| } | ||
| if u, err := url.Parse(be.URL); err != nil || u.Scheme == "" || u.Host == "" { | ||
| u, err := url.Parse(be.URL) | ||
| if err != nil || u.Scheme == "" || u.Host == "" { | ||
| return errors.New("url is not a valid URL") | ||
| } | ||
|
|
||
| // Check whether hostname is empty. | ||
| host := u.Hostname() | ||
| if host == "" { | ||
| return errors.New("url is missing a hostname") | ||
| } | ||
|
|
||
| // Check punycode: host must be ASCII. | ||
| if strings.IndexFunc(host, func(r rune) bool { return r > unicode.MaxASCII }) >= 0 { | ||
| return errors.New("url hostname must be ASCII; encode internationalized names as punycode") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should it include the url?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm logging the reasons for this validation is the only consumer of this error message, and I think we should consider to redact the log when we include URL. So I believe we don't need it right now. |
||
| } | ||
| if len(be.Pubkeys) > MaxBuilderPubkeys { | ||
| return errors.Errorf("builder_pubkeys exceeds %d keys", MaxBuilderPubkeys) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be some kind of helper?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe not, I'm not sure whether we will use this logic in other places.