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.2 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.PublicKeyComp, tokenID common.TokenID) []byte {
  20. pkComp := pk
  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.PublicKeyComp, 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. // store idx for EthAddr & BJJ assuming that EthAddr & BJJ still don't
  45. // have an Idx stored in the DB, and if so, the already stored Idx is
  46. // bigger than the given one, so should be updated to the new one
  47. // (smaller)
  48. tx, err := s.db.NewTx()
  49. if err != nil {
  50. return tracerr.Wrap(err)
  51. }
  52. idxBytes, err := idx.Bytes()
  53. if err != nil {
  54. return tracerr.Wrap(err)
  55. }
  56. // store Addr&BJJ-idx
  57. k := concatEthAddrBJJTokenID(addr, pk, tokenID)
  58. err = tx.Put(append(PrefixKeyAddrBJJ, k...), idxBytes[:])
  59. if err != nil {
  60. return tracerr.Wrap(err)
  61. }
  62. // store Addr-idx
  63. k = concatEthAddrTokenID(addr, tokenID)
  64. err = tx.Put(append(PrefixKeyAddr, k...), idxBytes[:])
  65. if err != nil {
  66. return tracerr.Wrap(err)
  67. }
  68. err = tx.Commit()
  69. if err != nil {
  70. return tracerr.Wrap(err)
  71. }
  72. return nil
  73. }
  74. // GetIdxByEthAddr returns the smallest Idx in the StateDB for the given
  75. // Ethereum Address. Will return common.Idx(0) and error in case that Idx is
  76. // not found in the StateDB.
  77. func (s *StateDB) GetIdxByEthAddr(addr ethCommon.Address, tokenID common.TokenID) (common.Idx, error) {
  78. k := concatEthAddrTokenID(addr, tokenID)
  79. b, err := s.db.Get(append(PrefixKeyAddr, k...))
  80. if err != nil {
  81. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddr: %s: ToEthAddr: %s, TokenID: %d",
  82. ErrToIdxNotFound, addr.Hex(), tokenID))
  83. }
  84. idx, err := common.IdxFromBytes(b)
  85. if err != nil {
  86. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddr: %s: ToEthAddr: %s, TokenID: %d",
  87. err, addr.Hex(), tokenID))
  88. }
  89. return idx, nil
  90. }
  91. // GetIdxByEthAddrBJJ returns the smallest Idx in the StateDB for the given
  92. // Ethereum Address AND the given BabyJubJub PublicKey. If `addr` is the zero
  93. // address, it's ignored in the query. If `pk` is nil, it's ignored in the
  94. // query. Will return common.Idx(0) and error in case that Idx is not found in
  95. // the StateDB.
  96. func (s *StateDB) GetIdxByEthAddrBJJ(addr ethCommon.Address, pk babyjub.PublicKeyComp, tokenID common.TokenID) (common.Idx, error) {
  97. if !bytes.Equal(addr.Bytes(), common.EmptyAddr.Bytes()) && pk == common.EmptyBJJComp {
  98. // ToEthAddr
  99. // case ToEthAddr!=0 && ToBJJ=0
  100. return s.GetIdxByEthAddr(addr, tokenID)
  101. } else if !bytes.Equal(addr.Bytes(), common.EmptyAddr.Bytes()) && pk != common.EmptyBJJComp {
  102. // case ToEthAddr!=0 && ToBJJ!=0
  103. k := concatEthAddrBJJTokenID(addr, pk, tokenID)
  104. b, err := s.db.Get(append(PrefixKeyAddrBJJ, k...))
  105. if err != nil {
  106. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddrBJJ: %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", ErrToIdxNotFound, addr.Hex(), pk, tokenID))
  107. }
  108. idx, err := common.IdxFromBytes(b)
  109. if err != nil {
  110. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddrBJJ: %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", err, addr.Hex(), pk, tokenID))
  111. }
  112. return idx, nil
  113. }
  114. // rest of cases (included case ToEthAddr==0) are not possible
  115. return common.Idx(0), tracerr.Wrap(fmt.Errorf("GetIdxByEthAddrBJJ: Not found, %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", ErrGetIdxNoCase, addr.Hex(), pk, tokenID))
  116. }
  117. // GetTokenIDsFromIdxs returns a map containing the common.TokenID with its
  118. // respective common.Idx for a given slice of common.Idx
  119. func (s *StateDB) GetTokenIDsFromIdxs(idxs []common.Idx) (map[common.TokenID]common.Idx, error) {
  120. m := make(map[common.TokenID]common.Idx)
  121. for i := 0; i < len(idxs); i++ {
  122. a, err := s.GetAccount(idxs[i])
  123. if err != nil {
  124. return nil, tracerr.Wrap(fmt.Errorf("GetTokenIDsFromIdxs error on GetAccount with Idx==%d: %s", idxs[i], err.Error()))
  125. }
  126. m[a.TokenID] = idxs[i]
  127. }
  128. return m, nil
  129. }
  130. func siblingsToZKInputFormat(s []*merkletree.Hash) []*big.Int {
  131. b := make([]*big.Int, len(s))
  132. for i := 0; i < len(s); i++ {
  133. b[i] = s[i].BigInt()
  134. }
  135. return b
  136. }
  137. // BJJCompressedTo256BigInts returns a [256]*big.Int array with the bit
  138. // representation of the babyjub.PublicKeyComp
  139. func BJJCompressedTo256BigInts(pkComp babyjub.PublicKeyComp) [256]*big.Int {
  140. var r [256]*big.Int
  141. b := pkComp[:]
  142. for i := 0; i < 256; i++ {
  143. if b[i/8]&(1<<(i%8)) == 0 {
  144. r[i] = big.NewInt(0)
  145. } else {
  146. r[i] = big.NewInt(1)
  147. }
  148. }
  149. return r
  150. }
  151. // formatAccumulatedFees returns an array of [nFeeAccounts]*big.Int containing
  152. // the balance of each FeeAccount, taken from the 'collectedFees' map, in the
  153. // order of the 'orderTokenIDs'
  154. func formatAccumulatedFees(collectedFees map[common.TokenID]*big.Int, orderTokenIDs []*big.Int) []*big.Int {
  155. accFeeOut := make([]*big.Int, len(orderTokenIDs))
  156. for i := 0; i < len(orderTokenIDs); i++ {
  157. tokenID := common.TokenIDFromBigInt(orderTokenIDs[i])
  158. if _, ok := collectedFees[tokenID]; ok {
  159. accFeeOut[i] = new(big.Int).Set(collectedFees[tokenID])
  160. } else {
  161. accFeeOut[i] = big.NewInt(0)
  162. }
  163. }
  164. return accFeeOut
  165. }