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 TestStateDBWithoutMT(t *testing.T) {
38 dir, err := ioutil.TempDir("", "tmpdb")
39 require.Nil(t, err)
40
41 sdb, err := NewStateDB(dir, false, 0)
42 assert.Nil(t, err)
43
44 // create test accounts
45 var accounts []*common.Account
46 for i := 0; i < 100; i++ {
47 accounts = append(accounts, newAccount(t, i))
48 }
49
50 // get non-existing account, expecting an error
51 _, err = sdb.GetAccount(common.Idx(1))
52 assert.NotNil(t, err)
53 assert.Equal(t, db.ErrNotFound, err)
54
55 // add test accounts
56 for i := 0; i < len(accounts); i++ {
57 _, err = sdb.CreateAccount(common.Idx(i), accounts[i])
58 assert.Nil(t, err)
59 }
60
61 for i := 0; i < len(accounts); i++ {
62 accGetted, err := sdb.GetAccount(common.Idx(i))
63 assert.Nil(t, err)
64 assert.Equal(t, accounts[i], accGetted)
65 }
66
67 // try already existing idx and get error
68 _, err = sdb.GetAccount(common.Idx(1)) // check that exist
69 assert.Nil(t, err)
70 _, err = sdb.CreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
71 assert.NotNil(t, err)
72 assert.Equal(t, ErrAccountAlreadyExists, err)
73
74 // update accounts
75 for i := 0; i < len(accounts); i++ {
76 accounts[i].Nonce = accounts[i].Nonce + 1
77 _, err = sdb.UpdateAccount(common.Idx(i), accounts[i])
78 assert.Nil(t, err)
79 }
80
81 _, err = sdb.MTGetProof(common.Idx(1))
82 assert.NotNil(t, err)
83 assert.Equal(t, ErrStateDBWithoutMT, err)
84}
85
86func TestStateDBWithMT(t *testing.T) {
87 dir, err := ioutil.TempDir("", "tmpdb")
88 require.Nil(t, err)
89
90 sdb, err := NewStateDB(dir, true, 32)
91 assert.Nil(t, err)
92
93 // create test accounts
94 var accounts []*common.Account
95 for i := 0; i < 20; i++ {
96 accounts = append(accounts, newAccount(t, i))
97 }
98
99 // get non-existing account, expecting an error
100 _, err = sdb.GetAccount(common.Idx(1))
101 assert.NotNil(t, err)
102 assert.Equal(t, db.ErrNotFound, err)
103
104 // add test accounts
105 for i := 0; i < len(accounts); i++ {
106 _, err = sdb.CreateAccount(common.Idx(i), accounts[i])
107 assert.Nil(t, err)
108 }
109
110 for i := 0; i < len(accounts); i++ {
111 accGetted, err := sdb.GetAccount(common.Idx(i))
112 assert.Nil(t, err)
113 assert.Equal(t, accounts[i], accGetted)
114 }
115
116 // try already existing idx and get error
117 _, err = sdb.GetAccount(common.Idx(1)) // check that exist
118 assert.Nil(t, err)
119 _, err = sdb.CreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
120 assert.NotNil(t, err)
121 assert.Equal(t, ErrAccountAlreadyExists, err)
122
123 _, err = sdb.MTGetProof(common.Idx(1))
124 assert.Nil(t, err)
125
126 // update accounts
127 for i := 0; i < len(accounts); i++ {
128 accounts[i].Nonce = accounts[i].Nonce + 1
129 _, err = sdb.UpdateAccount(common.Idx(i), accounts[i])
130 assert.Nil(t, err)
131 }
132 a, err := sdb.GetAccount(common.Idx(1)) // check that account value has been updated
133 assert.Nil(t, err)
134 assert.Equal(t, accounts[1].Nonce, a.Nonce)
135}
136
137func TestCheckpoints(t *testing.T) {
138 dir, err := ioutil.TempDir("", "sdb")
139 require.Nil(t, err)
140
141 sdb, err := NewStateDB(dir, true, 32)
142 assert.Nil(t, err)
143
144 // create test accounts
145 var accounts []*common.Account
146 for i := 0; i < 10; i++ {
147 accounts = append(accounts, newAccount(t, i))
148 }
149
150 // add test accounts
151 for i := 0; i < len(accounts); i++ {
152 _, err = sdb.CreateAccount(common.Idx(i), accounts[i])
153 assert.Nil(t, err)
154 }
155
156 // do checkpoints and check that currentBatch is correct
157 err = sdb.MakeCheckpoint()
158 assert.Nil(t, err)
159 cb, err := sdb.GetCurrentBatch()
160 assert.Nil(t, err)
161 assert.Equal(t, common.BatchNum(1), cb)
162
163 for i := 1; i < 10; i++ {
164 err = sdb.MakeCheckpoint()
165 assert.Nil(t, err)
166
167 cb, err = sdb.GetCurrentBatch()
168 assert.Nil(t, err)
169 assert.Equal(t, common.BatchNum(i+1), cb)
170 }
171
172 // printCheckpoints(t, sdb.path)
173
174 // reset checkpoint
175 err = sdb.Reset(3)
176 assert.Nil(t, err)
177
178 // check that reset can be repeated (as there exist the 'current' and
179 // 'BatchNum3', from where the 'current' is a copy)
180 err = sdb.Reset(3)
181 require.Nil(t, err)
182
183 // check that currentBatch is as expected after Reset
184 cb, err = sdb.GetCurrentBatch()
185 assert.Nil(t, err)
186 assert.Equal(t, common.BatchNum(3), cb)
187
188 // advance one checkpoint and check that currentBatch is fine
189 err = sdb.MakeCheckpoint()
190 assert.Nil(t, err)
191 cb, err = sdb.GetCurrentBatch()
192 assert.Nil(t, err)
193 assert.Equal(t, common.BatchNum(4), cb)
194
195 err = sdb.DeleteCheckpoint(common.BatchNum(9))
196 assert.Nil(t, err)
197 err = sdb.DeleteCheckpoint(common.BatchNum(10))
198 assert.Nil(t, err)
199 err = sdb.DeleteCheckpoint(common.BatchNum(9)) // does not exist, should return err
200 assert.NotNil(t, err)
201 err = sdb.DeleteCheckpoint(common.BatchNum(11)) // does not exist, should return err
202 assert.NotNil(t, err)
203
204 // Create a LocalStateDB from the initial StateDB
205 dirLocal, err := ioutil.TempDir("", "ldb")
206 require.Nil(t, err)
207 ldb, err := NewLocalStateDB(dirLocal, sdb, true, 32)
208 assert.Nil(t, err)
209
210 // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
211 err = ldb.Reset(4, true)
212 assert.Nil(t, err)
213 // check that currentBatch is 4 after the Reset
214 cb, err = ldb.GetCurrentBatch()
215 assert.Nil(t, err)
216 assert.Equal(t, common.BatchNum(4), cb)
217 // advance one checkpoint in ldb
218 err = ldb.MakeCheckpoint()
219 assert.Nil(t, err)
220 cb, err = ldb.GetCurrentBatch()
221 assert.Nil(t, err)
222 assert.Equal(t, common.BatchNum(5), cb)
223
224 // Create a 2nd LocalStateDB from the initial StateDB
225 dirLocal2, err := ioutil.TempDir("", "ldb2")
226 require.Nil(t, err)
227 ldb2, err := NewLocalStateDB(dirLocal2, sdb, true, 32)
228 assert.Nil(t, err)
229
230 // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
231 err = ldb2.Reset(4, true)
232 assert.Nil(t, err)
233 // check that currentBatch is 4 after the Reset
234 cb, err = ldb2.GetCurrentBatch()
235 assert.Nil(t, err)
236 assert.Equal(t, common.BatchNum(4), cb)
237 // advance one checkpoint in ldb2
238 err = ldb2.MakeCheckpoint()
239 assert.Nil(t, err)
240 cb, err = ldb2.GetCurrentBatch()
241 assert.Nil(t, err)
242 assert.Equal(t, common.BatchNum(5), cb)
243
244 debug := false
245 if debug {
246 printCheckpoints(t, sdb.path)
247 printCheckpoints(t, ldb.path)
248 printCheckpoints(t, ldb2.path)
249 }
250}
251
252func printCheckpoints(t *testing.T, path string) {
253 files, err := ioutil.ReadDir(path)
254 assert.Nil(t, err)
255
256 fmt.Println(path)
257 for _, f := range files {
258 fmt.Println(" " + f.Name())
259 }
260}