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.

179 lines
6.1 KiB

  1. package statedb
  2. import (
  3. "bytes"
  4. "fmt"
  5. "math/big"
  6. ethCommon "github.com/ethereum/go-ethereum/common"
  7. "github.com/hermeznetwork/hermez-node/common"
  8. "github.com/hermeznetwork/hermez-node/log"
  9. "github.com/hermeznetwork/tracerr"
  10. "github.com/iden3/go-iden3-crypto/babyjub"
  11. "github.com/iden3/go-merkletree"
  12. )
  13. func concatEthAddrTokenID(addr ethCommon.Address, tokenID common.TokenID) []byte {
  14. var b []byte
  15. b = append(b, addr.Bytes()...)
  16. b = append(b[:], tokenID.Bytes()[:]...)
  17. return b
  18. }
  19. func concatEthAddrBJJTokenID(addr ethCommon.Address, pk *babyjub.PublicKey, tokenID common.TokenID) []byte {
  20. pkComp := pk.Compress()
  21. var b []byte
  22. b = append(b, addr.Bytes()...)
  23. b = append(b[:], pkComp[:]...)
  24. b = append(b[:], tokenID.Bytes()[:]...)
  25. return b
  26. }
  27. // setIdxByEthAddrBJJ stores the given Idx in the StateDB as follows:
  28. // - key: Eth Address, value: idx
  29. // - key: EthAddr & BabyJubJub PublicKey Compressed, value: idx
  30. // If Idx already exist for the given EthAddr & BJJ, the remaining Idx will be
  31. // always the smallest one.
  32. func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr ethCommon.Address, pk *babyjub.PublicKey, tokenID common.TokenID) error {
  33. oldIdx, err := s.GetIdxByEthAddrBJJ(addr, pk, tokenID)
  34. if err == nil {
  35. // EthAddr & BJJ already have an Idx
  36. // check which Idx is smaller
  37. // if new idx is smaller, store the new one
  38. // if new idx is bigger, don't store and return, as the used one will be the old
  39. if idx >= oldIdx {
  40. log.Debug("StateDB.setIdxByEthAddrBJJ: Idx not stored because there already exist a smaller Idx for the given EthAddr & BJJ")
  41. return nil
  42. }
  43. }
  44. if pk == nil {
  45. return tracerr.Wrap(fmt.Errorf("BabyJubJub pk not defined"))
  46. }
  47. // store idx for EthAddr & BJJ assuming that EthAddr & BJJ still don't
  48. // have an Idx stored in the DB, and if so, the already stored Idx is
  49. // bigger than the given one, so should be updated to the new one
  50. // (smaller)
  51. tx, err := s.db.NewTx()
  52. if err != nil {
  53. return tracerr.Wrap(err)
  54. }
  55. idxBytes, err := idx.Bytes()
  56. if err != nil {
  57. return tracerr.Wrap(err)
  58. }
  59. // store Addr&BJJ-idx
  60. k := concatEthAddrBJJTokenID(addr, pk, tokenID)
  61. err = tx.Put(append(PrefixKeyAddrBJJ, k...), idxBytes[:])
  62. if err != nil {
  63. return tracerr.Wrap(err)
  64. }
  65. // store Addr-idx
  66. k = concatEthAddrTokenID(addr, tokenID)
  67. err = tx.Put(append(PrefixKeyAddr, k...), idxBytes[:])
  68. if err != nil {
  69. return tracerr.Wrap(err)
  70. }
  71. err = tx.Commit()
  72. if err != nil {
  73. return tracerr.Wrap(err)
  74. }
  75. return nil
  76. }
  77. // GetIdxByEthAddr returns the smallest Idx in the StateDB for the given
  78. // Ethereum Address. Will return common.Idx(0) and error in case that Idx is
  79. // not found in the StateDB.
  80. func (s *StateDB) GetIdxByEthAddr(addr ethCommon.Address, tokenID common.TokenID) (common.Idx, error) {
  81. k := concatEthAddrTokenID(addr, tokenID)
  82. b, err := s.db.Get(append(PrefixKeyAddr, k...))
  83. if err != nil {
  84. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddr: %s: ToEthAddr: %s, TokenID: %d", ErrToIdxNotFound, addr.Hex(), tokenID))
  85. }
  86. idx, err := common.IdxFromBytes(b)
  87. if err != nil {
  88. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddr: %s: ToEthAddr: %s, TokenID: %d", err, addr.Hex(), tokenID))
  89. }
  90. return idx, nil
  91. }
  92. // GetIdxByEthAddrBJJ returns the smallest Idx in the StateDB for the given
  93. // Ethereum Address AND the given BabyJubJub PublicKey. If `addr` is the zero
  94. // address, it's ignored in the query. If `pk` is nil, it's ignored in the
  95. // query. Will return common.Idx(0) and error in case that Idx is not found in
  96. // the StateDB.
  97. func (s *StateDB) GetIdxByEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicKey, tokenID common.TokenID) (common.Idx, error) {
  98. if !bytes.Equal(addr.Bytes(), common.EmptyAddr.Bytes()) && pk == nil {
  99. // ToEthAddr
  100. // case ToEthAddr!=0 && ToBJJ=0
  101. return s.GetIdxByEthAddr(addr, tokenID)
  102. } else if !bytes.Equal(addr.Bytes(), common.EmptyAddr.Bytes()) && pk != nil {
  103. // case ToEthAddr!=0 && ToBJJ!=0
  104. k := concatEthAddrBJJTokenID(addr, pk, tokenID)
  105. b, err := s.db.Get(append(PrefixKeyAddrBJJ, k...))
  106. if err != nil {
  107. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddrBJJ: %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", ErrToIdxNotFound, addr.Hex(), pk, tokenID))
  108. }
  109. idx, err := common.IdxFromBytes(b)
  110. if err != nil {
  111. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddrBJJ: %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", err, addr.Hex(), pk, tokenID))
  112. }
  113. return idx, nil
  114. }
  115. // rest of cases (included case ToEthAddr==0) are not possible
  116. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddrBJJ: Not found, %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", ErrGetIdxNoCase, addr.Hex(), pk, tokenID))
  117. }
  118. func (s *StateDB) getTokenIDsFromIdxs(idxs []common.Idx) (map[common.TokenID]common.Idx, error) {
  119. m := make(map[common.TokenID]common.Idx)
  120. for i := 0; i < len(idxs); i++ {
  121. a, err := s.GetAccount(idxs[i])
  122. if err != nil {
  123. return nil, tracerr.Wrap(fmt.Errorf("getTokenIDsFromIdxs error on GetAccount with Idx==%d: %s", idxs[i], err.Error()))
  124. }
  125. m[a.TokenID] = idxs[i]
  126. }
  127. return m, nil
  128. }
  129. func siblingsToZKInputFormat(s []*merkletree.Hash) []*big.Int {
  130. b := make([]*big.Int, len(s))
  131. for i := 0; i < len(s); i++ {
  132. b[i] = s[i].BigInt()
  133. }
  134. return b
  135. }
  136. // BJJCompressedTo256BigInts returns a [256]*big.Int array with the bit
  137. // representation of the babyjub.PublicKeyComp
  138. func BJJCompressedTo256BigInts(pkComp babyjub.PublicKeyComp) [256]*big.Int {
  139. var r [256]*big.Int
  140. b := pkComp[:]
  141. for i := 0; i < 256; i++ {
  142. if b[i/8]&(1<<(i%8)) == 0 {
  143. r[i] = big.NewInt(0)
  144. } else {
  145. r[i] = big.NewInt(1)
  146. }
  147. }
  148. return r
  149. }
  150. // formatAccumulatedFees returns an array of [nFeeAccounts]*big.Int containing
  151. // the balance of each FeeAccount, taken from the 'collectedFees' map, in the
  152. // order of the 'orderTokenIDs'
  153. func formatAccumulatedFees(collectedFees map[common.TokenID]*big.Int, orderTokenIDs []*big.Int) []*big.Int {
  154. accFeeOut := make([]*big.Int, len(orderTokenIDs))
  155. for i := 0; i < len(orderTokenIDs); i++ {
  156. tokenID := common.TokenIDFromBigInt(orderTokenIDs[i])
  157. if _, ok := collectedFees[tokenID]; ok {
  158. accFeeOut[i] = new(big.Int).Set(collectedFees[tokenID])
  159. } else {
  160. accFeeOut[i] = big.NewInt(0)
  161. }
  162. }
  163. return accFeeOut
  164. }