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