Update missing parts, improve til, and more

- Node
	- Updated configuration to initialize the interface to all the smart
	  contracts
- Common
	- Moved BlockData and BatchData types to common so that they can be
	  shared among: historydb, til and synchronizer
	- Remove hash.go (it was never used)
	- Remove slot.go (it was never used)
	- Remove smartcontractparams.go (it was never used, and appropriate
	  structs are defined in `eth/`)
	- Comment state / status method until requirements of this method are
	  properly defined, and move it to Synchronizer
- Synchronizer
	- Simplify `Sync` routine to only sync one block per call, and return
	  useful information.
	- Use BlockData and BatchData from common
	- Check that events belong to the expected block hash
	- In L1Batch, query L1UserTxs from HistoryDB
	- Fill ERC20 token information
	- Test AddTokens with test.Client
- HistryDB
	- Use BlockData and BatchData from common
	- Add `GetAllTokens` method
	- Uncomment and update GetL1UserTxs (with corresponding tests)
- Til
	- Rename all instances of RegisterToken to AddToken (to follow the smart
	  contract implementation naming)
	- Use BlockData and BatchData from common
		- Move testL1CoordinatorTxs and testL2Txs to a separate struct
		  from BatchData in Context
	- Start Context with BatchNum = 1 (which the protocol defines to be the
	  first batchNum)
	- In every Batch, set StateRoot and ExitRoot to a non-nil big.Int
	  (zero).
	- In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not
	  used, set it to 0; so that no *big.Int is nil.
	- In L1UserTx, don't set BatchNum, because when L1UserTxs are created
	  and obtained by the synchronizer, the BatchNum is not known yet (it's
	  a synchronizer job to set it)
	- In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
This commit is contained in:
Eduard S
2020-10-09 12:54:16 +02:00
parent 24bca9e3b0
commit 827e917fa0
23 changed files with 739 additions and 547 deletions

View File

