• R/O
  • HTTP
  • SSH
  • HTTPS

vapor: Commit

Golang implemented sidechain for Bytom


Commit MetaInfo

Revisione2294cec495077e4d76d8ff22ad4cae63c4eb2d2 (tree)
Time2019-07-01 16:52:48
Authorwz <mars@byto...>
CommiterPaladz

Log Message

Paging (#234)

* add paging

* fix review

* fix review

* remove space

* fix review

* add AccountAlias

* fix test

Change Summary

Incremental Difference

--- a/account/accounts.go
+++ b/account/accounts.go
@@ -57,6 +57,7 @@ var (
5757 ErrContractIndex = errors.New("Exceeded maximum addresses per account")
5858 ErrAccountIndex = errors.New("Exceeded maximum accounts per xpub")
5959 ErrFindTransaction = errors.New("No transaction")
60+ ErrAccountIDEmpty = errors.New("account_id is empty")
6061 )
6162
6263 // ContractKey account control promgram store prefix
--- a/api/query.go
+++ b/api/query.go
@@ -149,49 +149,37 @@ func (a *API) getTransaction(ctx context.Context, txInfo struct {
149149
150150 // POST /list-transactions
151151 func (a *API) listTransactions(ctx context.Context, filter struct {
152- ID string `json:"id"`
153- AccountID string `json:"account_id"`
154- Detail bool `json:"detail"`
155- Unconfirmed bool `json:"unconfirmed"`
156- From uint `json:"from"`
157- Count uint `json:"count"`
152+ AccountID string `json:"account_id"`
153+ AccountAlias string `json:"account_alias"`
154+ StartTxID string `json:"start_tx_id"`
155+ Detail bool `json:"detail"`
156+ Unconfirmed bool `json:"unconfirmed"`
157+ Count uint `json:"count"`
158158 }) Response {
159- transactions := []*query.AnnotatedTx{}
160- var err error
161- var transaction *query.AnnotatedTx
162-
163- if filter.ID != "" {
164- transaction, err = a.wallet.GetTransactionByTxID(filter.ID)
165- if err != nil && filter.Unconfirmed {
166- transaction, err = a.wallet.GetUnconfirmedTxByTxID(filter.ID)
167- }
168-
169- if err != nil {
170- return NewErrorResponse(err)
171- }
172- transactions = []*query.AnnotatedTx{transaction}
173- } else {
174- transactions, err = a.wallet.GetTransactions(filter.AccountID)
159+ accountID := filter.AccountID
160+ if filter.AccountAlias != "" {
161+ acc, err := a.wallet.AccountMgr.FindByAlias(filter.AccountAlias)
175162 if err != nil {
176163 return NewErrorResponse(err)
177164 }
165+ accountID = acc.ID
166+ }
178167
179- if filter.Unconfirmed {
180- unconfirmedTxs, err := a.wallet.GetUnconfirmedTxs(filter.AccountID)
181- if err != nil {
182- return NewErrorResponse(err)
183- }
184- transactions = append(unconfirmedTxs, transactions...)
185- }
168+ if accountID == "" {
169+ return NewErrorResponse(account.ErrAccountIDEmpty)
170+ }
171+
172+ transactions, err := a.wallet.GetTransactions(accountID, filter.StartTxID, filter.Count, filter.Unconfirmed)
173+ if err != nil {
174+ return NewErrorResponse(err)
186175 }
187176
188177 if filter.Detail == false {
189178 txSummary := a.wallet.GetTransactionsSummary(transactions)
190- start, end := getPageRange(len(txSummary), filter.From, filter.Count)
191- return NewSuccessResponse(txSummary[start:end])
179+ return NewSuccessResponse(txSummary)
192180 }
193- start, end := getPageRange(len(transactions), filter.From, filter.Count)
194- return NewSuccessResponse(transactions[start:end])
181+
182+ return NewSuccessResponse(transactions)
195183 }
196184
197185 // POST /get-unconfirmed-transaction
--- a/database/leveldb/db.go
+++ b/database/leveldb/db.go
@@ -1,4 +1,4 @@
1-package db
1+package leveldb
22
33 import . "github.com/tendermint/tmlibs/common"
44
@@ -12,6 +12,7 @@ type DB interface {
1212 NewBatch() Batch
1313 Iterator() Iterator
1414 IteratorPrefix([]byte) Iterator
15+ IteratorPrefixWithStart(Prefix, start []byte) Iterator
1516
1617 // For debugging
1718 Print()
--- /dev/null
+++ b/database/leveldb/db_test.go
@@ -0,0 +1,92 @@
1+package leveldb
2+
3+import (
4+ "fmt"
5+ "io/ioutil"
6+ "os"
7+ "testing"
8+
9+ "github.com/stretchr/testify/require"
10+)
11+
12+func newTempDB(t *testing.T, backend string) (db DB, dbDir string) {
13+ dirname, err := ioutil.TempDir("", "db_common_test")
14+ require.Nil(t, err)
15+ return NewDB("testdb", backend, dirname), dirname
16+}
17+
18+func TestDBIteratorSingleKey(t *testing.T) {
19+ for backend := range backends {
20+ t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) {
21+ db, dir := newTempDB(t, backend)
22+ defer os.RemoveAll(dir)
23+
24+ db.Set([]byte("1"), []byte("value_1"))
25+ itr := db.IteratorPrefixWithStart(nil, nil)
26+ require.Equal(t, []byte(""), itr.Key())
27+ require.Equal(t, true, itr.Next())
28+ require.Equal(t, []byte("1"), itr.Key())
29+ })
30+ }
31+}
32+
33+func TestDBIteratorTwoKeys(t *testing.T) {
34+ for backend := range backends {
35+ t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) {
36+ db, dir := newTempDB(t, backend)
37+ defer os.RemoveAll(dir)
38+
39+ db.SetSync([]byte("1"), []byte("value_1"))
40+ db.SetSync([]byte("2"), []byte("value_1"))
41+
42+ itr := db.IteratorPrefixWithStart(nil, []byte("1"))
43+
44+ require.Equal(t, []byte("1"), itr.Key())
45+
46+ require.Equal(t, true, itr.Next())
47+ itr = db.IteratorPrefixWithStart(nil, []byte("2"))
48+
49+ require.Equal(t, false, itr.Next())
50+ })
51+ }
52+}
53+
54+func TestDBIterator(t *testing.T) {
55+ dirname, err := ioutil.TempDir("", "db_common_test")
56+ require.Nil(t, err)
57+
58+ db, err := NewGoLevelDB("testdb", dirname)
59+ if err != nil {
60+ t.Fatal(err)
61+ }
62+
63+ defer func() {
64+ db.Close()
65+ os.RemoveAll(dirname)
66+ }()
67+
68+ db.SetSync([]byte("aaa1"), []byte("value_1"))
69+ db.SetSync([]byte("aaa22"), []byte("value_2"))
70+ db.SetSync([]byte("bbb22"), []byte("value_3"))
71+
72+ itr := db.IteratorPrefixWithStart([]byte("aaa"), []byte("aaa1"))
73+ defer itr.Release()
74+
75+ require.Equal(t, true, itr.Next())
76+ require.Equal(t, []byte("aaa22"), itr.Key())
77+
78+ require.Equal(t, false, itr.Next())
79+
80+ itr = db.IteratorPrefixWithStart([]byte("aaa"), nil)
81+
82+ require.Equal(t, true, itr.Next())
83+ require.Equal(t, []byte("aaa1"), itr.Key())
84+
85+ require.Equal(t, true, itr.Next())
86+ require.Equal(t, []byte("aaa22"), itr.Key())
87+
88+ require.Equal(t, false, itr.Next())
89+
90+ itr = db.IteratorPrefixWithStart([]byte("bbb"), []byte("aaa1"))
91+ require.Equal(t, false, itr.Next())
92+}
--- a/database/leveldb/go_level_db.go
+++ b/database/leveldb/go_level_db.go
@@ -1,4 +1,4 @@
1-package db
1+package leveldb
22
33 import (
44 "fmt"
@@ -119,6 +119,18 @@ func (db *GoLevelDB) Stats() map[string]string {
119119
120120 type goLevelDBIterator struct {
121121 source iterator.Iterator
122+ start []byte
123+}
124+
125+func newGoLevelDBIterator(source iterator.Iterator, start []byte) *goLevelDBIterator {
126+ if start != nil {
127+ source.Seek(start)
128+ }
129+
130+ return &goLevelDBIterator{
131+ source: source,
132+ start: start,
133+ }
122134 }
123135
124136 // Key returns a copy of the current key.
@@ -148,6 +160,7 @@ func (it *goLevelDBIterator) Error() error {
148160 }
149161
150162 func (it *goLevelDBIterator) Next() bool {
163+ it.assertNoError()
151164 return it.source.Next()
152165 }
153166
@@ -155,12 +168,23 @@ func (it *goLevelDBIterator) Release() {
155168 it.source.Release()
156169 }
157170
171+func (it *goLevelDBIterator) assertNoError() {
172+ if err := it.source.Error(); err != nil {
173+ panic(err)
174+ }
175+}
176+
158177 func (db *GoLevelDB) Iterator() Iterator {
159- return &goLevelDBIterator{db.db.NewIterator(nil, nil)}
178+ return &goLevelDBIterator{source: db.db.NewIterator(nil, nil)}
160179 }
161180
162181 func (db *GoLevelDB) IteratorPrefix(prefix []byte) Iterator {
163- return &goLevelDBIterator{db.db.NewIterator(util.BytesPrefix(prefix), nil)}
182+ return &goLevelDBIterator{source: db.db.NewIterator(util.BytesPrefix(prefix), nil)}
183+}
184+
185+func (db *GoLevelDB) IteratorPrefixWithStart(Prefix, start []byte) Iterator {
186+ itr := db.db.NewIterator(util.BytesPrefix(Prefix), nil)
187+ return newGoLevelDBIterator(itr, start)
164188 }
165189
166190 func (db *GoLevelDB) NewBatch() Batch {
--- a/database/leveldb/go_level_db_test.go
+++ b/database/leveldb/go_level_db_test.go
@@ -1,4 +1,4 @@
1-package db
1+package leveldb
22
33 import (
44 "bytes"
@@ -30,7 +30,7 @@ func BenchmarkRandomReadsWrites(b *testing.B) {
3030 // Write something
3131 {
3232 idx := (int64(RandInt()) % numItems)
33- internal[idx] += 1
33+ internal[idx]++
3434 val := internal[idx]
3535 idxBytes := int642Bytes(int64(idx))
3636 valBytes := int642Bytes(int64(val))
--- a/database/leveldb/mem_db.go
+++ b/database/leveldb/mem_db.go
@@ -1,6 +1,7 @@
1-package db
1+package leveldb
22
33 import (
4+ "bytes"
45 "fmt"
56 "sort"
67 "strings"
@@ -78,13 +79,29 @@ func (db *MemDB) Stats() map[string]string {
7879 type memDBIterator struct {
7980 last int
8081 keys []string
81- db *MemDB
82+ db DB
83+
84+ start []byte
8285 }
8386
8487 func newMemDBIterator() *memDBIterator {
8588 return &memDBIterator{}
8689 }
8790
91+// Keys is expected to be in reverse order for reverse iterators.
92+func newMemDBIteratorWithArgs(db DB, keys []string, start []byte) *memDBIterator {
93+ itr := &memDBIterator{
94+ db: db,
95+ keys: keys,
96+ start: start,
97+ last: -1,
98+ }
99+ if start != nil {
100+ itr.Seek(start)
101+ }
102+ return itr
103+}
104+
88105 func (it *memDBIterator) Next() bool {
89106 if it.last >= len(it.keys)-1 {
90107 return false
@@ -94,6 +111,9 @@ func (it *memDBIterator) Next() bool {
94111 }
95112
96113 func (it *memDBIterator) Key() []byte {
114+ if it.last < 0 {
115+ return []byte("")
116+ }
97117 return []byte(it.keys[it.last])
98118 }
99119
@@ -143,10 +163,30 @@ func (db *MemDB) IteratorPrefix(prefix []byte) Iterator {
143163 return it
144164 }
145165
166+func (db *MemDB) IteratorPrefixWithStart(Prefix, start []byte) Iterator {
167+ db.mtx.Lock()
168+ defer db.mtx.Unlock()
169+
170+ keys := db.getSortedKeys(start)
171+ return newMemDBIteratorWithArgs(db, keys, start)
172+}
173+
146174 func (db *MemDB) NewBatch() Batch {
147175 return &memDBBatch{db, nil}
148176 }
149177
178+func (db *MemDB) getSortedKeys(start []byte) []string {
179+ keys := []string{}
180+ for key := range db.db {
181+ if bytes.Compare([]byte(key), start) < 0 {
182+ continue
183+ }
184+ keys = append(keys, key)
185+ }
186+ sort.Strings(keys)
187+ return keys
188+}
189+
150190 //--------------------------------------------------------------------------------
151191
152192 type memDBBatch struct {
--- a/database/leveldb/mem_db_test.go
+++ b/database/leveldb/mem_db_test.go
@@ -1,4 +1,4 @@
1-package db
1+package leveldb
22
33 import (
44 "testing"
@@ -23,7 +23,7 @@ func TestMemDbIterator(t *testing.T) {
2323 i := 0
2424 for iter.Next() {
2525 assert.Equal(t, db.Get(iter.Key()), iter.Value(), "values dont match for key")
26- i += 1
26+ i++
2727 }
2828 assert.Equal(t, i, len(db.db), "iterator didnt cover whole db")
2929 }
--- a/wallet/indexer.go
+++ b/wallet/indexer.go
@@ -30,7 +30,7 @@ const (
3030 GlobalTxIndexPrefix = "GTID:"
3131 )
3232
33-var errAccntTxIDNotFound = errors.New("account TXID not found")
33+var ErrAccntTxIDNotFound = errors.New("account TXID not found")
3434
3535 func formatKey(blockHeight uint64, position uint32) string {
3636 return fmt.Sprintf("%016x%08x", blockHeight, position)
@@ -198,7 +198,7 @@ func (w *Wallet) getAccountTxByTxID(txID string) (*query.AnnotatedTx, error) {
198198 annotatedTx := &query.AnnotatedTx{}
199199 formatKey := w.DB.Get(calcTxIndexKey(txID))
200200 if formatKey == nil {
201- return nil, errAccntTxIDNotFound
201+ return nil, ErrAccntTxIDNotFound
202202 }
203203
204204 txInfo := w.DB.Get(calcAnnotatedKey(string(formatKey)))
@@ -288,15 +288,34 @@ func findTransactionsByAccount(annotatedTx *query.AnnotatedTx, accountID string)
288288 return false
289289 }
290290
291-// GetTransactions get all walletDB transactions, and filter transactions by accountID optional
292-func (w *Wallet) GetTransactions(accountID string) ([]*query.AnnotatedTx, error) {
291+// GetTransactions get all walletDB transactions or unconfirmed transactions, and filter transactions by accountID and StartTxID optional
292+func (w *Wallet) GetTransactions(accountID string, StartTxID string, count uint, unconfirmed bool) ([]*query.AnnotatedTx, error) {
293293 annotatedTxs := []*query.AnnotatedTx{}
294+ var startKey []byte
295+ preFix := TxPrefix
294296
295- txIter := w.DB.IteratorPrefix([]byte(TxPrefix))
296- defer txIter.Release()
297- for txIter.Next() {
297+ if StartTxID != "" {
298+ if unconfirmed {
299+ startKey = calcUnconfirmedTxKey(StartTxID)
300+ } else {
301+ formatKey := w.DB.Get(calcTxIndexKey(StartTxID))
302+ if formatKey == nil {
303+ return nil, ErrAccntTxIDNotFound
304+ }
305+ startKey = calcAnnotatedKey(string(formatKey))
306+ }
307+ }
308+
309+ if unconfirmed {
310+ preFix = UnconfirmedTxPrefix
311+ }
312+
313+ itr := w.DB.IteratorPrefixWithStart([]byte(preFix), startKey)
314+ defer itr.Release()
315+
316+ for txNum := count; itr.Next() && txNum > 0; txNum-- {
298317 annotatedTx := &query.AnnotatedTx{}
299- if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
318+ if err := json.Unmarshal(itr.Value(), &annotatedTx); err != nil {
300319 return nil, err
301320 }
302321
@@ -306,6 +325,10 @@ func (w *Wallet) GetTransactions(accountID string) ([]*query.AnnotatedTx, error)
306325 }
307326 }
308327
328+ if unconfirmed {
329+ sort.Sort(SortByTimestamp(annotatedTxs))
330+ }
331+
309332 return annotatedTxs, nil
310333 }
311334
--- a/wallet/wallet_test.go
+++ b/wallet/wallet_test.go
@@ -186,7 +186,7 @@ func TestWalletUpdate(t *testing.T) {
186186 t.Fatal(err)
187187 }
188188
189- wants, err := w.GetTransactions("")
189+ wants, err := w.GetTransactions(testAccount.ID, "", 1, false)
190190 if len(wants) != 1 {
191191 t.Fatal(err)
192192 }
Show on old repository browser