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