mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-11-28 00:03:39 +00:00
89 lines
3.9 KiB
Go
89 lines
3.9 KiB
Go
package rpchandlers
|
|
|
|
import (
|
|
"github.com/kaspanet/kaspad/app/appmessage"
|
|
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
|
"github.com/kaspanet/kaspad/domain/utxoindex"
|
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
|
"github.com/kaspanet/kaspad/util"
|
|
"sort"
|
|
)
|
|
|
|
// HandleGetUTXOsByAddresses handles the respectively named RPC command
|
|
func HandleGetUTXOsByAddresses(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
|
if !context.Config.UTXOIndex {
|
|
errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{}
|
|
errorMessage.Error = appmessage.RPCErrorf("Method unavailable when kaspad is run without --utxoindex")
|
|
return errorMessage, nil
|
|
}
|
|
|
|
getUTXOsByAddressesRequest := request.(*appmessage.GetUTXOsByAddressesRequestMessage)
|
|
|
|
allEntries := make([]*appmessage.UTXOsByAddressesEntry, 0)
|
|
for _, addressString := range getUTXOsByAddressesRequest.Addresses {
|
|
address, err := util.DecodeAddress(addressString, context.Config.ActiveNetParams.Prefix)
|
|
if err != nil {
|
|
errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{}
|
|
errorMessage.Error = appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err)
|
|
return errorMessage, nil
|
|
}
|
|
scriptPublicKey, err := txscript.PayToAddrScript(address)
|
|
if err != nil {
|
|
errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{}
|
|
errorMessage.Error = appmessage.RPCErrorf("Could not create a scriptPublicKey for address '%s': %s", addressString, err)
|
|
return errorMessage, nil
|
|
}
|
|
utxoOutpointEntryPairs, err := context.UTXOIndex.UTXOs(scriptPublicKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if getUTXOsByAddressesRequest.BatchDaaScoreStart > 0 ||
|
|
(getUTXOsByAddressesRequest.BatchSize > 0 && uint64(len(utxoOutpointEntryPairs)) > getUTXOsByAddressesRequest.BatchSize) {
|
|
// Find a batch of entries with consecutive DAA score
|
|
entriesOrderedBatch := extractOrderedEntriesBatch(utxoOutpointEntryPairs, getUTXOsByAddressesRequest.BatchDaaScoreStart, getUTXOsByAddressesRequest.BatchSize)
|
|
// Extract the batch from the full pairs map
|
|
entries := rpccontext.ConvertUTXOOutpointEntryBatchToUTXOsByAddressesEntries(addressString, utxoOutpointEntryPairs, entriesOrderedBatch)
|
|
allEntries = append(allEntries, entries...)
|
|
} else {
|
|
entries := rpccontext.ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(addressString, utxoOutpointEntryPairs)
|
|
allEntries = append(allEntries, entries...)
|
|
}
|
|
}
|
|
|
|
response := appmessage.NewGetUTXOsByAddressesResponseMessage(allEntries)
|
|
return response, nil
|
|
}
|
|
|
|
func extractOrderedEntriesBatch(utxoOutpointEntryPairs utxoindex.UTXOOutpointEntryPairs, batchDaaScoreStart, batchSize uint64) []rpccontext.OutpointDAAScoreEntry {
|
|
entriesSlice := make([]rpccontext.OutpointDAAScoreEntry, 0, len(utxoOutpointEntryPairs))
|
|
// Extract to slice
|
|
for outpoint, utxoEntry := range utxoOutpointEntryPairs {
|
|
entriesSlice = append(entriesSlice, rpccontext.OutpointDAAScoreEntry{DAAScore: utxoEntry.BlockDAAScore(), Outpoint: outpoint})
|
|
}
|
|
// Sort by DAA score
|
|
sort.Slice(entriesSlice, func(i, j int) bool {
|
|
if entriesSlice[i].DAAScore == entriesSlice[j].DAAScore {
|
|
if entriesSlice[i].Outpoint.TransactionID.Equal(&entriesSlice[j].Outpoint.TransactionID) {
|
|
return entriesSlice[i].Outpoint.Index < entriesSlice[j].Outpoint.Index
|
|
}
|
|
return entriesSlice[i].Outpoint.TransactionID.Less(&entriesSlice[j].Outpoint.TransactionID)
|
|
}
|
|
return entriesSlice[i].DAAScore < entriesSlice[j].DAAScore
|
|
})
|
|
// Find batch start and end points
|
|
startIndex := len(entriesSlice)
|
|
endIndex := uint64(len(entriesSlice))
|
|
for i := 0; i < len(entriesSlice); i++ {
|
|
if entriesSlice[i].DAAScore >= batchDaaScoreStart {
|
|
startIndex = i
|
|
break
|
|
}
|
|
}
|
|
if uint64(startIndex)+batchSize < endIndex {
|
|
endIndex = uint64(startIndex) + batchSize
|
|
}
|
|
return entriesSlice[startIndex:endIndex]
|
|
}
|