hermez-node/synchronizer/synchronizer_test.go
synchronizer/synchronizer_test.goRaw
1package synchronizer
2
3import (
4 "context"
5 "crypto/ecdsa"
6 "encoding/binary"
7 "fmt"
8 "io/ioutil"
9 "math/big"
10 "os"
11 "testing"
12
13 ethCommon "github.com/ethereum/go-ethereum/common"
14 ethCrypto "github.com/ethereum/go-ethereum/crypto"
15 "github.com/hermeznetwork/hermez-node/common"
16 dbUtils "github.com/hermeznetwork/hermez-node/db"
17 "github.com/hermeznetwork/hermez-node/db/historydb"
18 "github.com/hermeznetwork/hermez-node/db/statedb"
19 "github.com/hermeznetwork/hermez-node/eth"
20 "github.com/hermeznetwork/hermez-node/test"
21 "github.com/iden3/go-iden3-crypto/babyjub"
22 "github.com/jinzhu/copier"
23 "github.com/stretchr/testify/assert"
24 "github.com/stretchr/testify/require"
25)
26
27type timer struct {
28 time int64
29}
30
31func (t *timer) Time() int64 {
32 currentTime := t.time
33 t.time++
34 return currentTime
35}
36
37type tokenData struct {
38 TokenID common.TokenID
39 Addr ethCommon.Address
40 Consts eth.ERC20Consts
41}
42
43func TestSync(t *testing.T) {
44 ctx := context.Background()
45 // Int State DB
46 dir, err := ioutil.TempDir("", "tmpdb")
47 require.Nil(t, err)
48 defer assert.Nil(t, os.RemoveAll(dir))
49
50 stateDB, err := statedb.NewStateDB(dir, statedb.TypeSynchronizer, 32)
51 assert.Nil(t, err)
52
53 // Init History DB
54 pass := os.Getenv("POSTGRES_PASS")
55 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
56 require.Nil(t, err)
57 historyDB := historydb.NewHistoryDB(db)
58 // Clear DB
59 err = historyDB.Reorg(-1)
60 assert.Nil(t, err)
61
62 // Init eth client
63 var timer timer
64 clientSetup := test.NewClientSetupExample()
65 client := test.NewClient(true, &timer, ðCommon.Address{}, clientSetup)
66
67 // Create Synchronizer
68 s, err := NewSynchronizer(client, historyDB, stateDB)
69 require.Nil(t, err)
70
71 // Test Sync for rollup genesis block
72 blockData, _, err := s.Sync2(ctx, nil)
73 require.Nil(t, err)
74 require.NotNil(t, blockData)
75 assert.Equal(t, int64(1), blockData.Block.EthBlockNum)
76 blocks, err := s.historyDB.GetBlocks(0, 9999)
77 require.Nil(t, err)
78 assert.Equal(t, 1, len(blocks))
79 assert.Equal(t, int64(1), blocks[0].EthBlockNum)
80
81 /*
82 // Test Sync for a block with new Tokens and L1UserTxs
83 // accounts := test.GenerateKeys(t, []string{"A", "B", "C", "D"})
84 l1UserTxs, _, _, _ := test.GenerateTestTxsFromSet(t, `
85 A (1): 10
86 A (2): 20
87 B (1): 5
88 C (1): 8
89 D (3): 15
90 > advance batch
91 `)
92 require.Greater(t, len(l1UserTxs[0]), 0)
93 // require.Greater(t, len(tokens), 0)
94
95 for i := 1; i <= 3; i++ {
96 _, err := client.RollupAddToken(ethCommon.BigToAddress(big.NewInt(int64(i*10000))),
97 clientSetup.RollupVariables.FeeAddToken)
98 require.Nil(t, err)
99 }
100
101 for i := range l1UserTxs[0] {
102 client.CtlAddL1TxUser(&l1UserTxs[0][i])
103 }
104 client.CtlMineBlock()
105
106 err = s.Sync(context.Background())
107 require.Nil(t, err)
108
109 getTokens, err := s.historyDB.GetTokens()
110 require.Nil(t, err)
111 assert.Equal(t, 3, len(getTokens))
112 */
113
114 // Generate tokens vector
115 numTokens := 3
116 tokens := make([]tokenData, numTokens)
117 for i := 1; i <= numTokens; i++ {
118 addr := ethCommon.BigToAddress(big.NewInt(int64(i * 10000)))
119 consts := eth.ERC20Consts{
120 Name: fmt.Sprintf("Token %d", i),
121 Symbol: fmt.Sprintf("TK%d", i),
122 Decimals: uint64(i * 2),
123 }
124 tokens[i-1] = tokenData{common.TokenID(i), addr, consts}
125 }
126
127 numUsers := 4
128 keys := make([]*userKeys, numUsers)
129 for i := range keys {
130 keys[i] = genKeys(i)
131 }
132
133 // Generate some L1UserTxs of type deposit
134 l1UserTxs := make([]*common.L1Tx, 5)
135 for i := range l1UserTxs {
136 l1UserTxs[i] = &common.L1Tx{
137 FromIdx: common.Idx(0),
138 FromEthAddr: keys[i%numUsers].Addr,
139 FromBJJ: keys[i%numUsers].BJJPK,
140 Amount: big.NewInt(0),
141 LoadAmount: big.NewInt((int64(i) + 1) * 1000),
142 TokenID: common.TokenID(i%numTokens + 1),
143 }
144 }
145
146 // Add tokens to ethereum, and to rollup
147 for _, token := range tokens {
148 client.CtlAddERC20(token.Addr, token.Consts)
149 _, err := client.RollupAddToken(token.Addr, clientSetup.RollupVariables.FeeAddToken)
150 require.Nil(t, err)
151 }
152
153 // Add L1Txs to rollup
154 for i := range l1UserTxs {
155 tx := l1UserTxs[i]
156 _, err := client.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.LoadAmount, tx.Amount,
157 uint32(tx.TokenID), int64(tx.ToIdx))
158 require.Nil(t, err)
159 }
160
161 // Mine block and sync
162 client.CtlMineBlock()
163
164 blockData, _, err = s.Sync2(ctx, nil)
165 require.Nil(t, err)
166 require.NotNil(t, blockData)
167 assert.Equal(t, int64(2), blockData.Block.EthBlockNum)
168
169 // Check tokens in DB
170 dbTokens, err := s.historyDB.GetAllTokens()
171 require.Nil(t, err)
172 assert.Equal(t, len(tokens), len(dbTokens))
173 assert.Equal(t, len(tokens), len(blockData.AddedTokens))
174 for i := range tokens {
175 token := tokens[i]
176 addToken := blockData.AddedTokens[i]
177 dbToken := dbTokens[i]
178
179 assert.Equal(t, int64(2), addToken.EthBlockNum)
180 assert.Equal(t, token.TokenID, addToken.TokenID)
181 assert.Equal(t, token.Addr, addToken.EthAddr)
182 assert.Equal(t, token.Consts.Name, addToken.Name)
183 assert.Equal(t, token.Consts.Symbol, addToken.Symbol)
184 assert.Equal(t, token.Consts.Decimals, addToken.Decimals)
185
186 var addTokenCpy historydb.TokenRead
187 require.Nil(t, copier.Copy(&addTokenCpy, &addToken)) // copy common.Token to historydb.TokenRead
188 addTokenCpy.ItemID = dbToken.ItemID // we don't care about ItemID
189 assert.Equal(t, addTokenCpy, dbToken)
190 }
191
192 // Check L1UserTxs in DB
193
194 // TODO: Reorg will be properly tested once we have the mock ethClient implemented
195 /*
196 // Force a Reorg
197 lastSavedBlock, err := historyDB.GetLastBlock()
198 require.Nil(t, err)
199
200 lastSavedBlock.EthBlockNum++
201 err = historyDB.AddBlock(lastSavedBlock)
202 require.Nil(t, err)
203
204 lastSavedBlock.EthBlockNum++
205 err = historyDB.AddBlock(lastSavedBlock)
206 require.Nil(t, err)
207
208 log.Debugf("Wait for the blockchain to generate some blocks...")
209 time.Sleep(40 * time.Second)
210
211
212 err = s.Sync()
213 require.Nil(t, err)
214 */
215}
216
217type userKeys struct {
218 BJJSK *babyjub.PrivateKey
219 BJJPK *babyjub.PublicKey
220 Addr ethCommon.Address
221}
222
223func genKeys(i int) *userKeys {
224 i++ // i = 0 doesn't work for the ecdsa key generation
225 var sk babyjub.PrivateKey
226 binary.LittleEndian.PutUint64(sk[:], uint64(i))
227
228 // eth address
229 var key ecdsa.PrivateKey
230 key.D = big.NewInt(int64(i)) // only for testing
231 key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
232 key.Curve = ethCrypto.S256()
233 addr := ethCrypto.PubkeyToAddress(key.PublicKey)
234
235 return &userKeys{
236 BJJSK: &sk,
237 BJJPK: sk.Public(),
238 Addr: addr,
239 }
240}