Browse Source

Add PoolL2Tx.Info about the status of the tx

PoolL2Tx.Info contains information about the status & State of the
transaction. As for example, if the Tx has not been selected in the last
batch due not enough Balance at the Sender account, this reason would
appear at this parameter.
This will help the client (wallet, batchexplorer, etc) to reason why a
L2Tx is not selected in the forged batches.
feature/sql-semaphore1
arnaucube 3 years ago
parent
commit
a8f6891aea
12 changed files with 188 additions and 50 deletions
  1. +7
    -0
      api/swagger.yml
  2. +1
    -1
      common/l2tx.go
  3. +5
    -0
      common/pooll2tx.go
  4. +6
    -2
      coordinator/pipeline.go
  5. +33
    -2
      db/l2db/l2db.go
  6. +24
    -0
      db/l2db/l2db_test.go
  7. +2
    -0
      db/l2db/views.go
  8. +1
    -0
      db/migrations/0001.sql
  9. +13
    -5
      test/zkproof/flows_test.go
  10. +8
    -5
      txprocessor/txprocessor.go
  11. +61
    -22
      txselector/txselector.go
  12. +27
    -13
      txselector/txselector_test.go

+ 7
- 0
api/swagger.yml

@ -1314,6 +1314,12 @@ components:
$ref: '#/components/schemas/Nonce'
state:
$ref: '#/components/schemas/PoolL2TransactionState'
info:
type: string
description: "Info contains information about the status & State of the transaction. As for example, if the Tx has not been selected in the last batch due not enough Balance at the Sender account, this reason would appear at this parameter."
pattern: ".*"
example: "Tx not selected due not enough Balance at the sender."
nullable: true
signature:
allOf:
- $ref: '#/components/schemas/BJJSignature'
@ -1429,6 +1435,7 @@ components:
- fee
- nonce
- state
- info
- signature
- timestamp
- batchNum

+ 1
- 1
common/l2tx.go

@ -23,7 +23,7 @@ type L2Tx struct {
// Nonce is filled by the TxProcessor
Nonce Nonce `meddler:"nonce"`
Type TxType `meddler:"type"`
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L2Tx was added to the queue
EthBlockNum int64 `meddler:"eth_block_num"` // EthereumBlockNumber in which this L2Tx was added to the queue
}
// NewL2Tx returns the given L2Tx with the TxId & Type parameters calculated

+ 5
- 0
common/pooll2tx.go

@ -40,6 +40,11 @@ type PoolL2Tx struct {
Fee FeeSelector `meddler:"fee"`
Nonce Nonce `meddler:"nonce"` // effective 40 bits used
State PoolL2TxState `meddler:"state"`
// Info contains information about the status & State of the
// transaction. As for example, if the Tx has not been selected in the
// last batch due not enough Balance at the Sender account, this reason
// would appear at this parameter.
Info string `meddler:"info,zeroisnull"`
Signature babyjub.SignatureComp `meddler:"signature"` // tx signature
Timestamp time.Time `meddler:"timestamp,utctime"` // time when added to the tx pool
// Stored in DB: optional fileds, may be uninitialized

+ 6
- 2
coordinator/pipeline.go

@ -293,6 +293,7 @@ func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, e
}
var poolL2Txs []common.PoolL2Tx
var discardedL2Txs []common.PoolL2Tx
var l1UserTxsExtra, l1CoordTxs []common.L1Tx
var auths [][]byte
var coordIdxs []common.Idx
@ -316,14 +317,14 @@ func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, e
if err != nil {
return nil, tracerr.Wrap(err)
}
coordIdxs, auths, l1UserTxsExtra, l1CoordTxs, poolL2Txs, err =
coordIdxs, auths, l1UserTxsExtra, l1CoordTxs, poolL2Txs, discardedL2Txs, err =
p.txSelector.GetL1L2TxSelection(selectionCfg, l1UserTxs)
if err != nil {
return nil, tracerr.Wrap(err)
}
} else {
// 2b: only L2 txs
coordIdxs, auths, l1CoordTxs, poolL2Txs, err =
coordIdxs, auths, l1CoordTxs, poolL2Txs, discardedL2Txs, err =
p.txSelector.GetL2TxSelection(selectionCfg)
if err != nil {
return nil, tracerr.Wrap(err)
@ -341,6 +342,9 @@ func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, e
if err := p.l2DB.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs), batchInfo.BatchNum); err != nil {
return nil, tracerr.Wrap(err)
}
if err := p.l2DB.UpdateTxsInfo(discardedL2Txs); err != nil {
return nil, tracerr.Wrap(err)
}
// Invalidate transactions that become invalid beause of
// the poolL2Txs selected. Will mark as invalid the txs that have a

