Skip to content

Commit 9642e30

Browse files
committed
Merge branch 'mempool'
2 parents 3ef9426 + dffcded commit 9642e30

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+945
-543
lines changed

api/types.go

+13
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,16 @@ type SystemInfo struct {
337337
Blockbook *BlockbookInfo `json:"blockbook"`
338338
Backend *bchain.ChainInfo `json:"backend"`
339339
}
340+
341+
// MempoolTxid contains information about a transaction in mempool
342+
type MempoolTxid struct {
343+
Time int64 `json:"time"`
344+
Txid string `json:"txid"`
345+
}
346+
347+
// MempoolTxids contains a list of mempool txids with paging information
348+
type MempoolTxids struct {
349+
Paging
350+
Mempool []MempoolTxid `json:"mempool"`
351+
MempoolSize int `json:"mempoolSize"`
352+
}

api/worker.go

+31-2
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,19 @@ type Worker struct {
2323
chain bchain.BlockChain
2424
chainParser bchain.BlockChainParser
2525
chainType bchain.ChainType
26+
mempool bchain.Mempool
2627
is *common.InternalState
2728
}
2829

2930
// NewWorker creates new api worker
30-
func NewWorker(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState) (*Worker, error) {
31+
func NewWorker(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, is *common.InternalState) (*Worker, error) {
3132
w := &Worker{
3233
db: db,
3334
txCache: txCache,
3435
chain: chain,
3536
chainParser: chain.GetChainParser(),
3637
chainType: chain.GetChainParser().GetChainType(),
38+
mempool: mempool,
3739
is: is,
3840
}
3941
return w, nil
@@ -292,6 +294,10 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
292294
return nil, err
293295
}
294296
}
297+
// for mempool transaction get first seen time
298+
if bchainTx.Confirmations == 0 {
299+
bchainTx.Blocktime = int64(w.mempool.GetTransactionTime(bchainTx.Txid))
300+
}
295301
r := &Tx{
296302
Blockhash: blockhash,
297303
Blockheight: int(height),
@@ -348,7 +354,7 @@ func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool
348354
}
349355
if mempool {
350356
uniqueTxs := make(map[string]struct{})
351-
o, err := w.chain.GetMempoolTransactionsForAddrDesc(addrDesc)
357+
o, err := w.mempool.GetAddrDescTransactions(addrDesc)
352358
if err != nil {
353359
return nil, err
354360
}
@@ -1068,3 +1074,26 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
10681074
glog.Info("GetSystemInfo finished in ", time.Since(start))
10691075
return &SystemInfo{bi, ci}, nil
10701076
}
1077+
1078+
// GetMempool returns a page of mempool txids
1079+
func (w *Worker) GetMempool(page int, itemsOnPage int) (*MempoolTxids, error) {
1080+
page--
1081+
if page < 0 {
1082+
page = 0
1083+
}
1084+
entries := w.mempool.GetAllEntries()
1085+
pg, from, to, page := computePaging(len(entries), page, itemsOnPage)
1086+
r := &MempoolTxids{
1087+
Paging: pg,
1088+
MempoolSize: len(entries),
1089+
}
1090+
r.Mempool = make([]MempoolTxid, to-from)
1091+
for i := from; i < to; i++ {
1092+
entry := &entries[i]
1093+
r.Mempool[i-from] = MempoolTxid{
1094+
Txid: entry.Txid,
1095+
Time: int64(entry.Time),
1096+
}
1097+
}
1098+
return r, nil
1099+
}

api/xpub.go

