arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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}