arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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, false, 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, false, 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, false, 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, false, 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, true, 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, true, 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, true, 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, true, 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}