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