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		Idx:       common.Idx(256 + i),
 30		TokenID:   common.TokenID(i),
 31		Nonce:     common.Nonce(i),
 32		Balance:   big.NewInt(1000),
 33		PublicKey: pk,
 34		EthAddr:   address,
 35	}
 36}
 37
 38func TestNewStateDBIntermediateState(t *testing.T) {
 39	dir, err := ioutil.TempDir("", "tmpdb")
 40	require.Nil(t, err)
 41
 42	sdb, err := NewStateDB(dir, TypeTxSelector, 0)
 43	assert.Nil(t, err)
 44
 45	// test values
 46	k0 := []byte("testkey0")
 47	k1 := []byte("testkey1")
 48	v0 := []byte("testvalue0")
 49	v1 := []byte("testvalue1")
 50
 51	// store some data
 52	tx, err := sdb.db.NewTx()
 53	assert.Nil(t, err)
 54	err = tx.Put(k0, v0)
 55	assert.Nil(t, err)
 56	err = tx.Commit()
 57	assert.Nil(t, err)
 58	v, err := sdb.db.Get(k0)
 59	assert.Nil(t, err)
 60	assert.Equal(t, v0, v)
 61
 62	// call NewStateDB which should get the db at the last checkpoint state
 63	// executing a Reset (discarding the last 'testkey0'&'testvalue0' data)
 64	sdb, err = NewStateDB(dir, TypeTxSelector, 0)
 65	assert.Nil(t, err)
 66	v, err = sdb.db.Get(k0)
 67	assert.NotNil(t, err)
 68	assert.Equal(t, db.ErrNotFound, err)
 69	assert.Nil(t, v)
 70
 71	// store the same data from the beginning that has ben lost since last NewStateDB
 72	tx, err = sdb.db.NewTx()
 73	assert.Nil(t, err)
 74	err = tx.Put(k0, v0)
 75	assert.Nil(t, err)
 76	err = tx.Commit()
 77	assert.Nil(t, err)
 78	v, err = sdb.db.Get(k0)
 79	assert.Nil(t, err)
 80	assert.Equal(t, v0, v)
 81
 82	// make checkpoints with the current state
 83	bn, err := sdb.GetCurrentBatch()
 84	assert.Nil(t, err)
 85	assert.Equal(t, common.BatchNum(0), bn)
 86	err = sdb.MakeCheckpoint()
 87	assert.Nil(t, err)
 88	bn, err = sdb.GetCurrentBatch()
 89	assert.Nil(t, err)
 90	assert.Equal(t, common.BatchNum(1), bn)
 91
 92	// write more data
 93	tx, err = sdb.db.NewTx()
 94	assert.Nil(t, err)
 95	err = tx.Put(k1, v1)
 96	assert.Nil(t, err)
 97	err = tx.Commit()
 98	assert.Nil(t, err)
 99
100	v, err = sdb.db.Get(k1)
101	assert.Nil(t, err)
102	assert.Equal(t, v1, v)
103
104	// call NewStateDB which should get the db at the last checkpoint state
105	// executing a Reset (discarding the last 'testkey1'&'testvalue1' data)
106	sdb, err = NewStateDB(dir, TypeTxSelector, 0)
107	assert.Nil(t, err)
108
109	v, err = sdb.db.Get(k0)
110	assert.Nil(t, err)
111	assert.Equal(t, v0, v)
112
113	v, err = sdb.db.Get(k1)
114	assert.NotNil(t, err)
115	assert.Equal(t, db.ErrNotFound, err)
116	assert.Nil(t, v)
117}
118
119func TestStateDBWithoutMT(t *testing.T) {
120	dir, err := ioutil.TempDir("", "tmpdb")
121	require.Nil(t, err)
122
123	sdb, err := NewStateDB(dir, TypeTxSelector, 0)
124	assert.Nil(t, err)
125
126	// create test accounts
127	var accounts []*common.Account
128	for i := 0; i < 4; i++ {
129		accounts = append(accounts, newAccount(t, i))
130	}
131
132	// get non-existing account, expecting an error
133	unexistingAccount := common.Idx(1)
134	_, err = sdb.GetAccount(unexistingAccount)
135	assert.NotNil(t, err)
136	assert.Equal(t, db.ErrNotFound, err)
137
138	// add test accounts
139	for i := 0; i < len(accounts); i++ {
140		_, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
141		assert.Nil(t, err)
142	}
143
144	for i := 0; i < len(accounts); i++ {
145		existingAccount := accounts[i].Idx
146		accGetted, err := sdb.GetAccount(existingAccount)
147		assert.Nil(t, err)
148		assert.Equal(t, accounts[i], accGetted)
149	}
150
151	// try already existing idx and get error
152	existingAccount := common.Idx(256)
153	_, err = sdb.GetAccount(existingAccount) // check that exist
154	assert.Nil(t, err)
155	_, err = sdb.CreateAccount(common.Idx(256), accounts[1]) // check that can not be created twice
156	assert.NotNil(t, err)
157	assert.Equal(t, ErrAccountAlreadyExists, err)
158
159	// update accounts
160	for i := 0; i < len(accounts); i++ {
161		accounts[i].Nonce = accounts[i].Nonce + 1
162		existingAccount = common.Idx(i)
163		_, err = sdb.UpdateAccount(existingAccount, accounts[i])
164		assert.Nil(t, err)
165	}
166
167	_, err = sdb.MTGetProof(common.Idx(1))
168	assert.NotNil(t, err)
169	assert.Equal(t, ErrStateDBWithoutMT, err)
170}
171
172func TestStateDBWithMT(t *testing.T) {
173	dir, err := ioutil.TempDir("", "tmpdb")
174	require.Nil(t, err)
175
176	sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
177	assert.Nil(t, err)
178
179	// create test accounts
180	var accounts []*common.Account
181	for i := 0; i < 20; i++ {
182		accounts = append(accounts, newAccount(t, i))
183	}
184
185	// get non-existing account, expecting an error
186	_, err = sdb.GetAccount(common.Idx(1))
187	assert.NotNil(t, err)
188	assert.Equal(t, db.ErrNotFound, err)
189
190	// add test accounts
191	for i := 0; i < len(accounts); i++ {
192		_, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
193		assert.Nil(t, err)
194	}
195
196	for i := 0; i < len(accounts); i++ {
197		accGetted, err := sdb.GetAccount(accounts[i].Idx)
198		assert.Nil(t, err)
199		assert.Equal(t, accounts[i], accGetted)
200	}
201
202	// try already existing idx and get error
203	_, err = sdb.GetAccount(common.Idx(256)) // check that exist
204	assert.Nil(t, err)
205	_, err = sdb.CreateAccount(common.Idx(256), accounts[1]) // check that can not be created twice
206	assert.NotNil(t, err)
207	assert.Equal(t, ErrAccountAlreadyExists, err)
208
209	_, err = sdb.MTGetProof(common.Idx(256))
210	assert.Nil(t, err)
211
212	// update accounts
213	for i := 0; i < len(accounts); i++ {
214		accounts[i].Nonce = accounts[i].Nonce + 1
215		_, err = sdb.UpdateAccount(accounts[i].Idx, accounts[i])
216		assert.Nil(t, err)
217	}
218	a, err := sdb.GetAccount(common.Idx(256)) // check that account value has been updated
219	assert.Nil(t, err)
220	assert.Equal(t, accounts[0].Nonce, a.Nonce)
221}
222
223func TestCheckpoints(t *testing.T) {
224	dir, err := ioutil.TempDir("", "sdb")
225	require.Nil(t, err)
226
227	sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
228	assert.Nil(t, err)
229
230	// create test accounts
231	var accounts []*common.Account
232	for i := 0; i < 10; i++ {
233		accounts = append(accounts, newAccount(t, i))
234	}
235
236	// add test accounts
237	for i := 0; i < len(accounts); i++ {
238		_, err = sdb.CreateAccount(accounts[i].Idx, accounts[i])
239		assert.Nil(t, err)
240	}
241
242	// do checkpoints and check that currentBatch is correct
243	err = sdb.MakeCheckpoint()
244	assert.Nil(t, err)
245	cb, err := sdb.GetCurrentBatch()
246	assert.Nil(t, err)
247	assert.Equal(t, common.BatchNum(1), cb)
248
249	for i := 1; i < 10; i++ {
250		err = sdb.MakeCheckpoint()
251		assert.Nil(t, err)
252
253		cb, err = sdb.GetCurrentBatch()
254		assert.Nil(t, err)
255		assert.Equal(t, common.BatchNum(i+1), cb)
256	}
257
258	// printCheckpoints(t, sdb.path)
259
260	// reset checkpoint
261	err = sdb.Reset(3)
262	assert.Nil(t, err)
263
264	// check that reset can be repeated (as there exist the 'current' and
265	// 'BatchNum3', from where the 'current' is a copy)
266	err = sdb.Reset(3)
267	require.Nil(t, err)
268
269	// check that currentBatch is as expected after Reset
270	cb, err = sdb.GetCurrentBatch()
271	assert.Nil(t, err)
272	assert.Equal(t, common.BatchNum(3), cb)
273
274	// advance one checkpoint and check that currentBatch is fine
275	err = sdb.MakeCheckpoint()
276	assert.Nil(t, err)
277	cb, err = sdb.GetCurrentBatch()
278	assert.Nil(t, err)
279	assert.Equal(t, common.BatchNum(4), cb)
280
281	err = sdb.DeleteCheckpoint(common.BatchNum(9))
282	assert.Nil(t, err)
283	err = sdb.DeleteCheckpoint(common.BatchNum(10))
284	assert.Nil(t, err)
285	err = sdb.DeleteCheckpoint(common.BatchNum(9)) // does not exist, should return err
286	assert.NotNil(t, err)
287	err = sdb.DeleteCheckpoint(common.BatchNum(11)) // does not exist, should return err
288	assert.NotNil(t, err)
289
290	// Create a LocalStateDB from the initial StateDB
291	dirLocal, err := ioutil.TempDir("", "ldb")
292	require.Nil(t, err)
293	ldb, err := NewLocalStateDB(dirLocal, sdb, TypeBatchBuilder, 32)
294	assert.Nil(t, err)
295
296	// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
297	err = ldb.Reset(4, true)
298	assert.Nil(t, err)
299	// check that currentBatch is 4 after the Reset
300	cb, err = ldb.GetCurrentBatch()
301	assert.Nil(t, err)
302	assert.Equal(t, common.BatchNum(4), cb)
303	// advance one checkpoint in ldb
304	err = ldb.MakeCheckpoint()
305	assert.Nil(t, err)
306	cb, err = ldb.GetCurrentBatch()
307	assert.Nil(t, err)
308	assert.Equal(t, common.BatchNum(5), cb)
309
310	// Create a 2nd LocalStateDB from the initial StateDB
311	dirLocal2, err := ioutil.TempDir("", "ldb2")
312	require.Nil(t, err)
313	ldb2, err := NewLocalStateDB(dirLocal2, sdb, TypeBatchBuilder, 32)
314	assert.Nil(t, err)
315
316	// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
317	err = ldb2.Reset(4, true)
318	assert.Nil(t, err)
319	// check that currentBatch is 4 after the Reset
320	cb, err = ldb2.GetCurrentBatch()
321	assert.Nil(t, err)
322	assert.Equal(t, common.BatchNum(4), cb)
323	// advance one checkpoint in ldb2
324	err = ldb2.MakeCheckpoint()
325	assert.Nil(t, err)
326	cb, err = ldb2.GetCurrentBatch()
327	assert.Nil(t, err)
328	assert.Equal(t, common.BatchNum(5), cb)
329
330	debug := false
331	if debug {
332		printCheckpoints(t, sdb.path)
333		printCheckpoints(t, ldb.path)
334		printCheckpoints(t, ldb2.path)
335	}
336}
337
338func TestStateDBGetAccounts(t *testing.T) {
339	dir, err := ioutil.TempDir("", "tmpdb")
340	require.Nil(t, err)
341
342	sdb, err := NewStateDB(dir, TypeTxSelector, 0)
343	assert.Nil(t, err)
344
345	// create test accounts
346	var accounts []common.Account
347	for i := 0; i < 16; i++ {
348		account := newAccount(t, i)
349		accounts = append(accounts, *account)
350	}
351
352	// add test accounts
353	for i := range accounts {
354		_, err = sdb.CreateAccount(accounts[i].Idx, &accounts[i])
355		require.Nil(t, err)
356	}
357
358	dbAccounts, err := sdb.GetAccounts()
359	require.Nil(t, err)
360	assert.Equal(t, accounts, dbAccounts)
361}
362
363func printCheckpoints(t *testing.T, path string) {
364	files, err := ioutil.ReadDir(path)
365	assert.Nil(t, err)
366
367	fmt.Println(path)
368	for _, f := range files {
369		fmt.Println("	" + f.Name())
370	}
371}