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.

296 lines
8.5 KiB

  1. package apitypes
  2. import (
  3. "database/sql/driver"
  4. "encoding/base64"
  5. "encoding/hex"
  6. "encoding/json"
  7. "errors"
  8. "fmt"
  9. "math/big"
  10. "strconv"
  11. "strings"
  12. ethCommon "github.com/ethereum/go-ethereum/common"
  13. "github.com/hermeznetwork/hermez-node/common"
  14. "github.com/iden3/go-iden3-crypto/babyjub"
  15. )
  16. // BigIntStr is used to scan/value *big.Int directly into strings from/to sql DBs.
  17. // It assumes that *big.Int are inserted/fetched to/from the DB using the BigIntMeddler meddler
  18. // defined at github.com/hermeznetwork/hermez-node/db
  19. type BigIntStr string
  20. // NewBigIntStr creates a *BigIntStr from a *big.Int.
  21. // If the provided bigInt is nil the returned *BigIntStr will also be nil
  22. func NewBigIntStr(bigInt *big.Int) *BigIntStr {
  23. if bigInt == nil {
  24. return nil
  25. }
  26. bigIntStr := BigIntStr(bigInt.String())
  27. return &bigIntStr
  28. }
  29. // Scan implements Scanner for database/sql
  30. func (b *BigIntStr) Scan(src interface{}) error {
  31. srcBytes, ok := src.([]byte)
  32. if !ok {
  33. return fmt.Errorf("can't scan %T into apitypes.BigIntStr", src)
  34. }
  35. // bytes to *big.Int
  36. bigInt := new(big.Int).SetBytes(srcBytes)
  37. // *big.Int to BigIntStr
  38. bigIntStr := NewBigIntStr(bigInt)
  39. if bigIntStr == nil {
  40. return nil
  41. }
  42. *b = *bigIntStr
  43. return nil
  44. }
  45. // Value implements valuer for database/sql
  46. func (b BigIntStr) Value() (driver.Value, error) {
  47. // string to *big.Int
  48. bigInt, ok := new(big.Int).SetString(string(b), 10)
  49. if !ok || bigInt == nil {
  50. return nil, errors.New("invalid representation of a *big.Int")
  51. }
  52. // *big.Int to bytes
  53. return bigInt.Bytes(), nil
  54. }
  55. // StrBigInt is used to unmarshal BigIntStr directly into an alias of big.Int
  56. type StrBigInt big.Int
  57. // UnmarshalText unmarshals a StrBigInt
  58. func (s *StrBigInt) UnmarshalText(text []byte) error {
  59. bi, ok := (*big.Int)(s).SetString(string(text), 10)
  60. if !ok {
  61. return fmt.Errorf("could not unmarshal %s into a StrBigInt", text)
  62. }
  63. *s = StrBigInt(*bi)
  64. return nil
  65. }
  66. // CollectedFees is used to retrieve common.batch.CollectedFee from the DB
  67. type CollectedFees map[common.TokenID]BigIntStr
  68. // UnmarshalJSON unmarshals a json representation of map[common.TokenID]*big.Int
  69. func (c *CollectedFees) UnmarshalJSON(text []byte) error {
  70. bigIntMap := make(map[common.TokenID]*big.Int)
  71. if err := json.Unmarshal(text, &bigIntMap); err != nil {
  72. return err
  73. }
  74. *c = CollectedFees(make(map[common.TokenID]BigIntStr))
  75. for k, v := range bigIntMap {
  76. bStr := NewBigIntStr(v)
  77. (CollectedFees(*c)[k]) = *bStr
  78. }
  79. // *c = CollectedFees(bStrMap)
  80. return nil
  81. }
  82. // HezEthAddr is used to scan/value Ethereum Address directly into strings that follow the Ethereum address hez fotmat (^hez:0x[a-fA-F0-9]{40}$) from/to sql DBs.
  83. // It assumes that Ethereum Address are inserted/fetched to/from the DB using the default Scan/Value interface
  84. type HezEthAddr string
  85. // NewHezEthAddr creates a HezEthAddr from an Ethereum addr
  86. func NewHezEthAddr(addr ethCommon.Address) HezEthAddr {
  87. return HezEthAddr("hez:" + addr.String())
  88. }
  89. // ToEthAddr returns an Ethereum Address created from HezEthAddr
  90. func (a HezEthAddr) ToEthAddr() (ethCommon.Address, error) {
  91. addrStr := strings.TrimPrefix(string(a), "hez:")
  92. var addr ethCommon.Address
  93. return addr, addr.UnmarshalText([]byte(addrStr))
  94. }
  95. // Scan implements Scanner for database/sql
  96. func (a *HezEthAddr) Scan(src interface{}) error {
  97. ethAddr := &ethCommon.Address{}
  98. if err := ethAddr.Scan(src); err != nil {
  99. return err
  100. }
  101. if ethAddr == nil {
  102. return nil
  103. }
  104. *a = NewHezEthAddr(*ethAddr)
  105. return nil
  106. }
  107. // Value implements valuer for database/sql
  108. func (a HezEthAddr) Value() (driver.Value, error) {
  109. ethAddr, err := a.ToEthAddr()
  110. if err != nil {
  111. return nil, err
  112. }
  113. return ethAddr.Value()
  114. }
  115. // StrHezEthAddr is used to unmarshal HezEthAddr directly into an alias of ethCommon.Address
  116. type StrHezEthAddr ethCommon.Address
  117. // UnmarshalText unmarshals a StrHezEthAddr
  118. func (s *StrHezEthAddr) UnmarshalText(text []byte) error {
  119. withoutHez := strings.TrimPrefix(string(text), "hez:")
  120. var addr ethCommon.Address
  121. if err := addr.UnmarshalText([]byte(withoutHez)); err != nil {
  122. return err
  123. }
  124. *s = StrHezEthAddr(addr)
  125. return nil
  126. }
  127. // HezBJJ is used to scan/value *babyjub.PublicKey directly into strings that follow the BJJ public key hez fotmat (^hez:[A-Za-z0-9_-]{44}$) from/to sql DBs.
  128. // It assumes that *babyjub.PublicKey are inserted/fetched to/from the DB using the default Scan/Value interface
  129. type HezBJJ string
  130. // NewHezBJJ creates a HezBJJ from a *babyjub.PublicKey.
  131. // Calling this method with a nil bjj causes panic
  132. func NewHezBJJ(bjj *babyjub.PublicKey) HezBJJ {
  133. pkComp := [32]byte(bjj.Compress())
  134. sum := pkComp[0]
  135. for i := 1; i < len(pkComp); i++ {
  136. sum += pkComp[i]
  137. }
  138. bjjSum := append(pkComp[:], sum)
  139. return HezBJJ("hez:" + base64.RawURLEncoding.EncodeToString(bjjSum))
  140. }
  141. func hezStrToBJJ(s string) (*babyjub.PublicKey, error) {
  142. const decodedLen = 33
  143. const encodedLen = 44
  144. formatErr := errors.New("invalid BJJ format. Must follow this regex: ^hez:[A-Za-z0-9_-]{44}$")
  145. encoded := strings.TrimPrefix(s, "hez:")
  146. if len(encoded) != encodedLen {
  147. return nil, formatErr
  148. }
  149. decoded, err := base64.RawURLEncoding.DecodeString(encoded)
  150. if err != nil {
  151. return nil, formatErr
  152. }
  153. if len(decoded) != decodedLen {
  154. return nil, formatErr
  155. }
  156. bjjBytes := [decodedLen - 1]byte{}
  157. copy(bjjBytes[:decodedLen-1], decoded[:decodedLen-1])
  158. sum := bjjBytes[0]
  159. for i := 1; i < len(bjjBytes); i++ {
  160. sum += bjjBytes[i]
  161. }
  162. if decoded[decodedLen-1] != sum {
  163. return nil, errors.New("checksum verification failed")
  164. }
  165. bjjComp := babyjub.PublicKeyComp(bjjBytes)
  166. return bjjComp.Decompress()
  167. }
  168. // ToBJJ returns a *babyjub.PublicKey created from HezBJJ
  169. func (b HezBJJ) ToBJJ() (*babyjub.PublicKey, error) {
  170. return hezStrToBJJ(string(b))
  171. }
  172. // Scan implements Scanner for database/sql
  173. func (b *HezBJJ) Scan(src interface{}) error {
  174. bjj := &babyjub.PublicKey{}
  175. if err := bjj.Scan(src); err != nil {
  176. return err
  177. }
  178. if bjj == nil {
  179. return nil
  180. }
  181. *b = NewHezBJJ(bjj)
  182. return nil
  183. }
  184. // Value implements valuer for database/sql
  185. func (b HezBJJ) Value() (driver.Value, error) {
  186. bjj, err := b.ToBJJ()
  187. if err != nil {
  188. return nil, err
  189. }
  190. return bjj.Value()
  191. }
  192. // StrHezBJJ is used to unmarshal HezBJJ directly into an alias of babyjub.PublicKey
  193. type StrHezBJJ babyjub.PublicKey
  194. // UnmarshalText unmarshals a StrHezBJJ
  195. func (s *StrHezBJJ) UnmarshalText(text []byte) error {
  196. bjj, err := hezStrToBJJ(string(text))
  197. if err != nil {
  198. return err
  199. }
  200. *s = StrHezBJJ(*bjj)
  201. return nil
  202. }
  203. // HezIdx is used to value common.Idx directly into strings that follow the Idx key hez fotmat (hez:tokenSymbol:idx) to sql DBs.
  204. // Note that this can only be used to insert to DB since there is no way to automaticaly read from the DB since it needs the tokenSymbol
  205. type HezIdx string
  206. // StrHezIdx is used to unmarshal HezIdx directly into an alias of common.Idx
  207. type StrHezIdx common.Idx
  208. // UnmarshalText unmarshals a StrHezIdx
  209. func (s *StrHezIdx) UnmarshalText(text []byte) error {
  210. withoutHez := strings.TrimPrefix(string(text), "hez:")
  211. splitted := strings.Split(withoutHez, ":")
  212. const expectedLen = 2
  213. if len(splitted) != expectedLen {
  214. return fmt.Errorf("can not unmarshal %s into StrHezIdx", text)
  215. }
  216. idxInt, err := strconv.Atoi(splitted[1])
  217. if err != nil {
  218. return err
  219. }
  220. *s = StrHezIdx(common.Idx(idxInt))
  221. return nil
  222. }
  223. // EthSignature is used to scan/value []byte representing an Ethereum signature directly into strings from/to sql DBs.
  224. type EthSignature string
  225. // NewEthSignature creates a *EthSignature from []byte
  226. // If the provided signature is nil the returned *EthSignature will also be nil
  227. func NewEthSignature(signature []byte) *EthSignature {
  228. if signature == nil {
  229. return nil
  230. }
  231. ethSignature := EthSignature("0x" + hex.EncodeToString(signature))
  232. return &ethSignature
  233. }
  234. // Scan implements Scanner for database/sql
  235. func (e *EthSignature) Scan(src interface{}) error {
  236. if srcStr, ok := src.(string); ok {
  237. // src is a string
  238. *e = *(NewEthSignature([]byte(srcStr)))
  239. return nil
  240. } else if srcBytes, ok := src.([]byte); ok {
  241. // src is []byte
  242. *e = *(NewEthSignature(srcBytes))
  243. return nil
  244. } else {
  245. // unexpected src
  246. return fmt.Errorf("can't scan %T into apitypes.EthSignature", src)
  247. }
  248. }
  249. // Value implements valuer for database/sql
  250. func (e EthSignature) Value() (driver.Value, error) {
  251. without0x := strings.TrimPrefix(string(e), "0x")
  252. return hex.DecodeString(without0x)
  253. }
  254. // UnmarshalText unmarshals a StrEthSignature
  255. func (e *EthSignature) UnmarshalText(text []byte) error {
  256. without0x := strings.TrimPrefix(string(text), "0x")
  257. signature, err := hex.DecodeString(without0x)
  258. if err != nil {
  259. return err
  260. }
  261. *e = EthSignature([]byte(signature))
  262. return nil
  263. }