hermez-node/batchbuilder/batchbuilder.go
batchbuilder/batchbuilder.goRaw
1package batchbuilder
2
3import (
4 ethCommon "github.com/ethereum/go-ethereum/common"
5 "github.com/hermeznetwork/hermez-node/common"
6 "github.com/iden3/go-iden3-crypto/babyjub"
7 "github.com/iden3/go-merkletree"
8 "github.com/iden3/go-merkletree/db"
9 "github.com/iden3/go-merkletree/db/memory"
10)
11
12// ConfigCircuit contains the circuit configuration
13type ConfigCircuit struct {
14 TxsMax uint64
15 L1TxsMax uint64
16 SMTLevelsMax uint64
17}
18
19// BatchBuilder implements the batch builder type, which contains the functionallities
20type BatchBuilder struct {
21 StateDB db.Storage // where the MTs will be stored by the Synchronizer
22 idx uint64
23 mt *merkletree.MerkleTree
24 configCircuits []ConfigCircuit
25}
26
27// ConfigBatch contains the batch configuration
28type ConfigBatch struct {
29 CoordinatorAddress ethCommon.Address
30}
31
32// NewBatchBuilder constructs a new BatchBuilder, and executes the bb.Reset
33// method
34func NewBatchBuilder(stateDB db.Storage, configCircuits []ConfigCircuit, batchNum int, idx, nLevels uint64) (*BatchBuilder, error) {
35 localMt, err := merkletree.NewMerkleTree(memory.NewMemoryStorage(), int(nLevels))
36 if err != nil {
37 return nil, err
38 }
39 bb := BatchBuilder{
40 StateDB: stateDB,
41 idx: idx,
42 mt: localMt,
43 configCircuits: configCircuits,
44 }
45
46 err = bb.Reset(batchNum, idx, true)
47 return &bb, err
48}
49
50// Reset tells the BatchBuilder to reset it's internal state to the required
51// `batchNum`. If `fromSynchronizer` is true, the BatchBuilder must take a
52// copy of the rollup state from the Synchronizer at that `batchNum`, otherwise
53// it can just roll back the internal copy.
54func (bb *BatchBuilder) Reset(batchNum int, idx uint64, fromSynchronizer bool) error {
55 // TODO
56 return nil
57}
58
59// BuildBatch takes the transactions and returns the common.ZKInputs of the next batch
60func (bb *BatchBuilder) BuildBatch(configBatch ConfigBatch, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.L2Tx, tokenIDs []common.TokenID) (*common.ZKInputs, error) {
61 for _, tx := range l1usertxs {
62 err := bb.processL1Tx(tx)
63 if err != nil {
64 return nil, err
65 }
66 }
67 for _, tx := range l1coordinatortxs {
68 err := bb.processL1Tx(tx)
69 if err != nil {
70 return nil, err
71 }
72 }
73 for _, tx := range l2txs {
74 switch tx.Type {
75 case common.TxTypeTransfer:
76 // go to the MT leaf of sender and receiver, and update
77 // balance & nonce
78 err := bb.applyTransfer(tx.Tx)
79 if err != nil {
80 return nil, err
81 }
82 case common.TxTypeExit:
83 // execute exit flow
84 default:
85 }
86 }
87
88 return nil, nil
89}
90
91func (bb *BatchBuilder) processL1Tx(tx common.L1Tx) error {
92 switch tx.Type {
93 case common.TxTypeForceTransfer, common.TxTypeTransfer:
94 // go to the MT leaf of sender and receiver, and update balance
95 // & nonce
96 err := bb.applyTransfer(tx.Tx)
97 if err != nil {
98 return err
99 }
100 case common.TxTypeCreateAccountDeposit:
101 // add new leaf to the MT, update balance of the MT leaf
102 err := bb.applyCreateLeaf(tx)
103 if err != nil {
104 return err
105 }
106 case common.TxTypeDeposit:
107 // update balance of the MT leaf
108 err := bb.applyDeposit(tx, false)
109 if err != nil {
110 return err
111 }
112 case common.TxTypeDepositAndTransfer:
113 // update balance in MT leaf, update balance & nonce of sender
114 // & receiver
115 err := bb.applyDeposit(tx, true)
116 if err != nil {
117 return err
118 }
119 case common.TxTypeCreateAccountDepositAndTransfer:
120 // add new leaf to the merkletree, update balance in MT leaf,
121 // update balance & nonce of sender & receiver
122 err := bb.applyCreateLeaf(tx)
123 if err != nil {
124 return err
125 }
126 err = bb.applyTransfer(tx.Tx)
127 if err != nil {
128 return err
129 }
130 case common.TxTypeExit:
131 // execute exit flow
132 default:
133 }
134
135 return nil
136}
137
138// applyCreateLeaf creates a new leaf in the leaf of the depositer, it stores
139// the deposit value
140func (bb *BatchBuilder) applyCreateLeaf(tx common.L1Tx) error {
141 leaf := common.Leaf{
142 TokenID: tx.TokenID,
143 Nonce: 0, // TODO check w spec: always that a new leaf is created nonce is at 0
144 Balance: tx.LoadAmount,
145 Sign: babyjub.PointCoordSign(tx.FromBJJ.X),
146 Ay: tx.FromBJJ.Y,
147 EthAddr: tx.FromEthAddr,
148 }
149
150 v, err := leaf.HashValue()
151 if err != nil {
152 return err
153 }
154 dbTx, err := bb.mt.DB().NewTx()
155 if err != nil {
156 return err
157 }
158
159 err = bb.CreateBalance(dbTx, common.Idx(bb.idx+1), leaf)
160 if err != nil {
161 return err
162 }
163 leafBytes, err := leaf.Bytes()
164 if err != nil {
165 return err
166 }
167 dbTx.Put(v.Bytes(), leafBytes[:])
168
169 // if everything is fine, do dbTx & increment idx
170 if err := dbTx.Commit(); err != nil {
171 return err
172 }
173 bb.idx = bb.idx + 1
174 return nil
175}
176
177// applyDeposit updates the balance in the leaf of the depositer, if andTransfer parameter is set to true, the method will also apply the Transfer of the L1Tx/DepositAndTransfer
178func (bb *BatchBuilder) applyDeposit(tx common.L1Tx, andTransfer bool) error {
179 dbTx, err := bb.mt.DB().NewTx()
180 if err != nil {
181 return err
182 }
183
184 // deposit
185 err = bb.UpdateBalance(dbTx, tx.FromIdx, tx.LoadAmount, false)
186 if err != nil {
187 return err
188 }
189
190 // in case that the tx is a L1Tx>DepositAndTransfer
191 if andTransfer {
192 // transact
193 err = bb.UpdateBalance(dbTx, tx.FromIdx, tx.Tx.Amount, true)
194 if err != nil {
195 return err
196 }
197 err = bb.UpdateBalance(dbTx, tx.ToIdx, tx.Tx.Amount, false)
198 if err != nil {
199 return err
200 }
201 }
202
203 if err := dbTx.Commit(); err != nil {
204 return err
205 }
206 return nil
207}
208
209// applyTransfer updates the balance & nonce in the leaf of the sender, and the
210// balance in the leaf of the receiver
211func (bb *BatchBuilder) applyTransfer(tx common.Tx) error {
212 dbTx, err := bb.mt.DB().NewTx()
213 if err != nil {
214 return err
215 }
216
217 // transact
218 err = bb.UpdateBalance(dbTx, tx.FromIdx, tx.Amount, true)
219 if err != nil {
220 return err
221 }
222 err = bb.UpdateBalance(dbTx, tx.ToIdx, tx.Amount, false)
223 if err != nil {
224 return err
225 }
226
227 if err := dbTx.Commit(); err != nil {
228 return err
229 }
230 return nil
231}