Browse Source

Fix exit table, set delayed_withdrawn in exits

- In exit table, `instant_withdrawn`, `delayed_withdraw_request`, and
  `delayed_withdrawn` were referencing batch_num.  But these actions happen
  outside a batch, so they should reference a block_num.
- Process delayed withdrawns:
    - In Synchronizer, first match a Rollup delayed withdrawn request, with the
      WDelayer deposit (via TxHash), and store the owner and token associated
      with the delayed withdrawn.
    - In HistoryDB: store the owner and token of a delayed withdrawal request
      in the exit_tree, and set delayed_withdrawn when the withdraw is done in
      the WDelayer.
- Update dependency of sqlx to master
    - Last release of sqlx is from 2018 October, and it doesn't support
      `NamedQuery` with a slice of structs, which is used in this commit.
feature/sql-semaphore1
Eduard S 4 years ago
parent
commit
e731b79e96
16 changed files with 226 additions and 130 deletions
  1. +1
    -1
      api/api_test.go
  2. +18
    -2
      common/block.go
  3. +4
    -0
      common/exittree.go
  4. +64
    -57
      db/historydb/historydb.go
  5. +43
    -25
      db/historydb/historydb_test.go
  6. +2
    -2
      db/l2db/l2db.go
  7. +5
    -3
      db/migrations/0001.sql
  8. +1
    -2
      db/utils.go
  9. +2
    -0
      eth/rollup.go
  10. +2
    -0
      eth/wdelayer.go
  11. +1
    -1
      go.mod
  12. +2
    -0
      go.sum
  13. +33
    -5
      synchronizer/synchronizer.go
  14. +37
    -18
      test/ethclient.go
  15. +7
    -10
      test/historydb.go
  16. +4
    -4
      test/til/txs.go

+ 1
- 1
api/api_test.go

