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