mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-11-24 14:35:53 +00:00
Merge branch 'dev' into insert-block-sync-fix
This commit is contained in:
commit
a5be6afd9c
@ -102,7 +102,7 @@ func (flow *handleRelayedTransactionsFlow) requestInvTransactions(
|
|||||||
func (flow *handleRelayedTransactionsFlow) isKnownTransaction(txID *externalapi.DomainTransactionID) bool {
|
func (flow *handleRelayedTransactionsFlow) isKnownTransaction(txID *externalapi.DomainTransactionID) bool {
|
||||||
// Ask the transaction memory pool if the transaction is known
|
// Ask the transaction memory pool if the transaction is known
|
||||||
// to it in any form (main pool or orphan).
|
// to it in any form (main pool or orphan).
|
||||||
if _, ok := flow.Domain().MiningManager().GetTransaction(txID); ok {
|
if _, _, ok := flow.Domain().MiningManager().GetTransaction(txID, true, true); ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,7 @@ func (flow *handleRequestedTransactionsFlow) start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, transactionID := range msgRequestTransactions.IDs {
|
for _, transactionID := range msgRequestTransactions.IDs {
|
||||||
tx, ok := flow.Domain().MiningManager().GetTransaction(transactionID)
|
tx, _, ok := flow.Domain().MiningManager().GetTransaction(transactionID, true, false)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
msgTransactionNotFound := appmessage.NewMsgTransactionNotFound(transactionID)
|
msgTransactionNotFound := appmessage.NewMsgTransactionNotFound(transactionID)
|
||||||
@ -40,7 +40,6 @@ func (flow *handleRequestedTransactionsFlow) start() error {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err := flow.outgoingRoute.Enqueue(appmessage.DomainTransactionToMsgTx(tx))
|
err := flow.outgoingRoute.Enqueue(appmessage.DomainTransactionToMsgTx(tx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
@ -421,7 +422,7 @@ func (nl *NotificationListener) convertUTXOChangesToUTXOsChangedNotification(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (nl *NotificationListener) scriptPubKeyStringToAddressString(scriptPublicKeyString utxoindex.ScriptPublicKeyString) (string, error) {
|
func (nl *NotificationListener) scriptPubKeyStringToAddressString(scriptPublicKeyString utxoindex.ScriptPublicKeyString) (string, error) {
|
||||||
scriptPubKey := utxoindex.ConvertStringToScriptPublicKey(scriptPublicKeyString)
|
scriptPubKey := externalapi.NewScriptPublicKeyFromString(string(scriptPublicKeyString))
|
||||||
|
|
||||||
// ignore error because it is often returned when the script is of unknown type
|
// ignore error because it is often returned when the script is of unknown type
|
||||||
scriptType, address, err := txscript.ExtractScriptPubKeyAddress(scriptPubKey, nl.params)
|
scriptType, address, err := txscript.ExtractScriptPubKeyAddress(scriptPubKey, nl.params)
|
||||||
|
|||||||
@ -32,22 +32,6 @@ func ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(address string, pair
|
|||||||
return utxosByAddressesEntries
|
return utxosByAddressesEntries
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertUTXOOutpointsToUTXOsByAddressesEntries converts
|
|
||||||
// UTXOOutpoints to a slice of UTXOsByAddressesEntry
|
|
||||||
func convertUTXOOutpointsToUTXOsByAddressesEntries(address string, outpoints utxoindex.UTXOOutpoints) []*appmessage.UTXOsByAddressesEntry {
|
|
||||||
utxosByAddressesEntries := make([]*appmessage.UTXOsByAddressesEntry, 0, len(outpoints))
|
|
||||||
for outpoint := range outpoints {
|
|
||||||
utxosByAddressesEntries = append(utxosByAddressesEntries, &appmessage.UTXOsByAddressesEntry{
|
|
||||||
Address: address,
|
|
||||||
Outpoint: &appmessage.RPCOutpoint{
|
|
||||||
TransactionID: outpoint.TransactionID.String(),
|
|
||||||
Index: outpoint.Index,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return utxosByAddressesEntries
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertAddressStringsToUTXOsChangedNotificationAddresses converts address strings
|
// ConvertAddressStringsToUTXOsChangedNotificationAddresses converts address strings
|
||||||
// to UTXOsChangedNotificationAddresses
|
// to UTXOsChangedNotificationAddresses
|
||||||
func (ctx *Context) ConvertAddressStringsToUTXOsChangedNotificationAddresses(
|
func (ctx *Context) ConvertAddressStringsToUTXOsChangedNotificationAddresses(
|
||||||
@ -63,7 +47,7 @@ func (ctx *Context) ConvertAddressStringsToUTXOsChangedNotificationAddresses(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Errorf("Could not create a scriptPublicKey for address '%s': %s", addressString, err)
|
return nil, errors.Errorf("Could not create a scriptPublicKey for address '%s': %s", addressString, err)
|
||||||
}
|
}
|
||||||
scriptPublicKeyString := utxoindex.ConvertScriptPublicKeyToString(scriptPublicKey)
|
scriptPublicKeyString := utxoindex.ScriptPublicKeyString(scriptPublicKey.String())
|
||||||
addresses[i] = &UTXOsChangedNotificationAddress{
|
addresses[i] = &UTXOsChangedNotificationAddress{
|
||||||
Address: addressString,
|
Address: addressString,
|
||||||
ScriptPublicKeyString: scriptPublicKeyString,
|
ScriptPublicKeyString: scriptPublicKeyString,
|
||||||
|
|||||||
@ -16,7 +16,7 @@ func HandleGetInfo(context *rpccontext.Context, _ *router.Router, _ appmessage.M
|
|||||||
|
|
||||||
response := appmessage.NewGetInfoResponseMessage(
|
response := appmessage.NewGetInfoResponseMessage(
|
||||||
context.NetAdapter.ID().String(),
|
context.NetAdapter.ID().String(),
|
||||||
uint64(context.Domain.MiningManager().TransactionCount()),
|
uint64(context.Domain.MiningManager().TransactionCount(true, false)),
|
||||||
version.Version(),
|
version.Version(),
|
||||||
context.Config.UTXOIndex,
|
context.Config.UTXOIndex,
|
||||||
context.ProtocolManager.Context().HasPeers() && isNearlySynced,
|
context.ProtocolManager.Context().HasPeers() && isNearlySynced,
|
||||||
|
|||||||
@ -12,58 +12,36 @@ func HandleGetMempoolEntries(context *rpccontext.Context, _ *router.Router, requ
|
|||||||
|
|
||||||
entries := make([]*appmessage.MempoolEntry, 0)
|
entries := make([]*appmessage.MempoolEntry, 0)
|
||||||
|
|
||||||
|
transactionPoolTransactions, orphanPoolTransactions := context.Domain.MiningManager().AllTransactions(!getMempoolEntriesRequest.FilterTransactionPool, getMempoolEntriesRequest.IncludeOrphanPool)
|
||||||
|
|
||||||
if !getMempoolEntriesRequest.FilterTransactionPool {
|
if !getMempoolEntriesRequest.FilterTransactionPool {
|
||||||
transactionPoolEntries, err := getTransactionPoolMempoolEntries(context)
|
for _, transaction := range transactionPoolTransactions {
|
||||||
if err != nil {
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
||||||
return nil, err
|
err := context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entries = append(entries, &appmessage.MempoolEntry{
|
||||||
|
Fee: transaction.Fee,
|
||||||
|
Transaction: rpcTransaction,
|
||||||
|
IsOrphan: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
entries = append(entries, transactionPoolEntries...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if getMempoolEntriesRequest.IncludeOrphanPool {
|
if getMempoolEntriesRequest.IncludeOrphanPool {
|
||||||
orphanPoolEntries, err := getOrphanPoolMempoolEntries(context)
|
for _, transaction := range orphanPoolTransactions {
|
||||||
if err != nil {
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
||||||
return nil, err
|
err := context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entries = append(entries, &appmessage.MempoolEntry{
|
||||||
|
Fee: transaction.Fee,
|
||||||
|
Transaction: rpcTransaction,
|
||||||
|
IsOrphan: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
entries = append(entries, orphanPoolEntries...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return appmessage.NewGetMempoolEntriesResponseMessage(entries), nil
|
return appmessage.NewGetMempoolEntriesResponseMessage(entries), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTransactionPoolMempoolEntries(context *rpccontext.Context) ([]*appmessage.MempoolEntry, error) {
|
|
||||||
transactions := context.Domain.MiningManager().AllTransactions()
|
|
||||||
entries := make([]*appmessage.MempoolEntry, 0, len(transactions))
|
|
||||||
for _, transaction := range transactions {
|
|
||||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
|
||||||
err := context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
entries = append(entries, &appmessage.MempoolEntry{
|
|
||||||
Fee: transaction.Fee,
|
|
||||||
Transaction: rpcTransaction,
|
|
||||||
IsOrphan: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return entries, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOrphanPoolMempoolEntries(context *rpccontext.Context) ([]*appmessage.MempoolEntry, error) {
|
|
||||||
orphanTransactions := context.Domain.MiningManager().AllOrphanTransactions()
|
|
||||||
entries := make([]*appmessage.MempoolEntry, 0, len(orphanTransactions))
|
|
||||||
for _, orphanTransaction := range orphanTransactions {
|
|
||||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(orphanTransaction)
|
|
||||||
err := context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
entries = append(entries, &appmessage.MempoolEntry{
|
|
||||||
Fee: orphanTransaction.Fee,
|
|
||||||
Transaction: rpcTransaction,
|
|
||||||
IsOrphan: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return entries, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
package rpchandlers
|
package rpchandlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/util"
|
||||||
)
|
)
|
||||||
@ -20,132 +16,107 @@ func HandleGetMempoolEntriesByAddresses(context *rpccontext.Context, _ *router.R
|
|||||||
|
|
||||||
mempoolEntriesByAddresses := make([]*appmessage.MempoolEntryByAddress, 0)
|
mempoolEntriesByAddresses := make([]*appmessage.MempoolEntryByAddress, 0)
|
||||||
|
|
||||||
if !getMempoolEntriesByAddressesRequest.FilterTransactionPool {
|
sendingInTransactionPool, receivingInTransactionPool, sendingInOrphanPool, receivingInOrphanPool, err := context.Domain.MiningManager().GetTransactionsByAddresses(!getMempoolEntriesByAddressesRequest.FilterTransactionPool, getMempoolEntriesByAddressesRequest.IncludeOrphanPool)
|
||||||
transactionPoolTransactions := context.Domain.MiningManager().AllTransactions()
|
if err != nil {
|
||||||
transactionPoolEntriesByAddresses, err := extractMempoolEntriesByAddressesFromTransactions(
|
return nil, err
|
||||||
context,
|
|
||||||
getMempoolEntriesByAddressesRequest.Addresses,
|
|
||||||
transactionPoolTransactions,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
rpcError := &appmessage.RPCError{}
|
|
||||||
if !errors.As(err, &rpcError) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{}
|
|
||||||
errorMessage.Error = rpcError
|
|
||||||
return errorMessage, nil
|
|
||||||
}
|
|
||||||
mempoolEntriesByAddresses = append(mempoolEntriesByAddresses, transactionPoolEntriesByAddresses...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if getMempoolEntriesByAddressesRequest.IncludeOrphanPool {
|
for _, addressString := range getMempoolEntriesByAddressesRequest.Addresses {
|
||||||
|
|
||||||
orphanPoolTransactions := context.Domain.MiningManager().AllOrphanTransactions()
|
address, err := util.DecodeAddress(addressString, context.Config.NetParams().Prefix)
|
||||||
orphanPoolEntriesByAddress, err := extractMempoolEntriesByAddressesFromTransactions(
|
|
||||||
context,
|
|
||||||
getMempoolEntriesByAddressesRequest.Addresses,
|
|
||||||
orphanPoolTransactions,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rpcError := &appmessage.RPCError{}
|
errorMessage := &appmessage.GetMempoolEntriesByAddressesResponseMessage{}
|
||||||
if !errors.As(err, &rpcError) {
|
errorMessage.Error = appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{}
|
|
||||||
errorMessage.Error = rpcError
|
|
||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mempoolEntriesByAddresses = append(mempoolEntriesByAddresses, orphanPoolEntriesByAddress...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return appmessage.NewGetMempoolEntriesByAddressesResponseMessage(mempoolEntriesByAddresses), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//TO DO: optimize extractMempoolEntriesByAddressesFromTransactions
|
|
||||||
func extractMempoolEntriesByAddressesFromTransactions(context *rpccontext.Context, addresses []string, transactions []*externalapi.DomainTransaction, areOrphans bool) ([]*appmessage.MempoolEntryByAddress, error) {
|
|
||||||
mempoolEntriesByAddresses := make([]*appmessage.MempoolEntryByAddress, 0)
|
|
||||||
for _, addressString := range addresses {
|
|
||||||
_, err := util.DecodeAddress(addressString, context.Config.ActiveNetParams.Prefix)
|
|
||||||
if err != nil {
|
|
||||||
return nil, appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sending := make([]*appmessage.MempoolEntry, 0)
|
sending := make([]*appmessage.MempoolEntry, 0)
|
||||||
receiving := make([]*appmessage.MempoolEntry, 0)
|
receiving := make([]*appmessage.MempoolEntry, 0)
|
||||||
|
|
||||||
for _, transaction := range transactions {
|
scriptPublicKey, err := txscript.PayToAddrScript(address)
|
||||||
|
if err != nil {
|
||||||
|
errorMessage := &appmessage.GetMempoolEntriesByAddressesResponseMessage{}
|
||||||
|
errorMessage.Error = appmessage.RPCErrorf("Could not extract scriptPublicKey from address '%s': %s", addressString, err)
|
||||||
|
return errorMessage, nil
|
||||||
|
}
|
||||||
|
|
||||||
for i, input := range transaction.Inputs {
|
if !getMempoolEntriesByAddressesRequest.FilterTransactionPool {
|
||||||
if input.UTXOEntry == nil {
|
|
||||||
if !areOrphans { // Orphans can legitimately have `input.UTXOEntry == nil`
|
|
||||||
// TODO: Fix the underlying cause of the bug for non-orphan entries
|
|
||||||
log.Debugf(
|
|
||||||
"Couldn't find UTXO entry for input %d in mempool transaction %s. This is a bug and should be fixed.",
|
|
||||||
i, consensushashing.TransactionID(transaction))
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, transactionSendingAddress, err := txscript.ExtractScriptPubKeyAddress(
|
if transaction, found := sendingInTransactionPool[scriptPublicKey.String()]; found {
|
||||||
input.UTXOEntry.ScriptPublicKey(),
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
||||||
context.Config.ActiveNetParams)
|
err := context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if addressString == transactionSendingAddress.String() {
|
|
||||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
|
||||||
sending = append(
|
|
||||||
sending,
|
|
||||||
&appmessage.MempoolEntry{
|
|
||||||
Fee: transaction.Fee,
|
|
||||||
Transaction: rpcTransaction,
|
|
||||||
IsOrphan: areOrphans,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
break //one input is enough
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, output := range transaction.Outputs {
|
sending = append(sending, &appmessage.MempoolEntry{
|
||||||
_, transactionReceivingAddress, err := txscript.ExtractScriptPubKeyAddress(
|
Fee: transaction.Fee,
|
||||||
output.ScriptPublicKey,
|
Transaction: rpcTransaction,
|
||||||
context.Config.ActiveNetParams,
|
IsOrphan: false,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if transaction, found := receivingInTransactionPool[scriptPublicKey.String()]; found {
|
||||||
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
||||||
|
err := context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if addressString == transactionReceivingAddress.String() {
|
|
||||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
|
||||||
receiving = append(
|
|
||||||
receiving,
|
|
||||||
&appmessage.MempoolEntry{
|
|
||||||
Fee: transaction.Fee,
|
|
||||||
Transaction: rpcTransaction,
|
|
||||||
IsOrphan: areOrphans,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
break //one output is enough
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Only append mempoolEntriesByAddress, if at least 1 mempoolEntry for the address is found.
|
receiving = append(receiving, &appmessage.MempoolEntry{
|
||||||
//This mimics the behaviour of GetUtxosByAddresses RPC call.
|
Fee: transaction.Fee,
|
||||||
if len(sending) > 0 || len(receiving) > 0 {
|
Transaction: rpcTransaction,
|
||||||
mempoolEntriesByAddresses = append(
|
IsOrphan: false,
|
||||||
mempoolEntriesByAddresses,
|
},
|
||||||
&appmessage.MempoolEntryByAddress{
|
|
||||||
Address: addressString,
|
|
||||||
Sending: sending,
|
|
||||||
Receiving: receiving,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if getMempoolEntriesByAddressesRequest.IncludeOrphanPool {
|
||||||
|
|
||||||
|
if transaction, found := sendingInOrphanPool[scriptPublicKey.String()]; found {
|
||||||
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
||||||
|
err := context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sending = append(sending, &appmessage.MempoolEntry{
|
||||||
|
Fee: transaction.Fee,
|
||||||
|
Transaction: rpcTransaction,
|
||||||
|
IsOrphan: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if transaction, found := receivingInOrphanPool[scriptPublicKey.String()]; found {
|
||||||
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
||||||
|
err := context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
receiving = append(receiving, &appmessage.MempoolEntry{
|
||||||
|
Fee: transaction.Fee,
|
||||||
|
Transaction: rpcTransaction,
|
||||||
|
IsOrphan: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sending) > 0 || len(receiving) > 0 {
|
||||||
|
mempoolEntriesByAddresses = append(
|
||||||
|
mempoolEntriesByAddresses,
|
||||||
|
&appmessage.MempoolEntryByAddress{
|
||||||
|
Address: address.String(),
|
||||||
|
Sending: sending,
|
||||||
|
Receiving: receiving,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return mempoolEntriesByAddresses, nil
|
|
||||||
|
return appmessage.NewGetMempoolEntriesByAddressesResponseMessage(mempoolEntriesByAddresses), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,14 +24,7 @@ func HandleGetMempoolEntry(context *rpccontext.Context, _ *router.Router, reques
|
|||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !getMempoolEntryRequest.FilterTransactionPool {
|
mempoolTransaction, isOrphan, found := context.Domain.MiningManager().GetTransaction(transactionID, !getMempoolEntryRequest.FilterTransactionPool, getMempoolEntryRequest.IncludeOrphanPool)
|
||||||
transaction, found = context.Domain.MiningManager().GetTransaction(transactionID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if getMempoolEntryRequest.IncludeOrphanPool && !found {
|
|
||||||
transaction, found = context.Domain.MiningManager().GetOrphanTransaction(transactionID)
|
|
||||||
isOrphan = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
errorMessage := &appmessage.GetMempoolEntryResponseMessage{}
|
errorMessage := &appmessage.GetMempoolEntryResponseMessage{}
|
||||||
@ -39,7 +32,7 @@ func HandleGetMempoolEntry(context *rpccontext.Context, _ *router.Router, reques
|
|||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(mempoolTransaction)
|
||||||
err = context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
err = context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -111,7 +111,8 @@ type startDaemonConfig struct {
|
|||||||
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
||||||
Password string `long:"password" short:"p" description:"Wallet password"`
|
Password string `long:"password" short:"p" description:"Wallet password"`
|
||||||
RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"`
|
RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"`
|
||||||
Listen string `short:"l" long:"listen" description:"Address to listen on (default: 0.0.0.0:8082)"`
|
Listen string `long:"listen" short:"l" description:"Address to listen on (default: 0.0.0.0:8082)"`
|
||||||
|
Timeout uint32 `long:"wait-timeout" short:"w" description:"Waiting timeout for RPC calls, seconds (default: 30 s)"`
|
||||||
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
|
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
@ -181,7 +182,6 @@ func parseCommandLine() (subCommand string, config interface{}) {
|
|||||||
parser.AddCommand(startDaemonSubCmd, "Start the wallet daemon", "Start the wallet daemon", startDaemonConf)
|
parser.AddCommand(startDaemonSubCmd, "Start the wallet daemon", "Start the wallet daemon", startDaemonConf)
|
||||||
|
|
||||||
_, err := parser.Parse()
|
_, err := parser.Parse()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var flagsErr *flags.Error
|
var flagsErr *flags.Error
|
||||||
if ok := errors.As(err, &flagsErr); ok && flagsErr.Type == flags.ErrHelp {
|
if ok := errors.As(err, &flagsErr); ok && flagsErr.Type == flags.ErrHelp {
|
||||||
|
|||||||
@ -3,20 +3,22 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Implement a better fee estimation mechanism
|
// TODO: Implement a better fee estimation mechanism
|
||||||
const feePerInput = 10000
|
const feePerInput = 10000
|
||||||
|
|
||||||
func (s *server) CreateUnsignedTransactions(_ context.Context, request *pb.CreateUnsignedTransactionsRequest) (
|
func (s *server) CreateUnsignedTransactions(_ context.Context, request *pb.CreateUnsignedTransactionsRequest) (
|
||||||
*pb.CreateUnsignedTransactionsResponse, error) {
|
*pb.CreateUnsignedTransactionsResponse, error,
|
||||||
|
) {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
@ -33,12 +35,14 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, fromA
|
|||||||
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
|
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.refreshUTXOs()
|
// make sure address string is correct before proceeding to a
|
||||||
|
// potentially long UTXO refreshment operation
|
||||||
|
toAddress, err := util.DecodeAddress(address, s.params.Prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
toAddress, err := util.DecodeAddress(address, s.params.Prefix)
|
err = s.refreshUTXOs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -87,8 +91,8 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, fromA
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) selectUTXOs(spendAmount uint64, feePerInput uint64, fromAddresses []*walletAddress) (
|
func (s *server) selectUTXOs(spendAmount uint64, feePerInput uint64, fromAddresses []*walletAddress) (
|
||||||
selectedUTXOs []*libkaspawallet.UTXO, changeSompi uint64, err error) {
|
selectedUTXOs []*libkaspawallet.UTXO, changeSompi uint64, err error,
|
||||||
|
) {
|
||||||
selectedUTXOs = []*libkaspawallet.UTXO{}
|
selectedUTXOs = []*libkaspawallet.UTXO{}
|
||||||
totalValue := uint64(0)
|
totalValue := uint64(0)
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,26 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
func connectToRPC(params *dagconfig.Params, rpcServer string) (*rpcclient.RPCClient, error) {
|
func connectToRPC(params *dagconfig.Params, rpcServer string, timeout uint32) (*rpcclient.RPCClient, error) {
|
||||||
rpcAddress, err := params.NormalizeRPCServerAddress(rpcServer)
|
rpcAddress, err := params.NormalizeRPCServerAddress(rpcServer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return rpcclient.NewRPCClient(rpcAddress)
|
rpcClient, err := rpcclient.NewRPCClient(rpcAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if timeout != 0 {
|
||||||
|
rpcClient.SetTimeout(time.Duration(timeout) * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpcClient, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ type server struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the kaspawalletd server
|
// Start starts the kaspawalletd server
|
||||||
func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath string, profile string) error {
|
func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath string, profile string, timeout uint32) error {
|
||||||
initLog(defaultLogFile, defaultErrLogFile)
|
initLog(defaultLogFile, defaultErrLogFile)
|
||||||
|
|
||||||
defer panics.HandlePanic(log, "MAIN", nil)
|
defer panics.HandlePanic(log, "MAIN", nil)
|
||||||
@ -62,7 +62,7 @@ func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath stri
|
|||||||
log.Infof("Listening to TCP on %s", listen)
|
log.Infof("Listening to TCP on %s", listen)
|
||||||
|
|
||||||
log.Infof("Connecting to a node at %s...", rpcServer)
|
log.Infof("Connecting to a node at %s...", rpcServer)
|
||||||
rpcClient, err := connectToRPC(params, rpcServer)
|
rpcClient, err := connectToRPC(params, rpcServer, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return (errors.Wrapf(err, "Error connecting to RPC server %s", rpcServer))
|
return (errors.Wrapf(err, "Error connecting to RPC server %s", rpcServer))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,5 +3,5 @@ package main
|
|||||||
import "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/server"
|
import "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/server"
|
||||||
|
|
||||||
func startDaemon(conf *startDaemonConfig) error {
|
func startDaemon(conf *startDaemonConfig) error {
|
||||||
return server.Start(conf.NetParams(), conf.Listen, conf.RPCServer, conf.KeysFile, conf.Profile)
|
return server.Start(conf.NetParams(), conf.Listen, conf.RPCServer, conf.KeysFile, conf.Profile, conf.Timeout)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package externalapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -242,6 +243,23 @@ func (spk *ScriptPublicKey) Equal(other *ScriptPublicKey) bool {
|
|||||||
return bytes.Equal(spk.Script, other.Script)
|
return bytes.Equal(spk.Script, other.Script)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String stringifies a ScriptPublicKey.
|
||||||
|
func (spk *ScriptPublicKey) String() string {
|
||||||
|
var versionBytes = make([]byte, 2) // uint16
|
||||||
|
binary.LittleEndian.PutUint16(versionBytes, spk.Version)
|
||||||
|
versionString := string(versionBytes)
|
||||||
|
scriptString := string(spk.Script)
|
||||||
|
return versionString + scriptString
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewScriptPublicKeyFromString converts the given string to a scriptPublicKey
|
||||||
|
func NewScriptPublicKeyFromString(ScriptPublicKeyString string) *ScriptPublicKey {
|
||||||
|
bytes := []byte(ScriptPublicKeyString)
|
||||||
|
version := binary.LittleEndian.Uint16(bytes[:2])
|
||||||
|
script := bytes[2:]
|
||||||
|
return &ScriptPublicKey{Script: script, Version: version}
|
||||||
|
}
|
||||||
|
|
||||||
// DomainTransactionOutput represents a Kaspad transaction output
|
// DomainTransactionOutput represents a Kaspad transaction output
|
||||||
type DomainTransactionOutput struct {
|
type DomainTransactionOutput struct {
|
||||||
Value uint64
|
Value uint64
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
package mempool
|
package mempool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/domain/consensusreference"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensusreference"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model"
|
miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model"
|
||||||
)
|
)
|
||||||
@ -42,39 +43,89 @@ func (mp *mempool) ValidateAndInsertTransaction(transaction *externalapi.DomainT
|
|||||||
return mp.validateAndInsertTransaction(transaction, isHighPriority, allowOrphan)
|
return mp.validateAndInsertTransaction(transaction, isHighPriority, allowOrphan)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
func (mp *mempool) GetTransaction(transactionID *externalapi.DomainTransactionID,
|
||||||
|
includeTransactionPool bool,
|
||||||
|
includeOrphanPool bool) (
|
||||||
|
transaction *externalapi.DomainTransaction,
|
||||||
|
isOrphan bool,
|
||||||
|
found bool) {
|
||||||
|
|
||||||
mp.mtx.RLock()
|
mp.mtx.RLock()
|
||||||
defer mp.mtx.RUnlock()
|
defer mp.mtx.RUnlock()
|
||||||
|
|
||||||
return mp.transactionsPool.getTransaction(transactionID)
|
var transactionfound bool
|
||||||
|
isOrphan = false
|
||||||
|
|
||||||
|
if includeTransactionPool {
|
||||||
|
transaction, transactionfound = mp.transactionsPool.getTransaction(transactionID, true)
|
||||||
|
isOrphan = false
|
||||||
|
}
|
||||||
|
if !transactionfound && includeOrphanPool {
|
||||||
|
transaction, transactionfound = mp.orphansPool.getOrphanTransaction(transactionID)
|
||||||
|
isOrphan = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return transaction, isOrphan, transactionfound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) AllTransactions() []*externalapi.DomainTransaction {
|
func (mp *mempool) GetTransactionsByAddresses(includeTransactionPool bool, includeOrphanPool bool) (
|
||||||
|
sendingInTransactionPool map[string]*externalapi.DomainTransaction,
|
||||||
|
receivingInTransactionPool map[string]*externalapi.DomainTransaction,
|
||||||
|
sendingInOrphanPool map[string]*externalapi.DomainTransaction,
|
||||||
|
receivingInOrphanPool map[string]*externalapi.DomainTransaction,
|
||||||
|
err error) {
|
||||||
mp.mtx.RLock()
|
mp.mtx.RLock()
|
||||||
defer mp.mtx.RUnlock()
|
defer mp.mtx.RUnlock()
|
||||||
|
|
||||||
return mp.transactionsPool.getAllTransactions()
|
if includeTransactionPool {
|
||||||
|
sendingInTransactionPool, receivingInTransactionPool, err = mp.transactionsPool.getTransactionsByAddresses()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if includeOrphanPool {
|
||||||
|
sendingInTransactionPool, receivingInOrphanPool, err = mp.orphansPool.getOrphanTransactionsByAddresses()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendingInTransactionPool, receivingInTransactionPool, sendingInTransactionPool, receivingInOrphanPool, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) GetOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
func (mp *mempool) AllTransactions(includeTransactionPool bool, includeOrphanPool bool) (
|
||||||
|
transactionPoolTransactions []*externalapi.DomainTransaction,
|
||||||
|
orphanPoolTransactions []*externalapi.DomainTransaction) {
|
||||||
|
|
||||||
mp.mtx.RLock()
|
mp.mtx.RLock()
|
||||||
defer mp.mtx.RUnlock()
|
defer mp.mtx.RUnlock()
|
||||||
|
|
||||||
return mp.orphansPool.getOrphanTransaction(transactionID)
|
if includeTransactionPool {
|
||||||
|
transactionPoolTransactions = mp.transactionsPool.getAllTransactions()
|
||||||
|
}
|
||||||
|
|
||||||
|
if includeOrphanPool {
|
||||||
|
orphanPoolTransactions = mp.orphansPool.getAllOrphanTransactions()
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactionPoolTransactions, orphanPoolTransactions
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) AllOrphanTransactions() []*externalapi.DomainTransaction {
|
func (mp *mempool) TransactionCount(includeTransactionPool bool, includeOrphanPool bool) int {
|
||||||
mp.mtx.RLock()
|
mp.mtx.RLock()
|
||||||
defer mp.mtx.RUnlock()
|
defer mp.mtx.RUnlock()
|
||||||
|
|
||||||
return mp.orphansPool.getAllOrphanTransactions()
|
transactionCount := 0
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *mempool) TransactionCount() int {
|
if includeOrphanPool {
|
||||||
mp.mtx.RLock()
|
transactionCount += mp.orphansPool.orphanTransactionCount()
|
||||||
defer mp.mtx.RUnlock()
|
}
|
||||||
|
if includeTransactionPool {
|
||||||
|
transactionCount += mp.transactionsPool.transactionCount()
|
||||||
|
}
|
||||||
|
|
||||||
return mp.transactionsPool.transactionCount()
|
return transactionCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) HandleNewBlockTransactions(transactions []*externalapi.DomainTransaction) (
|
func (mp *mempool) HandleNewBlockTransactions(transactions []*externalapi.DomainTransaction) (
|
||||||
|
|||||||
@ -51,7 +51,7 @@ func (mpus *mempoolUTXOSet) addTransaction(transaction *model.MempoolTransaction
|
|||||||
func (mpus *mempoolUTXOSet) removeTransaction(transaction *model.MempoolTransaction) {
|
func (mpus *mempoolUTXOSet) removeTransaction(transaction *model.MempoolTransaction) {
|
||||||
for _, input := range transaction.Transaction().Inputs {
|
for _, input := range transaction.Transaction().Inputs {
|
||||||
// If the transaction creating the output spent by this input is in the mempool - restore it's UTXO
|
// If the transaction creating the output spent by this input is in the mempool - restore it's UTXO
|
||||||
if _, ok := mpus.mempool.transactionsPool.getTransaction(&input.PreviousOutpoint.TransactionID); ok {
|
if _, ok := mpus.mempool.transactionsPool.getTransaction(&input.PreviousOutpoint.TransactionID, false); ok {
|
||||||
mpus.poolUnspentOutputs[input.PreviousOutpoint] = input.UTXOEntry
|
mpus.poolUnspentOutputs[input.PreviousOutpoint] = input.UTXOEntry
|
||||||
}
|
}
|
||||||
delete(mpus.transactionByPreviousOutpoint, input.PreviousOutpoint)
|
delete(mpus.transactionByPreviousOutpoint, input.PreviousOutpoint)
|
||||||
|
|||||||
@ -15,3 +15,6 @@ type OutpointToUTXOEntryMap map[externalapi.DomainOutpoint]externalapi.UTXOEntry
|
|||||||
|
|
||||||
// OutpointToTransactionMap maps an outpoint to a MempoolTransaction
|
// OutpointToTransactionMap maps an outpoint to a MempoolTransaction
|
||||||
type OutpointToTransactionMap map[externalapi.DomainOutpoint]*MempoolTransaction
|
type OutpointToTransactionMap map[externalapi.DomainOutpoint]*MempoolTransaction
|
||||||
|
|
||||||
|
// ScriptPublicKeyStringToDomainTransaction maps an outpoint to a DomainTransaction
|
||||||
|
type ScriptPublicKeyStringToDomainTransaction map[string]*externalapi.DomainTransaction
|
||||||
|
|||||||
@ -169,7 +169,7 @@ func (op *orphansPool) processOrphansAfterAcceptedTransaction(acceptedTransactio
|
|||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
acceptedOrphans = append(acceptedOrphans, orphan.Transaction())
|
acceptedOrphans = append(acceptedOrphans, orphan.Transaction().Clone()) //these pointers leave the mempool, hence the clone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,15 +331,45 @@ func (op *orphansPool) randomNonHighPriorityOrphan() *model.OrphanTransaction {
|
|||||||
|
|
||||||
func (op *orphansPool) getOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
func (op *orphansPool) getOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
||||||
if orphanTransaction, ok := op.allOrphans[*transactionID]; ok {
|
if orphanTransaction, ok := op.allOrphans[*transactionID]; ok {
|
||||||
return orphanTransaction.Transaction(), true
|
return orphanTransaction.Transaction().Clone(), true //this pointer leaves the mempool, hence we clone.
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (op *orphansPool) getAllOrphanTransactions() []*externalapi.DomainTransaction {
|
func (op *orphansPool) getOrphanTransactionsByAddresses() (
|
||||||
allOrphanTransactions := make([]*externalapi.DomainTransaction, 0, len(op.allOrphans))
|
sending model.ScriptPublicKeyStringToDomainTransaction,
|
||||||
|
receiving model.ScriptPublicKeyStringToDomainTransaction,
|
||||||
|
err error) {
|
||||||
|
sending = make(model.ScriptPublicKeyStringToDomainTransaction)
|
||||||
|
receiving = make(model.ScriptPublicKeyStringToDomainTransaction, op.orphanTransactionCount())
|
||||||
|
var transaction *externalapi.DomainTransaction
|
||||||
for _, mempoolTransaction := range op.allOrphans {
|
for _, mempoolTransaction := range op.allOrphans {
|
||||||
allOrphanTransactions = append(allOrphanTransactions, mempoolTransaction.Transaction())
|
transaction = mempoolTransaction.Transaction().Clone() //these pointers leave the mempool, hence we clone.
|
||||||
|
for _, input := range transaction.Inputs {
|
||||||
|
if input.UTXOEntry == nil { //this is not a bug, but a valid state of orphan transactions with missing outpoints.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sending[input.UTXOEntry.ScriptPublicKey().String()] = transaction
|
||||||
|
}
|
||||||
|
for _, output := range transaction.Outputs {
|
||||||
|
receiving[output.ScriptPublicKey.String()] = transaction
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sending, receiving, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *orphansPool) getAllOrphanTransactions() []*externalapi.DomainTransaction {
|
||||||
|
allOrphanTransactions := make([]*externalapi.DomainTransaction, len(op.allOrphans))
|
||||||
|
i := 0
|
||||||
|
for _, mempoolTransaction := range op.allOrphans {
|
||||||
|
allOrphanTransactions[i] = mempoolTransaction.Transaction().Clone() //these pointers leave the mempool, hence we clone.
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
return allOrphanTransactions
|
return allOrphanTransactions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (op *orphansPool) orphanTransactionCount() int {
|
||||||
|
return len(op.allOrphans)
|
||||||
|
}
|
||||||
|
|||||||
@ -11,7 +11,6 @@ func (mp *mempool) revalidateHighPriorityTransactions() ([]*externalapi.DomainTr
|
|||||||
defer onEnd()
|
defer onEnd()
|
||||||
|
|
||||||
validTransactions := []*externalapi.DomainTransaction{}
|
validTransactions := []*externalapi.DomainTransaction{}
|
||||||
|
|
||||||
for _, transaction := range mp.transactionsPool.highPriorityTransactions {
|
for _, transaction := range mp.transactionsPool.highPriorityTransactions {
|
||||||
isValid, err := mp.revalidateTransaction(transaction)
|
isValid, err := mp.revalidateTransaction(transaction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -21,7 +20,7 @@ func (mp *mempool) revalidateHighPriorityTransactions() ([]*externalapi.DomainTr
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
validTransactions = append(validTransactions, transaction.Transaction())
|
validTransactions = append(validTransactions, transaction.Transaction().Clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
return validTransactions, nil
|
return validTransactions, nil
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -135,7 +136,7 @@ func (tp *transactionsPool) allReadyTransactions() []*externalapi.DomainTransact
|
|||||||
|
|
||||||
for _, mempoolTransaction := range tp.allTransactions {
|
for _, mempoolTransaction := range tp.allTransactions {
|
||||||
if len(mempoolTransaction.ParentTransactionsInPool()) == 0 {
|
if len(mempoolTransaction.ParentTransactionsInPool()) == 0 {
|
||||||
result = append(result, mempoolTransaction.Transaction())
|
result = append(result, mempoolTransaction.Transaction().Clone()) //this pointer leaves the mempool, and gets its utxo set to nil, hence we clone.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,17 +205,44 @@ func (tp *transactionsPool) limitTransactionCount() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tp *transactionsPool) getTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
func (tp *transactionsPool) getTransaction(transactionID *externalapi.DomainTransactionID, clone bool) (*externalapi.DomainTransaction, bool) {
|
||||||
if mempoolTransaction, ok := tp.allTransactions[*transactionID]; ok {
|
if mempoolTransaction, ok := tp.allTransactions[*transactionID]; ok {
|
||||||
|
if clone {
|
||||||
|
return mempoolTransaction.Transaction().Clone(), true //this pointer leaves the mempool, hence we clone.
|
||||||
|
}
|
||||||
return mempoolTransaction.Transaction(), true
|
return mempoolTransaction.Transaction(), true
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tp *transactionsPool) getAllTransactions() []*externalapi.DomainTransaction {
|
func (tp *transactionsPool) getTransactionsByAddresses() (
|
||||||
allTransactions := make([]*externalapi.DomainTransaction, 0, len(tp.allTransactions))
|
sending model.ScriptPublicKeyStringToDomainTransaction,
|
||||||
|
receiving model.ScriptPublicKeyStringToDomainTransaction,
|
||||||
|
err error) {
|
||||||
|
sending = make(model.ScriptPublicKeyStringToDomainTransaction, tp.transactionCount())
|
||||||
|
receiving = make(model.ScriptPublicKeyStringToDomainTransaction, tp.transactionCount())
|
||||||
|
var transaction *externalapi.DomainTransaction
|
||||||
for _, mempoolTransaction := range tp.allTransactions {
|
for _, mempoolTransaction := range tp.allTransactions {
|
||||||
allTransactions = append(allTransactions, mempoolTransaction.Transaction())
|
transaction = mempoolTransaction.Transaction().Clone() //this pointer leaves the mempool, hence we clone.
|
||||||
|
for _, input := range transaction.Inputs {
|
||||||
|
if input.UTXOEntry == nil {
|
||||||
|
return nil, nil, errors.Errorf("Mempool transaction %s is missing an UTXOEntry. This should be fixed, and not happen", consensushashing.TransactionID(transaction).String())
|
||||||
|
}
|
||||||
|
sending[input.UTXOEntry.ScriptPublicKey().String()] = transaction
|
||||||
|
}
|
||||||
|
for _, output := range transaction.Outputs {
|
||||||
|
receiving[output.ScriptPublicKey.String()] = transaction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sending, receiving, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tp *transactionsPool) getAllTransactions() []*externalapi.DomainTransaction {
|
||||||
|
allTransactions := make([]*externalapi.DomainTransaction, len(tp.allTransactions))
|
||||||
|
i := 0
|
||||||
|
for _, mempoolTransaction := range tp.allTransactions {
|
||||||
|
allTransactions[i] = mempoolTransaction.Transaction().Clone() //this pointer leaves the mempool, hence we clone.
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
return allTransactions
|
return allTransactions
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ func (mp *mempool) validateAndInsertTransaction(transaction *externalapi.DomainT
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptedTransactions = append([]*externalapi.DomainTransaction{transaction}, acceptedOrphans...)
|
acceptedTransactions = append([]*externalapi.DomainTransaction{transaction.Clone()}, acceptedOrphans...) //these pointer leave the mempool, hence we clone.
|
||||||
|
|
||||||
err = mp.transactionsPool.limitTransactionCount()
|
err = mp.transactionsPool.limitTransactionCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -15,11 +15,20 @@ type MiningManager interface {
|
|||||||
GetBlockTemplate(coinbaseData *externalapi.DomainCoinbaseData) (block *externalapi.DomainBlock, isNearlySynced bool, err error)
|
GetBlockTemplate(coinbaseData *externalapi.DomainCoinbaseData) (block *externalapi.DomainBlock, isNearlySynced bool, err error)
|
||||||
ClearBlockTemplate()
|
ClearBlockTemplate()
|
||||||
GetBlockTemplateBuilder() miningmanagermodel.BlockTemplateBuilder
|
GetBlockTemplateBuilder() miningmanagermodel.BlockTemplateBuilder
|
||||||
GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
GetTransaction(transactionID *externalapi.DomainTransactionID, includeTransactionPool bool, includeOrphanPool bool) (
|
||||||
AllTransactions() []*externalapi.DomainTransaction
|
transactionPoolTransaction *externalapi.DomainTransaction,
|
||||||
GetOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
isOrphan bool,
|
||||||
AllOrphanTransactions() []*externalapi.DomainTransaction
|
found bool)
|
||||||
TransactionCount() int
|
GetTransactionsByAddresses(includeTransactionPool bool, includeOrphanPool bool) (
|
||||||
|
sendingInTransactionPool map[string]*externalapi.DomainTransaction,
|
||||||
|
receivingInTransactionPool map[string]*externalapi.DomainTransaction,
|
||||||
|
sendingInOrphanPool map[string]*externalapi.DomainTransaction,
|
||||||
|
receivingInOrphanPool map[string]*externalapi.DomainTransaction,
|
||||||
|
err error)
|
||||||
|
AllTransactions(includeTransactionPool bool, includeOrphanPool bool) (
|
||||||
|
transactionPoolTransactions []*externalapi.DomainTransaction,
|
||||||
|
orphanPoolTransactions []*externalapi.DomainTransaction)
|
||||||
|
TransactionCount(includeTransactionPool bool, includeOrphanPool bool) int
|
||||||
HandleNewBlockTransactions(txs []*externalapi.DomainTransaction) ([]*externalapi.DomainTransaction, error)
|
HandleNewBlockTransactions(txs []*externalapi.DomainTransaction) ([]*externalapi.DomainTransaction, error)
|
||||||
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
||||||
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
||||||
@ -109,28 +118,35 @@ func (mm *miningManager) ValidateAndInsertTransaction(transaction *externalapi.D
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mm *miningManager) GetTransaction(
|
func (mm *miningManager) GetTransaction(
|
||||||
transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
transactionID *externalapi.DomainTransactionID,
|
||||||
|
includeTransactionPool bool,
|
||||||
|
includeOrphanPool bool) (
|
||||||
|
transactionPoolTransaction *externalapi.DomainTransaction,
|
||||||
|
isOrphan bool,
|
||||||
|
found bool) {
|
||||||
|
|
||||||
return mm.mempool.GetTransaction(transactionID)
|
return mm.mempool.GetTransaction(transactionID, includeTransactionPool, includeOrphanPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mm *miningManager) AllTransactions() []*externalapi.DomainTransaction {
|
func (mm *miningManager) AllTransactions(includeTransactionPool bool, includeOrphanPool bool) (
|
||||||
return mm.mempool.AllTransactions()
|
transactionPoolTransactions []*externalapi.DomainTransaction,
|
||||||
|
orphanPoolTransactions []*externalapi.DomainTransaction) {
|
||||||
|
|
||||||
|
return mm.mempool.AllTransactions(includeTransactionPool, includeOrphanPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mm *miningManager) GetOrphanTransaction(
|
func (mm *miningManager) GetTransactionsByAddresses(includeTransactionPool bool, includeOrphanPool bool) (
|
||||||
transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
sendingInTransactionPool map[string]*externalapi.DomainTransaction,
|
||||||
|
receivingInTransactionPool map[string]*externalapi.DomainTransaction,
|
||||||
|
sendingInOrphanPool map[string]*externalapi.DomainTransaction,
|
||||||
|
receivingInOrphanPool map[string]*externalapi.DomainTransaction,
|
||||||
|
err error) {
|
||||||
|
|
||||||
return mm.mempool.GetOrphanTransaction(transactionID)
|
return mm.mempool.GetTransactionsByAddresses(includeTransactionPool, includeOrphanPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mm *miningManager) AllOrphanTransactions() []*externalapi.DomainTransaction {
|
func (mm *miningManager) TransactionCount(includeTransactionPool bool, includeOrphanPool bool) int {
|
||||||
|
return mm.mempool.TransactionCount(includeTransactionPool, includeOrphanPool)
|
||||||
return mm.mempool.AllOrphanTransactions()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mm *miningManager) TransactionCount() int {
|
|
||||||
return mm.mempool.TransactionCount()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mm *miningManager) RevalidateHighPriorityTransactions() (
|
func (mm *miningManager) RevalidateHighPriorityTransactions() (
|
||||||
|
|||||||
@ -52,7 +52,7 @@ func TestValidateAndInsertTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// The UTXOEntry was filled manually for those transactions, so the transactions won't be considered orphans.
|
// The UTXOEntry was filled manually for those transactions, so the transactions won't be considered orphans.
|
||||||
// Therefore, all the transactions expected to be contained in the mempool.
|
// Therefore, all the transactions expected to be contained in the mempool.
|
||||||
transactionsFromMempool := miningManager.AllTransactions()
|
transactionsFromMempool, _ := miningManager.AllTransactions(true, false)
|
||||||
if len(transactionsToInsert) != len(transactionsFromMempool) {
|
if len(transactionsToInsert) != len(transactionsFromMempool) {
|
||||||
t.Fatalf("Wrong number of transactions in mempool: expected: %d, got: %d", len(transactionsToInsert), len(transactionsFromMempool))
|
t.Fatalf("Wrong number of transactions in mempool: expected: %d, got: %d", len(transactionsToInsert), len(transactionsFromMempool))
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ func TestValidateAndInsertTransaction(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||||
}
|
}
|
||||||
transactionsFromMempool = miningManager.AllTransactions()
|
transactionsFromMempool, _ = miningManager.AllTransactions(true, false)
|
||||||
if !contains(transactionNotAnOrphan, transactionsFromMempool) {
|
if !contains(transactionNotAnOrphan, transactionsFromMempool) {
|
||||||
t.Fatalf("Missing transaction %s in the mempool", consensushashing.TransactionID(transactionNotAnOrphan))
|
t.Fatalf("Missing transaction %s in the mempool", consensushashing.TransactionID(transactionNotAnOrphan))
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ func TestImmatureSpend(t *testing.T) {
|
|||||||
if !errors.As(err, txRuleError) || txRuleError.RejectCode != mempool.RejectImmatureSpend {
|
if !errors.As(err, txRuleError) || txRuleError.RejectCode != mempool.RejectImmatureSpend {
|
||||||
t.Fatalf("Unexpected error %+v", err)
|
t.Fatalf("Unexpected error %+v", err)
|
||||||
}
|
}
|
||||||
transactionsFromMempool := miningManager.AllTransactions()
|
transactionsFromMempool, _ := miningManager.AllTransactions(true, false)
|
||||||
if contains(tx, transactionsFromMempool) {
|
if contains(tx, transactionsFromMempool) {
|
||||||
t.Fatalf("Mempool contains a transaction with immature coinbase")
|
t.Fatalf("Mempool contains a transaction with immature coinbase")
|
||||||
}
|
}
|
||||||
@ -205,7 +205,7 @@ func TestHandleNewBlockTransactions(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("HandleNewBlockTransactions: %v", err)
|
t.Fatalf("HandleNewBlockTransactions: %v", err)
|
||||||
}
|
}
|
||||||
mempoolTransactions := miningManager.AllTransactions()
|
mempoolTransactions, _ := miningManager.AllTransactions(true, false)
|
||||||
for _, removedTransaction := range blockWithFirstPartOfTheTransactions {
|
for _, removedTransaction := range blockWithFirstPartOfTheTransactions {
|
||||||
if contains(removedTransaction, mempoolTransactions) {
|
if contains(removedTransaction, mempoolTransactions) {
|
||||||
t.Fatalf("This transaction shouldnt be in mempool: %s", consensushashing.TransactionID(removedTransaction))
|
t.Fatalf("This transaction shouldnt be in mempool: %s", consensushashing.TransactionID(removedTransaction))
|
||||||
@ -214,7 +214,7 @@ func TestHandleNewBlockTransactions(t *testing.T) {
|
|||||||
|
|
||||||
// There are no chained/double-spends transactions, and hence it is expected that all the other
|
// There are no chained/double-spends transactions, and hence it is expected that all the other
|
||||||
// transactions, will still be included in the mempool.
|
// transactions, will still be included in the mempool.
|
||||||
mempoolTransactions = miningManager.AllTransactions()
|
mempoolTransactions, _ = miningManager.AllTransactions(true, false)
|
||||||
for _, transaction := range blockWithRestOfTheTransactions[transactionhelper.CoinbaseTransactionIndex+1:] {
|
for _, transaction := range blockWithRestOfTheTransactions[transactionhelper.CoinbaseTransactionIndex+1:] {
|
||||||
if !contains(transaction, mempoolTransactions) {
|
if !contains(transaction, mempoolTransactions) {
|
||||||
t.Fatalf("This transaction %s should be in mempool.", consensushashing.TransactionID(transaction))
|
t.Fatalf("This transaction %s should be in mempool.", consensushashing.TransactionID(transaction))
|
||||||
@ -225,8 +225,9 @@ func TestHandleNewBlockTransactions(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("HandleNewBlockTransactions: %v", err)
|
t.Fatalf("HandleNewBlockTransactions: %v", err)
|
||||||
}
|
}
|
||||||
if len(miningManager.AllTransactions()) != 0 {
|
mempoolTransactions, _ = miningManager.AllTransactions(true, false)
|
||||||
blockIDs := domainBlocksToBlockIds(miningManager.AllTransactions())
|
if len(mempoolTransactions) != 0 {
|
||||||
|
blockIDs := domainBlocksToBlockIds(mempoolTransactions)
|
||||||
t.Fatalf("The mempool contains unexpected transactions: %s", blockIDs)
|
t.Fatalf("The mempool contains unexpected transactions: %s", blockIDs)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -269,7 +270,8 @@ func TestDoubleSpendWithBlock(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("HandleNewBlockTransactions: %v", err)
|
t.Fatalf("HandleNewBlockTransactions: %v", err)
|
||||||
}
|
}
|
||||||
if contains(transactionInTheMempool, miningManager.AllTransactions()) {
|
mempoolTransactions, _ := miningManager.AllTransactions(true, false)
|
||||||
|
if contains(transactionInTheMempool, mempoolTransactions) {
|
||||||
t.Fatalf("The transaction %s, shouldn't be in the mempool, since at least one "+
|
t.Fatalf("The transaction %s, shouldn't be in the mempool, since at least one "+
|
||||||
"output was already spent.", consensushashing.TransactionID(transactionInTheMempool))
|
"output was already spent.", consensushashing.TransactionID(transactionInTheMempool))
|
||||||
}
|
}
|
||||||
@ -303,7 +305,7 @@ func TestOrphanTransactions(t *testing.T) {
|
|||||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transactionsMempool := miningManager.AllTransactions()
|
transactionsMempool, _ := miningManager.AllTransactions(true, false)
|
||||||
for _, transaction := range transactionsMempool {
|
for _, transaction := range transactionsMempool {
|
||||||
if contains(transaction, childTransactions) {
|
if contains(transaction, childTransactions) {
|
||||||
t.Fatalf("Error: an orphan transaction is exist in the mempool")
|
t.Fatalf("Error: an orphan transaction is exist in the mempool")
|
||||||
@ -345,7 +347,7 @@ func TestOrphanTransactions(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("HandleNewBlockTransactions: %+v", err)
|
t.Fatalf("HandleNewBlockTransactions: %+v", err)
|
||||||
}
|
}
|
||||||
transactionsMempool = miningManager.AllTransactions()
|
transactionsMempool, _ = miningManager.AllTransactions(true, false)
|
||||||
if len(transactionsMempool) != len(childTransactions) {
|
if len(transactionsMempool) != len(childTransactions) {
|
||||||
t.Fatalf("Expected %d transactions in the mempool but got %d", len(childTransactions), len(transactionsMempool))
|
t.Fatalf("Expected %d transactions in the mempool but got %d", len(childTransactions), len(transactionsMempool))
|
||||||
}
|
}
|
||||||
@ -553,8 +555,8 @@ func TestRevalidateHighPriorityTransactions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure spendingTransaction is still in mempool
|
// Make sure spendingTransaction is still in mempool
|
||||||
allTransactions := miningManager.AllTransactions()
|
mempoolTransactions, _ := miningManager.AllTransactions(true, false)
|
||||||
if len(allTransactions) != 1 || !allTransactions[0].Equal(spendingTransaction) {
|
if len(mempoolTransactions) != 1 || !mempoolTransactions[0].Equal(spendingTransaction) {
|
||||||
t.Fatalf("Expected to have spendingTransaction as only validTransaction returned from "+
|
t.Fatalf("Expected to have spendingTransaction as only validTransaction returned from "+
|
||||||
"RevalidateHighPriorityTransactions, but got %v instead", validTransactions)
|
"RevalidateHighPriorityTransactions, but got %v instead", validTransactions)
|
||||||
}
|
}
|
||||||
@ -568,9 +570,9 @@ func TestRevalidateHighPriorityTransactions(t *testing.T) {
|
|||||||
t.Fatalf("Expected to have empty validTransactions, but got %v instead", validTransactions)
|
t.Fatalf("Expected to have empty validTransactions, but got %v instead", validTransactions)
|
||||||
}
|
}
|
||||||
// And also AllTransactions should be empty as well
|
// And also AllTransactions should be empty as well
|
||||||
allTransactions = miningManager.AllTransactions()
|
mempoolTransactions, _ = miningManager.AllTransactions(true, false)
|
||||||
if len(allTransactions) != 0 {
|
if len(mempoolTransactions) != 0 {
|
||||||
t.Fatalf("Expected to have empty allTransactions, but got %v instead", allTransactions)
|
t.Fatalf("Expected to have empty allTransactions, but got %v instead", mempoolTransactions)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -605,7 +607,7 @@ func TestModifyBlockTemplate(t *testing.T) {
|
|||||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transactionsMempool := miningManager.AllTransactions()
|
transactionsMempool, _ := miningManager.AllTransactions(true, false)
|
||||||
for _, transaction := range transactionsMempool {
|
for _, transaction := range transactionsMempool {
|
||||||
if contains(transaction, childTransactions) {
|
if contains(transaction, childTransactions) {
|
||||||
t.Fatalf("Error: an orphan transaction is exist in the mempool")
|
t.Fatalf("Error: an orphan transaction is exist in the mempool")
|
||||||
@ -654,7 +656,7 @@ func TestModifyBlockTemplate(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("HandleNewBlockTransactions: %+v", err)
|
t.Fatalf("HandleNewBlockTransactions: %+v", err)
|
||||||
}
|
}
|
||||||
transactionsMempool = miningManager.AllTransactions()
|
transactionsMempool, _ = miningManager.AllTransactions(true, false)
|
||||||
if len(transactionsMempool) != len(childTransactions) {
|
if len(transactionsMempool) != len(childTransactions) {
|
||||||
t.Fatalf("Expected %d transactions in the mempool but got %d", len(childTransactions), len(transactionsMempool))
|
t.Fatalf("Expected %d transactions in the mempool but got %d", len(childTransactions), len(transactionsMempool))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,11 +12,31 @@ type Mempool interface {
|
|||||||
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
||||||
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
||||||
RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error
|
RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error
|
||||||
GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
GetTransaction(
|
||||||
AllTransactions() []*externalapi.DomainTransaction
|
transactionID *externalapi.DomainTransactionID,
|
||||||
GetOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
includeTransactionPool bool,
|
||||||
AllOrphanTransactions() []*externalapi.DomainTransaction
|
includeOrphanPool bool,
|
||||||
TransactionCount() int
|
) (
|
||||||
|
transactionPoolTransaction *externalapi.DomainTransaction,
|
||||||
|
isOrphan bool,
|
||||||
|
found bool)
|
||||||
|
GetTransactionsByAddresses(
|
||||||
|
includeTransactionPool bool,
|
||||||
|
includeOrphanPool bool) (
|
||||||
|
sendingInTransactionPool map[string]*externalapi.DomainTransaction,
|
||||||
|
receivingInTransactionPool map[string]*externalapi.DomainTransaction,
|
||||||
|
sendingInOrphanPool map[string]*externalapi.DomainTransaction,
|
||||||
|
receivingInOrphanPool map[string]*externalapi.DomainTransaction,
|
||||||
|
err error)
|
||||||
|
AllTransactions(
|
||||||
|
includeTransactionPool bool,
|
||||||
|
includeOrphanPool bool,
|
||||||
|
) (
|
||||||
|
transactionPoolTransactions []*externalapi.DomainTransaction,
|
||||||
|
orphanPoolTransactions []*externalapi.DomainTransaction)
|
||||||
|
TransactionCount(
|
||||||
|
includeTransactionPool bool,
|
||||||
|
includeOrphanPool bool) int
|
||||||
RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error)
|
RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error)
|
||||||
IsTransactionOutputDust(output *externalapi.DomainTransactionOutput) bool
|
IsTransactionOutputDust(output *externalapi.DomainTransactionOutput) bool
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package utxoindex
|
package utxoindex
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,22 +21,3 @@ type UTXOChanges struct {
|
|||||||
Added map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
Added map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
||||||
Removed map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
Removed map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertScriptPublicKeyToString converts the given scriptPublicKey to a string
|
|
||||||
func ConvertScriptPublicKeyToString(scriptPublicKey *externalapi.ScriptPublicKey) ScriptPublicKeyString {
|
|
||||||
var versionBytes = make([]byte, 2) // uint16
|
|
||||||
binary.LittleEndian.PutUint16(versionBytes, scriptPublicKey.Version)
|
|
||||||
versionString := ScriptPublicKeyString(versionBytes)
|
|
||||||
scriptString := ScriptPublicKeyString(scriptPublicKey.Script)
|
|
||||||
return versionString + scriptString
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertStringToScriptPublicKey converts the given string to a scriptPublicKey
|
|
||||||
func ConvertStringToScriptPublicKey(string ScriptPublicKeyString) *externalapi.ScriptPublicKey {
|
|
||||||
bytes := []byte(string)
|
|
||||||
version := binary.LittleEndian.Uint16(bytes[:2])
|
|
||||||
script := bytes[2:]
|
|
||||||
return &externalapi.ScriptPublicKey{Script: script, Version: version}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ func newUTXOIndexStore(database database.Database) *utxoIndexStore {
|
|||||||
|
|
||||||
func (uis *utxoIndexStore) add(scriptPublicKey *externalapi.ScriptPublicKey, outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry) error {
|
func (uis *utxoIndexStore) add(scriptPublicKey *externalapi.ScriptPublicKey, outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry) error {
|
||||||
|
|
||||||
key := ConvertScriptPublicKeyToString(scriptPublicKey)
|
key := ScriptPublicKeyString(scriptPublicKey.String())
|
||||||
log.Tracef("Adding outpoint %s:%d to scriptPublicKey %s",
|
log.Tracef("Adding outpoint %s:%d to scriptPublicKey %s",
|
||||||
outpoint.TransactionID, outpoint.Index, key)
|
outpoint.TransactionID, outpoint.Index, key)
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ func (uis *utxoIndexStore) add(scriptPublicKey *externalapi.ScriptPublicKey, out
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (uis *utxoIndexStore) remove(scriptPublicKey *externalapi.ScriptPublicKey, outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry) error {
|
func (uis *utxoIndexStore) remove(scriptPublicKey *externalapi.ScriptPublicKey, outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry) error {
|
||||||
key := ConvertScriptPublicKeyToString(scriptPublicKey)
|
key := ScriptPublicKeyString(scriptPublicKey.String())
|
||||||
log.Tracef("Removing outpoint %s:%d from scriptPublicKey %s",
|
log.Tracef("Removing outpoint %s:%d from scriptPublicKey %s",
|
||||||
outpoint.TransactionID, outpoint.Index, key)
|
outpoint.TransactionID, outpoint.Index, key)
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ func (uis *utxoIndexStore) commit() error {
|
|||||||
toRemoveSompiSupply := uint64(0)
|
toRemoveSompiSupply := uint64(0)
|
||||||
|
|
||||||
for scriptPublicKeyString, toRemoveUTXOOutpointEntryPairs := range uis.toRemove {
|
for scriptPublicKeyString, toRemoveUTXOOutpointEntryPairs := range uis.toRemove {
|
||||||
scriptPublicKey := ConvertStringToScriptPublicKey(scriptPublicKeyString)
|
scriptPublicKey := externalapi.NewScriptPublicKeyFromString(string(scriptPublicKeyString))
|
||||||
bucket := uis.bucketForScriptPublicKey(scriptPublicKey)
|
bucket := uis.bucketForScriptPublicKey(scriptPublicKey)
|
||||||
for outpointToRemove, utxoEntryToRemove := range toRemoveUTXOOutpointEntryPairs {
|
for outpointToRemove, utxoEntryToRemove := range toRemoveUTXOOutpointEntryPairs {
|
||||||
key, err := uis.convertOutpointToKey(bucket, &outpointToRemove)
|
key, err := uis.convertOutpointToKey(bucket, &outpointToRemove)
|
||||||
@ -140,7 +140,7 @@ func (uis *utxoIndexStore) commit() error {
|
|||||||
toAddSompiSupply := uint64(0)
|
toAddSompiSupply := uint64(0)
|
||||||
|
|
||||||
for scriptPublicKeyString, toAddUTXOOutpointEntryPairs := range uis.toAdd {
|
for scriptPublicKeyString, toAddUTXOOutpointEntryPairs := range uis.toAdd {
|
||||||
scriptPublicKey := ConvertStringToScriptPublicKey(scriptPublicKeyString)
|
scriptPublicKey := externalapi.NewScriptPublicKeyFromString(string(scriptPublicKeyString))
|
||||||
bucket := uis.bucketForScriptPublicKey(scriptPublicKey)
|
bucket := uis.bucketForScriptPublicKey(scriptPublicKey)
|
||||||
for outpointToAdd, utxoEntryToAdd := range toAddUTXOOutpointEntryPairs {
|
for outpointToAdd, utxoEntryToAdd := range toAddUTXOOutpointEntryPairs {
|
||||||
key, err := uis.convertOutpointToKey(bucket, &outpointToAdd)
|
key, err := uis.convertOutpointToKey(bucket, &outpointToAdd)
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
package rpcclient
|
package rpcclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
@ -8,8 +11,6 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/util/panics"
|
"github.com/kaspanet/kaspad/util/panics"
|
||||||
"github.com/kaspanet/kaspad/version"
|
"github.com/kaspanet/kaspad/version"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultTimeout = 30 * time.Second
|
const defaultTimeout = 30 * time.Second
|
||||||
@ -28,7 +29,7 @@ type RPCClient struct {
|
|||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRPCClient creates a new RPC client
|
// NewRPCClient сreates a new RPC client with a default call timeout value
|
||||||
func NewRPCClient(rpcAddress string) (*RPCClient, error) {
|
func NewRPCClient(rpcAddress string) (*RPCClient, error) {
|
||||||
rpcClient := &RPCClient{
|
rpcClient := &RPCClient{
|
||||||
rpcAddress: rpcAddress,
|
rpcAddress: rpcAddress,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user