@ -222,7 +222,7 @@ func TestMain(m *testing.M) {
// Gen exits and add them to DB // Gen exits and add them to DB
const totalExits = 40 const totalExits = 40
// TODO: UPDATE with til // TODO: UPDATE with til
exits := test.GenExitTree(totalExits, batches, accs)
exits := test.GenExitTree(totalExits, batches, accs, blocks)
err = api.h.AddExitTree(exits) err = api.h.AddExitTree(exits)
if err != nil { if err != nil {
panic(err) panic(err)

+ 18
- 2
common/block.go

@ -1,6 +1,7 @@
package common package common
import ( import (
"math/big"
"time" "time"
ethCommon "github.com/ethereum/go-ethereum/common" ethCommon "github.com/ethereum/go-ethereum/common"
@ -51,15 +52,30 @@ func NewAuctionData() AuctionData {
} }
} }
// WDelayerTransfer represents a transfer (either deposit or withdrawal) in the
// WDelayer smart contract
type WDelayerTransfer struct {
Owner ethCommon.Address
Token ethCommon.Address
Amount *big.Int
// TxHash ethCommon.Hash // hash of the transaction in which the wdelayer transfer happened
}
// WDelayerData contains information returned by the WDelayer smart contract // WDelayerData contains information returned by the WDelayer smart contract
type WDelayerData struct { type WDelayerData struct {
Vars *WDelayerVariables
Vars *WDelayerVariables
Deposits []WDelayerTransfer
DepositsByTxHash map[ethCommon.Hash]*WDelayerTransfer
Withdrawals []WDelayerTransfer
} }
// NewWDelayerData creates an empty WDelayerData. // NewWDelayerData creates an empty WDelayerData.
func NewWDelayerData() WDelayerData { func NewWDelayerData() WDelayerData {
return WDelayerData{ return WDelayerData{
Vars: nil,
Vars: nil,
Deposits: make([]WDelayerTransfer, 0),
DepositsByTxHash: make(map[ethCommon.Hash]*WDelayerTransfer),
Withdrawals: make([]WDelayerTransfer, 0),
} }
} }

+ 4
- 0
common/exittree.go

@ -3,6 +3,7 @@ package common
import ( import (
"math/big" "math/big"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/iden3/go-merkletree" "github.com/iden3/go-merkletree"
) )
@ -30,4 +31,7 @@ type WithdrawInfo struct {
Idx Idx Idx Idx
NumExitRoot BatchNum NumExitRoot BatchNum
InstantWithdraw bool InstantWithdraw bool
TxHash ethCommon.Hash // hash of the transaction in which the withdraw happened
Owner ethCommon.Address
Token ethCommon.Address
} }

+ 64
- 57
db/historydb/historydb.go

@ -503,48 +503,72 @@ func (hdb *HistoryDB) addExitTree(d meddler.DB, exitTree []common.ExitInfo) erro
) )
} }
type exitID struct {
batchNum int64
idx int64
}
func (hdb *HistoryDB) updateExitTree(d meddler.DB, blockNum int64,
instantWithdrawn []exitID, delayedWithdrawRequest []exitID) error {
// helperQueryExitIDTuples is a helper function to build the query with
// an array of tuples in the arguments side built from []exitID
helperQueryExitIDTuples := func(queryTmpl string, blockNum int64, exits []exitID) (string, []interface{}) {
args := make([]interface{}, len(exits)*2+1)
holder := ""
args[0] = blockNum
for i, v := range exits {
args[1+i*2+0] = v.batchNum
args[1+i*2+1] = v.idx
holder += "(?, ?),"
func (hdb *HistoryDB) updateExitTree(d sqlx.Ext, blockNum int64,
rollupWithdrawals []common.WithdrawInfo, wDelayerWithdrawals []common.WDelayerTransfer) error {
type withdrawal struct {
BatchNum int64 `db:"batch_num"`
AccountIdx int64 `db:"account_idx"`
InstantWithdrawn *int64 `db:"instant_withdrawn"`
DelayedWithdrawRequest *int64 `db:"delayed_withdraw_request"`
DelayedWithdrawn *int64 `db:"delayed_withdrawn"`
Owner *ethCommon.Address `db:"owner"`
Token *ethCommon.Address `db:"token"`
}
withdrawals := make([]withdrawal, len(rollupWithdrawals)+len(wDelayerWithdrawals))
for i := range rollupWithdrawals {
info := &rollupWithdrawals[i]
withdrawals[i] = withdrawal{
BatchNum: int64(info.NumExitRoot),
AccountIdx: int64(info.Idx),
}
if info.InstantWithdraw {
withdrawals[i].InstantWithdrawn = &blockNum
} else {
withdrawals[i].DelayedWithdrawRequest = &blockNum
withdrawals[i].Owner = &info.Owner
withdrawals[i].Token = &info.Token
} }
query := fmt.Sprintf(queryTmpl, holder[:len(holder)-1])
return hdb.db.Rebind(query), args
} }
if len(instantWithdrawn) > 0 {
query, args := helperQueryExitIDTuples(
`UPDATE exit_tree SET instant_withdrawn = ? WHERE (batch_num, account_idx) IN (%s);`,
blockNum,
instantWithdrawn,
)
if _, err := hdb.db.DB.Exec(query, args...); err != nil {
return err
for i := range wDelayerWithdrawals {
info := &wDelayerWithdrawals[i]
withdrawals[len(rollupWithdrawals)+i] = withdrawal{
DelayedWithdrawn: &blockNum,
Owner: &info.Owner,
Token: &info.Token,
} }
} }
if len(delayedWithdrawRequest) > 0 {
query, args := helperQueryExitIDTuples(
`UPDATE exit_tree SET delayed_withdraw_request = ? WHERE (batch_num, account_idx) IN (%s);`,
blockNum,
delayedWithdrawRequest,
)
if _, err := hdb.db.DB.Exec(query, args...); err != nil {
// In VALUES we set an initial row of NULLs to set the types of each
// variable passed as argument
query := `
UPDATE exit_tree e SET
instant_withdrawn = d.instant_withdrawn,
delayed_withdraw_request = CASE
WHEN e.delayed_withdraw_request IS NOT NULL THEN e.delayed_withdraw_request
ELSE d.delayed_withdraw_request
END,
delayed_withdrawn = d.delayed_withdrawn,
owner = d.owner,
token = d.token
FROM (VALUES
(NULL::::BIGINT, NULL::::BIGINT, NULL::::BIGINT, NULL::::BIGINT, NULL::::BIGINT, NULL::::BYTEA, NULL::::BYTEA),
(:batch_num,
:account_idx,
:instant_withdrawn,
:delayed_withdraw_request,
:delayed_withdrawn,
:owner,
:token)
) as d (batch_num, account_idx, instant_withdrawn, delayed_withdraw_request, delayed_withdrawn, owner, token)
WHERE
(d.batch_num IS NOT NULL AND e.batch_num = d.batch_num AND e.account_idx = d.account_idx) OR
(d.delayed_withdrawn IS NOT NULL AND e.delayed_withdrawn IS NULL AND e.owner = d.owner AND e.token = d.token)
`
if len(withdrawals) > 0 {
if _, err := sqlx.NamedQuery(d, query, withdrawals); err != nil {
return err return err
} }
} }
return nil return nil
} }
@ -1210,7 +1234,7 @@ func (hdb *HistoryDB) setWDelayerVars(d meddler.DB, wDelayer *common.WDelayerVar
// exist in the smart contracts. // exist in the smart contracts.
func (hdb *HistoryDB) SetInitialSCVars(rollup *common.RollupVariables, func (hdb *HistoryDB) SetInitialSCVars(rollup *common.RollupVariables,
auction *common.AuctionVariables, wDelayer *common.WDelayerVariables) error { auction *common.AuctionVariables, wDelayer *common.WDelayerVariables) error {
txn, err := hdb.db.Begin()
txn, err := hdb.db.Beginx()
if err != nil { if err != nil {
return err return err
} }
@ -1242,7 +1266,7 @@ func (hdb *HistoryDB) SetInitialSCVars(rollup *common.RollupVariables,
// 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
// items should also be in the correct order (Accounts, Tokens, Txs, etc.) // items should also be in the correct order (Accounts, Tokens, Txs, etc.)
func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) { func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) {
txn, err := hdb.db.Begin()
txn, err := hdb.db.Beginx()
if err != nil { if err != nil {
return err return err
} }
@ -1340,28 +1364,11 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) {
} }
} }
if len(blockData.Rollup.Withdrawals) > 0 {
instantWithdrawn := []exitID{}
delayedWithdrawRequest := []exitID{}
for _, withdraw := range blockData.Rollup.Withdrawals {
exitID := exitID{
batchNum: int64(withdraw.NumExitRoot),
idx: int64(withdraw.Idx),
}
if withdraw.InstantWithdraw {
instantWithdrawn = append(instantWithdrawn, exitID)
} else {
delayedWithdrawRequest = append(delayedWithdrawRequest, exitID)
}
}
if err := hdb.updateExitTree(txn, blockData.Block.EthBlockNum,
instantWithdrawn, delayedWithdrawRequest); err != nil {
return err
}
if err := hdb.updateExitTree(txn, blockData.Block.EthBlockNum,
blockData.Rollup.Withdrawals, blockData.WDelayer.Withdrawals); err != nil {
return err
} }
// TODO: Process WDelayer withdrawals
return txn.Commit() return txn.Commit()
} }

