hermez-node/eth/rollup.go
eth/rollup.goRaw
1package eth
2
3import (
4 "context"
5 "fmt"
6 "math/big"
7 "strings"
8
9 "github.com/ethereum/go-ethereum"
10 "github.com/ethereum/go-ethereum/accounts/abi"
11 "github.com/ethereum/go-ethereum/accounts/abi/bind"
12 ethCommon "github.com/ethereum/go-ethereum/common"
13 "github.com/ethereum/go-ethereum/core/types"
14 "github.com/ethereum/go-ethereum/crypto"
15 "github.com/ethereum/go-ethereum/ethclient"
16 "github.com/hermeznetwork/hermez-node/common"
17 Hermez "github.com/hermeznetwork/hermez-node/eth/contracts/hermez"
18 HEZ "github.com/hermeznetwork/hermez-node/eth/contracts/tokenHEZ"
19 "github.com/hermeznetwork/hermez-node/log"
20 "github.com/hermeznetwork/tracerr"
21 "github.com/iden3/go-iden3-crypto/babyjub"
22)
23
24// QueueStruct is the queue of L1Txs for a batch
25type QueueStruct struct {
26 L1TxQueue []common.L1Tx
27 TotalL1TxFee *big.Int
28}
29
30// NewQueueStruct creates a new clear QueueStruct.
31func NewQueueStruct() *QueueStruct {
32 return &QueueStruct{
33 L1TxQueue: make([]common.L1Tx, 0),
34 TotalL1TxFee: big.NewInt(0),
35 }
36}
37
38// RollupState represents the state of the Rollup in the Smart Contract
39type RollupState struct {
40 StateRoot *big.Int
41 ExitRoots []*big.Int
42 // ExitNullifierMap map[[256 / 8]byte]bool
43 ExitNullifierMap map[int64]map[int64]bool // batchNum -> idx -> bool
44 TokenList []ethCommon.Address
45 TokenMap map[ethCommon.Address]bool
46 MapL1TxQueue map[int64]*QueueStruct
47 LastL1L2Batch int64
48 CurrentToForgeL1TxsNum int64
49 LastToForgeL1TxsNum int64
50 CurrentIdx int64
51}
52
53// RollupEventL1UserTx is an event of the Rollup Smart Contract
54type RollupEventL1UserTx struct {
55 // ToForgeL1TxsNum int64 // QueueIndex *big.Int
56 // Position int // TransactionIndex *big.Int
57 L1UserTx common.L1Tx
58}
59
60// RollupEventL1UserTxAux is an event of the Rollup Smart Contract
61type RollupEventL1UserTxAux struct {
62 ToForgeL1TxsNum uint64 // QueueIndex *big.Int
63 Position uint8 // TransactionIndex *big.Int
64 L1UserTx []byte
65}
66
67// RollupEventAddToken is an event of the Rollup Smart Contract
68type RollupEventAddToken struct {
69 TokenAddress ethCommon.Address
70 TokenID uint32
71}
72
73// RollupEventForgeBatch is an event of the Rollup Smart Contract
74type RollupEventForgeBatch struct {
75 BatchNum int64
76 // Sender ethCommon.Address
77 EthTxHash ethCommon.Hash
78}
79
80// RollupEventUpdateForgeL1L2BatchTimeout is an event of the Rollup Smart Contract
81type RollupEventUpdateForgeL1L2BatchTimeout struct {
82 NewForgeL1L2BatchTimeout int64
83}
84
85// RollupEventUpdateFeeAddToken is an event of the Rollup Smart Contract
86type RollupEventUpdateFeeAddToken struct {
87 NewFeeAddToken *big.Int
88}
89
90// RollupEventWithdraw is an event of the Rollup Smart Contract
91type RollupEventWithdraw struct {
92 Idx uint64
93 NumExitRoot uint64
94 InstantWithdraw bool
95 TxHash ethCommon.Hash // Hash of the transaction that generated this event
96}
97
98// RollupEvents is the list of events in a block of the Rollup Smart Contract
99type RollupEvents struct {
100 L1UserTx []RollupEventL1UserTx
101 AddToken []RollupEventAddToken
102 ForgeBatch []RollupEventForgeBatch
103 UpdateForgeL1L2BatchTimeout []RollupEventUpdateForgeL1L2BatchTimeout
104 UpdateFeeAddToken []RollupEventUpdateFeeAddToken
105 Withdraw []RollupEventWithdraw
106}
107
108// NewRollupEvents creates an empty RollupEvents with the slices initialized.
109func NewRollupEvents() RollupEvents {
110 return RollupEvents{
111 L1UserTx: make([]RollupEventL1UserTx, 0),
112 AddToken: make([]RollupEventAddToken, 0),
113 ForgeBatch: make([]RollupEventForgeBatch, 0),
114 UpdateForgeL1L2BatchTimeout: make([]RollupEventUpdateForgeL1L2BatchTimeout, 0),
115 UpdateFeeAddToken: make([]RollupEventUpdateFeeAddToken, 0),
116 Withdraw: make([]RollupEventWithdraw, 0),
117 }
118}
119
120// RollupForgeBatchArgs are the arguments to the ForgeBatch function in the Rollup Smart Contract
121type RollupForgeBatchArgs struct {
122 NewLastIdx int64
123 NewStRoot *big.Int
124 NewExitRoot *big.Int
125 L1CoordinatorTxs []common.L1Tx
126 L1CoordinatorTxsAuths [][]byte // Authorization for accountCreations for each L1CoordinatorTx
127 L2TxsData []common.L2Tx
128 FeeIdxCoordinator []common.Idx
129 // Circuit selector
130 VerifierIdx uint8
131 L1Batch bool
132 ProofA [2]*big.Int
133 ProofB [2][2]*big.Int
134 ProofC [2]*big.Int
135}
136
137// RollupForgeBatchArgsAux are the arguments to the ForgeBatch function in the Rollup Smart Contract
138type RollupForgeBatchArgsAux struct {
139 NewLastIdx *big.Int
140 NewStRoot *big.Int
141 NewExitRoot *big.Int
142 EncodedL1CoordinatorTx []byte
143 L2TxsData []byte
144 FeeIdxCoordinator []byte
145 // Circuit selector
146 VerifierIdx uint8
147 L1Batch bool
148 ProofA [2]*big.Int
149 ProofB [2][2]*big.Int
150 ProofC [2]*big.Int
151}
152
153// RollupInterface is the inteface to to Rollup Smart Contract
154type RollupInterface interface {
155 //
156 // Smart Contract Methods
157 //
158
159 // Public Functions
160
161 RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error)
162 RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (*types.Transaction, error)
163
164 RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error)
165 RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error)
166
167 RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
168 RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error)
169
170 // Governance Public Functions
171 RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (*types.Transaction, error)
172 RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error)
173
174 // Viewers
175 RollupRegisterTokensCount() (*big.Int, error)
176 RollupLastForgedBatch() (int64, error)
177
178 //
179 // Smart Contract Status
180 //
181
182 RollupConstants() (*common.RollupConstants, error)
183 RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error)
184 RollupForgeBatchArgs(ethCommon.Hash) (*RollupForgeBatchArgs, *ethCommon.Address, error)
185}
186
187//
188// Implementation
189//
190
191// RollupClient is the implementation of the interface to the Rollup Smart Contract in ethereum.
192type RollupClient struct {
193 client *EthereumClient
194 chainID *big.Int
195 address ethCommon.Address
196 tokenHEZCfg TokenConfig
197 hermez *Hermez.Hermez
198 tokenHEZ *HEZ.HEZ
199 contractAbi abi.ABI
200}
201
202// NewRollupClient creates a new RollupClient
203func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZCfg TokenConfig) (*RollupClient, error) {
204 contractAbi, err := abi.JSON(strings.NewReader(string(Hermez.HermezABI)))
205 if err != nil {
206 return nil, tracerr.Wrap(err)
207 }
208 hermez, err := Hermez.NewHermez(address, client.Client())
209 if err != nil {
210 return nil, tracerr.Wrap(err)
211 }
212 tokenHEZ, err := HEZ.NewHEZ(tokenHEZCfg.Address, client.Client())
213 if err != nil {
214 return nil, tracerr.Wrap(err)
215 }
216 chainID, err := client.client.ChainID(context.Background())
217 if err != nil {
218 return nil, tracerr.Wrap(err)
219 }
220 return &RollupClient{
221 client: client,
222 chainID: chainID,
223 address: address,
224 tokenHEZCfg: tokenHEZCfg,
225 hermez: hermez,
226 tokenHEZ: tokenHEZ,
227 contractAbi: contractAbi,
228 }, nil
229}
230
231// RollupForgeBatch is the interface to call the smart contract function
232func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) {
233 if tx, err = c.client.CallAuth(
234 1000000, //nolint:gomnd
235 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
236 rollupConst, err := c.RollupConstants()
237 if err != nil {
238 return nil, tracerr.Wrap(err)
239 }
240 nLevels := rollupConst.Verifiers[args.VerifierIdx].NLevels
241 lenBytes := nLevels / 8 //nolint:gomnd
242 newLastIdx := big.NewInt(int64(args.NewLastIdx))
243 var l1CoordinatorBytes []byte
244 for i := 0; i < len(args.L1CoordinatorTxs); i++ {
245 l1 := args.L1CoordinatorTxs[i]
246 bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
247 if err != nil {
248 return nil, tracerr.Wrap(err)
249 }
250 l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
251 }
252 var l2DataBytes []byte
253 for i := 0; i < len(args.L2TxsData); i++ {
254 l2 := args.L2TxsData[i]
255 bytesl2, err := l2.BytesDataAvailability(uint32(nLevels))
256 if err != nil {
257 return nil, tracerr.Wrap(err)
258 }
259 l2DataBytes = append(l2DataBytes, bytesl2[:]...)
260 }
261 var feeIdxCoordinator []byte
262 if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator {
263 return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
264 common.RollupConstMaxFeeIdxCoordinator))
265 }
266 for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ {
267 feeIdx := common.Idx(0)
268 if i < len(args.FeeIdxCoordinator) {
269 feeIdx = args.FeeIdxCoordinator[i]
270 }
271 bytesFeeIdx, err := feeIdx.Bytes()
272 if err != nil {
273 return nil, tracerr.Wrap(err)
274 }
275 feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
276 }
277 return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l2DataBytes, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC)
278 },
279 ); err != nil {
280 return nil, tracerr.Wrap(fmt.Errorf("Failed forge batch: %w", err))
281 }
282 return tx, nil
283}
284
285// RollupAddToken is the interface to call the smart contract function.
286// `feeAddToken` is the amount of HEZ tokens that will be paid to add the
287// token. `feeAddToken` must match the public value of the smart contract.
288func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (tx *types.Transaction, err error) {
289 if tx, err = c.client.CallAuth(
290 0,
291 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
292 owner := c.client.account.Address
293 spender := c.address
294 nonce, err := c.tokenHEZ.Nonces(nil, owner)
295 if err != nil {
296 return nil, tracerr.Wrap(err)
297 }
298 tokenName := c.tokenHEZCfg.Name
299 tokenAddr := c.tokenHEZCfg.Address
300 digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, feeAddToken, nonce, deadline, tokenName)
301 signature, _ := c.client.ks.SignHash(*c.client.account, digest)
302 permit := createPermit(owner, spender, feeAddToken, deadline, digest, signature)
303
304 return c.hermez.AddToken(auth, tokenAddress, permit)
305 },
306 ); err != nil {
307 return nil, tracerr.Wrap(fmt.Errorf("Failed add Token %w", err))
308 }
309 return tx, nil
310}
311
312// RollupWithdrawMerkleProof is the interface to call the smart contract function
313func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
314 if tx, err = c.client.CallAuth(
315 0,
316 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
317 pkCompL := fromBJJ.Compress()
318 pkCompB := common.SwapEndianness(pkCompL[:])
319 babyPubKey := new(big.Int).SetBytes(pkCompB)
320 numExitRootB := big.NewInt(numExitRoot)
321 idxBig := big.NewInt(idx)
322 return c.hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw)
323 },
324 ); err != nil {
325 return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawMerkleProof: %w", err))
326 }
327 return tx, nil
328}
329
330// RollupWithdrawCircuit is the interface to call the smart contract function
331func (c *RollupClient) RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error) {
332 log.Error("TODO")
333 return nil, tracerr.Wrap(errTODO)
334}
335
336// RollupL1UserTxERC20ETH is the interface to call the smart contract function
337func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
338 if tx, err = c.client.CallAuth(
339 0,
340 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
341 pkCompL := fromBJJ.Compress()
342 pkCompB := common.SwapEndianness(pkCompL[:])
343 babyPubKey := new(big.Int).SetBytes(pkCompB)
344 fromIdxBig := big.NewInt(fromIdx)
345 toIdxBig := big.NewInt(toIdx)
346 loadAmountF, err := common.NewFloat16(loadAmount)
347 if err != nil {
348 return nil, tracerr.Wrap(err)
349 }
350 amountF, err := common.NewFloat16(amount)
351 if err != nil {
352 return nil, tracerr.Wrap(err)
353 }
354 if tokenID == 0 {
355 auth.Value = loadAmount
356 }
357 var permit []byte
358 return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(loadAmountF),
359 uint16(amountF), tokenID, toIdxBig, permit)
360 },
361 ); err != nil {
362 return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err))
363 }
364 return tx, nil
365}
366
367// RollupL1UserTxERC20Permit is the interface to call the smart contract function
368func (c *RollupClient) RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) {
369 if tx, err = c.client.CallAuth(
370 0,
371 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
372 pkCompL := fromBJJ.Compress()
373 pkCompB := common.SwapEndianness(pkCompL[:])
374 babyPubKey := new(big.Int).SetBytes(pkCompB)
375 fromIdxBig := big.NewInt(fromIdx)
376 toIdxBig := big.NewInt(toIdx)
377 loadAmountF, err := common.NewFloat16(loadAmount)
378 if err != nil {
379 return nil, tracerr.Wrap(err)
380 }
381 amountF, err := common.NewFloat16(amount)
382 if err != nil {
383 return nil, tracerr.Wrap(err)
384 }
385 if tokenID == 0 {
386 auth.Value = loadAmount
387 }
388 owner := c.client.account.Address
389 spender := c.address
390 nonce, err := c.tokenHEZ.Nonces(nil, owner)
391 if err != nil {
392 return nil, tracerr.Wrap(err)
393 }
394 tokenName := c.tokenHEZCfg.Name
395 tokenAddr := c.tokenHEZCfg.Address
396 digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, amount, nonce, deadline, tokenName)
397 signature, _ := c.client.ks.SignHash(*c.client.account, digest)
398 permit := createPermit(owner, spender, amount, deadline, digest, signature)
399 return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(loadAmountF),
400 uint16(amountF), tokenID, toIdxBig, permit)
401 },
402 ); err != nil {
403 return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20Permit: %w", err))
404 }
405 return tx, nil
406}
407
408// RollupRegisterTokensCount is the interface to call the smart contract function
409func (c *RollupClient) RollupRegisterTokensCount() (registerTokensCount *big.Int, err error) {
410 if err := c.client.Call(func(ec *ethclient.Client) error {
411 registerTokensCount, err = c.hermez.RegisterTokensCount(nil)
412 return tracerr.Wrap(err)
413 }); err != nil {
414 return nil, tracerr.Wrap(err)
415 }
416 return registerTokensCount, nil
417}
418
419// RollupLastForgedBatch is the interface to call the smart contract function
420func (c *RollupClient) RollupLastForgedBatch() (lastForgedBatch int64, err error) {
421 if err := c.client.Call(func(ec *ethclient.Client) error {
422 _lastForgedBatch, err := c.hermez.LastForgedBatch(nil)
423 lastForgedBatch = int64(_lastForgedBatch)
424 return tracerr.Wrap(err)
425 }); err != nil {
426 return 0, tracerr.Wrap(err)
427 }
428 return lastForgedBatch, nil
429}
430
431// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
432func (c *RollupClient) RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (tx *types.Transaction, err error) {
433 if tx, err = c.client.CallAuth(
434 0,
435 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
436 return c.hermez.UpdateForgeL1L2BatchTimeout(auth, uint8(newForgeL1L2BatchTimeout))
437 },
438 ); err != nil {
439 return nil, tracerr.Wrap(fmt.Errorf("Failed update ForgeL1L2BatchTimeout: %w", err))
440 }
441 return tx, nil
442}
443
444// RollupUpdateFeeAddToken is the interface to call the smart contract function
445func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
446 if tx, err = c.client.CallAuth(
447 0,
448 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
449 return c.hermez.UpdateFeeAddToken(auth, newFeeAddToken)
450 },
451 ); err != nil {
452 return nil, tracerr.Wrap(fmt.Errorf("Failed update FeeAddToken: %w", err))
453 }
454 return tx, nil
455}
456
457// RollupConstants returns the Constants of the Rollup Smart Contract
458func (c *RollupClient) RollupConstants() (rollupConstants *common.RollupConstants, err error) {
459 rollupConstants = new(common.RollupConstants)
460 if err := c.client.Call(func(ec *ethclient.Client) error {
461 absoluteMaxL1L2BatchTimeout, err := c.hermez.ABSOLUTEMAXL1L2BATCHTIMEOUT(nil)
462 if err != nil {
463 return tracerr.Wrap(err)
464 }
465 rollupConstants.AbsoluteMaxL1L2BatchTimeout = int64(absoluteMaxL1L2BatchTimeout)
466 rollupConstants.TokenHEZ, err = c.hermez.TokenHEZ(nil)
467 if err != nil {
468 return tracerr.Wrap(err)
469 }
470 for i := int64(0); i < int64(common.LenVerifiers); i++ {
471 var newRollupVerifier common.RollupVerifierStruct
472 rollupVerifier, err := c.hermez.RollupVerifiers(nil, big.NewInt(i))
473 if err != nil {
474 return tracerr.Wrap(err)
475 }
476 newRollupVerifier.MaxTx = rollupVerifier.MaxTx.Int64()
477 newRollupVerifier.NLevels = rollupVerifier.NLevels.Int64()
478 rollupConstants.Verifiers = append(rollupConstants.Verifiers, newRollupVerifier)
479 }
480 rollupConstants.HermezAuctionContract, err = c.hermez.HermezAuctionContract(nil)
481 if err != nil {
482 return tracerr.Wrap(err)
483 }
484 rollupConstants.HermezGovernanceDAOAddress, err = c.hermez.HermezGovernanceDAOAddress(nil)
485 if err != nil {
486 return tracerr.Wrap(err)
487 }
488 rollupConstants.SafetyAddress, err = c.hermez.SafetyAddress(nil)
489 if err != nil {
490 return tracerr.Wrap(err)
491 }
492 rollupConstants.WithdrawDelayerContract, err = c.hermez.WithdrawDelayerContract(nil)
493 return tracerr.Wrap(err)
494 }); err != nil {
495 return nil, tracerr.Wrap(err)
496 }
497 return rollupConstants, nil
498}
499
500var (
501 logHermezL1UserTxEvent = crypto.Keccak256Hash([]byte("L1UserTxEvent(uint64,uint8,bytes)"))
502 logHermezAddToken = crypto.Keccak256Hash([]byte("AddToken(address,uint32)"))
503 logHermezForgeBatch = crypto.Keccak256Hash([]byte("ForgeBatch(uint64)"))
504 logHermezUpdateForgeL1L2BatchTimeout = crypto.Keccak256Hash([]byte("UpdateForgeL1L2BatchTimeout(uint8)"))
505 logHermezUpdateFeeAddToken = crypto.Keccak256Hash([]byte("UpdateFeeAddToken(uint256)"))
506 logHermezWithdrawEvent = crypto.Keccak256Hash([]byte("WithdrawEvent(uint48,uint48,bool)"))
507)
508
509// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
510func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) {
511 var rollupEvents RollupEvents
512 var blockHash *ethCommon.Hash
513
514 query := ethereum.FilterQuery{
515 FromBlock: big.NewInt(blockNum),
516 ToBlock: big.NewInt(blockNum),
517 Addresses: []ethCommon.Address{
518 c.address,
519 },
520 BlockHash: nil,
521 Topics: [][]ethCommon.Hash{},
522 }
523 logs, err := c.client.client.FilterLogs(context.Background(), query)
524 if err != nil {
525 return nil, nil, tracerr.Wrap(err)
526 }
527 if len(logs) > 0 {
528 blockHash = &logs[0].BlockHash
529 }
530 for _, vLog := range logs {
531 if vLog.BlockHash != *blockHash {
532 log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
533 return nil, nil, tracerr.Wrap(ErrBlockHashMismatchEvent)
534 }
535 switch vLog.Topics[0] {
536 case logHermezL1UserTxEvent:
537 var L1UserTxAux RollupEventL1UserTxAux
538 var L1UserTx RollupEventL1UserTx
539 err := c.contractAbi.Unpack(&L1UserTxAux, "L1UserTxEvent", vLog.Data)
540 if err != nil {
541 return nil, nil, tracerr.Wrap(err)
542 }
543 L1Tx, err := common.L1UserTxFromBytes(L1UserTxAux.L1UserTx)
544 if err != nil {
545 return nil, nil, tracerr.Wrap(err)
546 }
547 toForgeL1TxsNum := new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
548 L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
549 L1Tx.Position = int(new(big.Int).SetBytes(vLog.Topics[2][:]).Int64())
550 L1Tx.UserOrigin = true
551 L1UserTx.L1UserTx = *L1Tx
552 rollupEvents.L1UserTx = append(rollupEvents.L1UserTx, L1UserTx)
553 case logHermezAddToken:
554 var addToken RollupEventAddToken
555 err := c.contractAbi.Unpack(&addToken, "AddToken", vLog.Data)
556 if err != nil {
557 return nil, nil, tracerr.Wrap(err)
558 }
559 addToken.TokenAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
560 rollupEvents.AddToken = append(rollupEvents.AddToken, addToken)
561 case logHermezForgeBatch:
562 var forgeBatch RollupEventForgeBatch
563 forgeBatch.BatchNum = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
564 forgeBatch.EthTxHash = vLog.TxHash
565 // forgeBatch.Sender = vLog.Address
566 rollupEvents.ForgeBatch = append(rollupEvents.ForgeBatch, forgeBatch)
567 case logHermezUpdateForgeL1L2BatchTimeout:
568 var updateForgeL1L2BatchTimeout struct {
569 NewForgeL1L2BatchTimeout uint8
570 }
571 err := c.contractAbi.Unpack(&updateForgeL1L2BatchTimeout, "UpdateForgeL1L2BatchTimeout", vLog.Data)
572 if err != nil {
573 return nil, nil, tracerr.Wrap(err)
574 }
575 rollupEvents.UpdateForgeL1L2BatchTimeout = append(rollupEvents.UpdateForgeL1L2BatchTimeout,
576 RollupEventUpdateForgeL1L2BatchTimeout{
577 NewForgeL1L2BatchTimeout: int64(updateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout),
578 })
579 case logHermezUpdateFeeAddToken:
580 var updateFeeAddToken RollupEventUpdateFeeAddToken
581 err := c.contractAbi.Unpack(&updateFeeAddToken, "UpdateFeeAddToken", vLog.Data)
582 if err != nil {
583 return nil, nil, tracerr.Wrap(err)
584 }
585 rollupEvents.UpdateFeeAddToken = append(rollupEvents.UpdateFeeAddToken, updateFeeAddToken)
586 case logHermezWithdrawEvent:
587 var withdraw RollupEventWithdraw
588 withdraw.Idx = new(big.Int).SetBytes(vLog.Topics[1][:]).Uint64()
589 withdraw.NumExitRoot = new(big.Int).SetBytes(vLog.Topics[2][:]).Uint64()
590 instantWithdraw := new(big.Int).SetBytes(vLog.Topics[3][:]).Uint64()
591 if instantWithdraw == 1 {
592 withdraw.InstantWithdraw = true
593 }
594 withdraw.TxHash = vLog.TxHash
595 rollupEvents.Withdraw = append(rollupEvents.Withdraw, withdraw)
596 }
597 }
598 return &rollupEvents, blockHash, nil
599}
600
601// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the
602// Rollup Smart Contract in the given transaction, and the sender address.
603func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash) (*RollupForgeBatchArgs, *ethCommon.Address, error) {
604 tx, _, err := c.client.client.TransactionByHash(context.Background(), ethTxHash)
605 if err != nil {
606 return nil, nil, tracerr.Wrap(err)
607 }
608 txData := tx.Data()
609
610 method, err := c.contractAbi.MethodById(txData[:4])
611 if err != nil {
612 return nil, nil, tracerr.Wrap(err)
613 }
614 receipt, err := c.client.client.TransactionReceipt(context.Background(), ethTxHash)
615 if err != nil {
616 return nil, nil, tracerr.Wrap(err)
617 }
618 sender, err := c.client.client.TransactionSender(context.Background(), tx, receipt.Logs[0].BlockHash, receipt.Logs[0].Index)
619 if err != nil {
620 return nil, nil, tracerr.Wrap(err)
621 }
622 var aux RollupForgeBatchArgsAux
623 if err := method.Inputs.Unpack(&aux, txData[4:]); err != nil {
624 return nil, nil, tracerr.Wrap(err)
625 }
626 rollupForgeBatchArgs := RollupForgeBatchArgs{
627 L1Batch: aux.L1Batch,
628 NewExitRoot: aux.NewExitRoot,
629 NewLastIdx: aux.NewLastIdx.Int64(),
630 NewStRoot: aux.NewStRoot,
631 ProofA: aux.ProofA,
632 ProofB: aux.ProofB,
633 ProofC: aux.ProofC,
634 VerifierIdx: aux.VerifierIdx,
635 L1CoordinatorTxs: []common.L1Tx{},
636 L1CoordinatorTxsAuths: [][]byte{},
637 L2TxsData: []common.L2Tx{},
638 FeeIdxCoordinator: []common.Idx{},
639 }
640 numTxsL1 := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen
641 for i := 0; i < numTxsL1; i++ {
642 bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen]
643 var signature []byte
644 v := bytesL1Coordinator[0]
645 s := bytesL1Coordinator[1:33]
646 r := bytesL1Coordinator[33:65]
647 signature = append(signature, r[:]...)
648 signature = append(signature, s[:]...)
649 signature = append(signature, v)
650 l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator, c.chainID, c.address)
651 if err != nil {
652 return nil, nil, tracerr.Wrap(err)
653 }
654 rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx)
655 rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature)
656 }
657 rollupConsts, err := c.RollupConstants()
658 if err != nil {
659 return nil, nil, tracerr.Wrap(err)
660 }
661 nLevels := rollupConsts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels
662 lenL2TxsBytes := int((nLevels/8)*2 + 2 + 1)
663 numTxsL2 := len(aux.L2TxsData) / lenL2TxsBytes
664 for i := 0; i < numTxsL2; i++ {
665 l2Tx, err := common.L2TxFromBytes(aux.L2TxsData[i*lenL2TxsBytes:(i+1)*lenL2TxsBytes], int(nLevels))
666 if err != nil {
667 return nil, nil, tracerr.Wrap(err)
668 }
669 rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx)
670 }
671 lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
672 numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes
673 for i := 0; i < numFeeIdxCoordinator; i++ {
674 var paddedFeeIdx [6]byte
675 // TODO: This check is not necessary: the first case will always work. Test it before removing the if.
676 if lenFeeIdxCoordinatorBytes < common.IdxBytesLen {
677 copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
678 } else {
679 copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
680 }
681 feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:])
682 if err != nil {
683 return nil, nil, tracerr.Wrap(err)
684 }
685 if feeIdxCoordinator != common.Idx(0) {
686 rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator)
687 }
688 }
689 return &rollupForgeBatchArgs, &sender, nil
690}