-
Notifications
You must be signed in to change notification settings - Fork 41
feat: Cert encoding byte #370
base: main
Are you sure you want to change the base?
Conversation
- Remove commented out parseEncodingByte function - Remove commented out routingVarNameEncodingByteHex references - Fix and reenable test for unsupported version byte - Fix and reenable get_data_edge_cases test
…igenda-proxy into epociask--feat-encoding-byte
| } | ||
|
|
||
| // For V0/V1 certificates (backward compatibility) | ||
| return append([]byte{byte(c.prefix)}, c.b...) |
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.
Perhaps we should return an error if encoding is set, but the cert version doesn't support specifying an encoding? Otherwise this will just quietly ignore the specified user preference for a different encoding.
| ) | ||
|
|
||
| // EncodingType represents the serialization format for the certificate | ||
| type EncodingType byte |
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.
Rather than having two enums for encoding type (one with a string, and one with a byte), living in different locations, I think there should be a single enum type, with supporting methods to return either a byte or a string representation.
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.
the issue with having an imported definition in the standard client package is that proxy's core dependencies would also be imported which isn't possible given how we've provisioned the go workspace
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.
don't think that's true, see #376
| } | ||
|
|
||
| // handlePostOPGenericCommitment handles the POST request for optimism generic commitments. | ||
| func (svr *Server) handlePostOPGenericCommitment(w http.ResponseWriter, r *http.Request) error { |
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.
this method is identical to the standard commitment version, apart from the contained mode. I think a common utility method should be extracted, which accepts a mode input parameter
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.
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.
This comment wasn't addressed in this commit. handlePostOPGenericCommitment and handlePostStdCommitment are still identical, apart from CommitmentMeta.Mode, which could be passed in as a parameter
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.
wdym - any common logic here has been extracted into parseEncodingQueryParamType. Outside of this there's only redundancy or code overlap when setting a V2 cert commitment version
| } | ||
| switch versionByte[0] { | ||
| case byte(commitments.CertV0), byte(commitments.CertV1): | ||
| case byte(commitments.CertV0), byte(commitments.CertV1), byte(commitments.CertV2): |
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.
A switch is a bit of an awkward way to accomplish this, particularly as more cert types are added.
Consider creating a new method isValidCertVersion. Or alternatively, perhaps a method byteToCertVersion, which includes an error return value, would be useful here and elsewhere.
| // this is done to verify that a rollup must be able to provide | ||
| // the same certificate used in dispersal for retrieval | ||
| func (e *MemStore) Put(_ context.Context, value []byte) ([]byte, error) { | ||
| func (e *MemStore) Put(ctx context.Context, value []byte) ([]byte, error) { |
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.
I'm not a fan of how context injection is being used for this PR.
IMO we should bite the bullet and just modify the interface methods to accept an encoding parameter. It's a more fundamental change, but the current strategy doesn't seem very maintainable to me.
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.
would prefer that this be a follow up change or live as a separate PR given the large code overhead required
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.
Let's continue this conversation on this thread, since they are getting at the same thing
samlaf
left a comment
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.
Approach LGTM. Left a bunch of nits on the specifics
|
|
||
| For certificates with version byte 0x00 or 0x01, no encoding byte is included and RLP encoding is assumed. For version 0x02 and higher, an encoding byte is included that specifies the serialization format: | ||
| - 0x00: RLP encoding (default) | ||
| * `0x01`: `EigenDACertVerifier` *verifyDACertV2* ABI encoding (for smart contract verification) |
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.
do we want to wait until we've done the struct refactoring for verifyDACertV2? Then we can just say that its the ABI encoding of the solidity cert struct, which feels more natural than pointing to a function's arguments.
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.
yes! and fully agree
clients/standard_client/client.go
Outdated
| ) | ||
|
|
||
| // EncodingType represents the serialization format for the certificate | ||
| type EncodingType string |
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 CertEncoding or CertSerialization instead?
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.
Also not a fan of defining fundamental types in the client. Could we define these in some proxy package and import it in the client instead?
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.
how would you do that in a way that doesn't introduce proxy's dependency graph to the client?
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.
You import a package that doesn't have many transitive dependencies. For example I tried adding a main.go in clients that only imports common/consts:
package clients
import (
"fmt"
"github.com/Layr-Labs/eigenda-proxy/common/consts"
)
func main() {
fmt.Println(consts.EthHappyPathFinalizationDepthBlocks)
}
I don't fully understand it but I think golang does lazy module loading, and only based on PACKAGES that a build requires. The difference between package and module is important here. See https://go.dev/ref/mod#go-mod-file-go:
The go.mod file includes an explicit require directive for each module that provides any package transitively imported by a package or test in the main module.
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.
gotcha but wouldn't there by be a cyclic issue here? https://github.com/Layr-Labs/eigenda-proxy/blob/main/go.mod#L30-L31
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.
server module only imports clients for testing right? I think that's allowed...
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.
see #376 for an example
| type Config struct { | ||
| URL string // EigenDA proxy REST API URL | ||
| URL string // EigenDA proxy REST API URL | ||
| EncodingType EncodingType // Certificate encoding type (optional) |
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.
if optional, then describe what the zero (empty string) value defaults to
| m.log.Warn("Failed to read from cache targets", "err", err) | ||
| } | ||
|
|
||
| ctx = context.WithValue(ctx, common.EncodingCtxKey, cm.Encoding) |
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.
why use context key/value dict everywhere instead of passing as a proper (typed!) argument?
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.
this is a workaround to conform with existing interface constraints
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.
Why do we need to conform to existing interfaces?
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.
The current context-based solution is orthogonal to the correct parameter-based solution, IMO.
I don't think we should introduce the tech debt of context based parameters for the sake of maintaining these internal interfaces.
| subrouterGET.HandleFunc("/"+ | ||
| "{optional_prefix:(?:0x)?}"+ // commitments can be prefixed with 0x | ||
| "{"+routingVarNameVersionByteHex+":[0-9a-fA-F]{2}}"+ // should always be 0x00 for now but we let others through to return a 404 | ||
| "{"+routingVarNameVersionByteHex+":[0-9a-fA-F]{2}}"+ |
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.
shouldn't we add the encodingByte regexp here as well?
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.
how would you add that regex where you wouldn't also be unnecessarily truncating commitment bytes from an older version commitment that doesn't have the encoding prefix?
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.
Oh fuck right... now we're stuck with some context-dependent encoding. :(
Maybe one way is to have 2 separate routes? Something like:
// Route for version bytes that require encoding byte
router.HandleFunc("/"+
"{optional_prefix:(?:0x)?}"+
"{version:[0-9a-fA-F]{2}}"+
"{encoding:[0-9a-fA-F]{2}}"+ // Only for versions that need encoding
"{commitment:[0-9a-fA-F]+}",
handler).Methods("GET")
// Route for version bytes that don't require encoding byte
router.HandleFunc("/"+
"{optional_prefix:(?:0x)?}"+
"{version:[0-9a-fA-F]{2}}"+ // For older versions
"{commitment:[0-9a-fA-F]+}",
handler).Methods("GET")
Idk if this is any simpler overall, but I really don't like having implicit header parsing inside the handlers. If we do go this route though please add a comment in the router regexps explaining that we will further parse the routingVarNamePayloadHex to extract the encoding byte when versionByte >= 2 inside the handler.
server/handlers.go
Outdated
| return fmt.Errorf("failed to decode commitment %s: %w", rawCommitmentHex, err) | ||
| } | ||
|
|
||
| if versionByte >= byte(commitments.CertV2) { |
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.
wondering why >= instead of of just == ?
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.
He;s just saying that every future cert version is required to use the encoding byte. We should have enforced the encoding byte header from the start for everything, but now we're stuck with cert versions v0 and v1 not using an encoding byte.
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.
I see. I guess when there is V3, we'll coalesce the common functions.
…igenda-proxy into epociask--feat-encoding-byte
| prefix EigenDACommitmentType | ||
| b []byte | ||
| encoding *EncodingType // Optional encoding type, used only for V2+ | ||
| encoding EncodingType // Optional encoding type, used only for V2+ |
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.
| encoding EncodingType // Optional encoding type, used only for V2+ | |
| encoding EncodingType // encoding type, used only for V2+ |
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.
not optional anymore right?
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.
also is it really only used for v2? doesnt ssem for v2 only in meta struct
// encoding type for the certificate (defaults to RLPEncoding)
Encoding EncodingType
|
|
||
| // if encoding param provided but historical V1 backend used then error | ||
| if svr.sm.GetDispersalBackend() == common.V1EigenDABackend { | ||
| http.Error(w, "Encoding type query parameter cannot be specified for V1 backend", http.StatusBadRequest) |
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.
dont you need to return here?
| } | ||
|
|
||
| // handleGetEigenDA helper function used for processing gets for an eigenda backend type | ||
| func (svr *Server) handleGetEigenDA(w http.ResponseWriter, r *http.Request, |
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.
dont think this should be called handle because its not a routing table entrypoint
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.
or maybe prefix name with a _?
This is just an example for Ethen regarding discussions in his PR #370
chore: type alias proxy encoding enum in client This is just an example for Ethen regarding discussions in his PR #370
Fixes Issue
Fixes #363
Changes proposed
CertV2format that includes an encoding byte in DA commitmentScreenshots (Optional)
Note to reviewers