@@ -33,49 +33,6 @@ 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
WithdrawDelayerVars *common.WithdrawDelayerVars
// 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
}
// NewBatchData creates an empty BatchData with the slices initialized.
func NewBatchData() *BatchData {
return &BatchData{
L1Batch: false,
L1UserTxs: make([]common.L1Tx, 0),
L1CoordinatorTxs: make([]common.L1Tx, 0),
L2Txs: make([]common.L2Tx, 0),
CreatedAccounts: make([]common.Account, 0),
ExitTree: make([]common.ExitInfo, 0),
Batch: &common.Batch{},
}
}
// NewHistoryDB initialize the DB
func NewHistoryDB(db *sqlx.DB) *HistoryDB {
return &HistoryDB{db: db}
@@ -149,19 +106,21 @@ func (hdb *HistoryDB) addBatch(d meddler.DB, batch *common.Batch) error {
USD *float64 `meddler:"usd"`
Decimals int `meddler:"decimals"`
}
query, args, err := sqlx.In(
"SELECT token_id, usd, decimals FROM token WHERE token_id IN (?)",
tokenIDs,
)
if err != nil {
return err
}
query = hdb.db.Rebind(query)
var tokenPrices []*tokenPrice
if err := meddler.QueryAll(
hdb.db, &tokenPrices, query, args...,
); err != nil {
return err
if len(tokenIDs) > 0 {
query, args, err := sqlx.In(
"SELECT token_id, usd, decimals FROM token WHERE token_id IN (?)",
tokenIDs,
)
if err != nil {
return err
}
query = hdb.db.Rebind(query)
if err := meddler.QueryAll(
hdb.db, &tokenPrices, query, args...,
); err != nil {
return err
}
}
// Calculate total collected
var total float64
@@ -209,8 +168,8 @@ func (hdb *HistoryDB) GetLastBatchNum() (common.BatchNum, error) {
return batchNum, row.Scan(&batchNum)
}
// GetLastL1TxsNum returns the greatest ForgeL1TxsNum in the DB. If there's no
// batch in the DB (nil, nil) is returned.
// GetLastL1TxsNum returns the greatest ForgeL1TxsNum in the DB from forged
// batches. If there's no batch in the DB (nil, nil) is returned.
func (hdb *HistoryDB) GetLastL1TxsNum() (*int64, error) {
row := hdb.db.QueryRow("SELECT MAX(forge_l1_txs_num) FROM batch;")
lastL1TxsNum := new(int64)
@@ -326,6 +285,16 @@ func (hdb *HistoryDB) GetToken(tokenID common.TokenID) (*TokenRead, error) {
return token, err
}
// GetAllTokens returns all tokens from the DB
func (hdb *HistoryDB) GetAllTokens() ([]TokenRead, error) {
var tokens []*TokenRead
err := meddler.QueryAll(
hdb.db, &tokens,
"SELECT * FROM token ORDER BY token_id;",
)
return db.SlicePtrsToSlice(tokens).([]TokenRead), err
}
// GetTokens returns a list of tokens from the DB
func (hdb *HistoryDB) GetTokens(ids []common.TokenID, symbols []string, name string, fromItem, limit *uint, order string) ([]TokenRead, *db.Pagination, error) {
var query string
@@ -822,17 +791,19 @@ func (hdb *HistoryDB) GetExits(
// )
// }
// // 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
// }
// GetL1UserTxs gets L1 User Txs to be forged in the L1Batch with toForgeL1TxsNum.
func (hdb *HistoryDB) GetL1UserTxs(toForgeL1TxsNum int64) ([]common.L1Tx, error) {
var txs []*common.L1Tx
err := meddler.QueryAll(
hdb.db, &txs,
`SELECT tx.id, tx.to_forge_l1_txs_num, tx.position, tx.user_origin,
tx.from_idx, tx.from_eth_addr, tx.from_bjj, tx.to_idx, tx.token_id, tx.amount,
tx.load_amount, tx.eth_block_num, tx.type, tx.batch_num
FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;`,
toForgeL1TxsNum,
)
return db.SlicePtrsToSlice(txs).([]common.L1Tx), err
}
// TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value.
@@ -843,8 +814,11 @@ func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) {
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) {
// AddBlockSCData stores all the information of a block retrieved by the
// Synchronizer. Blocks should be inserted in order, leaving no gaps because
// the pagination system of the API/DB depends on this. Within blocks, all
// items should also be in the correct order (Accounts, Tokens, Txs, etc.)
func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) {
txn, err := hdb.db.Begin()
if err != nil {
return err
@@ -859,7 +833,7 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) {
}()
// Add block
err = hdb.addBlock(txn, blockData.Block)
err = hdb.addBlock(txn, &blockData.Block)
if err != nil {
return err
}
@@ -881,8 +855,8 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) {
}
// Add Tokens
if len(blockData.RegisteredTokens) > 0 {
err = hdb.addTokens(txn, blockData.RegisteredTokens)
if len(blockData.AddedTokens) > 0 {
err = hdb.addTokens(txn, blockData.AddedTokens)
if err != nil {
return err
}
@@ -897,10 +871,11 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) {
}
// Add Batches
for _, batch := range blockData.Batches {
for i := range blockData.Batches {
batch := &blockData.Batches[i]
// Add Batch: this will trigger an update on the DB
// that will set the batch num of forged L1 txs in this batch
err = hdb.addBatch(txn, batch.Batch)
err = hdb.addBatch(txn, &batch.Batch)
if err != nil {
return err
}

View File

@@ -6,11 +6,14 @@ import (
"os"
"testing"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/common"
dbUtils "github.com/hermeznetwork/hermez-node/db"
"github.com/hermeznetwork/hermez-node/log"
"github.com/hermeznetwork/hermez-node/test"
"github.com/hermeznetwork/hermez-node/test/til"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var historyDB *HistoryDB
@@ -378,6 +381,91 @@ func TestExitTree(t *testing.T) {
assert.NoError(t, err)
}
func TestGetL1UserTxs(t *testing.T) {
require.NoError(t, cleanHistoryDB())
set := `
Type: Blockchain
AddToken(1)
AddToken(2)
AddToken(3)
CreateAccountDeposit(1) A: 10
CreateAccountDeposit(2) A: 20
CreateAccountDeposit(1) B: 5
CreateAccountDeposit(1) C: 5
CreateAccountDepositTransfer(1) D-A: 15, 10 (3)
> batchL1 // freeze open l1UserTxs queue
> batchL1 // forge current l1UserTxs queue
> block
`
tc := til.NewContext(128)
blocks, err := tc.GenerateBlocks(set)
require.Nil(t, err)
// Sanity check
require.Equal(t, 1, len(blocks))
require.Equal(t, 5, len(blocks[0].L1UserTxs))
require.Equal(t, 2, len(blocks[0].Batches))
// fmt.Printf("DBG Blocks: %+v\n", blocks)
// TODO: Move this logic to `func (tc *TestContext) GenerateBlocks(set string) ([]common.BlockData, error)`
toForgeL1TxsNum := int64(1)
for i := range blocks {
block := &blocks[i]
block.Block.EthBlockNum = int64(i)
for j := range block.AddedTokens {
token := &block.AddedTokens[j]
token.EthAddr = ethCommon.BigToAddress(big.NewInt(int64(i*len(blocks) + j)))
}
for j := range block.L1UserTxs {
l1Tx := &block.L1UserTxs[j]
l1Tx.UserOrigin = true
l1Tx.Position = j
l1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
}
}
for i := range blocks {
// fmt.Printf("DBG %+v\n", blocks[i])
// fmt.Printf("DBG Batches %+v\n", blocks[i].Batches)
// for _, l1Tx := range blocks[i].L1UserTxs {
// fmt.Printf("DBG l1UserTx %+v\n", l1Tx)
// }
err = historyDB.AddBlockSCData(&blocks[i])
require.Nil(t, err)
}
// // TODO: Use til to generate a set with some L1UserTxs
// l1Txs := []common.L1Tx{}
// l1Tx, err := common.NewL1Tx(&common.L1Tx{
// ToForgeL1TxsNum: &toForgeL1TxsNum,
// Position: 0,
// UserOrigin: true,
// FromIdx: 0,
// FromEthAddr: ethCommon.Address{}, // ethCommon.HexToAddress("0xff"),
// FromBJJ: nil,
// ToIdx: 0,
// TokenID: 1,
// Amount: big.NewInt(0),
// LoadAmount: big.NewInt(0),
// })
// require.Nil(t, err)
// l1Txs = append(l1Txs, *l1Tx)
// require.Nil(t, historyDB.AddL1Txs(l1Txs))
l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
require.Nil(t, err)
assert.Equal(t, 5, len(l1UserTxs))
assert.Equal(t, blocks[0].L1UserTxs, l1UserTxs)
// No l1UserTxs for this toForgeL1TxsNum
l1UserTxs, err = historyDB.GetL1UserTxs(2)
require.Nil(t, err)
assert.Equal(t, 0, len(l1UserTxs))
}
// setTestBlocks WARNING: this will delete the blocks and recreate them
func setTestBlocks(from, to int64) []common.Block {
if err := cleanHistoryDB(); err != nil {