Browse Source

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
feature/sql-semaphore1
Eduard S 4 years ago
parent
commit
6e4b9b4b70
20 changed files with 669 additions and 151 deletions
  1. +66
    -3
      cli/node/cfg.buidler.toml
  2. +1
    -0
      cli/node/main.go
  3. +9
    -8
      common/ethauction.go
  4. +5
    -4
      common/ethrollup.go
  5. +6
    -5
      common/ethwdelayer.go
  6. +2
    -0
      common/l1tx.go
  7. +2
    -0
      common/l1tx_test.go
  8. +5
    -6
      config/config.go
  9. +92
    -26
      db/historydb/historydb.go
  10. +48
    -0
      db/historydb/historydb_test.go
  11. +2
    -9
      db/l2db/l2db.go
  12. +21
    -12
      db/migrations/0001.sql
  13. +9
    -0
      db/utils.go
  14. +15
    -2
      eth/client.go
  15. +0
    -3
      eth/rollup.go
  16. +7
    -6
      eth/wdelayer.go
  17. +14
    -11
      node/node.go
  18. +104
    -38
      synchronizer/synchronizer.go
  19. +5
    -0
      synchronizer/synchronizer_test.go
  20. +256
    -18
      test/ethclient.go

+ 66
- 3
cli/node/cfg.buidler.toml

@ -18,15 +18,17 @@ URL = "http://localhost:8545"
[Synchronizer] [Synchronizer]
SyncLoopInterval = "1s" SyncLoopInterval = "1s"
[Synchronizer.StartBlockNum] [Synchronizer.StartBlockNum]
Rollup = 1 Rollup = 1
Auction = 1 Auction = 1
WDelayer = 1 WDelayer = 1
[SmartContracts] [SmartContracts]
Rollup = "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe"
Auction = "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8"
TokenHEZ = "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c"
Rollup = "0x6F4e99522F4eB37e0B73D0C0373147893EF12fD5"
Auction = "0x5E0816F0f8bC560cB2B9e9C87187BeCac8c2021F"
WDelayer = "0x5D94e3e7aeC542aB0F9129B9a7BAdeb5B3Ca0f77"
TokenHEZ = "0x2b7dEe2CF60484325716A1c6A193519c8c3b19F3"
TokenHEZName = "Hermez Network Token" TokenHEZName = "Hermez Network Token"
[EthClient] [EthClient]
@ -35,3 +37,64 @@ DeployGasLimit = 1000000
GasPriceDiv = 100 GasPriceDiv = 100
ReceiptTimeout = "60s" ReceiptTimeout = "60s"
IntervalReceiptLoop = "200ms" 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

+ 1
- 0
cli/node/main.go

@ -107,6 +107,7 @@ func getConfig(c *cli.Context) (*Config, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// nodeCfg.Synchronizer.InitialVariables.WDelayer.HermezRollupAddress = nodeCfg.SmartContracts.Rollup
cfg.node = nodeCfg cfg.node = nodeCfg
return &cfg, nil return &cfg, nil

+ 9
- 8
common/ethauction.go

@ -25,20 +25,21 @@ type AuctionConstants struct {
// AuctionVariables are the variables of the Auction Smart Contract // AuctionVariables are the variables of the Auction Smart Contract
type AuctionVariables struct { type AuctionVariables struct {
EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"`
// Boot Coordinator Address // Boot Coordinator Address
DonationAddress ethCommon.Address `json:"donationAddress" meddler:"donation_address"`
DonationAddress ethCommon.Address `json:"donationAddress" meddler:"donation_address" validate:"required"`
// Boot Coordinator Address // 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 // 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 ) // 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 ) // 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%) // 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 // 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 // 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"`
} }

+ 5
- 4
common/ethrollup.go

@ -157,8 +157,9 @@ type Bucket struct {
// RollupVariables are the variables of the Rollup Smart Contract // RollupVariables are the variables of the Rollup Smart Contract
type RollupVariables struct { 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"`
} }

+ 6
- 5
common/ethwdelayer.go

@ -14,11 +14,12 @@ type WDelayerConstants struct {
// WDelayerVariables are the variables of the Withdrawal Delayer Smart Contract // WDelayerVariables are the variables of the Withdrawal Delayer Smart Contract
type WDelayerVariables struct { 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"` EmergencyModeStartingTime uint64 `json:"emergencyModeStartingTime" meddler:"emergency_start_time"`
EmergencyMode bool `json:"emergencyMode" meddler:"emergency_mode"` EmergencyMode bool `json:"emergencyMode" meddler:"emergency_mode"`
} }

+ 2
- 0
common/l1tx.go

@ -282,5 +282,7 @@ func L1CoordinatorTxFromBytes(b []byte) (*L1Tx, error) {
return nil, err return nil, err
} }
tx.FromEthAddr = crypto.PubkeyToAddress(*pubKey) tx.FromEthAddr = crypto.PubkeyToAddress(*pubKey)
tx.Amount = big.NewInt(0)
tx.LoadAmount = big.NewInt(0)
return tx, nil return tx, nil
} }