+ 43
- 25
db/historydb/historydb_test.go

@ -481,7 +481,7 @@ func TestExitTree(t *testing.T) {
const nAccounts = 3 const nAccounts = 3
accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches) accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
assert.NoError(t, historyDB.AddAccounts(accs)) assert.NoError(t, historyDB.AddAccounts(accs))
exitTree := test.GenExitTree(nBatches, batches, accs)
exitTree := test.GenExitTree(nBatches, batches, accs, blocks)
err = historyDB.AddExitTree(exitTree) err = historyDB.AddExitTree(exitTree)
assert.NoError(t, err) assert.NoError(t, err)
} }
@ -509,7 +509,6 @@ func TestGetL1UserTxs(t *testing.T) {
// Sanity check // Sanity check
require.Equal(t, 1, len(blocks)) require.Equal(t, 1, len(blocks))
require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs)) require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
// fmt.Printf("DBG Blocks: %+v\n", blocks)
toForgeL1TxsNum := int64(1) toForgeL1TxsNum := int64(1)
@ -597,14 +596,15 @@ func TestUpdateExitTree(t *testing.T) {
ForceExit(1) A: 100 ForceExit(1) A: 100
ForceExit(1) B: 80 ForceExit(1) B: 80
Exit(1) C: 50 (200)
Exit(1) D: 30 (200)
Exit(1) C: 50 (172)
Exit(1) D: 30 (172)
> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3} > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
> batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil} > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
> block // blockNum=3 > block // blockNum=3
> block // blockNum=4 (empty block) > block // blockNum=4 (empty block)
> block // blockNum=5 (empty block)
` `
tc := til.NewContext(common.RollupConstMaxL1UserTx) tc := til.NewContext(common.RollupConstMaxL1UserTx)
@ -617,39 +617,33 @@ func TestUpdateExitTree(t *testing.T) {
err = tc.FillBlocksExtra(blocks, &tilCfgExtra) err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
assert.Nil(t, err) assert.Nil(t, err)
// Add all blocks except for the last one
for i := range blocks[:len(blocks)-1] {
// Add all blocks except for the last two
for i := range blocks[:len(blocks)-2] {
err = historyDB.AddBlockSCData(&blocks[i]) err = historyDB.AddBlockSCData(&blocks[i])
require.Nil(t, err) require.Nil(t, err)
} }
// Add withdraws to the last block, and insert block into the DB
block := &blocks[len(blocks)-1]
// Add withdraws to the second-to-last block, and insert block into the DB
block := &blocks[len(blocks)-2]
require.Equal(t, int64(4), block.Block.EthBlockNum) require.Equal(t, int64(4), block.Block.EthBlockNum)
tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
// block.WDelayer.Deposits = append(block.WDelayer.Deposits,
// common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
// common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
// )
block.Rollup.Withdrawals = append(block.Rollup.Withdrawals, block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true}, common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false},
common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true}, common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false},
common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
) )
err = historyDB.addBlock(historyDB.db, &block.Block) err = historyDB.addBlock(historyDB.db, &block.Block)
require.Nil(t, err) require.Nil(t, err)
// update exit trees in DB
instantWithdrawn := []exitID{}
delayedWithdrawRequest := []exitID{}
for _, withdraw := range block.Rollup.Withdrawals {
exitID := exitID{
batchNum: int64(withdraw.NumExitRoot),
idx: int64(withdraw.Idx),
}
if withdraw.InstantWithdraw {
instantWithdrawn = append(instantWithdrawn, exitID)
} else {
delayedWithdrawRequest = append(delayedWithdrawRequest, exitID)
}
}
err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum, instantWithdrawn, delayedWithdrawRequest)
err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
require.Nil(t, err) require.Nil(t, err)
// Check that exits in DB match with the expected values // Check that exits in DB match with the expected values
@ -668,6 +662,30 @@ func TestUpdateExitTree(t *testing.T) {
assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest) assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
} }
} }
// Add delayed withdraw to the last block, and insert block into the DB
block = &blocks[len(blocks)-1]
require.Equal(t, int64(5), block.Block.EthBlockNum)
block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
common.WDelayerTransfer{
Owner: tc.UsersByIdx[257].Addr,
Token: tokenAddr,
Amount: big.NewInt(80),
})
err = historyDB.addBlock(historyDB.db, &block.Block)
require.Nil(t, err)
err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
require.Nil(t, err)
// Check that delayed withdrawn has been set
dbExits, err = historyDB.GetAllExits()
require.Nil(t, err)
for _, dbExit := range dbExits {
dbExitsByIdx[dbExit.AccountIdx] = dbExit
}
require.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[257].DelayedWithdrawn)
} }
// setTestBlocks WARNING: this will delete the blocks and recreate them // setTestBlocks WARNING: this will delete the blocks and recreate them

