Browse Source

Merge pull request #481 from hermeznetwork/feature/set-idx-new-accounts

Add idx for txs that create account
feature/sql-semaphore1
Eduard S 3 years ago
committed by GitHub
parent
commit
ca6a4a6013
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 172 additions and 108 deletions
  1. +6
    -1
      api/api_test.go
  2. +1
    -1
      api/txshistory_test.go
  3. +11
    -10
      common/l1tx.go
  4. +56
    -51
      db/historydb/historydb.go
  5. +6
    -5
      db/historydb/historydb_test.go
  6. +22
    -21
      db/historydb/views.go
  7. +1
    -0
      db/migrations/0001.sql
  8. +1
    -0
      node/node.go
  9. +13
    -8
      synchronizer/synchronizer.go
  10. +16
    -0
      synchronizer/synchronizer_test.go
  11. +25
    -6
      test/til/txs.go
  12. +14
    -5
      txprocessor/txprocessor.go

+ 6
- 1
api/api_test.go

@ -268,6 +268,10 @@ func TestMain(m *testing.M) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
err = tcc.FillBlocksForgedL1UserTxs(blocksData)
if err != nil {
panic(err)
}
AddAditionalInformation(blocksData) AddAditionalInformation(blocksData)
// Generate L2 Txs with til // Generate L2 Txs with til
commonPoolTxs, err := tcc.GeneratePoolL2Txs(txsets.SetPoolL2MinimumFlow0) commonPoolTxs, err := tcc.GeneratePoolL2Txs(txsets.SetPoolL2MinimumFlow0)
@ -304,6 +308,7 @@ func TestMain(m *testing.M) {
// Insert block into HistoryDB // Insert block into HistoryDB
// nolint reason: block is used as read only in the function // nolint reason: block is used as read only in the function
if err := api.h.AddBlockSCData(&block); err != nil { //nolint:gosec if err := api.h.AddBlockSCData(&block); err != nil { //nolint:gosec
log.Error(err)
panic(err) panic(err)
} }
// Extract data // Extract data
@ -329,7 +334,6 @@ func TestMain(m *testing.M) {
testTokens = append(testTokens, token) testTokens = append(testTokens, token)
} }
// Set USD value for tokens in DB // Set USD value for tokens in DB
commonL1Txs = append(commonL1Txs, block.Rollup.L1UserTxs...)
for _, batch := range block.Rollup.Batches { for _, batch := range block.Rollup.Batches {
commonL2Txs = append(commonL2Txs, batch.L2Txs...) commonL2Txs = append(commonL2Txs, batch.L2Txs...)
for i := range batch.CreatedAccounts { for i := range batch.CreatedAccounts {
@ -338,6 +342,7 @@ func TestMain(m *testing.M) {
} }
commonBatches = append(commonBatches, batch.Batch) commonBatches = append(commonBatches, batch.Batch)
commonExitTree = append(commonExitTree, batch.ExitTree...) commonExitTree = append(commonExitTree, batch.ExitTree...)
commonL1Txs = append(commonL1Txs, batch.L1UserTxs...)
commonL1Txs = append(commonL1Txs, batch.L1CoordinatorTxs...) commonL1Txs = append(commonL1Txs, batch.L1CoordinatorTxs...)
} }
} }

+ 1
- 1
api/txshistory_test.go

