From a7e09d0358df4f568b99937d1a4820136a39911a Mon Sep 17 00:00:00 2001 From: arnaucube Date: Fri, 9 Dec 2022 22:24:56 +0100 Subject: [PATCH] Add client to interact with Sequencer --- .gitignore | 3 + README.md | 2 +- client/msg.go | 45 ++++++++++ client/req.go | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 4 + go.sum | 14 ++++ 6 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 client/msg.go create mode 100644 client/req.go diff --git a/.gitignore b/.gitignore index 1ab4f55..4006346 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ parsed_state.json new_state.json +cmd/prevBatchContribution.json +cmd/contribution.json +cmd/contribution_receipt.json diff --git a/README.md b/README.md index 58aa4d4..4467051 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Ethereum will run the Ceremony which will be used at least in [EIP-4844](https:/ Probably most of the contributions will be generated with the same code (official impl, which has been audited). The idea of this repo is to try to bring more diversity to the table with another independent implementation. -This implementation has been done without looking at the other impls code (neither the python reference nor the rust impl (except for the points parsers test vectors)), in order to not be biased by that code. +This implementation has been done without looking at the other impls code (except for the point parsers test vectors), in order to not be biased by that code. > This code has not been audited, use it at your own risk. diff --git a/client/msg.go b/client/msg.go new file mode 100644 index 0000000..fbaa324 --- /dev/null +++ b/client/msg.go @@ -0,0 +1,45 @@ +package client + +import "fmt" + +type errorMsg struct { + Message string `json:"message"` +} + +type MsgStatus struct { + LobbySize uint64 `json:"lobby_size"` + NumContributions uint64 `json:"num_contributions"` + SequencerAddress string `json:"sequencer_address"` +} + +func (m *MsgStatus) String() string { + return fmt.Sprintf("Sequencer status:\n Lobby size: %d\n NumContributions: %d\n SequencerAddress: %s\n", + m.LobbySize, m.NumContributions, m.SequencerAddress) +} + +type MsgRequestLink struct { + EthAuthURL string `json:"eth_auth_url"` + GithubAuthURL string `json:"github_auth_url"` +} + +type IDToken struct { + Exp uint64 `json:"exp"` + Nickname string `json:"nickname"` + Provider string `json:"provider"` + Sub string `json:"sub"` +} + +type MsgAuthCallback struct { + IDToken IDToken `json:"id_token"` + SessionID string `json:"session_id"` +} + +type MsgContributeReceipt struct { + Receipt string `json:"receipt"` + Signature string `json:"signature"` +} + +func (m MsgContributeReceipt) String() string { + return fmt.Sprintf("Contribute Receipt:\n Receipt: %s\n Signature: %s\n", + m.Receipt, m.Signature) +} diff --git a/client/req.go b/client/req.go new file mode 100644 index 0000000..18f862e --- /dev/null +++ b/client/req.go @@ -0,0 +1,225 @@ +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "kzgceremony" + "net/http" +) + +type Client struct { + url string + c *http.Client +} + +func (c *Client) postWithAuth(url, contentType string, body io.Reader, bearer string) (resp *http.Response, err error) { + req, err := http.NewRequest("POST", url, body) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", contentType) + req.Header.Add("Authorization", bearer) + return c.c.Do(req) +} + +func NewClient(sequencerURL string) *Client { + httpClient := &http.Client{} + return &Client{ + url: sequencerURL, + c: httpClient, + } +} + +func (c *Client) GetCurrentStatus() (*MsgStatus, error) { + resp, err := c.c.Get( + c.url + "/info/status") + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var msg MsgStatus + err = json.Unmarshal(body, &msg) + return &msg, err +} + +func (c *Client) GetCurrentState() (*kzgceremony.State, error) { + resp, err := c.c.Get( + c.url + "/info/current_state") + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var state *kzgceremony.State + err = json.Unmarshal(body, &state) + return state, err +} + +func (c *Client) GetRequestLink() (*MsgRequestLink, error) { + resp, err := c.c.Get( + c.url + "/auth/request_link") + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + switch resp.StatusCode { + case http.StatusBadRequest: + return nil, fmt.Errorf("Invalid request. Missing parameters.") + case http.StatusUnauthorized: + return nil, fmt.Errorf("Eth address doesn't match message signer, or account nonce is too low") + case http.StatusForbidden: + return nil, fmt.Errorf("Invalid HTTP method") + default: + return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode) + } + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var msg MsgRequestLink + err = json.Unmarshal(body, &msg) + return &msg, err +} + +func (c *Client) PostAuthCallback() (*MsgRequestLink, error) { + resp, err := c.c.Get( + c.url + "/auth/request_link") + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + switch resp.StatusCode { + case http.StatusBadRequest: + return nil, fmt.Errorf("Invalid request. Missing parameters.") + case http.StatusUnauthorized: + return nil, fmt.Errorf("Eth address doesn't match message signer, or account nonce is too low") + case http.StatusForbidden: + return nil, fmt.Errorf("Invalid HTTP method") + default: + return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode) + } + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var msg MsgRequestLink + err = json.Unmarshal(body, &msg) + return &msg, err +} + +func (c *Client) PostTryContribute(sessionID string) (*kzgceremony.BatchContribution, bool, error) { + bearer := "Bearer " + sessionID + resp, err := c.postWithAuth( + c.url+"/lobby/try_contribute", "application/json", nil, bearer) + if err != nil { + return nil, false, err + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, false, err + } + + if resp.StatusCode != http.StatusOK { + fmt.Println(string(body)) + switch resp.StatusCode { + case http.StatusBadRequest: + return nil, true, fmt.Errorf("call came to early. rate limited") + case http.StatusUnauthorized: + return nil, false, fmt.Errorf("unkown session id. unauthorized access") + default: + return nil, false, fmt.Errorf("unexpected http code: %d", resp.StatusCode) + } + } + + err = ioutil.WriteFile("prevBatchContribution.json", body, 0600) + if err != nil { + return nil, false, err + } + bc := &kzgceremony.BatchContribution{} + err = json.Unmarshal(body, bc) + return bc, false, err +} + +func (c *Client) PostAbortContribution(sessionID string) ([]byte, error) { + bearer := "Bearer " + sessionID + resp, err := c.postWithAuth( + c.url+"/contribution/abort", "application/json", nil, bearer) + if err != nil { + return nil, err + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + fmt.Println("body", string(body)) + + if resp.StatusCode != http.StatusOK { + switch resp.StatusCode { + case http.StatusBadRequest: + return nil, fmt.Errorf("invalid request") + case http.StatusUnauthorized: + return nil, fmt.Errorf("unkown session id. unauthorized access") + default: + return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode) + } + } + + return body, nil +} + +func (c *Client) PostContribute(sessionID string, bc *kzgceremony.BatchContribution) (*MsgContributeReceipt, error) { + bearer := "Bearer " + sessionID + + jsonBC, err := json.Marshal(bc) + if err != nil { + return nil, err + } + + resp, err := c.postWithAuth( + c.url+"/contribute", "application/json", bytes.NewBuffer(jsonBC), bearer) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + switch resp.StatusCode { + case http.StatusBadRequest: + return nil, fmt.Errorf("invalid request") + default: + return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode) + } + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var msg MsgContributeReceipt + err = json.Unmarshal(body, &msg) + return &msg, err +} diff --git a/go.mod b/go.mod index b442c5b..6b226d1 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,18 @@ module kzgceremony go 1.19 require ( + github.com/fatih/color v1.13.0 github.com/frankban/quicktest v1.14.4 github.com/kilic/bls12-381 v0.1.0 + github.com/spf13/pflag v1.0.5 ) require ( github.com/google/go-cmp v0.5.9 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect ) diff --git a/go.sum b/go.sum index 7bfef31..1d77765 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= @@ -9,9 +11,21 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=