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 _, err = sdb.GetAccount(common.Idx(1))
133 assert.NotNil(t, err)
134 assert.Equal(t, db.ErrNotFound, err)
135
136 // add test accounts
137 for i := 0; i < len(accounts); i++ {
138 _, err = sdb.CreateAccount(common.Idx(i), accounts[i])
139 assert.Nil(t, err)
140 }
141
142 for i := 0; i < len(accounts); i++ {
143 accGetted, err := sdb.GetAccount(common.Idx(i))
144 assert.Nil(t, err)
145 assert.Equal(t, accounts[i], accGetted)
146 }
147
148 // try already existing idx and get error
149 _, err = sdb.GetAccount(common.Idx(1)) // check that exist
150 assert.Nil(t, err)
151 _, err = sdb.CreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
152 assert.NotNil(t, err)
153 assert.Equal(t, ErrAccountAlreadyExists, err)
154
155 // update accounts
156 for i := 0; i < len(accounts); i++ {
157 accounts[i].Nonce = accounts[i].Nonce + 1
158 _, err = sdb.UpdateAccount(common.Idx(i), accounts[i])
159 assert.Nil(t, err)
160 }
161
162 _, err = sdb.MTGetProof(common.Idx(1))
163 assert.NotNil(t, err)
164 assert.Equal(t, ErrStateDBWithoutMT, err)
165}
166
167func TestStateDBWithMT(t *testing.T) {
168 dir, err := ioutil.TempDir("", "tmpdb")
169 require.Nil(t, err)
170
171 sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
172 assert.Nil(t, err)
173
174 // create test accounts
175 var accounts []*common.Account
176 for i := 0; i < 20; i++ {
177 accounts = append(accounts, newAccount(t, i))
178 }
179
180 // get non-existing account, expecting an error
181 _, err = sdb.GetAccount(common.Idx(1))
182 assert.NotNil(t, err)
183 assert.Equal(t, db.ErrNotFound, err)
184
185 // add test accounts
186 for i := 0; i < len(accounts); i++ {
187 _, err = sdb.CreateAccount(common.Idx(i), accounts[i])
188 assert.Nil(t, err)
189 }
190
191 for i := 0; i < len(accounts); i++ {
192 accGetted, err := sdb.GetAccount(common.Idx(i))
193 assert.Nil(t, err)
194 assert.Equal(t, accounts[i], accGetted)
195 }
196
197 // try already existing idx and get error
198 _, err = sdb.GetAccount(common.Idx(1)) // check that exist
199 assert.Nil(t, err)
200 _, err = sdb.CreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
201 assert.NotNil(t, err)
202 assert.Equal(t, ErrAccountAlreadyExists, err)
203
204 _, err = sdb.MTGetProof(common.Idx(1))
205 assert.Nil(t, err)
206
207 // update accounts
208 for i := 0; i < len(accounts); i++ {
209 accounts[i].Nonce = accounts[i].Nonce + 1
210 _, err = sdb.UpdateAccount(common.Idx(i), accounts[i])
211 assert.Nil(t, err)
212 }
213 a, err := sdb.GetAccount(common.Idx(1)) // check that account value has been updated
214 assert.Nil(t, err)
215 assert.Equal(t, accounts[1].Nonce, a.Nonce)
216}
217
218func TestCheckpoints(t *testing.T) {
219 dir, err := ioutil.TempDir("", "sdb")
220 require.Nil(t, err)
221
222 sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
223 assert.Nil(t, err)
224
225 // create test accounts
226 var accounts []*common.Account
227 for i := 0; i < 10; i++ {
228 accounts = append(accounts, newAccount(t, i))
229 }
230
231 // add test accounts
232 for i := 0; i < len(accounts); i++ {
233 _, err = sdb.CreateAccount(common.Idx(i), accounts[i])
234 assert.Nil(t, err)
235 }
236
237 // do checkpoints and check that currentBatch is correct
238 err = sdb.MakeCheckpoint()
239 assert.Nil(t, err)
240 cb, err := sdb.GetCurrentBatch()
241 assert.Nil(t, err)
242 assert.Equal(t, common.BatchNum(1), cb)
243
244 for i := 1; i < 10; i++ {
245 err = sdb.MakeCheckpoint()
246 assert.Nil(t, err)
247
248 cb, err = sdb.GetCurrentBatch()
249 assert.Nil(t, err)
250 assert.Equal(t, common.BatchNum(i+1), cb)
251 }
252
253 // printCheckpoints(t, sdb.path)
254
255 // reset checkpoint
256 err = sdb.Reset(3)
257 assert.Nil(t, err)
258
259 // check that reset can be repeated (as there exist the 'current' and
260 // 'BatchNum3', from where the 'current' is a copy)
261 err = sdb.Reset(3)
262 require.Nil(t, err)
263
264 // check that currentBatch is as expected after Reset
265 cb, err = sdb.GetCurrentBatch()
266 assert.Nil(t, err)
267 assert.Equal(t, common.BatchNum(3), cb)
268
269 // advance one checkpoint and check that currentBatch is fine
270 err = sdb.MakeCheckpoint()
271 assert.Nil(t, err)
272 cb, err = sdb.GetCurrentBatch()
273 assert.Nil(t, err)
274 assert.Equal(t, common.BatchNum(4), cb)
275
276 err = sdb.DeleteCheckpoint(common.BatchNum(9))
277 assert.Nil(t, err)
278 err = sdb.DeleteCheckpoint(common.BatchNum(10))
279 assert.Nil(t, err)
280 err = sdb.DeleteCheckpoint(common.BatchNum(9)) // does not exist, should return err
281 assert.NotNil(t, err)
282 err = sdb.DeleteCheckpoint(common.BatchNum(11)) // does not exist, should return err
283 assert.NotNil(t, err)
284
285 // Create a LocalStateDB from the initial StateDB
286 dirLocal, err := ioutil.TempDir("", "ldb")
287 require.Nil(t, err)
288 ldb, err := NewLocalStateDB(dirLocal, sdb, TypeBatchBuilder, 32)
289 assert.Nil(t, err)
290
291 // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
292 err = ldb.Reset(4, true)
293 assert.Nil(t, err)
294 // check that currentBatch is 4 after the Reset
295 cb, err = ldb.GetCurrentBatch()
296 assert.Nil(t, err)
297 assert.Equal(t, common.BatchNum(4), cb)
298 // advance one checkpoint in ldb
299 err = ldb.MakeCheckpoint()
300 assert.Nil(t, err)
301 cb, err = ldb.GetCurrentBatch()
302 assert.Nil(t, err)
303 assert.Equal(t, common.BatchNum(5), cb)
304
305 // Create a 2nd LocalStateDB from the initial StateDB
306 dirLocal2, err := ioutil.TempDir("", "ldb2")
307 require.Nil(t, err)
308 ldb2, err := NewLocalStateDB(dirLocal2, sdb, TypeBatchBuilder, 32)
309 assert.Nil(t, err)
310
311 // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
312 err = ldb2.Reset(4, true)
313 assert.Nil(t, err)
314 // check that currentBatch is 4 after the Reset
315 cb, err = ldb2.GetCurrentBatch()
316 assert.Nil(t, err)
317 assert.Equal(t, common.BatchNum(4), cb)
318 // advance one checkpoint in ldb2
319 err = ldb2.MakeCheckpoint()
320 assert.Nil(t, err)
321 cb, err = ldb2.GetCurrentBatch()
322 assert.Nil(t, err)
323 assert.Equal(t, common.BatchNum(5), cb)
324
325 debug := false
326 if debug {
327 printCheckpoints(t, sdb.path)
328 printCheckpoints(t, ldb.path)
329 printCheckpoints(t, ldb2.path)
330 }
331}
332
333func printCheckpoints(t *testing.T, path string) {
334 files, err := ioutil.ReadDir(path)
335 assert.Nil(t, err)
336
337 fmt.Println(path)
338 for _, f := range files {
339 fmt.Println(" " + f.Name())
340 }
341}