hermez-node/test/ethclient.go
test/ethclient.goRaw
1package test
2
3import (
4 "context"
5 "encoding/binary"
6 "encoding/json"
7 "fmt"
8 "math/big"
9 "reflect"
10 "sync"
11 "time"
12
13 "github.com/ethereum/go-ethereum"
14 ethCommon "github.com/ethereum/go-ethereum/common"
15 "github.com/ethereum/go-ethereum/core/types"
16 "github.com/hermeznetwork/hermez-node/common"
17 "github.com/hermeznetwork/hermez-node/eth"
18 "github.com/hermeznetwork/hermez-node/log"
19 "github.com/hermeznetwork/tracerr"
20 "github.com/iden3/go-iden3-crypto/babyjub"
21 "github.com/mitchellh/copystructure"
22)
23
24func init() {
25 copystructure.Copiers[reflect.TypeOf(big.Int{})] =
26 func(raw interface{}) (interface{}, error) {
27 in := raw.(big.Int)
28 out := new(big.Int).Set(&in)
29 return *out, nil
30 }
31}
32
33// WDelayerBlock stores all the data related to the WDelayer SC from an ethereum block
34type WDelayerBlock struct {
35 // State eth.WDelayerState // TODO
36 Vars common.WDelayerVariables
37 Events eth.WDelayerEvents
38 Txs map[ethCommon.Hash]*types.Transaction
39 Constants *common.WDelayerConstants
40 Eth *EthereumBlock
41}
42
43func (w *WDelayerBlock) addTransaction(tx *types.Transaction) *types.Transaction {
44 txHash := tx.Hash()
45 w.Txs[txHash] = tx
46 return tx
47}
48
49func (w *WDelayerBlock) deposit(txHash ethCommon.Hash, owner, token ethCommon.Address, amount *big.Int) {
50 w.Events.Deposit = append(w.Events.Deposit, eth.WDelayerEventDeposit{
51 Owner: owner,
52 Token: token,
53 Amount: amount,
54 DepositTimestamp: uint64(w.Eth.Time),
55 TxHash: txHash,
56 })
57}
58
59// RollupBlock stores all the data related to the Rollup SC from an ethereum block
60type RollupBlock struct {
61 State eth.RollupState
62 Vars common.RollupVariables
63 Events eth.RollupEvents
64 Txs map[ethCommon.Hash]*types.Transaction
65 Constants *common.RollupConstants
66 Eth *EthereumBlock
67}
68
69func (r *RollupBlock) addTransaction(tx *types.Transaction) *types.Transaction {
70 txHash := tx.Hash()
71 r.Txs[txHash] = tx
72 return tx
73}
74
75var (
76 errBidClosed = fmt.Errorf("Bid has already been closed")
77 errBidNotOpen = fmt.Errorf("Bid has not been opened yet")
78 errBidBelowMin = fmt.Errorf("Bid below minimum")
79 errCoordNotReg = fmt.Errorf("Coordinator not registered")
80)
81
82// AuctionBlock stores all the data related to the Auction SC from an ethereum block
83type AuctionBlock struct {
84 State eth.AuctionState
85 Vars common.AuctionVariables
86 Events eth.AuctionEvents
87 Txs map[ethCommon.Hash]*types.Transaction
88 Constants *common.AuctionConstants
89 Eth *EthereumBlock
90}
91
92func (a *AuctionBlock) addTransaction(tx *types.Transaction) *types.Transaction {
93 txHash := tx.Hash()
94 a.Txs[txHash] = tx
95 return tx
96}
97
98func (a *AuctionBlock) getSlotNumber(blockNumber int64) int64 {
99 if a.Eth.BlockNum >= a.Constants.GenesisBlockNum {
100 return (blockNumber - a.Constants.GenesisBlockNum) / int64(a.Constants.BlocksPerSlot)
101 }
102 return 0
103}
104
105func (a *AuctionBlock) getCurrentSlotNumber() int64 {
106 return a.getSlotNumber(a.Eth.BlockNum)
107}
108
109func (a *AuctionBlock) getSlotSet(slot int64) int64 {
110 return slot % int64(len(a.Vars.DefaultSlotSetBid))
111}
112
113func (a *AuctionBlock) getMinBidBySlot(slot int64) (*big.Int, error) {
114 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
115 return nil, tracerr.Wrap(errBidClosed)
116 }
117
118 slotSet := a.getSlotSet(slot)
119 // fmt.Println("slot:", slot, "slotSet:", slotSet)
120 var prevBid *big.Int
121 slotState, ok := a.State.Slots[slot]
122 if !ok {
123 slotState = eth.NewSlotState()
124 a.State.Slots[slot] = slotState
125 }
126 // If the bidAmount for a slot is 0 it means that it has not yet been
127 // bid, so the midBid will be the minimum bid for the slot time plus
128 // the outbidding set, otherwise it will be the bidAmount plus the
129 // outbidding
130 if slotState.BidAmount.Cmp(big.NewInt(0)) == 0 {
131 prevBid = a.Vars.DefaultSlotSetBid[slotSet]
132 } else {
133 prevBid = slotState.BidAmount
134 }
135 outBid := new(big.Int).Set(prevBid)
136 // fmt.Println("outBid:", outBid)
137 outBid.Mul(outBid, big.NewInt(int64(a.Vars.Outbidding)))
138 outBid.Div(outBid, big.NewInt(10000)) //nolint:gomnd
139 outBid.Add(prevBid, outBid)
140 // fmt.Println("minBid:", outBid)
141 return outBid, nil
142}
143
144func (a *AuctionBlock) forge(forger ethCommon.Address) error {
145 if ok, err := a.canForge(forger, a.Eth.BlockNum); err != nil {
146 return tracerr.Wrap(err)
147 } else if !ok {
148 return tracerr.Wrap(fmt.Errorf("Can't forge"))
149 }
150
151 slotToForge := a.getSlotNumber(a.Eth.BlockNum)
152 slotState, ok := a.State.Slots[slotToForge]
153 if !ok {
154 slotState = eth.NewSlotState()
155 a.State.Slots[slotToForge] = slotState
156 }
157
158 if !slotState.ForgerCommitment {
159 // Get the relativeBlock to check if the slotDeadline has been exceeded
160 relativeBlock := a.Eth.BlockNum - (a.Constants.GenesisBlockNum +
161 (slotToForge * int64(a.Constants.BlocksPerSlot)))
162 if relativeBlock < int64(a.Vars.SlotDeadline) {
163 slotState.ForgerCommitment = true
164 }
165 }
166
167 slotState.Fulfilled = true
168
169 a.Events.NewForge = append(a.Events.NewForge, eth.AuctionEventNewForge{
170 Forger: forger,
171 SlotToForge: slotToForge,
172 })
173 return nil
174}
175
176func (a *AuctionBlock) canForge(forger ethCommon.Address, blockNum int64) (bool, error) {
177 if blockNum < a.Constants.GenesisBlockNum {
178 return false, tracerr.Wrap(fmt.Errorf("Auction has not started yet"))
179 }
180
181 slotToForge := a.getSlotNumber(blockNum)
182 // fmt.Printf("DBG canForge slot: %v\n", slotToForge)
183 // Get the relativeBlock to check if the slotDeadline has been exceeded
184 relativeBlock := blockNum - (a.Constants.GenesisBlockNum + (slotToForge * int64(a.Constants.BlocksPerSlot)))
185
186 // If the closedMinBid is 0 it means that we have to take as minBid the
187 // one that is set for this slot set, otherwise the one that has been
188 // saved will be used
189 var minBid *big.Int
190 slotState, ok := a.State.Slots[slotToForge]
191 if !ok {
192 slotState = eth.NewSlotState()
193 a.State.Slots[slotToForge] = slotState
194 }
195 if slotState.ClosedMinBid.Cmp(big.NewInt(0)) == 0 {
196 minBid = a.Vars.DefaultSlotSetBid[a.getSlotSet(slotToForge)]
197 } else {
198 minBid = slotState.ClosedMinBid
199 }
200
201 if !slotState.ForgerCommitment && (relativeBlock >= int64(a.Vars.SlotDeadline)) {
202 // if the relative block has exceeded the slotDeadline and no
203 // batch has been forged, anyone can forge
204 return true, nil
205 } else if coord, ok := a.State.Coordinators[slotState.Bidder]; ok &&
206 coord.Forger == forger && slotState.BidAmount.Cmp(minBid) >= 0 {
207 // if forger bidAmount has exceeded the minBid it can forge
208 return true, nil
209 } else if a.Vars.BootCoordinator == forger && slotState.BidAmount.Cmp(minBid) == -1 {
210 // if it's the boot coordinator and it has not been bid or the
211 // bid is below the minimum it can forge
212 return true, nil
213 } else {
214 return false, nil
215 }
216}
217
218// EthereumBlock stores all the generic data related to the an ethereum block
219type EthereumBlock struct {
220 BlockNum int64
221 Time int64
222 Hash ethCommon.Hash
223 ParentHash ethCommon.Hash
224 Tokens map[ethCommon.Address]eth.ERC20Consts
225 Nonce uint64
226 // state ethState
227}
228
229// Block represents a ethereum block
230type Block struct {
231 Rollup *RollupBlock
232 Auction *AuctionBlock
233 WDelayer *WDelayerBlock
234 Eth *EthereumBlock
235}
236
237func (b *Block) copy() *Block {
238 bCopyRaw, err := copystructure.Copy(b)
239 if err != nil {
240 panic(err)
241 }
242 bCopy := bCopyRaw.(*Block)
243 return bCopy
244}
245
246// Next prepares the successive block.
247func (b *Block) Next() *Block {
248 blockNext := b.copy()
249 blockNext.Rollup.Events = eth.NewRollupEvents()
250 blockNext.Auction.Events = eth.NewAuctionEvents()
251
252 blockNext.Eth.BlockNum = b.Eth.BlockNum + 1
253 blockNext.Eth.ParentHash = b.Eth.Hash
254
255 blockNext.Rollup.Constants = b.Rollup.Constants
256 blockNext.Auction.Constants = b.Auction.Constants
257 blockNext.WDelayer.Constants = b.WDelayer.Constants
258 blockNext.Rollup.Eth = blockNext.Eth
259 blockNext.Auction.Eth = blockNext.Eth
260 blockNext.WDelayer.Eth = blockNext.Eth
261
262 return blockNext
263}
264
265// ClientSetup is used to initialize the constants of the Smart Contracts and
266// other details of the test Client
267type ClientSetup struct {
268 RollupConstants *common.RollupConstants
269 RollupVariables *common.RollupVariables
270 AuctionConstants *common.AuctionConstants
271 AuctionVariables *common.AuctionVariables
272 WDelayerConstants *common.WDelayerConstants
273 WDelayerVariables *common.WDelayerVariables
274 VerifyProof bool
275}
276
277// NewClientSetupExample returns a ClientSetup example with hardcoded realistic
278// values. With this setup, the rollup genesis will be block 1, and block 0
279// and 1 will be premined.
280//nolint:gomnd
281func NewClientSetupExample() *ClientSetup {
282 // rfield, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
283 // if !ok {
284 // panic("bad rfield")
285 // }
286 initialMinimalBidding, ok := new(big.Int).SetString("10000000000000000000", 10) // 10 * (1e18)
287 if !ok {
288 panic("bad initialMinimalBidding")
289 }
290 tokenHEZ := ethCommon.HexToAddress("0x51D243D62852Bba334DD5cc33f242BAc8c698074")
291 governanceAddress := ethCommon.HexToAddress("0x688EfD95BA4391f93717CF02A9aED9DBD2855cDd")
292 rollupConstants := &common.RollupConstants{
293 Verifiers: []common.RollupVerifierStruct{
294 {
295 MaxTx: 2048,
296 NLevels: 32,
297 },
298 },
299 TokenHEZ: tokenHEZ,
300 HermezGovernanceAddress: governanceAddress,
301 HermezAuctionContract: ethCommon.HexToAddress("0x8E442975805fb1908f43050c9C1A522cB0e28D7b"),
302 WithdrawDelayerContract: ethCommon.HexToAddress("0x5CB7979cBdbf65719BEE92e4D15b7b7Ed3D79114"),
303 }
304 var buckets [common.RollupConstNumBuckets]common.BucketParams
305 for i := range buckets {
306 buckets[i] = common.BucketParams{
307 CeilUSD: big.NewInt(0),
308 Withdrawals: big.NewInt(0),
309 BlockWithdrawalRate: big.NewInt(0),
310 MaxWithdrawals: big.NewInt(0),
311 }
312 }
313 rollupVariables := &common.RollupVariables{
314 FeeAddToken: big.NewInt(11),
315 ForgeL1L2BatchTimeout: 9,
316 WithdrawalDelay: 80,
317 Buckets: buckets,
318 }
319 auctionConstants := &common.AuctionConstants{
320 BlocksPerSlot: 40,
321 InitialMinimalBidding: initialMinimalBidding,
322 GenesisBlockNum: 1,
323 GovernanceAddress: governanceAddress,
324 TokenHEZ: tokenHEZ,
325 HermezRollup: ethCommon.HexToAddress("0x474B6e29852257491cf283EfB1A9C61eBFe48369"),
326 }
327 auctionVariables := &common.AuctionVariables{
328 DonationAddress: ethCommon.HexToAddress("0x61Ed87CF0A1496b49A420DA6D84B58196b98f2e7"),
329 BootCoordinator: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
330 BootCoordinatorURL: "https://boot.coordinator.com",
331 DefaultSlotSetBid: [6]*big.Int{
332 initialMinimalBidding, initialMinimalBidding, initialMinimalBidding,
333 initialMinimalBidding, initialMinimalBidding, initialMinimalBidding,
334 },
335 ClosedAuctionSlots: 2,
336 OpenAuctionSlots: 4320,
337 AllocationRatio: [3]uint16{4000, 4000, 2000},
338 Outbidding: 1000,
339 SlotDeadline: 20,
340 }
341 wDelayerConstants := &common.WDelayerConstants{
342 MaxWithdrawalDelay: 60 * 60 * 24 * 7 * 2, // 2 weeks
343 MaxEmergencyModeTime: 60 * 60 * 24 * 7 * 26, // 26 weeks
344 HermezRollup: auctionConstants.HermezRollup,
345 }
346 wDelayerVariables := &common.WDelayerVariables{
347 HermezGovernanceAddress: ethCommon.HexToAddress("0xcfD0d163AE6432a72682323E2C3A5a69e6B37D12"),
348 EmergencyCouncilAddress: ethCommon.HexToAddress("0x2730700932a4FDB97B9268A3Ca29f97Ea5fd7EA0"),
349 WithdrawalDelay: 60,
350 EmergencyModeStartingBlock: 0,
351 EmergencyMode: false,
352 }
353 return &ClientSetup{
354 RollupConstants: rollupConstants,
355 RollupVariables: rollupVariables,
356 AuctionConstants: auctionConstants,
357 AuctionVariables: auctionVariables,
358 WDelayerConstants: wDelayerConstants,
359 WDelayerVariables: wDelayerVariables,
360 }
361}
362
363// Timer is an interface to simulate a source of time, useful to advance time
364// virtually.
365type Timer interface {
366 Time() int64
367}
368
369// type forgeBatchArgs struct {
370// ethTx *types.Transaction
371// blockNum int64
372// blockHash ethCommon.Hash
373// }
374
375type batch struct {
376 ForgeBatchArgs eth.RollupForgeBatchArgs
377 Sender ethCommon.Address
378}
379
380// Client implements the eth.ClientInterface interface, allowing to manipulate the
381// values for testing, working with deterministic results.
382type Client struct {
383 rw *sync.RWMutex
384 log bool
385 addr *ethCommon.Address
386 rollupConstants *common.RollupConstants
387 auctionConstants *common.AuctionConstants
388 wDelayerConstants *common.WDelayerConstants
389 blocks map[int64]*Block
390 // state state
391 blockNum int64 // last mined block num
392 maxBlockNum int64 // highest block num calculated
393 timer Timer
394 hasher hasher
395
396 forgeBatchArgsPending map[ethCommon.Hash]*batch
397 forgeBatchArgs map[ethCommon.Hash]*batch
398}
399
400// NewClient returns a new test Client that implements the eth.IClient
401// interface, at the given initialBlockNumber.
402func NewClient(l bool, timer Timer, addr *ethCommon.Address, setup *ClientSetup) *Client {
403 blocks := make(map[int64]*Block)
404 blockNum := int64(0)
405
406 hasher := hasher{}
407 // Add ethereum genesis block
408 mapL1TxQueue := make(map[int64]*eth.QueueStruct)
409 mapL1TxQueue[0] = eth.NewQueueStruct()
410 mapL1TxQueue[1] = eth.NewQueueStruct()
411 blockCurrent := &Block{
412 Rollup: &RollupBlock{
413 State: eth.RollupState{
414 StateRoot: big.NewInt(0),
415 ExitRoots: make([]*big.Int, 1),
416 ExitNullifierMap: make(map[int64]map[int64]bool),
417 // TokenID = 0 is ETH. Set first entry in TokenList with 0x0 address for ETH.
418 TokenList: []ethCommon.Address{{}},
419 TokenMap: make(map[ethCommon.Address]bool),
420 MapL1TxQueue: mapL1TxQueue,
421 LastL1L2Batch: 0,
422 CurrentToForgeL1TxsNum: 0,
423 LastToForgeL1TxsNum: 1,
424 CurrentIdx: 0,
425 },
426 Vars: *setup.RollupVariables,
427 Txs: make(map[ethCommon.Hash]*types.Transaction),
428 Events: eth.NewRollupEvents(),
429 Constants: setup.RollupConstants,
430 },
431 Auction: &AuctionBlock{
432 State: eth.AuctionState{
433 Slots: make(map[int64]*eth.SlotState),
434 PendingBalances: make(map[ethCommon.Address]*big.Int),
435 Coordinators: make(map[ethCommon.Address]*eth.Coordinator),
436 },
437 Vars: *setup.AuctionVariables,
438 Txs: make(map[ethCommon.Hash]*types.Transaction),
439 Events: eth.NewAuctionEvents(),
440 Constants: setup.AuctionConstants,
441 },
442 WDelayer: &WDelayerBlock{
443 // State: TODO
444 Vars: *setup.WDelayerVariables,
445 Txs: make(map[ethCommon.Hash]*types.Transaction),
446 Events: eth.NewWDelayerEvents(),
447 Constants: setup.WDelayerConstants,
448 },
449 Eth: &EthereumBlock{
450 BlockNum: blockNum,
451 Time: timer.Time(),
452 Hash: hasher.Next(),
453 ParentHash: ethCommon.Hash{},
454 Tokens: make(map[ethCommon.Address]eth.ERC20Consts),
455 },
456 }
457 blockCurrent.Rollup.Eth = blockCurrent.Eth
458 blockCurrent.Auction.Eth = blockCurrent.Eth
459 blocks[blockNum] = blockCurrent
460 blockNext := blockCurrent.Next()
461 blocks[blockNum+1] = blockNext
462
463 c := Client{
464 rw: &sync.RWMutex{},
465 log: l,
466 addr: addr,
467 rollupConstants: setup.RollupConstants,
468 auctionConstants: setup.AuctionConstants,
469 wDelayerConstants: setup.WDelayerConstants,
470 blocks: blocks,
471 timer: timer,
472 hasher: hasher,
473 forgeBatchArgsPending: make(map[ethCommon.Hash]*batch),
474 forgeBatchArgs: make(map[ethCommon.Hash]*batch),
475 blockNum: blockNum,
476 maxBlockNum: blockNum,
477 }
478
479 for i := int64(1); i < setup.AuctionConstants.GenesisBlockNum+1; i++ {
480 c.CtlMineBlock()
481 }
482
483 return &c
484}
485
486//
487// Mock Control
488//
489
490func (c *Client) setNextBlock(block *Block) {
491 c.blocks[c.blockNum+1] = block
492}
493
494func (c *Client) revertIfErr(err error, block *Block) {
495 if err != nil {
496 log.Infow("TestClient revert", "block", block.Eth.BlockNum, "err", err)
497 c.setNextBlock(block)
498 }
499}
500
501// Debugf calls log.Debugf if c.log is true
502func (c *Client) Debugf(template string, args ...interface{}) {
503 if c.log {
504 log.Debugf(template, args...)
505 }
506}
507
508// Debugw calls log.Debugw if c.log is true
509func (c *Client) Debugw(template string, kv ...interface{}) {
510 if c.log {
511 log.Debugw(template, kv...)
512 }
513}
514
515type hasher struct {
516 counter uint64
517}
518
519// Next returns the next hash
520func (h *hasher) Next() ethCommon.Hash {
521 var hash ethCommon.Hash
522 binary.LittleEndian.PutUint64(hash[:], h.counter)
523 h.counter++
524 return hash
525}
526
527func (c *Client) nextBlock() *Block {
528 return c.blocks[c.blockNum+1]
529}
530
531func (c *Client) currentBlock() *Block {
532 return c.blocks[c.blockNum]
533}
534
535// CtlSetAddr sets the address of the client
536func (c *Client) CtlSetAddr(addr ethCommon.Address) {
537 c.addr = &addr
538}
539
540// CtlMineBlock moves one block forward
541func (c *Client) CtlMineBlock() {
542 c.rw.Lock()
543 defer c.rw.Unlock()
544
545 blockCurrent := c.nextBlock()
546 c.blockNum++
547 c.maxBlockNum = c.blockNum
548 blockCurrent.Eth.Time = c.timer.Time()
549 blockCurrent.Eth.Hash = c.hasher.Next()
550 for ethTxHash, forgeBatchArgs := range c.forgeBatchArgsPending {
551 c.forgeBatchArgs[ethTxHash] = forgeBatchArgs
552 }
553 c.forgeBatchArgsPending = make(map[ethCommon.Hash]*batch)
554
555 blockNext := blockCurrent.Next()
556 c.blocks[c.blockNum+1] = blockNext
557 c.Debugw("TestClient mined block", "blockNum", c.blockNum)
558}
559
560// CtlRollback discards the last mined block. Use this to replace a mined
561// block to simulate reorgs.
562func (c *Client) CtlRollback() {
563 c.rw.Lock()
564 defer c.rw.Unlock()
565
566 if c.blockNum == 0 {
567 panic("Can't rollback at blockNum = 0")
568 }
569 delete(c.blocks, c.blockNum+1) // delete next block
570 delete(c.blocks, c.blockNum) // delete current block
571 c.blockNum--
572 blockCurrent := c.blocks[c.blockNum]
573 blockNext := blockCurrent.Next()
574 c.blocks[c.blockNum+1] = blockNext
575}
576
577//
578// Ethereum
579//
580
581// CtlLastBlock returns the last blockNum without checks
582func (c *Client) CtlLastBlock() *common.Block {
583 c.rw.RLock()
584 defer c.rw.RUnlock()
585
586 block := c.blocks[c.blockNum]
587 return &common.Block{
588 Num: c.blockNum,
589 Timestamp: time.Unix(block.Eth.Time, 0),
590 Hash: block.Eth.Hash,
591 ParentHash: block.Eth.ParentHash,
592 }
593}
594
595// CtlLastForgedBatch returns the last batchNum without checks
596func (c *Client) CtlLastForgedBatch() int64 {
597 c.rw.RLock()
598 defer c.rw.RUnlock()
599
600 currentBlock := c.currentBlock()
601 e := currentBlock.Rollup
602 return int64(len(e.State.ExitRoots)) - 1
603}
604
605// EthLastBlock returns the last blockNum
606func (c *Client) EthLastBlock() (int64, error) {
607 c.rw.RLock()
608 defer c.rw.RUnlock()
609
610 if c.blockNum < c.maxBlockNum {
611 panic("blockNum has decreased. " +
612 "After a rollback you must mine to reach the same or higher blockNum")
613 }
614 return c.blockNum, nil
615}
616
617// EthTransactionReceipt returns the transaction receipt of the given txHash
618func (c *Client) EthTransactionReceipt(ctx context.Context, txHash ethCommon.Hash) (*types.Receipt, error) {
619 c.rw.RLock()
620 defer c.rw.RUnlock()
621
622 for i := int64(0); i < c.blockNum; i++ {
623 b := c.blocks[i]
624 _, ok := b.Rollup.Txs[txHash]
625 if !ok {
626 _, ok = b.Auction.Txs[txHash]
627 }
628 if ok {
629 return &types.Receipt{
630 TxHash: txHash,
631 Status: types.ReceiptStatusSuccessful,
632 BlockHash: b.Eth.Hash,
633 BlockNumber: big.NewInt(b.Eth.BlockNum),
634 }, nil
635 }
636 }
637
638 return nil, nil
639}
640
641// CtlAddERC20 adds an ERC20 token to the blockchain.
642func (c *Client) CtlAddERC20(tokenAddr ethCommon.Address, constants eth.ERC20Consts) {
643 nextBlock := c.nextBlock()
644 e := nextBlock.Eth
645 e.Tokens[tokenAddr] = constants
646}
647
648// EthERC20Consts returns the constants defined for a particular ERC20 Token instance.
649func (c *Client) EthERC20Consts(tokenAddr ethCommon.Address) (*eth.ERC20Consts, error) {
650 currentBlock := c.currentBlock()
651 e := currentBlock.Eth
652 if constants, ok := e.Tokens[tokenAddr]; ok {
653 return &constants, nil
654 }
655 return nil, tracerr.Wrap(fmt.Errorf("tokenAddr not found"))
656}
657
658// func newHeader(number *big.Int) *types.Header {
659// return &types.Header{
660// Number: number,
661// Time: uint64(number.Int64()),
662// }
663// }
664
665// EthHeaderByNumber returns the *types.Header for the given block number in a
666// deterministic way.
667// func (c *Client) EthHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
668// return newHeader(number), nil
669// }
670
671// EthBlockByNumber returns the *common.Block for the given block number in a
672// deterministic way. If number == -1, the latests known block is returned.
673func (c *Client) EthBlockByNumber(ctx context.Context, blockNum int64) (*common.Block, error) {
674 c.rw.RLock()
675 defer c.rw.RUnlock()
676
677 if blockNum > c.blockNum {
678 return nil, ethereum.NotFound
679 }
680 if blockNum == -1 {
681 blockNum = c.blockNum
682 }
683 block := c.blocks[blockNum]
684 return &common.Block{
685 Num: blockNum,
686 Timestamp: time.Unix(block.Eth.Time, 0),
687 Hash: block.Eth.Hash,
688 ParentHash: block.Eth.ParentHash,
689 }, nil
690}
691
692// EthAddress returns the ethereum address of the account loaded into the Client
693func (c *Client) EthAddress() (*ethCommon.Address, error) {
694 if c.addr == nil {
695 return nil, tracerr.Wrap(eth.ErrAccountNil)
696 }
697 return c.addr, nil
698}
699
700var errTODO = fmt.Errorf("TODO: Not implemented yet")
701
702//
703// Rollup
704//
705
706// CtlAddL1TxUser adds an L1TxUser to the L1UserTxs queue of the Rollup
707// func (c *Client) CtlAddL1TxUser(l1Tx *common.L1Tx) {
708// c.rw.Lock()
709// defer c.rw.Unlock()
710//
711// nextBlock := c.nextBlock()
712// r := nextBlock.Rollup
713// queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
714// if len(queue.L1TxQueue) >= eth.RollupConstMaxL1UserTx {
715// r.State.LastToForgeL1TxsNum++
716// r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
717// queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
718// }
719// if int64(l1Tx.FromIdx) > r.State.CurrentIdx {
720// panic("l1Tx.FromIdx > r.State.CurrentIdx")
721// }
722// if int(l1Tx.TokenID)+1 > len(r.State.TokenList) {
723// panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
724// }
725// queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
726// r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
727// L1Tx: *l1Tx,
728// ToForgeL1TxsNum: r.State.LastToForgeL1TxsNum,
729// Position: len(queue.L1TxQueue) - 1,
730// })
731// }
732
733// RollupL1UserTxERC20Permit is the interface to call the smart contract function
734func (c *Client) RollupL1UserTxERC20Permit(fromBJJ babyjub.PublicKeyComp, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) {
735 log.Error("TODO")
736 return nil, tracerr.Wrap(errTODO)
737}
738
739// RollupL1UserTxERC20ETH sends an L1UserTx to the Rollup.
740func (c *Client) RollupL1UserTxERC20ETH(
741 fromBJJ babyjub.PublicKeyComp,
742 fromIdx int64,
743 depositAmount *big.Int,
744 amount *big.Int,
745 tokenID uint32,
746 toIdx int64,
747) (tx *types.Transaction, err error) {
748 c.rw.Lock()
749 defer c.rw.Unlock()
750 cpy := c.nextBlock().copy()
751 defer func() { c.revertIfErr(err, cpy) }()
752
753 _, err = common.NewFloat16(amount)
754 if err != nil {
755 return nil, tracerr.Wrap(err)
756 }
757 _, err = common.NewFloat16(depositAmount)
758 if err != nil {
759 return nil, tracerr.Wrap(err)
760 }
761
762 nextBlock := c.nextBlock()
763 r := nextBlock.Rollup
764 queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
765 if len(queue.L1TxQueue) >= common.RollupConstMaxL1UserTx {
766 r.State.LastToForgeL1TxsNum++
767 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
768 queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
769 }
770 if fromIdx > r.State.CurrentIdx {
771 panic("l1Tx.FromIdx > r.State.CurrentIdx")
772 }
773 if int(tokenID)+1 > len(r.State.TokenList) {
774 panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
775 }
776 toForgeL1TxsNum := r.State.LastToForgeL1TxsNum
777 l1Tx, err := common.NewL1Tx(&common.L1Tx{
778 FromIdx: common.Idx(fromIdx),
779 FromEthAddr: *c.addr,
780 FromBJJ: fromBJJ,
781 Amount: amount,
782 DepositAmount: depositAmount,
783 TokenID: common.TokenID(tokenID),
784 ToIdx: common.Idx(toIdx),
785 ToForgeL1TxsNum: &toForgeL1TxsNum,
786 Position: len(queue.L1TxQueue),
787 UserOrigin: true,
788 })
789 if err != nil {
790 return nil, tracerr.Wrap(err)
791 }
792
793 queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
794 r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
795 L1UserTx: *l1Tx,
796 })
797 return r.addTransaction(c.newTransaction("l1UserTxERC20ETH", l1Tx)), nil
798}
799
800// RollupL1UserTxERC777 is the interface to call the smart contract function
801// func (c *Client) RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error) {
802// log.Error("TODO")
803// return nil, errTODO
804// }
805
806// RollupRegisterTokensCount is the interface to call the smart contract function
807func (c *Client) RollupRegisterTokensCount() (*big.Int, error) {
808 log.Error("TODO")
809 return nil, tracerr.Wrap(errTODO)
810}
811
812// RollupLastForgedBatch is the interface to call the smart contract function
813func (c *Client) RollupLastForgedBatch() (int64, error) {
814 c.rw.RLock()
815 defer c.rw.RUnlock()
816
817 currentBlock := c.currentBlock()
818 e := currentBlock.Rollup
819 return int64(len(e.State.ExitRoots)) - 1, nil
820}
821
822// RollupWithdrawCircuit is the interface to call the smart contract function
823func (c *Client) RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error) {
824 log.Error("TODO")
825 return nil, tracerr.Wrap(errTODO)
826}
827
828// RollupWithdrawMerkleProof is the interface to call the smart contract function
829func (c *Client) RollupWithdrawMerkleProof(babyPubKey babyjub.PublicKeyComp, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
830 c.rw.Lock()
831 defer c.rw.Unlock()
832 cpy := c.nextBlock().copy()
833 defer func() { c.revertIfErr(err, cpy) }()
834
835 nextBlock := c.nextBlock()
836 r := nextBlock.Rollup
837
838 if int(numExitRoot) >= len(r.State.ExitRoots) {
839 return nil, tracerr.Wrap(fmt.Errorf("numExitRoot >= len(r.State.ExitRoots)"))
840 }
841 if _, ok := r.State.ExitNullifierMap[numExitRoot][idx]; ok {
842 return nil, tracerr.Wrap(fmt.Errorf("exit already withdrawn"))
843 }
844 r.State.ExitNullifierMap[numExitRoot][idx] = true
845
846 babyPubKeyDecomp, err := babyPubKey.Decompress()
847 if err != nil {
848 return nil, tracerr.Wrap(err)
849 }
850
851 type data struct {
852 BabyPubKey *babyjub.PublicKey
853 TokenID uint32
854 NumExitRoot int64
855 Idx int64
856 Amount *big.Int
857 Siblings []*big.Int
858 InstantWithdraw bool
859 }
860 tx = r.addTransaction(c.newTransaction("withdrawMerkleProof", data{
861 BabyPubKey: babyPubKeyDecomp,
862 TokenID: tokenID,
863 NumExitRoot: numExitRoot,
864 Idx: idx,
865 Amount: amount,
866 Siblings: siblings,
867 InstantWithdraw: instantWithdraw,
868 }))
869 r.Events.Withdraw = append(r.Events.Withdraw, eth.RollupEventWithdraw{
870 Idx: uint64(idx),
871 NumExitRoot: uint64(numExitRoot),
872 InstantWithdraw: instantWithdraw,
873 TxHash: tx.Hash(),
874 })
875
876 if !instantWithdraw {
877 w := nextBlock.WDelayer
878 w.deposit(tx.Hash(), *c.addr, r.State.TokenList[int(tokenID)], amount)
879 }
880 return tx, nil
881}
882
883type transactionData struct {
884 Name string
885 Value interface{}
886}
887
888func (c *Client) newTransaction(name string, value interface{}) *types.Transaction {
889 eth := c.nextBlock().Eth
890 nonce := eth.Nonce
891 eth.Nonce++
892 data, err := json.Marshal(transactionData{name, value})
893 if err != nil {
894 panic(err)
895 }
896 return types.NewTransaction(nonce, ethCommon.Address{}, nil, 0, nil,
897 data)
898}
899
900// RollupForgeBatch is the interface to call the smart contract function
901func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Transaction, err error) {
902 c.rw.Lock()
903 defer c.rw.Unlock()
904 cpy := c.nextBlock().copy()
905 defer func() { c.revertIfErr(err, cpy) }()
906 if c.addr == nil {
907 return nil, tracerr.Wrap(eth.ErrAccountNil)
908 }
909
910 a := c.nextBlock().Auction
911 ok, err := a.canForge(*c.addr, a.Eth.BlockNum)
912 if err != nil {
913 return nil, tracerr.Wrap(err)
914 }
915 if !ok {
916 return nil, tracerr.Wrap(fmt.Errorf(common.AuctionErrMsgCannotForge))
917 }
918
919 // TODO: Verify proof
920
921 // Auction
922 err = a.forge(*c.addr)
923 if err != nil {
924 return nil, tracerr.Wrap(err)
925 }
926
927 // TODO: If successful, store the tx in a successful array.
928 // TODO: If failed, store the tx in a failed array.
929 // TODO: Add method to move the tx to another block, reapply it there, and possibly go from successful to failed.
930
931 return c.addBatch(args)
932}
933
934// CtlAddBatch adds forged batch to the Rollup, without checking any ZKProof
935func (c *Client) CtlAddBatch(args *eth.RollupForgeBatchArgs) {
936 c.rw.Lock()
937 defer c.rw.Unlock()
938
939 if _, err := c.addBatch(args); err != nil {
940 panic(err)
941 }
942}
943
944func (c *Client) addBatch(args *eth.RollupForgeBatchArgs) (*types.Transaction, error) {
945 nextBlock := c.nextBlock()
946 r := nextBlock.Rollup
947 r.State.StateRoot = args.NewStRoot
948 if args.NewLastIdx < r.State.CurrentIdx {
949 return nil, tracerr.Wrap(fmt.Errorf("args.NewLastIdx < r.State.CurrentIdx"))
950 }
951 r.State.CurrentIdx = args.NewLastIdx
952 r.State.ExitNullifierMap[int64(len(r.State.ExitRoots))] = make(map[int64]bool)
953 r.State.ExitRoots = append(r.State.ExitRoots, args.NewExitRoot)
954 if args.L1Batch {
955 r.State.CurrentToForgeL1TxsNum++
956 if r.State.CurrentToForgeL1TxsNum == r.State.LastToForgeL1TxsNum {
957 r.State.LastToForgeL1TxsNum++
958 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
959 }
960 }
961 ethTx := r.addTransaction(c.newTransaction("forgebatch", args))
962 c.forgeBatchArgsPending[ethTx.Hash()] = &batch{*args, *c.addr}
963 r.Events.ForgeBatch = append(r.Events.ForgeBatch, eth.RollupEventForgeBatch{
964 BatchNum: int64(len(r.State.ExitRoots)) - 1,
965 EthTxHash: ethTx.Hash(),
966 L1UserTxsLen: uint16(len(args.L1UserTxs)),
967 })
968
969 return ethTx, nil
970}
971
972// RollupAddTokenSimple is a wrapper around RollupAddToken that automatically
973// sets `deadlie`.
974func (c *Client) RollupAddTokenSimple(tokenAddress ethCommon.Address, feeAddToken *big.Int) (tx *types.Transaction, err error) {
975 return c.RollupAddToken(tokenAddress, feeAddToken, big.NewInt(9999)) //nolint:gomnd
976}
977
978// RollupAddToken is the interface to call the smart contract function
979func (c *Client) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int,
980 deadline *big.Int) (tx *types.Transaction, err error) {
981 c.rw.Lock()
982 defer c.rw.Unlock()
983 cpy := c.nextBlock().copy()
984 defer func() { c.revertIfErr(err, cpy) }()
985 if c.addr == nil {
986 return nil, tracerr.Wrap(eth.ErrAccountNil)
987 }
988
989 nextBlock := c.nextBlock()
990 r := nextBlock.Rollup
991 if _, ok := r.State.TokenMap[tokenAddress]; ok {
992 return nil, tracerr.Wrap(fmt.Errorf("Token %v already registered", tokenAddress))
993 }
994 if feeAddToken.Cmp(r.Vars.FeeAddToken) != 0 {
995 return nil, tracerr.Wrap(fmt.Errorf("Expected fee: %v but got: %v", r.Vars.FeeAddToken, feeAddToken))
996 }
997
998 r.State.TokenMap[tokenAddress] = true
999 r.State.TokenList = append(r.State.TokenList, tokenAddress)
1000 r.Events.AddToken = append(r.Events.AddToken, eth.RollupEventAddToken{TokenAddress: tokenAddress,
1001 TokenID: uint32(len(r.State.TokenList) - 1)})
1002 return r.addTransaction(c.newTransaction("addtoken", tokenAddress)), nil
1003}
1004
1005// RollupGetCurrentTokens is the interface to call the smart contract function
1006func (c *Client) RollupGetCurrentTokens() (*big.Int, error) {
1007 c.rw.RLock()
1008 defer c.rw.RUnlock()
1009
1010 log.Error("TODO")
1011 return nil, tracerr.Wrap(errTODO)
1012}
1013
1014// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
1015func (c *Client) RollupUpdateForgeL1L2BatchTimeout(newForgeL1Timeout int64) (tx *types.Transaction, err error) {
1016 c.rw.Lock()
1017 defer c.rw.Unlock()
1018 cpy := c.nextBlock().copy()
1019 defer func() { c.revertIfErr(err, cpy) }()
1020 if c.addr == nil {
1021 return nil, tracerr.Wrap(eth.ErrAccountNil)
1022 }
1023
1024 nextBlock := c.nextBlock()
1025 r := nextBlock.Rollup
1026 r.Vars.ForgeL1L2BatchTimeout = newForgeL1Timeout
1027 r.Events.UpdateForgeL1L2BatchTimeout = append(r.Events.UpdateForgeL1L2BatchTimeout,
1028 eth.RollupEventUpdateForgeL1L2BatchTimeout{NewForgeL1L2BatchTimeout: newForgeL1Timeout})
1029
1030 return r.addTransaction(c.newTransaction("updateForgeL1L2BatchTimeout", newForgeL1Timeout)), nil
1031}
1032
1033// RollupUpdateFeeAddToken is the interface to call the smart contract function
1034func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
1035 c.rw.Lock()
1036 defer c.rw.Unlock()
1037 cpy := c.nextBlock().copy()
1038 defer func() { c.revertIfErr(err, cpy) }()
1039 if c.addr == nil {
1040 return nil, tracerr.Wrap(eth.ErrAccountNil)
1041 }
1042
1043 log.Error("TODO")
1044 return nil, tracerr.Wrap(errTODO)
1045}
1046
1047// RollupUpdateTokensHEZ is the interface to call the smart contract function
1048// func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (tx *types.Transaction, err error) {
1049// c.rw.Lock()
1050// defer c.rw.Unlock()
1051// cpy := c.nextBlock().copy()
1052// defer func() { c.revertIfErr(err, cpy) }()
1053//
1054// log.Error("TODO")
1055// return nil, errTODO
1056// }
1057
1058// RollupUpdateGovernance is the interface to call the smart contract function
1059// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
1060// return nil, errTODO
1061// }
1062
1063// RollupConstants returns the Constants of the Rollup Smart Contract
1064func (c *Client) RollupConstants() (*common.RollupConstants, error) {
1065 c.rw.RLock()
1066 defer c.rw.RUnlock()
1067
1068 return c.rollupConstants, nil
1069}
1070
1071// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
1072func (c *Client) RollupEventsByBlock(blockNum int64) (*eth.RollupEvents, *ethCommon.Hash, error) {
1073 c.rw.RLock()
1074 defer c.rw.RUnlock()
1075
1076 block, ok := c.blocks[blockNum]
1077 if !ok {
1078 return nil, nil, tracerr.Wrap(fmt.Errorf("Block %v doesn't exist", blockNum))
1079 }
1080 return &block.Rollup.Events, &block.Eth.Hash, nil
1081}
1082
1083// RollupEventInit returns the initialize event with its corresponding block number
1084func (c *Client) RollupEventInit() (*eth.RollupEventInitialize, int64, error) {
1085 vars := c.blocks[0].Rollup.Vars
1086 return ð.RollupEventInitialize{
1087 ForgeL1L2BatchTimeout: uint8(vars.ForgeL1L2BatchTimeout),
1088 FeeAddToken: vars.FeeAddToken,
1089 WithdrawalDelay: vars.WithdrawalDelay,
1090 }, 1, nil
1091}
1092
1093// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction
1094func (c *Client) RollupForgeBatchArgs(ethTxHash ethCommon.Hash, l1UserTxsLen uint16) (*eth.RollupForgeBatchArgs, *ethCommon.Address, error) {
1095 c.rw.RLock()
1096 defer c.rw.RUnlock()
1097
1098 batch, ok := c.forgeBatchArgs[ethTxHash]
1099 if !ok {
1100 return nil, nil, tracerr.Wrap(fmt.Errorf("transaction not found"))
1101 }
1102 return &batch.ForgeBatchArgs, &batch.Sender, nil
1103}
1104
1105//
1106// Auction
1107//
1108
1109// AuctionSetSlotDeadline is the interface to call the smart contract function
1110func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (tx *types.Transaction, err error) {
1111 c.rw.Lock()
1112 defer c.rw.Unlock()
1113 cpy := c.nextBlock().copy()
1114 defer func() { c.revertIfErr(err, cpy) }()
1115 if c.addr == nil {
1116 return nil, tracerr.Wrap(eth.ErrAccountNil)
1117 }
1118
1119 log.Error("TODO")
1120 return nil, tracerr.Wrap(errTODO)
1121}
1122
1123// AuctionGetSlotDeadline is the interface to call the smart contract function
1124func (c *Client) AuctionGetSlotDeadline() (uint8, error) {
1125 c.rw.RLock()
1126 defer c.rw.RUnlock()
1127
1128 log.Error("TODO")
1129 return 0, tracerr.Wrap(errTODO)
1130}
1131
1132// AuctionSetOpenAuctionSlots is the interface to call the smart contract function
1133func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (tx *types.Transaction, err error) {
1134 c.rw.Lock()
1135 defer c.rw.Unlock()
1136 cpy := c.nextBlock().copy()
1137 defer func() { c.revertIfErr(err, cpy) }()
1138 if c.addr == nil {
1139 return nil, tracerr.Wrap(eth.ErrAccountNil)
1140 }
1141
1142 nextBlock := c.nextBlock()
1143 a := nextBlock.Auction
1144 a.Vars.OpenAuctionSlots = newOpenAuctionSlots
1145 a.Events.NewOpenAuctionSlots = append(a.Events.NewOpenAuctionSlots,
1146 eth.AuctionEventNewOpenAuctionSlots{NewOpenAuctionSlots: newOpenAuctionSlots})
1147
1148 return a.addTransaction(c.newTransaction("setOpenAuctionSlots", newOpenAuctionSlots)), nil
1149}
1150
1151// AuctionGetOpenAuctionSlots is the interface to call the smart contract function
1152func (c *Client) AuctionGetOpenAuctionSlots() (uint16, error) {
1153 c.rw.RLock()
1154 defer c.rw.RUnlock()
1155
1156 log.Error("TODO")
1157 return 0, tracerr.Wrap(errTODO)
1158}
1159
1160// AuctionSetClosedAuctionSlots is the interface to call the smart contract function
1161func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (tx *types.Transaction, err error) {
1162 c.rw.Lock()
1163 defer c.rw.Unlock()
1164 cpy := c.nextBlock().copy()
1165 defer func() { c.revertIfErr(err, cpy) }()
1166 if c.addr == nil {
1167 return nil, tracerr.Wrap(eth.ErrAccountNil)
1168 }
1169
1170 log.Error("TODO")
1171 return nil, tracerr.Wrap(errTODO)
1172}
1173
1174// AuctionGetClosedAuctionSlots is the interface to call the smart contract function
1175func (c *Client) AuctionGetClosedAuctionSlots() (uint16, error) {
1176 c.rw.RLock()
1177 defer c.rw.RUnlock()
1178
1179 log.Error("TODO")
1180 return 0, tracerr.Wrap(errTODO)
1181}
1182
1183// AuctionSetOutbidding is the interface to call the smart contract function
1184func (c *Client) AuctionSetOutbidding(newOutbidding uint16) (tx *types.Transaction, err error) {
1185 c.rw.Lock()
1186 defer c.rw.Unlock()
1187 cpy := c.nextBlock().copy()
1188 defer func() { c.revertIfErr(err, cpy) }()
1189 if c.addr == nil {
1190 return nil, tracerr.Wrap(eth.ErrAccountNil)
1191 }
1192
1193 log.Error("TODO")
1194 return nil, tracerr.Wrap(errTODO)
1195}
1196
1197// AuctionGetOutbidding is the interface to call the smart contract function
1198func (c *Client) AuctionGetOutbidding() (uint16, error) {
1199 c.rw.RLock()
1200 defer c.rw.RUnlock()
1201
1202 log.Error("TODO")
1203 return 0, tracerr.Wrap(errTODO)
1204}
1205
1206// AuctionSetAllocationRatio is the interface to call the smart contract function
1207func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (tx *types.Transaction, err error) {
1208 c.rw.Lock()
1209 defer c.rw.Unlock()
1210 cpy := c.nextBlock().copy()
1211 defer func() { c.revertIfErr(err, cpy) }()
1212 if c.addr == nil {
1213 return nil, tracerr.Wrap(eth.ErrAccountNil)
1214 }
1215
1216 log.Error("TODO")
1217 return nil, tracerr.Wrap(errTODO)
1218}
1219
1220// AuctionGetAllocationRatio is the interface to call the smart contract function
1221func (c *Client) AuctionGetAllocationRatio() ([3]uint16, error) {
1222 c.rw.RLock()
1223 defer c.rw.RUnlock()
1224
1225 log.Error("TODO")
1226 return [3]uint16{}, tracerr.Wrap(errTODO)
1227}
1228
1229// AuctionSetDonationAddress is the interface to call the smart contract function
1230func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (tx *types.Transaction, err error) {
1231 c.rw.Lock()
1232 defer c.rw.Unlock()
1233 cpy := c.nextBlock().copy()
1234 defer func() { c.revertIfErr(err, cpy) }()
1235 if c.addr == nil {
1236 return nil, tracerr.Wrap(eth.ErrAccountNil)
1237 }
1238
1239 log.Error("TODO")
1240 return nil, tracerr.Wrap(errTODO)
1241}
1242
1243// AuctionGetDonationAddress is the interface to call the smart contract function
1244func (c *Client) AuctionGetDonationAddress() (*ethCommon.Address, error) {
1245 c.rw.RLock()
1246 defer c.rw.RUnlock()
1247
1248 log.Error("TODO")
1249 return nil, tracerr.Wrap(errTODO)
1250}
1251
1252// AuctionSetBootCoordinator is the interface to call the smart contract function
1253func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address, newBootCoordinatorURL string) (tx *types.Transaction, err error) {
1254 c.rw.Lock()
1255 defer c.rw.Unlock()
1256 cpy := c.nextBlock().copy()
1257 defer func() { c.revertIfErr(err, cpy) }()
1258 if c.addr == nil {
1259 return nil, tracerr.Wrap(eth.ErrAccountNil)
1260 }
1261
1262 log.Error("TODO")
1263 return nil, tracerr.Wrap(errTODO)
1264}
1265
1266// AuctionGetBootCoordinator is the interface to call the smart contract function
1267func (c *Client) AuctionGetBootCoordinator() (*ethCommon.Address, error) {
1268 c.rw.RLock()
1269 defer c.rw.RUnlock()
1270
1271 currentBlock := c.currentBlock()
1272 a := currentBlock.Auction
1273
1274 return &a.Vars.BootCoordinator, nil
1275}
1276
1277// AuctionChangeDefaultSlotSetBid is the interface to call the smart contract function
1278func (c *Client) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (tx *types.Transaction, err error) {
1279 c.rw.Lock()
1280 defer c.rw.Unlock()
1281 cpy := c.nextBlock().copy()
1282 defer func() { c.revertIfErr(err, cpy) }()
1283 if c.addr == nil {
1284 return nil, tracerr.Wrap(eth.ErrAccountNil)
1285 }
1286
1287 log.Error("TODO")
1288 return nil, tracerr.Wrap(errTODO)
1289}
1290
1291// AuctionSetCoordinator is the interface to call the smart contract function
1292func (c *Client) AuctionSetCoordinator(forger ethCommon.Address, URL string) (tx *types.Transaction, err error) {
1293 c.rw.Lock()
1294 defer c.rw.Unlock()
1295 cpy := c.nextBlock().copy()
1296 defer func() { c.revertIfErr(err, cpy) }()
1297 if c.addr == nil {
1298 return nil, tracerr.Wrap(eth.ErrAccountNil)
1299 }
1300
1301 nextBlock := c.nextBlock()
1302 a := nextBlock.Auction
1303
1304 a.State.Coordinators[*c.addr] = ð.Coordinator{
1305 Forger: forger,
1306 URL: URL,
1307 }
1308
1309 a.Events.SetCoordinator = append(a.Events.SetCoordinator,
1310 eth.AuctionEventSetCoordinator{
1311 BidderAddress: *c.addr,
1312 ForgerAddress: forger,
1313 CoordinatorURL: URL,
1314 })
1315
1316 type data struct {
1317 BidderAddress ethCommon.Address
1318 ForgerAddress ethCommon.Address
1319 URL string
1320 }
1321 return a.addTransaction(c.newTransaction("registercoordinator", data{*c.addr, forger, URL})), nil
1322}
1323
1324// AuctionIsRegisteredCoordinator is the interface to call the smart contract function
1325func (c *Client) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) {
1326 c.rw.RLock()
1327 defer c.rw.RUnlock()
1328
1329 log.Error("TODO")
1330 return false, tracerr.Wrap(errTODO)
1331}
1332
1333// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function
1334func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (tx *types.Transaction, err error) {
1335 c.rw.Lock()
1336 defer c.rw.Unlock()
1337 cpy := c.nextBlock().copy()
1338 defer func() { c.revertIfErr(err, cpy) }()
1339 if c.addr == nil {
1340 return nil, tracerr.Wrap(eth.ErrAccountNil)
1341 }
1342
1343 log.Error("TODO")
1344 return nil, tracerr.Wrap(errTODO)
1345}
1346
1347// AuctionGetSlotNumber is the interface to call the smart contract function
1348func (c *Client) AuctionGetSlotNumber(blockNum int64) (int64, error) {
1349 c.rw.RLock()
1350 defer c.rw.RUnlock()
1351
1352 currentBlock := c.currentBlock()
1353 a := currentBlock.Auction
1354 return a.getSlotNumber(blockNum), nil
1355}
1356
1357// AuctionGetCurrentSlotNumber is the interface to call the smart contract function
1358func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) {
1359 c.rw.RLock()
1360 defer c.rw.RUnlock()
1361
1362 log.Error("TODO")
1363 return 0, tracerr.Wrap(errTODO)
1364}
1365
1366// AuctionGetMinBidBySlot is the interface to call the smart contract function
1367func (c *Client) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) {
1368 c.rw.RLock()
1369 defer c.rw.RUnlock()
1370
1371 log.Error("TODO")
1372 return nil, tracerr.Wrap(errTODO)
1373}
1374
1375// AuctionGetDefaultSlotSetBid is the interface to call the smart contract function
1376func (c *Client) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) {
1377 c.rw.RLock()
1378 defer c.rw.RUnlock()
1379
1380 log.Error("TODO")
1381 return nil, tracerr.Wrap(errTODO)
1382}
1383
1384// AuctionGetSlotSet is the interface to call the smart contract function
1385func (c *Client) AuctionGetSlotSet(slot int64) (*big.Int, error) {
1386 c.rw.RLock()
1387 defer c.rw.RUnlock()
1388
1389 log.Error("TODO")
1390 return nil, tracerr.Wrap(errTODO)
1391}
1392
1393// AuctionTokensReceived is the interface to call the smart contract function
1394// func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error {
1395// return errTODO
1396// }
1397
1398// AuctionBidSimple is a wrapper around AuctionBid that automatically sets `amount` and `deadline`.
1399func (c *Client) AuctionBidSimple(slot int64, bidAmount *big.Int) (tx *types.Transaction, err error) {
1400 return c.AuctionBid(bidAmount, slot, bidAmount, big.NewInt(99999)) //nolint:gomnd
1401}
1402
1403// AuctionBid is the interface to call the smart contract function. This
1404// implementation behaves as if any address has infinite tokens.
1405func (c *Client) AuctionBid(amount *big.Int, slot int64, bidAmount *big.Int,
1406 deadline *big.Int) (tx *types.Transaction, err error) {
1407 c.rw.Lock()
1408 defer c.rw.Unlock()
1409 cpy := c.nextBlock().copy()
1410 defer func() { func() { c.revertIfErr(err, cpy) }() }()
1411 if c.addr == nil {
1412 return nil, tracerr.Wrap(eth.ErrAccountNil)
1413 }
1414
1415 nextBlock := c.nextBlock()
1416 a := nextBlock.Auction
1417
1418 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
1419 return nil, tracerr.Wrap(errBidClosed)
1420 }
1421
1422 if slot >= a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots)+int64(a.Vars.OpenAuctionSlots) {
1423 return nil, tracerr.Wrap(errBidNotOpen)
1424 }
1425
1426 minBid, err := a.getMinBidBySlot(slot)
1427 if err != nil {
1428 return nil, tracerr.Wrap(err)
1429 }
1430 if bidAmount.Cmp(minBid) == -1 {
1431 return nil, tracerr.Wrap(errBidBelowMin)
1432 }
1433
1434 if _, ok := a.State.Coordinators[*c.addr]; !ok {
1435 return nil, tracerr.Wrap(errCoordNotReg)
1436 }
1437
1438 slotState, ok := a.State.Slots[slot]
1439 if !ok {
1440 slotState = eth.NewSlotState()
1441 a.State.Slots[slot] = slotState
1442 }
1443 slotState.Bidder = *c.addr
1444 slotState.BidAmount = bidAmount
1445
1446 a.Events.NewBid = append(a.Events.NewBid,
1447 eth.AuctionEventNewBid{Slot: slot, BidAmount: bidAmount, Bidder: *c.addr})
1448
1449 type data struct {
1450 Slot int64
1451 BidAmount *big.Int
1452 Bidder ethCommon.Address
1453 }
1454 return a.addTransaction(c.newTransaction("bid", data{slot, bidAmount, *c.addr})), nil
1455}
1456
1457// AuctionMultiBid is the interface to call the smart contract function. This
1458// implementation behaves as if any address has infinite tokens.
1459func (c *Client) AuctionMultiBid(amount *big.Int, startingSlot int64, endingSlot int64, slotSet [6]bool,
1460 maxBid, closedMinBid, deadline *big.Int) (tx *types.Transaction, err error) {
1461 c.rw.Lock()
1462 defer c.rw.Unlock()
1463 cpy := c.nextBlock().copy()
1464 defer func() { c.revertIfErr(err, cpy) }()
1465 if c.addr == nil {
1466 return nil, tracerr.Wrap(eth.ErrAccountNil)
1467 }
1468
1469 log.Error("TODO")
1470 return nil, tracerr.Wrap(errTODO)
1471}
1472
1473// AuctionCanForge is the interface to call the smart contract function
1474func (c *Client) AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error) {
1475 c.rw.RLock()
1476 defer c.rw.RUnlock()
1477
1478 currentBlock := c.currentBlock()
1479 a := currentBlock.Auction
1480 return a.canForge(forger, blockNum)
1481}
1482
1483// AuctionForge is the interface to call the smart contract function
1484func (c *Client) AuctionForge(forger ethCommon.Address) (tx *types.Transaction, err error) {
1485 c.rw.Lock()
1486 defer c.rw.Unlock()
1487 cpy := c.nextBlock().copy()
1488 defer func() { c.revertIfErr(err, cpy) }()
1489 if c.addr == nil {
1490 return nil, tracerr.Wrap(eth.ErrAccountNil)
1491 }
1492
1493 log.Error("TODO")
1494 return nil, tracerr.Wrap(errTODO)
1495}
1496
1497// AuctionClaimHEZ is the interface to call the smart contract function
1498func (c *Client) AuctionClaimHEZ() (tx *types.Transaction, err error) {
1499 c.rw.Lock()
1500 defer c.rw.Unlock()
1501 cpy := c.nextBlock().copy()
1502 defer func() { c.revertIfErr(err, cpy) }()
1503 if c.addr == nil {
1504 return nil, tracerr.Wrap(eth.ErrAccountNil)
1505 }
1506
1507 log.Error("TODO")
1508 return nil, tracerr.Wrap(errTODO)
1509}
1510
1511// AuctionGetClaimableHEZ is the interface to call the smart contract function
1512func (c *Client) AuctionGetClaimableHEZ(bidder ethCommon.Address) (*big.Int, error) {
1513 c.rw.RLock()
1514 defer c.rw.RUnlock()
1515
1516 log.Error("TODO")
1517 return nil, tracerr.Wrap(errTODO)
1518}
1519
1520// AuctionConstants returns the Constants of the Auction Smart Contract
1521func (c *Client) AuctionConstants() (*common.AuctionConstants, error) {
1522 c.rw.RLock()
1523 defer c.rw.RUnlock()
1524
1525 return c.auctionConstants, nil
1526}
1527
1528// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract
1529func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethCommon.Hash, error) {
1530 c.rw.RLock()
1531 defer c.rw.RUnlock()
1532
1533 block, ok := c.blocks[blockNum]
1534 if !ok {
1535 return nil, nil, tracerr.Wrap(fmt.Errorf("Block %v doesn't exist", blockNum))
1536 }
1537 return &block.Auction.Events, &block.Eth.Hash, nil
1538}
1539
1540// AuctionEventInit returns the initialize event with its corresponding block number
1541func (c *Client) AuctionEventInit() (*eth.AuctionEventInitialize, int64, error) {
1542 vars := c.blocks[0].Auction.Vars
1543 return ð.AuctionEventInitialize{
1544 DonationAddress: vars.DonationAddress,
1545 BootCoordinatorAddress: vars.BootCoordinator,
1546 BootCoordinatorURL: vars.BootCoordinatorURL,
1547 Outbidding: vars.Outbidding,
1548 SlotDeadline: vars.SlotDeadline,
1549 ClosedAuctionSlots: vars.ClosedAuctionSlots,
1550 OpenAuctionSlots: vars.OpenAuctionSlots,
1551 AllocationRatio: vars.AllocationRatio,
1552 }, 1, nil
1553}
1554
1555//
1556// WDelayer
1557//
1558
1559// WDelayerGetHermezGovernanceAddress is the interface to call the smart contract function
1560func (c *Client) WDelayerGetHermezGovernanceAddress() (*ethCommon.Address, error) {
1561 c.rw.RLock()
1562 defer c.rw.RUnlock()
1563
1564 log.Error("TODO")
1565 return nil, tracerr.Wrap(errTODO)
1566}
1567
1568// WDelayerTransferGovernance is the interface to call the smart contract function
1569func (c *Client) WDelayerTransferGovernance(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1570 c.rw.Lock()
1571 defer c.rw.Unlock()
1572 cpy := c.nextBlock().copy()
1573 defer func() { c.revertIfErr(err, cpy) }()
1574 if c.addr == nil {
1575 return nil, tracerr.Wrap(eth.ErrAccountNil)
1576 }
1577
1578 log.Error("TODO")
1579 return nil, tracerr.Wrap(errTODO)
1580}
1581
1582// WDelayerClaimGovernance is the interface to call the smart contract function
1583func (c *Client) WDelayerClaimGovernance() (tx *types.Transaction, err error) {
1584 c.rw.Lock()
1585 defer c.rw.Unlock()
1586 cpy := c.nextBlock().copy()
1587 defer func() { c.revertIfErr(err, cpy) }()
1588 if c.addr == nil {
1589 return nil, tracerr.Wrap(eth.ErrAccountNil)
1590 }
1591
1592 log.Error("TODO")
1593 return nil, tracerr.Wrap(errTODO)
1594}
1595
1596// WDelayerGetEmergencyCouncil is the interface to call the smart contract function
1597func (c *Client) WDelayerGetEmergencyCouncil() (*ethCommon.Address, error) {
1598 c.rw.RLock()
1599 defer c.rw.RUnlock()
1600
1601 log.Error("TODO")
1602 return nil, tracerr.Wrap(errTODO)
1603}
1604
1605// WDelayerTransferEmergencyCouncil is the interface to call the smart contract function
1606func (c *Client) WDelayerTransferEmergencyCouncil(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1607 c.rw.Lock()
1608 defer c.rw.Unlock()
1609 cpy := c.nextBlock().copy()
1610 defer func() { c.revertIfErr(err, cpy) }()
1611 if c.addr == nil {
1612 return nil, tracerr.Wrap(eth.ErrAccountNil)
1613 }
1614
1615 log.Error("TODO")
1616 return nil, tracerr.Wrap(errTODO)
1617}
1618
1619// WDelayerClaimEmergencyCouncil is the interface to call the smart contract function
1620func (c *Client) WDelayerClaimEmergencyCouncil() (tx *types.Transaction, err error) {
1621 c.rw.Lock()
1622 defer c.rw.Unlock()
1623 cpy := c.nextBlock().copy()
1624 defer func() { c.revertIfErr(err, cpy) }()
1625 if c.addr == nil {
1626 return nil, tracerr.Wrap(eth.ErrAccountNil)
1627 }
1628
1629 log.Error("TODO")
1630 return nil, tracerr.Wrap(errTODO)
1631}
1632
1633// WDelayerIsEmergencyMode is the interface to call the smart contract function
1634func (c *Client) WDelayerIsEmergencyMode() (bool, error) {
1635 c.rw.RLock()
1636 defer c.rw.RUnlock()
1637
1638 log.Error("TODO")
1639 return false, tracerr.Wrap(errTODO)
1640}
1641
1642// WDelayerGetWithdrawalDelay is the interface to call the smart contract function
1643func (c *Client) WDelayerGetWithdrawalDelay() (int64, error) {
1644 c.rw.RLock()
1645 defer c.rw.RUnlock()
1646
1647 log.Error("TODO")
1648 return 0, tracerr.Wrap(errTODO)
1649}
1650
1651// WDelayerGetEmergencyModeStartingTime is the interface to call the smart contract function
1652func (c *Client) WDelayerGetEmergencyModeStartingTime() (int64, error) {
1653 c.rw.RLock()
1654 defer c.rw.RUnlock()
1655
1656 log.Error("TODO")
1657 return 0, tracerr.Wrap(errTODO)
1658}
1659
1660// WDelayerEnableEmergencyMode is the interface to call the smart contract function
1661func (c *Client) WDelayerEnableEmergencyMode() (tx *types.Transaction, err error) {
1662 c.rw.Lock()
1663 defer c.rw.Unlock()
1664 cpy := c.nextBlock().copy()
1665 defer func() { c.revertIfErr(err, cpy) }()
1666 if c.addr == nil {
1667 return nil, tracerr.Wrap(eth.ErrAccountNil)
1668 }
1669
1670 log.Error("TODO")
1671 return nil, tracerr.Wrap(errTODO)
1672}
1673
1674// WDelayerChangeWithdrawalDelay is the interface to call the smart contract function
1675func (c *Client) WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (tx *types.Transaction, err error) {
1676 c.rw.Lock()
1677 defer c.rw.Unlock()
1678 cpy := c.nextBlock().copy()
1679 defer func() { c.revertIfErr(err, cpy) }()
1680 if c.addr == nil {
1681 return nil, tracerr.Wrap(eth.ErrAccountNil)
1682 }
1683
1684 nextBlock := c.nextBlock()
1685 w := nextBlock.WDelayer
1686 w.Vars.WithdrawalDelay = newWithdrawalDelay
1687 w.Events.NewWithdrawalDelay = append(w.Events.NewWithdrawalDelay,
1688 eth.WDelayerEventNewWithdrawalDelay{WithdrawalDelay: newWithdrawalDelay})
1689
1690 return w.addTransaction(c.newTransaction("changeWithdrawalDelay", newWithdrawalDelay)), nil
1691}
1692
1693// WDelayerDepositInfo is the interface to call the smart contract function
1694func (c *Client) WDelayerDepositInfo(owner, token ethCommon.Address) (eth.DepositState, error) {
1695 c.rw.RLock()
1696 defer c.rw.RUnlock()
1697
1698 log.Error("TODO")
1699 return eth.DepositState{}, tracerr.Wrap(errTODO)
1700}
1701
1702// WDelayerDeposit is the interface to call the smart contract function
1703func (c *Client) WDelayerDeposit(onwer, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
1704 c.rw.Lock()
1705 defer c.rw.Unlock()
1706 cpy := c.nextBlock().copy()
1707 defer func() { c.revertIfErr(err, cpy) }()
1708 if c.addr == nil {
1709 return nil, tracerr.Wrap(eth.ErrAccountNil)
1710 }
1711
1712 log.Error("TODO")
1713 return nil, tracerr.Wrap(errTODO)
1714}
1715
1716// WDelayerWithdrawal is the interface to call the smart contract function
1717func (c *Client) WDelayerWithdrawal(owner, token ethCommon.Address) (tx *types.Transaction, err error) {
1718 c.rw.Lock()
1719 defer c.rw.Unlock()
1720 cpy := c.nextBlock().copy()
1721 defer func() { c.revertIfErr(err, cpy) }()
1722 if c.addr == nil {
1723 return nil, tracerr.Wrap(eth.ErrAccountNil)
1724 }
1725
1726 log.Error("TODO")
1727 return nil, tracerr.Wrap(errTODO)
1728}
1729
1730// WDelayerEscapeHatchWithdrawal is the interface to call the smart contract function
1731func (c *Client) WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
1732 c.rw.Lock()
1733 defer c.rw.Unlock()
1734 cpy := c.nextBlock().copy()
1735 defer func() { c.revertIfErr(err, cpy) }()
1736 if c.addr == nil {
1737 return nil, tracerr.Wrap(eth.ErrAccountNil)
1738 }
1739
1740 log.Error("TODO")
1741 return nil, tracerr.Wrap(errTODO)
1742}
1743
1744// WDelayerEventsByBlock returns the events in a block that happened in the WDelayer Contract
1745func (c *Client) WDelayerEventsByBlock(blockNum int64) (*eth.WDelayerEvents, *ethCommon.Hash, error) {
1746 c.rw.RLock()
1747 defer c.rw.RUnlock()
1748
1749 block, ok := c.blocks[blockNum]
1750 if !ok {
1751 return nil, nil, tracerr.Wrap(fmt.Errorf("Block %v doesn't exist", blockNum))
1752 }
1753 return &block.WDelayer.Events, &block.Eth.Hash, nil
1754}
1755
1756// WDelayerConstants returns the Constants of the WDelayer Contract
1757func (c *Client) WDelayerConstants() (*common.WDelayerConstants, error) {
1758 c.rw.RLock()
1759 defer c.rw.RUnlock()
1760
1761 return c.wDelayerConstants, nil
1762}
1763
1764// WDelayerEventInit returns the initialize event with its corresponding block number
1765func (c *Client) WDelayerEventInit() (*eth.WDelayerEventInitialize, int64, error) {
1766 vars := c.blocks[0].WDelayer.Vars
1767 return ð.WDelayerEventInitialize{
1768 InitialWithdrawalDelay: vars.WithdrawalDelay,
1769 InitialHermezGovernanceAddress: vars.HermezGovernanceAddress,
1770 InitialEmergencyCouncil: vars.EmergencyCouncilAddress,
1771 }, 1, nil
1772}
1773
1774// CtlAddBlocks adds block data to the smarts contracts. The added blocks will
1775// appear as mined. Not thread safe.
1776func (c *Client) CtlAddBlocks(blocks []common.BlockData) (err error) {
1777 // NOTE: We don't lock because internally we call public functions that
1778 // lock already.
1779 for _, block := range blocks {
1780 nextBlock := c.nextBlock()
1781 rollup := nextBlock.Rollup
1782 auction := nextBlock.Auction
1783 for _, token := range block.Rollup.AddedTokens {
1784 if _, err := c.RollupAddTokenSimple(token.EthAddr, rollup.Vars.FeeAddToken); err != nil {
1785 return tracerr.Wrap(err)
1786 }
1787 }
1788 for _, tx := range block.Rollup.L1UserTxs {
1789 c.CtlSetAddr(tx.FromEthAddr)
1790 if _, err := c.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.DepositAmount, tx.Amount,
1791 uint32(tx.TokenID), int64(tx.ToIdx)); err != nil {
1792 return tracerr.Wrap(err)
1793 }
1794 }
1795 c.CtlSetAddr(auction.Vars.BootCoordinator)
1796 for _, batch := range block.Rollup.Batches {
1797 if _, err := c.RollupForgeBatch(ð.RollupForgeBatchArgs{
1798 NewLastIdx: batch.Batch.LastIdx,
1799 NewStRoot: batch.Batch.StateRoot,
1800 NewExitRoot: batch.Batch.ExitRoot,
1801 L1CoordinatorTxs: batch.L1CoordinatorTxs,
1802 L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
1803 L2TxsData: batch.L2Txs,
1804 FeeIdxCoordinator: batch.Batch.FeeIdxsCoordinator,
1805 // Circuit selector
1806 VerifierIdx: 0, // Intentionally empty
1807 L1Batch: batch.L1Batch,
1808 ProofA: [2]*big.Int{}, // Intentionally empty
1809 ProofB: [2][2]*big.Int{}, // Intentionally empty
1810 ProofC: [2]*big.Int{}, // Intentionally empty
1811 }); err != nil {
1812 return tracerr.Wrap(err)
1813 }
1814 }
1815 // Mine block and sync
1816 c.CtlMineBlock()
1817 }
1818 return nil
1819}