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