+ 2
- 0
common/l1tx_test.go

@ -158,6 +158,8 @@ func TestL1CoordinatorTxByteParsers(t *testing.T) {
TokenID: 231, TokenID: 231,
FromBJJ: pk, FromBJJ: pk,
FromEthAddr: fromEthAddr, FromEthAddr: fromEthAddr,
Amount: big.NewInt(0),
LoadAmount: big.NewInt(0),
} }
bytesCoordinatorL1, err := l1Tx.BytesCoordinatorTx(signature) bytesCoordinatorL1, err := l1Tx.BytesCoordinatorTx(signature)

+ 5
- 6
config/config.go

@ -8,6 +8,7 @@ import (
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
ethCommon "github.com/ethereum/go-ethereum/common" ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/synchronizer"
"gopkg.in/go-playground/validator.v9" "gopkg.in/go-playground/validator.v9"
) )
@ -65,16 +66,14 @@ type Node struct {
URL string `validate:"required"` URL string `validate:"required"`
} `validate:"required"` } `validate:"required"`
Synchronizer struct { 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"` } `validate:"required"`
SmartContracts struct { SmartContracts struct {
Rollup ethCommon.Address `validate:"required"` Rollup ethCommon.Address `validate:"required"`
Auction ethCommon.Address `validate:"required"` Auction ethCommon.Address `validate:"required"`
WDelayer ethCommon.Address `validate:"required"`
TokenHEZ ethCommon.Address `validate:"required"` TokenHEZ ethCommon.Address `validate:"required"`
TokenHEZName string `validate:"required"` TokenHEZName string `validate:"required"`
} `validate:"required"` } `validate:"required"`

+ 92
- 26
db/historydb/historydb.go

@ -1097,6 +1097,72 @@ func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) {
return lastL1TxsPosition, row.Scan(&lastL1TxsPosition) 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 // AddBlockSCData stores all the information of a block retrieved by the
// Synchronizer. Blocks should be inserted in order, leaving no gaps because // Synchronizer. Blocks should be inserted in order, leaving no gaps because
// the pagination system of the API/DB depends on this. Within blocks, all // 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() { defer func() {
if err != nil { if err != nil {
errRollback := txn.Rollback()
if errRollback != nil {
log.Errorw("Rollback", "err", errRollback)
}
db.Rollback(txn)
} }
}() }()
// Add block // Add block
err = hdb.addBlock(txn, &blockData.Block)
if err != nil {
if err := hdb.addBlock(txn, &blockData.Block); err != nil {
return err return err
} }
// Add Coordinators // Add Coordinators
if len(blockData.Auction.Coordinators) > 0 { 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 return err
} }
} }
// Add Bids // Add Bids
if len(blockData.Auction.Bids) > 0 { 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 return err
} }
} }
// Add Tokens // Add Tokens
if len(blockData.Rollup.AddedTokens) > 0 { 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 return err
} }
} }
// Add l1 Txs // Add l1 Txs
if len(blockData.Rollup.L1UserTxs) > 0 { 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 return err
} }
} }
@ -1158,16 +1216,14 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) {
batch := &blockData.Rollup.Batches[i] batch := &blockData.Rollup.Batches[i]
// Add Batch: this will trigger an update on the DB // Add Batch: this will trigger an update on the DB
// that will set the batch num of forged L1 txs in this batch // 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 return err
} }
// Add unforged l1 Txs // Add unforged l1 Txs
if batch.L1Batch { if batch.L1Batch {
if len(batch.L1CoordinatorTxs) > 0 { 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 return err
} }
} }
@ -1175,29 +1231,39 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) {
// Add l2 Txs // Add l2 Txs
if len(batch.L2Txs) > 0 { 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 return err
} }
} }
// Add accounts // Add accounts
if len(batch.CreatedAccounts) > 0 { 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 return err
} }
} }
// Add exit tree // Add exit tree
if len(batch.ExitTree) > 0 { 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 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 // TODO: Process withdrawals

+ 48
- 0
db/historydb/historydb_test.go

@ -1,11 +1,13 @@
package historydb package historydb
import ( import (
"database/sql"
"math" "math"
"math/big" "math/big"
"os" "os"
"testing" "testing"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
dbUtils "github.com/hermeznetwork/hermez-node/db" dbUtils "github.com/hermeznetwork/hermez-node/db"
"github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/log"
@ -429,6 +431,52 @@ func TestGetL1UserTxs(t *testing.T) {
assert.Equal(t, 0, len(l1UserTxs)) 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 // setTestBlocks WARNING: this will delete the blocks and recreate them
func setTestBlocks(from, to int64) []common.Block { func setTestBlocks(from, to int64) []common.Block {
test.WipeDB(historyDB.DB()) test.WipeDB(historyDB.DB())

+ 2
- 9
db/l2db/l2db.go

@ -7,7 +7,6 @@ import (
ethCommon "github.com/ethereum/go-ethereum/common" ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db"
"github.com/hermeznetwork/hermez-node/log"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
//nolint:errcheck // driver for postgres DB //nolint:errcheck // driver for postgres DB
@ -243,10 +242,7 @@ func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account, batchNum common.
defer func() { defer func() {
// Rollback the transaction if there was an error. // Rollback the transaction if there was an error.
if err != nil { if err != nil {
errRollback := txn.Rollback()
if errRollback != nil {
log.Errorw("Rollback", "err", errRollback)
}
db.Rollback(txn)
} }
}() }()
for i := 0; i < len(updatedAccounts); i++ { for i := 0; i < len(updatedAccounts); i++ {
@ -291,10 +287,7 @@ func (l2db *L2DB) Purge(currentBatchNum common.BatchNum) (err error) {
defer func() { defer func() {
// Rollback the transaction if there was an error. // Rollback the transaction if there was an error.
if err != nil { 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 // Delete pending txs that have been in the pool after the TTL if maxTxs is reached

+ 21
- 12
db/migrations/0001.sql

@ -516,23 +516,31 @@ FOR EACH ROW EXECUTE PROCEDURE forge_l1_user_txs();
CREATE TABLE rollup_vars ( CREATE TABLE rollup_vars (
eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE, 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, 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, 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, open_auction_slots INT NOT NULL,
min_bid_slots VARCHAR(200) NOT NULL,
allocation_ratio VARCHAR(200),
outbidding INT NOT NULL, 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 -- L2
@ -606,8 +614,9 @@ DROP FUNCTION set_pool_tx;
-- drop tables -- drop tables
DROP TABLE account_creation_auth; DROP TABLE account_creation_auth;
DROP TABLE tx_pool; DROP TABLE tx_pool;
DROP TABLE consensus_vars;
DROP TABLE auction_vars;
DROP TABLE rollup_vars; DROP TABLE rollup_vars;
DROP TABLE wdelayer_vars;
DROP TABLE tx; DROP TABLE tx;
DROP TABLE exit_tree; DROP TABLE exit_tree;
DROP TABLE account; DROP TABLE account;

+ 9
- 0
db/utils.go

@ -1,6 +1,7 @@
package db package db
import ( import (
"database/sql"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"math/big" "math/big"
@ -192,3 +193,11 @@ type Paginationer interface {
GetPagination() *Pagination GetPagination() *Pagination
Len() int 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)
}
}

+ 15
- 2
eth/client.go

@ -17,6 +17,7 @@ type ClientInterface interface {
EthereumInterface EthereumInterface
RollupInterface RollupInterface
AuctionInterface AuctionInterface
WDelayerInterface
} }
// //
@ -28,6 +29,7 @@ type Client struct {
EthereumClient EthereumClient
AuctionClient AuctionClient
RollupClient RollupClient
WDelayerClient
} }
// TokenConfig is used to define the information about token // TokenConfig is used to define the information about token
@ -47,11 +49,17 @@ type AuctionConfig struct {
TokenHEZ TokenConfig 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 // ClientConfig is the configuration of the Client
type ClientConfig struct { type ClientConfig struct {
Ethereum EthereumConfig Ethereum EthereumConfig
Rollup RollupConfig Rollup RollupConfig
Auction AuctionConfig Auction AuctionConfig
WDelayer WDelayerConfig
} }
// NewClient creates a new Client to interact with Ethereum and the Hermez smart contracts. // 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 { if err != nil {
return nil, err 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 { if err != nil {
return nil, err return nil, err
} }
return &Client{ return &Client{
EthereumClient: *ethereumClient, EthereumClient: *ethereumClient,
AuctionClient: *auctionClient, AuctionClient: *auctionClient,
RollupClient: *rollupCient,
RollupClient: *rollupClient,
WDelayerClient: *wDelayerClient,
}, nil }, nil
} }

+ 0
- 3
eth/rollup.go

@ -510,9 +510,6 @@ func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethC
return nil, nil, err return nil, nil, err
} }
if len(logs) > 0 { if len(logs) > 0 {
for i := range logs {
log.Debugw("log", "i", i, "blockHash", logs[i].BlockHash)
}
blockHash = &logs[0].BlockHash blockHash = &logs[0].BlockHash
} }
for _, vLog := range logs { for _, vLog := range logs {

+ 7
- 6
eth/wdelayer.go

@ -114,7 +114,7 @@ type WDelayerInterface interface {
WDelayerGetEmergencyModeStartingTime() (*big.Int, error) WDelayerGetEmergencyModeStartingTime() (*big.Int, error)
WDelayerEnableEmergencyMode() (*types.Transaction, error) WDelayerEnableEmergencyMode() (*types.Transaction, error)
WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (*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) WDelayerDeposit(onwer, token ethCommon.Address, amount *big.Int) (*types.Transaction, error)
WDelayerWithdrawal(owner, token ethCommon.Address) (*types.Transaction, error) WDelayerWithdrawal(owner, token ethCommon.Address) (*types.Transaction, error)
WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (*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 // 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 { if err := c.client.Call(func(ec *ethclient.Client) error {
constants.MaxWithdrawalDelay, err = c.wdelayer.MAXWITHDRAWALDELAY(nil) constants.MaxWithdrawalDelay, err = c.wdelayer.MAXWITHDRAWALDELAY(nil)
if err != nil { if err != nil {
@ -377,7 +378,7 @@ var (
// there are no events in that block, blockHash is nil. // there are no events in that block, blockHash is nil.
func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, *ethCommon.Hash, error) { func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, *ethCommon.Hash, error) {
var wdelayerEvents WDelayerEvents var wdelayerEvents WDelayerEvents
var blockHash ethCommon.Hash
var blockHash *ethCommon.Hash
query := ethereum.FilterQuery{ query := ethereum.FilterQuery{
FromBlock: big.NewInt(blockNum), FromBlock: big.NewInt(blockNum),
@ -394,10 +395,10 @@ func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents,
return nil, nil, err return nil, nil, err
} }
if len(logs) > 0 { if len(logs) > 0 {
blockHash = logs[0].BlockHash
blockHash = &logs[0].BlockHash
} }
for _, vLog := range logs { for _, vLog := range logs {
if vLog.BlockHash != blockHash {
if vLog.BlockHash != *blockHash {
log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String()) log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
return nil, nil, ErrBlockHashMismatchEvent return nil, nil, ErrBlockHashMismatchEvent
} }
@ -470,5 +471,5 @@ func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents,
wdelayerEvents.NewHermezGovernanceDAOAddress = append(wdelayerEvents.NewHermezGovernanceDAOAddress, governanceDAOAddress) wdelayerEvents.NewHermezGovernanceDAOAddress = append(wdelayerEvents.NewHermezGovernanceDAOAddress, governanceDAOAddress)
} }
} }
return &wdelayerEvents, &blockHash, nil
return &wdelayerEvents, blockHash, nil
} }

+ 14
- 11
node/node.go

@ -102,17 +102,17 @@ func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node,
Name: cfg.SmartContracts.TokenHEZName, Name: cfg.SmartContracts.TokenHEZName,
}, },
}, },
WDelayer: eth.WDelayerConfig{
Address: cfg.SmartContracts.WDelayer,
},
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
sync, err := synchronizer.NewSynchronizer(client, historyDB, stateDB, synchronizer.Config{ 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 { if err != nil {
return nil, err return nil, err
@ -176,9 +176,9 @@ func (n *Node) StartCoordinator() {
n.stopGetProofCallForge = make(chan bool) n.stopGetProofCallForge = make(chan bool)
n.stopForgeCallConfirm = 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 queueSize := 1
batchCh0 := make(chan *coordinator.BatchInfo, queueSize) batchCh0 := make(chan *coordinator.BatchInfo, queueSize)
@ -249,15 +249,18 @@ func (n *Node) StopCoordinator() {
// StartSynchronizer starts the synchronizer // StartSynchronizer starts the synchronizer
func (n *Node) StartSynchronizer() { func (n *Node) StartSynchronizer() {
log.Info("Starting Synchronizer...") 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() { go func() {
defer func() { n.stoppedSync <- true }()
defer func() {
n.stoppedSync <- true
}()
var lastBlock *common.Block var lastBlock *common.Block
d := time.Duration(0) d := time.Duration(0)
for { for {
select { select {
case <-n.ctx.Done(): case <-n.ctx.Done():
log.Info("Coordinator stopped")
log.Info("Synchronizer stopped")
return return
case <-time.After(d): case <-time.After(d):
if blockData, discarded, err := n.sync.Sync2(n.ctx, lastBlock); err != nil { if blockData, discarded, err := n.sync.Sync2(n.ctx, lastBlock); err != nil {

+ 104
- 38
synchronizer/synchronizer.go

@ -41,14 +41,22 @@ var (
// ConfigStartBlockNum sets the first block used to start tracking the smart // ConfigStartBlockNum sets the first block used to start tracking the smart
// contracts // contracts
type ConfigStartBlockNum struct { 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 // Config is the Synchronizer configuration
type Config struct { type Config struct {
StartBlockNum ConfigStartBlockNum
StartBlockNum ConfigStartBlockNum
InitialVariables SCVariables
} }
// Synchronizer implements the Synchronizer type // Synchronizer implements the Synchronizer type
@ -61,6 +69,7 @@ type Synchronizer struct {
stateDB *statedb.StateDB stateDB *statedb.StateDB
cfg Config cfg Config
startBlockNum int64 startBlockNum int64
vars SCVariables
// firstSavedBlock *common.Block // firstSavedBlock *common.Block
// mux sync.Mutex // mux sync.Mutex
} }
@ -78,12 +87,11 @@ func NewSynchronizer(ethClient eth.ClientInterface, historyDB *historydb.History
log.Errorw("NewSynchronizer ethClient.RollupConstants()", "err", err) log.Errorw("NewSynchronizer ethClient.RollupConstants()", "err", err)
return nil, 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 // Set startBlockNum to the minimum between Auction, Rollup and
// WDelayer StartBlockNum // WDelayer StartBlockNum
@ -94,19 +102,17 @@ func NewSynchronizer(ethClient eth.ClientInterface, historyDB *historydb.History
if startBlockNum < cfg.StartBlockNum.WDelayer { if startBlockNum < cfg.StartBlockNum.WDelayer {
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, historyDB: historyDB,
stateDB: stateDB, stateDB: stateDB,
cfg: cfg, cfg: cfg,
startBlockNum: startBlockNum, startBlockNum: startBlockNum,
}, nil
}
return s, s.init()
} }
// AuctionConstants returns the AuctionConstants read from the smart contract // AuctionConstants returns the AuctionConstants read from the smart contract
@ -124,6 +130,23 @@ func (s *Synchronizer) WDelayerConstants() *common.WDelayerConstants {
return &s.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. // Sync2 attems to synchronize an ethereum block starting from lastSavedBlock.
// If lastSavedBlock is nil, the lastSavedBlock value is obtained from de DB. // 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 // 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 return &rollupData, nil
} }
if *blockHash != ethBlock.Hash { 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()) "got", blockHash.String())
return nil, eth.ErrBlockHashMismatchEvent return nil, eth.ErrBlockHashMismatchEvent
} }
@ -498,16 +521,15 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e
rollupData.AddedTokens = append(rollupData.AddedTokens, token) rollupData.AddedTokens = append(rollupData.AddedTokens, token)
} }
var vars common.RollupVariables
varsUpdate := false varsUpdate := false
for _, evtUpdateForgeL1L2BatchTimeout := range rollupEvents.UpdateForgeL1L2BatchTimeout { for _, evtUpdateForgeL1L2BatchTimeout := range rollupEvents.UpdateForgeL1L2BatchTimeout {
vars.ForgeL1L2BatchTimeout = evtUpdateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout
s.vars.Rollup.ForgeL1L2BatchTimeout = evtUpdateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout
varsUpdate = true varsUpdate = true
} }
for _, evtUpdateFeeAddToken := range rollupEvents.UpdateFeeAddToken { for _, evtUpdateFeeAddToken := range rollupEvents.UpdateFeeAddToken {
vars.FeeAddToken = evtUpdateFeeAddToken.NewFeeAddToken
s.vars.Rollup.FeeAddToken = evtUpdateFeeAddToken.NewFeeAddToken
varsUpdate = true varsUpdate = true
} }
@ -524,7 +546,8 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e
} }
if varsUpdate { if varsUpdate {
rollupData.Vars = &vars
s.vars.Rollup.EthBlockNum = blockNum
rollupData.Vars = &s.vars.Rollup
} }
return &rollupData, nil return &rollupData, nil
@ -552,7 +575,7 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData,
return &auctionData, nil return &auctionData, nil
} }
if *blockHash != ethBlock.Hash { 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()) "got", blockHash.String())
return nil, eth.ErrBlockHashMismatchEvent return nil, eth.ErrBlockHashMismatchEvent
} }
@ -578,35 +601,34 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData,
auctionData.Coordinators = append(auctionData.Coordinators, coordinator) auctionData.Coordinators = append(auctionData.Coordinators, coordinator)
} }
var vars common.AuctionVariables
varsUpdate := false varsUpdate := false
for _, evt := range auctionEvents.NewSlotDeadline { for _, evt := range auctionEvents.NewSlotDeadline {
vars.SlotDeadline = evt.NewSlotDeadline
s.vars.Auction.SlotDeadline = evt.NewSlotDeadline
varsUpdate = true varsUpdate = true
} }
for _, evt := range auctionEvents.NewClosedAuctionSlots { for _, evt := range auctionEvents.NewClosedAuctionSlots {
vars.ClosedAuctionSlots = evt.NewClosedAuctionSlots
s.vars.Auction.ClosedAuctionSlots = evt.NewClosedAuctionSlots
varsUpdate = true varsUpdate = true
} }
for _, evt := range auctionEvents.NewOutbidding { for _, evt := range auctionEvents.NewOutbidding {
vars.Outbidding = evt.NewOutbidding
s.vars.Auction.Outbidding = evt.NewOutbidding
varsUpdate = true varsUpdate = true
} }
for _, evt := range auctionEvents.NewDonationAddress { for _, evt := range auctionEvents.NewDonationAddress {
vars.DonationAddress = evt.NewDonationAddress
s.vars.Auction.DonationAddress = evt.NewDonationAddress
varsUpdate = true varsUpdate = true
} }
for _, evt := range auctionEvents.NewBootCoordinator { for _, evt := range auctionEvents.NewBootCoordinator {
vars.BootCoordinator = evt.NewBootCoordinator
s.vars.Auction.BootCoordinator = evt.NewBootCoordinator
varsUpdate = true varsUpdate = true
} }
for _, evt := range auctionEvents.NewOpenAuctionSlots { for _, evt := range auctionEvents.NewOpenAuctionSlots {
vars.OpenAuctionSlots = evt.NewOpenAuctionSlots
s.vars.Auction.OpenAuctionSlots = evt.NewOpenAuctionSlots
varsUpdate = true varsUpdate = true
} }
for _, evt := range auctionEvents.NewAllocationRatio { for _, evt := range auctionEvents.NewAllocationRatio {
vars.AllocationRatio = evt.NewAllocationRatio
s.vars.Auction.AllocationRatio = evt.NewAllocationRatio
varsUpdate = true varsUpdate = true
} }
for _, evt := range auctionEvents.NewDefaultSlotSetBid { 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 "+ return nil, fmt.Errorf("unexpected SlotSet in "+
"auctionEvents.NewDefaultSlotSetBid: %v", evt.SlotSet) "auctionEvents.NewDefaultSlotSetBid: %v", evt.SlotSet)
} }
vars.DefaultSlotSetBid[evt.SlotSet] = evt.NewInitialMinBid
s.vars.Auction.DefaultSlotSetBid[evt.SlotSet] = evt.NewInitialMinBid
varsUpdate = true varsUpdate = true
} }
@ -623,7 +645,8 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData,
// NOTE: We ignore HEZClaimed // NOTE: We ignore HEZClaimed
if varsUpdate { if varsUpdate {
auctionData.Vars = &vars
s.vars.Auction.EthBlockNum = blockNum
auctionData.Vars = &s.vars.Auction
} }
return &auctionData, nil return &auctionData, nil
@ -631,11 +654,54 @@ func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData,
// wdelayerSync gets information from the Withdrawal Delayer Contract // wdelayerSync gets information from the Withdrawal Delayer Contract
func (s *Synchronizer) wdelayerSync(ethBlock *common.Block) (*common.WDelayerData, error) { 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 return &wDelayerData, nil
} }

+ 5
- 0
synchronizer/synchronizer_test.go

@ -241,6 +241,11 @@ func TestSync(t *testing.T) {
Auction: 1, Auction: 1,
WDelayer: 1, WDelayer: 1,
}, },
InitialVariables: SCVariables{
Rollup: *clientSetup.RollupVariables,
Auction: *clientSetup.AuctionVariables,
WDelayer: *clientSetup.WDelayerVariables,
},
}) })
require.Nil(t, err) require.Nil(t, err)

