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, TypeTxSelector, 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, TypeTxSelector, 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, TypeTxSelector, 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, TypeTxSelector, 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	unexistingAccount := common.Idx(1)
133	_, err = sdb.GetAccount(&unexistingAccount)
134	assert.NotNil(t, err)
135	assert.Equal(t, db.ErrNotFound, err)
136
137	// add test accounts
138	for i := 0; i < len(accounts); i++ {
139		_, err = sdb.CreateAccount(common.Idx(i), accounts[i])
140		assert.Nil(t, err)
141	}
142
143	for i := 0; i < len(accounts); i++ {
144		existingAccount := common.Idx(i)
145		accGetted, err := sdb.GetAccount(&existingAccount)
146		assert.Nil(t, err)
147		assert.Equal(t, accounts[i], accGetted)
148	}
149
150	// try already existing idx and get error
151	existingAccount := common.Idx(1)
152	_, err = sdb.GetAccount(&existingAccount) // check that exist
153	assert.Nil(t, err)
154	_, err = sdb.CreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
155	assert.NotNil(t, err)
156	assert.Equal(t, ErrAccountAlreadyExists, err)
157
158	// update accounts
159	for i := 0; i < len(accounts); i++ {
160		accounts[i].Nonce = accounts[i].Nonce + 1
161		existingAccount = common.Idx(i)
162		_, err = sdb.UpdateAccount(&existingAccount, accounts[i])
163		assert.Nil(t, err)
164	}
165
166	_, err = sdb.MTGetProof(common.Idx(1))
167	assert.NotNil(t, err)
168	assert.Equal(t, ErrStateDBWithoutMT, err)
169}
170
171func TestStateDBWithMT(t *testing.T) {
172	dir, err := ioutil.TempDir("", "tmpdb")
173	require.Nil(t, err)
174
175	sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
176	assert.Nil(t, err)
177
178	// create test accounts
179	var accounts []*common.Account
180	for i := 0; i < 20; i++ {
181		accounts = append(accounts, newAccount(t, i))
182	}
183
184	// get non-existing account, expecting an error
185	accountIdx := common.Idx(1)
186	_, err = sdb.GetAccount(&accountIdx)
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(common.Idx(i), accounts[i])
193		assert.Nil(t, err)
194	}
195
196	for i := 0; i < len(accounts); i++ {
197		accountIdx = common.Idx(i)
198		accGetted, err := sdb.GetAccount(&accountIdx)
199		assert.Nil(t, err)
200		assert.Equal(t, accounts[i], accGetted)
201	}
202
203	// try already existing idx and get error
204	accountIdx = 1
205	_, err = sdb.GetAccount(&accountIdx) // check that exist
206	assert.Nil(t, err)
207	_, err = sdb.CreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
208	assert.NotNil(t, err)
209	assert.Equal(t, ErrAccountAlreadyExists, err)
210
211	_, err = sdb.MTGetProof(common.Idx(1))
212	assert.Nil(t, err)
213
214	// update accounts
215	for i := 0; i < len(accounts); i++ {
216		accounts[i].Nonce = accounts[i].Nonce + 1
217		accountIdx = common.Idx(i)
218		_, err = sdb.UpdateAccount(&accountIdx, accounts[i])
219		assert.Nil(t, err)
220	}
221	accountIdx = 1
222	a, err := sdb.GetAccount(&accountIdx) // check that account value has been updated
223	assert.Nil(t, err)
224	assert.Equal(t, accounts[1].Nonce, a.Nonce)
225}
226
227func TestCheckpoints(t *testing.T) {
228	dir, err := ioutil.TempDir("", "sdb")
229	require.Nil(t, err)
230
231	sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
232	assert.Nil(t, err)
233
234	// create test accounts
235	var accounts []*common.Account
236	for i := 0; i < 10; i++ {
237		accounts = append(accounts, newAccount(t, i))
238	}
239
240	// add test accounts
241	for i := 0; i < len(accounts); i++ {
242		_, err = sdb.CreateAccount(common.Idx(i), accounts[i])
243		assert.Nil(t, err)
244	}
245
246	// do checkpoints and check that currentBatch is correct
247	err = sdb.MakeCheckpoint()
248	assert.Nil(t, err)
249	cb, err := sdb.GetCurrentBatch()
250	assert.Nil(t, err)
251	assert.Equal(t, common.BatchNum(1), cb)
252
253	for i := 1; i < 10; i++ {
254		err = sdb.MakeCheckpoint()
255		assert.Nil(t, err)
256
257		cb, err = sdb.GetCurrentBatch()
258		assert.Nil(t, err)
259		assert.Equal(t, common.BatchNum(i+1), cb)
260	}
261
262	// printCheckpoints(t, sdb.path)
263
264	// reset checkpoint
265	err = sdb.Reset(3)
266	assert.Nil(t, err)
267
268	// check that reset can be repeated (as there exist the 'current' and
269	// 'BatchNum3', from where the 'current' is a copy)
270	err = sdb.Reset(3)
271	require.Nil(t, err)
272
273	// check that currentBatch is as expected after Reset
274	cb, err = sdb.GetCurrentBatch()
275	assert.Nil(t, err)
276	assert.Equal(t, common.BatchNum(3), cb)
277
278	// advance one checkpoint and check that currentBatch is fine
279	err = sdb.MakeCheckpoint()
280	assert.Nil(t, err)
281	cb, err = sdb.GetCurrentBatch()
282	assert.Nil(t, err)
283	assert.Equal(t, common.BatchNum(4), cb)
284
285	err = sdb.DeleteCheckpoint(common.BatchNum(9))
286	assert.Nil(t, err)
287	err = sdb.DeleteCheckpoint(common.BatchNum(10))
288	assert.Nil(t, err)
289	err = sdb.DeleteCheckpoint(common.BatchNum(9)) // does not exist, should return err
290	assert.NotNil(t, err)
291	err = sdb.DeleteCheckpoint(common.BatchNum(11)) // does not exist, should return err
292	assert.NotNil(t, err)
293
294	// Create a LocalStateDB from the initial StateDB
295	dirLocal, err := ioutil.TempDir("", "ldb")
296	require.Nil(t, err)
297	ldb, err := NewLocalStateDB(dirLocal, sdb, TypeBatchBuilder, 32)
298	assert.Nil(t, err)
299
300	// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
301	err = ldb.Reset(4, true)
302	assert.Nil(t, err)
303	// check that currentBatch is 4 after the Reset
304	cb, err = ldb.GetCurrentBatch()
305	assert.Nil(t, err)
306	assert.Equal(t, common.BatchNum(4), cb)
307	// advance one checkpoint in ldb
308	err = ldb.MakeCheckpoint()
309	assert.Nil(t, err)
310	cb, err = ldb.GetCurrentBatch()
311	assert.Nil(t, err)
312	assert.Equal(t, common.BatchNum(5), cb)
313
314	// Create a 2nd LocalStateDB from the initial StateDB
315	dirLocal2, err := ioutil.TempDir("", "ldb2")
316	require.Nil(t, err)
317	ldb2, err := NewLocalStateDB(dirLocal2, sdb, TypeBatchBuilder, 32)
318	assert.Nil(t, err)
319
320	// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
321	err = ldb2.Reset(4, true)
322	assert.Nil(t, err)
323	// check that currentBatch is 4 after the Reset
324	cb, err = ldb2.GetCurrentBatch()
325	assert.Nil(t, err)
326	assert.Equal(t, common.BatchNum(4), cb)
327	// advance one checkpoint in ldb2
328	err = ldb2.MakeCheckpoint()
329	assert.Nil(t, err)
330	cb, err = ldb2.GetCurrentBatch()
331	assert.Nil(t, err)
332	assert.Equal(t, common.BatchNum(5), cb)
333
334	debug := false
335	if debug {
336		printCheckpoints(t, sdb.path)
337		printCheckpoints(t, ldb.path)
338		printCheckpoints(t, ldb2.path)
339	}
340}
341
342func printCheckpoints(t *testing.T, path string) {
343	files, err := ioutil.ReadDir(path)
344	assert.Nil(t, err)
345
346	fmt.Println(path)
347	for _, f := range files {
348		fmt.Println("	" + f.Name())
349	}
350}