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