arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/synchronizer/synchronizer_test.go
synchronizer/synchronizer_test.goRaw
  1package synchronizer
  2
  3import (
  4	"context"
  5	"fmt"
  6	"io/ioutil"
  7	"math/big"
  8	"os"
  9	"testing"
 10
 11	ethCommon "github.com/ethereum/go-ethereum/common"
 12	"github.com/hermeznetwork/hermez-node/common"
 13	dbUtils "github.com/hermeznetwork/hermez-node/db"
 14	"github.com/hermeznetwork/hermez-node/db/historydb"
 15	"github.com/hermeznetwork/hermez-node/db/statedb"
 16	"github.com/hermeznetwork/hermez-node/eth"
 17	"github.com/hermeznetwork/hermez-node/test"
 18	"github.com/hermeznetwork/hermez-node/test/til"
 19	"github.com/jinzhu/copier"
 20	"github.com/stretchr/testify/assert"
 21	"github.com/stretchr/testify/require"
 22)
 23
 24type timer struct {
 25	time int64
 26}
 27
 28func (t *timer) Time() int64 {
 29	currentTime := t.time
 30	t.time++
 31	return currentTime
 32}
 33
 34func TestSync(t *testing.T) {
 35	//
 36	// Setup
 37	//
 38
 39	ctx := context.Background()
 40	// Int State DB
 41	dir, err := ioutil.TempDir("", "tmpdb")
 42	require.Nil(t, err)
 43	defer assert.Nil(t, os.RemoveAll(dir))
 44
 45	stateDB, err := statedb.NewStateDB(dir, statedb.TypeSynchronizer, 32)
 46	assert.Nil(t, err)
 47
 48	// Init History DB
 49	pass := os.Getenv("POSTGRES_PASS")
 50	db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
 51	require.Nil(t, err)
 52	historyDB := historydb.NewHistoryDB(db)
 53	// Clear DB
 54	err = historyDB.Reorg(-1)
 55	assert.Nil(t, err)
 56
 57	// Init eth client
 58	var timer timer
 59	clientSetup := test.NewClientSetupExample()
 60	bootCoordAddr := clientSetup.AuctionVariables.BootCoordinator
 61	client := test.NewClient(true, &timer, &ethCommon.Address{}, clientSetup)
 62
 63	// Create Synchronizer
 64	s, err := NewSynchronizer(client, historyDB, stateDB)
 65	require.Nil(t, err)
 66
 67	//
 68	// First Sync from an initial state
 69	//
 70
 71	// Test Sync for rollup genesis block
 72	syncBlock, discards, err := s.Sync2(ctx, nil)
 73	require.Nil(t, err)
 74	require.Nil(t, discards)
 75	require.NotNil(t, syncBlock)
 76	assert.Equal(t, int64(1), syncBlock.Block.EthBlockNum)
 77	dbBlocks, err := s.historyDB.GetAllBlocks()
 78	require.Nil(t, err)
 79	assert.Equal(t, 1, len(dbBlocks))
 80	assert.Equal(t, int64(1), dbBlocks[0].EthBlockNum)
 81
 82	// Sync again and expect no new blocks
 83	syncBlock, discards, err = s.Sync2(ctx, nil)
 84	require.Nil(t, err)
 85	require.Nil(t, discards)
 86	require.Nil(t, syncBlock)
 87
 88	//
 89	// Generate blockchain and smart contract data, and fill the test smart contracts
 90	//
 91
 92	// Generate blockchain data with til
 93	set1 := `
 94		Type: Blockchain
 95
 96		AddToken(1)
 97		AddToken(2)
 98		AddToken(3)
 99
100		CreateAccountDeposit(1) A: 20 // Idx=256+1
101		CreateAccountDeposit(2) A: 20 // Idx=256+2
102		CreateAccountDeposit(1) B: 5  // Idx=256+3
103		CreateAccountDeposit(1) C: 5  // Idx=256+4
104		CreateAccountDeposit(1) D: 5  // Idx=256+5
105
106		CreateAccountCoordinator(2) B // Idx=256+0
107
108		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs
109		> batchL1 // forge defined L1UserTxs, freeze L1UserTxs{nil}
110		> block
111
112	`
113	tc := til.NewContext(eth.RollupConstMaxL1UserTx)
114	blocks, err := tc.GenerateBlocks(set1)
115	require.Nil(t, err)
116	require.Equal(t, 1, len(blocks))
117	require.Equal(t, 3, len(blocks[0].AddedTokens))
118	require.Equal(t, 5, len(blocks[0].L1UserTxs))
119	require.Equal(t, 2, len(blocks[0].Batches))
120
121	tokenConsts := map[common.TokenID]eth.ERC20Consts{}
122	// Generate extra required data
123	for _, block := range blocks {
124		for _, token := range block.AddedTokens {
125			consts := eth.ERC20Consts{
126				Name:     fmt.Sprintf("Token %d", token.TokenID),
127				Symbol:   fmt.Sprintf("TK%d", token.TokenID),
128				Decimals: 18,
129			}
130			tokenConsts[token.TokenID] = consts
131			client.CtlAddERC20(token.EthAddr, consts)
132		}
133	}
134
135	// Add block data to the smart contracts
136	for _, block := range blocks {
137		for _, token := range block.AddedTokens {
138			_, err := client.RollupAddTokenSimple(token.EthAddr, clientSetup.RollupVariables.FeeAddToken)
139			require.Nil(t, err)
140		}
141		for _, tx := range block.L1UserTxs {
142			client.CtlSetAddr(tx.FromEthAddr)
143			_, err := client.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.LoadAmount, tx.Amount,
144				uint32(tx.TokenID), int64(tx.ToIdx))
145			require.Nil(t, err)
146		}
147		client.CtlSetAddr(bootCoordAddr)
148		for _, batch := range block.Batches {
149			_, err := client.RollupForgeBatch(&eth.RollupForgeBatchArgs{
150				NewLastIdx:            batch.Batch.LastIdx,
151				NewStRoot:             batch.Batch.StateRoot,
152				NewExitRoot:           batch.Batch.ExitRoot,
153				L1CoordinatorTxs:      batch.L1CoordinatorTxs,
154				L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
155				L2TxsData:             batch.L2Txs,
156				FeeIdxCoordinator:     []common.Idx{}, // TODO
157				// Circuit selector
158				VerifierIdx: 0, // Intentionally empty
159				L1Batch:     batch.L1Batch,
160				ProofA:      [2]*big.Int{},    // Intentionally empty
161				ProofB:      [2][2]*big.Int{}, // Intentionally empty
162				ProofC:      [2]*big.Int{},    // Intentionally empty
163			})
164			require.Nil(t, err)
165		}
166		// Mine block and sync
167		client.CtlMineBlock()
168	}
169
170	//
171	// Sync to synchronize the current state from the test smart contracts
172	//
173
174	syncBlock, discards, err = s.Sync2(ctx, nil)
175	require.Nil(t, err)
176	require.Nil(t, discards)
177	require.NotNil(t, syncBlock)
178	assert.Equal(t, int64(2), syncBlock.Block.EthBlockNum)
179
180	// Fill extra fields not generated by til in til block
181	openToForge := int64(0)
182	toForgeL1TxsNum := int64(0)
183	for i := range blocks {
184		block := &blocks[i]
185		for j := range block.Batches {
186			batch := &block.Batches[j]
187			if batch.L1Batch {
188				// Set BatchNum for forged L1UserTxs to til blocks
189				bn := batch.Batch.BatchNum
190				for k := range blocks {
191					block := &blocks[k]
192					for l := range block.L1UserTxs {
193						tx := &block.L1UserTxs[l]
194						if *tx.ToForgeL1TxsNum == openToForge {
195							tx.BatchNum = &bn
196						}
197					}
198				}
199				openToForge++
200			}
201
202			batch.Batch.EthBlockNum = block.Block.EthBlockNum
203			batch.Batch.ForgerAddr = bootCoordAddr // til doesn't fill the batch forger addr
204			if batch.L1Batch {
205				toForgeL1TxsNumCpy := toForgeL1TxsNum
206				batch.Batch.ForgeL1TxsNum = &toForgeL1TxsNumCpy // til doesn't fill the ForgeL1TxsNum
207				toForgeL1TxsNum++
208			}
209
210			batchNum := batch.Batch.BatchNum
211			for j := range batch.L1CoordinatorTxs {
212				tx := &batch.L1CoordinatorTxs[j]
213				tx.BatchNum = &batchNum
214				tx.EthBlockNum = batch.Batch.EthBlockNum
215				nTx, err := common.NewL1Tx(tx)
216				require.Nil(t, err)
217				*tx = *nTx
218			}
219		}
220	}
221
222	block := blocks[0]
223
224	//
225	// Check Sync output and HistoryDB state against expected values
226	// generated by til
227	//
228
229	// Check Blocks
230	dbBlocks, err = s.historyDB.GetAllBlocks()
231	require.Nil(t, err)
232	assert.Equal(t, 2, len(dbBlocks))
233	assert.Equal(t, int64(2), dbBlocks[1].EthBlockNum)
234	assert.NotEqual(t, dbBlocks[1].Hash, dbBlocks[0].Hash)
235	assert.Greater(t, dbBlocks[1].Timestamp.Unix(), dbBlocks[0].Timestamp.Unix())
236
237	// Check Tokens
238	assert.Equal(t, len(block.AddedTokens), len(syncBlock.AddedTokens))
239	dbTokens, err := s.historyDB.GetAllTokens()
240	require.Nil(t, err)
241	assert.Equal(t, len(block.AddedTokens), len(dbTokens))
242	for i, token := range block.AddedTokens {
243		dbToken := dbTokens[i]
244		syncToken := syncBlock.AddedTokens[i]
245
246		assert.Equal(t, block.Block.EthBlockNum, syncToken.EthBlockNum)
247		assert.Equal(t, token.TokenID, syncToken.TokenID)
248		assert.Equal(t, token.EthAddr, syncToken.EthAddr)
249		tokenConst := tokenConsts[token.TokenID]
250		assert.Equal(t, tokenConst.Name, syncToken.Name)
251		assert.Equal(t, tokenConst.Symbol, syncToken.Symbol)
252		assert.Equal(t, tokenConst.Decimals, syncToken.Decimals)
253
254		var tokenCpy historydb.TokenRead
255		//nolint:gosec
256		require.Nil(t, copier.Copy(&tokenCpy, &token))      // copy common.Token to historydb.TokenRead
257		require.Nil(t, copier.Copy(&tokenCpy, &tokenConst)) // copy common.Token to historydb.TokenRead
258		tokenCpy.ItemID = dbToken.ItemID                    // we don't care about ItemID
259		assert.Equal(t, tokenCpy, dbToken)
260	}
261
262	// Check L1UserTxs
263	assert.Equal(t, len(block.L1UserTxs), len(syncBlock.L1UserTxs))
264	dbL1UserTxs, err := s.historyDB.GetAllL1UserTxs()
265	require.Nil(t, err)
266	assert.Equal(t, len(block.L1UserTxs), len(dbL1UserTxs))
267	// Ignore BatchNum in syncBlock.L1UserTxs because this value is set by the HistoryDB
268	for i := range syncBlock.L1UserTxs {
269		syncBlock.L1UserTxs[i].BatchNum = block.L1UserTxs[i].BatchNum
270	}
271	assert.Equal(t, block.L1UserTxs, syncBlock.L1UserTxs)
272	assert.Equal(t, block.L1UserTxs, dbL1UserTxs)
273
274	// Check Batches
275	assert.Equal(t, len(block.Batches), len(syncBlock.Batches))
276	dbBatches, err := s.historyDB.GetAllBatches()
277	require.Nil(t, err)
278	assert.Equal(t, len(block.Batches), len(dbBatches))
279
280	for i, batch := range block.Batches {
281		batchNum := batch.Batch.BatchNum
282		dbBatch := dbBatches[i]
283		syncBatch := syncBlock.Batches[i]
284
285		// We don't care about TotalFeesUSD.  Use the syncBatch that
286		// has a TotalFeesUSD inserted by the HistoryDB
287		batch.Batch.TotalFeesUSD = syncBatch.Batch.TotalFeesUSD
288		batch.CreatedAccounts = syncBatch.CreatedAccounts // til doesn't output CreatedAccounts
289
290		// fmt.Printf("DBG Batch %d %+v\n", i, batch)
291		// fmt.Printf("DBG Batch Sync %d %+v\n", i, syncBatch)
292		// assert.Equal(t, batch.L1CoordinatorTxs, syncBatch.L1CoordinatorTxs)
293		fmt.Printf("DBG BatchNum: %d, LastIdx: %d\n", batchNum, batch.Batch.LastIdx)
294		assert.Equal(t, batch, syncBatch)
295		assert.Equal(t, batch.Batch, dbBatch)
296	}
297
298	// Check L1UserTxs in DB
299
300	// TODO: Reorg will be properly tested once we have the mock ethClient implemented
301	/*
302		// Force a Reorg
303		lastSavedBlock, err := historyDB.GetLastBlock()
304		require.Nil(t, err)
305
306		lastSavedBlock.EthBlockNum++
307		err = historyDB.AddBlock(lastSavedBlock)
308		require.Nil(t, err)
309
310		lastSavedBlock.EthBlockNum++
311		err = historyDB.AddBlock(lastSavedBlock)
312		require.Nil(t, err)
313
314		log.Debugf("Wait for the blockchain to generate some blocks...")
315		time.Sleep(40 * time.Second)
316
317
318		err = s.Sync()
319		require.Nil(t, err)
320	*/
321}