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 ethCommon "github.com/ethereum/go-ethereum/common"
14 "github.com/ethereum/go-ethereum/core/types"
15 "github.com/hermeznetwork/hermez-node/common"
16 "github.com/hermeznetwork/hermez-node/eth"
17 "github.com/hermeznetwork/hermez-node/log"
18 "github.com/iden3/go-iden3-crypto/babyjub"
19 "github.com/mitchellh/copystructure"
20)
21
22func init() {
23 copystructure.Copiers[reflect.TypeOf(big.Int{})] =
24 func(raw interface{}) (interface{}, error) {
25 in := raw.(big.Int)
26 out := new(big.Int).Set(&in)
27 return *out, nil
28 }
29}
30
31// RollupBlock stores all the data related to the Rollup SC from an ethereum block
32type RollupBlock struct {
33 State eth.RollupState
34 Vars eth.RollupVariables
35 Events eth.RollupEvents
36 Txs map[ethCommon.Hash]*types.Transaction
37 Constants *eth.RollupConstants
38 Eth *EthereumBlock
39}
40
41func (r *RollupBlock) addTransaction(tx *types.Transaction) *types.Transaction {
42 txHash := tx.Hash()
43 r.Txs[txHash] = tx
44 return tx
45}
46
47var (
48 errBidClosed = fmt.Errorf("Bid has already been closed")
49 errBidNotOpen = fmt.Errorf("Bid has not been opened yet")
50 errBidBelowMin = fmt.Errorf("Bid below minimum")
51 errCoordNotReg = fmt.Errorf("Coordinator not registered")
52)
53
54// AuctionBlock stores all the data related to the Auction SC from an ethereum block
55type AuctionBlock struct {
56 State eth.AuctionState
57 Vars eth.AuctionVariables
58 Events eth.AuctionEvents
59 Txs map[ethCommon.Hash]*types.Transaction
60 Constants *eth.AuctionConstants
61 Eth *EthereumBlock
62}
63
64func (a *AuctionBlock) addTransaction(tx *types.Transaction) *types.Transaction {
65 txHash := tx.Hash()
66 a.Txs[txHash] = tx
67 return tx
68}
69
70func (a *AuctionBlock) getSlotNumber(blockNumber int64) int64 {
71 if a.Eth.BlockNum >= a.Constants.GenesisBlockNum {
72 return (blockNumber - a.Constants.GenesisBlockNum) / int64(a.Constants.BlocksPerSlot)
73 }
74 return 0
75}
76
77func (a *AuctionBlock) getCurrentSlotNumber() int64 {
78 return a.getSlotNumber(a.Eth.BlockNum)
79}
80
81func (a *AuctionBlock) getSlotSet(slot int64) int64 {
82 return slot % int64(len(a.Vars.DefaultSlotSetBid))
83}
84
85func (a *AuctionBlock) getMinBidBySlot(slot int64) (*big.Int, error) {
86 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
87 return nil, errBidClosed
88 }
89
90 slotSet := a.getSlotSet(slot)
91 // fmt.Println("slot:", slot, "slotSet:", slotSet)
92 var prevBid *big.Int
93 slotState, ok := a.State.Slots[slot]
94 if !ok {
95 slotState = eth.NewSlotState()
96 a.State.Slots[slot] = slotState
97 }
98 // If the bidAmount for a slot is 0 it means that it has not yet been bid, so the midBid will be the minimum
99 // bid for the slot time plus the outbidding set, otherwise it will be the bidAmount plus the outbidding
100 if slotState.BidAmount.Cmp(big.NewInt(0)) == 0 {
101 prevBid = a.Vars.DefaultSlotSetBid[slotSet]
102 } else {
103 prevBid = slotState.BidAmount
104 }
105 outBid := new(big.Int).Set(prevBid)
106 // fmt.Println("outBid:", outBid)
107 outBid.Mul(outBid, big.NewInt(int64(a.Vars.Outbidding)))
108 outBid.Div(outBid, big.NewInt(10000)) //nolint:gomnd
109 outBid.Add(prevBid, outBid)
110 // fmt.Println("minBid:", outBid)
111 return outBid, nil
112}
113
114func (a *AuctionBlock) forge(forger ethCommon.Address) error {
115 if ok, err := a.canForge(forger, a.Eth.BlockNum); err != nil {
116 return err
117 } else if !ok {
118 return fmt.Errorf("Can't forge")
119 }
120
121 slotToForge := a.getSlotNumber(a.Eth.BlockNum)
122 slotState, ok := a.State.Slots[slotToForge]
123 if !ok {
124 slotState = eth.NewSlotState()
125 a.State.Slots[slotToForge] = slotState
126 }
127 slotState.Fulfilled = true
128
129 a.Events.NewForge = append(a.Events.NewForge, eth.AuctionEventNewForge{
130 Forger: forger,
131 CurrentSlot: slotToForge,
132 })
133 return nil
134}
135
136func (a *AuctionBlock) canForge(forger ethCommon.Address, blockNum int64) (bool, error) {
137 if blockNum < a.Constants.GenesisBlockNum {
138 return false, fmt.Errorf("Auction has not started yet")
139 }
140
141 slotToForge := a.getSlotNumber(blockNum)
142 // Get the relativeBlock to check if the slotDeadline has been exceeded
143 relativeBlock := blockNum - (a.Constants.GenesisBlockNum + (slotToForge * int64(a.Constants.BlocksPerSlot)))
144
145 // If the closedMinBid is 0 it means that we have to take as minBid the one that is set for this slot set,
146 // otherwise the one that has been saved will be used
147 var minBid *big.Int
148 slotState, ok := a.State.Slots[slotToForge]
149 if !ok {
150 slotState = eth.NewSlotState()
151 a.State.Slots[slotToForge] = slotState
152 }
153 if slotState.ClosedMinBid.Cmp(big.NewInt(0)) == 0 {
154 minBid = a.Vars.DefaultSlotSetBid[a.getSlotSet(slotToForge)]
155 } else {
156 minBid = slotState.ClosedMinBid
157 }
158
159 if !slotState.Fulfilled && (relativeBlock >= int64(a.Vars.SlotDeadline)) {
160 // if the relative block has exceeded the slotDeadline and no batch has been forged, anyone can forge
161 return true, nil
162 } else if slotState.Forger == forger && slotState.BidAmount.Cmp(minBid) >= 0 {
163 // if forger bidAmount has exceeded the minBid it can forge
164 return true, nil
165 } else if a.Vars.BootCoordinator == forger && slotState.BidAmount.Cmp(minBid) == -1 {
166 // if it's the boot coordinator and it has not been bid or the bid is below the minimum it can forge
167 return true, nil
168 } else {
169 return false, nil
170 }
171}
172
173// EthereumBlock stores all the generic data related to the an ethereum block
174type EthereumBlock struct {
175 BlockNum int64
176 Time int64
177 Hash ethCommon.Hash
178 ParentHash ethCommon.Hash
179 // state ethState
180}
181
182// Block represents a ethereum block
183type Block struct {
184 Rollup *RollupBlock
185 Auction *AuctionBlock
186 Eth *EthereumBlock
187}
188
189func (b *Block) copy() *Block {
190 bCopyRaw, err := copystructure.Copy(b)
191 if err != nil {
192 panic(err)
193 }
194 bCopy := bCopyRaw.(*Block)
195 return bCopy
196}
197
198// Next prepares the successive block.
199func (b *Block) Next() *Block {
200 blockNext := b.copy()
201 blockNext.Rollup.Events = eth.NewRollupEvents()
202 blockNext.Auction.Events = eth.NewAuctionEvents()
203 blockNext.Eth = &EthereumBlock{
204 BlockNum: b.Eth.BlockNum + 1,
205 ParentHash: b.Eth.Hash,
206 }
207 blockNext.Rollup.Constants = b.Rollup.Constants
208 blockNext.Auction.Constants = b.Auction.Constants
209 blockNext.Rollup.Eth = blockNext.Eth
210 blockNext.Auction.Eth = blockNext.Eth
211 return blockNext
212}
213
214// ClientSetup is used to initialize the constants of the Smart Contracts and
215// other details of the test Client
216type ClientSetup struct {
217 RollupConstants *eth.RollupConstants
218 RollupVariables *eth.RollupVariables
219 AuctionConstants *eth.AuctionConstants
220 AuctionVariables *eth.AuctionVariables
221 VerifyProof bool
222}
223
224// NewClientSetupExample returns a ClientSetup example with hardcoded realistic values.
225//nolint:gomnd
226func NewClientSetupExample() *ClientSetup {
227 rfield, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
228 if !ok {
229 panic("bad rfield")
230 }
231 initialMinimalBidding, ok := new(big.Int).SetString("10000000000000000000", 10) // 10 * (1e18)
232 if !ok {
233 panic("bad initialMinimalBidding")
234 }
235 tokenHEZ := ethCommon.HexToAddress("0x51D243D62852Bba334DD5cc33f242BAc8c698074")
236 governanceAddress := ethCommon.HexToAddress("0x688EfD95BA4391f93717CF02A9aED9DBD2855cDd")
237 rollupConstants := ð.RollupConstants{
238 MaxAmountDeposit: new(big.Int).Lsh(big.NewInt(1), 128),
239 MaxAmountL2: new(big.Int).Lsh(big.NewInt(1), 192),
240 MaxTokens: 0xffffffff,
241 MaxL1Tx: 256,
242 MaxL1UserTx: 128,
243 Rfield: rfield,
244 L1CoordinatorBytes: 101,
245 L1UserBytes: 68,
246 L2Bytes: 11,
247 MaxTxVerifiers: []int{512, 1024, 2048},
248 TokenHEZ: tokenHEZ,
249 GovernanceAddress: governanceAddress,
250 SafetyBot: ethCommon.HexToAddress("0x84d8B79E84fe87B14ad61A554e740f6736bF4c20"),
251 ConsensusContract: ethCommon.HexToAddress("0x8E442975805fb1908f43050c9C1A522cB0e28D7b"),
252 WithdrawalContract: ethCommon.HexToAddress("0x5CB7979cBdbf65719BEE92e4D15b7b7Ed3D79114"),
253 }
254 rollupVariables := ð.RollupVariables{
255 FeeAddToken: big.NewInt(11),
256 ForgeL1Timeout: 9,
257 }
258 auctionConstants := ð.AuctionConstants{
259 BlocksPerSlot: 40,
260 InitialMinimalBidding: initialMinimalBidding,
261 GenesisBlockNum: 0,
262 GovernanceAddress: governanceAddress,
263 TokenHEZ: tokenHEZ,
264 HermezRollup: ethCommon.HexToAddress("0x474B6e29852257491cf283EfB1A9C61eBFe48369"),
265 }
266 auctionVariables := ð.AuctionVariables{
267 DonationAddress: ethCommon.HexToAddress("0x61Ed87CF0A1496b49A420DA6D84B58196b98f2e7"),
268 BootCoordinator: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
269 DefaultSlotSetBid: [6]*big.Int{
270 big.NewInt(1000), big.NewInt(1100), big.NewInt(1200),
271 big.NewInt(1300), big.NewInt(1400), big.NewInt(1500)},
272 ClosedAuctionSlots: 2,
273 OpenAuctionSlots: 4320,
274 AllocationRatio: [3]uint16{4000, 4000, 2000},
275 Outbidding: 1000,
276 SlotDeadline: 20,
277 }
278 return &ClientSetup{
279 RollupConstants: rollupConstants,
280 RollupVariables: rollupVariables,
281 AuctionConstants: auctionConstants,
282 AuctionVariables: auctionVariables,
283 }
284}
285
286// Timer is an interface to simulate a source of time, useful to advance time
287// virtually.
288type Timer interface {
289 Time() int64
290}
291
292// type forgeBatchArgs struct {
293// ethTx *types.Transaction
294// blockNum int64
295// blockHash ethCommon.Hash
296// }
297
298// Client implements the eth.ClientInterface interface, allowing to manipulate the
299// values for testing, working with deterministic results.
300type Client struct {
301 rw *sync.RWMutex
302 log bool
303 addr *ethCommon.Address
304 rollupConstants *eth.RollupConstants
305 auctionConstants *eth.AuctionConstants
306 blocks map[int64]*Block
307 // state state
308 blockNum int64 // last mined block num
309 maxBlockNum int64 // highest block num calculated
310 timer Timer
311 hasher hasher
312
313 forgeBatchArgsPending map[ethCommon.Hash]*eth.RollupForgeBatchArgs
314 forgeBatchArgs map[ethCommon.Hash]*eth.RollupForgeBatchArgs
315}
316
317// NewClient returns a new test Client that implements the eth.IClient
318// interface, at the given initialBlockNumber.
319func NewClient(l bool, timer Timer, addr *ethCommon.Address, setup *ClientSetup) *Client {
320 blocks := make(map[int64]*Block)
321 blockNum := int64(0)
322
323 hasher := hasher{}
324 // Add ethereum genesis block
325 mapL1TxQueue := make(map[int64]*eth.QueueStruct)
326 mapL1TxQueue[0] = eth.NewQueueStruct()
327 mapL1TxQueue[1] = eth.NewQueueStruct()
328 blockCurrent := Block{
329 Rollup: &RollupBlock{
330 State: eth.RollupState{
331 StateRoot: big.NewInt(0),
332 ExitRoots: make([]*big.Int, 0),
333 ExitNullifierMap: make(map[[256 / 8]byte]bool),
334 TokenList: make([]ethCommon.Address, 0),
335 TokenMap: make(map[ethCommon.Address]bool),
336 MapL1TxQueue: mapL1TxQueue,
337 LastL1L2Batch: 0,
338 CurrentToForgeL1TxsNum: 0,
339 LastToForgeL1TxsNum: 1,
340 CurrentIdx: 0,
341 },
342 Vars: *setup.RollupVariables,
343 Txs: make(map[ethCommon.Hash]*types.Transaction),
344 Events: eth.NewRollupEvents(),
345 Constants: setup.RollupConstants,
346 },
347 Auction: &AuctionBlock{
348 State: eth.AuctionState{
349 Slots: make(map[int64]*eth.SlotState),
350 PendingBalances: make(map[ethCommon.Address]*big.Int),
351 Coordinators: make(map[ethCommon.Address]*eth.Coordinator),
352 },
353 Vars: *setup.AuctionVariables,
354 Txs: make(map[ethCommon.Hash]*types.Transaction),
355 Events: eth.NewAuctionEvents(),
356 Constants: setup.AuctionConstants,
357 },
358 Eth: &EthereumBlock{
359 BlockNum: blockNum,
360 Time: timer.Time(),
361 Hash: hasher.Next(),
362 ParentHash: ethCommon.Hash{},
363 },
364 }
365 blockCurrent.Rollup.Eth = blockCurrent.Eth
366 blockCurrent.Auction.Eth = blockCurrent.Eth
367 blocks[blockNum] = &blockCurrent
368 blockNext := blockCurrent.Next()
369 blocks[blockNum+1] = blockNext
370
371 return &Client{
372 rw: &sync.RWMutex{},
373 log: l,
374 addr: addr,
375 rollupConstants: setup.RollupConstants,
376 auctionConstants: setup.AuctionConstants,
377 blocks: blocks,
378 timer: timer,
379 hasher: hasher,
380 forgeBatchArgsPending: make(map[ethCommon.Hash]*eth.RollupForgeBatchArgs),
381 forgeBatchArgs: make(map[ethCommon.Hash]*eth.RollupForgeBatchArgs),
382 }
383}
384
385//
386// Mock Control
387//
388
389func (c *Client) setNextBlock(block *Block) {
390 c.blocks[c.blockNum+1] = block
391}
392
393func (c *Client) revertIfErr(err error, block *Block) {
394 if err != nil {
395 log.Infow("TestClient revert", "block", block.Eth.BlockNum, "err", err)
396 c.setNextBlock(block)
397 }
398}
399
400// Debugf calls log.Debugf if c.log is true
401func (c *Client) Debugf(template string, args ...interface{}) {
402 if c.log {
403 log.Debugf(template, args...)
404 }
405}
406
407// Debugw calls log.Debugw if c.log is true
408func (c *Client) Debugw(template string, kv ...interface{}) {
409 if c.log {
410 log.Debugw(template, kv...)
411 }
412}
413
414type hasher struct {
415 counter uint64
416}
417
418// Next returns the next hash
419func (h *hasher) Next() ethCommon.Hash {
420 var hash ethCommon.Hash
421 binary.LittleEndian.PutUint64(hash[:], h.counter)
422 h.counter++
423 return hash
424}
425
426func (c *Client) nextBlock() *Block {
427 return c.blocks[c.blockNum+1]
428}
429
430func (c *Client) currentBlock() *Block {
431 return c.blocks[c.blockNum]
432}
433
434// CtlMineBlock moves one block forward
435func (c *Client) CtlMineBlock() {
436 c.rw.Lock()
437 defer c.rw.Unlock()
438
439 blockCurrent := c.nextBlock()
440 c.blockNum++
441 c.maxBlockNum = c.blockNum
442 blockCurrent.Eth.Time = c.timer.Time()
443 blockCurrent.Eth.Hash = c.hasher.Next()
444 for ethTxHash, forgeBatchArgs := range c.forgeBatchArgsPending {
445 c.forgeBatchArgs[ethTxHash] = forgeBatchArgs
446 }
447 c.forgeBatchArgsPending = make(map[ethCommon.Hash]*eth.RollupForgeBatchArgs)
448
449 blockNext := blockCurrent.Next()
450 c.blocks[c.blockNum+1] = blockNext
451 c.Debugw("TestClient mined block", "blockNum", c.blockNum)
452}
453
454// CtlRollback discards the last mined block. Use this to replace a mined
455// block to simulate reorgs.
456func (c *Client) CtlRollback() {
457 c.rw.Lock()
458 defer c.rw.Unlock()
459
460 if c.blockNum == 0 {
461 panic("Can't rollback at blockNum = 0")
462 }
463 delete(c.blocks, c.blockNum+1) // delete next block
464 delete(c.blocks, c.blockNum) // delete current block
465 c.blockNum--
466 blockCurrent := c.blocks[c.blockNum]
467 blockNext := blockCurrent.Next()
468 c.blocks[c.blockNum+1] = blockNext
469}
470
471//
472// Ethereum
473//
474
475// EthCurrentBlock returns the current blockNum
476func (c *Client) EthCurrentBlock() (int64, error) {
477 c.rw.RLock()
478 defer c.rw.RUnlock()
479
480 if c.blockNum < c.maxBlockNum {
481 panic("blockNum has decreased. " +
482 "After a rollback you must mine to reach the same or higher blockNum")
483 }
484 return c.blockNum, nil
485}
486
487// EthTransactionReceipt returns the transaction receipt of the given txHash
488func (c *Client) EthTransactionReceipt(ctx context.Context, txHash ethCommon.Hash) (*types.Receipt, error) {
489 c.rw.RLock()
490 defer c.rw.RUnlock()
491
492 for i := int64(0); i < c.blockNum; i++ {
493 b := c.blocks[i]
494 _, ok := b.Rollup.Txs[txHash]
495 if !ok {
496 _, ok = b.Auction.Txs[txHash]
497 }
498 if ok {
499 return &types.Receipt{
500 TxHash: txHash,
501 Status: types.ReceiptStatusSuccessful,
502 BlockHash: b.Eth.Hash,
503 BlockNumber: big.NewInt(b.Eth.BlockNum),
504 }, nil
505 }
506 }
507
508 return nil, nil
509}
510
511// func newHeader(number *big.Int) *types.Header {
512// return &types.Header{
513// Number: number,
514// Time: uint64(number.Int64()),
515// }
516// }
517
518// EthHeaderByNumber returns the *types.Header for the given block number in a
519// deterministic way.
520// func (c *Client) EthHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
521// return newHeader(number), nil
522// }
523
524// EthBlockByNumber returns the *common.Block for the given block number in a
525// deterministic way.
526func (c *Client) EthBlockByNumber(ctx context.Context, blockNum int64) (*common.Block, error) {
527 c.rw.RLock()
528 defer c.rw.RUnlock()
529
530 block, ok := c.blocks[blockNum]
531 if !ok {
532 return nil, fmt.Errorf("block not found")
533 }
534 return &common.Block{
535 EthBlockNum: blockNum,
536 Timestamp: time.Unix(block.Eth.Time, 0),
537 Hash: block.Eth.Hash,
538 ParentHash: block.Eth.ParentHash,
539 }, nil
540}
541
542// EthAddress returns the ethereum address of the account loaded into the Client
543func (c *Client) EthAddress() (*ethCommon.Address, error) {
544 if c.addr == nil {
545 return nil, eth.ErrAccountNil
546 }
547 return c.addr, nil
548}
549
550var errTODO = fmt.Errorf("TODO: Not implemented yet")
551
552//
553// Rollup
554//
555
556// CtlAddL1TxUser adds an L1TxUser to the L1UserTxs queue of the Rollup
557func (c *Client) CtlAddL1TxUser(l1Tx *common.L1Tx) {
558 c.rw.Lock()
559 defer c.rw.Unlock()
560
561 nextBlock := c.nextBlock()
562 r := nextBlock.Rollup
563 queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
564 if len(queue.L1TxQueue) >= c.rollupConstants.MaxL1UserTx {
565 r.State.LastToForgeL1TxsNum++
566 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
567 queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
568 }
569 if l1Tx.FromIdx != nil && int64(*l1Tx.FromIdx) > r.State.CurrentIdx {
570 panic("l1Tx.FromIdx > r.State.CurrentIdx")
571 }
572 if int(l1Tx.TokenID)+1 > len(r.State.TokenList) {
573 panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
574 }
575 queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
576 r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{L1Tx: *l1Tx})
577}
578
579type transactionData struct {
580 Name string
581 Value interface{}
582}
583
584func newTransaction(name string, value interface{}) *types.Transaction {
585 data, err := json.Marshal(transactionData{name, value})
586 if err != nil {
587 panic(err)
588 }
589 return types.NewTransaction(0, ethCommon.Address{}, nil, 0, nil,
590 data)
591}
592
593// RollupForgeBatch is the interface to call the smart contract function
594func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Transaction, err error) {
595 c.rw.Lock()
596 defer c.rw.Unlock()
597 cpy := c.nextBlock().copy()
598 defer func() { c.revertIfErr(err, cpy) }()
599 if c.addr == nil {
600 return nil, eth.ErrAccountNil
601 }
602
603 a := c.nextBlock().Auction
604 ok, err := a.canForge(*c.addr, a.Eth.BlockNum)
605 if err != nil {
606 return nil, err
607 }
608 if !ok {
609 return nil, fmt.Errorf("incorrect slot")
610 }
611
612 // TODO: Verify proof
613
614 // Auction
615 err = a.forge(*c.addr)
616 if err != nil {
617 return nil, err
618 }
619
620 // TODO: If successful, store the tx in a successful array.
621 // TODO: If failed, store the tx in a failed array.
622 // TODO: Add method to move the tx to another block, reapply it there, and possibly go from successful to failed.
623
624 return c.addBatch(args)
625}
626
627// CtlAddBatch adds forged batch to the Rollup, without checking any ZKProof
628func (c *Client) CtlAddBatch(args *eth.RollupForgeBatchArgs) {
629 c.rw.Lock()
630 defer c.rw.Unlock()
631
632 if _, err := c.addBatch(args); err != nil {
633 panic(err)
634 }
635}
636
637func (c *Client) addBatch(args *eth.RollupForgeBatchArgs) (*types.Transaction, error) {
638 nextBlock := c.nextBlock()
639 r := nextBlock.Rollup
640 r.State.StateRoot = args.NewStRoot
641 if args.NewLastIdx < r.State.CurrentIdx {
642 return nil, fmt.Errorf("args.NewLastIdx < r.State.CurrentIdx")
643 }
644 r.State.CurrentIdx = args.NewLastIdx
645 r.State.ExitRoots = append(r.State.ExitRoots, args.NewExitRoot)
646 if args.L1Batch {
647 r.State.CurrentToForgeL1TxsNum++
648 if r.State.CurrentToForgeL1TxsNum == r.State.LastToForgeL1TxsNum {
649 r.State.LastToForgeL1TxsNum++
650 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
651 }
652 }
653 ethTx := r.addTransaction(newTransaction("forgebatch", args))
654 c.forgeBatchArgsPending[ethTx.Hash()] = args
655 r.Events.ForgeBatch = append(r.Events.ForgeBatch, eth.RollupEventForgeBatch{
656 BatchNum: int64(len(r.State.ExitRoots)),
657 EthTxHash: ethTx.Hash(),
658 })
659
660 return ethTx, nil
661}
662
663// RollupAddToken is the interface to call the smart contract function
664func (c *Client) RollupAddToken(tokenAddress ethCommon.Address) (tx *types.Transaction, err error) {
665 c.rw.Lock()
666 defer c.rw.Unlock()
667 cpy := c.nextBlock().copy()
668 defer func() { c.revertIfErr(err, cpy) }()
669 if c.addr == nil {
670 return nil, eth.ErrAccountNil
671 }
672
673 nextBlock := c.nextBlock()
674 r := nextBlock.Rollup
675 if _, ok := r.State.TokenMap[tokenAddress]; ok {
676 return nil, fmt.Errorf("Token %v already registered", tokenAddress)
677 }
678
679 r.State.TokenMap[tokenAddress] = true
680 r.State.TokenList = append(r.State.TokenList, tokenAddress)
681 r.Events.AddToken = append(r.Events.AddToken, eth.RollupEventAddToken{Address: tokenAddress,
682 TokenID: uint32(len(r.State.TokenList) - 1)})
683 return r.addTransaction(newTransaction("addtoken", tokenAddress)), nil
684}
685
686// RollupWithdrawSNARK is the interface to call the smart contract function
687// func (c *Client) RollupWithdrawSNARK() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
688// return nil, errTODO
689// }
690
691// RollupWithdraw is the interface to call the smart contract function
692func (c *Client) RollupWithdraw(tokenID int64, balance *big.Int, babyPubKey *babyjub.PublicKey, numExitRoot int64, siblings []*big.Int, idx int64, instantWithdraw bool) (tx *types.Transaction, err error) {
693 c.rw.Lock()
694 defer c.rw.Unlock()
695 cpy := c.nextBlock().copy()
696 defer func() { c.revertIfErr(err, cpy) }()
697 if c.addr == nil {
698 return nil, eth.ErrAccountNil
699 }
700
701 log.Error("TODO")
702 return nil, errTODO
703}
704
705// RollupForceExit is the interface to call the smart contract function
706func (c *Client) RollupForceExit(fromIdx int64, amountF common.Float16, tokenID int64) (tx *types.Transaction, err error) {
707 c.rw.Lock()
708 defer c.rw.Unlock()
709 cpy := c.nextBlock().copy()
710 defer func() { c.revertIfErr(err, cpy) }()
711 if c.addr == nil {
712 return nil, eth.ErrAccountNil
713 }
714
715 log.Error("TODO")
716 return nil, errTODO
717}
718
719// RollupForceTransfer is the interface to call the smart contract function
720func (c *Client) RollupForceTransfer(fromIdx int64, amountF common.Float16, tokenID, toIdx int64) (tx *types.Transaction, err error) {
721 c.rw.Lock()
722 defer c.rw.Unlock()
723 cpy := c.nextBlock().copy()
724 defer func() { c.revertIfErr(err, cpy) }()
725 if c.addr == nil {
726 return nil, eth.ErrAccountNil
727 }
728
729 log.Error("TODO")
730 return nil, errTODO
731}
732
733// RollupCreateAccountDepositTransfer is the interface to call the smart contract function
734func (c *Client) RollupCreateAccountDepositTransfer(babyPubKey babyjub.PublicKey, loadAmountF, amountF common.Float16, tokenID int64, toIdx int64) (tx *types.Transaction, err error) {
735 c.rw.Lock()
736 defer c.rw.Unlock()
737 cpy := c.nextBlock().copy()
738 defer func() { c.revertIfErr(err, cpy) }()
739 if c.addr == nil {
740 return nil, eth.ErrAccountNil
741 }
742
743 log.Error("TODO")
744 return nil, errTODO
745}
746
747// RollupGetCurrentTokens is the interface to call the smart contract function
748func (c *Client) RollupGetCurrentTokens() (*big.Int, error) {
749 c.rw.RLock()
750 defer c.rw.RUnlock()
751
752 log.Error("TODO")
753 return nil, errTODO
754}
755
756// RollupDepositTransfer is the interface to call the smart contract function
757func (c *Client) RollupDepositTransfer(fromIdx int64, loadAmountF, amountF common.Float16, tokenID int64, toIdx int64) (tx *types.Transaction, err error) {
758 c.rw.Lock()
759 defer c.rw.Unlock()
760 cpy := c.nextBlock().copy()
761 defer func() { c.revertIfErr(err, cpy) }()
762 if c.addr == nil {
763 return nil, eth.ErrAccountNil
764 }
765
766 log.Error("TODO")
767 return nil, errTODO
768}
769
770// RollupDeposit is the interface to call the smart contract function
771func (c *Client) RollupDeposit(fromIdx int64, loadAmountF common.Float16, tokenID int64) (tx *types.Transaction, err error) {
772 c.rw.Lock()
773 defer c.rw.Unlock()
774 cpy := c.nextBlock().copy()
775 defer func() { c.revertIfErr(err, cpy) }()
776 if c.addr == nil {
777 return nil, eth.ErrAccountNil
778 }
779
780 log.Error("TODO")
781 return nil, errTODO
782}
783
784// RollupCreateAccountDepositFromRelayer is the interface to call the smart contract function
785func (c *Client) RollupCreateAccountDepositFromRelayer(accountCreationAuthSig []byte, babyPubKey babyjub.PublicKey, loadAmountF common.Float16) (tx *types.Transaction, err error) {
786 c.rw.Lock()
787 defer c.rw.Unlock()
788 cpy := c.nextBlock().copy()
789 defer func() { c.revertIfErr(err, cpy) }()
790 if c.addr == nil {
791 return nil, eth.ErrAccountNil
792 }
793
794 log.Error("TODO")
795 return nil, errTODO
796}
797
798// RollupCreateAccountDeposit is the interface to call the smart contract function
799func (c *Client) RollupCreateAccountDeposit(babyPubKey babyjub.PublicKey, loadAmountF common.Float16, tokenID int64) (tx *types.Transaction, err error) {
800 c.rw.Lock()
801 defer c.rw.Unlock()
802 cpy := c.nextBlock().copy()
803 defer func() { c.revertIfErr(err, cpy) }()
804 if c.addr == nil {
805 return nil, eth.ErrAccountNil
806 }
807
808 log.Error("TODO")
809 return nil, errTODO
810}
811
812// RollupGetTokenAddress is the interface to call the smart contract function
813// func (c *Client) RollupGetTokenAddress(tokenID int64) (*ethCommon.Address, error) {
814// c.rw.RLock()
815// defer c.rw.RUnlock()
816//
817// log.Error("TODO")
818// return nil, errTODO
819// }
820
821// RollupGetL1TxFromQueue is the interface to call the smart contract function
822// func (c *Client) RollupGetL1TxFromQueue(queue int64, position int64) ([]byte, error) {
823// c.rw.RLock()
824// defer c.rw.RUnlock()
825//
826// log.Error("TODO")
827// return nil, errTODO
828// }
829
830// RollupGetQueue is the interface to call the smart contract function
831// func (c *Client) RollupGetQueue(queue int64) ([]byte, error) {
832// c.rw.RLock()
833// defer c.rw.RUnlock()
834//
835// log.Error("TODO")
836// return nil, errTODO
837// }
838
839// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
840func (c *Client) RollupUpdateForgeL1L2BatchTimeout(newForgeL1Timeout int64) (tx *types.Transaction, err error) {
841 c.rw.Lock()
842 defer c.rw.Unlock()
843 cpy := c.nextBlock().copy()
844 defer func() { c.revertIfErr(err, cpy) }()
845 if c.addr == nil {
846 return nil, eth.ErrAccountNil
847 }
848
849 log.Error("TODO")
850 return nil, errTODO
851}
852
853// RollupUpdateFeeAddToken is the interface to call the smart contract function
854func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
855 c.rw.Lock()
856 defer c.rw.Unlock()
857 cpy := c.nextBlock().copy()
858 defer func() { c.revertIfErr(err, cpy) }()
859 if c.addr == nil {
860 return nil, eth.ErrAccountNil
861 }
862
863 log.Error("TODO")
864 return nil, errTODO
865}
866
867// RollupUpdateTokensHEZ is the interface to call the smart contract function
868// func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (tx *types.Transaction, err error) {
869// c.rw.Lock()
870// defer c.rw.Unlock()
871// cpy := c.nextBlock().copy()
872// defer func() { c.revertIfErr(err, cpy) }()
873//
874// log.Error("TODO")
875// return nil, errTODO
876// }
877
878// RollupUpdateGovernance is the interface to call the smart contract function
879// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
880// return nil, errTODO
881// }
882
883// RollupConstants returns the Constants of the Rollup Smart Contract
884func (c *Client) RollupConstants() (*eth.RollupConstants, error) {
885 c.rw.RLock()
886 defer c.rw.RUnlock()
887
888 log.Error("TODO")
889 return nil, errTODO
890}
891
892// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
893func (c *Client) RollupEventsByBlock(blockNum int64) (*eth.RollupEvents, *ethCommon.Hash, error) {
894 c.rw.RLock()
895 defer c.rw.RUnlock()
896
897 block, ok := c.blocks[blockNum]
898 if !ok {
899 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
900 }
901 return &block.Rollup.Events, &block.Eth.Hash, nil
902}
903
904// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction
905func (c *Client) RollupForgeBatchArgs(ethTxHash ethCommon.Hash) (*eth.RollupForgeBatchArgs, error) {
906 c.rw.RLock()
907 defer c.rw.RUnlock()
908
909 forgeBatchArgs, ok := c.forgeBatchArgs[ethTxHash]
910 if !ok {
911 return nil, fmt.Errorf("transaction not found")
912 }
913 return forgeBatchArgs, nil
914}
915
916//
917// Auction
918//
919
920// AuctionSetSlotDeadline is the interface to call the smart contract function
921func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (tx *types.Transaction, err error) {
922 c.rw.Lock()
923 defer c.rw.Unlock()
924 cpy := c.nextBlock().copy()
925 defer func() { c.revertIfErr(err, cpy) }()
926 if c.addr == nil {
927 return nil, eth.ErrAccountNil
928 }
929
930 log.Error("TODO")
931 return nil, errTODO
932}
933
934// AuctionGetSlotDeadline is the interface to call the smart contract function
935func (c *Client) AuctionGetSlotDeadline() (uint8, error) {
936 c.rw.RLock()
937 defer c.rw.RUnlock()
938
939 log.Error("TODO")
940 return 0, errTODO
941}
942
943// AuctionSetOpenAuctionSlots is the interface to call the smart contract function
944func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (tx *types.Transaction, err error) {
945 c.rw.Lock()
946 defer c.rw.Unlock()
947 cpy := c.nextBlock().copy()
948 defer func() { c.revertIfErr(err, cpy) }()
949 if c.addr == nil {
950 return nil, eth.ErrAccountNil
951 }
952
953 log.Error("TODO")
954 return nil, errTODO
955}
956
957// AuctionGetOpenAuctionSlots is the interface to call the smart contract function
958func (c *Client) AuctionGetOpenAuctionSlots() (uint16, error) {
959 c.rw.RLock()
960 defer c.rw.RUnlock()
961
962 log.Error("TODO")
963 return 0, errTODO
964}
965
966// AuctionSetClosedAuctionSlots is the interface to call the smart contract function
967func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (tx *types.Transaction, err error) {
968 c.rw.Lock()
969 defer c.rw.Unlock()
970 cpy := c.nextBlock().copy()
971 defer func() { c.revertIfErr(err, cpy) }()
972 if c.addr == nil {
973 return nil, eth.ErrAccountNil
974 }
975
976 log.Error("TODO")
977 return nil, errTODO
978}
979
980// AuctionGetClosedAuctionSlots is the interface to call the smart contract function
981func (c *Client) AuctionGetClosedAuctionSlots() (uint16, error) {
982 c.rw.RLock()
983 defer c.rw.RUnlock()
984
985 log.Error("TODO")
986 return 0, errTODO
987}
988
989// AuctionSetOutbidding is the interface to call the smart contract function
990func (c *Client) AuctionSetOutbidding(newOutbidding uint16) (tx *types.Transaction, err error) {
991 c.rw.Lock()
992 defer c.rw.Unlock()
993 cpy := c.nextBlock().copy()
994 defer func() { c.revertIfErr(err, cpy) }()
995 if c.addr == nil {
996 return nil, eth.ErrAccountNil
997 }
998
999 log.Error("TODO")
1000 return nil, errTODO
1001}
1002
1003// AuctionGetOutbidding is the interface to call the smart contract function
1004func (c *Client) AuctionGetOutbidding() (uint16, error) {
1005 c.rw.RLock()
1006 defer c.rw.RUnlock()
1007
1008 log.Error("TODO")
1009 return 0, errTODO
1010}
1011
1012// AuctionSetAllocationRatio is the interface to call the smart contract function
1013func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (tx *types.Transaction, err error) {
1014 c.rw.Lock()
1015 defer c.rw.Unlock()
1016 cpy := c.nextBlock().copy()
1017 defer func() { c.revertIfErr(err, cpy) }()
1018 if c.addr == nil {
1019 return nil, eth.ErrAccountNil
1020 }
1021
1022 log.Error("TODO")
1023 return nil, errTODO
1024}
1025
1026// AuctionGetAllocationRatio is the interface to call the smart contract function
1027func (c *Client) AuctionGetAllocationRatio() ([3]uint16, error) {
1028 c.rw.RLock()
1029 defer c.rw.RUnlock()
1030
1031 log.Error("TODO")
1032 return [3]uint16{}, errTODO
1033}
1034
1035// AuctionSetDonationAddress is the interface to call the smart contract function
1036func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (tx *types.Transaction, err error) {
1037 c.rw.Lock()
1038 defer c.rw.Unlock()
1039 cpy := c.nextBlock().copy()
1040 defer func() { c.revertIfErr(err, cpy) }()
1041 if c.addr == nil {
1042 return nil, eth.ErrAccountNil
1043 }
1044
1045 log.Error("TODO")
1046 return nil, errTODO
1047}
1048
1049// AuctionGetDonationAddress is the interface to call the smart contract function
1050func (c *Client) AuctionGetDonationAddress() (*ethCommon.Address, error) {
1051 c.rw.RLock()
1052 defer c.rw.RUnlock()
1053
1054 log.Error("TODO")
1055 return nil, errTODO
1056}
1057
1058// AuctionSetBootCoordinator is the interface to call the smart contract function
1059func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (tx *types.Transaction, err error) {
1060 c.rw.Lock()
1061 defer c.rw.Unlock()
1062 cpy := c.nextBlock().copy()
1063 defer func() { c.revertIfErr(err, cpy) }()
1064 if c.addr == nil {
1065 return nil, eth.ErrAccountNil
1066 }
1067
1068 log.Error("TODO")
1069 return nil, errTODO
1070}
1071
1072// AuctionGetBootCoordinator is the interface to call the smart contract function
1073func (c *Client) AuctionGetBootCoordinator() (*ethCommon.Address, error) {
1074 c.rw.RLock()
1075 defer c.rw.RUnlock()
1076
1077 currentBlock := c.currentBlock()
1078 a := currentBlock.Auction
1079
1080 return &a.Vars.BootCoordinator, nil
1081}
1082
1083// AuctionChangeDefaultSlotSetBid is the interface to call the smart contract function
1084func (c *Client) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (tx *types.Transaction, err error) {
1085 c.rw.Lock()
1086 defer c.rw.Unlock()
1087 cpy := c.nextBlock().copy()
1088 defer func() { c.revertIfErr(err, cpy) }()
1089 if c.addr == nil {
1090 return nil, eth.ErrAccountNil
1091 }
1092
1093 log.Error("TODO")
1094 return nil, errTODO
1095}
1096
1097// AuctionRegisterCoordinator is the interface to call the smart contract function
1098func (c *Client) AuctionRegisterCoordinator(forgerAddress ethCommon.Address, URL string) (tx *types.Transaction, err error) {
1099 c.rw.Lock()
1100 defer c.rw.Unlock()
1101 cpy := c.nextBlock().copy()
1102 defer func() { c.revertIfErr(err, cpy) }()
1103 if c.addr == nil {
1104 return nil, eth.ErrAccountNil
1105 }
1106
1107 nextBlock := c.nextBlock()
1108 a := nextBlock.Auction
1109
1110 if _, ok := a.State.Coordinators[forgerAddress]; ok {
1111 return nil, fmt.Errorf("Already registered")
1112 }
1113 a.State.Coordinators[forgerAddress] = ð.Coordinator{
1114 WithdrawalAddress: *c.addr,
1115 URL: URL,
1116 }
1117
1118 a.Events.NewCoordinator = append(a.Events.NewCoordinator,
1119 eth.AuctionEventNewCoordinator{
1120 ForgerAddress: forgerAddress,
1121 WithdrawalAddress: *c.addr,
1122 CoordinatorURL: URL,
1123 })
1124
1125 type data struct {
1126 ForgerAddress ethCommon.Address
1127 URL string
1128 }
1129 return a.addTransaction(newTransaction("registercoordinator", data{forgerAddress, URL})), nil
1130}
1131
1132// AuctionIsRegisteredCoordinator is the interface to call the smart contract function
1133func (c *Client) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) {
1134 c.rw.RLock()
1135 defer c.rw.RUnlock()
1136
1137 log.Error("TODO")
1138 return false, errTODO
1139}
1140
1141// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function
1142func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (tx *types.Transaction, err error) {
1143 c.rw.Lock()
1144 defer c.rw.Unlock()
1145 cpy := c.nextBlock().copy()
1146 defer func() { c.revertIfErr(err, cpy) }()
1147 if c.addr == nil {
1148 return nil, eth.ErrAccountNil
1149 }
1150
1151 log.Error("TODO")
1152 return nil, errTODO
1153}
1154
1155// AuctionGetSlotNumber is the interface to call the smart contract function
1156func (c *Client) AuctionGetSlotNumber(blockNum int64) (int64, error) {
1157 c.rw.RLock()
1158 defer c.rw.RUnlock()
1159
1160 currentBlock := c.currentBlock()
1161 a := currentBlock.Auction
1162 return a.getSlotNumber(blockNum), nil
1163}
1164
1165// AuctionGetCurrentSlotNumber is the interface to call the smart contract function
1166func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) {
1167 c.rw.RLock()
1168 defer c.rw.RUnlock()
1169
1170 log.Error("TODO")
1171 return 0, errTODO
1172}
1173
1174// AuctionGetMinBidBySlot is the interface to call the smart contract function
1175func (c *Client) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) {
1176 c.rw.RLock()
1177 defer c.rw.RUnlock()
1178
1179 log.Error("TODO")
1180 return nil, errTODO
1181}
1182
1183// AuctionGetDefaultSlotSetBid is the interface to call the smart contract function
1184func (c *Client) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) {
1185 c.rw.RLock()
1186 defer c.rw.RUnlock()
1187
1188 log.Error("TODO")
1189 return nil, errTODO
1190}
1191
1192// AuctionGetSlotSet is the interface to call the smart contract function
1193func (c *Client) AuctionGetSlotSet(slot int64) (*big.Int, error) {
1194 c.rw.RLock()
1195 defer c.rw.RUnlock()
1196
1197 log.Error("TODO")
1198 return nil, errTODO
1199}
1200
1201// AuctionTokensReceived is the interface to call the smart contract function
1202// func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error {
1203// return errTODO
1204// }
1205
1206// AuctionBid is the interface to call the smart contract function
1207func (c *Client) AuctionBid(slot int64, bidAmount *big.Int, forger ethCommon.Address) (tx *types.Transaction, err error) {
1208 c.rw.Lock()
1209 defer c.rw.Unlock()
1210 cpy := c.nextBlock().copy()
1211 defer func() { func() { c.revertIfErr(err, cpy) }() }()
1212 if c.addr == nil {
1213 return nil, eth.ErrAccountNil
1214 }
1215
1216 nextBlock := c.nextBlock()
1217 a := nextBlock.Auction
1218
1219 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
1220 return nil, errBidClosed
1221 }
1222
1223 if slot >= a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots)+int64(a.Vars.OpenAuctionSlots) {
1224 return nil, errBidNotOpen
1225 }
1226
1227 minBid, err := a.getMinBidBySlot(slot)
1228 if err != nil {
1229 return nil, err
1230 }
1231 if bidAmount.Cmp(minBid) == -1 {
1232 return nil, errBidBelowMin
1233 }
1234
1235 if _, ok := a.State.Coordinators[forger]; !ok {
1236 return nil, errCoordNotReg
1237 }
1238
1239 slotState, ok := a.State.Slots[slot]
1240 if !ok {
1241 slotState = eth.NewSlotState()
1242 a.State.Slots[slot] = slotState
1243 }
1244 slotState.Forger = forger
1245 slotState.BidAmount = bidAmount
1246
1247 a.Events.NewBid = append(a.Events.NewBid,
1248 eth.AuctionEventNewBid{Slot: slot, BidAmount: bidAmount, CoordinatorForger: forger})
1249
1250 type data struct {
1251 Slot int64
1252 BidAmount *big.Int
1253 Forger ethCommon.Address
1254 }
1255 return a.addTransaction(newTransaction("bid", data{slot, bidAmount, forger})), nil
1256}
1257
1258// AuctionMultiBid is the interface to call the smart contract function
1259func (c *Client) AuctionMultiBid(startingSlot int64, endingSlot int64, slotSet [6]bool, maxBid, closedMinBid, budget *big.Int, forger ethCommon.Address) (tx *types.Transaction, err error) {
1260 c.rw.Lock()
1261 defer c.rw.Unlock()
1262 cpy := c.nextBlock().copy()
1263 defer func() { c.revertIfErr(err, cpy) }()
1264 if c.addr == nil {
1265 return nil, eth.ErrAccountNil
1266 }
1267
1268 log.Error("TODO")
1269 return nil, errTODO
1270}
1271
1272// AuctionCanForge is the interface to call the smart contract function
1273func (c *Client) AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error) {
1274 c.rw.RLock()
1275 defer c.rw.RUnlock()
1276
1277 currentBlock := c.currentBlock()
1278 a := currentBlock.Auction
1279 return a.canForge(forger, blockNum)
1280}
1281
1282// AuctionForge is the interface to call the smart contract function
1283// func (c *Client) AuctionForge(forger ethCommon.Address) (bool, error) {
1284// return false, errTODO
1285// }
1286
1287// AuctionClaimHEZ is the interface to call the smart contract function
1288func (c *Client) AuctionClaimHEZ(claimAddress ethCommon.Address) (tx *types.Transaction, err error) {
1289 c.rw.Lock()
1290 defer c.rw.Unlock()
1291 cpy := c.nextBlock().copy()
1292 defer func() { c.revertIfErr(err, cpy) }()
1293 if c.addr == nil {
1294 return nil, eth.ErrAccountNil
1295 }
1296
1297 log.Error("TODO")
1298 return nil, errTODO
1299}
1300
1301// AuctionConstants returns the Constants of the Auction Smart Contract
1302func (c *Client) AuctionConstants() (*eth.AuctionConstants, error) {
1303 c.rw.RLock()
1304 defer c.rw.RUnlock()
1305
1306 return c.auctionConstants, nil
1307}
1308
1309// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract
1310func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethCommon.Hash, error) {
1311 c.rw.RLock()
1312 defer c.rw.RUnlock()
1313
1314 block, ok := c.blocks[blockNum]
1315 if !ok {
1316 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
1317 }
1318 return &block.Auction.Events, &block.Eth.Hash, nil
1319}