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