You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
6.1 KiB

  1. package client
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "net/http"
  9. "strings"
  10. kzgceremony "github.com/arnaucube/eth-kzg-ceremony-alt"
  11. )
  12. type Client struct {
  13. url string
  14. c *http.Client
  15. }
  16. func (c *Client) postWithAuth(url, contentType string, body io.Reader, bearer string) (resp *http.Response, err error) {
  17. req, err := http.NewRequest("POST", url, body)
  18. if err != nil {
  19. return nil, err
  20. }
  21. req.Header.Set("Content-Type", contentType)
  22. req.Header.Add("Authorization", bearer)
  23. return c.c.Do(req)
  24. }
  25. func NewClient(sequencerURL string) *Client {
  26. httpClient := &http.Client{}
  27. return &Client{
  28. url: sequencerURL,
  29. c: httpClient,
  30. }
  31. }
  32. func (c *Client) GetCurrentStatus() (*MsgStatus, error) {
  33. resp, err := c.c.Get(
  34. c.url + "/info/status")
  35. if err != nil {
  36. return nil, err
  37. }
  38. if resp.StatusCode != http.StatusOK {
  39. return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode)
  40. }
  41. body, err := ioutil.ReadAll(resp.Body)
  42. if err != nil {
  43. return nil, err
  44. }
  45. var msg MsgStatus
  46. err = json.Unmarshal(body, &msg)
  47. return &msg, err
  48. }
  49. func (c *Client) GetCurrentState() (*kzgceremony.State, error) {
  50. resp, err := c.c.Get(
  51. c.url + "/info/current_state")
  52. if err != nil {
  53. return nil, err
  54. }
  55. if resp.StatusCode != http.StatusOK {
  56. return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode)
  57. }
  58. body, err := ioutil.ReadAll(resp.Body)
  59. if err != nil {
  60. return nil, err
  61. }
  62. var state *kzgceremony.State
  63. err = json.Unmarshal(body, &state)
  64. return state, err
  65. }
  66. func (c *Client) GetRequestLink() (*MsgRequestLink, error) {
  67. resp, err := c.c.Get(
  68. c.url + "/auth/request_link")
  69. if err != nil {
  70. return nil, err
  71. }
  72. if resp.StatusCode != http.StatusOK {
  73. switch resp.StatusCode {
  74. case http.StatusBadRequest:
  75. return nil, fmt.Errorf("Invalid request. Missing parameters.")
  76. case http.StatusUnauthorized:
  77. return nil, fmt.Errorf("Eth address doesn't match message signer, or account nonce is too low")
  78. case http.StatusForbidden:
  79. return nil, fmt.Errorf("Invalid HTTP method")
  80. default:
  81. return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode)
  82. }
  83. }
  84. body, err := ioutil.ReadAll(resp.Body)
  85. if err != nil {
  86. return nil, err
  87. }
  88. var msg MsgRequestLink
  89. err = json.Unmarshal(body, &msg)
  90. return &msg, err
  91. }
  92. func (c *Client) PostAuthCallback() (*MsgRequestLink, error) {
  93. resp, err := c.c.Get(
  94. c.url + "/auth/request_link")
  95. if err != nil {
  96. return nil, err
  97. }
  98. if resp.StatusCode != http.StatusOK {
  99. switch resp.StatusCode {
  100. case http.StatusBadRequest:
  101. return nil, fmt.Errorf("Invalid request. Missing parameters.")
  102. case http.StatusUnauthorized:
  103. return nil, fmt.Errorf("Eth address doesn't match message signer, or account nonce is too low")
  104. case http.StatusForbidden:
  105. return nil, fmt.Errorf("Invalid HTTP method")
  106. default:
  107. return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode)
  108. }
  109. }
  110. body, err := ioutil.ReadAll(resp.Body)
  111. if err != nil {
  112. return nil, err
  113. }
  114. var msg MsgRequestLink
  115. err = json.Unmarshal(body, &msg)
  116. return &msg, err
  117. }
  118. type Status int
  119. const (
  120. StatusReauth = Status(iota)
  121. StatusError
  122. StatusWait
  123. StatusProceed
  124. )
  125. func (c *Client) PostTryContribute(sessionID string) (*kzgceremony.BatchContribution, Status, error) {
  126. bearer := "Bearer " + sessionID
  127. resp, err := c.postWithAuth(
  128. c.url+"/lobby/try_contribute", "application/json", nil, bearer)
  129. if err != nil {
  130. return nil, StatusError, err
  131. }
  132. body, err := ioutil.ReadAll(resp.Body)
  133. if err != nil {
  134. return nil, StatusError, err
  135. }
  136. if resp.StatusCode != http.StatusOK {
  137. switch resp.StatusCode {
  138. case http.StatusBadRequest:
  139. return nil, StatusWait, fmt.Errorf("call came to early. rate limited")
  140. case http.StatusUnauthorized:
  141. return nil, StatusReauth, fmt.Errorf("unkown session id. unauthorized access")
  142. default:
  143. return nil, StatusWait, fmt.Errorf("unexpected http code: %d", resp.StatusCode)
  144. }
  145. }
  146. // note: a 200 (Ok) code by the Sequencer on try_contribute doesn't
  147. // mean that the contributor has been selected. It could mean that the
  148. // Sequencer is returning the error AnotherContributionInProgress in a
  149. // json msg (see
  150. // https://github.com/ethereum/kzg-ceremony-sequencer/blob/2538f2f08d4db880d7f4608e964df0b695bc7d2f/src/api/v1/error_response.rs#L105
  151. // )
  152. // check if body contains the error message of "another contribution in
  153. // progress" (despite http statuscode being 200 (Ok))
  154. if strings.Contains(string(body), "another contribution in progress") {
  155. return nil, StatusWait, fmt.Errorf("another contribution in progress")
  156. }
  157. err = ioutil.WriteFile("prevBatchContribution.json", body, 0600)
  158. if err != nil {
  159. return nil, StatusError, err
  160. }
  161. bc := &kzgceremony.BatchContribution{}
  162. err = json.Unmarshal(body, bc)
  163. return bc, StatusProceed, err
  164. }
  165. func (c *Client) PostAbortContribution(sessionID string) ([]byte, error) {
  166. bearer := "Bearer " + sessionID
  167. resp, err := c.postWithAuth(
  168. c.url+"/contribution/abort", "application/json", nil, bearer)
  169. if err != nil {
  170. return nil, err
  171. }
  172. body, err := ioutil.ReadAll(resp.Body)
  173. if err != nil {
  174. return nil, err
  175. }
  176. fmt.Println("body", string(body))
  177. if resp.StatusCode != http.StatusOK {
  178. switch resp.StatusCode {
  179. case http.StatusBadRequest:
  180. return nil, fmt.Errorf("invalid request")
  181. case http.StatusUnauthorized:
  182. return nil, fmt.Errorf("unkown session id. unauthorized access")
  183. default:
  184. return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode)
  185. }
  186. }
  187. return body, nil
  188. }
  189. func (c *Client) PostContribute(sessionID string, bc *kzgceremony.BatchContribution) (*MsgContributeReceipt, error) {
  190. bearer := "Bearer " + sessionID
  191. jsonBC, err := json.Marshal(bc)
  192. if err != nil {
  193. return nil, err
  194. }
  195. resp, err := c.postWithAuth(
  196. c.url+"/contribute", "application/json", bytes.NewBuffer(jsonBC), bearer)
  197. if err != nil {
  198. return nil, err
  199. }
  200. if resp.StatusCode != http.StatusOK {
  201. switch resp.StatusCode {
  202. case http.StatusBadRequest:
  203. return nil, fmt.Errorf("invalid request")
  204. default:
  205. return nil, fmt.Errorf("unexpected http code: %d", resp.StatusCode)
  206. }
  207. }
  208. body, err := ioutil.ReadAll(resp.Body)
  209. if err != nil {
  210. return nil, err
  211. }
  212. var msg MsgContributeReceipt
  213. err = json.Unmarshal(body, &msg)
  214. return &msg, err
  215. }