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