+ 256
- 18
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 // RollupBlock stores all the data related to the Rollup SC from an ethereum block
type RollupBlock struct { type RollupBlock struct {
State eth.RollupState State eth.RollupState
@ -185,9 +195,10 @@ type EthereumBlock struct {
// Block represents a ethereum block // Block represents a ethereum block
type Block struct { type Block struct {
Rollup *RollupBlock
Auction *AuctionBlock
Eth *EthereumBlock
Rollup *RollupBlock
Auction *AuctionBlock
WDelayer *WDelayerBlock
Eth *EthereumBlock
} }
func (b *Block) copy() *Block { func (b *Block) copy() *Block {
@ -210,8 +221,10 @@ func (b *Block) Next() *Block {
blockNext.Rollup.Constants = b.Rollup.Constants blockNext.Rollup.Constants = b.Rollup.Constants
blockNext.Auction.Constants = b.Auction.Constants blockNext.Auction.Constants = b.Auction.Constants
blockNext.WDelayer.Constants = b.WDelayer.Constants
blockNext.Rollup.Eth = blockNext.Eth blockNext.Rollup.Eth = blockNext.Eth
blockNext.Auction.Eth = blockNext.Eth blockNext.Auction.Eth = blockNext.Eth
blockNext.WDelayer.Eth = blockNext.Eth
return blockNext return blockNext
} }
@ -219,11 +232,13 @@ func (b *Block) Next() *Block {
// ClientSetup is used to initialize the constants of the Smart Contracts and // ClientSetup is used to initialize the constants of the Smart Contracts and
// other details of the test Client // other details of the test Client
type ClientSetup struct { 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 // NewClientSetupExample returns a ClientSetup example with hardcoded realistic
@ -279,11 +294,26 @@ func NewClientSetupExample() *ClientSetup {
Outbidding: 1000, Outbidding: 1000,
SlotDeadline: 20, 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{ 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 // Client implements the eth.ClientInterface interface, allowing to manipulate the
// values for testing, working with deterministic results. // values for testing, working with deterministic results.
type Client struct { 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 // state state
blockNum int64 // last mined block num blockNum int64 // last mined block num
maxBlockNum int64 // highest block num calculated maxBlockNum int64 // highest block num calculated
@ -365,6 +396,13 @@ func NewClient(l bool, timer Timer, addr *ethCommon.Address, setup *ClientSetup)
Events: eth.NewAuctionEvents(), Events: eth.NewAuctionEvents(),
Constants: setup.AuctionConstants, 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{ Eth: &EthereumBlock{
BlockNum: blockNum, BlockNum: blockNum,
Time: timer.Time(), Time: timer.Time(),
@ -385,6 +423,7 @@ func NewClient(l bool, timer Timer, addr *ethCommon.Address, setup *ClientSetup)
addr: addr, addr: addr,
rollupConstants: setup.RollupConstants, rollupConstants: setup.RollupConstants,
auctionConstants: setup.AuctionConstants, auctionConstants: setup.AuctionConstants,
wDelayerConstants: setup.WDelayerConstants,
blocks: blocks, blocks: blocks,
timer: timer, timer: timer,
hasher: hasher, hasher: hasher,
@ -1343,3 +1382,202 @@ func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethC
} }
return &block.Auction.Events, &block.Eth.Hash, nil 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
}

Loading…
Cancel
Save