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