+ 2
- 2
db/l2db/l2db.go

@ -235,7 +235,7 @@ func (l2db *L2DB) InvalidateTxs(txIDs []common.TxID, batchNum common.BatchNum) e
// CheckNonces invalidate txs with nonces that are smaller or equal than their respective accounts nonces. // CheckNonces invalidate txs with nonces that are smaller or equal than their respective accounts nonces.
// The state of the affected txs will be changed from Pending -> Invalid // The state of the affected txs will be changed from Pending -> Invalid
func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account, batchNum common.BatchNum) (err error) { func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account, batchNum common.BatchNum) (err error) {
txn, err := l2db.db.Begin()
txn, err := l2db.db.Beginx()
if err != nil { if err != nil {
return err return err
} }
@ -280,7 +280,7 @@ func (l2db *L2DB) Reorg(lastValidBatch common.BatchNum) error {
// Purge deletes transactions that have been forged or marked as invalid for longer than the safety period // Purge deletes transactions that have been forged or marked as invalid for longer than the safety period
// it also deletes txs that has been in the L2DB for longer than the ttl if maxTxs has been exceeded // it also deletes txs that has been in the L2DB for longer than the ttl if maxTxs has been exceeded
func (l2db *L2DB) Purge(currentBatchNum common.BatchNum) (err error) { func (l2db *L2DB) Purge(currentBatchNum common.BatchNum) (err error) {
txn, err := l2db.db.Begin()
txn, err := l2db.db.Beginx()
if err != nil { if err != nil {
return err return err
} }

+ 5
- 3
db/migrations/0001.sql

@ -109,9 +109,11 @@ CREATE TABLE exit_tree (
account_idx BIGINT REFERENCES account (idx) ON DELETE CASCADE, account_idx BIGINT REFERENCES account (idx) ON DELETE CASCADE,
merkle_proof BYTEA NOT NULL, merkle_proof BYTEA NOT NULL,
balance BYTEA NOT NULL, balance BYTEA NOT NULL,
instant_withdrawn BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL,
delayed_withdraw_request BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL,
delayed_withdrawn BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL
instant_withdrawn BIGINT REFERENCES block (eth_block_num) ON DELETE SET NULL,
delayed_withdraw_request BIGINT REFERENCES block (eth_block_num) ON DELETE SET NULL,
owner BYTEA,
token BYTEA,
delayed_withdrawn BIGINT REFERENCES block (eth_block_num) ON DELETE SET NULL
); );
-- +migrate StatementBegin -- +migrate StatementBegin

+ 1
- 2
db/utils.go

@ -1,7 +1,6 @@
package db package db
import ( import (
"database/sql"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"math/big" "math/big"
@ -180,7 +179,7 @@ func SlicePtrsToSlice(slice interface{}) interface{} {
} }
// Rollback an sql transaction, and log the error if it's not nil // Rollback an sql transaction, and log the error if it's not nil
func Rollback(txn *sql.Tx) {
func Rollback(txn *sqlx.Tx) {
err := txn.Rollback() err := txn.Rollback()
if err != nil { if err != nil {
log.Errorw("Rollback", "err", err) log.Errorw("Rollback", "err", err)

+ 2
- 0
eth/rollup.go

@ -91,6 +91,7 @@ type RollupEventWithdraw struct {
Idx uint64 Idx uint64
NumExitRoot uint64 NumExitRoot uint64
InstantWithdraw bool InstantWithdraw bool
TxHash ethCommon.Hash // Hash of the transaction that generated this event
} }
// RollupEvents is the list of events in a block of the Rollup Smart Contract // RollupEvents is the list of events in a block of the Rollup Smart Contract
@ -577,6 +578,7 @@ func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethC
if instantWithdraw == 1 { if instantWithdraw == 1 {
withdraw.InstantWithdraw = true withdraw.InstantWithdraw = true
} }
withdraw.TxHash = vLog.TxHash
rollupEvents.Withdraw = append(rollupEvents.Withdraw, withdraw) rollupEvents.Withdraw = append(rollupEvents.Withdraw, withdraw)
} }
} }

+ 2
- 0
eth/wdelayer.go

@ -30,6 +30,7 @@ type WDelayerEventDeposit struct {
Token ethCommon.Address Token ethCommon.Address
Amount *big.Int Amount *big.Int
DepositTimestamp uint64 DepositTimestamp uint64
TxHash ethCommon.Hash // Hash of the transaction that generated this event
} }
// WDelayerEventWithdraw is an event of the WithdrawalDelayer Smart Contract // WDelayerEventWithdraw is an event of the WithdrawalDelayer Smart Contract
@ -411,6 +412,7 @@ func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents,
} }
deposit.Owner = ethCommon.BytesToAddress(vLog.Topics[1].Bytes()) deposit.Owner = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
deposit.Token = ethCommon.BytesToAddress(vLog.Topics[2].Bytes()) deposit.Token = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
deposit.TxHash = vLog.TxHash
wdelayerEvents.Deposit = append(wdelayerEvents.Deposit, deposit) wdelayerEvents.Deposit = append(wdelayerEvents.Deposit, deposit)
case logWDelayerWithdraw: case logWDelayerWithdraw:

