mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Test synchronizer reorg
This commit is contained in:
@@ -289,11 +289,12 @@ func (s *Synchronizer) reorg(uncleBlock *common.Block) (int64, error) {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return 0, err
|
||||
}
|
||||
if batchNum != 0 {
|
||||
err = s.stateDB.Reset(batchNum)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err == sql.ErrNoRows {
|
||||
batchNum = 0
|
||||
}
|
||||
err = s.stateDB.Reset(batchNum)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return blockNum, nil
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
@@ -34,6 +35,10 @@ func (t *timer) Time() int64 {
|
||||
return currentTime
|
||||
}
|
||||
|
||||
func accountsCmp(accounts []common.Account) func(i, j int) bool {
|
||||
return func(i, j int) bool { return accounts[i].Idx < accounts[j].Idx }
|
||||
}
|
||||
|
||||
// Check Sync output and HistoryDB state against expected values generated by
|
||||
// til
|
||||
func checkSyncBlock(t *testing.T, s *Synchronizer, blockNum int, block, syncBlock *common.BlockData) {
|
||||
@@ -194,6 +199,80 @@ func checkSyncBlock(t *testing.T, s *Synchronizer, blockNum int, block, syncBloc
|
||||
assert.Equal(t, &exit, dbExit) //nolint:gosec
|
||||
}
|
||||
}
|
||||
|
||||
// Compare accounts from HistoryDB with StateDB (they should match)
|
||||
dbAccounts, err := s.historyDB.GetAllAccounts()
|
||||
require.Nil(t, err)
|
||||
sdbAccounts, err := s.stateDB.GetAccounts()
|
||||
require.Nil(t, err)
|
||||
assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
|
||||
}
|
||||
|
||||
func assertEqualAccountsHistoryDBStateDB(t *testing.T, hdbAccs, sdbAccs []common.Account) {
|
||||
assert.Equal(t, len(hdbAccs), len(sdbAccs))
|
||||
sort.SliceStable(hdbAccs, accountsCmp(hdbAccs))
|
||||
sort.SliceStable(sdbAccs, accountsCmp(sdbAccs))
|
||||
for i := range hdbAccs {
|
||||
hdbAcc := hdbAccs[i]
|
||||
sdbAcc := sdbAccs[i]
|
||||
assert.Equal(t, hdbAcc.Idx, sdbAcc.Idx)
|
||||
assert.Equal(t, hdbAcc.TokenID, sdbAcc.TokenID)
|
||||
assert.Equal(t, hdbAcc.EthAddr, sdbAcc.EthAddr)
|
||||
assert.Equal(t, hdbAcc.PublicKey, sdbAcc.PublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
// ethAddTokens adds the tokens from the blocks to the blockchain
|
||||
func ethAddTokens(blocks []common.BlockData, client *test.Client) {
|
||||
for _, block := range blocks {
|
||||
for _, token := range block.Rollup.AddedTokens {
|
||||
consts := eth.ERC20Consts{
|
||||
Name: fmt.Sprintf("Token %d", token.TokenID),
|
||||
Symbol: fmt.Sprintf("TK%d", token.TokenID),
|
||||
Decimals: 18,
|
||||
}
|
||||
tokenConsts[token.TokenID] = consts
|
||||
client.CtlAddERC20(token.EthAddr, consts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ethAddBlocks adds block data to the smart contracts
|
||||
func ethAddBlocks(t *testing.T, blocks []common.BlockData,
|
||||
client *test.Client, clientSetup *test.ClientSetup) {
|
||||
for _, block := range blocks {
|
||||
for _, token := range block.Rollup.AddedTokens {
|
||||
_, err := client.RollupAddTokenSimple(token.EthAddr, clientSetup.RollupVariables.FeeAddToken)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
for _, tx := range block.Rollup.L1UserTxs {
|
||||
client.CtlSetAddr(tx.FromEthAddr)
|
||||
_, err := client.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.LoadAmount, tx.Amount,
|
||||
uint32(tx.TokenID), int64(tx.ToIdx))
|
||||
require.Nil(t, err)
|
||||
}
|
||||
client.CtlSetAddr(clientSetup.AuctionVariables.BootCoordinator)
|
||||
for _, batch := range block.Rollup.Batches {
|
||||
_, err := client.RollupForgeBatch(ð.RollupForgeBatchArgs{
|
||||
NewLastIdx: batch.Batch.LastIdx,
|
||||
NewStRoot: batch.Batch.StateRoot,
|
||||
NewExitRoot: batch.Batch.ExitRoot,
|
||||
L1CoordinatorTxs: batch.L1CoordinatorTxs,
|
||||
L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
|
||||
L2TxsData: batch.L2Txs,
|
||||
FeeIdxCoordinator: batch.Batch.FeeIdxsCoordinator,
|
||||
// Circuit selector
|
||||
VerifierIdx: 0, // Intentionally empty
|
||||
L1Batch: batch.L1Batch,
|
||||
ProofA: [2]*big.Int{}, // Intentionally empty
|
||||
ProofB: [2][2]*big.Int{}, // Intentionally empty
|
||||
ProofC: [2]*big.Int{}, // Intentionally empty
|
||||
})
|
||||
require.Nil(t, err)
|
||||
}
|
||||
// Mine block and sync
|
||||
client.CtlMineBlock()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSync(t *testing.T) {
|
||||
@@ -322,62 +401,14 @@ func TestSync(t *testing.T) {
|
||||
require.Equal(t, 3, len(blocks[i].Rollup.Batches[0].L2Txs))
|
||||
|
||||
// Generate extra required data
|
||||
for _, block := range blocks {
|
||||
for _, token := range block.Rollup.AddedTokens {
|
||||
consts := eth.ERC20Consts{
|
||||
Name: fmt.Sprintf("Token %d", token.TokenID),
|
||||
Symbol: fmt.Sprintf("TK%d", token.TokenID),
|
||||
Decimals: 18,
|
||||
}
|
||||
tokenConsts[token.TokenID] = consts
|
||||
client.CtlAddERC20(token.EthAddr, consts)
|
||||
}
|
||||
}
|
||||
ethAddTokens(blocks, client)
|
||||
|
||||
err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
|
||||
assert.Nil(t, err)
|
||||
tc.FillBlocksL1UserTxsBatchNum(blocks)
|
||||
|
||||
// Add block data to the smart contracts
|
||||
for _, block := range blocks {
|
||||
for _, token := range block.Rollup.AddedTokens {
|
||||
_, err := client.RollupAddTokenSimple(token.EthAddr, clientSetup.RollupVariables.FeeAddToken)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
for _, tx := range block.Rollup.L1UserTxs {
|
||||
client.CtlSetAddr(tx.FromEthAddr)
|
||||
_, err := client.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.LoadAmount, tx.Amount,
|
||||
uint32(tx.TokenID), int64(tx.ToIdx))
|
||||
require.Nil(t, err)
|
||||
}
|
||||
client.CtlSetAddr(bootCoordAddr)
|
||||
// feeIdxCoordinator := []common.Idx{}
|
||||
// if block.Block.EthBlockNum > 2 {
|
||||
// // After blockNum=2 we have some accounts, use them as
|
||||
// // coordinator owned to receive fees.
|
||||
// feeIdxCoordinator = []common.Idx{common.Idx(256), common.Idx(259)}
|
||||
// }
|
||||
for _, batch := range block.Rollup.Batches {
|
||||
_, err := client.RollupForgeBatch(ð.RollupForgeBatchArgs{
|
||||
NewLastIdx: batch.Batch.LastIdx,
|
||||
NewStRoot: batch.Batch.StateRoot,
|
||||
NewExitRoot: batch.Batch.ExitRoot,
|
||||
L1CoordinatorTxs: batch.L1CoordinatorTxs,
|
||||
L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
|
||||
L2TxsData: batch.L2Txs,
|
||||
FeeIdxCoordinator: batch.Batch.FeeIdxsCoordinator,
|
||||
// Circuit selector
|
||||
VerifierIdx: 0, // Intentionally empty
|
||||
L1Batch: batch.L1Batch,
|
||||
ProofA: [2]*big.Int{}, // Intentionally empty
|
||||
ProofB: [2][2]*big.Int{}, // Intentionally empty
|
||||
ProofC: [2]*big.Int{}, // Intentionally empty
|
||||
})
|
||||
require.Nil(t, err)
|
||||
}
|
||||
// Mine block and sync
|
||||
client.CtlMineBlock()
|
||||
}
|
||||
ethAddBlocks(t, blocks, client, clientSetup)
|
||||
|
||||
//
|
||||
// Sync to synchronize the current state from the test smart contracts,
|
||||
@@ -467,25 +498,94 @@ func TestSync(t *testing.T) {
|
||||
assert.Equal(t, auctionVars, dbAuctionVars)
|
||||
assert.Equal(t, wDelayerVars, dbWDelayerVars)
|
||||
|
||||
// TODO: Reorg will be properly tested once we have the mock ethClient implemented
|
||||
/*
|
||||
// Force a Reorg
|
||||
lastSavedBlock, err := historyDB.GetLastBlock()
|
||||
//
|
||||
// Reorg test
|
||||
//
|
||||
|
||||
// Redo blocks 2-5 (as a reorg) only leaving:
|
||||
// - 2 create account transactions
|
||||
// - 2 add tokens
|
||||
// We add a 6th block so that the synchronizer can detect the reorg
|
||||
set2 := `
|
||||
Type: Blockchain
|
||||
|
||||
AddToken(1)
|
||||
AddToken(2)
|
||||
|
||||
CreateAccountDeposit(1) C: 2000 // Idx=256+1=257
|
||||
|
||||
CreateAccountCoordinator(1) A // Idx=256+0=256
|
||||
|
||||
> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{1}
|
||||
> batchL1 // forge defined L1UserTxs{1}, freeze L1UserTxs{nil}
|
||||
> block // blockNum=2
|
||||
> block // blockNum=3
|
||||
> block // blockNum=4
|
||||
> block // blockNum=5
|
||||
> block // blockNum=6
|
||||
`
|
||||
tc = til.NewContext(common.RollupConstMaxL1UserTx)
|
||||
tilCfgExtra = til.ConfigExtra{
|
||||
BootCoordAddr: bootCoordAddr,
|
||||
CoordUser: "A",
|
||||
}
|
||||
blocks, err = tc.GenerateBlocks(set2)
|
||||
require.Nil(t, err)
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
client.CtlRollback()
|
||||
}
|
||||
blockNum := client.CtlCurrentBlock()
|
||||
require.Equal(t, int64(1), blockNum)
|
||||
|
||||
// Generate extra required data
|
||||
ethAddTokens(blocks, client)
|
||||
|
||||
err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
|
||||
assert.Nil(t, err)
|
||||
tc.FillBlocksL1UserTxsBatchNum(blocks)
|
||||
|
||||
// Add block data to the smart contracts
|
||||
ethAddBlocks(t, blocks, client, clientSetup)
|
||||
|
||||
// First sync detects the reorg and discards 4 blocks
|
||||
syncBlock, discards, err = s.Sync2(ctx, nil)
|
||||
require.Nil(t, err)
|
||||
expetedDiscards := int64(4)
|
||||
require.Equal(t, &expetedDiscards, discards)
|
||||
require.Nil(t, syncBlock)
|
||||
|
||||
// At this point, the DB only has data up to block 1
|
||||
dbBlock, err := s.historyDB.GetLastBlock()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, int64(1), dbBlock.EthBlockNum)
|
||||
|
||||
// Accounts in HistoryDB and StateDB must be empty
|
||||
dbAccounts, err := s.historyDB.GetAllAccounts()
|
||||
require.Nil(t, err)
|
||||
sdbAccounts, err := s.stateDB.GetAccounts()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, 0, len(dbAccounts))
|
||||
assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
|
||||
|
||||
// Sync blocks 2-6
|
||||
for i := 0; i < 5; i++ {
|
||||
syncBlock, discards, err = s.Sync2(ctx, nil)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, discards)
|
||||
require.NotNil(t, syncBlock)
|
||||
assert.Equal(t, int64(2+i), syncBlock.Block.EthBlockNum)
|
||||
}
|
||||
|
||||
lastSavedBlock.EthBlockNum++
|
||||
err = historyDB.AddBlock(lastSavedBlock)
|
||||
require.Nil(t, err)
|
||||
dbBlock, err = s.historyDB.GetLastBlock()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, int64(6), dbBlock.EthBlockNum)
|
||||
|
||||
lastSavedBlock.EthBlockNum++
|
||||
err = historyDB.AddBlock(lastSavedBlock)
|
||||
require.Nil(t, err)
|
||||
|
||||
log.Debugf("Wait for the blockchain to generate some blocks...")
|
||||
time.Sleep(40 * time.Second)
|
||||
|
||||
|
||||
err = s.Sync()
|
||||
require.Nil(t, err)
|
||||
*/
|
||||
// Accounts in HistoryDB and StateDB is only 2 entries
|
||||
dbAccounts, err = s.historyDB.GetAllAccounts()
|
||||
require.Nil(t, err)
|
||||
sdbAccounts, err = s.stateDB.GetAccounts()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, 2, len(dbAccounts))
|
||||
assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user