+ 33
- 2
db/l2db/l2db.go

@ -94,6 +94,37 @@ func (l2db *L2DB) AddTx(tx *PoolL2TxWrite) error {
return tracerr.Wrap(meddler.Insert(l2db.db, "tx_pool", tx))
}
// UpdateTxsInfo updates the parameter Info of the pool transactions
func (l2db *L2DB) UpdateTxsInfo(txs []common.PoolL2Tx) error {
if len(txs) == 0 {
return nil
}
type txUpdate struct {
ID common.TxID `db:"id"`
Info string `db:"info"`
}
txUpdates := make([]txUpdate, len(txs))
for i := range txs {
txUpdates[i] = txUpdate{ID: txs[i].TxID, Info: txs[i].Info}
}
const query string = `
UPDATE tx_pool SET
info = tx_update.info
FROM (VALUES
(NULL::::BYTEA, NULL::::VARCHAR),
(:id, :info)
) as tx_update (id, info)
WHERE tx_pool.tx_id = tx_update.id;
`
if len(txUpdates) > 0 {
if _, err := sqlx.NamedExec(l2db.db, query, txUpdates); err != nil {
return tracerr.Wrap(err)
}
}
return nil
}
// AddTxTest inserts a tx into the L2DB. This is useful for test purposes,
// but in production txs will only be inserted through the API
func (l2db *L2DB) AddTxTest(tx *common.PoolL2Tx) error {
@ -146,7 +177,7 @@ func (l2db *L2DB) AddTxTest(tx *common.PoolL2Tx) error {
const selectPoolTxAPI = `SELECT tx_pool.tx_id, hez_idx(tx_pool.from_idx, token.symbol) AS from_idx, tx_pool.effective_from_eth_addr,
tx_pool.effective_from_bjj, hez_idx(tx_pool.to_idx, token.symbol) AS to_idx, tx_pool.effective_to_eth_addr,
tx_pool.effective_to_bjj, tx_pool.token_id, tx_pool.amount, tx_pool.fee, tx_pool.nonce,
tx_pool.state, tx_pool.signature, tx_pool.timestamp, tx_pool.batch_num, hez_idx(tx_pool.rq_from_idx, token.symbol) AS rq_from_idx,
tx_pool.state, tx_pool.info, tx_pool.signature, tx_pool.timestamp, tx_pool.batch_num, hez_idx(tx_pool.rq_from_idx, token.symbol) AS rq_from_idx,
hez_idx(tx_pool.rq_to_idx, token.symbol) AS rq_to_idx, tx_pool.rq_to_eth_addr, tx_pool.rq_to_bjj, tx_pool.rq_token_id, tx_pool.rq_amount,
tx_pool.rq_fee, tx_pool.rq_nonce, tx_pool.tx_type,
token.item_id AS token_item_id, token.eth_block_num, token.eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update
@ -155,7 +186,7 @@ FROM tx_pool INNER JOIN token ON tx_pool.token_id = token.token_id `
// selectPoolTxCommon select part of queries to get common.PoolL2Tx
const selectPoolTxCommon = `SELECT tx_pool.tx_id, from_idx, to_idx, tx_pool.to_eth_addr,
tx_pool.to_bjj, tx_pool.token_id, tx_pool.amount, tx_pool.fee, tx_pool.nonce,
tx_pool.state, tx_pool.signature, tx_pool.timestamp, rq_from_idx,
tx_pool.state, tx_pool.info, tx_pool.signature, tx_pool.timestamp, rq_from_idx,
rq_to_idx, tx_pool.rq_to_eth_addr, tx_pool.rq_to_bjj, tx_pool.rq_token_id, tx_pool.rq_amount,
tx_pool.rq_fee, tx_pool.rq_nonce, tx_pool.tx_type,
fee_percentage(tx_pool.fee::NUMERIC) * token.usd * tx_pool.amount_f AS fee_usd, token.usd_update

+ 24
- 0
db/l2db/l2db_test.go

@ -162,6 +162,30 @@ func TestAddTxTest(t *testing.T) {
assert.Equal(t, 0, offset)
}
}
func TestUpdateTxsInfo(t *testing.T) {
err := prepareHistoryDB(historyDB)
if err != nil {
log.Error("Error prepare historyDB", err)
}
poolL2Txs, err := generatePoolL2Txs()
assert.NoError(t, err)
for i := range poolL2Txs {
err := l2DB.AddTxTest(&poolL2Txs[i])
require.NoError(t, err)
// once added, change the Info parameter
poolL2Txs[i].Info = "test"
}
// update the txs
err = l2DB.UpdateTxsInfo(poolL2Txs)
require.NoError(t, err)
for i := range poolL2Txs {
fetchedTx, err := l2DB.GetTx(poolL2Txs[i].TxID)
assert.NoError(t, err)
assert.Equal(t, "test", fetchedTx.Info)
}
}
func assertTx(t *testing.T, expected, actual *common.PoolL2Tx) {
// Check that timestamp has been set within the last 3 seconds

+ 2
- 0
db/l2db/views.go

@ -49,6 +49,7 @@ type PoolTxAPI struct {
Fee common.FeeSelector `meddler:"fee"`
Nonce common.Nonce `meddler:"nonce"`
State common.PoolL2TxState `meddler:"state"`
Info *string `meddler:"info"`
Signature babyjub.SignatureComp `meddler:"signature"`
RqFromIdx *apitypes.HezIdx `meddler:"rq_from_idx"`
RqToIdx *apitypes.HezIdx `meddler:"rq_to_idx"`
@ -90,6 +91,7 @@ func (tx PoolTxAPI) MarshalJSON() ([]byte, error) {
"fee": tx.Fee,
"nonce": tx.Nonce,
"state": tx.State,
"info": tx.Info,
"signature": tx.Signature,
"timestamp": tx.Timestamp,
"batchNum": tx.BatchNum,

+ 1
- 0
db/migrations/0001.sql

@ -606,6 +606,7 @@ CREATE TABLE tx_pool (
fee SMALLINT NOT NULL,
nonce BIGINT NOT NULL,
state CHAR(4) NOT NULL,
info VARCHAR,
signature BYTEA NOT NULL,
timestamp TIMESTAMP WITHOUT TIME ZONE DEFAULT timezone('utc', now()),
batch_num BIGINT,

+ 13
- 5
test/zkproof/flows_test.go

@ -152,7 +152,7 @@ func TestTxSelectorBatchBuilderZKInputs(t *testing.T) {
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[i].Batch.ForgeL1TxsNum])
}
// TxSelector select the transactions for the next Batch
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
// BatchBuilder build Batch
zki, err := bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
@ -175,7 +175,7 @@ func TestTxSelectorBatchBuilderZKInputs(t *testing.T) {
addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
// TxSelector select the transactions for the next Batch
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
// BatchBuilder build Batch
zki, err := bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
@ -184,6 +184,8 @@ func TestTxSelectorBatchBuilderZKInputs(t *testing.T) {
sendProofAndCheckResp(t, zki)
err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.LocalAccountsDB().CurrentBatch())
require.NoError(t, err)
err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
require.NoError(t, err)
log.Debug("block:0 batch:8")
// simulate the PoolL2Txs of the batch8
@ -198,7 +200,7 @@ func TestTxSelectorBatchBuilderZKInputs(t *testing.T) {
addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
// TxSelector select the transactions for the next Batch
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
// BatchBuilder build Batch
zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
@ -207,6 +209,8 @@ func TestTxSelectorBatchBuilderZKInputs(t *testing.T) {
sendProofAndCheckResp(t, zki)
err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(l2Txs), txsel.LocalAccountsDB().CurrentBatch())
require.NoError(t, err)
err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
require.NoError(t, err)
log.Debug("(batch9) block:1 batch:1")
// simulate the PoolL2Txs of the batch9
@ -219,7 +223,7 @@ func TestTxSelectorBatchBuilderZKInputs(t *testing.T) {
addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
// TxSelector select the transactions for the next Batch
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
// BatchBuilder build Batch
zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
@ -228,12 +232,14 @@ func TestTxSelectorBatchBuilderZKInputs(t *testing.T) {
sendProofAndCheckResp(t, zki)
err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(l2Txs), txsel.LocalAccountsDB().CurrentBatch())
require.NoError(t, err)
err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
require.NoError(t, err)
log.Debug("(batch10) block:1 batch:2")
l2Txs = []common.PoolL2Tx{}
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[1].Batch.ForgeL1TxsNum])
// TxSelector select the transactions for the next Batch
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
// BatchBuilder build Batch
zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
@ -244,4 +250,6 @@ func TestTxSelectorBatchBuilderZKInputs(t *testing.T) {
sendProofAndCheckResp(t, zki)
err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(l2Txs), txsel.LocalAccountsDB().CurrentBatch())
require.NoError(t, err)
err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
require.NoError(t, err)
}

+ 8
- 5
txprocessor/txprocessor.go

@ -1300,16 +1300,19 @@ func (tp *TxProcessor) computeEffectiveAmounts(tx *common.L1Tx) {
}
// CheckEnoughBalance returns true if the sender of the transaction has enough
// balance in the account to send the Amount+Fee
func (tp *TxProcessor) CheckEnoughBalance(tx common.PoolL2Tx) bool {
// balance in the account to send the Amount+Fee, and also returns the account
// Balance and the Fee+Amount (which is used to give information about why the
// transaction is not selected in case that this method returns false.
func (tp *TxProcessor) CheckEnoughBalance(tx common.PoolL2Tx) (bool, *big.Int, *big.Int) {
acc, err := tp.s.GetAccount(tx.FromIdx)
if err != nil {
return false
return false, nil, nil
}
fee, err := common.CalcFeeAmount(tx.Amount, tx.Fee)
if err != nil {
return false
return false, nil, nil
}
feeAndAmount := new(big.Int).Add(tx.Amount, fee)
return acc.Balance.Cmp(feeAndAmount) != -1 // !=-1 balance<amount
return acc.Balance.Cmp(feeAndAmount) != -1, // !=-1 balance<amount
acc.Balance, feeAndAmount
}

+ 61
- 22
txselector/txselector.go

@ -143,11 +143,10 @@ func (txsel *TxSelector) coordAccountForTokenID(l1CoordinatorTxs []common.L1Tx,
// creation exists. The L1UserTxs, L1CoordinatorTxs, PoolL2Txs that will be
// included in the next batch.
func (txsel *TxSelector) GetL2TxSelection(selectionConfig *SelectionConfig) ([]common.Idx,
[][]byte, []common.L1Tx,
[]common.PoolL2Tx, error) {
coordIdxs, accCreationAuths, _, l1CoordinatorTxs, l2Txs, err :=
[][]byte, []common.L1Tx, []common.PoolL2Tx, []common.PoolL2Tx, error) {
coordIdxs, accCreationAuths, _, l1CoordinatorTxs, l2Txs, discardedL2Txs, err :=
txsel.GetL1L2TxSelection(selectionConfig, []common.L1Tx{})
return coordIdxs, accCreationAuths, l1CoordinatorTxs, l2Txs, tracerr.Wrap(err)
return coordIdxs, accCreationAuths, l1CoordinatorTxs, l2Txs, discardedL2Txs, tracerr.Wrap(err)
}
// GetL1L2TxSelection returns the selection of L1 + L2 txs.
@ -160,7 +159,7 @@ func (txsel *TxSelector) GetL2TxSelection(selectionConfig *SelectionConfig) ([]c
// included in the next batch.
func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
l1UserTxs []common.L1Tx) ([]common.Idx, [][]byte, []common.L1Tx,
[]common.L1Tx, []common.PoolL2Tx, error) {
[]common.L1Tx, []common.PoolL2Tx, []common.PoolL2Tx, error) {
// WIP.0: the TxSelector is not optimized and will need a redesign. The
// current version is implemented in order to have a functional
// implementation that can be used asap.
@ -173,7 +172,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
// get pending l2-tx from tx-pool
l2TxsRaw, err := txsel.l2db.GetPendingTxs()
if err != nil {
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
txselStateDB := txsel.localAccountsDB.StateDB
@ -184,10 +183,13 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
// assumption: l1usertx are sorted by L1Tx.Position
_, _, _, _, err := tp.ProcessL1Tx(nil, &l1UserTxs[i])
if err != nil {
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
}
// discardedL2Txs contains an array of the L2Txs that have not been selected in this Batch
var discardedL2Txs []common.PoolL2Tx
var l1CoordinatorTxs []common.L1Tx
positionL1 := len(l1UserTxs)
var accAuths [][]byte
@ -204,7 +206,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
for i := 0; i < len(l2Txs0); i++ {
accSender, err := tp.StateDB().GetAccount(l2Txs0[i].FromIdx)
if err != nil {
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
l2Txs0[i].TokenID = accSender.TokenID
// populate the noncesMap used at the next iteration
@ -220,12 +222,15 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
txsel.coordAccountForTokenID(l1CoordinatorTxs,
accSender.TokenID, positionL1)
if err != nil {
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
if newL1CoordTx != nil {
// if there is no space for the L1CoordinatorTx, discard the L2Tx
if len(l1CoordinatorTxs) >= int(selectionConfig.MaxL1UserTxs)-len(l1UserTxs) {
// discard L2Tx
// discard L2Tx, and update Info parameter of
// the tx, and add it to the discardedTxs array
l2Txs0[i].Info = "Tx not selected due the L2Tx depends on a L1CoordinatorTx and there is not enough space for L1Coordinator"
discardedL2Txs = append(discardedL2Txs, l2Txs0[i])
continue
}
// increase positionL1
@ -244,8 +249,13 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
// - keep used accAuths
// - put the valid txs into validTxs array
for i := 0; i < len(l2Txs); i++ {
if !tp.CheckEnoughBalance(l2Txs[i]) {
// not valid Amount with current Balance
enoughBalance, balance, feeAndAmount := tp.CheckEnoughBalance(l2Txs[i])
if !enoughBalance {
// not valid Amount with current Balance. Discard L2Tx,
// and update Info parameter of the tx, and add it to
// the discardedTxs array
l2Txs[i].Info = fmt.Sprintf("Tx not selected due not enough Balance at the sender. Current sender account Balance: %s, Amount+Fee: %s", balance.String(), feeAndAmount.String())
discardedL2Txs = append(discardedL2Txs, l2Txs[i])
continue
}
// check if Nonce is correct
@ -253,7 +263,11 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
if l2Txs[i].Nonce == nonce {
noncesMap[l2Txs[i].FromIdx]++
} else {
// not valid Nonce at tx
// not valid Nonce at tx. Discard L2Tx, and update Info
// parameter of the tx, and add it to the discardedTxs
// array
l2Txs[i].Info = fmt.Sprintf("Tx not selected due not current Nonce. Tx.Nonce: %d, Account.Nonce: %d", l2Txs[i].Nonce, nonce)
discardedL2Txs = append(discardedL2Txs, l2Txs[i])
continue
}
@ -271,6 +285,10 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
len(l1UserTxs), l1CoordinatorTxs, positionL1, l2Txs[i])
if err != nil {
log.Debug(err)
// Discard L2Tx, and update Info parameter of
// the tx, and add it to the discardedTxs array
l2Txs[i].Info = fmt.Sprintf("Tx not selected (in processTxToEthAddrBJJ) due %s", err.Error())
discardedL2Txs = append(discardedL2Txs, l2Txs[i])
continue
}
if accAuth != nil && l1CoordinatorTx != nil {
@ -287,13 +305,24 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
// tx not valid
log.Debugw("invalid L2Tx: ToIdx not found in StateDB",
"ToIdx", l2Txs[i].ToIdx)
// Discard L2Tx, and update Info parameter of
// the tx, and add it to the discardedTxs array
l2Txs[i].Info = fmt.Sprintf("Tx not selected due tx.ToIdx not found in StateDB. ToIdx: %d",
l2Txs[i].ToIdx)
discardedL2Txs = append(discardedL2Txs, l2Txs[i])
continue
}
if l2Txs[i].ToEthAddr != common.EmptyAddr {
if l2Txs[i].ToEthAddr != receiverAcc.EthAddr {
log.Debugw("invalid L2Tx: ToEthAddr does not correspond to the Account.EthAddr",
"ToIdx", l2Txs[i].ToIdx, "tx.ToEthAddr", l2Txs[i].ToEthAddr,
"account.EthAddr", receiverAcc.EthAddr)
"ToIdx", l2Txs[i].ToIdx, "tx.ToEthAddr",
l2Txs[i].ToEthAddr, "account.EthAddr", receiverAcc.EthAddr)
// Discard L2Tx, and update Info
// parameter of the tx, and add it to
// the discardedTxs array
l2Txs[i].Info = fmt.Sprintf("Tx not selected due ToEthAddr does not correspond to the Account.EthAddr. tx.ToIdx: %d, tx.ToEthAddr: %s, account.EthAddr: %s",
l2Txs[i].ToIdx, l2Txs[i].ToEthAddr, receiverAcc.EthAddr)
discardedL2Txs = append(discardedL2Txs, l2Txs[i])
continue
}
}
@ -302,6 +331,12 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
log.Debugw("invalid L2Tx: ToBJJ does not correspond to the Account.BJJ",
"ToIdx", l2Txs[i].ToIdx, "tx.ToEthAddr", l2Txs[i].ToBJJ,
"account.BJJ", receiverAcc.BJJ)
// Discard L2Tx, and update Info
// parameter of the tx, and add it to
// the discardedTxs array
l2Txs[i].Info = fmt.Sprintf("Tx not selected due tx.ToBJJ does not correspond to the Account.BJJ. tx.ToIdx: %d, tx.ToEthAddr: %s, tx.ToBJJ: %s, account.BJJ: %s",
l2Txs[i].ToIdx, l2Txs[i].ToEthAddr, l2Txs[i].ToBJJ, receiverAcc.BJJ)
discardedL2Txs = append(discardedL2Txs, l2Txs[i])
continue
}
}
@ -318,7 +353,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
for i := 0; i < len(l1CoordinatorTxs); i++ {
_, _, _, _, err := tp.ProcessL1Tx(nil, &l1CoordinatorTxs[i])
if err != nil {
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
}
@ -328,7 +363,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
// get TokenID from tx.Sender
accSender, err := tp.StateDB().GetAccount(validTxs[i].FromIdx)
if err != nil {
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
tokenID := accSender.TokenID
@ -337,7 +372,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
// if err is db.ErrNotFound, should not happen, as all
// the validTxs.TokenID should have a CoordinatorIdx
// created in the DB at this point
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
coordIdxsMap[tokenID] = coordIdx
}
@ -371,6 +406,10 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
// log the error, assuming that this will be iterated
// in a near future.
log.Error(err)
// Discard L2Tx, and update Info parameter of the tx,
// and add it to the discardedTxs array
selectedL2Txs[i].Info = fmt.Sprintf("Tx not selected (in ProcessL2Tx) due %s", err.Error())
discardedL2Txs = append(discardedL2Txs, selectedL2Txs[i])
continue
}
finalL2Txs = append(finalL2Txs, selectedL2Txs[i])
@ -385,23 +424,23 @@ func (txsel *TxSelector) GetL1L2TxSelection(selectionConfig *SelectionConfig,
accCoord, err := txsel.localAccountsDB.GetAccount(idx)
if err != nil {
log.Errorw("Can not distribute accumulated fees to coordinator account: No coord Idx to receive fee", "idx", idx)
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
accCoord.Balance = new(big.Int).Add(accCoord.Balance, accumulatedFee)
_, err = txsel.localAccountsDB.UpdateAccount(idx, accCoord)
if err != nil {
log.Error(err)
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
}
}
err = tp.StateDB().MakeCheckpoint()
if err != nil {
return nil, nil, nil, nil, nil, tracerr.Wrap(err)
return nil, nil, nil, nil, nil, nil, tracerr.Wrap(err)
}
return coordIdxs, accAuths, l1UserTxs, l1CoordinatorTxs, finalL2Txs, nil
return coordIdxs, accAuths, l1UserTxs, l1CoordinatorTxs, finalL2Txs, discardedL2Txs, nil
}
// processTxsToEthAddrBJJ process the common.PoolL2Tx in the case where

+ 27
- 13
txselector/txselector_test.go

@ -177,7 +177,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
log.Debug("block:0 batch:1")
l1UserTxs := []common.L1Tx{}
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, 0, len(oL1UserTxs))
assert.Equal(t, 0, len(oL1CoordTxs))
@ -187,7 +187,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
log.Debug("block:0 batch:2")
l1UserTxs = []common.L1Tx{}
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, 0, len(oL1UserTxs))
assert.Equal(t, 0, len(oL1CoordTxs))
@ -197,7 +197,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
log.Debug("block:0 batch:3")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, 2, len(oL1UserTxs))
assert.Equal(t, 0, len(oL1CoordTxs))
@ -209,7 +209,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
log.Debug("block:0 batch:4")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, 1, len(oL1UserTxs))
assert.Equal(t, 0, len(oL1CoordTxs))
@ -222,7 +222,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
log.Debug("block:0 batch:5")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, 0, len(oL1UserTxs))
assert.Equal(t, 0, len(oL1CoordTxs))
@ -235,7 +235,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
log.Debug("block:0 batch:6")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, 1, len(oL1UserTxs))
assert.Equal(t, 0, len(oL1CoordTxs))
@ -268,7 +268,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, []common.Idx{261, 262}, coordIdxs)
assert.Equal(t, txsel.coordAccount.AccountCreationAuth, accAuths[0])
@ -314,7 +314,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
assert.True(t, l2TxsFromDB[2].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
assert.True(t, l2TxsFromDB[3].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, []common.Idx{261, 262}, coordIdxs)
assert.Equal(t, 0, len(accAuths))
@ -355,7 +355,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["D"].BJJ.Public().Compress()))
assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, []common.Idx{262}, coordIdxs)
assert.Equal(t, 0, len(accAuths))
@ -420,9 +420,13 @@ func TestPoolL2TxsWithoutEnoughBalance(t *testing.T) {
}
// batch1
l1UserTxs := []common.L1Tx{}
_, _, _, _, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, _, _, _, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
expectedTxID0 := "0x0248bae02b5c8c3847d312bfac3a33ae790616e888f2f711f22aeaff007cde92c2" // 1st TransferToEthAddr
expectedTxID1 := "0x0249af018311a393c337ab9174ca2466cba489e49942b4ca4e5c530903671c4aef" // 1st Exit
expectedTxID2 := "0x0228b93a261a0cdc62f35588c03bd179d31a0807c28afffdb6a7aaf0c4f017e4cf" // 2nd TransferToEthAddr
// batch2
// prepare the PoolL2Txs
batchPoolL2 := `
@ -435,11 +439,14 @@ func TestPoolL2TxsWithoutEnoughBalance(t *testing.T) {
addL2Txs(t, txsel, poolL2Txs)
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, 3, len(oL1UserTxs))
assert.Equal(t, 0, len(oL1CoordTxs))
assert.Equal(t, 0, len(oL2Txs)) // should be 0 as the 2 PoolL2Txs does not have enough funds
assert.Equal(t, 2, len(discardedL2Txs))
assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
assert.Equal(t, expectedTxID1, discardedL2Txs[1].TxID.String())
err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
require.NoError(t, err)
@ -460,11 +467,15 @@ func TestPoolL2TxsWithoutEnoughBalance(t *testing.T) {
addL2Txs(t, txsel, poolL2Txs)
l1UserTxs = []common.L1Tx{}
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, 0, len(oL1UserTxs))
assert.Equal(t, 0, len(oL1CoordTxs))
assert.Equal(t, 1, len(oL2Txs)) // see 'NOTE' at the beginning of 'batch3' of this test
assert.Equal(t, 2, len(discardedL2Txs))
assert.Equal(t, expectedTxID2, oL2Txs[0].TxID.String())
assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
assert.Equal(t, expectedTxID1, discardedL2Txs[1].TxID.String())
assert.Equal(t, common.TxTypeTransferToEthAddr, oL2Txs[0].Type)
err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
require.NoError(t, err)
@ -473,11 +484,14 @@ func TestPoolL2TxsWithoutEnoughBalance(t *testing.T) {
// make the selection of another batch, which should include the
// initial PoolExit, which now is valid as B has enough Balance
l1UserTxs = []common.L1Tx{}
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
_, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
require.NoError(t, err)
assert.Equal(t, 0, len(oL1UserTxs))
assert.Equal(t, 0, len(oL1CoordTxs))
assert.Equal(t, 1, len(oL2Txs))
assert.Equal(t, 1, len(discardedL2Txs))
assert.Equal(t, expectedTxID1, oL2Txs[0].TxID.String()) // the Exit that was not accepted at the batch2
assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
assert.Equal(t, common.TxTypeExit, oL2Txs[0].Type)
err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
require.NoError(t, err)

Loading…
Cancel
Save