@ -144,7 +144,7 @@ func genTestTxs(
tx.BatchNum = &bn tx.BatchNum = &bn
} }
// If FromIdx is not nil // If FromIdx is not nil
idxStr := idxToHez(l1.FromIdx, token.Symbol)
idxStr := idxToHez(l1.EffectiveFromIdx, token.Symbol)
tx.FromIdx = &idxStr tx.FromIdx = &idxStr
// If tx has a normal ToIdx (>255), set FromEthAddr and FromBJJ // If tx has a normal ToIdx (>255), set FromEthAddr and FromBJJ
if l1.ToIdx >= common.UserThreshold { if l1.ToIdx >= common.UserThreshold {

+ 11
- 10
common/l1tx.go

@ -28,16 +28,17 @@ type L1Tx struct {
// where type: // where type:
// - L1UserTx: 0 // - L1UserTx: 0
// - L1CoordinatorTx: 1 // - L1CoordinatorTx: 1
TxID TxID `meddler:"id"`
ToForgeL1TxsNum *int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
Position int `meddler:"position"`
UserOrigin bool `meddler:"user_origin"` // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
FromIdx Idx `meddler:"from_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.DepositAmount (deposit)
FromEthAddr ethCommon.Address `meddler:"from_eth_addr,zeroisnull"`
FromBJJ babyjub.PublicKeyComp `meddler:"from_bjj,zeroisnull"`
ToIdx Idx `meddler:"to_idx"` // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
TokenID TokenID `meddler:"token_id"`
Amount *big.Int `meddler:"amount,bigint"`
TxID TxID `meddler:"id"`
ToForgeL1TxsNum *int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
Position int `meddler:"position"`
UserOrigin bool `meddler:"user_origin"` // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
FromIdx Idx `meddler:"from_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.DepositAmount (deposit)
EffectiveFromIdx Idx `meddler:"effective_from_idx,zeroisnull"`
FromEthAddr ethCommon.Address `meddler:"from_eth_addr,zeroisnull"`
FromBJJ babyjub.PublicKeyComp `meddler:"from_bjj,zeroisnull"`
ToIdx Idx `meddler:"to_idx"` // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
TokenID TokenID `meddler:"token_id"`
Amount *big.Int `meddler:"amount,bigint"`
// EffectiveAmount only applies to L1UserTx. // EffectiveAmount only applies to L1UserTx.
EffectiveAmount *big.Int `meddler:"effective_amount,bigintnull"` EffectiveAmount *big.Int `meddler:"effective_amount,bigintnull"`
DepositAmount *big.Int `meddler:"deposit_amount,bigint"` DepositAmount *big.Int `meddler:"deposit_amount,bigint"`

+ 56
- 51
db/historydb/historydb.go

@ -851,19 +851,29 @@ func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
amountFloat, _ := af.Float64() amountFloat, _ := af.Float64()
laf := new(big.Float).SetInt(l1txs[i].DepositAmount) laf := new(big.Float).SetInt(l1txs[i].DepositAmount)
depositAmountFloat, _ := laf.Float64() depositAmountFloat, _ := laf.Float64()
var effectiveFromIdx *common.Idx
if l1txs[i].UserOrigin {
if l1txs[i].Type != common.TxTypeCreateAccountDeposit &&
l1txs[i].Type != common.TxTypeCreateAccountDepositTransfer {
effectiveFromIdx = &l1txs[i].FromIdx
}
} else {
effectiveFromIdx = &l1txs[i].EffectiveFromIdx
}
txs = append(txs, txWrite{ txs = append(txs, txWrite{
// Generic // Generic
IsL1: true,
TxID: l1txs[i].TxID,
Type: l1txs[i].Type,
Position: l1txs[i].Position,
FromIdx: &l1txs[i].FromIdx,
ToIdx: l1txs[i].ToIdx,
Amount: l1txs[i].Amount,
AmountFloat: amountFloat,
TokenID: l1txs[i].TokenID,
BatchNum: l1txs[i].BatchNum,
EthBlockNum: l1txs[i].EthBlockNum,
IsL1: true,
TxID: l1txs[i].TxID,
Type: l1txs[i].Type,
Position: l1txs[i].Position,
FromIdx: &l1txs[i].FromIdx,
EffectiveFromIdx: effectiveFromIdx,
ToIdx: l1txs[i].ToIdx,
Amount: l1txs[i].Amount,
AmountFloat: amountFloat,
TokenID: l1txs[i].TokenID,
BatchNum: l1txs[i].BatchNum,
EthBlockNum: l1txs[i].EthBlockNum,
// L1 // L1
ToForgeL1TxsNum: l1txs[i].ToForgeL1TxsNum, ToForgeL1TxsNum: l1txs[i].ToForgeL1TxsNum,
UserOrigin: &l1txs[i].UserOrigin, UserOrigin: &l1txs[i].UserOrigin,
@ -889,16 +899,17 @@ func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
amountFloat, _ := f.Float64() amountFloat, _ := f.Float64()
txs = append(txs, txWrite{ txs = append(txs, txWrite{
// Generic // Generic
IsL1: false,
TxID: l2txs[i].TxID,
Type: l2txs[i].Type,
Position: l2txs[i].Position,
FromIdx: &l2txs[i].FromIdx,
ToIdx: l2txs[i].ToIdx,
Amount: l2txs[i].Amount,
AmountFloat: amountFloat,
BatchNum: &l2txs[i].BatchNum,
EthBlockNum: l2txs[i].EthBlockNum,
IsL1: false,
TxID: l2txs[i].TxID,
Type: l2txs[i].Type,
Position: l2txs[i].Position,
FromIdx: &l2txs[i].FromIdx,
EffectiveFromIdx: &l2txs[i].FromIdx,
ToIdx: l2txs[i].ToIdx,
Amount: l2txs[i].Amount,
AmountFloat: amountFloat,
BatchNum: &l2txs[i].BatchNum,
EthBlockNum: l2txs[i].EthBlockNum,
// L2 // L2
Fee: &l2txs[i].Fee, Fee: &l2txs[i].Fee,
Nonce: &l2txs[i].Nonce, Nonce: &l2txs[i].Nonce,
@ -919,6 +930,7 @@ func (hdb *HistoryDB) addTxs(d meddler.DB, txs []txWrite) error {
type, type,
position, position,
from_idx, from_idx,
effective_from_idx,
to_idx, to_idx,
amount, amount,
amount_f, amount_f,
@ -938,17 +950,6 @@ func (hdb *HistoryDB) addTxs(d meddler.DB, txs []txWrite) error {
)) ))
} }
// // GetTxs returns a list of txs from the DB
// func (hdb *HistoryDB) GetTxs() ([]common.Tx, error) {
// var txs []*common.Tx
// err := meddler.QueryAll(
// hdb.db, &txs,
// `SELECT * FROM tx
// ORDER BY (batch_num, position) ASC`,
// )
// return db.SlicePtrsToSlice(txs).([]common.Tx), err
// }
// GetHistoryTx returns a tx from the DB given a TxID // GetHistoryTx returns a tx from the DB given a TxID
func (hdb *HistoryDB) GetHistoryTx(txID common.TxID) (*TxAPI, error) { func (hdb *HistoryDB) GetHistoryTx(txID common.TxID) (*TxAPI, error) {
// Warning: amount_success and deposit_amount_success have true as default for // Warning: amount_success and deposit_amount_success have true as default for
@ -957,7 +958,7 @@ func (hdb *HistoryDB) GetHistoryTx(txID common.TxID) (*TxAPI, error) {
tx := &TxAPI{} tx := &TxAPI{}
err := meddler.QueryRow( err := meddler.QueryRow(
hdb.db, tx, `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position, hdb.db, tx, `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
hez_idx(tx.from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
hez_idx(tx.effective_from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj, hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
tx.amount, tx.amount_success, tx.token_id, tx.amount_usd, tx.amount, tx.amount_success, tx.token_id, tx.amount_usd,
tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin, tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
@ -988,7 +989,7 @@ func (hdb *HistoryDB) GetHistoryTxs(
var query string var query string
var args []interface{} var args []interface{}
queryStr := `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position, queryStr := `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
hez_idx(tx.from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
hez_idx(tx.effective_from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj, hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
tx.amount, tx.amount_success, tx.token_id, tx.amount_usd, tx.amount, tx.amount_success, tx.token_id, tx.amount_usd,
tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin, tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
@ -1028,7 +1029,7 @@ func (hdb *HistoryDB) GetHistoryTxs(
} else { } else {
queryStr += "WHERE " queryStr += "WHERE "
} }
queryStr += "(tx.from_idx = ? OR tx.to_idx = ?) "
queryStr += "(tx.effective_from_idx = ? OR tx.to_idx = ?) "
args = append(args, idx, idx) args = append(args, idx, idx)
nextIsAnd = true nextIsAnd = true
} }
@ -1245,7 +1246,7 @@ func (hdb *HistoryDB) GetAllL1UserTxs() ([]common.L1Tx, error) {
err := meddler.QueryAll( err := meddler.QueryAll(
hdb.db, &txs, // Note that '\x' gets parsed as a big.Int with value = 0 hdb.db, &txs, // Note that '\x' gets parsed as a big.Int with value = 0
`SELECT tx.id, tx.to_forge_l1_txs_num, tx.position, tx.user_origin, `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.from_idx, tx.effective_from_idx, tx.from_eth_addr, tx.from_bjj, tx.to_idx, tx.token_id,
tx.amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.amount_success THEN tx.amount ELSE '\x' END) AS effective_amount, tx.amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.amount_success THEN tx.amount ELSE '\x' END) AS effective_amount,
tx.deposit_amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.deposit_amount_success THEN tx.deposit_amount ELSE '\x' END) AS effective_deposit_amount, tx.deposit_amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.deposit_amount_success THEN tx.deposit_amount ELSE '\x' END) AS effective_deposit_amount,
tx.eth_block_num, tx.type, tx.batch_num tx.eth_block_num, tx.type, tx.batch_num
@ -1262,7 +1263,7 @@ func (hdb *HistoryDB) GetAllL1CoordinatorTxs() ([]common.L1Tx, error) {
err := meddler.QueryAll( err := meddler.QueryAll(
hdb.db, &txs, hdb.db, &txs,
`SELECT tx.id, tx.to_forge_l1_txs_num, tx.position, tx.user_origin, `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.from_idx, tx.effective_from_idx, tx.from_eth_addr, tx.from_bjj, tx.to_idx, tx.token_id,
tx.amount, tx.amount AS effective_amount, tx.amount, tx.amount AS effective_amount,
tx.deposit_amount, tx.deposit_amount AS effective_deposit_amount, tx.deposit_amount, tx.deposit_amount AS effective_deposit_amount,
tx.eth_block_num, tx.type, tx.batch_num tx.eth_block_num, tx.type, tx.batch_num
@ -1480,19 +1481,21 @@ func (hdb *HistoryDB) SetInitialSCVars(rollup *common.RollupVariables,
return tracerr.Wrap(txn.Commit()) return tracerr.Wrap(txn.Commit())
} }
// setL1UserTxEffectiveAmounts sets the EffectiveAmount and EffectiveDepositAmount
// of the given l1UserTxs (with an UPDATE)
func (hdb *HistoryDB) setL1UserTxEffectiveAmounts(d sqlx.Ext, txs []common.L1Tx) error {
// setExtraInfoForgedL1UserTxs sets the EffectiveAmount, EffectiveDepositAmount
// and EffectiveFromIdx of the given l1UserTxs (with an UPDATE)
func (hdb *HistoryDB) setExtraInfoForgedL1UserTxs(d sqlx.Ext, txs []common.L1Tx) error {
if len(txs) == 0 { if len(txs) == 0 {
return nil return nil
} }
// Effective amounts are stored as success flags in the DB, with true value by default // Effective amounts are stored as success flags in the DB, with true value by default
// to reduce the amount of updates. Therefore, only amounts that became uneffective should be // to reduce the amount of updates. Therefore, only amounts that became uneffective should be
// updated to become false
// updated to become false. At the same time, all the txs that contain
// accounts (FromIdx == 0) are updated to set the EffectiveFromIdx.
type txUpdate struct { type txUpdate struct {
ID common.TxID `db:"id"` ID common.TxID `db:"id"`
AmountSuccess bool `db:"amount_success"` AmountSuccess bool `db:"amount_success"`
DepositAmountSuccess bool `db:"deposit_amount_success"` DepositAmountSuccess bool `db:"deposit_amount_success"`
EffectiveFromIdx common.Idx `db:"effective_from_idx"`
} }
txUpdates := []txUpdate{} txUpdates := []txUpdate{}
equal := func(a *big.Int, b *big.Int) bool { equal := func(a *big.Int, b *big.Int) bool {
@ -1501,22 +1504,24 @@ func (hdb *HistoryDB) setL1UserTxEffectiveAmounts(d sqlx.Ext, txs []common.L1Tx)
for i := range txs { for i := range txs {
amountSuccess := equal(txs[i].Amount, txs[i].EffectiveAmount) amountSuccess := equal(txs[i].Amount, txs[i].EffectiveAmount)
depositAmountSuccess := equal(txs[i].DepositAmount, txs[i].EffectiveDepositAmount) depositAmountSuccess := equal(txs[i].DepositAmount, txs[i].EffectiveDepositAmount)
if !amountSuccess || !depositAmountSuccess {
if !amountSuccess || !depositAmountSuccess || txs[i].FromIdx == 0 {
txUpdates = append(txUpdates, txUpdate{ txUpdates = append(txUpdates, txUpdate{
ID: txs[i].TxID, ID: txs[i].TxID,
AmountSuccess: amountSuccess, AmountSuccess: amountSuccess,
DepositAmountSuccess: depositAmountSuccess, DepositAmountSuccess: depositAmountSuccess,
EffectiveFromIdx: txs[i].EffectiveFromIdx,
}) })
} }
} }
const query string = ` const query string = `
UPDATE tx SET UPDATE tx SET
amount_success = tx_update.amount_success, amount_success = tx_update.amount_success,
deposit_amount_success = tx_update.deposit_amount_success
deposit_amount_success = tx_update.deposit_amount_success,
effective_from_idx = tx_update.effective_from_idx
FROM (VALUES FROM (VALUES
(NULL::::BYTEA, NULL::::BOOL, NULL::::BOOL),
(:id, :amount_success, :deposit_amount_success)
) as tx_update (id, amount_success, deposit_amount_success)
(NULL::::BYTEA, NULL::::BOOL, NULL::::BOOL, NULL::::BIGINT),
(:id, :amount_success, :deposit_amount_success, :effective_from_idx)
) as tx_update (id, amount_success, deposit_amount_success, effective_from_idx)
WHERE tx.id = tx_update.id; WHERE tx.id = tx_update.id;
` `
if len(txUpdates) > 0 { if len(txUpdates) > 0 {
@ -1599,14 +1604,14 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) {
return tracerr.Wrap(err) return tracerr.Wrap(err)
} }
// Set the EffectiveAmount and EffectiveDepositAmount of all the
// L1UserTxs that have been forged in this batch
if err = hdb.setL1UserTxEffectiveAmounts(txn, batch.L1UserTxs); err != nil {
// Add accounts
if err := hdb.addAccounts(txn, batch.CreatedAccounts); err != nil {
return tracerr.Wrap(err) return tracerr.Wrap(err)
} }
// Add accounts
if err := hdb.addAccounts(txn, batch.CreatedAccounts); err != nil {
// Set the EffectiveAmount and EffectiveDepositAmount of all the
// L1UserTxs that have been forged in this batch
if err = hdb.setExtraInfoForgedL1UserTxs(txn, batch.L1UserTxs); err != nil {
return tracerr.Wrap(err) return tracerr.Wrap(err)
} }

+ 6
- 5
db/historydb/historydb_test.go

@ -752,7 +752,7 @@ func TestSetInitialSCVars(t *testing.T) {
require.Equal(t, wDelayer, dbWDelayer) require.Equal(t, wDelayer, dbWDelayer)
} }
func TestSetL1UserTxEffectiveAmounts(t *testing.T) {
func TestSetExtraInfoForgedL1UserTxs(t *testing.T) {
test.WipeDB(historyDB.DB()) test.WipeDB(historyDB.DB())
set := ` set := `
@ -789,11 +789,12 @@ func TestSetL1UserTxEffectiveAmounts(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
} }
// Add second batch to trigger the update of the batch_num, // Add second batch to trigger the update of the batch_num,
// while avoiding the implicit call of setL1UserTxEffectiveAmounts
// while avoiding the implicit call of setExtraInfoForgedL1UserTxs
err = historyDB.addBlock(historyDB.db, &blocks[1].Block) err = historyDB.addBlock(historyDB.db, &blocks[1].Block)
assert.NoError(t, err)
require.NoError(t, err)
err = historyDB.addBatch(historyDB.db, &blocks[1].Rollup.Batches[0].Batch) err = historyDB.addBatch(historyDB.db, &blocks[1].Rollup.Batches[0].Batch)
assert.NoError(t, err)
require.NoError(t, err)
err = historyDB.addAccounts(historyDB.db, blocks[1].Rollup.Batches[0].CreatedAccounts)
require.NoError(t, err) require.NoError(t, err)
// Set the Effective{Amount,DepositAmount} of the L1UserTxs that are forged in the second block // Set the Effective{Amount,DepositAmount} of the L1UserTxs that are forged in the second block
@ -803,7 +804,7 @@ func TestSetL1UserTxEffectiveAmounts(t *testing.T) {
l1Txs[1].EffectiveAmount = big.NewInt(0) l1Txs[1].EffectiveAmount = big.NewInt(0)
l1Txs[2].EffectiveDepositAmount = big.NewInt(0) l1Txs[2].EffectiveDepositAmount = big.NewInt(0)
l1Txs[2].EffectiveAmount = big.NewInt(0) l1Txs[2].EffectiveAmount = big.NewInt(0)
err = historyDB.setL1UserTxEffectiveAmounts(historyDB.db, l1Txs)
err = historyDB.setExtraInfoForgedL1UserTxs(historyDB.db, l1Txs)
require.NoError(t, err) require.NoError(t, err)
dbL1Txs, err := historyDB.GetAllL1UserTxs() dbL1Txs, err := historyDB.GetAllL1UserTxs()

+ 22
- 21
db/historydb/views.go

@ -123,17 +123,18 @@ func (tx TxAPI) MarshalJSON() ([]byte, error) {
// EffectiveAmount and EffectiveDepositAmount are not set since they have default values in the DB // EffectiveAmount and EffectiveDepositAmount are not set since they have default values in the DB
type txWrite struct { type txWrite struct {
// Generic // Generic
IsL1 bool `meddler:"is_l1"`
TxID common.TxID `meddler:"id"`
Type common.TxType `meddler:"type"`
Position int `meddler:"position"`
FromIdx *common.Idx `meddler:"from_idx"`
ToIdx common.Idx `meddler:"to_idx"`
Amount *big.Int `meddler:"amount,bigint"`
AmountFloat float64 `meddler:"amount_f"`
TokenID common.TokenID `meddler:"token_id"`
BatchNum *common.BatchNum `meddler:"batch_num"` // batchNum in which this tx was forged. If the tx is L2, this must be != 0
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
IsL1 bool `meddler:"is_l1"`
TxID common.TxID `meddler:"id"`
Type common.TxType `meddler:"type"`
Position int `meddler:"position"`
FromIdx *common.Idx `meddler:"from_idx"`
EffectiveFromIdx *common.Idx `meddler:"effective_from_idx"`
ToIdx common.Idx `meddler:"to_idx"`
Amount *big.Int `meddler:"amount,bigint"`
AmountFloat float64 `meddler:"amount_f"`
TokenID common.TokenID `meddler:"token_id"`
BatchNum *common.BatchNum `meddler:"batch_num"` // batchNum in which this tx was forged. If the tx is L2, this must be != 0
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
// L1 // L1
ToForgeL1TxsNum *int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged ToForgeL1TxsNum *int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
UserOrigin *bool `meddler:"user_origin"` // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes UserOrigin *bool `meddler:"user_origin"` // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
@ -375,24 +376,24 @@ type RollupVariablesAPI struct {
// AuctionVariablesAPI are the variables of the Auction Smart Contract // AuctionVariablesAPI are the variables of the Auction Smart Contract
type AuctionVariablesAPI struct { type AuctionVariablesAPI struct {
EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"` EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"`
// Donation Address
// DonationAddress Address where the donations will be sent
DonationAddress ethCommon.Address `json:"donationAddress" meddler:"donation_address" validate:"required"` DonationAddress ethCommon.Address `json:"donationAddress" meddler:"donation_address" validate:"required"`
// Boot Coordinator Address
// BootCoordinator Address of the boot coordinator
BootCoordinator ethCommon.Address `json:"bootCoordinator" meddler:"boot_coordinator" validate:"required"` BootCoordinator ethCommon.Address `json:"bootCoordinator" meddler:"boot_coordinator" validate:"required"`
// Boot Coordinator URL
// BootCoordinatorURL URL of the boot coordinator
BootCoordinatorURL string `json:"bootCoordinatorUrl" meddler:"boot_coordinator_url" validate:"required"` BootCoordinatorURL string `json:"bootCoordinatorUrl" meddler:"boot_coordinator_url" validate:"required"`
// The minimum bid value in a series of 6 slots
// DefaultSlotSetBid The minimum bid value in a series of 6 slots
DefaultSlotSetBid [6]*apitypes.BigIntStr `json:"defaultSlotSetBid" meddler:"default_slot_set_bid,json" validate:"required"` DefaultSlotSetBid [6]*apitypes.BigIntStr `json:"defaultSlotSetBid" meddler:"default_slot_set_bid,json" validate:"required"`
// SlotNum at which the new default_slot_set_bid applies
// DefaultSlotSetBidSlotNum SlotNum at which the new default_slot_set_bid applies
DefaultSlotSetBidSlotNum int64 `json:"defaultSlotSetBidSlotNum" meddler:"default_slot_set_bid_slot_num"` DefaultSlotSetBidSlotNum int64 `json:"defaultSlotSetBidSlotNum" meddler:"default_slot_set_bid_slot_num"`
// Distance (#slots) to the closest slot to which you can bid ( 2 Slots = 2 * 40 Blocks = 20 min )
// ClosedAuctionSlots 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" validate:"required"` ClosedAuctionSlots uint16 `json:"closedAuctionSlots" meddler:"closed_auction_slots" validate:"required"`
// Distance (#slots) to the farthest slot to which you can bid (30 days = 4320 slots )
// OpenAuctionSlots Distance (#slots) to the farthest slot to which you can bid (30 days = 4320 slots )
OpenAuctionSlots uint16 `json:"openAuctionSlots" meddler:"open_auction_slots" validate:"required"` OpenAuctionSlots uint16 `json:"openAuctionSlots" meddler:"open_auction_slots" validate:"required"`
// How the HEZ tokens deposited by the slot winner are distributed (Burn: 40% - Donation: 40% - HGT: 20%)
// AllocationRatio 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" validate:"required"` AllocationRatio [3]uint16 `json:"allocationRatio" meddler:"allocation_ratio,json" validate:"required"`
// Minimum outbid (percentage) over the previous one to consider it valid
// Outbidding Minimum outbid (percentage) over the previous one to consider it valid
Outbidding uint16 `json:"outbidding" meddler:"outbidding" validate:"required"` Outbidding uint16 `json:"outbidding" meddler:"outbidding" validate:"required"`
// Number of blocks at the end of a slot in which any coordinator can forge if the winner has not forged one before
// SlotDeadline 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" validate:"required"` SlotDeadline uint8 `json:"slotDeadline" meddler:"slot_deadline" validate:"required"`
} }

+ 1
- 0
db/migrations/0001.sql

@ -149,6 +149,7 @@ CREATE TABLE tx (
type VARCHAR(40) NOT NULL, type VARCHAR(40) NOT NULL,
position INT NOT NULL, position INT NOT NULL,
from_idx BIGINT, from_idx BIGINT,
effective_from_idx BIGINT REFERENCES account (idx) ON DELETE SET NULL,
from_eth_addr BYTEA, from_eth_addr BYTEA,
from_bjj BYTEA, from_bjj BYTEA,
to_idx BIGINT NOT NULL, to_idx BIGINT NOT NULL,

+ 1
- 0
node/node.go

@ -172,6 +172,7 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) {
sync, err := synchronizer.NewSynchronizer(client, historyDB, stateDB, synchronizer.Config{ sync, err := synchronizer.NewSynchronizer(client, historyDB, stateDB, synchronizer.Config{
StatsRefreshPeriod: cfg.Synchronizer.StatsRefreshPeriod.Duration, StatsRefreshPeriod: cfg.Synchronizer.StatsRefreshPeriod.Duration,
ChainID: chainIDU16,
}) })
if err != nil { if err != nil {
return nil, tracerr.Wrap(err) return nil, tracerr.Wrap(err)

+ 13
- 8
synchronizer/synchronizer.go

@ -180,6 +180,7 @@ type SCConsts struct {
// Config is the Synchronizer configuration // Config is the Synchronizer configuration
type Config struct { type Config struct {
StatsRefreshPeriod time.Duration StatsRefreshPeriod time.Duration
ChainID uint16
} }
// Synchronizer implements the Synchronizer type // Synchronizer implements the Synchronizer type
@ -797,17 +798,21 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e
// Transform L2 txs to PoolL2Txs // Transform L2 txs to PoolL2Txs
poolL2Txs := common.L2TxsToPoolL2Txs(forgeBatchArgs.L2TxsData) // NOTE: This is a big ugly, find a better way poolL2Txs := common.L2TxsToPoolL2Txs(forgeBatchArgs.L2TxsData) // NOTE: This is a big ugly, find a better way
// ProcessTxs updates poolL2Txs adding: Nonce (and also TokenID, but we don't use it).
//nolint:gomnd
tpc := txprocessor.Config{ // TODO TMP
NLevels: 32,
MaxFeeTx: 64,
MaxTx: 512,
MaxL1Tx: 64,
ChainID: uint16(0),
if int(forgeBatchArgs.VerifierIdx) >= len(s.consts.Rollup.Verifiers) {
return nil, tracerr.Wrap(fmt.Errorf("forgeBatchArgs.VerifierIdx (%v) >= "+
" len(s.consts.Rollup.Verifiers) (%v)",
forgeBatchArgs.VerifierIdx, len(s.consts.Rollup.Verifiers)))
}
tpc := txprocessor.Config{
NLevels: uint32(s.consts.Rollup.Verifiers[forgeBatchArgs.VerifierIdx].NLevels),
MaxTx: uint32(s.consts.Rollup.Verifiers[forgeBatchArgs.VerifierIdx].MaxTx),
ChainID: s.cfg.ChainID,
MaxFeeTx: common.RollupConstMaxFeeIdxCoordinator,
MaxL1Tx: common.RollupConstMaxL1Tx,
} }
tp := txprocessor.NewTxProcessor(s.stateDB, tpc) tp := txprocessor.NewTxProcessor(s.stateDB, tpc)
// ProcessTxs updates poolL2Txs adding: Nonce (and also TokenID, but we don't use it).
processTxsOut, err := tp.ProcessTxs(forgeBatchArgs.FeeIdxCoordinator, processTxsOut, err := tp.ProcessTxs(forgeBatchArgs.FeeIdxCoordinator,
l1UserTxs, batchData.L1CoordinatorTxs, poolL2Txs) l1UserTxs, batchData.L1CoordinatorTxs, poolL2Txs)
if err != nil { if err != nil {

+ 16
- 0
synchronizer/synchronizer_test.go

@ -98,6 +98,11 @@ func checkSyncBlock(t *testing.T, s *Synchronizer, blockNum int, block, syncBloc
tx.Position == _dbTx.Position { tx.Position == _dbTx.Position {
dbTx = new(common.L1Tx) dbTx = new(common.L1Tx)
*dbTx = _dbTx *dbTx = _dbTx
// NOTE: Overwrite EffectiveFromIdx in L1UserTx
// from db because we don't expect
// EffectiveFromIdx to be set yet, as this tx
// is not in yet forged
dbTx.EffectiveFromIdx = 0
break break
} }
} }
@ -142,7 +147,18 @@ func checkSyncBlock(t *testing.T, s *Synchronizer, blockNum int, block, syncBloc
batch.Batch.NumAccounts = len(batch.CreatedAccounts) batch.Batch.NumAccounts = len(batch.CreatedAccounts)
// Test field by field to facilitate debugging of errors // Test field by field to facilitate debugging of errors
assert.Equal(t, len(batch.L1UserTxs), len(syncBatch.L1UserTxs))
// NOTE: EffectiveFromIdx is set to til L1UserTxs in
// `FillBlocksForgedL1UserTxs` function
for j := range syncBatch.L1UserTxs {
assert.NotEqual(t, 0, syncBatch.L1UserTxs[j].EffectiveFromIdx)
}
assert.Equal(t, batch.L1UserTxs, syncBatch.L1UserTxs) assert.Equal(t, batch.L1UserTxs, syncBatch.L1UserTxs)
// NOTE: EffectiveFromIdx is set to til L1CoordinatorTxs in
// `FillBlocksExtra` function
for j := range syncBatch.L1CoordinatorTxs {
assert.NotEqual(t, 0, syncBatch.L1CoordinatorTxs[j].EffectiveFromIdx)
}
assert.Equal(t, batch.L1CoordinatorTxs, syncBatch.L1CoordinatorTxs) assert.Equal(t, batch.L1CoordinatorTxs, syncBatch.L1CoordinatorTxs)
assert.Equal(t, batch.L2Txs, syncBatch.L2Txs) assert.Equal(t, batch.L2Txs, syncBatch.L2Txs)
// In exit tree, we only check AccountIdx and Balance, because // In exit tree, we only check AccountIdx and Balance, because

+ 25
- 6
test/til/txs.go

@ -45,6 +45,7 @@ type contextExtra struct {
toForgeL1TxsNum int64 toForgeL1TxsNum int64
nonces map[common.Idx]common.Nonce nonces map[common.Idx]common.Nonce
idx int idx int
idxByTxID map[common.TxID]common.Idx
} }
// Context contains the data of the test // Context contains the data of the test
@ -107,6 +108,7 @@ func NewContext(chainID uint16, rollupConstMaxL1UserTx int) *Context {
toForgeL1TxsNum: 0, toForgeL1TxsNum: 0,
nonces: make(map[common.Idx]common.Nonce), nonces: make(map[common.Idx]common.Nonce),
idx: common.UserThreshold, idx: common.UserThreshold,
idxByTxID: make(map[common.TxID]common.Idx),
}, },
} }
} }
@ -762,7 +764,12 @@ func (tc *Context) FillBlocksL1UserTxsBatchNum(blocks []common.BlockData) {
// FillBlocksForgedL1UserTxs fills the L1UserTxs of a batch with the L1UserTxs // FillBlocksForgedL1UserTxs fills the L1UserTxs of a batch with the L1UserTxs
// that are forged in that batch. It always sets `EffectiveAmount` = `Amount` // that are forged in that batch. It always sets `EffectiveAmount` = `Amount`
// and `EffectiveDepositAmount` = `DepositAmount`.
// and `EffectiveDepositAmount` = `DepositAmount`. This function requires a
// previous call to `FillBlocksExtra`.
// - blocks[].Rollup.L1UserTxs[].BatchNum
// - blocks[].Rollup.L1UserTxs[].EffectiveAmount
// - blocks[].Rollup.L1UserTxs[].EffectiveDepositAmount
// - blocks[].Rollup.L1UserTxs[].EffectiveFromIdx
func (tc *Context) FillBlocksForgedL1UserTxs(blocks []common.BlockData) error { func (tc *Context) FillBlocksForgedL1UserTxs(blocks []common.BlockData) error {
for i := range blocks { for i := range blocks {
block := &blocks[i] block := &blocks[i]
@ -783,6 +790,11 @@ func (tc *Context) FillBlocksForgedL1UserTxs(blocks []common.BlockData) error {
return tracerr.Wrap(err) return tracerr.Wrap(err)
} }
*tx = *_tx *tx = *_tx
if tx.FromIdx == 0 {
tx.EffectiveFromIdx = tc.extra.idxByTxID[tx.TxID]
} else {
tx.EffectiveFromIdx = tx.FromIdx
}
} }
} }
} }
@ -802,6 +814,7 @@ func (tc *Context) FillBlocksForgedL1UserTxs(blocks []common.BlockData) error {
// - blocks[].Rollup.Batch.L1CoordinatorTxs[].Position // - blocks[].Rollup.Batch.L1CoordinatorTxs[].Position
// - blocks[].Rollup.Batch.L1CoordinatorTxs[].EffectiveAmount // - blocks[].Rollup.Batch.L1CoordinatorTxs[].EffectiveAmount
// - blocks[].Rollup.Batch.L1CoordinatorTxs[].EffectiveDepositAmount // - blocks[].Rollup.Batch.L1CoordinatorTxs[].EffectiveDepositAmount
// - blocks[].Rollup.Batch.L1CoordinatorTxs[].EffectiveFromIdx
// - blocks[].Rollup.Batch.L2Txs[].TxID // - blocks[].Rollup.Batch.L2Txs[].TxID
// - blocks[].Rollup.Batch.L2Txs[].Position // - blocks[].Rollup.Batch.L2Txs[].Position
// - blocks[].Rollup.Batch.L2Txs[].Nonce // - blocks[].Rollup.Batch.L2Txs[].Nonce
@ -839,15 +852,17 @@ func (tc *Context) FillBlocksExtra(blocks []common.BlockData, cfg *ConfigExtra)
block := &blocks[i] block := &blocks[i]
for j := range block.Rollup.Batches { for j := range block.Rollup.Batches {
batch := &block.Rollup.Batches[j] batch := &block.Rollup.Batches[j]
l1Txs := []common.L1Tx{}
l1Txs := []*common.L1Tx{}
if batch.L1Batch { if batch.L1Batch {
for _, tx := range tc.Queues[*batch.Batch.ForgeL1TxsNum] {
l1Txs = append(l1Txs, tx.L1Tx)
for k := range tc.Queues[*batch.Batch.ForgeL1TxsNum] {
l1Txs = append(l1Txs, &tc.Queues[*batch.Batch.ForgeL1TxsNum][k].L1Tx)
} }
} }
l1Txs = append(l1Txs, batch.L1CoordinatorTxs...)
for k := range batch.L1CoordinatorTxs {
l1Txs = append(l1Txs, &batch.L1CoordinatorTxs[k])
}
for k := range l1Txs { for k := range l1Txs {
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]
@ -864,6 +879,10 @@ func (tc *Context) FillBlocksExtra(blocks []common.BlockData, cfg *ConfigExtra)
Nonce: 0, Nonce: 0,
Balance: big.NewInt(0), Balance: big.NewInt(0),
}) })
if !tx.UserOrigin {
tx.EffectiveFromIdx = common.Idx(tc.extra.idx)
}
tc.extra.idxByTxID[tx.TxID] = common.Idx(tc.extra.idx)
tc.extra.idx++ tc.extra.idx++
} }
} }

+ 14
- 5
txprocessor/txprocessor.go

@ -154,10 +154,14 @@ func (tp *TxProcessor) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinat
if err != nil { if err != nil {
return nil, tracerr.Wrap(err) return nil, tracerr.Wrap(err)
} }
if tp.s.Typ == statedb.TypeSynchronizer && createdAccount != nil {
createdAccounts = append(createdAccounts, *createdAccount)
if tp.s.Typ == statedb.TypeSynchronizer {
if createdAccount != nil {
createdAccounts = append(createdAccounts, *createdAccount)
l1usertxs[i].EffectiveFromIdx = createdAccount.Idx
} else {
l1usertxs[i].EffectiveFromIdx = l1usertxs[i].FromIdx
}
} }
if tp.zki != nil { if tp.zki != nil {
l1TxData, err := l1usertxs[i].BytesGeneric() l1TxData, err := l1usertxs[i].BytesGeneric()
if err != nil { if err != nil {
@ -201,8 +205,13 @@ func (tp *TxProcessor) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinat
if exitIdx != nil { if exitIdx != nil {
log.Error("Unexpected Exit in L1CoordinatorTx") log.Error("Unexpected Exit in L1CoordinatorTx")
} }
if tp.s.Typ == statedb.TypeSynchronizer && createdAccount != nil {
createdAccounts = append(createdAccounts, *createdAccount)
if tp.s.Typ == statedb.TypeSynchronizer {
if createdAccount != nil {
createdAccounts = append(createdAccounts, *createdAccount)
l1coordinatortxs[i].EffectiveFromIdx = createdAccount.Idx
} else {
l1coordinatortxs[i].EffectiveFromIdx = l1coordinatortxs[i].FromIdx
}
} }
if tp.zki != nil { if tp.zki != nil {
l1TxData, err := l1coordinatortxs[i].BytesGeneric() l1TxData, err := l1coordinatortxs[i].BytesGeneric()

Loading…
Cancel
Save