Add the new RPC function existsmempooltxs
A new RPC function has been added to the daemon to quickly check for the existence of transactions in the mempool. It handles raw encoded hex containing transaction hashes and outputs a raw encoded hex of bit flags. This makes the output size as small as possible while speeding up the JSON encoding/decoding of the data.
This commit is contained in:
parent
b237418c14
commit
cd8ea2e309
@ -46,6 +46,19 @@ func NewExistsLiveTicketsCmd(txHashBlob string) *ExistsLiveTicketsCmd {
|
||||
}
|
||||
}
|
||||
|
||||
// ExistsMempoolTxsCmd defines the existsmempooltxs JSON-RPC command.
|
||||
type ExistsMempoolTxsCmd struct {
|
||||
TxHashBlob string
|
||||
}
|
||||
|
||||
// NewExistsMempoolTxsCmd returns a new instance which can be used to issue an
|
||||
// existslivetickets JSON-RPC command.
|
||||
func NewExistsMempoolTxsCmd(txHashBlob string) *ExistsMempoolTxsCmd {
|
||||
return &ExistsMempoolTxsCmd{
|
||||
TxHashBlob: txHashBlob,
|
||||
}
|
||||
}
|
||||
|
||||
// GetCoinSupplyCmd defines the getcoinsupply JSON-RPC command.
|
||||
type GetCoinSupplyCmd struct{}
|
||||
|
||||
@ -113,6 +126,7 @@ func init() {
|
||||
MustRegisterCmd("existsaddress", (*ExistsAddressCmd)(nil), flags)
|
||||
MustRegisterCmd("existsliveticket", (*ExistsLiveTicketCmd)(nil), flags)
|
||||
MustRegisterCmd("existslivetickets", (*ExistsLiveTicketsCmd)(nil), flags)
|
||||
MustRegisterCmd("existsmempooltxs", (*ExistsMempoolTxsCmd)(nil), flags)
|
||||
MustRegisterCmd("getcoinsupply", (*GetCoinSupplyCmd)(nil), flags)
|
||||
MustRegisterCmd("getstakedifficulty", (*GetStakeDifficultyCmd)(nil), flags)
|
||||
MustRegisterCmd("missedtickets", (*MissedTicketsCmd)(nil), flags)
|
||||
|
||||
24
mempool.go
24
mempool.go
@ -925,6 +925,30 @@ func (mp *txMemPool) HaveTransaction(hash *chainhash.Hash) bool {
|
||||
return mp.haveTransaction(hash)
|
||||
}
|
||||
|
||||
// haveTransactions returns whether or not the passed transactions already exist
|
||||
// in the main pool or in the orphan pool.
|
||||
//
|
||||
// This function MUST be called with the mempool lock held (for reads).
|
||||
func (mp *txMemPool) haveTransactions(hashes []*chainhash.Hash) []bool {
|
||||
have := make([]bool, len(hashes))
|
||||
for i := range hashes {
|
||||
have[i] = mp.haveTransaction(hashes[i])
|
||||
}
|
||||
return have
|
||||
}
|
||||
|
||||
// HaveTransactions returns whether or not the passed transactions already exist
|
||||
// in the main pool or in the orphan pool.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (mp *txMemPool) HaveTransactions(hashes []*chainhash.Hash) []bool {
|
||||
// Protect concurrent access.
|
||||
mp.RLock()
|
||||
defer mp.RUnlock()
|
||||
|
||||
return mp.haveTransactions(hashes)
|
||||
}
|
||||
|
||||
// removeTransaction is the internal function which implements the public
|
||||
// RemoveTransaction. See the comment for RemoveTransaction for more details.
|
||||
//
|
||||
|
||||
80
rpcserver.go
80
rpcserver.go
@ -157,6 +157,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
|
||||
"existsaddress": handleExistsAddress,
|
||||
"existsliveticket": handleExistsLiveTicket,
|
||||
"existslivetickets": handleExistsLiveTickets,
|
||||
"existsmempooltxs": handleExistsMempoolTxs,
|
||||
"generate": handleGenerate,
|
||||
"getaddednodeinfo": handleGetAddedNodeInfo,
|
||||
"getbestblock": handleGetBestBlock,
|
||||
@ -1515,16 +1516,18 @@ func handleExistsLiveTickets(s *rpcServer, cmd interface{},
|
||||
txHashBlob, err := hex.DecodeString(c.TxHashBlob)
|
||||
if err != nil {
|
||||
return nil, &dcrjson.RPCError{
|
||||
Code: dcrjson.ErrRPCDecodeHexString,
|
||||
Message: "bad transaction hash blob (unparseable)",
|
||||
Code: dcrjson.ErrRPCDecodeHexString,
|
||||
Message: fmt.Sprintf("bad ticket hash blob (unparseable): %v",
|
||||
err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
// It needs to be an exact number of hashes.
|
||||
if len(txHashBlob)%32 != 0 {
|
||||
return nil, &dcrjson.RPCError{
|
||||
Code: dcrjson.ErrRPCDecodeHexString,
|
||||
Message: "bad transaction hash blob (bad length)",
|
||||
Code: dcrjson.ErrRPCDecodeHexString,
|
||||
Message: fmt.Sprintf("bad ticket hash blob (bad length): %v",
|
||||
len(txHashBlob)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1533,6 +1536,13 @@ func handleExistsLiveTickets(s *rpcServer, cmd interface{},
|
||||
for i := 0; i < hashesLen; i++ {
|
||||
hashes[i], err = chainhash.NewHash(
|
||||
txHashBlob[i*chainhash.HashSize : (i+1)*chainhash.HashSize])
|
||||
if err != nil {
|
||||
return nil, &dcrjson.RPCError{
|
||||
Code: dcrjson.ErrRPCDecodeHexString,
|
||||
Message: fmt.Sprintf("bad ticket hash: %v",
|
||||
err.Error()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exists, err := s.server.blockManager.ExistsLiveTickets(hashes)
|
||||
@ -1541,8 +1551,66 @@ func handleExistsLiveTickets(s *rpcServer, cmd interface{},
|
||||
}
|
||||
if len(exists) != hashesLen {
|
||||
return nil, &dcrjson.RPCError{
|
||||
Code: dcrjson.ErrRPCDatabase,
|
||||
Message: "output of ExistsLiveTickets wrong size",
|
||||
Code: dcrjson.ErrRPCDatabase,
|
||||
Message: fmt.Sprintf("output of ExistsLiveTickets wrong size "+
|
||||
"(want %v, got %v)", hashesLen, len(exists)),
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the slice of bools into a compacted set of bit flags.
|
||||
set := bitset.NewBytes(hashesLen)
|
||||
for i := range exists {
|
||||
if exists[i] {
|
||||
set.Set(i)
|
||||
}
|
||||
}
|
||||
|
||||
return hex.EncodeToString([]byte(set)), nil
|
||||
}
|
||||
|
||||
// handleExistsMempoolTxs implements the existsmempooltxs command.
|
||||
func handleExistsMempoolTxs(s *rpcServer, cmd interface{},
|
||||
closeChan <-chan struct{}) (interface{}, error) {
|
||||
c := cmd.(*dcrjson.ExistsMempoolTxsCmd)
|
||||
|
||||
txHashBlob, err := hex.DecodeString(c.TxHashBlob)
|
||||
if err != nil {
|
||||
return nil, &dcrjson.RPCError{
|
||||
Code: dcrjson.ErrRPCDecodeHexString,
|
||||
Message: fmt.Sprintf("bad transaction hash blob (unparseable): %v",
|
||||
err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
// It needs to be an exact number of hashes.
|
||||
if len(txHashBlob)%32 != 0 {
|
||||
return nil, &dcrjson.RPCError{
|
||||
Code: dcrjson.ErrRPCDecodeHexString,
|
||||
Message: fmt.Sprintf("bad transaction hash blob (bad length): %v",
|
||||
len(txHashBlob)),
|
||||
}
|
||||
}
|
||||
|
||||
hashesLen := len(txHashBlob) / 32
|
||||
hashes := make([]*chainhash.Hash, hashesLen)
|
||||
for i := 0; i < hashesLen; i++ {
|
||||
hashes[i], err = chainhash.NewHash(
|
||||
txHashBlob[i*chainhash.HashSize : (i+1)*chainhash.HashSize])
|
||||
if err != nil {
|
||||
return nil, &dcrjson.RPCError{
|
||||
Code: dcrjson.ErrRPCDecodeHexString,
|
||||
Message: fmt.Sprintf("bad transaction hash: %v",
|
||||
err.Error()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exists := s.server.txMemPool.HaveTransactions(hashes)
|
||||
if len(exists) != hashesLen {
|
||||
return nil, &dcrjson.RPCError{
|
||||
Code: dcrjson.ErrRPCDatabase,
|
||||
Message: fmt.Sprintf("output of ExistsMempoolTxs wrong size "+
|
||||
"(want %v, got %v)", hashesLen, len(exists)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -153,9 +153,14 @@ var helpDescsEnUS = map[string]string{
|
||||
"existsliveticket--result0": "Bool showing if address exists in the live ticket database or not",
|
||||
|
||||
// ExistsLiveTicketsCmd help.
|
||||
"existslivetickets--synopsis": "Test for the existance of the provided tickets",
|
||||
"existslivetickets--synopsis": "Test for the existance of the provided tickets in the live ticket map",
|
||||
"existslivetickets-txhashblob": "Blob containing the hashes to check",
|
||||
"existslivetickets--result0": "Bool showing if address exists in the live ticket database or not",
|
||||
"existslivetickets--result0": "Bool blob showing if ticket exists in the live ticket database or not",
|
||||
|
||||
// ExistsMempoolTxsCmd help.
|
||||
"existsmempooltxs--synopsis": "Test for the existance of the provided txs in the mempool",
|
||||
"existsmempooltxs-txhashblob": "Blob containing the hashes to check",
|
||||
"existsmempooltxs--result0": "Bool blob showing if txs exist in the mempool or not",
|
||||
|
||||
// GenerateCmd help
|
||||
"generate--synopsis": "Generates a set number of blocks (simnet or regtest only) and returns a JSON\n" +
|
||||
@ -669,7 +674,8 @@ var rpcResultTypes = map[string][]interface{}{
|
||||
"estimatefee": []interface{}{(*float64)(nil)},
|
||||
"existsaddress": []interface{}{(*bool)(nil)},
|
||||
"existsliveticket": []interface{}{(*bool)(nil)},
|
||||
"existslivetickets": []interface{}{(*bool)(nil)},
|
||||
"existslivetickets": []interface{}{(*string)(nil)},
|
||||
"existsmempooltxs": []interface{}{(*string)(nil)},
|
||||
"getaddednodeinfo": []interface{}{(*[]string)(nil), (*[]dcrjson.GetAddedNodeInfoResult)(nil)},
|
||||
"getbestblock": []interface{}{(*dcrjson.GetBestBlockResult)(nil)},
|
||||
"generate": []interface{}{(*[]string)(nil)},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user