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 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 L1UserTx: *l1Tx,
603 ToForgeL1TxsNum: r.State.LastToForgeL1TxsNum,
604 Position: len(queue.L1TxQueue) - 1,
605 })
606}
607
608// RollupL1UserTxERC20ETH is the interface to call the smart contract function
609func (c *Client) RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error) {
610 log.Error("TODO")
611 return nil, errTODO
612}
613
614// RollupL1UserTxERC777 is the interface to call the smart contract function
615func (c *Client) RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error) {
616 log.Error("TODO")
617 return nil, errTODO
618}
619
620// RollupRegisterTokensCount is the interface to call the smart contract function
621func (c *Client) RollupRegisterTokensCount() (*big.Int, error) {
622 log.Error("TODO")
623 return nil, errTODO
624}
625
626// RollupWithdrawCircuit is the interface to call the smart contract function
627func (c *Client) RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error) {
628 log.Error("TODO")
629 return nil, errTODO
630}
631
632// RollupWithdrawMerkleProof is the interface to call the smart contract function
633func (c *Client) RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error) {
634 log.Error("TODO")
635 return nil, errTODO
636}
637
638type transactionData struct {
639 Name string
640 Value interface{}
641}
642
643func newTransaction(name string, value interface{}) *types.Transaction {
644 data, err := json.Marshal(transactionData{name, value})
645 if err != nil {
646 panic(err)
647 }
648 return types.NewTransaction(0, ethCommon.Address{}, nil, 0, nil,
649 data)
650}
651
652// RollupForgeBatch is the interface to call the smart contract function
653func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Transaction, err error) {
654 c.rw.Lock()
655 defer c.rw.Unlock()
656 cpy := c.nextBlock().copy()
657 defer func() { c.revertIfErr(err, cpy) }()
658 if c.addr == nil {
659 return nil, eth.ErrAccountNil
660 }
661
662 a := c.nextBlock().Auction
663 ok, err := a.canForge(*c.addr, a.Eth.BlockNum)
664 if err != nil {
665 return nil, err
666 }
667 if !ok {
668 return nil, fmt.Errorf("incorrect slot")
669 }
670
671 // TODO: Verify proof
672
673 // Auction
674 err = a.forge(*c.addr)
675 if err != nil {
676 return nil, err
677 }
678
679 // TODO: If successful, store the tx in a successful array.
680 // TODO: If failed, store the tx in a failed array.
681 // TODO: Add method to move the tx to another block, reapply it there, and possibly go from successful to failed.
682
683 return c.addBatch(args)
684}
685
686// CtlAddBatch adds forged batch to the Rollup, without checking any ZKProof
687func (c *Client) CtlAddBatch(args *eth.RollupForgeBatchArgs) {
688 c.rw.Lock()
689 defer c.rw.Unlock()
690
691 if _, err := c.addBatch(args); err != nil {
692 panic(err)
693 }
694}
695
696func (c *Client) addBatch(args *eth.RollupForgeBatchArgs) (*types.Transaction, error) {
697 nextBlock := c.nextBlock()
698 r := nextBlock.Rollup
699 r.State.StateRoot = args.NewStRoot
700 if args.NewLastIdx < r.State.CurrentIdx {
701 return nil, fmt.Errorf("args.NewLastIdx < r.State.CurrentIdx")
702 }
703 r.State.CurrentIdx = args.NewLastIdx
704 r.State.ExitRoots = append(r.State.ExitRoots, args.NewExitRoot)
705 if args.L1Batch {
706 r.State.CurrentToForgeL1TxsNum++
707 if r.State.CurrentToForgeL1TxsNum == r.State.LastToForgeL1TxsNum {
708 r.State.LastToForgeL1TxsNum++
709 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
710 }
711 }
712 ethTx := r.addTransaction(newTransaction("forgebatch", args))
713 c.forgeBatchArgsPending[ethTx.Hash()] = args
714 r.Events.ForgeBatch = append(r.Events.ForgeBatch, eth.RollupEventForgeBatch{
715 BatchNum: int64(len(r.State.ExitRoots)),
716 EthTxHash: ethTx.Hash(),
717 })
718
719 return ethTx, nil
720}
721
722// RollupAddToken is the interface to call the smart contract function
723func (c *Client) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int) (tx *types.Transaction, err error) {
724 c.rw.Lock()
725 defer c.rw.Unlock()
726 cpy := c.nextBlock().copy()
727 defer func() { c.revertIfErr(err, cpy) }()
728 if c.addr == nil {
729 return nil, eth.ErrAccountNil
730 }
731
732 nextBlock := c.nextBlock()
733 r := nextBlock.Rollup
734 if _, ok := r.State.TokenMap[tokenAddress]; ok {
735 return nil, fmt.Errorf("Token %v already registered", tokenAddress)
736 }
737 if feeAddToken.Cmp(r.Vars.FeeAddToken) != 0 {
738 return nil, fmt.Errorf("Expected fee: %v but got: %v", r.Vars.FeeAddToken, feeAddToken)
739 }
740
741 r.State.TokenMap[tokenAddress] = true
742 r.State.TokenList = append(r.State.TokenList, tokenAddress)
743 r.Events.AddToken = append(r.Events.AddToken, eth.RollupEventAddToken{TokenAddress: tokenAddress,
744 TokenID: uint32(len(r.State.TokenList) - 1)})
745 return r.addTransaction(newTransaction("addtoken", tokenAddress)), nil
746}
747
748// RollupGetCurrentTokens is the interface to call the smart contract function
749func (c *Client) RollupGetCurrentTokens() (*big.Int, 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 if c.addr == nil {
764 return nil, eth.ErrAccountNil
765 }
766
767 log.Error("TODO")
768 return nil, errTODO
769}
770
771// RollupUpdateFeeAddToken is the interface to call the smart contract function
772func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
773 c.rw.Lock()
774 defer c.rw.Unlock()
775 cpy := c.nextBlock().copy()
776 defer func() { c.revertIfErr(err, cpy) }()
777 if c.addr == nil {
778 return nil, eth.ErrAccountNil
779 }
780
781 log.Error("TODO")
782 return nil, errTODO
783}
784
785// RollupUpdateTokensHEZ is the interface to call the smart contract function
786// func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (tx *types.Transaction, err error) {
787// c.rw.Lock()
788// defer c.rw.Unlock()
789// cpy := c.nextBlock().copy()
790// defer func() { c.revertIfErr(err, cpy) }()
791//
792// log.Error("TODO")
793// return nil, errTODO
794// }
795
796// RollupUpdateGovernance is the interface to call the smart contract function
797// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
798// return nil, errTODO
799// }
800
801// RollupConstants returns the Constants of the Rollup Smart Contract
802func (c *Client) RollupConstants() (*eth.RollupPublicConstants, error) {
803 c.rw.RLock()
804 defer c.rw.RUnlock()
805
806 log.Error("TODO")
807 return nil, errTODO
808}
809
810// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
811func (c *Client) RollupEventsByBlock(blockNum int64) (*eth.RollupEvents, *ethCommon.Hash, error) {
812 c.rw.RLock()
813 defer c.rw.RUnlock()
814
815 block, ok := c.blocks[blockNum]
816 if !ok {
817 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
818 }
819 return &block.Rollup.Events, &block.Eth.Hash, nil
820}
821
822// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction
823func (c *Client) RollupForgeBatchArgs(ethTxHash ethCommon.Hash) (*eth.RollupForgeBatchArgs, error) {
824 c.rw.RLock()
825 defer c.rw.RUnlock()
826
827 forgeBatchArgs, ok := c.forgeBatchArgs[ethTxHash]
828 if !ok {
829 return nil, fmt.Errorf("transaction not found")
830 }
831 return forgeBatchArgs, nil
832}
833
834//
835// Auction
836//
837
838// AuctionSetSlotDeadline is the interface to call the smart contract function
839func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (tx *types.Transaction, err error) {
840 c.rw.Lock()
841 defer c.rw.Unlock()
842 cpy := c.nextBlock().copy()
843 defer func() { c.revertIfErr(err, cpy) }()
844 if c.addr == nil {
845 return nil, eth.ErrAccountNil
846 }
847
848 log.Error("TODO")
849 return nil, errTODO
850}
851
852// AuctionGetSlotDeadline is the interface to call the smart contract function
853func (c *Client) AuctionGetSlotDeadline() (uint8, error) {
854 c.rw.RLock()
855 defer c.rw.RUnlock()
856
857 log.Error("TODO")
858 return 0, errTODO
859}
860
861// AuctionSetOpenAuctionSlots is the interface to call the smart contract function
862func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (tx *types.Transaction, err error) {
863 c.rw.Lock()
864 defer c.rw.Unlock()
865 cpy := c.nextBlock().copy()
866 defer func() { c.revertIfErr(err, cpy) }()
867 if c.addr == nil {
868 return nil, eth.ErrAccountNil
869 }
870
871 log.Error("TODO")
872 return nil, errTODO
873}
874
875// AuctionGetOpenAuctionSlots is the interface to call the smart contract function
876func (c *Client) AuctionGetOpenAuctionSlots() (uint16, error) {
877 c.rw.RLock()
878 defer c.rw.RUnlock()
879
880 log.Error("TODO")
881 return 0, errTODO
882}
883
884// AuctionSetClosedAuctionSlots is the interface to call the smart contract function
885func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (tx *types.Transaction, err error) {
886 c.rw.Lock()
887 defer c.rw.Unlock()
888 cpy := c.nextBlock().copy()
889 defer func() { c.revertIfErr(err, cpy) }()
890 if c.addr == nil {
891 return nil, eth.ErrAccountNil
892 }
893
894 log.Error("TODO")
895 return nil, errTODO
896}
897
898// AuctionGetClosedAuctionSlots is the interface to call the smart contract function
899func (c *Client) AuctionGetClosedAuctionSlots() (uint16, error) {
900 c.rw.RLock()
901 defer c.rw.RUnlock()
902
903 log.Error("TODO")
904 return 0, errTODO
905}
906
907// AuctionSetOutbidding is the interface to call the smart contract function
908func (c *Client) AuctionSetOutbidding(newOutbidding uint16) (tx *types.Transaction, err error) {
909 c.rw.Lock()
910 defer c.rw.Unlock()
911 cpy := c.nextBlock().copy()
912 defer func() { c.revertIfErr(err, cpy) }()
913 if c.addr == nil {
914 return nil, eth.ErrAccountNil
915 }
916
917 log.Error("TODO")
918 return nil, errTODO
919}
920
921// AuctionGetOutbidding is the interface to call the smart contract function
922func (c *Client) AuctionGetOutbidding() (uint16, error) {
923 c.rw.RLock()
924 defer c.rw.RUnlock()
925
926 log.Error("TODO")
927 return 0, errTODO
928}
929
930// AuctionSetAllocationRatio is the interface to call the smart contract function
931func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (tx *types.Transaction, err error) {
932 c.rw.Lock()
933 defer c.rw.Unlock()
934 cpy := c.nextBlock().copy()
935 defer func() { c.revertIfErr(err, cpy) }()
936 if c.addr == nil {
937 return nil, eth.ErrAccountNil
938 }
939
940 log.Error("TODO")
941 return nil, errTODO
942}
943
944// AuctionGetAllocationRatio is the interface to call the smart contract function
945func (c *Client) AuctionGetAllocationRatio() ([3]uint16, error) {
946 c.rw.RLock()
947 defer c.rw.RUnlock()
948
949 log.Error("TODO")
950 return [3]uint16{}, errTODO
951}
952
953// AuctionSetDonationAddress is the interface to call the smart contract function
954func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (tx *types.Transaction, err error) {
955 c.rw.Lock()
956 defer c.rw.Unlock()
957 cpy := c.nextBlock().copy()
958 defer func() { c.revertIfErr(err, cpy) }()
959 if c.addr == nil {
960 return nil, eth.ErrAccountNil
961 }
962
963 log.Error("TODO")
964 return nil, errTODO
965}
966
967// AuctionGetDonationAddress is the interface to call the smart contract function
968func (c *Client) AuctionGetDonationAddress() (*ethCommon.Address, error) {
969 c.rw.RLock()
970 defer c.rw.RUnlock()
971
972 log.Error("TODO")
973 return nil, errTODO
974}
975
976// AuctionSetBootCoordinator is the interface to call the smart contract function
977func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (tx *types.Transaction, err error) {
978 c.rw.Lock()
979 defer c.rw.Unlock()
980 cpy := c.nextBlock().copy()
981 defer func() { c.revertIfErr(err, cpy) }()
982 if c.addr == nil {
983 return nil, eth.ErrAccountNil
984 }
985
986 log.Error("TODO")
987 return nil, errTODO
988}
989
990// AuctionGetBootCoordinator is the interface to call the smart contract function
991func (c *Client) AuctionGetBootCoordinator() (*ethCommon.Address, error) {
992 c.rw.RLock()
993 defer c.rw.RUnlock()
994
995 currentBlock := c.currentBlock()
996 a := currentBlock.Auction
997
998 return &a.Vars.BootCoordinator, nil
999}
1000
1001// AuctionChangeDefaultSlotSetBid is the interface to call the smart contract function
1002func (c *Client) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (tx *types.Transaction, err error) {
1003 c.rw.Lock()
1004 defer c.rw.Unlock()
1005 cpy := c.nextBlock().copy()
1006 defer func() { c.revertIfErr(err, cpy) }()
1007 if c.addr == nil {
1008 return nil, eth.ErrAccountNil
1009 }
1010
1011 log.Error("TODO")
1012 return nil, errTODO
1013}
1014
1015// AuctionSetCoordinator is the interface to call the smart contract function
1016func (c *Client) AuctionSetCoordinator(forger ethCommon.Address, URL string) (tx *types.Transaction, err error) {
1017 c.rw.Lock()
1018 defer c.rw.Unlock()
1019 cpy := c.nextBlock().copy()
1020 defer func() { c.revertIfErr(err, cpy) }()
1021 if c.addr == nil {
1022 return nil, eth.ErrAccountNil
1023 }
1024
1025 nextBlock := c.nextBlock()
1026 a := nextBlock.Auction
1027
1028 a.State.Coordinators[*c.addr] = ð.Coordinator{
1029 Forger: forger,
1030 URL: URL,
1031 }
1032
1033 a.Events.SetCoordinator = append(a.Events.SetCoordinator,
1034 eth.AuctionEventSetCoordinator{
1035 BidderAddress: *c.addr,
1036 ForgerAddress: forger,
1037 CoordinatorURL: URL,
1038 })
1039
1040 type data struct {
1041 BidderAddress ethCommon.Address
1042 ForgerAddress ethCommon.Address
1043 URL string
1044 }
1045 return a.addTransaction(newTransaction("registercoordinator", data{*c.addr, forger, URL})), nil
1046}
1047
1048// AuctionIsRegisteredCoordinator is the interface to call the smart contract function
1049func (c *Client) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) {
1050 c.rw.RLock()
1051 defer c.rw.RUnlock()
1052
1053 log.Error("TODO")
1054 return false, errTODO
1055}
1056
1057// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function
1058func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (tx *types.Transaction, err error) {
1059 c.rw.Lock()
1060 defer c.rw.Unlock()
1061 cpy := c.nextBlock().copy()
1062 defer func() { c.revertIfErr(err, cpy) }()
1063 if c.addr == nil {
1064 return nil, eth.ErrAccountNil
1065 }
1066
1067 log.Error("TODO")
1068 return nil, errTODO
1069}
1070
1071// AuctionGetSlotNumber is the interface to call the smart contract function
1072func (c *Client) AuctionGetSlotNumber(blockNum int64) (int64, error) {
1073 c.rw.RLock()
1074 defer c.rw.RUnlock()
1075
1076 currentBlock := c.currentBlock()
1077 a := currentBlock.Auction
1078 return a.getSlotNumber(blockNum), nil
1079}
1080
1081// AuctionGetCurrentSlotNumber is the interface to call the smart contract function
1082func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) {
1083 c.rw.RLock()
1084 defer c.rw.RUnlock()
1085
1086 log.Error("TODO")
1087 return 0, errTODO
1088}
1089
1090// AuctionGetMinBidBySlot is the interface to call the smart contract function
1091func (c *Client) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) {
1092 c.rw.RLock()
1093 defer c.rw.RUnlock()
1094
1095 log.Error("TODO")
1096 return nil, errTODO
1097}
1098
1099// AuctionGetDefaultSlotSetBid is the interface to call the smart contract function
1100func (c *Client) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) {
1101 c.rw.RLock()
1102 defer c.rw.RUnlock()
1103
1104 log.Error("TODO")
1105 return nil, errTODO
1106}
1107
1108// AuctionGetSlotSet is the interface to call the smart contract function
1109func (c *Client) AuctionGetSlotSet(slot int64) (*big.Int, error) {
1110 c.rw.RLock()
1111 defer c.rw.RUnlock()
1112
1113 log.Error("TODO")
1114 return nil, errTODO
1115}
1116
1117// AuctionTokensReceived is the interface to call the smart contract function
1118// func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error {
1119// return errTODO
1120// }
1121
1122// AuctionBid is the interface to call the smart contract function
1123func (c *Client) AuctionBid(slot int64, bidAmount *big.Int) (tx *types.Transaction, err error) {
1124 c.rw.Lock()
1125 defer c.rw.Unlock()
1126 cpy := c.nextBlock().copy()
1127 defer func() { func() { c.revertIfErr(err, cpy) }() }()
1128 if c.addr == nil {
1129 return nil, eth.ErrAccountNil
1130 }
1131
1132 nextBlock := c.nextBlock()
1133 a := nextBlock.Auction
1134
1135 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
1136 return nil, errBidClosed
1137 }
1138
1139 if slot >= a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots)+int64(a.Vars.OpenAuctionSlots) {
1140 return nil, errBidNotOpen
1141 }
1142
1143 minBid, err := a.getMinBidBySlot(slot)
1144 if err != nil {
1145 return nil, err
1146 }
1147 if bidAmount.Cmp(minBid) == -1 {
1148 return nil, errBidBelowMin
1149 }
1150
1151 if _, ok := a.State.Coordinators[*c.addr]; !ok {
1152 return nil, errCoordNotReg
1153 }
1154
1155 slotState, ok := a.State.Slots[slot]
1156 if !ok {
1157 slotState = eth.NewSlotState()
1158 a.State.Slots[slot] = slotState
1159 }
1160 slotState.Bidder = *c.addr
1161 slotState.BidAmount = bidAmount
1162
1163 a.Events.NewBid = append(a.Events.NewBid,
1164 eth.AuctionEventNewBid{Slot: slot, BidAmount: bidAmount, Bidder: *c.addr})
1165
1166 type data struct {
1167 Slot int64
1168 BidAmount *big.Int
1169 Bidder ethCommon.Address
1170 }
1171 return a.addTransaction(newTransaction("bid", data{slot, bidAmount, *c.addr})), nil
1172}
1173
1174// AuctionMultiBid is the interface to call the smart contract function
1175func (c *Client) AuctionMultiBid(startingSlot int64, endingSlot int64, slotSet [6]bool, maxBid, closedMinBid, budget *big.Int) (tx *types.Transaction, err error) {
1176 c.rw.Lock()
1177 defer c.rw.Unlock()
1178 cpy := c.nextBlock().copy()
1179 defer func() { c.revertIfErr(err, cpy) }()
1180 if c.addr == nil {
1181 return nil, eth.ErrAccountNil
1182 }
1183
1184 log.Error("TODO")
1185 return nil, errTODO
1186}
1187
1188// AuctionCanForge is the interface to call the smart contract function
1189func (c *Client) AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error) {
1190 c.rw.RLock()
1191 defer c.rw.RUnlock()
1192
1193 currentBlock := c.currentBlock()
1194 a := currentBlock.Auction
1195 return a.canForge(forger, blockNum)
1196}
1197
1198// AuctionForge is the interface to call the smart contract function
1199func (c *Client) AuctionForge(forger ethCommon.Address) (tx *types.Transaction, err error) {
1200 c.rw.Lock()
1201 defer c.rw.Unlock()
1202 cpy := c.nextBlock().copy()
1203 defer func() { c.revertIfErr(err, cpy) }()
1204 if c.addr == nil {
1205 return nil, eth.ErrAccountNil
1206 }
1207
1208 log.Error("TODO")
1209 return nil, errTODO
1210}
1211
1212// AuctionClaimHEZ is the interface to call the smart contract function
1213func (c *Client) AuctionClaimHEZ() (tx *types.Transaction, err error) {
1214 c.rw.Lock()
1215 defer c.rw.Unlock()
1216 cpy := c.nextBlock().copy()
1217 defer func() { c.revertIfErr(err, cpy) }()
1218 if c.addr == nil {
1219 return nil, eth.ErrAccountNil
1220 }
1221
1222 log.Error("TODO")
1223 return nil, errTODO
1224}
1225
1226// AuctionGetClaimableHEZ is the interface to call the smart contract function
1227func (c *Client) AuctionGetClaimableHEZ(bidder ethCommon.Address) (*big.Int, error) {
1228 c.rw.RLock()
1229 defer c.rw.RUnlock()
1230
1231 log.Error("TODO")
1232 return nil, errTODO
1233}
1234
1235// AuctionConstants returns the Constants of the Auction Smart Contract
1236func (c *Client) AuctionConstants() (*eth.AuctionConstants, error) {
1237 c.rw.RLock()
1238 defer c.rw.RUnlock()
1239
1240 return c.auctionConstants, nil
1241}
1242
1243// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract
1244func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethCommon.Hash, error) {
1245 c.rw.RLock()
1246 defer c.rw.RUnlock()
1247
1248 block, ok := c.blocks[blockNum]
1249 if !ok {
1250 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
1251 }
1252 return &block.Auction.Events, &block.Eth.Hash, nil
1253}