+17-11
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func (w *Worker) xpubGetAddressTxids(addrDesc bchain.AddressDescriptor, mempool
9292
}
9393
if mempool {
9494
uniqueTxs := make(map[string]int)
95-
o, err := w.chain.GetMempoolTransactionsForAddrDesc(addrDesc)
95+
o, err := w.mempool.GetAddrDescTransactions(addrDesc)
9696
if err != nil {
9797
return nil, false, err
9898
}
@@ -383,13 +383,13 @@ func (w *Worker) GetXpubAddress(xpub string, page int, txsOnPage int, option Acc
383383
return nil, err
384384
}
385385
// setup filtering of txids
386-
var useTxids func(txid *xpubTxid, ad *xpubAddress) bool
386+
var txidFilter func(txid *xpubTxid, ad *xpubAddress) bool
387387
if !(filter.FromHeight == 0 && filter.ToHeight == 0 && filter.Vout == AddressFilterVoutOff) {
388388
toHeight := maxUint32
389389
if filter.ToHeight != 0 {
390390
toHeight = filter.ToHeight
391391
}
392-
useTxids = func(txid *xpubTxid, ad *xpubAddress) bool {
392+
txidFilter = func(txid *xpubTxid, ad *xpubAddress) bool {
393393
if txid.height < filter.FromHeight || txid.height > toHeight {
394394
return false
395395
}
@@ -406,6 +406,7 @@ func (w *Worker) GetXpubAddress(xpub string, page int, txsOnPage int, option Acc
406406
// process mempool, only if ToHeight is not specified
407407
if filter.ToHeight == 0 && !filter.OnlyConfirmed {
408408
txmMap = make(map[string]*Tx)
409+
mempoolEntries := make(bchain.MempoolTxidEntries, 0)
409410
for _, da := range [][]xpubAddress{data.addresses, data.changeAddresses} {
410411
for i := range da {
411412
ad := &da[i]
@@ -432,18 +433,23 @@ func (w *Worker) GetXpubAddress(xpub string, page int, txsOnPage int, option Acc
432433
}
433434
uBalSat.Add(&uBalSat, tx.getAddrVoutValue(ad.addrDesc))
434435
uBalSat.Sub(&uBalSat, tx.getAddrVinValue(ad.addrDesc))
435-
if page == 0 && !foundTx && (useTxids == nil || useTxids(&txid, ad)) {
436-
if option == AccountDetailsTxidHistory {
437-
txids = append(txids, tx.Txid)
438-
} else if option >= AccountDetailsTxHistoryLight {
439-
txs = append(txs, tx)
440-
}
436+
// mempool txs are returned only on the first page, uniquely and filtered
437+
if page == 0 && !foundTx && (txidFilter == nil || txidFilter(&txid, ad)) {
438+
mempoolEntries = append(mempoolEntries, bchain.MempoolTxidEntry{Txid: txid.txid, Time: uint32(tx.Blocktime)})
441439
}
442440
}
443-
444441
}
445442
}
446443
}
444+
// sort the entries by time descending
445+
sort.Sort(mempoolEntries)
446+
for _, entry := range mempoolEntries {
447+
if option == AccountDetailsTxidHistory {
448+
txids = append(txids, entry.Txid)
449+
} else if option >= AccountDetailsTxHistoryLight {
450+
txs = append(txs, txmMap[entry.Txid])
451+
}
452+
}
447453
}
448454
if option >= AccountDetailsTxidHistory {
449455
txcMap := make(map[string]bool)
@@ -459,7 +465,7 @@ func (w *Worker) GetXpubAddress(xpub string, page int, txsOnPage int, option Acc
459465
}
460466
// add tx only once
461467
if !added {
462-
add := useTxids == nil || useTxids(&txid, ad)
468+
add := txidFilter == nil || txidFilter(&txid, ad)
463469
txcMap[txid.txid] = add
464470
if add {
465471
txc = append(txc, txid)

bchain/basechain.go

+5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ func (b *BaseChain) GetNetworkName() string {
2929
return b.Network
3030
}
3131

32+
// GetMempoolEntry is not supported by default
33+
func (b *BaseChain) GetMempoolEntry(txid string) (*MempoolEntry, error) {
34+
return nil, errors.New("GetMempoolEntry: not supported")
35+
}
36+
3237
// EthereumTypeGetBalance is not supported
3338
func (b *BaseChain) EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error) {
3439
return nil, errors.New("Not supported")

bchain/basemempool.go

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package bchain
2+
3+
import (
4+
"sort"
5+
"sync"
6+
)
7+
8+
type addrIndex struct {
9+
addrDesc string
10+
n int32
11+
}
12+
13+
type txEntry struct {
14+
addrIndexes []addrIndex
15+
time uint32
16+
}
17+
18+
type txidio struct {
19+
txid string
20+
io []addrIndex
21+
}
22+
23+
// BaseMempool is mempool base handle
24+
type BaseMempool struct {
25+
chain BlockChain
26+
mux sync.Mutex
27+
txEntries map[string]txEntry
28+
addrDescToTx map[string][]Outpoint
29+
OnNewTxAddr OnNewTxAddrFunc
30+
}
31+
32+
// GetTransactions returns slice of mempool transactions for given address
33+
func (m *BaseMempool) GetTransactions(address string) ([]Outpoint, error) {
34+
parser := m.chain.GetChainParser()
35+
addrDesc, err := parser.GetAddrDescFromAddress(address)
36+
if err != nil {
37+
return nil, err
38+
}
39+
return m.GetAddrDescTransactions(addrDesc)
40+
}
41+
42+
// GetAddrDescTransactions returns slice of mempool transactions for given address descriptor, in reverse order
43+
func (m *BaseMempool) GetAddrDescTransactions(addrDesc AddressDescriptor) ([]Outpoint, error) {
44+
m.mux.Lock()
45+
defer m.mux.Unlock()
46+
outpoints := m.addrDescToTx[string(addrDesc)]
47+
rv := make([]Outpoint, len(outpoints))
48+
for i, j := len(outpoints)-1, 0; i >= 0; i-- {
49+
rv[j] = outpoints[i]
50+
j++
51+
}
52+
return rv, nil
53+
}
54+
55+
func (a MempoolTxidEntries) Len() int { return len(a) }
56+
func (a MempoolTxidEntries) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
57+
func (a MempoolTxidEntries) Less(i, j int) bool {
58+
// if the Time is equal, sort by txid to make the order defined
59+
hi := a[i].Time
60+
hj := a[j].Time
61+
if hi == hj {
62+
return a[i].Txid > a[j].Txid
63+
}
64+
// order in reverse
65+
return hi > hj
66+
}
67+
68+
// removeEntryFromMempool removes entry from mempool structs. The caller is responsible for locking!
69+
func (m *BaseMempool) removeEntryFromMempool(txid string, entry txEntry) {
70+
delete(m.txEntries, txid)
71+
for _, si := range entry.addrIndexes {
72+
outpoints, found := m.addrDescToTx[si.addrDesc]
73+
if found {
74+
newOutpoints := make([]Outpoint, 0, len(outpoints)-1)
75+
for _, o := range outpoints {
76+
if o.Txid != txid {
77+
newOutpoints = append(newOutpoints, o)
78+
}
79+
}
80+
if len(newOutpoints) > 0 {
81+
m.addrDescToTx[si.addrDesc] = newOutpoints
82+
} else {
83+
delete(m.addrDescToTx, si.addrDesc)
84+
}
85+
}
86+
}
87+
}
88+
89+
// GetAllEntries returns all mempool entries sorted by fist seen time in descending order
90+
func (m *BaseMempool) GetAllEntries() MempoolTxidEntries {
91+
i := 0
92+
m.mux.Lock()
93+
entries := make(MempoolTxidEntries, len(m.txEntries))
94+
for txid, entry := range m.txEntries {
95+
entries[i] = MempoolTxidEntry{
96+
Txid: txid,
97+
Time: entry.time,
98+
}
99+
i++
100+
}
101+
m.mux.Unlock()
102+
sort.Sort(entries)
103+
return entries
104+
}
105+
106+
// GetTransactionTime returns first seen time of a transaction
107+
func (m *BaseMempool) GetTransactionTime(txid string) uint32 {
108+
m.mux.Lock()
109+
e, found := m.txEntries[txid]
110+
m.mux.Unlock()
111+
if !found {
112+
return 0
113+
}
114+
return e.time
115+
}

bchain/coins/bch/bcashrpc.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ func NewBCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
3434

3535
// Initialize initializes BCashRPC instance.
3636
func (b *BCashRPC) Initialize() error {
37-
chainName, err := b.GetChainInfoAndInitializeMempool(b)
37+
ci, err := b.GetChainInfo()
3838
if err != nil {
3939
return err
4040
}
41+
chainName := ci.Chain
4142

4243
params := GetChainParams(chainName)
4344

bchain/coins/bellcoin/bellcoinrpc.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ func NewBellcoinRPC(config json.RawMessage, pushHandler func(bchain.Notification
3131

3232
// Initialize initializes BellcoinRPC instance.
3333
func (b *BellcoinRPC) Initialize() error {
34-
chainName, err := b.GetChainInfoAndInitializeMempool(b)
34+
ci, err := b.GetChainInfo()
3535
if err != nil {
3636
return err
3737
}
38+
chainName := ci.Chain
3839

3940
glog.Info("Chain name ", chainName)
4041
params := GetChainParams(chainName)

0 commit comments

Comments
 (0)