Browse Source

Test purger, fix some nonces

- Test all the purger functions
- Fix nonces set by til (previously til started with nonce 1 for pool l2txs,
  but the correct implementation is to start with nonce 0)
- Rename L2DB.CheckNonces to L2DB.invalidateOldNoncesQuery
- Rename L2DB.checkNoncesQuery to L2DB.InvalidateOldNonces

Related https://github.com/hermeznetwork/hermez-node/issues/392 (Fix checkNoncesQuery)
Resolve https://github.com/hermeznetwork/hermez-node/issues/396
feature/sql-semaphore1
Eduard S 3 years ago
parent
commit
a8ac35059a
8 changed files with 325 additions and 49 deletions
  1. +2
    -3
      coordinator/coordinator.go
  2. +1
    -3
      coordinator/coordinator_test.go
  3. +5
    -15
      coordinator/purger.go
  4. +285
    -1
      coordinator/purger_test.go
  5. +8
    -6
      db/l2db/l2db.go
  6. +16
    -13
      db/l2db/l2db_test.go
  7. +2
    -2
      test/til/txs.go
  8. +6
    -6
      test/til/txs_test.go

+ 2
- 3
coordinator/coordinator.go

@ -245,7 +245,7 @@ func (c *Coordinator) syncStats(ctx context.Context, stats *synchronizer.Stats)
if c.pipeline == nil { if c.pipeline == nil {
// Mark invalid in Pool due to forged L2Txs // Mark invalid in Pool due to forged L2Txs
// for _, batch := range batches { // for _, batch := range batches {
// if err := poolMarkInvalidOldNoncesFromL2Txs(c.l2DB,
// if err := c.l2DB.InvalidateOldNonces(
// idxsNonceFromL2Txs(batch.L2Txs), batch.Batch.BatchNum); err != nil { // idxsNonceFromL2Txs(batch.L2Txs), batch.Batch.BatchNum); err != nil {
// return err // return err
// } // }
@ -850,8 +850,7 @@ func (p *Pipeline) forgeBatch(ctx context.Context, batchNum common.BatchNum, sel
// the poolL2Txs selected. Will mark as invalid the txs that have a // the poolL2Txs selected. Will mark as invalid the txs that have a
// (fromIdx, nonce) which already appears in the selected txs (includes // (fromIdx, nonce) which already appears in the selected txs (includes
// all the nonces smaller than the current one) // all the nonces smaller than the current one)
err = poolMarkInvalidOldNoncesFromL2Txs(p.l2DB, idxsNonceFromPoolL2Txs(poolL2Txs),
batchInfo.BatchNum)
err = p.l2DB.InvalidateOldNonces(idxsNonceFromPoolL2Txs(poolL2Txs), batchInfo.BatchNum)
if err != nil { if err != nil {
return nil, tracerr.Wrap(err) return nil, tracerr.Wrap(err)
} }

+ 1
- 3
coordinator/coordinator_test.go

@ -92,13 +92,11 @@ var nLevels uint32 = 32 //nolint:deadcode,unused
var maxFeeTxs uint32 = 64 //nolint:deadcode,varcheck var maxFeeTxs uint32 = 64 //nolint:deadcode,varcheck
func newTestModules(t *testing.T) modules { func newTestModules(t *testing.T) modules {
nLevels := 32
var err error var err error
syncDBPath, err = ioutil.TempDir("", "tmpSyncDB") syncDBPath, err = ioutil.TempDir("", "tmpSyncDB")
require.NoError(t, err) require.NoError(t, err)
deleteme = append(deleteme, syncDBPath) deleteme = append(deleteme, syncDBPath)
syncStateDB, err := statedb.NewStateDB(syncDBPath, statedb.TypeSynchronizer, nLevels)
syncStateDB, err := statedb.NewStateDB(syncDBPath, statedb.TypeSynchronizer, 48)
assert.NoError(t, err) assert.NoError(t, err)
pass := os.Getenv("POSTGRES_PASS") pass := os.Getenv("POSTGRES_PASS")

+ 5
- 15
coordinator/purger.go

@ -35,10 +35,10 @@ type Purger struct {
// CanPurge returns true if it's a good time to purge according to the // CanPurge returns true if it's a good time to purge according to the
// configuration // configuration
func (p *Purger) CanPurge(blockNum, batchNum int64) bool { func (p *Purger) CanPurge(blockNum, batchNum int64) bool {
if blockNum > p.lastPurgeBlock+p.cfg.PurgeBlockDelay {
if blockNum >= p.lastPurgeBlock+p.cfg.PurgeBlockDelay {
return true return true
} }
if batchNum > p.lastPurgeBatch+p.cfg.PurgeBatchDelay {
if batchNum >= p.lastPurgeBatch+p.cfg.PurgeBatchDelay {
return true return true
} }
return false return false
@ -47,10 +47,10 @@ func (p *Purger) CanPurge(blockNum, batchNum int64) bool {
// CanInvalidate returns true if it's a good time to invalidate according to // CanInvalidate returns true if it's a good time to invalidate according to
// the configuration // the configuration
func (p *Purger) CanInvalidate(blockNum, batchNum int64) bool { func (p *Purger) CanInvalidate(blockNum, batchNum int64) bool {
if blockNum > p.lastInvalidateBlock+p.cfg.InvalidateBlockDelay {
if blockNum >= p.lastInvalidateBlock+p.cfg.InvalidateBlockDelay {
return true return true
} }
if batchNum > p.lastInvalidateBatch+p.cfg.InvalidateBatchDelay {
if batchNum >= p.lastInvalidateBatch+p.cfg.InvalidateBatchDelay {
return true return true
} }
return false return false
@ -114,15 +114,6 @@ func idxsNonceFromPoolL2Txs(txs []common.PoolL2Tx) []common.IdxNonce {
return idxsNonce return idxsNonce
} }
// poolMarkInvalidOldNoncesFromL2Txs marks as invalid the txs in the pool that
// contain nonces equal or older to the highest nonce used in a forged l2Tx for
// the
// corresponding sender account
func poolMarkInvalidOldNoncesFromL2Txs(l2DB *l2db.L2DB,
idxsNonce []common.IdxNonce, batchNum common.BatchNum) error {
return l2DB.CheckNonces(idxsNonce, batchNum)
}
// poolMarkInvalidOldNonces marks as invalid txs in the pool that contain // poolMarkInvalidOldNonces marks as invalid txs in the pool that contain
// nonces equal or older to the nonce of the corresponding sender account // nonces equal or older to the nonce of the corresponding sender account
func poolMarkInvalidOldNonces(l2DB *l2db.L2DB, stateDB *statedb.LocalStateDB, func poolMarkInvalidOldNonces(l2DB *l2db.L2DB, stateDB *statedb.LocalStateDB,
@ -147,9 +138,8 @@ func poolMarkInvalidOldNonces(l2DB *l2db.L2DB, stateDB *statedb.LocalStateDB,
return tracerr.Wrap(fmt.Errorf("unexpected stateDB error with idx %v: %w", idx, err)) return tracerr.Wrap(fmt.Errorf("unexpected stateDB error with idx %v: %w", idx, err))
} }
} }
fmt.Printf("DBG acc: %#v\n", acc)
idxsNonce[i].Idx = idx idxsNonce[i].Idx = idx
idxsNonce[i].Nonce = acc.Nonce idxsNonce[i].Nonce = acc.Nonce
} }
return l2DB.CheckNonces(idxsNonce, batchNum)
return l2DB.InvalidateOldNonces(idxsNonce, batchNum)
} }

+ 285
- 1
coordinator/purger_test.go

@ -1,3 +1,287 @@
package coordinator package coordinator
// TODO: Test purger functions
import (
"io/ioutil"
"os"
"testing"
"time"
"github.com/hermeznetwork/hermez-node/common"
dbUtils "github.com/hermeznetwork/hermez-node/db"
"github.com/hermeznetwork/hermez-node/db/l2db"
"github.com/hermeznetwork/hermez-node/db/statedb"
"github.com/hermeznetwork/hermez-node/test"
"github.com/hermeznetwork/hermez-node/test/til"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func newL2DB(t *testing.T) *l2db.L2DB {
pass := os.Getenv("POSTGRES_PASS")
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
require.NoError(t, err)
test.WipeDB(db)
return l2db.NewL2DB(db, 10, 100, 24*time.Hour)
}
func newStateDB(t *testing.T) *statedb.LocalStateDB {
syncDBPath, err := ioutil.TempDir("", "tmpSyncDB")
require.NoError(t, err)
deleteme = append(deleteme, syncDBPath)
syncStateDB, err := statedb.NewStateDB(syncDBPath, statedb.TypeSynchronizer, 48)
assert.NoError(t, err)
stateDBPath, err := ioutil.TempDir("", "tmpStateDB")
require.NoError(t, err)
deleteme = append(deleteme, stateDBPath)
stateDB, err := statedb.NewLocalStateDB(stateDBPath, syncStateDB, statedb.TypeTxSelector, 0)
require.NoError(t, err)
return stateDB
}
func TestCanPurgeCanInvalidate(t *testing.T) {
cfg := PurgerCfg{
PurgeBatchDelay: 2,
PurgeBlockDelay: 6,
InvalidateBatchDelay: 4,
InvalidateBlockDelay: 8,
}
p := Purger{
cfg: cfg,
}
startBlockNum := int64(1000)
startBatchNum := int64(10)
blockNum := startBlockNum
batchNum := startBatchNum
assert.True(t, p.CanPurge(blockNum, batchNum))
p.lastPurgeBlock = startBlockNum
p.lastPurgeBatch = startBatchNum
assert.False(t, p.CanPurge(blockNum, batchNum))
blockNum = startBlockNum + cfg.PurgeBlockDelay - 1
batchNum = startBatchNum + cfg.PurgeBatchDelay - 1
assert.False(t, p.CanPurge(blockNum, batchNum))
blockNum = startBlockNum + cfg.PurgeBlockDelay - 1
batchNum = startBatchNum + cfg.PurgeBatchDelay
assert.True(t, p.CanPurge(blockNum, batchNum))
blockNum = startBlockNum + cfg.PurgeBlockDelay
batchNum = startBatchNum + cfg.PurgeBatchDelay - 1
assert.True(t, p.CanPurge(blockNum, batchNum))
assert.True(t, p.CanInvalidate(blockNum, batchNum))
p.lastInvalidateBlock = startBlockNum
p.lastInvalidateBatch = startBatchNum
assert.False(t, p.CanInvalidate(blockNum, batchNum))
blockNum = startBlockNum + cfg.InvalidateBlockDelay - 1
batchNum = startBatchNum + cfg.InvalidateBatchDelay - 1
assert.False(t, p.CanInvalidate(blockNum, batchNum))
blockNum = startBlockNum + cfg.InvalidateBlockDelay - 1
batchNum = startBatchNum + cfg.InvalidateBatchDelay
assert.True(t, p.CanInvalidate(blockNum, batchNum))
blockNum = startBlockNum + cfg.InvalidateBlockDelay
batchNum = startBatchNum + cfg.InvalidateBatchDelay - 1
assert.True(t, p.CanInvalidate(blockNum, batchNum))
}
func TestPurgeMaybeInvalidateMaybe(t *testing.T) {
cfg := PurgerCfg{
PurgeBatchDelay: 2,
PurgeBlockDelay: 6,
InvalidateBatchDelay: 4,
InvalidateBlockDelay: 8,
}
p := Purger{
cfg: cfg,
}
l2DB := newL2DB(t)
stateDB := newStateDB(t)
startBlockNum := int64(1000)
startBatchNum := int64(10)
p.lastPurgeBlock = startBlockNum
p.lastPurgeBatch = startBatchNum
blockNum := startBlockNum + cfg.PurgeBlockDelay - 1
batchNum := startBatchNum + cfg.PurgeBatchDelay - 1
ok, err := p.PurgeMaybe(l2DB, blockNum, batchNum)
require.NoError(t, err)
assert.False(t, ok)
// At this point the purger will purge. The second time it doesn't
// because it the first time it has updates the last time it did.
blockNum = startBlockNum + cfg.PurgeBlockDelay - 1
batchNum = startBatchNum + cfg.PurgeBatchDelay
ok, err = p.PurgeMaybe(l2DB, blockNum, batchNum)
require.NoError(t, err)
assert.True(t, ok)
ok, err = p.PurgeMaybe(l2DB, blockNum, batchNum)
require.NoError(t, err)
assert.False(t, ok)
p.lastInvalidateBlock = startBlockNum
p.lastInvalidateBatch = startBatchNum
blockNum = startBlockNum + cfg.InvalidateBlockDelay - 1
batchNum = startBatchNum + cfg.InvalidateBatchDelay - 1
ok, err = p.InvalidateMaybe(l2DB, stateDB, blockNum, batchNum)
require.NoError(t, err)
assert.False(t, ok)
// At this point the purger will invaidate. The second time it doesn't
// because it the first time it has updates the last time it did.
blockNum = startBlockNum + cfg.InvalidateBlockDelay - 1
batchNum = startBatchNum + cfg.InvalidateBatchDelay
ok, err = p.InvalidateMaybe(l2DB, stateDB, blockNum, batchNum)
require.NoError(t, err)
assert.True(t, ok)
ok, err = p.InvalidateMaybe(l2DB, stateDB, blockNum, batchNum)
require.NoError(t, err)
assert.False(t, ok)
}
func TestIdxsNonce(t *testing.T) {
inputIdxsNonce := []common.IdxNonce{
{Idx: 256, Nonce: 1},
{Idx: 256, Nonce: 2},
{Idx: 257, Nonce: 3},
{Idx: 258, Nonce: 5},
{Idx: 258, Nonce: 2},
}
expectedIdxsNonce := map[common.Idx]common.Nonce{
common.Idx(256): common.Nonce(2),
common.Idx(257): common.Nonce(3),
common.Idx(258): common.Nonce(5),
}
l2txs := make([]common.L2Tx, len(inputIdxsNonce))
for i, idxNonce := range inputIdxsNonce {
l2txs[i].FromIdx = idxNonce.Idx
l2txs[i].Nonce = idxNonce.Nonce
}
idxsNonce := idxsNonceFromL2Txs(l2txs)
assert.Equal(t, len(expectedIdxsNonce), len(idxsNonce))
for _, idxNonce := range idxsNonce {
nonce := expectedIdxsNonce[idxNonce.Idx]
assert.Equal(t, nonce, idxNonce.Nonce)
}
pooll2txs := make([]common.PoolL2Tx, len(inputIdxsNonce))
for i, idxNonce := range inputIdxsNonce {
pooll2txs[i].FromIdx = idxNonce.Idx
pooll2txs[i].Nonce = idxNonce.Nonce
}
idxsNonce = idxsNonceFromPoolL2Txs(pooll2txs)
assert.Equal(t, len(expectedIdxsNonce), len(idxsNonce))
for _, idxNonce := range idxsNonce {
nonce := expectedIdxsNonce[idxNonce.Idx]
assert.Equal(t, nonce, idxNonce.Nonce)
}
}
func TestPoolMarkInvalidOldNonces(t *testing.T) {
l2DB := newL2DB(t)
stateDB := newStateDB(t)
set0 := `
Type: Blockchain
CreateAccountDeposit(0) A: 1000 // Idx=256
CreateAccountDeposit(0) B: 1000 // Idx=257
CreateAccountDeposit(0) C: 1000 // Idx=258
CreateAccountDeposit(0) D: 1000 // Idx=259
> batchL1
> batchL1
> block
`
tc := til.NewContext(common.RollupConstMaxL1UserTx)
blocks, err := tc.GenerateBlocks(set0)
require.NoError(t, err)
tilCfgExtra := til.ConfigExtra{
CoordUser: "A",
}
// Call FillBlocksExtra to fill `Batch.CreatedAccounts`
err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
require.NoError(t, err)
require.Equal(t, 4, len(blocks[0].Rollup.Batches[1].CreatedAccounts)) // sanity check
for _, acc := range blocks[0].Rollup.Batches[1].CreatedAccounts {
_, err := stateDB.CreateAccount(acc.Idx, &acc) //nolint:gosec
require.NoError(t, err)
}
setPool0 := `
Type: PoolL2
PoolTransfer(0) A-B: 10 (1)
PoolTransfer(0) A-C: 10 (1)
PoolTransfer(0) A-D: 10 (1)
PoolTransfer(0) B-A: 10 (1)
PoolTransfer(0) B-C: 10 (1)
PoolTransfer(0) C-A: 10 (1)
`
// We expect the following nonces
nonces0 := map[string]int64{"A": 3, "B": 2, "C": 1, "D": 0}
l2txs0, err := tc.GeneratePoolL2Txs(setPool0)
assert.Nil(t, err)
assert.Equal(t, 6, len(l2txs0))
for _, tx := range l2txs0 {
require.NoError(t, l2DB.AddTxTest(&tx)) //nolint:gosec
}
// Update the accounts in the StateDB, making the txs in the setPool0
// invalid
for name, user := range tc.Users {
for _, _acc := range user.Accounts {
require.Equal(t, common.Nonce(nonces0[name]), _acc.Nonce) // sanity check
acc, err := stateDB.GetAccount(_acc.Idx)
require.NoError(t, err)
require.Equal(t, common.Nonce(0), acc.Nonce) // sanity check
acc.Nonce = _acc.Nonce
_, err = stateDB.UpdateAccount(acc.Idx, acc)
require.NoError(t, err)
}
}
setPool1 := `
Type: PoolL2
PoolTransfer(0) A-B: 10 (1)
PoolTransfer(0) A-C: 10 (1)
PoolTransfer(0) A-D: 10 (1)
PoolTransfer(0) B-A: 10 (1)
PoolTransfer(0) B-C: 10 (1)
PoolTransfer(0) C-A: 10 (1)
`
// We expect the following nonces
nonces1 := map[string]int64{"A": 6, "B": 4, "C": 2, "D": 0}
l2txs1, err := tc.GeneratePoolL2Txs(setPool1)
require.NoError(t, err)
assert.Equal(t, 6, len(l2txs1))
for _, tx := range l2txs1 {
require.NoError(t, l2DB.AddTxTest(&tx)) //nolint:gosec
}
for name, user := range tc.Users {
for _, _acc := range user.Accounts {
require.Equal(t, common.Nonce(nonces1[name]), _acc.Nonce) // sanity check
acc, err := stateDB.GetAccount(_acc.Idx)
require.NoError(t, err)
require.Equal(t, common.Nonce(nonces0[name]), acc.Nonce) // sanity check
}
}
// Now we should have 12 txs in the pool, all marked as pending. Since
// we updated the stateDB with the nonces after setPool0, the first 6
// txs will be marked as invalid
pendingTxs, err := l2DB.GetPendingTxs()
require.NoError(t, err)
assert.Equal(t, 12, len(pendingTxs))
batchNum := common.BatchNum(1)
err = poolMarkInvalidOldNonces(l2DB, stateDB, batchNum)
require.NoError(t, err)
pendingTxs, err = l2DB.GetPendingTxs()
require.NoError(t, err)
assert.Equal(t, 6, len(pendingTxs))
}

+ 8
- 6
db/l2db/l2db.go

@ -268,7 +268,7 @@ func (l2db *L2DB) GetPendingUniqueFromIdxs() ([]common.Idx, error) {
return idxs, nil return idxs, nil
} }
var checkNoncesQuery = fmt.Sprintf(`
var invalidateOldNoncesQuery = fmt.Sprintf(`
UPDATE tx_pool SET UPDATE tx_pool SET
state = '%s', state = '%s',
batch_num = %%d batch_num = %%d
@ -276,20 +276,22 @@ var checkNoncesQuery = fmt.Sprintf(`
(NULL::::BIGINT, NULL::::BIGINT), (NULL::::BIGINT, NULL::::BIGINT),
(:idx, :nonce) (:idx, :nonce)
) as updated_acc (idx, nonce) ) as updated_acc (idx, nonce)
WHERE tx_pool.from_idx = updated_acc.idx AND tx_pool.nonce <= updated_acc.nonce;
`, common.PoolL2TxStateInvalid)
WHERE tx_pool.state = '%s' AND
tx_pool.from_idx = updated_acc.idx AND
tx_pool.nonce < updated_acc.nonce;
`, common.PoolL2TxStateInvalid, common.PoolL2TxStatePending)
// CheckNonces invalidate txs with nonces that are smaller or equal than their
// InvalidateOldNonces invalidate txs with nonces that are smaller or equal than their
// respective accounts nonces. The state of the affected txs will be changed // respective accounts nonces. The state of the affected txs will be changed
// from Pending to Invalid // from Pending to Invalid
func (l2db *L2DB) CheckNonces(updatedAccounts []common.IdxNonce, batchNum common.BatchNum) (err error) {
func (l2db *L2DB) InvalidateOldNonces(updatedAccounts []common.IdxNonce, batchNum common.BatchNum) (err error) {
if len(updatedAccounts) == 0 { if len(updatedAccounts) == 0 {
return nil return nil
} }
// Fill the batch_num in the query with Sprintf because we are using a // Fill the batch_num in the query with Sprintf because we are using a
// named query which works with slices, and doens't handle an extra // named query which works with slices, and doens't handle an extra
// individual argument. // individual argument.
query := fmt.Sprintf(checkNoncesQuery, batchNum)
query := fmt.Sprintf(invalidateOldNoncesQuery, batchNum)
if _, err := sqlx.NamedExec(l2db.db, query, updatedAccounts); err != nil { if _, err := sqlx.NamedExec(l2db.db, query, updatedAccounts); err != nil {
return tracerr.Wrap(err) return tracerr.Wrap(err)
} }

+ 16
- 13
db/l2db/l2db_test.go

@ -16,6 +16,7 @@ import (
"github.com/hermeznetwork/hermez-node/test/til" "github.com/hermeznetwork/hermez-node/test/til"
"github.com/hermeznetwork/tracerr" "github.com/hermeznetwork/tracerr"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var l2DB *L2DB var l2DB *L2DB
@ -217,7 +218,7 @@ func TestGetPending(t *testing.T) {
func TestStartForging(t *testing.T) { func TestStartForging(t *testing.T) {
// Generate txs // Generate txs
const fakeBatchNum common.BatchNum = 33
var fakeBatchNum common.BatchNum = 33
err := prepareHistoryDB(historyDB) err := prepareHistoryDB(historyDB)
if err != nil { if err != nil {
log.Error("Error prepare historyDB", err) log.Error("Error prepare historyDB", err)
@ -243,13 +244,13 @@ func TestStartForging(t *testing.T) {
fetchedTx, err := l2DB.GetTxAPI(id) fetchedTx, err := l2DB.GetTxAPI(id)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, common.PoolL2TxStateForging, fetchedTx.State) assert.Equal(t, common.PoolL2TxStateForging, fetchedTx.State)
assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
assert.Equal(t, &fakeBatchNum, fetchedTx.BatchNum)
} }
} }
func TestDoneForging(t *testing.T) { func TestDoneForging(t *testing.T) {
// Generate txs // Generate txs
const fakeBatchNum common.BatchNum = 33
var fakeBatchNum common.BatchNum = 33
err := prepareHistoryDB(historyDB) err := prepareHistoryDB(historyDB)
if err != nil { if err != nil {
log.Error("Error prepare historyDB", err) log.Error("Error prepare historyDB", err)
@ -288,13 +289,13 @@ func TestDoneForging(t *testing.T) {
fetchedTx, err := l2DB.GetTxAPI(id) fetchedTx, err := l2DB.GetTxAPI(id)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, common.PoolL2TxStateForged, fetchedTx.State) assert.Equal(t, common.PoolL2TxStateForged, fetchedTx.State)
assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
assert.Equal(t, &fakeBatchNum, fetchedTx.BatchNum)
} }
} }
func TestInvalidate(t *testing.T) { func TestInvalidate(t *testing.T) {
// Generate txs // Generate txs
const fakeBatchNum common.BatchNum = 33
var fakeBatchNum common.BatchNum = 33
err := prepareHistoryDB(historyDB) err := prepareHistoryDB(historyDB)
if err != nil { if err != nil {
log.Error("Error prepare historyDB", err) log.Error("Error prepare historyDB", err)
@ -320,13 +321,13 @@ func TestInvalidate(t *testing.T) {
fetchedTx, err := l2DB.GetTxAPI(id) fetchedTx, err := l2DB.GetTxAPI(id)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State) assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
assert.Equal(t, &fakeBatchNum, fetchedTx.BatchNum)
} }
} }
func TestCheckNonces(t *testing.T) {
func TestInvalidateOldNonces(t *testing.T) {
// Generate txs // Generate txs
const fakeBatchNum common.BatchNum = 33
var fakeBatchNum common.BatchNum = 33
err := prepareHistoryDB(historyDB) err := prepareHistoryDB(historyDB)
if err != nil { if err != nil {
log.Error("Error prepare historyDB", err) log.Error("Error prepare historyDB", err)
@ -335,7 +336,7 @@ func TestCheckNonces(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// Update Accounts currentNonce // Update Accounts currentNonce
var updateAccounts []common.IdxNonce var updateAccounts []common.IdxNonce
const currentNonce = common.Nonce(1)
var currentNonce = common.Nonce(1)
for i := range accs { for i := range accs {
updateAccounts = append(updateAccounts, common.IdxNonce{ updateAccounts = append(updateAccounts, common.IdxNonce{
Idx: accs[i].Idx, Idx: accs[i].Idx,
@ -345,21 +346,23 @@ func TestCheckNonces(t *testing.T) {
// Add txs to DB // Add txs to DB
var invalidTxIDs []common.TxID var invalidTxIDs []common.TxID
for i := range poolL2Txs { for i := range poolL2Txs {
if poolL2Txs[i].Nonce <= currentNonce {
if poolL2Txs[i].Nonce < currentNonce {
invalidTxIDs = append(invalidTxIDs, poolL2Txs[i].TxID) invalidTxIDs = append(invalidTxIDs, poolL2Txs[i].TxID)
} }
err := l2DB.AddTxTest(&poolL2Txs[i]) err := l2DB.AddTxTest(&poolL2Txs[i])
assert.NoError(t, err) assert.NoError(t, err)
} }
// sanity check
require.Greater(t, len(invalidTxIDs), 0)
err = l2DB.CheckNonces(updateAccounts, fakeBatchNum)
err = l2DB.InvalidateOldNonces(updateAccounts, fakeBatchNum)
assert.NoError(t, err) assert.NoError(t, err)
// Fetch txs and check that they've been updated correctly // Fetch txs and check that they've been updated correctly
for _, id := range invalidTxIDs { for _, id := range invalidTxIDs {
fetchedTx, err := l2DB.GetTxAPI(id) fetchedTx, err := l2DB.GetTxAPI(id)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State) assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
assert.Equal(t, &fakeBatchNum, fetchedTx.BatchNum)
} }
} }

+ 2
- 2
test/til/txs.go

@ -597,7 +597,6 @@ func (tc *Context) generatePoolL2Txs() ([]common.PoolL2Tx, error) {
return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error())) return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
} }
} }
tc.Users[inst.From].Accounts[inst.TokenID].Nonce++
// if account of receiver does not exist, don't use // if account of receiver does not exist, don't use
// ToIdx, and use only ToEthAddr & ToBJJ // ToIdx, and use only ToEthAddr & ToBJJ
tx := common.PoolL2Tx{ tx := common.PoolL2Tx{
@ -612,6 +611,7 @@ func (tc *Context) generatePoolL2Txs() ([]common.PoolL2Tx, error) {
RqToBJJ: common.EmptyBJJComp, RqToBJJ: common.EmptyBJJComp,
Type: inst.Typ, Type: inst.Typ,
} }
tc.Users[inst.From].Accounts[inst.TokenID].Nonce++
if tx.Type == common.TxTypeTransfer { if tx.Type == common.TxTypeTransfer {
tx.ToIdx = tc.Users[inst.To].Accounts[inst.TokenID].Idx tx.ToIdx = tc.Users[inst.To].Accounts[inst.TokenID].Idx
tx.ToEthAddr = tc.Users[inst.To].Addr tx.ToEthAddr = tc.Users[inst.To].Addr
@ -639,7 +639,6 @@ func (tc *Context) generatePoolL2Txs() ([]common.PoolL2Tx, error) {
txs = append(txs, tx) txs = append(txs, tx)
case common.TxTypeExit: case common.TxTypeExit:
tc.Users[inst.From].Accounts[inst.TokenID].Nonce++
tx := common.PoolL2Tx{ tx := common.PoolL2Tx{
FromIdx: tc.Users[inst.From].Accounts[inst.TokenID].Idx, FromIdx: tc.Users[inst.From].Accounts[inst.TokenID].Idx,
ToIdx: common.Idx(1), // as is an Exit ToIdx: common.Idx(1), // as is an Exit
@ -650,6 +649,7 @@ func (tc *Context) generatePoolL2Txs() ([]common.PoolL2Tx, error) {
State: common.PoolL2TxStatePending, State: common.PoolL2TxStatePending,
Type: common.TxTypeExit, Type: common.TxTypeExit,
} }
tc.Users[inst.From].Accounts[inst.TokenID].Nonce++
nTx, err := common.NewPoolL2Tx(&tx) nTx, err := common.NewPoolL2Tx(&tx)
if err != nil { if err != nil {
return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error())) return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))

+ 6
- 6
test/til/txs_test.go

@ -218,9 +218,9 @@ func TestGeneratePoolL2Txs(t *testing.T) {
assert.Equal(t, tc.Users["User1"].Addr.Hex(), poolL2Txs[5].ToEthAddr.Hex()) assert.Equal(t, tc.Users["User1"].Addr.Hex(), poolL2Txs[5].ToEthAddr.Hex())
assert.Equal(t, tc.Users["User1"].BJJ.Public().String(), poolL2Txs[5].ToBJJ.String()) assert.Equal(t, tc.Users["User1"].BJJ.Public().String(), poolL2Txs[5].ToBJJ.String())
assert.Equal(t, common.Nonce(1), poolL2Txs[0].Nonce)
assert.Equal(t, common.Nonce(2), poolL2Txs[3].Nonce)
assert.Equal(t, common.Nonce(3), poolL2Txs[8].Nonce)
assert.Equal(t, common.Nonce(0), poolL2Txs[0].Nonce)
assert.Equal(t, common.Nonce(1), poolL2Txs[3].Nonce)
assert.Equal(t, common.Nonce(2), poolL2Txs[8].Nonce)
assert.Equal(t, tc.Users["B"].Addr.Hex(), poolL2Txs[9].ToEthAddr.Hex()) assert.Equal(t, tc.Users["B"].Addr.Hex(), poolL2Txs[9].ToEthAddr.Hex())
assert.Equal(t, common.EmptyBJJComp, poolL2Txs[9].ToBJJ) assert.Equal(t, common.EmptyBJJComp, poolL2Txs[9].ToBJJ)
@ -238,9 +238,9 @@ func TestGeneratePoolL2Txs(t *testing.T) {
` `
poolL2Txs, err = tc.GeneratePoolL2Txs(set) poolL2Txs, err = tc.GeneratePoolL2Txs(set)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, common.Nonce(6), poolL2Txs[0].Nonce)
assert.Equal(t, common.Nonce(2), poolL2Txs[1].Nonce)
assert.Equal(t, common.Nonce(7), poolL2Txs[2].Nonce)
assert.Equal(t, common.Nonce(5), poolL2Txs[0].Nonce)
assert.Equal(t, common.Nonce(1), poolL2Txs[1].Nonce)
assert.Equal(t, common.Nonce(6), poolL2Txs[2].Nonce)
// check that a PoolL2Tx can be done to a non existing ToIdx // check that a PoolL2Tx can be done to a non existing ToIdx
set = ` set = `

Loading…
Cancel
Save