hermez-node/db/statedb/statedb_test.go
db/statedb/statedb_test.goRaw
1package statedb
2
3import (
4 "encoding/hex"
5 "fmt"
6 "io/ioutil"
7 "math/big"
8 "os"
9 "testing"
10
11 ethCrypto "github.com/ethereum/go-ethereum/crypto"
12 "github.com/hermeznetwork/hermez-node/common"
13 "github.com/iden3/go-iden3-crypto/babyjub"
14 "github.com/iden3/go-merkletree/db"
15 "github.com/stretchr/testify/assert"
16 "github.com/stretchr/testify/require"
17)
18
19func newAccount(t *testing.T, i int) *common.Account {
20 var sk babyjub.PrivateKey
21 _, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
22 require.Nil(t, err)
23 pk := sk.Public()
24
25 key, err := ethCrypto.GenerateKey()
26 require.Nil(t, err)
27 address := ethCrypto.PubkeyToAddress(key.PublicKey)
28
29 return &common.Account{
30 Idx: common.Idx(256 + i),
31 TokenID: common.TokenID(i),
32 Nonce: common.Nonce(i),
33 Balance: big.NewInt(1000),
34 PublicKey: pk,
35 EthAddr: address,
36 }
37}
38
39func TestNewStateDBIntermediateState(t *testing.T) {
40 dir, err := ioutil.TempDir("", "tmpdb")
41 require.Nil(t, err)
42 defer assert.Nil(t, os.RemoveAll(dir))
43
44 sdb, err := NewStateDB(dir, TypeTxSelector, 0)
45 assert.Nil(t, err)
46
47 // test values
48 k0 := []byte("testkey0")
49 k1 := []byte("testkey1")
50 v0 := []byte("testvalue0")
51 v1 := []byte("testvalue1")
52
53 // store some data
54 tx, err := sdb.db.NewTx()
55 assert.Nil(t, err)
56 err = tx.Put(k0, v0)
57 assert.Nil(t, err)
58 err = tx.Commit()
59 assert.Nil(t, err)
60 v, err := sdb.db.Get(k0)
61 assert.Nil(t, err)
62 assert.Equal(t, v0, v)
63
64 // call NewStateDB which should get the db at the last checkpoint state
65 // executing a Reset (discarding the last 'testkey0'&'testvalue0' data)
66 sdb, err = NewStateDB(dir, TypeTxSelector, 0)
67 assert.Nil(t, err)
68 v, err = sdb.db.Get(k0)
69 assert.NotNil(t, err)
70 assert.Equal(t, db.ErrNotFound, err)
71 assert.Nil(t, v)
72
73 // store the same data from the beginning that has ben lost since last NewStateDB
74 tx, err = sdb.db.NewTx()
75 assert.Nil(t, err)
76 err = tx.Put(k0, v0)
77 assert.Nil(t, err)
78 err = tx.Commit()
79 assert.Nil(t, err)
80 v, err = sdb.db.Get(k0)
81 assert.Nil(t, err)
82 assert.Equal(t, v0, v)
83
84 // make checkpoints with the current state
85 bn, err := sdb.GetCurrentBatch()
86 assert.Nil(t, err)
87 assert.Equal(t, common.BatchNum(0), bn)
88 err = sdb.MakeCheckpoint()
89 assert.Nil(t, err)
90 bn, err = sdb.GetCurrentBatch()
91 assert.Nil(t, err)
92 assert.Equal(t, common.BatchNum(1), bn)
93
94 // write more data
95 tx, err = sdb.db.NewTx()
96 assert.Nil(t, err)
97 err = tx.Put(k1, v1)
98 assert.Nil(t, err)
99 err = tx.Commit()
100 assert.Nil(t, err)
101
102 v, err = sdb.db.Get(k1)
103 assert.Nil(t, err)
104 assert.Equal(t, v1, v)
105
106 // call NewStateDB which should get the db at the last checkpoint state
107 // executing a Reset (discarding the last 'testkey1'&'testvalue1' data)
108 sdb, err = NewStateDB(dir, TypeTxSelector, 0)
109 assert.Nil(t, err)
110
111 v, err = sdb.db.Get(k0)
112 assert.Nil(t, err)
113 assert.Equal(t, v0, v)
114
115 v, err = sdb.db.Get(k1)
116 assert.NotNil(t, err)
117 assert.Equal(t, db.ErrNotFound, err)
118 assert.Nil(t, v)
119}
120
121func TestStateDBWithoutMT(t *testing.T) {
122 dir, err := ioutil.TempDir("", "tmpdb")
123 require.Nil(t, err)
124 defer assert.Nil(t, os.RemoveAll(dir))
125
126 sdb, err := NewStateDB(dir, TypeTxSelector, 0)
127 assert.Nil(t, err)
128
129 // create test accounts
130 var accounts []*common.Account
131 for i := 0; i < 4; i++ {
132 accounts = append(accounts, newAccount(t, i))
133 }
134
135 // get non-existing account, expecting an error
136 unexistingAccount := common.Idx(1)
137 _, err = sdb.GetAccount(unexistingAccount)
138 assert.NotNil(t, err)
139 assert.Equal(t, db.ErrNotFound, err)
140
141 // add test accounts
142 for i := 0; i < len(accounts); i++ {
143 _, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
144 assert.Nil(t, err)
145 }
146
147 for i := 0; i < len(accounts); i++ {
148 existingAccount := accounts[i].Idx
149 accGetted, err := sdb.GetAccount(existingAccount)
150 assert.Nil(t, err)
151 assert.Equal(t, accounts[i], accGetted)
152 }
153
154 // try already existing idx and get error
155 existingAccount := common.Idx(256)
156 _, err = sdb.GetAccount(existingAccount) // check that exist
157 assert.Nil(t, err)
158 _, err = sdb.CreateAccount(common.Idx(256), accounts[1]) // check that can not be created twice
159 assert.NotNil(t, err)
160 assert.Equal(t, ErrAccountAlreadyExists, err)
161
162 // update accounts
163 for i := 0; i < len(accounts); i++ {
164 accounts[i].Nonce = accounts[i].Nonce + 1
165 existingAccount = common.Idx(i)
166 _, err = sdb.UpdateAccount(existingAccount, accounts[i])
167 assert.Nil(t, err)
168 }
169
170 _, err = sdb.MTGetProof(common.Idx(1))
171 assert.NotNil(t, err)
172 assert.Equal(t, ErrStateDBWithoutMT, err)
173}
174
175func TestStateDBWithMT(t *testing.T) {
176 dir, err := ioutil.TempDir("", "tmpdb")
177 require.Nil(t, err)
178 defer assert.Nil(t, os.RemoveAll(dir))
179
180 sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
181 assert.Nil(t, err)
182
183 // create test accounts
184 var accounts []*common.Account
185 for i := 0; i < 20; i++ {
186 accounts = append(accounts, newAccount(t, i))
187 }
188
189 // get non-existing account, expecting an error
190 _, err = sdb.GetAccount(common.Idx(1))
191 assert.NotNil(t, err)
192 assert.Equal(t, db.ErrNotFound, err)
193
194 // add test accounts
195 for i := 0; i < len(accounts); i++ {
196 _, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
197 assert.Nil(t, err)
198 }
199
200 for i := 0; i < len(accounts); i++ {
201 accGetted, err := sdb.GetAccount(accounts[i].Idx)
202 assert.Nil(t, err)
203 assert.Equal(t, accounts[i], accGetted)
204 }
205
206 // try already existing idx and get error
207 _, err = sdb.GetAccount(common.Idx(256)) // check that exist
208 assert.Nil(t, err)
209 _, err = sdb.CreateAccount(common.Idx(256), accounts[1]) // check that can not be created twice
210 assert.NotNil(t, err)
211 assert.Equal(t, ErrAccountAlreadyExists, err)
212
213 _, err = sdb.MTGetProof(common.Idx(256))
214 assert.Nil(t, err)
215
216 // update accounts
217 for i := 0; i < len(accounts); i++ {
218 accounts[i].Nonce = accounts[i].Nonce + 1
219 _, err = sdb.UpdateAccount(accounts[i].Idx, accounts[i])
220 assert.Nil(t, err)
221 }
222 a, err := sdb.GetAccount(common.Idx(256)) // check that account value has been updated
223 assert.Nil(t, err)
224 assert.Equal(t, accounts[0].Nonce, a.Nonce)
225}
226
227func TestCheckpoints(t *testing.T) {
228 dir, err := ioutil.TempDir("", "sdb")
229 require.Nil(t, err)
230 defer assert.Nil(t, os.RemoveAll(dir))
231
232 sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
233 assert.Nil(t, err)
234
235 // create test accounts
236 var accounts []*common.Account
237 for i := 0; i < 10; i++ {
238 accounts = append(accounts, newAccount(t, i))
239 }
240
241 // add test accounts
242 for i := 0; i < len(accounts); i++ {
243 _, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
244 assert.Nil(t, err)
245 }
246
247 // do checkpoints and check that currentBatch is correct
248 err = sdb.MakeCheckpoint()
249 assert.Nil(t, err)
250 cb, err := sdb.GetCurrentBatch()
251 assert.Nil(t, err)
252 assert.Equal(t, common.BatchNum(1), cb)
253
254 for i := 1; i < 10; i++ {
255 err = sdb.MakeCheckpoint()
256 assert.Nil(t, err)
257
258 cb, err = sdb.GetCurrentBatch()
259 assert.Nil(t, err)
260 assert.Equal(t, common.BatchNum(i+1), cb)
261 }
262
263 // printCheckpoints(t, sdb.path)
264
265 // reset checkpoint
266 err = sdb.Reset(3)
267 assert.Nil(t, err)
268
269 // check that reset can be repeated (as there exist the 'current' and
270 // 'BatchNum3', from where the 'current' is a copy)
271 err = sdb.Reset(3)
272 require.Nil(t, err)
273
274 // check that currentBatch is as expected after Reset
275 cb, err = sdb.GetCurrentBatch()
276 assert.Nil(t, err)
277 assert.Equal(t, common.BatchNum(3), cb)
278
279 // advance one checkpoint and check that currentBatch is fine
280 err = sdb.MakeCheckpoint()
281 assert.Nil(t, err)
282 cb, err = sdb.GetCurrentBatch()
283 assert.Nil(t, err)
284 assert.Equal(t, common.BatchNum(4), cb)
285
286 err = sdb.DeleteCheckpoint(common.BatchNum(9))
287 assert.Nil(t, err)
288 err = sdb.DeleteCheckpoint(common.BatchNum(10))
289 assert.Nil(t, err)
290 err = sdb.DeleteCheckpoint(common.BatchNum(9)) // does not exist, should return err
291 assert.NotNil(t, err)
292 err = sdb.DeleteCheckpoint(common.BatchNum(11)) // does not exist, should return err
293 assert.NotNil(t, err)
294
295 // Create a LocalStateDB from the initial StateDB
296 dirLocal, err := ioutil.TempDir("", "ldb")
297 require.Nil(t, err)
298 defer assert.Nil(t, os.RemoveAll(dirLocal))
299 ldb, err := NewLocalStateDB(dirLocal, sdb, TypeBatchBuilder, 32)
300 assert.Nil(t, err)
301
302 // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
303 err = ldb.Reset(4, true)
304 assert.Nil(t, err)
305 // check that currentBatch is 4 after the Reset
306 cb, err = ldb.GetCurrentBatch()
307 assert.Nil(t, err)
308 assert.Equal(t, common.BatchNum(4), cb)
309 // advance one checkpoint in ldb
310 err = ldb.MakeCheckpoint()
311 assert.Nil(t, err)
312 cb, err = ldb.GetCurrentBatch()
313 assert.Nil(t, err)
314 assert.Equal(t, common.BatchNum(5), cb)
315
316 // Create a 2nd LocalStateDB from the initial StateDB
317 dirLocal2, err := ioutil.TempDir("", "ldb2")
318 require.Nil(t, err)
319 defer assert.Nil(t, os.RemoveAll(dirLocal2))
320 ldb2, err := NewLocalStateDB(dirLocal2, sdb, TypeBatchBuilder, 32)
321 assert.Nil(t, err)
322
323 // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
324 err = ldb2.Reset(4, true)
325 assert.Nil(t, err)
326 // check that currentBatch is 4 after the Reset
327 cb, err = ldb2.GetCurrentBatch()
328 assert.Nil(t, err)
329 assert.Equal(t, common.BatchNum(4), cb)
330 // advance one checkpoint in ldb2
331 err = ldb2.MakeCheckpoint()
332 assert.Nil(t, err)
333 cb, err = ldb2.GetCurrentBatch()
334 assert.Nil(t, err)
335 assert.Equal(t, common.BatchNum(5), cb)
336
337 debug := false
338 if debug {
339 printCheckpoints(t, sdb.path)
340 printCheckpoints(t, ldb.path)
341 printCheckpoints(t, ldb2.path)
342 }
343}
344
345func TestStateDBGetAccounts(t *testing.T) {
346 dir, err := ioutil.TempDir("", "tmpdb")
347 require.Nil(t, err)
348
349 sdb, err := NewStateDB(dir, TypeTxSelector, 0)
350 assert.Nil(t, err)
351
352 // create test accounts
353 var accounts []common.Account
354 for i := 0; i < 16; i++ {
355 account := newAccount(t, i)
356 accounts = append(accounts, *account)
357 }
358
359 // add test accounts
360 for i := range accounts {
361 _, err = sdb.CreateAccount(accounts[i].Idx, &accounts[i])
362 require.Nil(t, err)
363 }
364
365 dbAccounts, err := sdb.GetAccounts()
366 require.Nil(t, err)
367 assert.Equal(t, accounts, dbAccounts)
368}
369
370func printCheckpoints(t *testing.T, path string) {
371 files, err := ioutil.ReadDir(path)
372 assert.Nil(t, err)
373
374 fmt.Println(path)
375 for _, f := range files {
376 fmt.Println(" " + f.Name())
377 }
378}