diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6b59ae9..2de5849 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,4 +23,4 @@ jobs: POSTGRES_PASS: ${{ secrets.POSTGRES_PASS }} ETHCLIENT_DIAL_URL: ${{ secrets.ETHCLIENT_DIAL_URL }} GOARCH: ${{ matrix.goarch }} - run: go test ./... -v + run: go test -p 1 ./... diff --git a/README.md b/README.md index df7cfd1..1d4fd68 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,13 @@ POSTGRES_PASS=yourpasswordhere; sudo docker run --rm --name hermez-db-test -p 54 - Then, run the tests with the password as env var ``` -POSTGRES_PASS=yourpasswordhere ETHCLIENT_DIAL_URL=yourethereumurlhere go test ./... +POSTGRES_PASS=yourpasswordhere ETHCLIENT_DIAL_URL=yourethereumurlhere go test -p 1 ./... ``` +NOTE: `-p 1` forces execution of package test in serial. Otherwise they may be +executed in paralel and the test may find unexpected entries in the SQL +databse because it's shared among all tests. + ## Lint - Install [golangci-lint](https://golangci-lint.run) diff --git a/api/api_test.go b/api/api_test.go index 1c71ac4..26d1493 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -82,6 +82,11 @@ func TestMain(m *testing.M) { if err != nil { panic(err) } + // Reset DB + err = hdb.Reorg(-1) + if err != nil { + panic(err) + } dir, err := ioutil.TempDir("", "tmpdb") if err != nil { panic(err) @@ -94,6 +99,7 @@ func TestMain(m *testing.M) { if err != nil { panic(err) } + test.CleanL2DB(l2db.DB()) // Init API api := gin.Default() if err := SetAPIEndpoints( diff --git a/common/batch.go b/common/batch.go index e8baf01..5ba7953 100644 --- a/common/batch.go +++ b/common/batch.go @@ -8,7 +8,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" ) -const batchNumBytesLen = 4 +const batchNumBytesLen = 8 // Batch is a struct that represents Hermez network batch type Batch struct { @@ -24,20 +24,20 @@ type Batch struct { } // BatchNum identifies a batch -type BatchNum uint32 +type BatchNum int64 // Bytes returns a byte array of length 4 representing the BatchNum func (bn BatchNum) Bytes() []byte { - var batchNumBytes [4]byte - binary.LittleEndian.PutUint32(batchNumBytes[:], uint32(bn)) + var batchNumBytes [batchNumBytesLen]byte + binary.BigEndian.PutUint64(batchNumBytes[:], uint64(bn)) return batchNumBytes[:] } // BatchNumFromBytes returns BatchNum from a []byte func BatchNumFromBytes(b []byte) (BatchNum, error) { if len(b) != batchNumBytesLen { - return 0, fmt.Errorf("can not parse BatchNumFromBytes, bytes len %d, expected 4", len(b)) + return 0, fmt.Errorf("can not parse BatchNumFromBytes, bytes len %d, expected %d", len(b), batchNumBytesLen) } - batchNum := binary.LittleEndian.Uint32(b[:4]) + batchNum := binary.BigEndian.Uint64(b[:batchNumBytesLen]) return BatchNum(batchNum), nil } diff --git a/common/coordinator.go b/common/coordinator.go index cbc841c..c49051d 100644 --- a/common/coordinator.go +++ b/common/coordinator.go @@ -7,8 +7,8 @@ import ( // Coordinator represents a Hermez network coordinator who wins an auction for an specific slot // WARNING: this is strongly based on the previous implementation, once the new spec is done, this may change a lot. type Coordinator struct { - EthBlockNum int64 // block in which the coordinator was registered - Forger ethCommon.Address // address of the forger - Withdraw ethCommon.Address // address of the withdraw - URL string // URL of the coordinators API + Forger ethCommon.Address `meddler:"forger_addr"` // address of the forger + EthBlockNum int64 `meddler:"eth_block_num"` // block in which the coordinator was registered + WithdrawAddr ethCommon.Address `meddler:"withdraw_addr"` // address of the withdraw + URL string `meddler:"url"` // URL of the coordinators API } diff --git a/common/exittree.go b/common/exittree.go index e657c73..f433c50 100644 --- a/common/exittree.go +++ b/common/exittree.go @@ -8,8 +8,19 @@ import ( // ExitInfo represents the ExitTree Leaf data type ExitInfo struct { - AccountIdx Idx - MerkleProof *merkletree.CircomVerifierProof - Balance *big.Int - Nullifier *big.Int + BatchNum BatchNum `meddler:"batch_num"` + AccountIdx Idx `meddler:"account_idx"` + MerkleProof *merkletree.CircomVerifierProof `meddler:"merkle_proof,json"` + Balance *big.Int `meddler:"balance,bigint"` + // InstantWithdrawn is the ethBlockNum in which the exit is withdrawn + // instantly. nil means this hasn't happened. + InstantWithdrawn *int64 `meddler:"instant_withdrawn"` + // DelayedWithdrawRequest is the ethBlockNum in which the exit is + // requested to be withdrawn from the delayedWithdrawn smart contract. + // nil means this hasn't happened. + DelayedWithdrawRequest *int64 `meddler:"delayed_withdraw_request"` + // DelayedWithdrawn is the ethBlockNum in which the exit is withdrawn + // from the delayedWithdrawn smart contract. nil means this hasn't + // happened. + DelayedWithdrawn *int64 `meddler:"delayed_withdrawn"` } diff --git a/common/tx.go b/common/tx.go index 94bc97e..de70726 100644 --- a/common/tx.go +++ b/common/tx.go @@ -66,3 +66,24 @@ type Tx struct { FeeUSD float64 `meddler:"fee_usd,zeroisnull"` Nonce Nonce `meddler:"nonce,zeroisnull"` } + +// L1Tx returns a *L1Tx from the Tx +func (tx *Tx) L1Tx() *L1Tx { + l1Tx := &L1Tx{ + TxID: tx.TxID, + ToForgeL1TxsNum: tx.ToForgeL1TxsNum, + Position: tx.Position, + UserOrigin: tx.UserOrigin, + FromIdx: tx.FromIdx, + FromEthAddr: tx.FromEthAddr, + FromBJJ: tx.FromBJJ, + ToIdx: tx.ToIdx, + TokenID: tx.TokenID, + Amount: tx.Amount, + LoadAmount: tx.LoadAmount, + EthBlockNum: tx.EthBlockNum, + Type: tx.Type, + BatchNum: tx.BatchNum, + } + return l1Tx +} diff --git a/db/historydb/historydb.go b/db/historydb/historydb.go index 4946ac9..5108e51 100644 --- a/db/historydb/historydb.go +++ b/db/historydb/historydb.go @@ -26,6 +26,36 @@ type HistoryDB struct { db *sqlx.DB } +// BlockData contains the information of a Block +type BlockData struct { + block *common.Block + // Rollup + // L1UserTxs that were submitted in the block + L1UserTxs []common.L1Tx + Batches []BatchData + RegisteredTokens []common.Token + RollupVars *common.RollupVars + // Auction + Bids []common.Bid + Coordinators []common.Coordinator + AuctionVars *common.AuctionVars + // WithdrawalDelayer + // TODO: enable when common.WithdrawalDelayerVars is Merged from Synchronizer PR + // WithdrawalDelayerVars *common.WithdrawalDelayerVars +} + +// BatchData contains the information of a Batch +type BatchData struct { + // L1UserTxs that were forged in the batch + L1Batch bool // TODO: Remove once Batch.ForgeL1TxsNum is a pointer + L1UserTxs []common.L1Tx + L1CoordinatorTxs []common.L1Tx + L2Txs []common.L2Tx + CreatedAccounts []common.Account + ExitTree []common.ExitInfo + Batch *common.Batch +} + // NewHistoryDB initialize the DB func NewHistoryDB(port int, host, user, password, dbname string) (*HistoryDB, error) { // Connect to DB @@ -52,14 +82,19 @@ func NewHistoryDB(port int, host, user, password, dbname string) (*HistoryDB, er } // AddBlock insert a block into the DB -func (hdb *HistoryDB) AddBlock(block *common.Block) error { - return meddler.Insert(hdb.db, "block", block) +func (hdb *HistoryDB) AddBlock(block *common.Block) error { return hdb.addBlock(hdb.db, block) } +func (hdb *HistoryDB) addBlock(d meddler.DB, block *common.Block) error { + return meddler.Insert(d, "block", block) } // AddBlocks inserts blocks into the DB func (hdb *HistoryDB) AddBlocks(blocks []common.Block) error { + return hdb.addBlocks(hdb.db, blocks) +} + +func (hdb *HistoryDB) addBlocks(d meddler.DB, blocks []common.Block) error { return db.BulkInsert( - hdb.db, + d, `INSERT INTO block ( eth_block_num, timestamp, @@ -84,7 +119,7 @@ func (hdb *HistoryDB) GetBlocks(from, to int64) ([]*common.Block, error) { var blocks []*common.Block err := meddler.QueryAll( hdb.db, &blocks, - "SELECT * FROM block WHERE $1 <= eth_block_num AND eth_block_num < $2", + "SELECT * FROM block WHERE $1 <= eth_block_num AND eth_block_num < $2;", from, to, ) return blocks, err @@ -99,10 +134,19 @@ func (hdb *HistoryDB) GetLastBlock() (*common.Block, error) { return block, err } +// AddBatch insert a Batch into the DB +func (hdb *HistoryDB) AddBatch(batch *common.Batch) error { return hdb.addBatch(hdb.db, batch) } +func (hdb *HistoryDB) addBatch(d meddler.DB, batch *common.Batch) error { + return meddler.Insert(d, "batch", batch) +} + // AddBatches insert Bids into the DB func (hdb *HistoryDB) AddBatches(batches []common.Batch) error { + return hdb.addBatches(hdb.db, batches) +} +func (hdb *HistoryDB) addBatches(d meddler.DB, batches []common.Batch) error { return db.BulkInsert( - hdb.db, + d, `INSERT INTO batch ( batch_num, eth_block_num, @@ -123,7 +167,7 @@ func (hdb *HistoryDB) GetBatches(from, to common.BatchNum) ([]*common.Batch, err var batches []*common.Batch err := meddler.QueryAll( hdb.db, &batches, - "SELECT * FROM batch WHERE $1 <= batch_num AND batch_num < $2", + "SELECT * FROM batch WHERE $1 <= batch_num AND batch_num < $2;", from, to, ) return batches, err @@ -144,29 +188,17 @@ func (hdb *HistoryDB) GetLastL1TxsNum() (*int64, error) { return lastL1TxsNum, row.Scan(&lastL1TxsNum) } -// Reorg deletes all the information that was added into the DB after the lastValidBlock +// Reorg deletes all the information that was added into the DB after the +// lastValidBlock. If lastValidBlock is negative, all block information is +// deleted. func (hdb *HistoryDB) Reorg(lastValidBlock int64) error { - _, err := hdb.db.Exec("DELETE FROM block WHERE eth_block_num > $1;", lastValidBlock) - return err -} - -// SyncRollup stores all the data that can be changed / added on a block in the Rollup SC -func (hdb *HistoryDB) SyncRollup( - blockNum uint64, - l1txs []common.L1Tx, - l2txs []common.L2Tx, - registeredAccounts []common.Account, - exitTree common.ExitInfo, - withdrawals common.ExitInfo, - registeredTokens []common.Token, - batches []common.Batch, - vars *common.RollupVars, -) error { - // TODO: make all in a single DB commit - if err := hdb.AddBatches(batches); err != nil { - return err + var err error + if lastValidBlock < 0 { + _, err = hdb.db.Exec("DELETE FROM block;") + } else { + _, err = hdb.db.Exec("DELETE FROM block WHERE eth_block_num > $1;", lastValidBlock) } - return nil + return err } // SyncPoD stores all the data that can be changed / added on a block in the PoD SC @@ -179,12 +211,13 @@ func (hdb *HistoryDB) SyncPoD( return nil } -// addBids insert Bids into the DB -func (hdb *HistoryDB) addBids(bids []common.Bid) error { +// AddBids insert Bids into the DB +func (hdb *HistoryDB) AddBids(bids []common.Bid) error { return hdb.addBids(hdb.db, bids) } +func (hdb *HistoryDB) addBids(d meddler.DB, bids []common.Bid) error { // TODO: check the coordinator info return db.BulkInsert( - hdb.db, - "INSERT INTO bid (slot_num, forger_addr, bid_value, eth_block_num) VALUES %s", + d, + "INSERT INTO bid (slot_num, forger_addr, bid_value, eth_block_num) VALUES %s;", bids[:], ) } @@ -199,15 +232,41 @@ func (hdb *HistoryDB) GetBids() ([]*common.Bid, error) { return bids, err } +// AddCoordinators insert Coordinators into the DB +func (hdb *HistoryDB) AddCoordinators(coordinators []common.Coordinator) error { + return hdb.addCoordinators(hdb.db, coordinators) +} +func (hdb *HistoryDB) addCoordinators(d meddler.DB, coordinators []common.Coordinator) error { + return db.BulkInsert( + d, + "INSERT INTO coordinator (forger_addr, eth_block_num, withdraw_addr, url) VALUES %s;", + coordinators[:], + ) +} + +// AddExitTree insert Exit tree into the DB +func (hdb *HistoryDB) AddExitTree(exitTree []common.ExitInfo) error { + return hdb.addExitTree(hdb.db, exitTree) +} +func (hdb *HistoryDB) addExitTree(d meddler.DB, exitTree []common.ExitInfo) error { + return db.BulkInsert( + d, + "INSERT INTO exit_tree (batch_num, account_idx, merkle_proof, balance, "+ + "instant_withdrawn, delayed_withdraw_request, delayed_withdrawn) VALUES %s;", + exitTree[:], + ) +} + // AddToken insert a token into the DB func (hdb *HistoryDB) AddToken(token *common.Token) error { return meddler.Insert(hdb.db, "token", token) } // AddTokens insert tokens into the DB -func (hdb *HistoryDB) AddTokens(tokens []common.Token) error { +func (hdb *HistoryDB) AddTokens(tokens []common.Token) error { return hdb.addTokens(hdb.db, tokens) } +func (hdb *HistoryDB) addTokens(d meddler.DB, tokens []common.Token) error { return db.BulkInsert( - hdb.db, + d, `INSERT INTO token ( token_id, eth_block_num, @@ -243,8 +302,11 @@ func (hdb *HistoryDB) GetTokens() ([]*common.Token, error) { // AddAccounts insert accounts into the DB func (hdb *HistoryDB) AddAccounts(accounts []common.Account) error { + return hdb.addAccounts(hdb.db, accounts) +} +func (hdb *HistoryDB) addAccounts(d meddler.DB, accounts []common.Account) error { return db.BulkInsert( - hdb.db, + d, `INSERT INTO account ( idx, token_id, @@ -267,27 +329,30 @@ func (hdb *HistoryDB) GetAccounts() ([]*common.Account, error) { } // AddL1Txs inserts L1 txs to the DB -func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error { +func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error { return hdb.addL1Txs(hdb.db, l1txs) } +func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error { txs := []common.Tx{} for _, tx := range l1txs { - txs = append(txs, *tx.Tx()) + txs = append(txs, *(tx.Tx())) } - return hdb.AddTxs(txs) + return hdb.addTxs(d, txs) } // AddL2Txs inserts L2 txs to the DB -func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error { +func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error { return hdb.addL2Txs(hdb.db, l2txs) } +func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error { txs := []common.Tx{} for _, tx := range l2txs { - txs = append(txs, *tx.Tx()) + txs = append(txs, *(tx.Tx())) } - return hdb.AddTxs(txs) + return hdb.addTxs(d, txs) } // AddTxs insert L1 txs into the DB -func (hdb *HistoryDB) AddTxs(txs []common.Tx) error { +func (hdb *HistoryDB) AddTxs(txs []common.Tx) error { return hdb.addTxs(hdb.db, txs) } +func (hdb *HistoryDB) addTxs(d meddler.DB, txs []common.Tx) error { return db.BulkInsert( - hdb.db, + d, `INSERT INTO tx ( is_l1, id, @@ -316,6 +381,16 @@ func (hdb *HistoryDB) AddTxs(txs []common.Tx) error { ) } +// SetBatchNumL1UserTxs sets the batchNum in all the L1UserTxs with toForgeL1TxsNum. +func (hdb *HistoryDB) SetBatchNumL1UserTxs(toForgeL1TxsNum, batchNum int64) error { + return hdb.setBatchNumL1UserTxs(hdb.db, toForgeL1TxsNum, batchNum) +} +func (hdb *HistoryDB) setBatchNumL1UserTxs(d meddler.DB, toForgeL1TxsNum, batchNum int64) error { + _, err := d.Exec("UPDATE tx SET batch_num = $1 WHERE to_forge_l1_txs_num = $2 AND is_l1 = TRUE AND user_origin = TRUE;", + batchNum, toForgeL1TxsNum) + return err +} + // GetTxs returns a list of txs from the DB func (hdb *HistoryDB) GetTxs() ([]*common.Tx, error) { var txs []*common.Tx @@ -409,7 +484,7 @@ func (hdb *HistoryDB) GetHistoryTxs( queryStr += "ORDER BY (batch_num, position) ASC NULLS LAST " queryStr += fmt.Sprintf("OFFSET %d ", *offset) } - queryStr += fmt.Sprintf("LIMIT %d ", *limit) + queryStr += fmt.Sprintf("LIMIT %d;", *limit) query = hdb.db.Rebind(queryStr) // log.Debug(query) txs := []*HistoryTx{} @@ -438,6 +513,128 @@ func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) { ) } +// GetL1UserTxs gets L1 User Txs to be forged in a batch that will create an account +// TODO: This is currently not used. Figure out if it should be used somewhere or removed. +func (hdb *HistoryDB) GetL1UserTxs(toForgeL1TxsNum int64) ([]*common.Tx, error) { + var txs []*common.Tx + err := meddler.QueryAll( + hdb.db, &txs, + "SELECT * FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;", + toForgeL1TxsNum, + ) + return txs, err +} + +// TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value. + +// GetLastTxsPosition for a given to_forge_l1_txs_num +func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) { + row := hdb.db.QueryRow("SELECT MAX(position) FROM tx WHERE to_forge_l1_txs_num = $1;", toForgeL1TxsNum) + var lastL1TxsPosition int + return lastL1TxsPosition, row.Scan(&lastL1TxsPosition) +} + +// AddBlockSCData stores all the information of a block retrieved by the Synchronizer +func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) { + txn, err := hdb.db.Begin() + if err != nil { + return err + } + defer func() { + if err != nil { + err = txn.Rollback() + } + }() + + // Add block + err = hdb.addBlock(txn, blockData.block) + if err != nil { + return err + } + + // Add l1 Txs + if len(blockData.L1UserTxs) > 0 { + err = hdb.addL1Txs(txn, blockData.L1UserTxs) + if err != nil { + return err + } + } + + // Add Tokens + if len(blockData.RegisteredTokens) > 0 { + err = hdb.addTokens(txn, blockData.RegisteredTokens) + if err != nil { + return err + } + } + + // Add Bids + if len(blockData.Bids) > 0 { + err = hdb.addBids(txn, blockData.Bids) + if err != nil { + return err + } + } + + // Add Coordinators + if len(blockData.Coordinators) > 0 { + err = hdb.addCoordinators(txn, blockData.Coordinators) + if err != nil { + return err + } + } + + // Add Batches + for _, batch := range blockData.Batches { + if batch.L1Batch { + err = hdb.setBatchNumL1UserTxs(txn, batch.Batch.ForgeL1TxsNum, int64(batch.Batch.BatchNum)) + if err != nil { + return err + } + if len(batch.L1CoordinatorTxs) > 0 { + err = hdb.addL1Txs(txn, batch.L1CoordinatorTxs) + if err != nil { + return err + } + } + } + + // Add l2 Txs + if len(batch.L2Txs) > 0 { + err = hdb.addL2Txs(txn, batch.L2Txs) + if err != nil { + return err + } + } + + // Add accounts + if len(batch.CreatedAccounts) > 0 { + err = hdb.addAccounts(txn, batch.CreatedAccounts) + if err != nil { + return err + } + } + + // Add exit tree + if len(batch.ExitTree) > 0 { + err = hdb.addExitTree(txn, batch.ExitTree) + if err != nil { + return err + } + } + + // Add Batch + err = hdb.addBatch(txn, batch.Batch) + if err != nil { + return err + } + + // TODO: INSERT CONTRACTS VARS + } + + return txn.Commit() +} + // Close frees the resources used by HistoryDB func (hdb *HistoryDB) Close() error { return hdb.db.Close() diff --git a/db/historydb/historydb_test.go b/db/historydb/historydb_test.go index 5222af7..0867df1 100644 --- a/db/historydb/historydb_test.go +++ b/db/historydb/historydb_test.go @@ -119,10 +119,12 @@ func TestBids(t *testing.T) { // Generate fake coordinators const nCoords = 5 coords := test.GenCoordinators(nCoords, blocks) + err := historyDB.AddCoordinators(coords) + assert.NoError(t, err) // Generate fake bids const nBids = 20 bids := test.GenBids(nBids, blocks, coords) - err := historyDB.addBids(bids) + err = historyDB.AddBids(bids) assert.NoError(t, err) // Fetch bids fetchedBids, err := historyDB.GetBids() @@ -302,6 +304,35 @@ func TestTxs(t *testing.T) { l2txs[0].Nonce = 0 err = historyDB.AddL2Txs(l2txs) assert.Error(t, err) + // Test helper functions for Synchronizer + txs, err := historyDB.GetL1UserTxs(2) + assert.NoError(t, err) + assert.NotZero(t, len(txs)) + position, err := historyDB.GetLastTxsPosition(2) + assert.NoError(t, err) + assert.Equal(t, 22, position) + // Test Update L1 TX Batch_num + assert.Equal(t, common.BatchNum(0), txs[0].BatchNum) + txs[0].BatchNum = common.BatchNum(1) + // err = historyDB.UpdateTxsBatchNum(txs) + err = historyDB.SetBatchNumL1UserTxs(2, 1) + assert.NoError(t, err) + txs, err = historyDB.GetL1UserTxs(2) + assert.NoError(t, err) + assert.NotZero(t, len(txs)) + assert.Equal(t, common.BatchNum(1), txs[0].BatchNum) +} + +func TestExitTree(t *testing.T) { + nBatches := 17 + blocks := setTestBlocks(0, 10) + batches := test.GenBatches(nBatches, blocks) + err := historyDB.AddBatches(batches) + assert.NoError(t, err) + + exitTree := test.GenExitTree(nBatches) + err = historyDB.AddExitTree(exitTree) + assert.NoError(t, err) } // setTestBlocks WARNING: this will delete the blocks and recreate them @@ -317,5 +348,5 @@ func setTestBlocks(from, to int64) []common.Block { } func cleanHistoryDB() error { - return historyDB.Reorg(0) + return historyDB.Reorg(-1) } diff --git a/db/historydb/migrations/001_init.sql b/db/historydb/migrations/001_init.sql index 16307e3..bbe8704 100644 --- a/db/historydb/migrations/001_init.sql +++ b/db/historydb/migrations/001_init.sql @@ -27,11 +27,12 @@ CREATE TABLE batch ( CREATE TABLE exit_tree ( batch_num BIGINT REFERENCES batch (batch_num) ON DELETE CASCADE, - withdrawn BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL, account_idx BIGINT, merkle_proof BYTEA NOT NULL, - balance NUMERIC NOT NULL, - nullifier 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, PRIMARY KEY (batch_num, account_idx) ); @@ -205,4 +206,4 @@ DROP TABLE bid; DROP TABLE exit_tree; DROP TABLE batch; DROP TABLE coordinator; -DROP TABLE block; \ No newline at end of file +DROP TABLE block; diff --git a/db/l2db/l2db.go b/db/l2db/l2db.go index b6dc985..ac5a585 100644 --- a/db/l2db/l2db.go +++ b/db/l2db/l2db.go @@ -173,7 +173,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. // The state of the affected txs will be changed from Pending -> Invalid -func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account, batchNum common.BatchNum) error { +func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account, batchNum common.BatchNum) (err error) { txn, err := l2db.db.Begin() if err != nil { return err @@ -203,7 +203,7 @@ func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account, batchNum common. } // UpdateTxValue updates the absolute fee and value of txs given a token list that include their price in USD -func (l2db *L2DB) UpdateTxValue(tokens []common.Token) error { +func (l2db *L2DB) UpdateTxValue(tokens []common.Token) (err error) { // WARNING: this is very slow and should be optimized txn, err := l2db.db.Begin() if err != nil { @@ -252,7 +252,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 // 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) error { +func (l2db *L2DB) Purge(currentBatchNum common.BatchNum) (err error) { txn, err := l2db.db.Begin() if err != nil { return err diff --git a/db/statedb/txprocessors.go b/db/statedb/txprocessors.go index f7d48ef..724e01c 100644 --- a/db/statedb/txprocessors.go +++ b/db/statedb/txprocessors.go @@ -8,7 +8,6 @@ import ( "github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/log" "github.com/iden3/go-iden3-crypto/babyjub" - "github.com/iden3/go-iden3-crypto/poseidon" "github.com/iden3/go-merkletree" "github.com/iden3/go-merkletree/db" "github.com/iden3/go-merkletree/db/memory" @@ -142,24 +141,10 @@ func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordin if err != nil { return nil, nil, err } - // 1. compute nullifier - exitAccStateValue, err := exitAccount.HashValue() - if err != nil { - return nil, nil, err - } - nullifier, err := poseidon.Hash([]*big.Int{ - exitAccStateValue, - big.NewInt(int64(s.currentBatch)), - exitTree.Root().BigInt(), - }) - if err != nil { - return nil, nil, err - } - // 2. generate common.ExitInfo + // 1. generate common.ExitInfo ei := &common.ExitInfo{ AccountIdx: exitIdx, MerkleProof: p, - Nullifier: nullifier, Balance: exitAccount.Balance, } exitInfos = append(exitInfos, ei) diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index 5bd63b7..fdc4d21 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -501,9 +501,9 @@ func (s *Synchronizer) auctionSync(blockNum int64) (*auctionData, error) { // Get Coordinators for _, eNewCoordinator := range auctionEvents.NewCoordinator { coordinator := &common.Coordinator{ - Forger: eNewCoordinator.ForgerAddress, - Withdraw: eNewCoordinator.WithdrawalAddress, - URL: eNewCoordinator.URL, + Forger: eNewCoordinator.ForgerAddress, + WithdrawAddr: eNewCoordinator.WithdrawalAddress, + URL: eNewCoordinator.URL, } auctionData.coordinators = append(auctionData.coordinators, coordinator) } @@ -525,9 +525,9 @@ func (s *Synchronizer) auctionSync(blockNum int64) (*auctionData, error) { // Get Coordinators from updates for _, eCoordinatorUpdated := range auctionEvents.CoordinatorUpdated { coordinator := &common.Coordinator{ - Forger: eCoordinatorUpdated.ForgerAddress, - Withdraw: eCoordinatorUpdated.WithdrawalAddress, - URL: eCoordinatorUpdated.URL, + Forger: eCoordinatorUpdated.ForgerAddress, + WithdrawAddr: eCoordinatorUpdated.WithdrawalAddress, + URL: eCoordinatorUpdated.URL, } auctionData.coordinators = append(auctionData.coordinators, coordinator) } diff --git a/test/historydb.go b/test/historydb.go index 2c2cd80..001d39a 100644 --- a/test/historydb.go +++ b/test/historydb.go @@ -10,6 +10,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" "github.com/iden3/go-iden3-crypto/babyjub" + "github.com/iden3/go-merkletree" ) // WARNING: the generators in this file doesn't necessary follow the protocol @@ -142,7 +143,7 @@ func GenL1Txs( continue } if i < nUserTxs { - var from, to common.Account + var from, to *common.Account var err error if i%2 == 0 { from, err = randomAccount(i, true, userAddr, accounts) @@ -216,7 +217,7 @@ func GenL2Txs( Type: randomTxType(i), } if i < nUserTxs { - var from, to common.Account + var from, to *common.Account var err error if i%2 == 0 { from, err = randomAccount(i, true, userAddr, accounts) @@ -262,10 +263,10 @@ func GenCoordinators(nCoords int, blocks []common.Block) []common.Coordinator { coords := []common.Coordinator{} for i := 0; i < nCoords; i++ { coords = append(coords, common.Coordinator{ - EthBlockNum: blocks[i%len(blocks)].EthBlockNum, - Forger: ethCommon.BigToAddress(big.NewInt(int64(i))), - Withdraw: ethCommon.BigToAddress(big.NewInt(int64(i))), - URL: "https://foo.bar", + EthBlockNum: blocks[i%len(blocks)].EthBlockNum, + Forger: ethCommon.BigToAddress(big.NewInt(int64(i))), + WithdrawAddr: ethCommon.BigToAddress(big.NewInt(int64(i))), + URL: "https://foo.bar", }) } return coords @@ -285,21 +286,51 @@ func GenBids(nBids int, blocks []common.Block, coords []common.Coordinator) []co return bids } -func randomAccount(seed int, userAccount bool, userAddr *ethCommon.Address, accs []common.Account) (common.Account, error) { +// GenExitTree generates an exitTree (as an array of Exits) +//nolint:gomnd +func GenExitTree(n int) []common.ExitInfo { + exitTree := make([]common.ExitInfo, n) + for i := 0; i < n; i++ { + exitTree[i] = common.ExitInfo{ + BatchNum: common.BatchNum(i + 1), + InstantWithdrawn: nil, + DelayedWithdrawRequest: nil, + DelayedWithdrawn: nil, + AccountIdx: common.Idx(i * 10), + MerkleProof: &merkletree.CircomVerifierProof{ + Root: &merkletree.Hash{byte(i), byte(i + 1)}, + Siblings: []*big.Int{ + big.NewInt(int64(i) * 10), + big.NewInt(int64(i)*100 + 1), + big.NewInt(int64(i)*1000 + 2)}, + OldKey: &merkletree.Hash{byte(i * 1), byte(i*1 + 1)}, + OldValue: &merkletree.Hash{byte(i * 2), byte(i*2 + 1)}, + IsOld0: i%2 == 0, + Key: &merkletree.Hash{byte(i * 3), byte(i*3 + 1)}, + Value: &merkletree.Hash{byte(i * 4), byte(i*4 + 1)}, + Fnc: i % 2, + }, + Balance: big.NewInt(int64(i) * 1000), + } + } + return exitTree +} + +func randomAccount(seed int, userAccount bool, userAddr *ethCommon.Address, accs []common.Account) (*common.Account, error) { i := seed % len(accs) firstI := i for { acc := accs[i] if userAccount && *userAddr == acc.EthAddr { - return acc, nil + return &acc, nil } if !userAccount && (userAddr == nil || *userAddr != acc.EthAddr) { - return acc, nil + return &acc, nil } i++ i = i % len(accs) if i == firstI { - return acc, errors.New("Didnt found any account matchinng the criteria") + return &acc, errors.New("Didnt found any account matchinng the criteria") } } } diff --git a/test/l2db.go b/test/l2db.go index 47f6227..5c3d3f8 100644 --- a/test/l2db.go +++ b/test/l2db.go @@ -13,10 +13,10 @@ import ( // CleanL2DB deletes 'tx_pool' and 'account_creation_auth' from the given DB func CleanL2DB(db *sqlx.DB) { - if _, err := db.Exec("DELETE FROM tx_pool"); err != nil { + if _, err := db.Exec("DELETE FROM tx_pool;"); err != nil { panic(err) } - if _, err := db.Exec("DELETE FROM account_creation_auth"); err != nil { + if _, err := db.Exec("DELETE FROM account_creation_auth;"); err != nil { panic(err) } }