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