package client import ( "bytes" "encoding/json" "fmt" "io" "io/ioutil" "net/http" "strings" kzgceremony "github.com/arnaucube/eth-kzg-ceremony-alt" ) 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 } type Status int const ( StatusReauth = Status(iota) StatusError StatusWait StatusProceed ) func (c *Client) PostTryContribute(sessionID string) (*kzgceremony.BatchContribution, Status, error) { bearer := "Bearer " + sessionID resp, err := c.postWithAuth( c.url+"/lobby/try_contribute", "application/json", nil, bearer) if err != nil { return nil, StatusError, err } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, StatusError, err } if resp.StatusCode != http.StatusOK { switch resp.StatusCode { case http.StatusBadRequest: return nil, StatusWait, fmt.Errorf("call came to early. rate limited") case http.StatusUnauthorized: return nil, StatusReauth, fmt.Errorf("unkown session id. unauthorized access") default: return nil, StatusWait, fmt.Errorf("unexpected http code: %d", resp.StatusCode) } } // note: a 200 (Ok) code by the Sequencer on try_contribute doesn't // mean that the contributor has been selected. It could mean that the // Sequencer is returning the error AnotherContributionInProgress in a // json msg (see // https://github.com/ethereum/kzg-ceremony-sequencer/blob/2538f2f08d4db880d7f4608e964df0b695bc7d2f/src/api/v1/error_response.rs#L105 // ) // check if body contains the error message of "another contribution in // progress" (despite http statuscode being 200 (Ok)) if strings.Contains(string(body), "another contribution in progress") { return nil, StatusWait, fmt.Errorf("another contribution in progress") } err = ioutil.WriteFile("prevBatchContribution.json", body, 0600) if err != nil { return nil, StatusError, err } bc := &kzgceremony.BatchContribution{} err = json.Unmarshal(body, bc) return bc, StatusProceed, 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 }