From 6e4b9b4b702951639a45d991437df093b10fd224 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Wed, 28 Oct 2020 16:09:05 +0100 Subject: [PATCH] Update Synchronizer (node) implementation - node: - Extend config to add initial variables of the smart contracts used as defaults before they are changed via events. - In stopped channels, set size 1 so that panics are not witheld until the node stops completely. - common: - In Smart Contract variables, comment: - `WDelayerVariables.HermezRollupAddress` because it's not needed. - `RollupVariables.Buckets` because there are no events for it, and for now it's not used. - historydb: - Add functions to get and set smart contract variables. - db: - Add `Rollback` function in `utils.go` to reduce boilerplate in sql transaction rollbacks in defers in db functions. - Update `rollup_vars` and `auction_vars` (renamed from `consensus_vars`) table, and add `wdelayer_vars` table. - synchronizer: - Synchronize WDelayer - Handle SC variables properly - test/ethclient: - Add essential implementation of WDelayer --- cli/node/cfg.buidler.toml | 69 +++++++- cli/node/main.go | 1 + common/ethauction.go | 17 +- common/ethrollup.go | 9 +- common/ethwdelayer.go | 11 +- common/l1tx.go | 2 + common/l1tx_test.go | 2 + config/config.go | 11 +- db/historydb/historydb.go | 118 ++++++++++--- db/historydb/historydb_test.go | 48 ++++++ db/l2db/l2db.go | 11 +- db/migrations/0001.sql | 33 ++-- db/utils.go | 9 + eth/client.go | 17 +- eth/rollup.go | 3 - eth/wdelayer.go | 13 +- node/node.go | 25 +-- synchronizer/synchronizer.go | 142 +++++++++++----- synchronizer/synchronizer_test.go | 5 + test/ethclient.go | 274 ++++++++++++++++++++++++++++-- 20 files changed, 669 insertions(+), 151 deletions(-) diff --git a/cli/node/cfg.buidler.toml b/cli/node/cfg.buidler.toml index 9d1ba18..d2ed40a 100644 --- a/cli/node/cfg.buidler.toml +++ b/cli/node/cfg.buidler.toml @@ -18,15 +18,17 @@ URL = "http://localhost:8545" [Synchronizer] SyncLoopInterval = "1s" + [Synchronizer.StartBlockNum] Rollup = 1 Auction = 1 WDelayer = 1 [SmartContracts] -Rollup = "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe" -Auction = "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8" -TokenHEZ = "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c" +Rollup = "0x6F4e99522F4eB37e0B73D0C0373147893EF12fD5" +Auction = "0x5E0816F0f8bC560cB2B9e9C87187BeCac8c2021F" +WDelayer = "0x5D94e3e7aeC542aB0F9129B9a7BAdeb5B3Ca0f77" +TokenHEZ = "0x2b7dEe2CF60484325716A1c6A193519c8c3b19F3" TokenHEZName = "Hermez Network Token" [EthClient] @@ -35,3 +37,64 @@ DeployGasLimit = 1000000 GasPriceDiv = 100 ReceiptTimeout = "60s" IntervalReceiptLoop = "200ms" + + [Synchronizer.InitialVariables.Auction] + DonationAddress = "0x0000000000000000000000000000000000000001" + BootCoordinator = "0x0000000000000000000000000000000000000001" + DefaultSlotSetBid = [ + "10000000000000000000", + "10000000000000000000", + "10000000000000000000", + "10000000000000000000", + "10000000000000000000", + "10000000000000000000", + ] + ClosedAuctionSlots = 2 + OpenAuctionSlots = 4320 + AllocationRatio = [4000, 4000, 2000] + Outbidding = 1000 + SlotDeadline = 20 + + [Synchronizer.InitialVariables.WDelayer] + # HermezRollupAddress = + HermezGovernanceDAOAddress = "0x0000000000000000000000000000000000000001" + WhiteHackGroupAddress = "0x0000000000000000000000000000000000000001" + HermezKeeperAddress = "0x0000000000000000000000000000000000000001" + WithdrawalDelay = 60 + EmergencyModeStartingTime = 0 + EmergencyMode = false + + [Synchronizer.InitialVariables.Rollup] + FeeAddToken = "10" + ForgeL1L2BatchTimeout = 10 + WithdrawalDelay = 1209600 # 60 * 60 * 24 * 7 * 2 + # [[Synchronizer.InitialVariables.Rollup.Buckets]] + # CeilUSD = 0 + # BlockStamp = 0 + # Withdrawals = 0 + # BlockWithdrawalRate = 0 + # MaxWithdrawals = 0 + # [[Synchronizer.InitialVariables.Rollup.Buckets]] + # CeilUSD = 0 + # BlockStamp = 0 + # Withdrawals = 0 + # BlockWithdrawalRate = 0 + # MaxWithdrawals = 0 + # [[Synchronizer.InitialVariables.Rollup.Buckets]] + # CeilUSD = 0 + # BlockStamp = 0 + # Withdrawals = 0 + # BlockWithdrawalRate = 0 + # MaxWithdrawals = 0 + # [[Synchronizer.InitialVariables.Rollup.Buckets]] + # CeilUSD = 0 + # BlockStamp = 0 + # Withdrawals = 0 + # BlockWithdrawalRate = 0 + # MaxWithdrawals = 0 + # [[Synchronizer.InitialVariables.Rollup.Buckets]] + # CeilUSD = 0 + # BlockStamp = 0 + # Withdrawals = 0 + # BlockWithdrawalRate = 0 + # MaxWithdrawals = 0 diff --git a/cli/node/main.go b/cli/node/main.go index c1ca4c2..a0a0256 100644 --- a/cli/node/main.go +++ b/cli/node/main.go @@ -107,6 +107,7 @@ func getConfig(c *cli.Context) (*Config, error) { if err != nil { return nil, err } + // nodeCfg.Synchronizer.InitialVariables.WDelayer.HermezRollupAddress = nodeCfg.SmartContracts.Rollup cfg.node = nodeCfg return &cfg, nil diff --git a/common/ethauction.go b/common/ethauction.go index 0e85880..f9171a9 100644 --- a/common/ethauction.go +++ b/common/ethauction.go @@ -25,20 +25,21 @@ type AuctionConstants struct { // AuctionVariables are the variables of the Auction Smart Contract type AuctionVariables struct { + EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"` // Boot Coordinator Address - DonationAddress ethCommon.Address `json:"donationAddress" meddler:"donation_address"` + DonationAddress ethCommon.Address `json:"donationAddress" meddler:"donation_address" validate:"required"` // Boot Coordinator Address - BootCoordinator ethCommon.Address `json:"bootCoordinator" meddler:"boot_coordinator"` + BootCoordinator ethCommon.Address `json:"bootCoordinator" meddler:"boot_coordinator" validate:"required"` // The minimum bid value in a series of 6 slots - DefaultSlotSetBid [6]*big.Int `json:"defaultSlotSetBid" meddler:"default_slot_set_bid,json"` + DefaultSlotSetBid [6]*big.Int `json:"defaultSlotSetBid" meddler:"default_slot_set_bid,json" validate:"required"` // Distance (#slots) to the closest slot to which you can bid ( 2 Slots = 2 * 40 Blocks = 20 min ) - ClosedAuctionSlots uint16 `json:"closedAuctionSlots" meddler:"closed_auction_slots"` + ClosedAuctionSlots uint16 `json:"closedAuctionSlots" meddler:"closed_auction_slots" validate:"required"` // Distance (#slots) to the farthest slot to which you can bid (30 days = 4320 slots ) - OpenAuctionSlots uint16 `json:"openAuctionSlots" meddler:"open_auction_slots"` + OpenAuctionSlots uint16 `json:"openAuctionSlots" meddler:"open_auction_slots" validate:"required"` // How the HEZ tokens deposited by the slot winner are distributed (Burn: 40% - Donation: 40% - HGT: 20%) - AllocationRatio [3]uint16 `json:"allocationRatio" meddler:"allocation_ratio,json"` + AllocationRatio [3]uint16 `json:"allocationRatio" meddler:"allocation_ratio,json" validate:"required"` // Minimum outbid (percentage) over the previous one to consider it valid - Outbidding uint16 `json:"outbidding" meddler:"outbidding"` + Outbidding uint16 `json:"outbidding" meddler:"outbidding" validate:"required"` // Number of blocks at the end of a slot in which any coordinator can forge if the winner has not forged one before - SlotDeadline uint8 `json:"slotDeadline" meddler:"slot_deadline"` + SlotDeadline uint8 `json:"slotDeadline" meddler:"slot_deadline" validate:"required"` } diff --git a/common/ethrollup.go b/common/ethrollup.go index 437dfb7..09c6d19 100644 --- a/common/ethrollup.go +++ b/common/ethrollup.go @@ -157,8 +157,9 @@ type Bucket struct { // RollupVariables are the variables of the Rollup Smart Contract type RollupVariables struct { - FeeAddToken *big.Int `json:"feeAddToken" meddler:"fee_addtoken"` - ForgeL1L2BatchTimeout int64 `json:"forgeL1L2BatchTimeout" meddler:"forge_l1l2_timeout"` - WithdrawalDelay uint64 `json:"withdrawalDelay" meddler:"withdrawal_delay"` - Buckets [RollupConstNumBuckets]Bucket `json:"buckets" meddler:"buckets,json"` + EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"` + FeeAddToken *big.Int `json:"feeAddToken" meddler:"fee_add_token,bigint" validate:"required"` + ForgeL1L2BatchTimeout int64 `json:"forgeL1L2BatchTimeout" meddler:"forge_l1_timeout" validate:"required"` + WithdrawalDelay uint64 `json:"withdrawalDelay" meddler:"withdrawal_delay" validate:"required"` + // Buckets [RollupConstNumBuckets]Bucket `json:"buckets" meddler:"buckets,json"` } diff --git a/common/ethwdelayer.go b/common/ethwdelayer.go index 242d1be..b07348b 100644 --- a/common/ethwdelayer.go +++ b/common/ethwdelayer.go @@ -14,11 +14,12 @@ type WDelayerConstants struct { // WDelayerVariables are the variables of the Withdrawal Delayer Smart Contract type WDelayerVariables struct { - HermezRollupAddress ethCommon.Address `json:"hermezRollupAddress" meddler:"rollup_address"` - HermezGovernanceDAOAddress ethCommon.Address `json:"hermezGovernanceDAOAddress" meddler:"govdao_address"` - WhiteHackGroupAddress ethCommon.Address `json:"whiteHackGroupAddress" meddler:"whg_address"` - HermezKeeperAddress ethCommon.Address `json:"hermezKeeperAddress" meddler:"keeper_address"` - WithdrawalDelay uint64 `json:"withdrawalDelay" meddler:"withdrawal_delay"` + EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"` + // HermezRollupAddress ethCommon.Address `json:"hermezRollupAddress" meddler:"rollup_address"` + HermezGovernanceDAOAddress ethCommon.Address `json:"hermezGovernanceDAOAddress" meddler:"govdao_address" validate:"required"` + WhiteHackGroupAddress ethCommon.Address `json:"whiteHackGroupAddress" meddler:"whg_address" validate:"required"` + HermezKeeperAddress ethCommon.Address `json:"hermezKeeperAddress" meddler:"keeper_address" validate:"required"` + WithdrawalDelay uint64 `json:"withdrawalDelay" meddler:"withdrawal_delay" validate:"required"` EmergencyModeStartingTime uint64 `json:"emergencyModeStartingTime" meddler:"emergency_start_time"` EmergencyMode bool `json:"emergencyMode" meddler:"emergency_mode"` } diff --git a/common/l1tx.go b/common/l1tx.go index a690357..ceddb31 100644 --- a/common/l1tx.go +++ b/common/l1tx.go @@ -282,5 +282,7 @@ func L1CoordinatorTxFromBytes(b []byte) (*L1Tx, error) { return nil, err } tx.FromEthAddr = crypto.PubkeyToAddress(*pubKey) + tx.Amount = big.NewInt(0) + tx.LoadAmount = big.NewInt(0) return tx, nil } diff --git a/common/l1tx_test.go b/common/l1tx_test.go index b2ae2ef..c04b08a 100644 --- a/common/l1tx_test.go +++ b/common/l1tx_test.go @@ -158,6 +158,8 @@ func TestL1CoordinatorTxByteParsers(t *testing.T) { TokenID: 231, FromBJJ: pk, FromEthAddr: fromEthAddr, + Amount: big.NewInt(0), + LoadAmount: big.NewInt(0), } bytesCoordinatorL1, err := l1Tx.BytesCoordinatorTx(signature) diff --git a/config/config.go b/config/config.go index 56dc974..4b20b0e 100644 --- a/config/config.go +++ b/config/config.go @@ -8,6 +8,7 @@ import ( "github.com/BurntSushi/toml" ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/synchronizer" "gopkg.in/go-playground/validator.v9" ) @@ -65,16 +66,14 @@ type Node struct { URL string `validate:"required"` } `validate:"required"` Synchronizer struct { - SyncLoopInterval Duration `validate:"required"` - StartBlockNum struct { - Rollup int64 `validate:"required"` - Auction int64 `validate:"required"` - WDelayer int64 `validate:"required"` - } `validate:"required"` + SyncLoopInterval Duration `validate:"required"` + StartBlockNum synchronizer.ConfigStartBlockNum `validate:"required"` + InitialVariables synchronizer.SCVariables `validate:"required"` } `validate:"required"` SmartContracts struct { Rollup ethCommon.Address `validate:"required"` Auction ethCommon.Address `validate:"required"` + WDelayer ethCommon.Address `validate:"required"` TokenHEZ ethCommon.Address `validate:"required"` TokenHEZName string `validate:"required"` } `validate:"required"` diff --git a/db/historydb/historydb.go b/db/historydb/historydb.go index 5323610..5542395 100644 --- a/db/historydb/historydb.go +++ b/db/historydb/historydb.go @@ -1097,6 +1097,72 @@ func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) { return lastL1TxsPosition, row.Scan(&lastL1TxsPosition) } +// GetSCVars returns the rollup, auction and wdelayer smart contracts variables at their last update. +func (hdb *HistoryDB) GetSCVars() (*common.RollupVariables, *common.AuctionVariables, + *common.WDelayerVariables, error) { + var rollup common.RollupVariables + var auction common.AuctionVariables + var wDelayer common.WDelayerVariables + if err := meddler.QueryRow(hdb.db, &rollup, + "SELECT * FROM rollup_vars ORDER BY eth_block_num DESC LIMIT 1;"); err != nil { + return nil, nil, nil, err + } + if err := meddler.QueryRow(hdb.db, &auction, + "SELECT * FROM auction_vars ORDER BY eth_block_num DESC LIMIT 1;"); err != nil { + return nil, nil, nil, err + } + if err := meddler.QueryRow(hdb.db, &wDelayer, + "SELECT * FROM wdelayer_vars ORDER BY eth_block_num DESC LIMIT 1;"); err != nil { + return nil, nil, nil, err + } + return &rollup, &auction, &wDelayer, nil +} + +func (hdb *HistoryDB) setRollupVars(d meddler.DB, rollup *common.RollupVariables) error { + return meddler.Insert(d, "rollup_vars", rollup) +} + +func (hdb *HistoryDB) setAuctionVars(d meddler.DB, auction *common.AuctionVariables) error { + return meddler.Insert(d, "auction_vars", auction) +} + +func (hdb *HistoryDB) setWDelayerVars(d meddler.DB, wDelayer *common.WDelayerVariables) error { + return meddler.Insert(d, "wdelayer_vars", wDelayer) +} + +// SetInitialSCVars sets the initial state of rollup, auction, wdelayer smart +// contract variables. This initial state is stored linked to block 0, which +// always exist in the DB and is used to store initialization data that always +// exist in the smart contracts. +func (hdb *HistoryDB) SetInitialSCVars(rollup *common.RollupVariables, + auction *common.AuctionVariables, wDelayer *common.WDelayerVariables) error { + txn, err := hdb.db.Begin() + if err != nil { + return err + } + defer func() { + if err != nil { + db.Rollback(txn) + } + }() + // Force EthBlockNum to be 0 because it's the block used to link data + // that belongs to the creation of the smart contracts + rollup.EthBlockNum = 0 + auction.EthBlockNum = 0 + wDelayer.EthBlockNum = 0 + if err := hdb.setRollupVars(txn, rollup); err != nil { + return err + } + if err := hdb.setAuctionVars(txn, auction); err != nil { + return err + } + if err := hdb.setWDelayerVars(txn, wDelayer); err != nil { + return err + } + + return txn.Commit() +} + // AddBlockSCData stores all the information of a block retrieved by the // Synchronizer. Blocks should be inserted in order, leaving no gaps because // the pagination system of the API/DB depends on this. Within blocks, all @@ -1108,47 +1174,39 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) { } defer func() { if err != nil { - errRollback := txn.Rollback() - if errRollback != nil { - log.Errorw("Rollback", "err", errRollback) - } + db.Rollback(txn) } }() // Add block - err = hdb.addBlock(txn, &blockData.Block) - if err != nil { + if err := hdb.addBlock(txn, &blockData.Block); err != nil { return err } // Add Coordinators if len(blockData.Auction.Coordinators) > 0 { - err = hdb.addCoordinators(txn, blockData.Auction.Coordinators) - if err != nil { + if err := hdb.addCoordinators(txn, blockData.Auction.Coordinators); err != nil { return err } } // Add Bids if len(blockData.Auction.Bids) > 0 { - err = hdb.addBids(txn, blockData.Auction.Bids) - if err != nil { + if err := hdb.addBids(txn, blockData.Auction.Bids); err != nil { return err } } // Add Tokens if len(blockData.Rollup.AddedTokens) > 0 { - err = hdb.addTokens(txn, blockData.Rollup.AddedTokens) - if err != nil { + if err := hdb.addTokens(txn, blockData.Rollup.AddedTokens); err != nil { return err } } // Add l1 Txs if len(blockData.Rollup.L1UserTxs) > 0 { - err = hdb.addL1Txs(txn, blockData.Rollup.L1UserTxs) - if err != nil { + if err := hdb.addL1Txs(txn, blockData.Rollup.L1UserTxs); err != nil { return err } } @@ -1158,16 +1216,14 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) { batch := &blockData.Rollup.Batches[i] // Add Batch: this will trigger an update on the DB // that will set the batch num of forged L1 txs in this batch - err = hdb.addBatch(txn, &batch.Batch) - if err != nil { + if err = hdb.addBatch(txn, &batch.Batch); err != nil { return err } // Add unforged l1 Txs if batch.L1Batch { if len(batch.L1CoordinatorTxs) > 0 { - err = hdb.addL1Txs(txn, batch.L1CoordinatorTxs) - if err != nil { + if err := hdb.addL1Txs(txn, batch.L1CoordinatorTxs); err != nil { return err } } @@ -1175,29 +1231,39 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) { // Add l2 Txs if len(batch.L2Txs) > 0 { - err = hdb.addL2Txs(txn, batch.L2Txs) - if err != nil { + if err := hdb.addL2Txs(txn, batch.L2Txs); err != nil { return err } } // Add accounts if len(batch.CreatedAccounts) > 0 { - err = hdb.addAccounts(txn, batch.CreatedAccounts) - if err != nil { + if err := hdb.addAccounts(txn, batch.CreatedAccounts); err != nil { return err } } // Add exit tree if len(batch.ExitTree) > 0 { - err = hdb.addExitTree(txn, batch.ExitTree) - if err != nil { + if err := hdb.addExitTree(txn, batch.ExitTree); err != nil { return err } } - - // TODO: INSERT CONTRACTS VARS + } + if blockData.Rollup.Vars != nil { + if err := hdb.setRollupVars(txn, blockData.Rollup.Vars); err != nil { + return err + } + } + if blockData.Auction.Vars != nil { + if err := hdb.setAuctionVars(txn, blockData.Auction.Vars); err != nil { + return err + } + } + if blockData.WDelayer.Vars != nil { + if err := hdb.setWDelayerVars(txn, blockData.WDelayer.Vars); err != nil { + return err + } } // TODO: Process withdrawals diff --git a/db/historydb/historydb_test.go b/db/historydb/historydb_test.go index a96d952..a6db577 100644 --- a/db/historydb/historydb_test.go +++ b/db/historydb/historydb_test.go @@ -1,11 +1,13 @@ package historydb import ( + "database/sql" "math" "math/big" "os" "testing" + ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" dbUtils "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/log" @@ -429,6 +431,52 @@ func TestGetL1UserTxs(t *testing.T) { assert.Equal(t, 0, len(l1UserTxs)) } +func TestSetInitialSCVars(t *testing.T) { + test.WipeDB(historyDB.DB()) + _, _, _, err := historyDB.GetSCVars() + assert.Equal(t, sql.ErrNoRows, err) + + //nolint:govet + rollup := &common.RollupVariables{ + 0, + big.NewInt(10), + 12, + 13, + } + //nolint:govet + auction := &common.AuctionVariables{ + 0, + ethCommon.BigToAddress(big.NewInt(2)), + ethCommon.BigToAddress(big.NewInt(3)), + [6]*big.Int{ + big.NewInt(1), big.NewInt(2), big.NewInt(3), + big.NewInt(4), big.NewInt(5), big.NewInt(6), + }, + 2, + 4320, + [3]uint16{10, 11, 12}, + 1000, + 20, + } + //nolint:govet + wDelayer := &common.WDelayerVariables{ + 0, + ethCommon.BigToAddress(big.NewInt(2)), + ethCommon.BigToAddress(big.NewInt(3)), + ethCommon.BigToAddress(big.NewInt(4)), + 13, + 14, + false, + } + err = historyDB.SetInitialSCVars(rollup, auction, wDelayer) + require.Nil(t, err) + dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars() + assert.Nil(t, err) + require.Equal(t, rollup, dbRollup) + require.Equal(t, auction, dbAuction) + require.Equal(t, wDelayer, dbWDelayer) +} + // setTestBlocks WARNING: this will delete the blocks and recreate them func setTestBlocks(from, to int64) []common.Block { test.WipeDB(historyDB.DB()) diff --git a/db/l2db/l2db.go b/db/l2db/l2db.go index 970bb9d..df53255 100644 --- a/db/l2db/l2db.go +++ b/db/l2db/l2db.go @@ -7,7 +7,6 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/db" - "github.com/hermeznetwork/hermez-node/log" "github.com/jmoiron/sqlx" //nolint:errcheck // driver for postgres DB @@ -243,10 +242,7 @@ func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account, batchNum common. defer func() { // Rollback the transaction if there was an error. if err != nil { - errRollback := txn.Rollback() - if errRollback != nil { - log.Errorw("Rollback", "err", errRollback) - } + db.Rollback(txn) } }() for i := 0; i < len(updatedAccounts); i++ { @@ -291,10 +287,7 @@ func (l2db *L2DB) Purge(currentBatchNum common.BatchNum) (err error) { defer func() { // Rollback the transaction if there was an error. if err != nil { - errRollback := txn.Rollback() - if errRollback != nil { - log.Errorw("Rollback", "err", errRollback) - } + db.Rollback(txn) } }() // Delete pending txs that have been in the pool after the TTL if maxTxs is reached diff --git a/db/migrations/0001.sql b/db/migrations/0001.sql index ee5a402..f7332de 100644 --- a/db/migrations/0001.sql +++ b/db/migrations/0001.sql @@ -516,23 +516,31 @@ FOR EACH ROW EXECUTE PROCEDURE forge_l1_user_txs(); CREATE TABLE rollup_vars ( eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE, - forge_l1_timeout BYTEA NOT NULL, - fee_l1_user_tx BYTEA NOT NULL, fee_add_token BYTEA NOT NULL, - tokens_hez BYTEA NOT NULL, - governance BYTEA NOT NULL + forge_l1_timeout BYTEA NOT NULL, + withdrawal_delay BIGINT NOT NULL ); -CREATE TABLE consensus_vars ( +CREATE TABLE auction_vars ( eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE, - slot_deadline INT NOT NULL, - close_auction_slots INT NOT NULL, + donation_address BYTEA NOT NULL, + boot_coordinator BYTEA NOT NULL, + default_slot_set_bid BYTEA NOT NULL, + closed_auction_slots INT NOT NULL, open_auction_slots INT NOT NULL, - min_bid_slots VARCHAR(200) NOT NULL, + allocation_ratio VARCHAR(200), outbidding INT NOT NULL, - donation_address BYTEA NOT NULL, - governance_address BYTEA NOT NULL, - allocation_ratio VARCHAR(200) + slot_deadline INT NOT NULL +); + +CREATE TABLE wdelayer_vars ( + eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE, + govdao_address BYTEA NOT NULL, + whg_address BYTEA NOT NULL, + keeper_address BYTEA NOT NULL, + withdrawal_delay BIGINT NOT NULL, + emergency_start_time BIGINT NOT NULL, + emergency_mode BOOLEAN NOT NULL ); -- L2 @@ -606,8 +614,9 @@ DROP FUNCTION set_pool_tx; -- drop tables DROP TABLE account_creation_auth; DROP TABLE tx_pool; -DROP TABLE consensus_vars; +DROP TABLE auction_vars; DROP TABLE rollup_vars; +DROP TABLE wdelayer_vars; DROP TABLE tx; DROP TABLE exit_tree; DROP TABLE account; diff --git a/db/utils.go b/db/utils.go index cb96172..b6a0220 100644 --- a/db/utils.go +++ b/db/utils.go @@ -1,6 +1,7 @@ package db import ( + "database/sql" "encoding/base64" "fmt" "math/big" @@ -192,3 +193,11 @@ type Paginationer interface { GetPagination() *Pagination Len() int } + +// Rollback an sql transaction, and log the error if it's not nil +func Rollback(txn *sql.Tx) { + err := txn.Rollback() + if err != nil { + log.Errorw("Rollback", "err", err) + } +} diff --git a/eth/client.go b/eth/client.go index 5afe408..3d9feb8 100644 --- a/eth/client.go +++ b/eth/client.go @@ -17,6 +17,7 @@ type ClientInterface interface { EthereumInterface RollupInterface AuctionInterface + WDelayerInterface } // @@ -28,6 +29,7 @@ type Client struct { EthereumClient AuctionClient RollupClient + WDelayerClient } // TokenConfig is used to define the information about token @@ -47,11 +49,17 @@ type AuctionConfig struct { TokenHEZ TokenConfig } +// WDelayerConfig is the configuration for the WDelayer smart contract interface +type WDelayerConfig struct { + Address ethCommon.Address +} + // ClientConfig is the configuration of the Client type ClientConfig struct { Ethereum EthereumConfig Rollup RollupConfig Auction AuctionConfig + WDelayer WDelayerConfig } // NewClient creates a new Client to interact with Ethereum and the Hermez smart contracts. @@ -61,13 +69,18 @@ func NewClient(client *ethclient.Client, account *accounts.Account, ks *ethKeyst if err != nil { return nil, err } - rollupCient, err := NewRollupClient(ethereumClient, cfg.Rollup.Address, cfg.Auction.TokenHEZ) + rollupClient, err := NewRollupClient(ethereumClient, cfg.Rollup.Address, cfg.Auction.TokenHEZ) + if err != nil { + return nil, err + } + wDelayerClient, err := NewWDelayerClient(ethereumClient, cfg.WDelayer.Address) if err != nil { return nil, err } return &Client{ EthereumClient: *ethereumClient, AuctionClient: *auctionClient, - RollupClient: *rollupCient, + RollupClient: *rollupClient, + WDelayerClient: *wDelayerClient, }, nil } diff --git a/eth/rollup.go b/eth/rollup.go index 91709c0..a695f8d 100644 --- a/eth/rollup.go +++ b/eth/rollup.go @@ -510,9 +510,6 @@ func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethC return nil, nil, err } if len(logs) > 0 { - for i := range logs { - log.Debugw("log", "i", i, "blockHash", logs[i].BlockHash) - } blockHash = &logs[0].BlockHash } for _, vLog := range logs { diff --git a/eth/wdelayer.go b/eth/wdelayer.go index ed2c470..2a38f9b 100644 --- a/eth/wdelayer.go +++ b/eth/wdelayer.go @@ -114,7 +114,7 @@ type WDelayerInterface interface { WDelayerGetEmergencyModeStartingTime() (*big.Int, error) WDelayerEnableEmergencyMode() (*types.Transaction, error) WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (*types.Transaction, error) - WDelayerDepositInfo(owner, token ethCommon.Address) (*big.Int, uint64) + WDelayerDepositInfo(owner, token ethCommon.Address) (depositInfo DepositState, err error) WDelayerDeposit(onwer, token ethCommon.Address, amount *big.Int) (*types.Transaction, error) WDelayerWithdrawal(owner, token ethCommon.Address) (*types.Transaction, error) WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (*types.Transaction, error) @@ -340,7 +340,8 @@ func (c *WDelayerClient) WDelayerEscapeHatchWithdrawal(to, token ethCommon.Addre } // WDelayerConstants returns the Constants of the WDelayer Smart Contract -func (c *WDelayerClient) WDelayerConstants() (constants common.WDelayerConstants, err error) { +func (c *WDelayerClient) WDelayerConstants() (constants *common.WDelayerConstants, err error) { + constants = new(common.WDelayerConstants) if err := c.client.Call(func(ec *ethclient.Client) error { constants.MaxWithdrawalDelay, err = c.wdelayer.MAXWITHDRAWALDELAY(nil) if err != nil { @@ -377,7 +378,7 @@ var ( // there are no events in that block, blockHash is nil. func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, *ethCommon.Hash, error) { var wdelayerEvents WDelayerEvents - var blockHash ethCommon.Hash + var blockHash *ethCommon.Hash query := ethereum.FilterQuery{ FromBlock: big.NewInt(blockNum), @@ -394,10 +395,10 @@ func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, return nil, nil, err } if len(logs) > 0 { - blockHash = logs[0].BlockHash + blockHash = &logs[0].BlockHash } for _, vLog := range logs { - if vLog.BlockHash != blockHash { + if vLog.BlockHash != *blockHash { log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String()) return nil, nil, ErrBlockHashMismatchEvent } @@ -470,5 +471,5 @@ func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, wdelayerEvents.NewHermezGovernanceDAOAddress = append(wdelayerEvents.NewHermezGovernanceDAOAddress, governanceDAOAddress) } } - return &wdelayerEvents, &blockHash, nil + return &wdelayerEvents, blockHash, nil } diff --git a/node/node.go b/node/node.go index 51e9c1a..beb8280 100644 --- a/node/node.go +++ b/node/node.go @@ -102,17 +102,17 @@ func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node, Name: cfg.SmartContracts.TokenHEZName, }, }, + WDelayer: eth.WDelayerConfig{ + Address: cfg.SmartContracts.WDelayer, + }, }) if err != nil { return nil, err } sync, err := synchronizer.NewSynchronizer(client, historyDB, stateDB, synchronizer.Config{ - StartBlockNum: synchronizer.ConfigStartBlockNum{ - Rollup: cfg.Synchronizer.StartBlockNum.Rollup, - Auction: cfg.Synchronizer.StartBlockNum.Auction, - WDelayer: cfg.Synchronizer.StartBlockNum.WDelayer, - }, + StartBlockNum: cfg.Synchronizer.StartBlockNum, + InitialVariables: cfg.Synchronizer.InitialVariables, }) if err != nil { return nil, err @@ -176,9 +176,9 @@ func (n *Node) StartCoordinator() { n.stopGetProofCallForge = make(chan bool) n.stopForgeCallConfirm = make(chan bool) - n.stoppedForge = make(chan bool) - n.stoppedGetProofCallForge = make(chan bool) - n.stoppedForgeCallConfirm = make(chan bool) + n.stoppedForge = make(chan bool, 1) + n.stoppedGetProofCallForge = make(chan bool, 1) + n.stoppedForgeCallConfirm = make(chan bool, 1) queueSize := 1 batchCh0 := make(chan *coordinator.BatchInfo, queueSize) @@ -249,15 +249,18 @@ func (n *Node) StopCoordinator() { // StartSynchronizer starts the synchronizer func (n *Node) StartSynchronizer() { log.Info("Starting Synchronizer...") - n.stoppedSync = make(chan bool) + // stopped channel is size 1 so that the defer doesn't block + n.stoppedSync = make(chan bool, 1) go func() { - defer func() { n.stoppedSync <- true }() + defer func() { + n.stoppedSync <- true + }() var lastBlock *common.Block d := time.Duration(0) for { select { case <-n.ctx.Done(): - log.Info("Coordinator stopped") + log.Info("Synchronizer stopped") return case <-time.After(d): if blockData, discarded, err := n.sync.Sync2(n.ctx, lastBlock); err != nil { diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index 99925ff..ba7c5e7 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -41,14 +41,22 @@ var ( // ConfigStartBlockNum sets the first block used to start tracking the smart // contracts type ConfigStartBlockNum struct { - Rollup int64 - Auction int64 - WDelayer int64 + Rollup int64 `validate:"required"` + Auction int64 `validate:"required"` + WDelayer int64 `validate:"required"` +} + +// SCVariables joins all the smart contract variables in a single struct +type SCVariables struct { + Rollup common.RollupVariables `validate:"required"` + Auction common.AuctionVariables `validate:"required"` + WDelayer common.WDelayerVariables `validate:"required"` } // Config is the Synchronizer configuration type Config struct { - StartBlockNum ConfigStartBlockNum + StartBlockNum ConfigStartBlockNum + InitialVariables SCVariables } // Synchronizer implements the Synchronizer type @@ -61,6 +69,7 @@ type Synchronizer struct { stateDB *statedb.StateDB cfg Config startBlockNum int64 + vars SCVariables // firstSavedBlock *common.Block // mux sync.Mutex } @@ -78,12 +87,11 @@ func NewSynchronizer(ethClient eth.ClientInterface, historyDB *historydb.History log.Errorw("NewSynchronizer ethClient.RollupConstants()", "err", err) return nil, err } - // TODO: Uncomment once ethClient.WDelayerConstants() is implemented - // wDelayerConstants, err := ethClient.WDelayerConstants() - // if err != nil { - // log.Errorw("NewSynchronizer ethClient.WDelayerConstants()", "err", err) - // return nil, err - // } + wDelayerConstants, err := ethClient.WDelayerConstants() + if err != nil { + log.Errorw("NewSynchronizer ethClient.WDelayerConstants()", "err", err) + return nil, err + } // Set startBlockNum to the minimum between Auction, Rollup and // WDelayer StartBlockNum @@ -94,19 +102,17 @@ func NewSynchronizer(ethClient eth.ClientInterface, historyDB *historydb.History if startBlockNum < cfg.StartBlockNum.WDelayer { startBlockNum = cfg.StartBlockNum.WDelayer } - return &Synchronizer{ - ethClient: ethClient, - auctionConstants: *auctionConstants, - // auctionConstants: common.AuctionConstants{}, - rollupConstants: *rollupConstants, - // rollupConstants: common.RollupConstants{}, - // wDelayerConstants: *wDelayerConstants, - wDelayerConstants: common.WDelayerConstants{}, + s := &Synchronizer{ + ethClient: ethClient, + auctionConstants: *auctionConstants, + rollupConstants: *rollupConstants, + wDelayerConstants: *wDelayerConstants, historyDB: historyDB, stateDB: stateDB, cfg: cfg, startBlockNum: startBlockNum, - }, nil + } + return s, s.init() } // AuctionConstants returns the AuctionConstants read from the smart contract @@ -124,6 +130,23 @@ func (s *Synchronizer) WDelayerConstants() *common.WDelayerConstants { return &s.wDelayerConstants } +func (s *Synchronizer) init() error { + rollup, auction, wDelayer, err := s.historyDB.GetSCVars() + if err == sql.ErrNoRows { + rollup = &s.cfg.InitialVariables.Rollup + auction = &s.cfg.InitialVariables.Auction + wDelayer = &s.cfg.InitialVariables.WDelayer + log.Debug("Setting initial SCVars in HistoryDB") + if err = s.historyDB.SetInitialSCVars(rollup, auction, wDelayer); err != nil { + return err + } + } + s.vars.Rollup = *rollup + s.vars.Auction = *auction + s.vars.WDelayer = *wDelayer + return nil +} + // Sync2 attems to synchronize an ethereum block starting from lastSavedBlock. // If lastSavedBlock is nil, the lastSavedBlock value is obtained from de DB. // If a block is synched, it will be returned and also stored in the DB. If a @@ -325,7 +348,7 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e return &rollupData, nil } if *blockHash != ethBlock.Hash { - log.Errorw("Block hash mismatch", "expectd", ethBlock.Hash.String(), + log.Errorw("Block hash mismatch in Rollup events", "expected", ethBlock.Hash.String(), "got", blockHash.String()) return nil, eth.ErrBlockHashMismatchEvent } @@ -498,16 +521,15 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e rollupData.AddedTokens = append(rollupData.AddedTokens, token) } - var vars common.RollupVariables varsUpdate := false for _, evtUpdateForgeL1L2BatchTimeout := range rollupEvents.UpdateForgeL1L2BatchTimeout { - vars.ForgeL1L2BatchTimeout = evtUpdateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout + s.vars.Rollup.ForgeL1L2BatchTimeout = evtUpdateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout varsUpdate = true } for _, evtUpdateFeeAddToken := range rollupEvents.UpdateFeeAddToken { - vars.FeeAddToken = evtUpdateFeeAddToken.NewFeeAddToken + s.vars.Rollup.FeeAddToken = evtUpdateFeeAddToken.NewFeeAddToken varsUpdate = true } @@ -524,7 +546,8 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e } if varsUpdate { - rollupData.Vars = &vars + s.vars.Rollup.EthBlockNum = blockNum + rollupData.Vars = &s.vars.Rollup } return &rollupData, nil @@ -552,7 +575,7 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData, return &auctionData, nil } if *blockHash != ethBlock.Hash { - log.Errorw("Block hash mismatch", "expectd", ethBlock.Hash.String(), + log.Errorw("Block hash mismatch in Auction events", "expected", ethBlock.Hash.String(), "got", blockHash.String()) return nil, eth.ErrBlockHashMismatchEvent } @@ -578,35 +601,34 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData, auctionData.Coordinators = append(auctionData.Coordinators, coordinator) } - var vars common.AuctionVariables varsUpdate := false for _, evt := range auctionEvents.NewSlotDeadline { - vars.SlotDeadline = evt.NewSlotDeadline + s.vars.Auction.SlotDeadline = evt.NewSlotDeadline varsUpdate = true } for _, evt := range auctionEvents.NewClosedAuctionSlots { - vars.ClosedAuctionSlots = evt.NewClosedAuctionSlots + s.vars.Auction.ClosedAuctionSlots = evt.NewClosedAuctionSlots varsUpdate = true } for _, evt := range auctionEvents.NewOutbidding { - vars.Outbidding = evt.NewOutbidding + s.vars.Auction.Outbidding = evt.NewOutbidding varsUpdate = true } for _, evt := range auctionEvents.NewDonationAddress { - vars.DonationAddress = evt.NewDonationAddress + s.vars.Auction.DonationAddress = evt.NewDonationAddress varsUpdate = true } for _, evt := range auctionEvents.NewBootCoordinator { - vars.BootCoordinator = evt.NewBootCoordinator + s.vars.Auction.BootCoordinator = evt.NewBootCoordinator varsUpdate = true } for _, evt := range auctionEvents.NewOpenAuctionSlots { - vars.OpenAuctionSlots = evt.NewOpenAuctionSlots + s.vars.Auction.OpenAuctionSlots = evt.NewOpenAuctionSlots varsUpdate = true } for _, evt := range auctionEvents.NewAllocationRatio { - vars.AllocationRatio = evt.NewAllocationRatio + s.vars.Auction.AllocationRatio = evt.NewAllocationRatio varsUpdate = true } for _, evt := range auctionEvents.NewDefaultSlotSetBid { @@ -614,7 +636,7 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData, return nil, fmt.Errorf("unexpected SlotSet in "+ "auctionEvents.NewDefaultSlotSetBid: %v", evt.SlotSet) } - vars.DefaultSlotSetBid[evt.SlotSet] = evt.NewInitialMinBid + s.vars.Auction.DefaultSlotSetBid[evt.SlotSet] = evt.NewInitialMinBid varsUpdate = true } @@ -623,7 +645,8 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData, // NOTE: We ignore HEZClaimed if varsUpdate { - auctionData.Vars = &vars + s.vars.Auction.EthBlockNum = blockNum + auctionData.Vars = &s.vars.Auction } return &auctionData, nil @@ -631,11 +654,54 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData, // wdelayerSync gets information from the Withdrawal Delayer Contract func (s *Synchronizer) wdelayerSync(ethBlock *common.Block) (*common.WDelayerData, error) { - // blockNum := ethBlock.EthBlockNum + blockNum := ethBlock.EthBlockNum + wDelayerData := common.NewWDelayerData() + + // Get wDelayer events in the block + wDelayerEvents, blockHash, err := s.ethClient.WDelayerEventsByBlock(blockNum) + if err != nil { + return nil, err + } + // No events in this block + if blockHash == nil { + return &wDelayerData, nil + } + if *blockHash != ethBlock.Hash { + log.Errorw("Block hash mismatch in WDelayer events", "expected", ethBlock.Hash.String(), + "got", blockHash.String()) + return nil, eth.ErrBlockHashMismatchEvent + } - // TODO: Parse events to generate varialbes once ethClient.WDelayerEventsByBlock is implemented + varsUpdate := false - wDelayerData := common.NewWDelayerData() + // TODO Deposit + // TODO Withdraw + // TODO EscapeHatchWithdrawal + for range wDelayerEvents.EmergencyModeEnabled { + s.vars.WDelayer.EmergencyMode = true + varsUpdate = true + } + for _, evt := range wDelayerEvents.NewWithdrawalDelay { + s.vars.WDelayer.WithdrawalDelay = evt.WithdrawalDelay + varsUpdate = true + } + for _, evt := range wDelayerEvents.NewHermezKeeperAddress { + s.vars.WDelayer.HermezKeeperAddress = evt.NewHermezKeeperAddress + varsUpdate = true + } + for _, evt := range wDelayerEvents.NewWhiteHackGroupAddress { + s.vars.WDelayer.WhiteHackGroupAddress = evt.NewWhiteHackGroupAddress + varsUpdate = true + } + for _, evt := range wDelayerEvents.NewHermezGovernanceDAOAddress { + s.vars.WDelayer.HermezGovernanceDAOAddress = evt.NewHermezGovernanceDAOAddress + varsUpdate = true + } + + if varsUpdate { + s.vars.WDelayer.EthBlockNum = blockNum + wDelayerData.Vars = &s.vars.WDelayer + } return &wDelayerData, nil } diff --git a/synchronizer/synchronizer_test.go b/synchronizer/synchronizer_test.go index 88e0357..4fc195c 100644 --- a/synchronizer/synchronizer_test.go +++ b/synchronizer/synchronizer_test.go @@ -241,6 +241,11 @@ func TestSync(t *testing.T) { Auction: 1, WDelayer: 1, }, + InitialVariables: SCVariables{ + Rollup: *clientSetup.RollupVariables, + Auction: *clientSetup.AuctionVariables, + WDelayer: *clientSetup.WDelayerVariables, + }, }) require.Nil(t, err) diff --git a/test/ethclient.go b/test/ethclient.go index ba5b028..c12f851 100644 --- a/test/ethclient.go +++ b/test/ethclient.go @@ -29,6 +29,16 @@ func init() { } } +// WDelayerBlock stores all the data related to the WDelayer SC from an ethereum block +type WDelayerBlock struct { + // State eth.WDelayerState // TODO + Vars common.WDelayerVariables + Events eth.WDelayerEvents + Txs map[ethCommon.Hash]*types.Transaction + Constants *common.WDelayerConstants + Eth *EthereumBlock +} + // RollupBlock stores all the data related to the Rollup SC from an ethereum block type RollupBlock struct { State eth.RollupState @@ -185,9 +195,10 @@ type EthereumBlock struct { // Block represents a ethereum block type Block struct { - Rollup *RollupBlock - Auction *AuctionBlock - Eth *EthereumBlock + Rollup *RollupBlock + Auction *AuctionBlock + WDelayer *WDelayerBlock + Eth *EthereumBlock } func (b *Block) copy() *Block { @@ -210,8 +221,10 @@ func (b *Block) Next() *Block { blockNext.Rollup.Constants = b.Rollup.Constants blockNext.Auction.Constants = b.Auction.Constants + blockNext.WDelayer.Constants = b.WDelayer.Constants blockNext.Rollup.Eth = blockNext.Eth blockNext.Auction.Eth = blockNext.Eth + blockNext.WDelayer.Eth = blockNext.Eth return blockNext } @@ -219,11 +232,13 @@ func (b *Block) Next() *Block { // ClientSetup is used to initialize the constants of the Smart Contracts and // other details of the test Client type ClientSetup struct { - RollupConstants *common.RollupConstants - RollupVariables *common.RollupVariables - AuctionConstants *common.AuctionConstants - AuctionVariables *common.AuctionVariables - VerifyProof bool + RollupConstants *common.RollupConstants + RollupVariables *common.RollupVariables + AuctionConstants *common.AuctionConstants + AuctionVariables *common.AuctionVariables + WDelayerConstants *common.WDelayerConstants + WDelayerVariables *common.WDelayerVariables + VerifyProof bool } // NewClientSetupExample returns a ClientSetup example with hardcoded realistic @@ -279,11 +294,26 @@ func NewClientSetupExample() *ClientSetup { Outbidding: 1000, SlotDeadline: 20, } + wDelayerConstants := &common.WDelayerConstants{ + MaxWithdrawalDelay: 60 * 60 * 24 * 7 * 2, // 2 weeks + MaxEmergencyModeTime: 60 * 60 * 24 * 7 * 26, // 26 weeks + HermezRollup: auctionConstants.HermezRollup, + } + wDelayerVariables := &common.WDelayerVariables{ + HermezGovernanceDAOAddress: ethCommon.HexToAddress("0xcfD0d163AE6432a72682323E2C3A5a69e6B37D12"), + WhiteHackGroupAddress: ethCommon.HexToAddress("0x2730700932a4FDB97B9268A3Ca29f97Ea5fd7EA0"), + HermezKeeperAddress: ethCommon.HexToAddress("0x92aAD86176dC0f0046FE85Ed5dA008a828bE3868"), + WithdrawalDelay: 60, + EmergencyModeStartingTime: 0, + EmergencyMode: false, + } return &ClientSetup{ - RollupConstants: rollupConstants, - RollupVariables: rollupVariables, - AuctionConstants: auctionConstants, - AuctionVariables: auctionVariables, + RollupConstants: rollupConstants, + RollupVariables: rollupVariables, + AuctionConstants: auctionConstants, + AuctionVariables: auctionVariables, + WDelayerConstants: wDelayerConstants, + WDelayerVariables: wDelayerVariables, } } @@ -307,12 +337,13 @@ type batch struct { // Client implements the eth.ClientInterface interface, allowing to manipulate the // values for testing, working with deterministic results. type Client struct { - rw *sync.RWMutex - log bool - addr *ethCommon.Address - rollupConstants *common.RollupConstants - auctionConstants *common.AuctionConstants - blocks map[int64]*Block + rw *sync.RWMutex + log bool + addr *ethCommon.Address + rollupConstants *common.RollupConstants + auctionConstants *common.AuctionConstants + wDelayerConstants *common.WDelayerConstants + blocks map[int64]*Block // state state blockNum int64 // last mined block num maxBlockNum int64 // highest block num calculated @@ -365,6 +396,13 @@ func NewClient(l bool, timer Timer, addr *ethCommon.Address, setup *ClientSetup) Events: eth.NewAuctionEvents(), Constants: setup.AuctionConstants, }, + WDelayer: &WDelayerBlock{ + // State: TODO + Vars: *setup.WDelayerVariables, + Txs: make(map[ethCommon.Hash]*types.Transaction), + Events: eth.NewWDelayerEvents(), + Constants: setup.WDelayerConstants, + }, Eth: &EthereumBlock{ BlockNum: blockNum, Time: timer.Time(), @@ -385,6 +423,7 @@ func NewClient(l bool, timer Timer, addr *ethCommon.Address, setup *ClientSetup) addr: addr, rollupConstants: setup.RollupConstants, auctionConstants: setup.AuctionConstants, + wDelayerConstants: setup.WDelayerConstants, blocks: blocks, timer: timer, hasher: hasher, @@ -1343,3 +1382,202 @@ func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethC } return &block.Auction.Events, &block.Eth.Hash, nil } + +// +// WDelayer +// + +// WDelayerGetHermezGovernanceDAOAddress is the interface to call the smart contract function +func (c *Client) WDelayerGetHermezGovernanceDAOAddress() (*ethCommon.Address, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerSetHermezGovernanceDAOAddress is the interface to call the smart contract function +func (c *Client) WDelayerSetHermezGovernanceDAOAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) { + c.rw.Lock() + defer c.rw.Unlock() + cpy := c.nextBlock().copy() + defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerGetHermezKeeperAddress is the interface to call the smart contract function +func (c *Client) WDelayerGetHermezKeeperAddress() (*ethCommon.Address, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerSetHermezKeeperAddress is the interface to call the smart contract function +func (c *Client) WDelayerSetHermezKeeperAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) { + c.rw.Lock() + defer c.rw.Unlock() + cpy := c.nextBlock().copy() + defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerGetWhiteHackGroupAddress is the interface to call the smart contract function +func (c *Client) WDelayerGetWhiteHackGroupAddress() (*ethCommon.Address, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerSetWhiteHackGroupAddress is the interface to call the smart contract function +func (c *Client) WDelayerSetWhiteHackGroupAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) { + c.rw.Lock() + defer c.rw.Unlock() + cpy := c.nextBlock().copy() + defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerIsEmergencyMode is the interface to call the smart contract function +func (c *Client) WDelayerIsEmergencyMode() (bool, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + log.Error("TODO") + return false, errTODO +} + +// WDelayerGetWithdrawalDelay is the interface to call the smart contract function +func (c *Client) WDelayerGetWithdrawalDelay() (*big.Int, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerGetEmergencyModeStartingTime is the interface to call the smart contract function +func (c *Client) WDelayerGetEmergencyModeStartingTime() (*big.Int, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerEnableEmergencyMode is the interface to call the smart contract function +func (c *Client) WDelayerEnableEmergencyMode() (tx *types.Transaction, err error) { + c.rw.Lock() + defer c.rw.Unlock() + cpy := c.nextBlock().copy() + defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerChangeWithdrawalDelay is the interface to call the smart contract function +func (c *Client) WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (tx *types.Transaction, err error) { + c.rw.Lock() + defer c.rw.Unlock() + cpy := c.nextBlock().copy() + defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerDepositInfo is the interface to call the smart contract function +func (c *Client) WDelayerDepositInfo(owner, token ethCommon.Address) (eth.DepositState, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + log.Error("TODO") + return eth.DepositState{}, errTODO +} + +// WDelayerDeposit is the interface to call the smart contract function +func (c *Client) WDelayerDeposit(onwer, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) { + c.rw.Lock() + defer c.rw.Unlock() + cpy := c.nextBlock().copy() + defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerWithdrawal is the interface to call the smart contract function +func (c *Client) WDelayerWithdrawal(owner, token ethCommon.Address) (tx *types.Transaction, err error) { + c.rw.Lock() + defer c.rw.Unlock() + cpy := c.nextBlock().copy() + defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerEscapeHatchWithdrawal is the interface to call the smart contract function +func (c *Client) WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) { + c.rw.Lock() + defer c.rw.Unlock() + cpy := c.nextBlock().copy() + defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } + + log.Error("TODO") + return nil, errTODO +} + +// WDelayerEventsByBlock returns the events in a block that happened in the WDelayer Contract +func (c *Client) WDelayerEventsByBlock(blockNum int64) (*eth.WDelayerEvents, *ethCommon.Hash, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + block, ok := c.blocks[blockNum] + if !ok { + return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum) + } + return &block.WDelayer.Events, &block.Eth.Hash, nil +} + +// WDelayerConstants returns the Constants of the WDelayer Contract +func (c *Client) WDelayerConstants() (*common.WDelayerConstants, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + return c.wDelayerConstants, nil +}