+ 1
- 1
go.mod

@ -15,7 +15,7 @@ require (
github.com/iden3/go-iden3-crypto v0.0.6-0.20201016142444-94e92e88fb4e github.com/iden3/go-iden3-crypto v0.0.6-0.20201016142444-94e92e88fb4e
github.com/iden3/go-merkletree v0.0.0-20201103115630-ad30c8309b44 github.com/iden3/go-merkletree v0.0.0-20201103115630-ad30c8309b44
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/jmoiron/sqlx v1.2.0
github.com/jmoiron/sqlx v1.2.1-0.20200615141059-0794cb1f47ee
github.com/joho/godotenv v1.3.0 github.com/joho/godotenv v1.3.0
github.com/lib/pq v1.8.0 github.com/lib/pq v1.8.0
github.com/mattn/go-sqlite3 v2.0.3+incompatible github.com/mattn/go-sqlite3 v2.0.3+incompatible

+ 2
- 0
go.sum

@ -343,6 +343,8 @@ github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/jmoiron/sqlx v1.2.1-0.20200615141059-0794cb1f47ee h1:59lyMGvZusByi7Rvctn8cxdVAjhiOnqCv3G5DrYApYQ=
github.com/jmoiron/sqlx v1.2.1-0.20200615141059-0794cb1f47ee/go.mod h1:ClpsPFzLpSBl7MvJ+BhV0JHz4vmKRBarpvZ9644v9Oo=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=

+ 33
- 5
synchronizer/synchronizer.go

@ -213,17 +213,30 @@ func (s *Synchronizer) Sync2(ctx context.Context, lastSavedBlock *common.Block)
} }
// Get data from the WithdrawalDelayer contract // Get data from the WithdrawalDelayer contract
wdelayerData, err := s.wdelayerSync(ethBlock)
wDelayerData, err := s.wdelayerSync(ethBlock)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
for i := range rollupData.Withdrawals {
withdrawal := &rollupData.Withdrawals[i]
if !withdrawal.InstantWithdraw {
wDelayerTransfer, ok := wDelayerData.DepositsByTxHash[withdrawal.TxHash]
if !ok {
return nil, nil, fmt.Errorf("WDelayer deposit corresponding to " +
"non-instant rollup withdrawal not found")
}
withdrawal.Owner = wDelayerTransfer.Owner
withdrawal.Token = wDelayerTransfer.Token
}
}
// Group all the block data into the structs to save into HistoryDB // Group all the block data into the structs to save into HistoryDB
blockData := common.BlockData{ blockData := common.BlockData{
Block: *ethBlock, Block: *ethBlock,
Rollup: *rollupData, Rollup: *rollupData,
Auction: *auctionData, Auction: *auctionData,
WDelayer: *wdelayerData,
WDelayer: *wDelayerData,
} }
// log.Debugw("Sync()", "block", blockData) // log.Debugw("Sync()", "block", blockData)
@ -481,7 +494,6 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e
} }
// Get Batch information // Get Batch information
// fmt.Printf("DBG: %#v\n", forgeBatchArgs.FeeIdxCoordinator)
batch := common.Batch{ batch := common.Batch{
BatchNum: batchNum, BatchNum: batchNum,
EthBlockNum: blockNum, EthBlockNum: blockNum,
@ -547,6 +559,7 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e
Idx: common.Idx(evtWithdraw.Idx), Idx: common.Idx(evtWithdraw.Idx),
NumExitRoot: common.BatchNum(evtWithdraw.NumExitRoot), NumExitRoot: common.BatchNum(evtWithdraw.NumExitRoot),
InstantWithdraw: evtWithdraw.InstantWithdraw, InstantWithdraw: evtWithdraw.InstantWithdraw,
TxHash: evtWithdraw.TxHash,
}) })
} }
@ -677,10 +690,25 @@ func (s *Synchronizer) wdelayerSync(ethBlock *common.Block) (*common.WDelayerDat
return nil, eth.ErrBlockHashMismatchEvent return nil, eth.ErrBlockHashMismatchEvent
} }
for _, evt := range wDelayerEvents.Deposit {
wDelayerData.Deposits = append(wDelayerData.Deposits, common.WDelayerTransfer{
Owner: evt.Owner,
Token: evt.Token,
Amount: evt.Amount,
})
wDelayerData.DepositsByTxHash[evt.TxHash] =
&wDelayerData.Deposits[len(wDelayerData.Deposits)-1]
}
for _, evt := range wDelayerEvents.Withdraw {
wDelayerData.Withdrawals = append(wDelayerData.Withdrawals, common.WDelayerTransfer{
Owner: evt.Owner,
Token: evt.Token,
Amount: evt.Amount,
})
}
varsUpdate := false varsUpdate := false
// TODO Deposit
// TODO Withdraw
// TODO EscapeHatchWithdrawal // TODO EscapeHatchWithdrawal
for range wDelayerEvents.EmergencyModeEnabled { for range wDelayerEvents.EmergencyModeEnabled {
s.vars.WDelayer.EmergencyMode = true s.vars.WDelayer.EmergencyMode = true

+ 37
- 18
test/ethclient.go

@ -45,6 +45,16 @@ func (w *WDelayerBlock) addTransaction(tx *types.Transaction) *types.Transaction
return tx return tx
} }
func (w *WDelayerBlock) deposit(txHash ethCommon.Hash, owner, token ethCommon.Address, amount *big.Int) {
w.Events.Deposit = append(w.Events.Deposit, eth.WDelayerEventDeposit{
Owner: owner,
Token: token,
Amount: amount,
DepositTimestamp: uint64(w.Eth.Time),
TxHash: txHash,
})
}
// 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
@ -57,6 +67,7 @@ type RollupBlock struct {
func (r *RollupBlock) addTransaction(tx *types.Transaction) *types.Transaction { func (r *RollupBlock) addTransaction(tx *types.Transaction) *types.Transaction {
txHash := tx.Hash() txHash := tx.Hash()
fmt.Printf("DBG txHash %v\n", txHash.Hex())
r.Txs[txHash] = tx r.Txs[txHash] = tx
return tx return tx
} }
@ -769,29 +780,36 @@ func (c *Client) RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenI
} }
r.State.ExitNullifierMap[numExitRoot][idx] = true r.State.ExitNullifierMap[numExitRoot][idx] = true
type data struct {
BabyPubKey *babyjub.PublicKey
TokenID uint32
NumExitRoot int64
Idx int64
Amount *big.Int
Siblings []*big.Int
InstantWithdraw bool
}
tx = r.addTransaction(newTransaction("withdrawMerkleProof", data{
BabyPubKey: babyPubKey,
TokenID: tokenID,
NumExitRoot: numExitRoot,
Idx: idx,
Amount: amount,
Siblings: siblings,
InstantWithdraw: instantWithdraw,
}))
r.Events.Withdraw = append(r.Events.Withdraw, eth.RollupEventWithdraw{ r.Events.Withdraw = append(r.Events.Withdraw, eth.RollupEventWithdraw{
Idx: uint64(idx), Idx: uint64(idx),
NumExitRoot: uint64(numExitRoot), NumExitRoot: uint64(numExitRoot),
InstantWithdraw: instantWithdraw, InstantWithdraw: instantWithdraw,
TxHash: tx.Hash(),
}) })
type data struct {
babyPubKey *babyjub.PublicKey
tokenID uint32
numExitRoot int64
idx int64
amount *big.Int
siblings []*big.Int
instantWithdraw bool
}
return r.addTransaction(newTransaction("withdrawMerkleProof", data{
babyPubKey: babyPubKey,
tokenID: tokenID,
numExitRoot: numExitRoot,
idx: idx,
amount: amount,
siblings: siblings,
instantWithdraw: instantWithdraw,
})), nil
if !instantWithdraw {
w := nextBlock.WDelayer
w.deposit(tx.Hash(), *c.addr, r.State.TokenList[int(tokenID)], amount)
}
return tx, nil
} }
type transactionData struct { type transactionData struct {
@ -804,6 +822,7 @@ func newTransaction(name string, value interface{}) *types.Transaction {
if err != nil { if err != nil {
panic(err) panic(err)
} }
fmt.Printf("DBG dataJSON: %v\n", string(data))
return types.NewTransaction(0, ethCommon.Address{}, nil, 0, nil, return types.NewTransaction(0, ethCommon.Address{}, nil, 0, nil,
data) data)
} }

+ 7
- 10
test/historydb.go

@ -372,7 +372,7 @@ func GenBids(nBids int, blocks []common.Block, coords []common.Coordinator) []co
// GenExitTree generates an exitTree (as an array of Exits) // GenExitTree generates an exitTree (as an array of Exits)
//nolint:gomnd //nolint:gomnd
func GenExitTree(n int, batches []common.Batch, accounts []common.Account) []common.ExitInfo {
func GenExitTree(n int, batches []common.Batch, accounts []common.Account, blocks []common.Block) []common.ExitInfo {
exitTree := make([]common.ExitInfo, n) exitTree := make([]common.ExitInfo, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
exitTree[i] = common.ExitInfo{ exitTree[i] = common.ExitInfo{
@ -397,17 +397,14 @@ func GenExitTree(n int, batches []common.Batch, accounts []common.Account) []com
Balance: big.NewInt(int64(i) * 1000), Balance: big.NewInt(int64(i) * 1000),
} }
if i%2 == 0 { if i%2 == 0 {
instant := new(int64)
*instant = int64(batches[(i+1)%len(batches)].BatchNum)
exitTree[i].InstantWithdrawn = instant
instant := int64(blocks[i%len(blocks)].EthBlockNum)
exitTree[i].InstantWithdrawn = &instant
} else if i%3 == 0 { } else if i%3 == 0 {
delayedReq := new(int64)
*delayedReq = int64(batches[(i+1)%len(batches)].BatchNum)
exitTree[i].DelayedWithdrawRequest = delayedReq
delayedReq := int64(blocks[i%len(blocks)].EthBlockNum)
exitTree[i].DelayedWithdrawRequest = &delayedReq
if i%9 == 0 { if i%9 == 0 {
delayed := new(int64)
*delayed = int64(batches[(i+2)%len(batches)].BatchNum)
exitTree[i].DelayedWithdrawn = delayed
delayed := int64(blocks[i%len(blocks)].EthBlockNum)
exitTree[i].DelayedWithdrawn = &delayed
} }
} }
} }

+ 4
- 4
test/til/txs.go

@ -51,7 +51,7 @@ type Context struct {
Instructions []instruction Instructions []instruction
userNames []string userNames []string
Users map[string]*User // Name -> *User Users map[string]*User // Name -> *User
usersByIdx map[int]*User
UsersByIdx map[int]*User
accountsByIdx map[int]*Account accountsByIdx map[int]*Account
LastRegisteredTokenID common.TokenID LastRegisteredTokenID common.TokenID
l1CreatedAccounts map[string]*Account // (Name, TokenID) -> *Account l1CreatedAccounts map[string]*Account // (Name, TokenID) -> *Account
@ -81,7 +81,7 @@ func NewContext(rollupConstMaxL1UserTx int) *Context {
return &Context{ return &Context{
Users: make(map[string]*User), Users: make(map[string]*User),
l1CreatedAccounts: make(map[string]*Account), l1CreatedAccounts: make(map[string]*Account),
usersByIdx: make(map[int]*User),
UsersByIdx: make(map[int]*User),
accountsByIdx: make(map[int]*Account), accountsByIdx: make(map[int]*Account),
LastRegisteredTokenID: 0, LastRegisteredTokenID: 0,
@ -393,7 +393,7 @@ func (tc *Context) calculateIdxForL1Txs(isCoordinatorTxs bool, txs []L1Tx) error
} }
tc.l1CreatedAccounts[idxTokenIDToString(tx.fromIdxName, tx.L1Tx.TokenID)] = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] tc.l1CreatedAccounts[idxTokenIDToString(tx.fromIdxName, tx.L1Tx.TokenID)] = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID]
tc.accountsByIdx[tc.idx] = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] tc.accountsByIdx[tc.idx] = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID]
tc.usersByIdx[tc.idx] = tc.Users[tx.fromIdxName]
tc.UsersByIdx[tc.idx] = tc.Users[tx.fromIdxName]
tc.idx++ tc.idx++
} }
if isCoordinatorTxs { if isCoordinatorTxs {
@ -745,7 +745,7 @@ func (tc *Context) FillBlocksExtra(blocks []common.BlockData, cfg *ConfigExtra)
tx := &l1Txs[k] tx := &l1Txs[k]
if tx.Type == common.TxTypeCreateAccountDeposit || if tx.Type == common.TxTypeCreateAccountDeposit ||
tx.Type == common.TxTypeCreateAccountDepositTransfer { tx.Type == common.TxTypeCreateAccountDepositTransfer {
user, ok := tc.usersByIdx[tc.extra.idx]
user, ok := tc.UsersByIdx[tc.extra.idx]
if !ok { if !ok {
return fmt.Errorf("Created account with idx: %v not found", tc.extra.idx) return fmt.Errorf("Created account with idx: %v not found", tc.extra.idx)
} }

Loading…
Cancel
Save