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	"os"
  9	"strings"
 10	"testing"
 11
 12	ethCommon "github.com/ethereum/go-ethereum/common"
 13	ethCrypto "github.com/ethereum/go-ethereum/crypto"
 14	"github.com/hermeznetwork/hermez-node/common"
 15	"github.com/hermeznetwork/tracerr"
 16	"github.com/iden3/go-iden3-crypto/babyjub"
 17	"github.com/iden3/go-merkletree/db"
 18	"github.com/stretchr/testify/assert"
 19	"github.com/stretchr/testify/require"
 20)
 21
 22func newAccount(t *testing.T, i int) *common.Account {
 23	var sk babyjub.PrivateKey
 24	_, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
 25	require.Nil(t, err)
 26	pk := sk.Public()
 27
 28	key, err := ethCrypto.GenerateKey()
 29	require.Nil(t, err)
 30	address := ethCrypto.PubkeyToAddress(key.PublicKey)
 31
 32	return &common.Account{
 33		Idx:       common.Idx(256 + i),
 34		TokenID:   common.TokenID(i),
 35		Nonce:     common.Nonce(i),
 36		Balance:   big.NewInt(1000),
 37		PublicKey: pk,
 38		EthAddr:   address,
 39	}
 40}
 41
 42func TestNewStateDBIntermediateState(t *testing.T) {
 43	dir, err := ioutil.TempDir("", "tmpdb")
 44	require.Nil(t, err)
 45	defer assert.Nil(t, os.RemoveAll(dir))
 46
 47	sdb, err := NewStateDB(dir, TypeTxSelector, 0)
 48	assert.Nil(t, err)
 49
 50	// test values
 51	k0 := []byte("testkey0")
 52	k1 := []byte("testkey1")
 53	v0 := []byte("testvalue0")
 54	v1 := []byte("testvalue1")
 55
 56	// store some data
 57	tx, err := sdb.db.NewTx()
 58	assert.Nil(t, err)
 59	err = tx.Put(k0, v0)
 60	assert.Nil(t, err)
 61	err = tx.Commit()
 62	assert.Nil(t, err)
 63	v, err := sdb.db.Get(k0)
 64	assert.Nil(t, err)
 65	assert.Equal(t, v0, v)
 66
 67	// call NewStateDB which should get the db at the last checkpoint state
 68	// executing a Reset (discarding the last 'testkey0'&'testvalue0' data)
 69	sdb, err = NewStateDB(dir, TypeTxSelector, 0)
 70	assert.Nil(t, err)
 71	v, err = sdb.db.Get(k0)
 72	assert.NotNil(t, err)
 73	assert.Equal(t, db.ErrNotFound, tracerr.Unwrap(err))
 74	assert.Nil(t, v)
 75
 76	// store the same data from the beginning that has ben lost since last NewStateDB
 77	tx, err = sdb.db.NewTx()
 78	assert.Nil(t, err)
 79	err = tx.Put(k0, v0)
 80	assert.Nil(t, err)
 81	err = tx.Commit()
 82	assert.Nil(t, err)
 83	v, err = sdb.db.Get(k0)
 84	assert.Nil(t, err)
 85	assert.Equal(t, v0, v)
 86
 87	// make checkpoints with the current state
 88	bn, err := sdb.GetCurrentBatch()
 89	assert.Nil(t, err)
 90	assert.Equal(t, common.BatchNum(0), bn)
 91	err = sdb.MakeCheckpoint()
 92	assert.Nil(t, err)
 93	bn, err = sdb.GetCurrentBatch()
 94	assert.Nil(t, err)
 95	assert.Equal(t, common.BatchNum(1), bn)
 96
 97	// write more data
 98	tx, err = sdb.db.NewTx()
 99	assert.Nil(t, err)
100	err = tx.Put(k1, v1)
101	assert.Nil(t, err)
102	err = tx.Commit()
103	assert.Nil(t, err)
104
105	v, err = sdb.db.Get(k1)
106	assert.Nil(t, err)
107	assert.Equal(t, v1, v)
108
109	// call NewStateDB which should get the db at the last checkpoint state
110	// executing a Reset (discarding the last 'testkey1'&'testvalue1' data)
111	sdb, err = NewStateDB(dir, TypeTxSelector, 0)
112	assert.Nil(t, err)
113
114	v, err = sdb.db.Get(k0)
115	assert.Nil(t, err)
116	assert.Equal(t, v0, v)
117
118	v, err = sdb.db.Get(k1)
119	assert.NotNil(t, err)
120	assert.Equal(t, db.ErrNotFound, tracerr.Unwrap(err))
121	assert.Nil(t, v)
122}
123
124func TestStateDBWithoutMT(t *testing.T) {
125	dir, err := ioutil.TempDir("", "tmpdb")
126	require.Nil(t, err)
127	defer assert.Nil(t, os.RemoveAll(dir))
128
129	sdb, err := NewStateDB(dir, TypeTxSelector, 0)
130	assert.Nil(t, err)
131
132	// create test accounts
133	var accounts []*common.Account
134	for i := 0; i < 4; i++ {
135		accounts = append(accounts, newAccount(t, i))
136	}
137
138	// get non-existing account, expecting an error
139	unexistingAccount := common.Idx(1)
140	_, err = sdb.GetAccount(unexistingAccount)
141	assert.NotNil(t, err)
142	assert.Equal(t, db.ErrNotFound, tracerr.Unwrap(err))
143
144	// add test accounts
145	for i := 0; i < len(accounts); i++ {
146		_, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
147		assert.Nil(t, err)
148	}
149
150	for i := 0; i < len(accounts); i++ {
151		existingAccount := accounts[i].Idx
152		accGetted, err := sdb.GetAccount(existingAccount)
153		assert.Nil(t, err)
154		assert.Equal(t, accounts[i], accGetted)
155	}
156
157	// try already existing idx and get error
158	existingAccount := common.Idx(256)
159	_, err = sdb.GetAccount(existingAccount) // check that exist
160	assert.Nil(t, err)
161	_, err = sdb.CreateAccount(common.Idx(256), accounts[1]) // check that can not be created twice
162	assert.NotNil(t, err)
163	assert.Equal(t, ErrAccountAlreadyExists, tracerr.Unwrap(err))
164
165	// update accounts
166	for i := 0; i < len(accounts); i++ {
167		accounts[i].Nonce = accounts[i].Nonce + 1
168		existingAccount = common.Idx(i)
169		_, err = sdb.UpdateAccount(existingAccount, accounts[i])
170		assert.Nil(t, err)
171	}
172
173	_, err = sdb.MTGetProof(common.Idx(1))
174	assert.NotNil(t, err)
175	assert.Equal(t, ErrStateDBWithoutMT, tracerr.Unwrap(err))
176}
177
178func TestStateDBWithMT(t *testing.T) {
179	dir, err := ioutil.TempDir("", "tmpdb")
180	require.Nil(t, err)
181	defer assert.Nil(t, os.RemoveAll(dir))
182
183	sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
184	assert.Nil(t, err)
185
186	// create test accounts
187	var accounts []*common.Account
188	for i := 0; i < 20; i++ {
189		accounts = append(accounts, newAccount(t, i))
190	}
191
192	// get non-existing account, expecting an error
193	_, err = sdb.GetAccount(common.Idx(1))
194	assert.NotNil(t, err)
195	assert.Equal(t, db.ErrNotFound, tracerr.Unwrap(err))
196
197	// add test accounts
198	for i := 0; i < len(accounts); i++ {
199		_, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
200		assert.Nil(t, err)
201	}
202
203	for i := 0; i < len(accounts); i++ {
204		accGetted, err := sdb.GetAccount(accounts[i].Idx)
205		assert.Nil(t, err)
206		assert.Equal(t, accounts[i], accGetted)
207	}
208
209	// try already existing idx and get error
210	_, err = sdb.GetAccount(common.Idx(256)) // check that exist
211	assert.Nil(t, err)
212	_, err = sdb.CreateAccount(common.Idx(256), accounts[1]) // check that can not be created twice
213	assert.NotNil(t, err)
214	assert.Equal(t, ErrAccountAlreadyExists, tracerr.Unwrap(err))
215
216	_, err = sdb.MTGetProof(common.Idx(256))
217	assert.Nil(t, err)
218
219	// update accounts
220	for i := 0; i < len(accounts); i++ {
221		accounts[i].Nonce = accounts[i].Nonce + 1
222		_, err = sdb.UpdateAccount(accounts[i].Idx, accounts[i])
223		assert.Nil(t, err)
224	}
225	a, err := sdb.GetAccount(common.Idx(256)) // check that account value has been updated
226	assert.Nil(t, err)
227	assert.Equal(t, accounts[0].Nonce, a.Nonce)
228}
229
230func TestCheckpoints(t *testing.T) {
231	dir, err := ioutil.TempDir("", "sdb")
232	require.Nil(t, err)
233	defer assert.Nil(t, os.RemoveAll(dir))
234
235	sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
236	assert.Nil(t, err)
237
238	// create test accounts
239	var accounts []*common.Account
240	for i := 0; i < 10; i++ {
241		accounts = append(accounts, newAccount(t, i))
242	}
243
244	// add test accounts
245	for i := 0; i < len(accounts); i++ {
246		_, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
247		assert.Nil(t, err)
248	}
249
250	// do checkpoints and check that currentBatch is correct
251	err = sdb.MakeCheckpoint()
252	assert.Nil(t, err)
253	cb, err := sdb.GetCurrentBatch()
254	assert.Nil(t, err)
255	assert.Equal(t, common.BatchNum(1), cb)
256
257	for i := 1; i < 10; i++ {
258		err = sdb.MakeCheckpoint()
259		assert.Nil(t, err)
260
261		cb, err = sdb.GetCurrentBatch()
262		assert.Nil(t, err)
263		assert.Equal(t, common.BatchNum(i+1), cb)
264	}
265
266	// printCheckpoints(t, sdb.path)
267
268	// reset checkpoint
269	err = sdb.Reset(3)
270	assert.Nil(t, err)
271
272	// check that reset can be repeated (as there exist the 'current' and
273	// 'BatchNum3', from where the 'current' is a copy)
274	err = sdb.Reset(3)
275	require.Nil(t, err)
276
277	// check that currentBatch is as expected after Reset
278	cb, err = sdb.GetCurrentBatch()
279	assert.Nil(t, err)
280	assert.Equal(t, common.BatchNum(3), cb)
281
282	// advance one checkpoint and check that currentBatch is fine
283	err = sdb.MakeCheckpoint()
284	assert.Nil(t, err)
285	cb, err = sdb.GetCurrentBatch()
286	assert.Nil(t, err)
287	assert.Equal(t, common.BatchNum(4), cb)
288
289	err = sdb.DeleteCheckpoint(common.BatchNum(9))
290	assert.Nil(t, err)
291	err = sdb.DeleteCheckpoint(common.BatchNum(10))
292	assert.Nil(t, err)
293	err = sdb.DeleteCheckpoint(common.BatchNum(9)) // does not exist, should return err
294	assert.NotNil(t, err)
295	err = sdb.DeleteCheckpoint(common.BatchNum(11)) // does not exist, should return err
296	assert.NotNil(t, err)
297
298	// Create a LocalStateDB from the initial StateDB
299	dirLocal, err := ioutil.TempDir("", "ldb")
300	require.Nil(t, err)
301	defer assert.Nil(t, os.RemoveAll(dirLocal))
302	ldb, err := NewLocalStateDB(dirLocal, sdb, TypeBatchBuilder, 32)
303	assert.Nil(t, err)
304
305	// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
306	err = ldb.Reset(4, true)
307	assert.Nil(t, err)
308	// check that currentBatch is 4 after the Reset
309	cb, err = ldb.GetCurrentBatch()
310	assert.Nil(t, err)
311	assert.Equal(t, common.BatchNum(4), cb)
312	// advance one checkpoint in ldb
313	err = ldb.MakeCheckpoint()
314	assert.Nil(t, err)
315	cb, err = ldb.GetCurrentBatch()
316	assert.Nil(t, err)
317	assert.Equal(t, common.BatchNum(5), cb)
318
319	// Create a 2nd LocalStateDB from the initial StateDB
320	dirLocal2, err := ioutil.TempDir("", "ldb2")
321	require.Nil(t, err)
322	defer assert.Nil(t, os.RemoveAll(dirLocal2))
323	ldb2, err := NewLocalStateDB(dirLocal2, sdb, TypeBatchBuilder, 32)
324	assert.Nil(t, err)
325
326	// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
327	err = ldb2.Reset(4, true)
328	assert.Nil(t, err)
329	// check that currentBatch is 4 after the Reset
330	cb, err = ldb2.GetCurrentBatch()
331	assert.Nil(t, err)
332	assert.Equal(t, common.BatchNum(4), cb)
333	// advance one checkpoint in ldb2
334	err = ldb2.MakeCheckpoint()
335	assert.Nil(t, err)
336	cb, err = ldb2.GetCurrentBatch()
337	assert.Nil(t, err)
338	assert.Equal(t, common.BatchNum(5), cb)
339
340	debug := false
341	if debug {
342		printCheckpoints(t, sdb.path)
343		printCheckpoints(t, ldb.path)
344		printCheckpoints(t, ldb2.path)
345	}
346}
347
348func TestStateDBGetAccounts(t *testing.T) {
349	dir, err := ioutil.TempDir("", "tmpdb")
350	require.Nil(t, err)
351
352	sdb, err := NewStateDB(dir, TypeTxSelector, 0)
353	assert.Nil(t, err)
354
355	// create test accounts
356	var accounts []common.Account
357	for i := 0; i < 16; i++ {
358		account := newAccount(t, i)
359		accounts = append(accounts, *account)
360	}
361
362	// add test accounts
363	for i := range accounts {
364		_, err = sdb.CreateAccount(accounts[i].Idx, &accounts[i])
365		require.Nil(t, err)
366	}
367
368	dbAccounts, err := sdb.GetAccounts()
369	require.Nil(t, err)
370	assert.Equal(t, accounts, dbAccounts)
371}
372
373func printCheckpoints(t *testing.T, path string) {
374	files, err := ioutil.ReadDir(path)
375	assert.Nil(t, err)
376
377	fmt.Println(path)
378	for _, f := range files {
379		fmt.Println("	" + f.Name())
380	}
381}
382
383func bigFromStr(h string, u int) *big.Int {
384	if u == 16 {
385		h = strings.TrimPrefix(h, "0x")
386	}
387	b, ok := new(big.Int).SetString(h, u)
388	if !ok {
389		panic("bigFromStr err")
390	}
391	return b
392}
393
394func TestCheckAccountsTreeTestVectors(t *testing.T) {
395	dir, err := ioutil.TempDir("", "tmpdb")
396	require.Nil(t, err)
397	defer assert.Nil(t, os.RemoveAll(dir))
398
399	sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
400	require.Nil(t, err)
401
402	ay0 := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(253), nil), big.NewInt(1))
403	// test value from js version (compatibility-canary)
404	assert.Equal(t, "1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", (hex.EncodeToString(ay0.Bytes())))
405	bjj0, err := babyjub.PointFromSignAndY(true, ay0)
406	require.Nil(t, err)
407
408	ay1 := bigFromStr("00", 16)
409	bjj1, err := babyjub.PointFromSignAndY(false, ay1)
410	require.Nil(t, err)
411	ay2 := bigFromStr("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7", 16)
412	bjj2, err := babyjub.PointFromSignAndY(false, ay2)
413	require.Nil(t, err)
414
415	ay3 := bigFromStr("0x10", 16) // 0x10=16
416	bjj3, err := babyjub.PointFromSignAndY(false, ay3)
417	require.Nil(t, err)
418	accounts := []*common.Account{
419		{
420			Idx:       1,
421			TokenID:   0xFFFFFFFF,
422			PublicKey: (*babyjub.PublicKey)(bjj0),
423			EthAddr:   ethCommon.HexToAddress("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
424			Nonce:     common.Nonce(0xFFFFFFFFFF),
425			Balance:   bigFromStr("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16),
426		},
427		{
428			Idx:       100,
429			TokenID:   0,
430			PublicKey: (*babyjub.PublicKey)(bjj1),
431			EthAddr:   ethCommon.HexToAddress("0x00"),
432			Nonce:     common.Nonce(0),
433			Balance:   bigFromStr("0", 10),
434		},
435		{
436			Idx:       0xFFFFFFFFFFFF,
437			TokenID:   3,
438			PublicKey: (*babyjub.PublicKey)(bjj2),
439			EthAddr:   ethCommon.HexToAddress("0xA3C88ac39A76789437AED31B9608da72e1bbfBF9"),
440			Nonce:     common.Nonce(129),
441			Balance:   bigFromStr("42000000000000000000", 10),
442		},
443		{
444			Idx:       10000,
445			TokenID:   1000,
446			PublicKey: (*babyjub.PublicKey)(bjj3),
447			EthAddr:   ethCommon.HexToAddress("0x64"),
448			Nonce:     common.Nonce(1900),
449			Balance:   bigFromStr("14000000000000000000", 10),
450		},
451	}
452	for i := 0; i < len(accounts); i++ {
453		_, err = accounts[i].HashValue()
454		require.Nil(t, err)
455		_, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
456		require.Nil(t, err)
457	}
458	// root value generated by js version:
459	assert.Equal(t, "17298264051379321456969039521810887093935433569451713402227686942080129181291", sdb.mt.Root().BigInt().String())
460}