arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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	"github.com/ethereum/go-ethereum"
  14	ethCommon "github.com/ethereum/go-ethereum/common"
  15	"github.com/ethereum/go-ethereum/core/types"
  16	"github.com/hermeznetwork/hermez-node/common"
  17	"github.com/hermeznetwork/hermez-node/eth"
  18	"github.com/hermeznetwork/hermez-node/log"
  19	"github.com/hermeznetwork/tracerr"
  20	"github.com/iden3/go-iden3-crypto/babyjub"
  21	"github.com/mitchellh/copystructure"
  22)
  23
  24func init() {
  25	copystructure.Copiers[reflect.TypeOf(big.Int{})] =
  26		func(raw interface{}) (interface{}, error) {
  27			in := raw.(big.Int)
  28			out := new(big.Int).Set(&in)
  29			return *out, nil
  30		}
  31}
  32
  33// WDelayerBlock stores all the data related to the WDelayer SC from an ethereum block
  34type WDelayerBlock struct {
  35	// State     eth.WDelayerState // TODO
  36	Vars      common.WDelayerVariables
  37	Events    eth.WDelayerEvents
  38	Txs       map[ethCommon.Hash]*types.Transaction
  39	Constants *common.WDelayerConstants
  40	Eth       *EthereumBlock
  41}
  42
  43func (w *WDelayerBlock) addTransaction(tx *types.Transaction) *types.Transaction {
  44	txHash := tx.Hash()
  45	w.Txs[txHash] = tx
  46	return tx
  47}
  48
  49func (w *WDelayerBlock) deposit(txHash ethCommon.Hash, owner, token ethCommon.Address, amount *big.Int) {
  50	w.Events.Deposit = append(w.Events.Deposit, eth.WDelayerEventDeposit{
  51		Owner:            owner,
  52		Token:            token,
  53		Amount:           amount,
  54		DepositTimestamp: uint64(w.Eth.Time),
  55		TxHash:           txHash,
  56	})
  57}
  58
  59// RollupBlock stores all the data related to the Rollup SC from an ethereum block
  60type RollupBlock struct {
  61	State     eth.RollupState
  62	Vars      common.RollupVariables
  63	Events    eth.RollupEvents
  64	Txs       map[ethCommon.Hash]*types.Transaction
  65	Constants *common.RollupConstants
  66	Eth       *EthereumBlock
  67}
  68
  69func (r *RollupBlock) addTransaction(tx *types.Transaction) *types.Transaction {
  70	txHash := tx.Hash()
  71	r.Txs[txHash] = tx
  72	return tx
  73}
  74
  75var (
  76	errBidClosed   = fmt.Errorf("Bid has already been closed")
  77	errBidNotOpen  = fmt.Errorf("Bid has not been opened yet")
  78	errBidBelowMin = fmt.Errorf("Bid below minimum")
  79	errCoordNotReg = fmt.Errorf("Coordinator not registered")
  80)
  81
  82// AuctionBlock stores all the data related to the Auction SC from an ethereum block
  83type AuctionBlock struct {
  84	State     eth.AuctionState
  85	Vars      common.AuctionVariables
  86	Events    eth.AuctionEvents
  87	Txs       map[ethCommon.Hash]*types.Transaction
  88	Constants *common.AuctionConstants
  89	Eth       *EthereumBlock
  90}
  91
  92func (a *AuctionBlock) addTransaction(tx *types.Transaction) *types.Transaction {
  93	txHash := tx.Hash()
  94	a.Txs[txHash] = tx
  95	return tx
  96}
  97
  98func (a *AuctionBlock) getSlotNumber(blockNumber int64) int64 {
  99	if a.Eth.BlockNum >= a.Constants.GenesisBlockNum {
 100		return (blockNumber - a.Constants.GenesisBlockNum) / int64(a.Constants.BlocksPerSlot)
 101	}
 102	return 0
 103}
 104
 105func (a *AuctionBlock) getCurrentSlotNumber() int64 {
 106	return a.getSlotNumber(a.Eth.BlockNum)
 107}
 108
 109func (a *AuctionBlock) getSlotSet(slot int64) int64 {
 110	return slot % int64(len(a.Vars.DefaultSlotSetBid))
 111}
 112
 113func (a *AuctionBlock) getMinBidBySlot(slot int64) (*big.Int, error) {
 114	if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
 115		return nil, tracerr.Wrap(errBidClosed)
 116	}
 117
 118	slotSet := a.getSlotSet(slot)
 119	// fmt.Println("slot:", slot, "slotSet:", slotSet)
 120	var prevBid *big.Int
 121	slotState, ok := a.State.Slots[slot]
 122	if !ok {
 123		slotState = eth.NewSlotState()
 124		a.State.Slots[slot] = slotState
 125	}
 126	// If the bidAmount for a slot is 0 it means that it has not yet been bid, so the midBid will be the minimum
 127	// bid for the slot time plus the outbidding set, otherwise it will be the bidAmount plus the outbidding
 128	if slotState.BidAmount.Cmp(big.NewInt(0)) == 0 {
 129		prevBid = a.Vars.DefaultSlotSetBid[slotSet]
 130	} else {
 131		prevBid = slotState.BidAmount
 132	}
 133	outBid := new(big.Int).Set(prevBid)
 134	// fmt.Println("outBid:", outBid)
 135	outBid.Mul(outBid, big.NewInt(int64(a.Vars.Outbidding)))
 136	outBid.Div(outBid, big.NewInt(10000)) //nolint:gomnd
 137	outBid.Add(prevBid, outBid)
 138	// fmt.Println("minBid:", outBid)
 139	return outBid, nil
 140}
 141
 142func (a *AuctionBlock) forge(forger ethCommon.Address) error {
 143	if ok, err := a.canForge(forger, a.Eth.BlockNum); err != nil {
 144		return tracerr.Wrap(err)
 145	} else if !ok {
 146		return tracerr.Wrap(fmt.Errorf("Can't forge"))
 147	}
 148
 149	slotToForge := a.getSlotNumber(a.Eth.BlockNum)
 150	slotState, ok := a.State.Slots[slotToForge]
 151	if !ok {
 152		slotState = eth.NewSlotState()
 153		a.State.Slots[slotToForge] = slotState
 154	}
 155
 156	if !slotState.ForgerCommitment {
 157		// Get the relativeBlock to check if the slotDeadline has been exceeded
 158		relativeBlock := a.Eth.BlockNum - (a.Constants.GenesisBlockNum +
 159			(slotToForge * int64(a.Constants.BlocksPerSlot)))
 160
 161		if relativeBlock < int64(a.Vars.SlotDeadline) {
 162			slotState.ForgerCommitment = true
 163		}
 164	}
 165
 166	slotState.Fulfilled = true
 167
 168	a.Events.NewForge = append(a.Events.NewForge, eth.AuctionEventNewForge{
 169		Forger:      forger,
 170		SlotToForge: slotToForge,
 171	})
 172	return nil
 173}
 174
 175func (a *AuctionBlock) canForge(forger ethCommon.Address, blockNum int64) (bool, error) {
 176	if blockNum < a.Constants.GenesisBlockNum {
 177		return false, tracerr.Wrap(fmt.Errorf("Auction has not started yet"))
 178	}
 179
 180	slotToForge := a.getSlotNumber(blockNum)
 181	// fmt.Printf("DBG canForge slot: %v\n", slotToForge)
 182	// Get the relativeBlock to check if the slotDeadline has been exceeded
 183	relativeBlock := blockNum - (a.Constants.GenesisBlockNum + (slotToForge * int64(a.Constants.BlocksPerSlot)))
 184
 185	// If the closedMinBid is 0 it means that we have to take as minBid the one that is set for this slot set,
 186	// otherwise the one that has been saved will be used
 187	var minBid *big.Int
 188	slotState, ok := a.State.Slots[slotToForge]
 189	if !ok {
 190		slotState = eth.NewSlotState()
 191		a.State.Slots[slotToForge] = slotState
 192	}
 193	if slotState.ClosedMinBid.Cmp(big.NewInt(0)) == 0 {
 194		minBid = a.Vars.DefaultSlotSetBid[a.getSlotSet(slotToForge)]
 195	} else {
 196		minBid = slotState.ClosedMinBid
 197	}
 198
 199	if !slotState.ForgerCommitment && (relativeBlock >= int64(a.Vars.SlotDeadline)) {
 200		// if the relative block has exceeded the slotDeadline and no batch has been forged, anyone can forge
 201		return true, nil
 202	} else if coord, ok := a.State.Coordinators[slotState.Bidder]; ok &&
 203		coord.Forger == forger && slotState.BidAmount.Cmp(minBid) >= 0 {
 204		// if forger bidAmount has exceeded the minBid it can forge
 205		return true, nil
 206	} else if a.Vars.BootCoordinator == forger && slotState.BidAmount.Cmp(minBid) == -1 {
 207		// if it's the boot coordinator and it has not been bid or the bid is below the minimum it can forge
 208		return true, nil
 209	} else {
 210		return false, nil
 211	}
 212}
 213
 214// EthereumBlock stores all the generic data related to the an ethereum block
 215type EthereumBlock struct {
 216	BlockNum   int64
 217	Time       int64
 218	Hash       ethCommon.Hash
 219	ParentHash ethCommon.Hash
 220	Tokens     map[ethCommon.Address]eth.ERC20Consts
 221	Nonce      uint64
 222	// state      ethState
 223}
 224
 225// Block represents a ethereum block
 226type Block struct {
 227	Rollup   *RollupBlock
 228	Auction  *AuctionBlock
 229	WDelayer *WDelayerBlock
 230	Eth      *EthereumBlock
 231}
 232
 233func (b *Block) copy() *Block {
 234	bCopyRaw, err := copystructure.Copy(b)
 235	if err != nil {
 236		panic(err)
 237	}
 238	bCopy := bCopyRaw.(*Block)
 239	return bCopy
 240}
 241
 242// Next prepares the successive block.
 243func (b *Block) Next() *Block {
 244	blockNext := b.copy()
 245	blockNext.Rollup.Events = eth.NewRollupEvents()
 246	blockNext.Auction.Events = eth.NewAuctionEvents()
 247
 248	blockNext.Eth.BlockNum = b.Eth.BlockNum + 1
 249	blockNext.Eth.ParentHash = b.Eth.Hash
 250
 251	blockNext.Rollup.Constants = b.Rollup.Constants
 252	blockNext.Auction.Constants = b.Auction.Constants
 253	blockNext.WDelayer.Constants = b.WDelayer.Constants
 254	blockNext.Rollup.Eth = blockNext.Eth
 255	blockNext.Auction.Eth = blockNext.Eth
 256	blockNext.WDelayer.Eth = blockNext.Eth
 257
 258	return blockNext
 259}
 260
 261// ClientSetup is used to initialize the constants of the Smart Contracts and
 262// other details of the test Client
 263type ClientSetup struct {
 264	RollupConstants   *common.RollupConstants
 265	RollupVariables   *common.RollupVariables
 266	AuctionConstants  *common.AuctionConstants
 267	AuctionVariables  *common.AuctionVariables
 268	WDelayerConstants *common.WDelayerConstants
 269	WDelayerVariables *common.WDelayerVariables
 270	VerifyProof       bool
 271}
 272
 273// NewClientSetupExample returns a ClientSetup example with hardcoded realistic
 274// values.  With this setup, the rollup genesis will be block 1, and block 0
 275// and 1 will be premined.
 276//nolint:gomnd
 277func NewClientSetupExample() *ClientSetup {
 278	// rfield, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
 279	// if !ok {
 280	// 	panic("bad rfield")
 281	// }
 282	initialMinimalBidding, ok := new(big.Int).SetString("10000000000000000000", 10) // 10 * (1e18)
 283	if !ok {
 284		panic("bad initialMinimalBidding")
 285	}
 286	tokenHEZ := ethCommon.HexToAddress("0x51D243D62852Bba334DD5cc33f242BAc8c698074")
 287	governanceAddress := ethCommon.HexToAddress("0x688EfD95BA4391f93717CF02A9aED9DBD2855cDd")
 288	rollupConstants := &common.RollupConstants{
 289		Verifiers: []common.RollupVerifierStruct{
 290			{
 291				MaxTx:   2048,
 292				NLevels: 32,
 293			},
 294		},
 295		TokenHEZ:                tokenHEZ,
 296		HermezGovernanceAddress: governanceAddress,
 297		HermezAuctionContract:   ethCommon.HexToAddress("0x8E442975805fb1908f43050c9C1A522cB0e28D7b"),
 298		WithdrawDelayerContract: ethCommon.HexToAddress("0x5CB7979cBdbf65719BEE92e4D15b7b7Ed3D79114"),
 299	}
 300	rollupVariables := &common.RollupVariables{
 301		FeeAddToken:           big.NewInt(11),
 302		ForgeL1L2BatchTimeout: 9,
 303		WithdrawalDelay:       80,
 304	}
 305	auctionConstants := &common.AuctionConstants{
 306		BlocksPerSlot:         40,
 307		InitialMinimalBidding: initialMinimalBidding,
 308		GenesisBlockNum:       1,
 309		GovernanceAddress:     governanceAddress,
 310		TokenHEZ:              tokenHEZ,
 311		HermezRollup:          ethCommon.HexToAddress("0x474B6e29852257491cf283EfB1A9C61eBFe48369"),
 312	}
 313	auctionVariables := &common.AuctionVariables{
 314		DonationAddress: ethCommon.HexToAddress("0x61Ed87CF0A1496b49A420DA6D84B58196b98f2e7"),
 315		BootCoordinator: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
 316		DefaultSlotSetBid: [6]*big.Int{
 317			big.NewInt(1000), big.NewInt(1100), big.NewInt(1200),
 318			big.NewInt(1300), big.NewInt(1400), big.NewInt(1500)},
 319		ClosedAuctionSlots: 2,
 320		OpenAuctionSlots:   4320,
 321		AllocationRatio:    [3]uint16{4000, 4000, 2000},
 322		Outbidding:         1000,
 323		SlotDeadline:       20,
 324	}
 325	wDelayerConstants := &common.WDelayerConstants{
 326		MaxWithdrawalDelay:   60 * 60 * 24 * 7 * 2,  // 2 weeks
 327		MaxEmergencyModeTime: 60 * 60 * 24 * 7 * 26, // 26 weeks
 328		HermezRollup:         auctionConstants.HermezRollup,
 329	}
 330	wDelayerVariables := &common.WDelayerVariables{
 331		HermezGovernanceAddress:   ethCommon.HexToAddress("0xcfD0d163AE6432a72682323E2C3A5a69e6B37D12"),
 332		EmergencyCouncilAddress:   ethCommon.HexToAddress("0x2730700932a4FDB97B9268A3Ca29f97Ea5fd7EA0"),
 333		WithdrawalDelay:           60,
 334		EmergencyModeStartingTime: 0,
 335		EmergencyMode:             false,
 336	}
 337	return &ClientSetup{
 338		RollupConstants:   rollupConstants,
 339		RollupVariables:   rollupVariables,
 340		AuctionConstants:  auctionConstants,
 341		AuctionVariables:  auctionVariables,
 342		WDelayerConstants: wDelayerConstants,
 343		WDelayerVariables: wDelayerVariables,
 344	}
 345}
 346
 347// Timer is an interface to simulate a source of time, useful to advance time
 348// virtually.
 349type Timer interface {
 350	Time() int64
 351}
 352
 353// type forgeBatchArgs struct {
 354// 	ethTx     *types.Transaction
 355// 	blockNum  int64
 356// 	blockHash ethCommon.Hash
 357// }
 358
 359type batch struct {
 360	ForgeBatchArgs eth.RollupForgeBatchArgs
 361	Sender         ethCommon.Address
 362}
 363
 364// Client implements the eth.ClientInterface interface, allowing to manipulate the
 365// values for testing, working with deterministic results.
 366type Client struct {
 367	rw                *sync.RWMutex
 368	log               bool
 369	addr              *ethCommon.Address
 370	rollupConstants   *common.RollupConstants
 371	auctionConstants  *common.AuctionConstants
 372	wDelayerConstants *common.WDelayerConstants
 373	blocks            map[int64]*Block
 374	// state            state
 375	blockNum    int64 // last mined block num
 376	maxBlockNum int64 // highest block num calculated
 377	timer       Timer
 378	hasher      hasher
 379
 380	forgeBatchArgsPending map[ethCommon.Hash]*batch
 381	forgeBatchArgs        map[ethCommon.Hash]*batch
 382}
 383
 384// NewClient returns a new test Client that implements the eth.IClient
 385// interface, at the given initialBlockNumber.
 386func NewClient(l bool, timer Timer, addr *ethCommon.Address, setup *ClientSetup) *Client {
 387	blocks := make(map[int64]*Block)
 388	blockNum := int64(0)
 389
 390	hasher := hasher{}
 391	// Add ethereum genesis block
 392	mapL1TxQueue := make(map[int64]*eth.QueueStruct)
 393	mapL1TxQueue[0] = eth.NewQueueStruct()
 394	mapL1TxQueue[1] = eth.NewQueueStruct()
 395	blockCurrent := &Block{
 396		Rollup: &RollupBlock{
 397			State: eth.RollupState{
 398				StateRoot:        big.NewInt(0),
 399				ExitRoots:        make([]*big.Int, 1),
 400				ExitNullifierMap: make(map[int64]map[int64]bool),
 401				// TokenID = 0 is ETH.  Set first entry in TokenList with 0x0 address for ETH.
 402				TokenList:              []ethCommon.Address{{}},
 403				TokenMap:               make(map[ethCommon.Address]bool),
 404				MapL1TxQueue:           mapL1TxQueue,
 405				LastL1L2Batch:          0,
 406				CurrentToForgeL1TxsNum: 0,
 407				LastToForgeL1TxsNum:    1,
 408				CurrentIdx:             0,
 409			},
 410			Vars:      *setup.RollupVariables,
 411			Txs:       make(map[ethCommon.Hash]*types.Transaction),
 412			Events:    eth.NewRollupEvents(),
 413			Constants: setup.RollupConstants,
 414		},
 415		Auction: &AuctionBlock{
 416			State: eth.AuctionState{
 417				Slots:           make(map[int64]*eth.SlotState),
 418				PendingBalances: make(map[ethCommon.Address]*big.Int),
 419				Coordinators:    make(map[ethCommon.Address]*eth.Coordinator),
 420			},
 421			Vars:      *setup.AuctionVariables,
 422			Txs:       make(map[ethCommon.Hash]*types.Transaction),
 423			Events:    eth.NewAuctionEvents(),
 424			Constants: setup.AuctionConstants,
 425		},
 426		WDelayer: &WDelayerBlock{
 427			// State: TODO
 428			Vars:      *setup.WDelayerVariables,
 429			Txs:       make(map[ethCommon.Hash]*types.Transaction),
 430			Events:    eth.NewWDelayerEvents(),
 431			Constants: setup.WDelayerConstants,
 432		},
 433		Eth: &EthereumBlock{
 434			BlockNum:   blockNum,
 435			Time:       timer.Time(),
 436			Hash:       hasher.Next(),
 437			ParentHash: ethCommon.Hash{},
 438			Tokens:     make(map[ethCommon.Address]eth.ERC20Consts),
 439		},
 440	}
 441	blockCurrent.Rollup.Eth = blockCurrent.Eth
 442	blockCurrent.Auction.Eth = blockCurrent.Eth
 443	blocks[blockNum] = blockCurrent
 444	blockNext := blockCurrent.Next()
 445	blocks[blockNum+1] = blockNext
 446
 447	c := Client{
 448		rw:                    &sync.RWMutex{},
 449		log:                   l,
 450		addr:                  addr,
 451		rollupConstants:       setup.RollupConstants,
 452		auctionConstants:      setup.AuctionConstants,
 453		wDelayerConstants:     setup.WDelayerConstants,
 454		blocks:                blocks,
 455		timer:                 timer,
 456		hasher:                hasher,
 457		forgeBatchArgsPending: make(map[ethCommon.Hash]*batch),
 458		forgeBatchArgs:        make(map[ethCommon.Hash]*batch),
 459		blockNum:              blockNum,
 460		maxBlockNum:           blockNum,
 461	}
 462
 463	for i := int64(1); i < setup.AuctionConstants.GenesisBlockNum+1; i++ {
 464		c.CtlMineBlock()
 465	}
 466
 467	return &c
 468}
 469
 470//
 471// Mock Control
 472//
 473
 474func (c *Client) setNextBlock(block *Block) {
 475	c.blocks[c.blockNum+1] = block
 476}
 477
 478func (c *Client) revertIfErr(err error, block *Block) {
 479	if err != nil {
 480		log.Infow("TestClient revert", "block", block.Eth.BlockNum, "err", err)
 481		c.setNextBlock(block)
 482	}
 483}
 484
 485// Debugf calls log.Debugf if c.log is true
 486func (c *Client) Debugf(template string, args ...interface{}) {
 487	if c.log {
 488		log.Debugf(template, args...)
 489	}
 490}
 491
 492// Debugw calls log.Debugw if c.log is true
 493func (c *Client) Debugw(template string, kv ...interface{}) {
 494	if c.log {
 495		log.Debugw(template, kv...)
 496	}
 497}
 498
 499type hasher struct {
 500	counter uint64
 501}
 502
 503// Next returns the next hash
 504func (h *hasher) Next() ethCommon.Hash {
 505	var hash ethCommon.Hash
 506	binary.LittleEndian.PutUint64(hash[:], h.counter)
 507	h.counter++
 508	return hash
 509}
 510
 511func (c *Client) nextBlock() *Block {
 512	return c.blocks[c.blockNum+1]
 513}
 514
 515func (c *Client) currentBlock() *Block {
 516	return c.blocks[c.blockNum]
 517}
 518
 519// CtlSetAddr sets the address of the client
 520func (c *Client) CtlSetAddr(addr ethCommon.Address) {
 521	c.addr = &addr
 522}
 523
 524// CtlMineBlock moves one block forward
 525func (c *Client) CtlMineBlock() {
 526	c.rw.Lock()
 527	defer c.rw.Unlock()
 528
 529	blockCurrent := c.nextBlock()
 530	c.blockNum++
 531	c.maxBlockNum = c.blockNum
 532	blockCurrent.Eth.Time = c.timer.Time()
 533	blockCurrent.Eth.Hash = c.hasher.Next()
 534	for ethTxHash, forgeBatchArgs := range c.forgeBatchArgsPending {
 535		c.forgeBatchArgs[ethTxHash] = forgeBatchArgs
 536	}
 537	c.forgeBatchArgsPending = make(map[ethCommon.Hash]*batch)
 538
 539	blockNext := blockCurrent.Next()
 540	c.blocks[c.blockNum+1] = blockNext
 541	c.Debugw("TestClient mined block", "blockNum", c.blockNum)
 542}
 543
 544// CtlRollback discards the last mined block.  Use this to replace a mined
 545// block to simulate reorgs.
 546func (c *Client) CtlRollback() {
 547	c.rw.Lock()
 548	defer c.rw.Unlock()
 549
 550	if c.blockNum == 0 {
 551		panic("Can't rollback at blockNum = 0")
 552	}
 553	delete(c.blocks, c.blockNum+1) // delete next block
 554	delete(c.blocks, c.blockNum)   // delete current block
 555	c.blockNum--
 556	blockCurrent := c.blocks[c.blockNum]
 557	blockNext := blockCurrent.Next()
 558	c.blocks[c.blockNum+1] = blockNext
 559}
 560
 561//
 562// Ethereum
 563//
 564
 565// CtlLastBlock returns the last blockNum without checks
 566func (c *Client) CtlLastBlock() *common.Block {
 567	c.rw.RLock()
 568	defer c.rw.RUnlock()
 569
 570	block := c.blocks[c.blockNum]
 571	return &common.Block{
 572		Num:        c.blockNum,
 573		Timestamp:  time.Unix(block.Eth.Time, 0),
 574		Hash:       block.Eth.Hash,
 575		ParentHash: block.Eth.ParentHash,
 576	}
 577}
 578
 579// CtlLastForgedBatch returns the last batchNum without checks
 580func (c *Client) CtlLastForgedBatch() int64 {
 581	c.rw.RLock()
 582	defer c.rw.RUnlock()
 583
 584	currentBlock := c.currentBlock()
 585	e := currentBlock.Rollup
 586	return int64(len(e.State.ExitRoots)) - 1
 587}
 588
 589// EthLastBlock returns the last blockNum
 590func (c *Client) EthLastBlock() (int64, error) {
 591	c.rw.RLock()
 592	defer c.rw.RUnlock()
 593
 594	if c.blockNum < c.maxBlockNum {
 595		panic("blockNum has decreased.  " +
 596			"After a rollback you must mine to reach the same or higher blockNum")
 597	}
 598	return c.blockNum, nil
 599}
 600
 601// EthTransactionReceipt returns the transaction receipt of the given txHash
 602func (c *Client) EthTransactionReceipt(ctx context.Context, txHash ethCommon.Hash) (*types.Receipt, error) {
 603	c.rw.RLock()
 604	defer c.rw.RUnlock()
 605
 606	for i := int64(0); i < c.blockNum; i++ {
 607		b := c.blocks[i]
 608		_, ok := b.Rollup.Txs[txHash]
 609		if !ok {
 610			_, ok = b.Auction.Txs[txHash]
 611		}
 612		if ok {
 613			return &types.Receipt{
 614				TxHash:      txHash,
 615				Status:      types.ReceiptStatusSuccessful,
 616				BlockHash:   b.Eth.Hash,
 617				BlockNumber: big.NewInt(b.Eth.BlockNum),
 618			}, nil
 619		}
 620	}
 621
 622	return nil, nil
 623}
 624
 625// CtlAddERC20 adds an ERC20 token to the blockchain.
 626func (c *Client) CtlAddERC20(tokenAddr ethCommon.Address, constants eth.ERC20Consts) {
 627	nextBlock := c.nextBlock()
 628	e := nextBlock.Eth
 629	e.Tokens[tokenAddr] = constants
 630}
 631
 632// EthERC20Consts returns the constants defined for a particular ERC20 Token instance.
 633func (c *Client) EthERC20Consts(tokenAddr ethCommon.Address) (*eth.ERC20Consts, error) {
 634	currentBlock := c.currentBlock()
 635	e := currentBlock.Eth
 636	if constants, ok := e.Tokens[tokenAddr]; ok {
 637		return &constants, nil
 638	}
 639	return nil, tracerr.Wrap(fmt.Errorf("tokenAddr not found"))
 640}
 641
 642// func newHeader(number *big.Int) *types.Header {
 643// 	return &types.Header{
 644// 		Number: number,
 645// 		Time:   uint64(number.Int64()),
 646// 	}
 647// }
 648
 649// EthHeaderByNumber returns the *types.Header for the given block number in a
 650// deterministic way.
 651// func (c *Client) EthHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
 652// 	return newHeader(number), nil
 653// }
 654
 655// EthBlockByNumber returns the *common.Block for the given block number in a
 656// deterministic way.  If number == -1, the latests known block is returned.
 657func (c *Client) EthBlockByNumber(ctx context.Context, blockNum int64) (*common.Block, error) {
 658	c.rw.RLock()
 659	defer c.rw.RUnlock()
 660
 661	if blockNum > c.blockNum {
 662		return nil, ethereum.NotFound
 663	}
 664	if blockNum == -1 {
 665		blockNum = c.blockNum
 666	}
 667	block := c.blocks[blockNum]
 668	return &common.Block{
 669		Num:        blockNum,
 670		Timestamp:  time.Unix(block.Eth.Time, 0),
 671		Hash:       block.Eth.Hash,
 672		ParentHash: block.Eth.ParentHash,
 673	}, nil
 674}
 675
 676// EthAddress returns the ethereum address of the account loaded into the Client
 677func (c *Client) EthAddress() (*ethCommon.Address, error) {
 678	if c.addr == nil {
 679		return nil, tracerr.Wrap(eth.ErrAccountNil)
 680	}
 681	return c.addr, nil
 682}
 683
 684var errTODO = fmt.Errorf("TODO: Not implemented yet")
 685
 686//
 687// Rollup
 688//
 689
 690// CtlAddL1TxUser adds an L1TxUser to the L1UserTxs queue of the Rollup
 691// func (c *Client) CtlAddL1TxUser(l1Tx *common.L1Tx) {
 692// 	c.rw.Lock()
 693// 	defer c.rw.Unlock()
 694//
 695// 	nextBlock := c.nextBlock()
 696// 	r := nextBlock.Rollup
 697// 	queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
 698// 	if len(queue.L1TxQueue) >= eth.RollupConstMaxL1UserTx {
 699// 		r.State.LastToForgeL1TxsNum++
 700// 		r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
 701// 		queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
 702// 	}
 703// 	if int64(l1Tx.FromIdx) > r.State.CurrentIdx {
 704// 		panic("l1Tx.FromIdx > r.State.CurrentIdx")
 705// 	}
 706// 	if int(l1Tx.TokenID)+1 > len(r.State.TokenList) {
 707// 		panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
 708// 	}
 709// 	queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
 710// 	r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
 711// 		L1Tx:            *l1Tx,
 712// 		ToForgeL1TxsNum: r.State.LastToForgeL1TxsNum,
 713// 		Position:        len(queue.L1TxQueue) - 1,
 714// 	})
 715// }
 716
 717// RollupL1UserTxERC20Permit is the interface to call the smart contract function
 718func (c *Client) RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) {
 719	log.Error("TODO")
 720	return nil, tracerr.Wrap(errTODO)
 721}
 722
 723// RollupL1UserTxERC20ETH sends an L1UserTx to the Rollup.
 724func (c *Client) RollupL1UserTxERC20ETH(
 725	fromBJJ *babyjub.PublicKey,
 726	fromIdx int64,
 727	loadAmount *big.Int,
 728	amount *big.Int,
 729	tokenID uint32,
 730	toIdx int64,
 731) (tx *types.Transaction, err error) {
 732	c.rw.Lock()
 733	defer c.rw.Unlock()
 734	cpy := c.nextBlock().copy()
 735	defer func() { c.revertIfErr(err, cpy) }()
 736
 737	_, err = common.NewFloat16(amount)
 738	if err != nil {
 739		return nil, tracerr.Wrap(err)
 740	}
 741	_, err = common.NewFloat16(loadAmount)
 742	if err != nil {
 743		return nil, tracerr.Wrap(err)
 744	}
 745
 746	nextBlock := c.nextBlock()
 747	r := nextBlock.Rollup
 748	queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
 749	if len(queue.L1TxQueue) >= common.RollupConstMaxL1UserTx {
 750		r.State.LastToForgeL1TxsNum++
 751		r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
 752		queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
 753	}
 754	if fromIdx > r.State.CurrentIdx {
 755		panic("l1Tx.FromIdx > r.State.CurrentIdx")
 756	}
 757	if int(tokenID)+1 > len(r.State.TokenList) {
 758		panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
 759	}
 760	toForgeL1TxsNum := r.State.LastToForgeL1TxsNum
 761	l1Tx, err := common.NewL1Tx(&common.L1Tx{
 762		FromIdx:         common.Idx(fromIdx),
 763		FromEthAddr:     *c.addr,
 764		FromBJJ:         fromBJJ,
 765		Amount:          amount,
 766		LoadAmount:      loadAmount,
 767		TokenID:         common.TokenID(tokenID),
 768		ToIdx:           common.Idx(toIdx),
 769		ToForgeL1TxsNum: &toForgeL1TxsNum,
 770		Position:        len(queue.L1TxQueue),
 771		UserOrigin:      true,
 772	})
 773	if err != nil {
 774		return nil, tracerr.Wrap(err)
 775	}
 776
 777	queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
 778	r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
 779		L1UserTx: *l1Tx,
 780	})
 781	return r.addTransaction(c.newTransaction("l1UserTxERC20ETH", l1Tx)), nil
 782}
 783
 784// RollupL1UserTxERC777 is the interface to call the smart contract function
 785// func (c *Client) RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error) {
 786// 	log.Error("TODO")
 787// 	return nil, errTODO
 788// }
 789
 790// RollupRegisterTokensCount is the interface to call the smart contract function
 791func (c *Client) RollupRegisterTokensCount() (*big.Int, error) {
 792	log.Error("TODO")
 793	return nil, tracerr.Wrap(errTODO)
 794}
 795
 796// RollupLastForgedBatch is the interface to call the smart contract function
 797func (c *Client) RollupLastForgedBatch() (int64, error) {
 798	c.rw.RLock()
 799	defer c.rw.RUnlock()
 800
 801	currentBlock := c.currentBlock()
 802	e := currentBlock.Rollup
 803	return int64(len(e.State.ExitRoots)) - 1, nil
 804}
 805
 806// RollupWithdrawCircuit is the interface to call the smart contract function
 807func (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) {
 808	log.Error("TODO")
 809	return nil, tracerr.Wrap(errTODO)
 810}
 811
 812// RollupWithdrawMerkleProof is the interface to call the smart contract function
 813func (c *Client) RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
 814	c.rw.Lock()
 815	defer c.rw.Unlock()
 816	cpy := c.nextBlock().copy()
 817	defer func() { c.revertIfErr(err, cpy) }()
 818
 819	nextBlock := c.nextBlock()
 820	r := nextBlock.Rollup
 821
 822	if int(numExitRoot) >= len(r.State.ExitRoots) {
 823		return nil, tracerr.Wrap(fmt.Errorf("numExitRoot >= len(r.State.ExitRoots)"))
 824	}
 825	if _, ok := r.State.ExitNullifierMap[numExitRoot][idx]; ok {
 826		return nil, tracerr.Wrap(fmt.Errorf("exit already withdrawn"))
 827	}
 828	r.State.ExitNullifierMap[numExitRoot][idx] = true
 829
 830	type data struct {
 831		BabyPubKey      *babyjub.PublicKey
 832		TokenID         uint32
 833		NumExitRoot     int64
 834		Idx             int64
 835		Amount          *big.Int
 836		Siblings        []*big.Int
 837		InstantWithdraw bool
 838	}
 839	tx = r.addTransaction(c.newTransaction("withdrawMerkleProof", data{
 840		BabyPubKey:      babyPubKey,
 841		TokenID:         tokenID,
 842		NumExitRoot:     numExitRoot,
 843		Idx:             idx,
 844		Amount:          amount,
 845		Siblings:        siblings,
 846		InstantWithdraw: instantWithdraw,
 847	}))
 848	r.Events.Withdraw = append(r.Events.Withdraw, eth.RollupEventWithdraw{
 849		Idx:             uint64(idx),
 850		NumExitRoot:     uint64(numExitRoot),
 851		InstantWithdraw: instantWithdraw,
 852		TxHash:          tx.Hash(),
 853	})
 854
 855	if !instantWithdraw {
 856		w := nextBlock.WDelayer
 857		w.deposit(tx.Hash(), *c.addr, r.State.TokenList[int(tokenID)], amount)
 858	}
 859	return tx, nil
 860}
 861
 862type transactionData struct {
 863	Name  string
 864	Value interface{}
 865}
 866
 867func (c *Client) newTransaction(name string, value interface{}) *types.Transaction {
 868	eth := c.nextBlock().Eth
 869	nonce := eth.Nonce
 870	eth.Nonce++
 871	data, err := json.Marshal(transactionData{name, value})
 872	if err != nil {
 873		panic(err)
 874	}
 875	return types.NewTransaction(nonce, ethCommon.Address{}, nil, 0, nil,
 876		data)
 877}
 878
 879// RollupForgeBatch is the interface to call the smart contract function
 880func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Transaction, err error) {
 881	c.rw.Lock()
 882	defer c.rw.Unlock()
 883	cpy := c.nextBlock().copy()
 884	defer func() { c.revertIfErr(err, cpy) }()
 885	if c.addr == nil {
 886		return nil, tracerr.Wrap(eth.ErrAccountNil)
 887	}
 888
 889	a := c.nextBlock().Auction
 890	ok, err := a.canForge(*c.addr, a.Eth.BlockNum)
 891	if err != nil {
 892		return nil, tracerr.Wrap(err)
 893	}
 894	if !ok {
 895		return nil, tracerr.Wrap(fmt.Errorf(common.AuctionErrMsgCannotForge))
 896	}
 897
 898	// TODO: Verify proof
 899
 900	// Auction
 901	err = a.forge(*c.addr)
 902	if err != nil {
 903		return nil, tracerr.Wrap(err)
 904	}
 905
 906	// TODO: If successful, store the tx in a successful array.
 907	// TODO: If failed, store the tx in a failed array.
 908	// TODO: Add method to move the tx to another block, reapply it there, and possibly go from successful to failed.
 909
 910	return c.addBatch(args)
 911}
 912
 913// CtlAddBatch adds forged batch to the Rollup, without checking any ZKProof
 914func (c *Client) CtlAddBatch(args *eth.RollupForgeBatchArgs) {
 915	c.rw.Lock()
 916	defer c.rw.Unlock()
 917
 918	if _, err := c.addBatch(args); err != nil {
 919		panic(err)
 920	}
 921}
 922
 923func (c *Client) addBatch(args *eth.RollupForgeBatchArgs) (*types.Transaction, error) {
 924	nextBlock := c.nextBlock()
 925	r := nextBlock.Rollup
 926	r.State.StateRoot = args.NewStRoot
 927	if args.NewLastIdx < r.State.CurrentIdx {
 928		return nil, tracerr.Wrap(fmt.Errorf("args.NewLastIdx < r.State.CurrentIdx"))
 929	}
 930	r.State.CurrentIdx = args.NewLastIdx
 931	r.State.ExitNullifierMap[int64(len(r.State.ExitRoots))] = make(map[int64]bool)
 932	r.State.ExitRoots = append(r.State.ExitRoots, args.NewExitRoot)
 933	if args.L1Batch {
 934		r.State.CurrentToForgeL1TxsNum++
 935		if r.State.CurrentToForgeL1TxsNum == r.State.LastToForgeL1TxsNum {
 936			r.State.LastToForgeL1TxsNum++
 937			r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
 938		}
 939	}
 940	ethTx := r.addTransaction(c.newTransaction("forgebatch", args))
 941	c.forgeBatchArgsPending[ethTx.Hash()] = &batch{*args, *c.addr}
 942	r.Events.ForgeBatch = append(r.Events.ForgeBatch, eth.RollupEventForgeBatch{
 943		BatchNum:  int64(len(r.State.ExitRoots)) - 1,
 944		EthTxHash: ethTx.Hash(),
 945	})
 946
 947	return ethTx, nil
 948}
 949
 950// RollupAddTokenSimple is a wrapper around RollupAddToken that automatically
 951// sets `deadlie`.
 952func (c *Client) RollupAddTokenSimple(tokenAddress ethCommon.Address, feeAddToken *big.Int) (tx *types.Transaction, err error) {
 953	return c.RollupAddToken(tokenAddress, feeAddToken, big.NewInt(9999)) //nolint:gomnd
 954}
 955
 956// RollupAddToken is the interface to call the smart contract function
 957func (c *Client) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int,
 958	deadline *big.Int) (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	if c.addr == nil {
 964		return nil, tracerr.Wrap(eth.ErrAccountNil)
 965	}
 966
 967	nextBlock := c.nextBlock()
 968	r := nextBlock.Rollup
 969	if _, ok := r.State.TokenMap[tokenAddress]; ok {
 970		return nil, tracerr.Wrap(fmt.Errorf("Token %v already registered", tokenAddress))
 971	}
 972	if feeAddToken.Cmp(r.Vars.FeeAddToken) != 0 {
 973		return nil, tracerr.Wrap(fmt.Errorf("Expected fee: %v but got: %v", r.Vars.FeeAddToken, feeAddToken))
 974	}
 975
 976	r.State.TokenMap[tokenAddress] = true
 977	r.State.TokenList = append(r.State.TokenList, tokenAddress)
 978	r.Events.AddToken = append(r.Events.AddToken, eth.RollupEventAddToken{TokenAddress: tokenAddress,
 979		TokenID: uint32(len(r.State.TokenList) - 1)})
 980	return r.addTransaction(c.newTransaction("addtoken", tokenAddress)), nil
 981}
 982
 983// RollupGetCurrentTokens is the interface to call the smart contract function
 984func (c *Client) RollupGetCurrentTokens() (*big.Int, error) {
 985	c.rw.RLock()
 986	defer c.rw.RUnlock()
 987
 988	log.Error("TODO")
 989	return nil, tracerr.Wrap(errTODO)
 990}
 991
 992// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
 993func (c *Client) RollupUpdateForgeL1L2BatchTimeout(newForgeL1Timeout int64) (tx *types.Transaction, err error) {
 994	c.rw.Lock()
 995	defer c.rw.Unlock()
 996	cpy := c.nextBlock().copy()
 997	defer func() { c.revertIfErr(err, cpy) }()
 998	if c.addr == nil {
 999		return nil, tracerr.Wrap(eth.ErrAccountNil)
1000	}
1001
1002	nextBlock := c.nextBlock()
1003	r := nextBlock.Rollup
1004	r.Vars.ForgeL1L2BatchTimeout = newForgeL1Timeout
1005	r.Events.UpdateForgeL1L2BatchTimeout = append(r.Events.UpdateForgeL1L2BatchTimeout,
1006		eth.RollupEventUpdateForgeL1L2BatchTimeout{NewForgeL1L2BatchTimeout: newForgeL1Timeout})
1007
1008	return r.addTransaction(c.newTransaction("updateForgeL1L2BatchTimeout", newForgeL1Timeout)), nil
1009}
1010
1011// RollupUpdateFeeAddToken is the interface to call the smart contract function
1012func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
1013	c.rw.Lock()
1014	defer c.rw.Unlock()
1015	cpy := c.nextBlock().copy()
1016	defer func() { c.revertIfErr(err, cpy) }()
1017	if c.addr == nil {
1018		return nil, tracerr.Wrap(eth.ErrAccountNil)
1019	}
1020
1021	log.Error("TODO")
1022	return nil, tracerr.Wrap(errTODO)
1023}
1024
1025// RollupUpdateTokensHEZ is the interface to call the smart contract function
1026// func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (tx *types.Transaction, err error) {
1027// 	c.rw.Lock()
1028// 	defer c.rw.Unlock()
1029// 	cpy := c.nextBlock().copy()
1030// 	defer func() { c.revertIfErr(err, cpy) }()
1031//
1032// 	log.Error("TODO")
1033// 	return nil, errTODO
1034// }
1035
1036// RollupUpdateGovernance is the interface to call the smart contract function
1037// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
1038// 	return nil, errTODO
1039// }
1040
1041// RollupConstants returns the Constants of the Rollup Smart Contract
1042func (c *Client) RollupConstants() (*common.RollupConstants, error) {
1043	c.rw.RLock()
1044	defer c.rw.RUnlock()
1045
1046	return c.rollupConstants, nil
1047}
1048
1049// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
1050func (c *Client) RollupEventsByBlock(blockNum int64) (*eth.RollupEvents, *ethCommon.Hash, error) {
1051	c.rw.RLock()
1052	defer c.rw.RUnlock()
1053
1054	block, ok := c.blocks[blockNum]
1055	if !ok {
1056		return nil, nil, tracerr.Wrap(fmt.Errorf("Block %v doesn't exist", blockNum))
1057	}
1058	return &block.Rollup.Events, &block.Eth.Hash, nil
1059}
1060
1061// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction
1062func (c *Client) RollupForgeBatchArgs(ethTxHash ethCommon.Hash, numL1TxUser uint16) (*eth.RollupForgeBatchArgs, *ethCommon.Address, error) {
1063	c.rw.RLock()
1064	defer c.rw.RUnlock()
1065
1066	batch, ok := c.forgeBatchArgs[ethTxHash]
1067	if !ok {
1068		return nil, nil, tracerr.Wrap(fmt.Errorf("transaction not found"))
1069	}
1070	return &batch.ForgeBatchArgs, &batch.Sender, nil
1071}
1072
1073//
1074// Auction
1075//
1076
1077// AuctionSetSlotDeadline is the interface to call the smart contract function
1078func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (tx *types.Transaction, err error) {
1079	c.rw.Lock()
1080	defer c.rw.Unlock()
1081	cpy := c.nextBlock().copy()
1082	defer func() { c.revertIfErr(err, cpy) }()
1083	if c.addr == nil {
1084		return nil, tracerr.Wrap(eth.ErrAccountNil)
1085	}
1086
1087	log.Error("TODO")
1088	return nil, tracerr.Wrap(errTODO)
1089}
1090
1091// AuctionGetSlotDeadline is the interface to call the smart contract function
1092func (c *Client) AuctionGetSlotDeadline() (uint8, error) {
1093	c.rw.RLock()
1094	defer c.rw.RUnlock()
1095
1096	log.Error("TODO")
1097	return 0, tracerr.Wrap(errTODO)
1098}
1099
1100// AuctionSetOpenAuctionSlots is the interface to call the smart contract function
1101func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (tx *types.Transaction, err error) {
1102	c.rw.Lock()
1103	defer c.rw.Unlock()
1104	cpy := c.nextBlock().copy()
1105	defer func() { c.revertIfErr(err, cpy) }()
1106	if c.addr == nil {
1107		return nil, tracerr.Wrap(eth.ErrAccountNil)
1108	}
1109
1110	nextBlock := c.nextBlock()
1111	a := nextBlock.Auction
1112	a.Vars.OpenAuctionSlots = newOpenAuctionSlots
1113	a.Events.NewOpenAuctionSlots = append(a.Events.NewOpenAuctionSlots,
1114		eth.AuctionEventNewOpenAuctionSlots{NewOpenAuctionSlots: newOpenAuctionSlots})
1115
1116	return a.addTransaction(c.newTransaction("setOpenAuctionSlots", newOpenAuctionSlots)), nil
1117}
1118
1119// AuctionGetOpenAuctionSlots is the interface to call the smart contract function
1120func (c *Client) AuctionGetOpenAuctionSlots() (uint16, error) {
1121	c.rw.RLock()
1122	defer c.rw.RUnlock()
1123
1124	log.Error("TODO")
1125	return 0, tracerr.Wrap(errTODO)
1126}
1127
1128// AuctionSetClosedAuctionSlots is the interface to call the smart contract function
1129func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (tx *types.Transaction, err error) {
1130	c.rw.Lock()
1131	defer c.rw.Unlock()
1132	cpy := c.nextBlock().copy()
1133	defer func() { c.revertIfErr(err, cpy) }()
1134	if c.addr == nil {
1135		return nil, tracerr.Wrap(eth.ErrAccountNil)
1136	}
1137
1138	log.Error("TODO")
1139	return nil, tracerr.Wrap(errTODO)
1140}
1141
1142// AuctionGetClosedAuctionSlots is the interface to call the smart contract function
1143func (c *Client) AuctionGetClosedAuctionSlots() (uint16, error) {
1144	c.rw.RLock()
1145	defer c.rw.RUnlock()
1146
1147	log.Error("TODO")
1148	return 0, tracerr.Wrap(errTODO)
1149}
1150
1151// AuctionSetOutbidding is the interface to call the smart contract function
1152func (c *Client) AuctionSetOutbidding(newOutbidding uint16) (tx *types.Transaction, err error) {
1153	c.rw.Lock()
1154	defer c.rw.Unlock()
1155	cpy := c.nextBlock().copy()
1156	defer func() { c.revertIfErr(err, cpy) }()
1157	if c.addr == nil {
1158		return nil, tracerr.Wrap(eth.ErrAccountNil)
1159	}
1160
1161	log.Error("TODO")
1162	return nil, tracerr.Wrap(errTODO)
1163}
1164
1165// AuctionGetOutbidding is the interface to call the smart contract function
1166func (c *Client) AuctionGetOutbidding() (uint16, error) {
1167	c.rw.RLock()
1168	defer c.rw.RUnlock()
1169
1170	log.Error("TODO")
1171	return 0, tracerr.Wrap(errTODO)
1172}
1173
1174// AuctionSetAllocationRatio is the interface to call the smart contract function
1175func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (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, tracerr.Wrap(eth.ErrAccountNil)
1182	}
1183
1184	log.Error("TODO")
1185	return nil, tracerr.Wrap(errTODO)
1186}
1187
1188// AuctionGetAllocationRatio is the interface to call the smart contract function
1189func (c *Client) AuctionGetAllocationRatio() ([3]uint16, error) {
1190	c.rw.RLock()
1191	defer c.rw.RUnlock()
1192
1193	log.Error("TODO")
1194	return [3]uint16{}, tracerr.Wrap(errTODO)
1195}
1196
1197// AuctionSetDonationAddress is the interface to call the smart contract function
1198func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (tx *types.Transaction, err error) {
1199	c.rw.Lock()
1200	defer c.rw.Unlock()
1201	cpy := c.nextBlock().copy()
1202	defer func() { c.revertIfErr(err, cpy) }()
1203	if c.addr == nil {
1204		return nil, tracerr.Wrap(eth.ErrAccountNil)
1205	}
1206
1207	log.Error("TODO")
1208	return nil, tracerr.Wrap(errTODO)
1209}
1210
1211// AuctionGetDonationAddress is the interface to call the smart contract function
1212func (c *Client) AuctionGetDonationAddress() (*ethCommon.Address, error) {
1213	c.rw.RLock()
1214	defer c.rw.RUnlock()
1215
1216	log.Error("TODO")
1217	return nil, tracerr.Wrap(errTODO)
1218}
1219
1220// AuctionSetBootCoordinator is the interface to call the smart contract function
1221func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address, newBootCoordinatorURL string) (tx *types.Transaction, err error) {
1222	c.rw.Lock()
1223	defer c.rw.Unlock()
1224	cpy := c.nextBlock().copy()
1225	defer func() { c.revertIfErr(err, cpy) }()
1226	if c.addr == nil {
1227		return nil, tracerr.Wrap(eth.ErrAccountNil)
1228	}
1229
1230	log.Error("TODO")
1231	return nil, tracerr.Wrap(errTODO)
1232}
1233
1234// AuctionGetBootCoordinator is the interface to call the smart contract function
1235func (c *Client) AuctionGetBootCoordinator() (*ethCommon.Address, error) {
1236	c.rw.RLock()
1237	defer c.rw.RUnlock()
1238
1239	currentBlock := c.currentBlock()
1240	a := currentBlock.Auction
1241
1242	return &a.Vars.BootCoordinator, nil
1243}
1244
1245// AuctionChangeDefaultSlotSetBid is the interface to call the smart contract function
1246func (c *Client) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (tx *types.Transaction, err error) {
1247	c.rw.Lock()
1248	defer c.rw.Unlock()
1249	cpy := c.nextBlock().copy()
1250	defer func() { c.revertIfErr(err, cpy) }()
1251	if c.addr == nil {
1252		return nil, tracerr.Wrap(eth.ErrAccountNil)
1253	}
1254
1255	log.Error("TODO")
1256	return nil, tracerr.Wrap(errTODO)
1257}
1258
1259// AuctionSetCoordinator is the interface to call the smart contract function
1260func (c *Client) AuctionSetCoordinator(forger ethCommon.Address, URL string) (tx *types.Transaction, err error) {
1261	c.rw.Lock()
1262	defer c.rw.Unlock()
1263	cpy := c.nextBlock().copy()
1264	defer func() { c.revertIfErr(err, cpy) }()
1265	if c.addr == nil {
1266		return nil, tracerr.Wrap(eth.ErrAccountNil)
1267	}
1268
1269	nextBlock := c.nextBlock()
1270	a := nextBlock.Auction
1271
1272	a.State.Coordinators[*c.addr] = &eth.Coordinator{
1273		Forger: forger,
1274		URL:    URL,
1275	}
1276
1277	a.Events.SetCoordinator = append(a.Events.SetCoordinator,
1278		eth.AuctionEventSetCoordinator{
1279			BidderAddress:  *c.addr,
1280			ForgerAddress:  forger,
1281			CoordinatorURL: URL,
1282		})
1283
1284	type data struct {
1285		BidderAddress ethCommon.Address
1286		ForgerAddress ethCommon.Address
1287		URL           string
1288	}
1289	return a.addTransaction(c.newTransaction("registercoordinator", data{*c.addr, forger, URL})), nil
1290}
1291
1292// AuctionIsRegisteredCoordinator is the interface to call the smart contract function
1293func (c *Client) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) {
1294	c.rw.RLock()
1295	defer c.rw.RUnlock()
1296
1297	log.Error("TODO")
1298	return false, tracerr.Wrap(errTODO)
1299}
1300
1301// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function
1302func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (tx *types.Transaction, err error) {
1303	c.rw.Lock()
1304	defer c.rw.Unlock()
1305	cpy := c.nextBlock().copy()
1306	defer func() { c.revertIfErr(err, cpy) }()
1307	if c.addr == nil {
1308		return nil, tracerr.Wrap(eth.ErrAccountNil)
1309	}
1310
1311	log.Error("TODO")
1312	return nil, tracerr.Wrap(errTODO)
1313}
1314
1315// AuctionGetSlotNumber is the interface to call the smart contract function
1316func (c *Client) AuctionGetSlotNumber(blockNum int64) (int64, error) {
1317	c.rw.RLock()
1318	defer c.rw.RUnlock()
1319
1320	currentBlock := c.currentBlock()
1321	a := currentBlock.Auction
1322	return a.getSlotNumber(blockNum), nil
1323}
1324
1325// AuctionGetCurrentSlotNumber is the interface to call the smart contract function
1326func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) {
1327	c.rw.RLock()
1328	defer c.rw.RUnlock()
1329
1330	log.Error("TODO")
1331	return 0, tracerr.Wrap(errTODO)
1332}
1333
1334// AuctionGetMinBidBySlot is the interface to call the smart contract function
1335func (c *Client) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) {
1336	c.rw.RLock()
1337	defer c.rw.RUnlock()
1338
1339	log.Error("TODO")
1340	return nil, tracerr.Wrap(errTODO)
1341}
1342
1343// AuctionGetDefaultSlotSetBid is the interface to call the smart contract function
1344func (c *Client) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) {
1345	c.rw.RLock()
1346	defer c.rw.RUnlock()
1347
1348	log.Error("TODO")
1349	return nil, tracerr.Wrap(errTODO)
1350}
1351
1352// AuctionGetSlotSet is the interface to call the smart contract function
1353func (c *Client) AuctionGetSlotSet(slot int64) (*big.Int, error) {
1354	c.rw.RLock()
1355	defer c.rw.RUnlock()
1356
1357	log.Error("TODO")
1358	return nil, tracerr.Wrap(errTODO)
1359}
1360
1361// AuctionTokensReceived is the interface to call the smart contract function
1362// func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error {
1363// 	return errTODO
1364// }
1365
1366// AuctionBidSimple is a wrapper around AuctionBid that automatically sets `amount` and `deadline`.
1367func (c *Client) AuctionBidSimple(slot int64, bidAmount *big.Int) (tx *types.Transaction, err error) {
1368	return c.AuctionBid(bidAmount, slot, bidAmount, big.NewInt(99999)) //nolint:gomnd
1369}
1370
1371// AuctionBid is the interface to call the smart contract function.  This
1372// implementation behaves as if any address has infinite tokens.
1373func (c *Client) AuctionBid(amount *big.Int, slot int64, bidAmount *big.Int,
1374	deadline *big.Int) (tx *types.Transaction, err error) {
1375	c.rw.Lock()
1376	defer c.rw.Unlock()
1377	cpy := c.nextBlock().copy()
1378	defer func() { func() { c.revertIfErr(err, cpy) }() }()
1379	if c.addr == nil {
1380		return nil, tracerr.Wrap(eth.ErrAccountNil)
1381	}
1382
1383	nextBlock := c.nextBlock()
1384	a := nextBlock.Auction
1385
1386	if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
1387		return nil, tracerr.Wrap(errBidClosed)
1388	}
1389
1390	if slot >= a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots)+int64(a.Vars.OpenAuctionSlots) {
1391		return nil, tracerr.Wrap(errBidNotOpen)
1392	}
1393
1394	minBid, err := a.getMinBidBySlot(slot)
1395	if err != nil {
1396		return nil, tracerr.Wrap(err)
1397	}
1398	if bidAmount.Cmp(minBid) == -1 {
1399		return nil, tracerr.Wrap(errBidBelowMin)
1400	}
1401
1402	if _, ok := a.State.Coordinators[*c.addr]; !ok {
1403		return nil, tracerr.Wrap(errCoordNotReg)
1404	}
1405
1406	slotState, ok := a.State.Slots[slot]
1407	if !ok {
1408		slotState = eth.NewSlotState()
1409		a.State.Slots[slot] = slotState
1410	}
1411	slotState.Bidder = *c.addr
1412	slotState.BidAmount = bidAmount
1413
1414	a.Events.NewBid = append(a.Events.NewBid,
1415		eth.AuctionEventNewBid{Slot: slot, BidAmount: bidAmount, Bidder: *c.addr})
1416
1417	type data struct {
1418		Slot      int64
1419		BidAmount *big.Int
1420		Bidder    ethCommon.Address
1421	}
1422	return a.addTransaction(c.newTransaction("bid", data{slot, bidAmount, *c.addr})), nil
1423}
1424
1425// AuctionMultiBid is the interface to call the smart contract function.  This
1426// implementation behaves as if any address has infinite tokens.
1427func (c *Client) AuctionMultiBid(amount *big.Int, startingSlot int64, endingSlot int64, slotSet [6]bool,
1428	maxBid, closedMinBid, deadline *big.Int) (tx *types.Transaction, err error) {
1429	c.rw.Lock()
1430	defer c.rw.Unlock()
1431	cpy := c.nextBlock().copy()
1432	defer func() { c.revertIfErr(err, cpy) }()
1433	if c.addr == nil {
1434		return nil, tracerr.Wrap(eth.ErrAccountNil)
1435	}
1436
1437	log.Error("TODO")
1438	return nil, tracerr.Wrap(errTODO)
1439}
1440
1441// AuctionCanForge is the interface to call the smart contract function
1442func (c *Client) AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error) {
1443	c.rw.RLock()
1444	defer c.rw.RUnlock()
1445
1446	currentBlock := c.currentBlock()
1447	a := currentBlock.Auction
1448	return a.canForge(forger, blockNum)
1449}
1450
1451// AuctionForge is the interface to call the smart contract function
1452func (c *Client) AuctionForge(forger ethCommon.Address) (tx *types.Transaction, err error) {
1453	c.rw.Lock()
1454	defer c.rw.Unlock()
1455	cpy := c.nextBlock().copy()
1456	defer func() { c.revertIfErr(err, cpy) }()
1457	if c.addr == nil {
1458		return nil, tracerr.Wrap(eth.ErrAccountNil)
1459	}
1460
1461	log.Error("TODO")
1462	return nil, tracerr.Wrap(errTODO)
1463}
1464
1465// AuctionClaimHEZ is the interface to call the smart contract function
1466func (c *Client) AuctionClaimHEZ() (tx *types.Transaction, err error) {
1467	c.rw.Lock()
1468	defer c.rw.Unlock()
1469	cpy := c.nextBlock().copy()
1470	defer func() { c.revertIfErr(err, cpy) }()
1471	if c.addr == nil {
1472		return nil, tracerr.Wrap(eth.ErrAccountNil)
1473	}
1474
1475	log.Error("TODO")
1476	return nil, tracerr.Wrap(errTODO)
1477}
1478
1479// AuctionGetClaimableHEZ is the interface to call the smart contract function
1480func (c *Client) AuctionGetClaimableHEZ(bidder ethCommon.Address) (*big.Int, error) {
1481	c.rw.RLock()
1482	defer c.rw.RUnlock()
1483
1484	log.Error("TODO")
1485	return nil, tracerr.Wrap(errTODO)
1486}
1487
1488// AuctionConstants returns the Constants of the Auction Smart Contract
1489func (c *Client) AuctionConstants() (*common.AuctionConstants, error) {
1490	c.rw.RLock()
1491	defer c.rw.RUnlock()
1492
1493	return c.auctionConstants, nil
1494}
1495
1496// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract
1497func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethCommon.Hash, error) {
1498	c.rw.RLock()
1499	defer c.rw.RUnlock()
1500
1501	block, ok := c.blocks[blockNum]
1502	if !ok {
1503		return nil, nil, tracerr.Wrap(fmt.Errorf("Block %v doesn't exist", blockNum))
1504	}
1505	return &block.Auction.Events, &block.Eth.Hash, nil
1506}
1507
1508//
1509// WDelayer
1510//
1511
1512// WDelayerGetHermezGovernanceAddress is the interface to call the smart contract function
1513func (c *Client) WDelayerGetHermezGovernanceAddress() (*ethCommon.Address, error) {
1514	c.rw.RLock()
1515	defer c.rw.RUnlock()
1516
1517	log.Error("TODO")
1518	return nil, tracerr.Wrap(errTODO)
1519}
1520
1521// WDelayerSetHermezGovernanceAddress is the interface to call the smart contract function
1522func (c *Client) WDelayerSetHermezGovernanceAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1523	c.rw.Lock()
1524	defer c.rw.Unlock()
1525	cpy := c.nextBlock().copy()
1526	defer func() { c.revertIfErr(err, cpy) }()
1527	if c.addr == nil {
1528		return nil, tracerr.Wrap(eth.ErrAccountNil)
1529	}
1530
1531	log.Error("TODO")
1532	return nil, tracerr.Wrap(errTODO)
1533}
1534
1535// WDelayerGetHermezKeeperAddress is the interface to call the smart contract function
1536func (c *Client) WDelayerGetHermezKeeperAddress() (*ethCommon.Address, error) {
1537	c.rw.RLock()
1538	defer c.rw.RUnlock()
1539
1540	log.Error("TODO")
1541	return nil, tracerr.Wrap(errTODO)
1542}
1543
1544// WDelayerSetHermezKeeperAddress is the interface to call the smart contract function
1545func (c *Client) WDelayerSetHermezKeeperAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1546	c.rw.Lock()
1547	defer c.rw.Unlock()
1548	cpy := c.nextBlock().copy()
1549	defer func() { c.revertIfErr(err, cpy) }()
1550	if c.addr == nil {
1551		return nil, tracerr.Wrap(eth.ErrAccountNil)
1552	}
1553
1554	log.Error("TODO")
1555	return nil, tracerr.Wrap(errTODO)
1556}
1557
1558// WDelayerGetWhiteHackGroupAddress is the interface to call the smart contract function
1559func (c *Client) WDelayerGetWhiteHackGroupAddress() (*ethCommon.Address, error) {
1560	c.rw.RLock()
1561	defer c.rw.RUnlock()
1562
1563	log.Error("TODO")
1564	return nil, tracerr.Wrap(errTODO)
1565}
1566
1567// WDelayerSetWhiteHackGroupAddress is the interface to call the smart contract function
1568func (c *Client) WDelayerSetWhiteHackGroupAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1569	c.rw.Lock()
1570	defer c.rw.Unlock()
1571	cpy := c.nextBlock().copy()
1572	defer func() { c.revertIfErr(err, cpy) }()
1573	if c.addr == nil {
1574		return nil, tracerr.Wrap(eth.ErrAccountNil)
1575	}
1576
1577	log.Error("TODO")
1578	return nil, tracerr.Wrap(errTODO)
1579}
1580
1581// WDelayerIsEmergencyMode is the interface to call the smart contract function
1582func (c *Client) WDelayerIsEmergencyMode() (bool, error) {
1583	c.rw.RLock()
1584	defer c.rw.RUnlock()
1585
1586	log.Error("TODO")
1587	return false, tracerr.Wrap(errTODO)
1588}
1589
1590// WDelayerGetWithdrawalDelay is the interface to call the smart contract function
1591func (c *Client) WDelayerGetWithdrawalDelay() (*big.Int, error) {
1592	c.rw.RLock()
1593	defer c.rw.RUnlock()
1594
1595	log.Error("TODO")
1596	return nil, tracerr.Wrap(errTODO)
1597}
1598
1599// WDelayerGetEmergencyModeStartingTime is the interface to call the smart contract function
1600func (c *Client) WDelayerGetEmergencyModeStartingTime() (*big.Int, error) {
1601	c.rw.RLock()
1602	defer c.rw.RUnlock()
1603
1604	log.Error("TODO")
1605	return nil, tracerr.Wrap(errTODO)
1606}
1607
1608// WDelayerEnableEmergencyMode is the interface to call the smart contract function
1609func (c *Client) WDelayerEnableEmergencyMode() (tx *types.Transaction, err error) {
1610	c.rw.Lock()
1611	defer c.rw.Unlock()
1612	cpy := c.nextBlock().copy()
1613	defer func() { c.revertIfErr(err, cpy) }()
1614	if c.addr == nil {
1615		return nil, tracerr.Wrap(eth.ErrAccountNil)
1616	}
1617
1618	log.Error("TODO")
1619	return nil, tracerr.Wrap(errTODO)
1620}
1621
1622// WDelayerChangeWithdrawalDelay is the interface to call the smart contract function
1623func (c *Client) WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (tx *types.Transaction, err error) {
1624	c.rw.Lock()
1625	defer c.rw.Unlock()
1626	cpy := c.nextBlock().copy()
1627	defer func() { c.revertIfErr(err, cpy) }()
1628	if c.addr == nil {
1629		return nil, tracerr.Wrap(eth.ErrAccountNil)
1630	}
1631
1632	nextBlock := c.nextBlock()
1633	w := nextBlock.WDelayer
1634	w.Vars.WithdrawalDelay = newWithdrawalDelay
1635	w.Events.NewWithdrawalDelay = append(w.Events.NewWithdrawalDelay,
1636		eth.WDelayerEventNewWithdrawalDelay{WithdrawalDelay: newWithdrawalDelay})
1637
1638	return w.addTransaction(c.newTransaction("changeWithdrawalDelay", newWithdrawalDelay)), nil
1639}
1640
1641// WDelayerDepositInfo is the interface to call the smart contract function
1642func (c *Client) WDelayerDepositInfo(owner, token ethCommon.Address) (eth.DepositState, error) {
1643	c.rw.RLock()
1644	defer c.rw.RUnlock()
1645
1646	log.Error("TODO")
1647	return eth.DepositState{}, tracerr.Wrap(errTODO)
1648}
1649
1650// WDelayerDeposit is the interface to call the smart contract function
1651func (c *Client) WDelayerDeposit(onwer, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
1652	c.rw.Lock()
1653	defer c.rw.Unlock()
1654	cpy := c.nextBlock().copy()
1655	defer func() { c.revertIfErr(err, cpy) }()
1656	if c.addr == nil {
1657		return nil, tracerr.Wrap(eth.ErrAccountNil)
1658	}
1659
1660	log.Error("TODO")
1661	return nil, tracerr.Wrap(errTODO)
1662}
1663
1664// WDelayerWithdrawal is the interface to call the smart contract function
1665func (c *Client) WDelayerWithdrawal(owner, token ethCommon.Address) (tx *types.Transaction, err error) {
1666	c.rw.Lock()
1667	defer c.rw.Unlock()
1668	cpy := c.nextBlock().copy()
1669	defer func() { c.revertIfErr(err, cpy) }()
1670	if c.addr == nil {
1671		return nil, tracerr.Wrap(eth.ErrAccountNil)
1672	}
1673
1674	log.Error("TODO")
1675	return nil, tracerr.Wrap(errTODO)
1676}
1677
1678// WDelayerEscapeHatchWithdrawal is the interface to call the smart contract function
1679func (c *Client) WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
1680	c.rw.Lock()
1681	defer c.rw.Unlock()
1682	cpy := c.nextBlock().copy()
1683	defer func() { c.revertIfErr(err, cpy) }()
1684	if c.addr == nil {
1685		return nil, tracerr.Wrap(eth.ErrAccountNil)
1686	}
1687
1688	log.Error("TODO")
1689	return nil, tracerr.Wrap(errTODO)
1690}
1691
1692// WDelayerEventsByBlock returns the events in a block that happened in the WDelayer Contract
1693func (c *Client) WDelayerEventsByBlock(blockNum int64) (*eth.WDelayerEvents, *ethCommon.Hash, error) {
1694	c.rw.RLock()
1695	defer c.rw.RUnlock()
1696
1697	block, ok := c.blocks[blockNum]
1698	if !ok {
1699		return nil, nil, tracerr.Wrap(fmt.Errorf("Block %v doesn't exist", blockNum))
1700	}
1701	return &block.WDelayer.Events, &block.Eth.Hash, nil
1702}
1703
1704// WDelayerConstants returns the Constants of the WDelayer Contract
1705func (c *Client) WDelayerConstants() (*common.WDelayerConstants, error) {
1706	c.rw.RLock()
1707	defer c.rw.RUnlock()
1708
1709	return c.wDelayerConstants, nil
1710}