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