mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-11-24 06:25:55 +00:00
Merge branch 'dev' into add_id_to_wallet_client_and_daemon_interaction
This commit is contained in:
commit
8cce9832cf
@ -4,6 +4,8 @@ package appmessage
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetMempoolEntriesRequestMessage struct {
|
type GetMempoolEntriesRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
|
IncludeOrphanPool bool
|
||||||
|
FilterTransactionPool bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -12,8 +14,11 @@ func (msg *GetMempoolEntriesRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetMempoolEntriesRequestMessage returns a instance of the message
|
// NewGetMempoolEntriesRequestMessage returns a instance of the message
|
||||||
func NewGetMempoolEntriesRequestMessage() *GetMempoolEntriesRequestMessage {
|
func NewGetMempoolEntriesRequestMessage(includeOrphanPool bool, filterTransactionPool bool) *GetMempoolEntriesRequestMessage {
|
||||||
return &GetMempoolEntriesRequestMessage{}
|
return &GetMempoolEntriesRequestMessage{
|
||||||
|
IncludeOrphanPool: includeOrphanPool,
|
||||||
|
FilterTransactionPool: filterTransactionPool,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMempoolEntriesResponseMessage is an appmessage corresponding to
|
// GetMempoolEntriesResponseMessage is an appmessage corresponding to
|
||||||
|
|||||||
@ -11,7 +11,9 @@ type MempoolEntryByAddress struct {
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetMempoolEntriesByAddressesRequestMessage struct {
|
type GetMempoolEntriesByAddressesRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
Addresses []string
|
Addresses []string
|
||||||
|
IncludeOrphanPool bool
|
||||||
|
FilterTransactionPool bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -20,9 +22,11 @@ func (msg *GetMempoolEntriesByAddressesRequestMessage) Command() MessageCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetMempoolEntriesByAddressesRequestMessage returns a instance of the message
|
// NewGetMempoolEntriesByAddressesRequestMessage returns a instance of the message
|
||||||
func NewGetMempoolEntriesByAddressesRequestMessage(addresses []string) *GetMempoolEntriesByAddressesRequestMessage {
|
func NewGetMempoolEntriesByAddressesRequestMessage(addresses []string, includeOrphanPool bool, filterTransactionPool bool) *GetMempoolEntriesByAddressesRequestMessage {
|
||||||
return &GetMempoolEntriesByAddressesRequestMessage{
|
return &GetMempoolEntriesByAddressesRequestMessage{
|
||||||
Addresses: addresses,
|
Addresses: addresses,
|
||||||
|
IncludeOrphanPool: includeOrphanPool,
|
||||||
|
FilterTransactionPool: filterTransactionPool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,9 @@ package appmessage
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetMempoolEntryRequestMessage struct {
|
type GetMempoolEntryRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
TxID string
|
TxID string
|
||||||
|
IncludeOrphanPool bool
|
||||||
|
FilterTransactionPool bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -13,8 +15,12 @@ func (msg *GetMempoolEntryRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetMempoolEntryRequestMessage returns a instance of the message
|
// NewGetMempoolEntryRequestMessage returns a instance of the message
|
||||||
func NewGetMempoolEntryRequestMessage(txID string) *GetMempoolEntryRequestMessage {
|
func NewGetMempoolEntryRequestMessage(txID string, includeOrphanPool bool, filterTransactionPool bool) *GetMempoolEntryRequestMessage {
|
||||||
return &GetMempoolEntryRequestMessage{TxID: txID}
|
return &GetMempoolEntryRequestMessage{
|
||||||
|
TxID: txID,
|
||||||
|
IncludeOrphanPool: includeOrphanPool,
|
||||||
|
FilterTransactionPool: filterTransactionPool,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMempoolEntryResponseMessage is an appmessage corresponding to
|
// GetMempoolEntryResponseMessage is an appmessage corresponding to
|
||||||
@ -30,6 +36,7 @@ type GetMempoolEntryResponseMessage struct {
|
|||||||
type MempoolEntry struct {
|
type MempoolEntry struct {
|
||||||
Fee uint64
|
Fee uint64
|
||||||
Transaction *RPCTransaction
|
Transaction *RPCTransaction
|
||||||
|
IsOrphan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -38,11 +45,12 @@ func (msg *GetMempoolEntryResponseMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetMempoolEntryResponseMessage returns a instance of the message
|
// NewGetMempoolEntryResponseMessage returns a instance of the message
|
||||||
func NewGetMempoolEntryResponseMessage(fee uint64, transaction *RPCTransaction) *GetMempoolEntryResponseMessage {
|
func NewGetMempoolEntryResponseMessage(fee uint64, transaction *RPCTransaction, isOrphan bool) *GetMempoolEntryResponseMessage {
|
||||||
return &GetMempoolEntryResponseMessage{
|
return &GetMempoolEntryResponseMessage{
|
||||||
Entry: &MempoolEntry{
|
Entry: &MempoolEntry{
|
||||||
Fee: fee,
|
Fee: fee,
|
||||||
Transaction: transaction,
|
Transaction: transaction,
|
||||||
|
IsOrphan: isOrphan,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -107,7 +107,7 @@ func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error {
|
|||||||
return protocolerrors.Errorf(false, "cannot add header only block")
|
return protocolerrors.Errorf(false, "cannot add header only block")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := f.Domain().Consensus().ValidateAndInsertBlock(block, true)
|
err := f.Domain().Consensus().ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
log.Warnf("Validation failed for block %s: %s", consensushashing.BlockHash(block), err)
|
log.Warnf("Validation failed for block %s: %s", consensushashing.BlockHash(block), err)
|
||||||
|
|||||||
@ -141,7 +141,7 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (bool, er
|
|||||||
}
|
}
|
||||||
delete(f.orphans, orphanHash)
|
delete(f.orphans, orphanHash)
|
||||||
|
|
||||||
_, err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock, true)
|
err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
log.Warnf("Validation failed for orphan block %s: %s", orphanHash, err)
|
log.Warnf("Validation failed for orphan block %s: %s", orphanHash, err)
|
||||||
|
|||||||
@ -321,7 +321,7 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock,
|
|||||||
|
|
||||||
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, error) {
|
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, error) {
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
_, err := flow.Domain().Consensus().ValidateAndInsertBlock(block, true)
|
err := flow.Domain().Consensus().ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.As(err, &ruleerrors.RuleError{}) {
|
if !errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
return nil, errors.Wrapf(err, "failed to process block %s", blockHash)
|
return nil, errors.Wrapf(err, "failed to process block %s", blockHash)
|
||||||
|
|||||||
@ -488,7 +488,7 @@ func (flow *handleIBDFlow) processHeader(consensus externalapi.Consensus, msgBlo
|
|||||||
log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash)
|
log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err = consensus.ValidateAndInsertBlock(block, false)
|
err = consensus.ValidateAndInsertBlock(block, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.As(err, &ruleerrors.RuleError{}) {
|
if !errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
return errors.Wrapf(err, "failed to process header %s during IBD", blockHash)
|
return errors.Wrapf(err, "failed to process header %s during IBD", blockHash)
|
||||||
@ -654,7 +654,7 @@ func (flow *handleIBDFlow) syncMissingBlockBodies(highHash *externalapi.DomainHa
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = flow.Domain().Consensus().ValidateAndInsertBlock(block, false)
|
err = flow.Domain().Consensus().ValidateAndInsertBlock(block, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
||||||
log.Debugf("Skipping IBD Block %s as it has already been added to the DAG", blockHash)
|
log.Debugf("Skipping IBD Block %s as it has already been added to the DAG", blockHash)
|
||||||
@ -705,7 +705,7 @@ func (flow *handleIBDFlow) resolveVirtual(estimatedVirtualDAAScoreTarget uint64)
|
|||||||
}
|
}
|
||||||
log.Infof("Resolving virtual. Estimated progress: %d%%", percents)
|
log.Infof("Resolving virtual. Estimated progress: %d%%", percents)
|
||||||
}
|
}
|
||||||
_, isCompletelyResolved, err := flow.Domain().Consensus().ResolveVirtual()
|
isCompletelyResolved, err := flow.Domain().Consensus().ResolveVirtual()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -280,7 +280,7 @@ func (flow *handleIBDFlow) processBlockWithTrustedData(
|
|||||||
blockWithTrustedData.GHOSTDAGData = append(blockWithTrustedData.GHOSTDAGData, appmessage.GHOSTDAGHashPairToDomainGHOSTDAGHashPair(data.GHOSTDAGData[index]))
|
blockWithTrustedData.GHOSTDAGData = append(blockWithTrustedData.GHOSTDAGData, appmessage.GHOSTDAGHashPairToDomainGHOSTDAGHashPair(data.GHOSTDAGData[index]))
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := consensus.ValidateAndInsertBlockWithTrustedData(blockWithTrustedData, false)
|
err := consensus.ValidateAndInsertBlockWithTrustedData(blockWithTrustedData, false)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,32 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// HandleGetMempoolEntries handles the respectively named RPC command
|
// HandleGetMempoolEntries handles the respectively named RPC command
|
||||||
func HandleGetMempoolEntries(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
func HandleGetMempoolEntries(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||||
|
getMempoolEntriesRequest := request.(*appmessage.GetMempoolEntriesRequestMessage)
|
||||||
|
|
||||||
|
entries := make([]*appmessage.MempoolEntry, 0)
|
||||||
|
|
||||||
|
if !getMempoolEntriesRequest.FilterTransactionPool {
|
||||||
|
transactionPoolEntries, err := getTransactionPoolMempoolEntries(context)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entries = append(entries, transactionPoolEntries...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if getMempoolEntriesRequest.IncludeOrphanPool {
|
||||||
|
orphanPoolEntries, err := getOrphanPoolMempoolEntries(context)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entries = append(entries, orphanPoolEntries...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return appmessage.NewGetMempoolEntriesResponseMessage(entries), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTransactionPoolMempoolEntries(context *rpccontext.Context) ([]*appmessage.MempoolEntry, error) {
|
||||||
transactions := context.Domain.MiningManager().AllTransactions()
|
transactions := context.Domain.MiningManager().AllTransactions()
|
||||||
entries := make([]*appmessage.MempoolEntry, 0, len(transactions))
|
entries := make([]*appmessage.MempoolEntry, 0, len(transactions))
|
||||||
for _, transaction := range transactions {
|
for _, transaction := range transactions {
|
||||||
@ -19,8 +44,26 @@ func HandleGetMempoolEntries(context *rpccontext.Context, _ *router.Router, _ ap
|
|||||||
entries = append(entries, &appmessage.MempoolEntry{
|
entries = append(entries, &appmessage.MempoolEntry{
|
||||||
Fee: transaction.Fee,
|
Fee: transaction.Fee,
|
||||||
Transaction: rpcTransaction,
|
Transaction: rpcTransaction,
|
||||||
|
IsOrphan: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
return entries, nil
|
||||||
return appmessage.NewGetMempoolEntriesResponseMessage(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,8 +1,12 @@
|
|||||||
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/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"
|
||||||
@ -12,17 +16,62 @@ import (
|
|||||||
// HandleGetMempoolEntriesByAddresses handles the respectively named RPC command
|
// HandleGetMempoolEntriesByAddresses handles the respectively named RPC command
|
||||||
func HandleGetMempoolEntriesByAddresses(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
func HandleGetMempoolEntriesByAddresses(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||||
|
|
||||||
transactions := context.Domain.MiningManager().AllTransactions()
|
|
||||||
getMempoolEntriesByAddressesRequest := request.(*appmessage.GetMempoolEntriesByAddressesRequestMessage)
|
getMempoolEntriesByAddressesRequest := request.(*appmessage.GetMempoolEntriesByAddressesRequestMessage)
|
||||||
|
|
||||||
mempoolEntriesByAddresses := make([]*appmessage.MempoolEntryByAddress, 0)
|
mempoolEntriesByAddresses := make([]*appmessage.MempoolEntryByAddress, 0)
|
||||||
|
|
||||||
for _, addressString := range getMempoolEntriesByAddressesRequest.Addresses {
|
if !getMempoolEntriesByAddressesRequest.FilterTransactionPool {
|
||||||
|
transactionPoolTransactions := context.Domain.MiningManager().AllTransactions()
|
||||||
|
transactionPoolEntriesByAddresses, err := extractMempoolEntriesByAddressesFromTransactions(
|
||||||
|
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 {
|
||||||
|
|
||||||
|
orphanPoolTransactions := context.Domain.MiningManager().AllOrphanTransactions()
|
||||||
|
orphanPoolEntriesByAddresse, err := extractMempoolEntriesByAddressesFromTransactions(
|
||||||
|
context,
|
||||||
|
getMempoolEntriesByAddressesRequest.Addresses,
|
||||||
|
orphanPoolTransactions,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
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, orphanPoolEntriesByAddresse...)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
_, err := util.DecodeAddress(addressString, context.Config.ActiveNetParams.Prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{}
|
return nil, appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err)
|
||||||
errorMessage.Error = appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err)
|
|
||||||
return errorMessage, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sending := make([]*appmessage.MempoolEntry, 0)
|
sending := make([]*appmessage.MempoolEntry, 0)
|
||||||
@ -50,6 +99,7 @@ func HandleGetMempoolEntriesByAddresses(context *rpccontext.Context, _ *router.R
|
|||||||
&appmessage.MempoolEntry{
|
&appmessage.MempoolEntry{
|
||||||
Fee: transaction.Fee,
|
Fee: transaction.Fee,
|
||||||
Transaction: rpcTransaction,
|
Transaction: rpcTransaction,
|
||||||
|
IsOrphan: areOrphans,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
break //one input is enough
|
break //one input is enough
|
||||||
@ -71,6 +121,7 @@ func HandleGetMempoolEntriesByAddresses(context *rpccontext.Context, _ *router.R
|
|||||||
&appmessage.MempoolEntry{
|
&appmessage.MempoolEntry{
|
||||||
Fee: transaction.Fee,
|
Fee: transaction.Fee,
|
||||||
Transaction: rpcTransaction,
|
Transaction: rpcTransaction,
|
||||||
|
IsOrphan: areOrphans,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
break //one output is enough
|
break //one output is enough
|
||||||
@ -89,9 +140,8 @@ func HandleGetMempoolEntriesByAddresses(context *rpccontext.Context, _ *router.R
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return appmessage.NewGetMempoolEntriesByAddressesResponseMessage(mempoolEntriesByAddresses), nil
|
}
|
||||||
|
return mempoolEntriesByAddresses, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,12 +3,18 @@ package rpchandlers
|
|||||||
import (
|
import (
|
||||||
"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/transactionid"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleGetMempoolEntry handles the respectively named RPC command
|
// HandleGetMempoolEntry handles the respectively named RPC command
|
||||||
func HandleGetMempoolEntry(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
func HandleGetMempoolEntry(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||||
|
|
||||||
|
transaction := &externalapi.DomainTransaction{}
|
||||||
|
var found bool
|
||||||
|
var isOrphan bool
|
||||||
|
|
||||||
getMempoolEntryRequest := request.(*appmessage.GetMempoolEntryRequestMessage)
|
getMempoolEntryRequest := request.(*appmessage.GetMempoolEntryRequestMessage)
|
||||||
|
|
||||||
transactionID, err := transactionid.FromString(getMempoolEntryRequest.TxID)
|
transactionID, err := transactionid.FromString(getMempoolEntryRequest.TxID)
|
||||||
@ -18,17 +24,25 @@ func HandleGetMempoolEntry(context *rpccontext.Context, _ *router.Router, reques
|
|||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction, ok := context.Domain.MiningManager().GetTransaction(transactionID)
|
if !getMempoolEntryRequest.FilterTransactionPool {
|
||||||
if !ok {
|
transaction, found = context.Domain.MiningManager().GetTransaction(transactionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if getMempoolEntryRequest.IncludeOrphanPool && !found {
|
||||||
|
transaction, found = context.Domain.MiningManager().GetOrphanTransaction(transactionID)
|
||||||
|
isOrphan = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
errorMessage := &appmessage.GetMempoolEntryResponseMessage{}
|
errorMessage := &appmessage.GetMempoolEntryResponseMessage{}
|
||||||
errorMessage.Error = appmessage.RPCErrorf("Transaction %s was not found", transactionID)
|
errorMessage.Error = appmessage.RPCErrorf("Transaction %s was not found", transactionID)
|
||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
||||||
err = context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
err = context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return appmessage.NewGetMempoolEntryResponseMessage(transaction.Fee, rpcTransaction, isOrphan), nil
|
||||||
return appmessage.NewGetMempoolEntryResponseMessage(transaction.Fee, rpcTransaction), nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,23 @@
|
|||||||
|
Kaspad v0.12.2 - 2022-06-17
|
||||||
|
===========================
|
||||||
|
|
||||||
|
* Clarify wallet message concerning a wallet daemon sync state (#2045)
|
||||||
|
* Change the way the miner executable reports execution errors (closes issue #1677) (#2048)
|
||||||
|
* Fix kaspawallet help messages, clarify sweep command help string (#2067)
|
||||||
|
* Wallet parse/send/create commands improvement (#2024)
|
||||||
|
* Use chunks for `GetBlocksAcceptanceData` calls in order to avoid blocking consensus for too long (#2075)
|
||||||
|
* Unite multiple `GetBlockAcceptanceData` consensus calls to one (#2074)
|
||||||
|
* Update many-small-chains-and-one-big-chain DAG to not fail merge depth limit (#2072)
|
||||||
|
|
||||||
|
RPC API Changes:
|
||||||
|
* RPC: include orphans into mempool entries (#2046)
|
||||||
|
* RPC & UtxoIndex: keep track of, query and test circulating supply. (#2070)
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
* Fix RPC connections counting (#2026)
|
||||||
|
* Fix UTXO diff child error (#2084)
|
||||||
|
* Fix `not in selected chain` crash (#2082)
|
||||||
|
|
||||||
Kaspad v0.12.1 - 2022-05-31
|
Kaspad v0.12.1 - 2022-05-31
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
|||||||
@ -23,8 +23,7 @@ func main() {
|
|||||||
|
|
||||||
cfg, err := parseConfig()
|
cfg, err := parseConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error parsing command-line arguments: %s\n", err)
|
printErrorAndExit(errors.Errorf("Error parsing command-line arguments: %s", err))
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
defer backendLog.Close()
|
defer backendLog.Close()
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ func main() {
|
|||||||
|
|
||||||
miningAddr, err := util.DecodeAddress(cfg.MiningAddr, cfg.ActiveNetParams.Prefix)
|
miningAddr, err := util.DecodeAddress(cfg.MiningAddr, cfg.ActiveNetParams.Prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(errors.Wrap(err, "error decoding mining address"))
|
printErrorAndExit(errors.Errorf("Error decoding mining address: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
doneChan := make(chan struct{})
|
doneChan := make(chan struct{})
|
||||||
@ -61,3 +60,8 @@ func main() {
|
|||||||
case <-interrupt:
|
case <-interrupt:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printErrorAndExit(err error) {
|
||||||
|
fmt.Fprintf(os.Stderr, "%+v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|||||||
@ -39,10 +39,10 @@ func (s *server) ShowAddresses(_ context.Context, request *pb.ShowAddressesReque
|
|||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
if !s.isSynced() {
|
if !s.isSynced() {
|
||||||
return nil, errors.New("server is not synced")
|
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
|
||||||
}
|
}
|
||||||
|
|
||||||
addresses := make([]string, 0)
|
addresses := make([]string, s.keysFile.LastUsedExternalIndex())
|
||||||
for i := uint32(1); i <= s.keysFile.LastUsedExternalIndex(); i++ {
|
for i := uint32(1); i <= s.keysFile.LastUsedExternalIndex(); i++ {
|
||||||
walletAddr := &walletAddress{
|
walletAddr := &walletAddress{
|
||||||
index: i,
|
index: i,
|
||||||
@ -54,7 +54,7 @@ func (s *server) ShowAddresses(_ context.Context, request *pb.ShowAddressesReque
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
addresses = append(addresses, address.String())
|
addresses[i-1] = address.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pb.ShowAddressesResponse{Address: addresses}, nil
|
return &pb.ShowAddressesResponse{Address: addresses}, nil
|
||||||
@ -65,7 +65,7 @@ func (s *server) NewAddress(_ context.Context, request *pb.NewAddressRequest) (*
|
|||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
if !s.isSynced() {
|
if !s.isSynced() {
|
||||||
return nil, errors.New("server is not synced")
|
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.keysFile.SetLastUsedExternalIndex(s.keysFile.LastUsedExternalIndex() + 1)
|
err := s.keysFile.SetLastUsedExternalIndex(s.keysFile.LastUsedExternalIndex() + 1)
|
||||||
|
|||||||
@ -30,7 +30,7 @@ func (s *server) CreateUnsignedTransactions(_ context.Context, request *pb.Creat
|
|||||||
|
|
||||||
func (s *server) createUnsignedTransactions(address string, amount uint64, fromAddressesString []string) ([][]byte, error) {
|
func (s *server) createUnsignedTransactions(address string, amount uint64, fromAddressesString []string) ([][]byte, error) {
|
||||||
if !s.isSynced() {
|
if !s.isSynced() {
|
||||||
return nil, errors.New("server is not synced")
|
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.refreshUTXOs()
|
err := s.refreshUTXOs()
|
||||||
|
|||||||
@ -31,7 +31,6 @@ func (s *server) GetExternalSpendableUTXOs(_ context.Context, request *pb.GetExt
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) selectExternalSpendableUTXOs(externalUTXOs *appmessage.GetUTXOsByAddressesResponseMessage, address string) ([]*pb.UtxosByAddressesEntry, error) {
|
func (s *server) selectExternalSpendableUTXOs(externalUTXOs *appmessage.GetUTXOsByAddressesResponseMessage, address string) ([]*pb.UtxosByAddressesEntry, error) {
|
||||||
|
|
||||||
dagInfo, err := s.rpcClient.GetBlockDAGInfo()
|
dagInfo, err := s.rpcClient.GetBlockDAGInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -101,10 +102,14 @@ func (s *server) collectFarAddresses() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) maxUsedIndex() uint32 {
|
func (s *server) maxUsedIndexWithLock() uint32 {
|
||||||
s.lock.RLock()
|
s.lock.RLock()
|
||||||
defer s.lock.RUnlock()
|
defer s.lock.RUnlock()
|
||||||
|
|
||||||
|
return s.maxUsedIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) maxUsedIndex() uint32 {
|
||||||
maxUsedIndex := s.keysFile.LastUsedExternalIndex()
|
maxUsedIndex := s.keysFile.LastUsedExternalIndex()
|
||||||
if s.keysFile.LastUsedInternalIndex() > maxUsedIndex {
|
if s.keysFile.LastUsedInternalIndex() > maxUsedIndex {
|
||||||
maxUsedIndex = s.keysFile.LastUsedInternalIndex()
|
maxUsedIndex = s.keysFile.LastUsedInternalIndex()
|
||||||
@ -122,10 +127,11 @@ func (s *server) collectRecentAddresses() error {
|
|||||||
maxUsedIndex := uint32(0)
|
maxUsedIndex := uint32(0)
|
||||||
for ; index < maxUsedIndex+numIndexesToQueryForRecentAddresses; index += numIndexesToQueryForRecentAddresses {
|
for ; index < maxUsedIndex+numIndexesToQueryForRecentAddresses; index += numIndexesToQueryForRecentAddresses {
|
||||||
err := s.collectAddressesWithLock(index, index+numIndexesToQueryForRecentAddresses)
|
err := s.collectAddressesWithLock(index, index+numIndexesToQueryForRecentAddresses)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
maxUsedIndex = s.maxUsedIndex()
|
maxUsedIndex = s.maxUsedIndexWithLock()
|
||||||
|
|
||||||
s.updateSyncingProgressLog(index, maxUsedIndex)
|
s.updateSyncingProgressLog(index, maxUsedIndex)
|
||||||
}
|
}
|
||||||
@ -261,7 +267,7 @@ func (s *server) refreshUTXOs() error {
|
|||||||
// and not in consensus, and between the calls its spending transaction will be
|
// and not in consensus, and between the calls its spending transaction will be
|
||||||
// added to consensus and removed from the mempool, so `getUTXOsByAddressesResponse`
|
// added to consensus and removed from the mempool, so `getUTXOsByAddressesResponse`
|
||||||
// will include an obsolete output.
|
// will include an obsolete output.
|
||||||
mempoolEntriesByAddresses, err := s.rpcClient.GetMempoolEntriesByAddresses(s.addressSet.strings())
|
mempoolEntriesByAddresses, err := s.rpcClient.GetMempoolEntriesByAddresses(s.addressSet.strings(), true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -275,7 +281,18 @@ func (s *server) refreshUTXOs() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) isSynced() bool {
|
func (s *server) isSynced() bool {
|
||||||
return s.nextSyncStartIndex > s.keysFile.LastUsedInternalIndex() && s.nextSyncStartIndex > s.keysFile.LastUsedExternalIndex()
|
return s.nextSyncStartIndex > s.maxUsedIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) formatSyncStateReport() string {
|
||||||
|
maxUsedIndex := s.maxUsedIndex()
|
||||||
|
|
||||||
|
if s.nextSyncStartIndex > maxUsedIndex {
|
||||||
|
maxUsedIndex = s.nextSyncStartIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("scanned %d out of %d addresses (%.2f%%)",
|
||||||
|
s.nextSyncStartIndex, maxUsedIndex, float64(s.nextSyncStartIndex)*100.0/float64(maxUsedIndex))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) updateSyncingProgressLog(currProcessedAddresses, currMaxUsedAddresses uint32) {
|
func (s *server) updateSyncingProgressLog(currProcessedAddresses, currMaxUsedAddresses uint32) {
|
||||||
|
|||||||
@ -61,17 +61,18 @@ type consensus struct {
|
|||||||
blocksWithTrustedDataDAAWindowStore model.BlocksWithTrustedDataDAAWindowStore
|
blocksWithTrustedDataDAAWindowStore model.BlocksWithTrustedDataDAAWindowStore
|
||||||
|
|
||||||
consensusEventsChan chan externalapi.ConsensusEvent
|
consensusEventsChan chan externalapi.ConsensusEvent
|
||||||
|
virtualNotUpdated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consensus) ValidateAndInsertBlockWithTrustedData(block *externalapi.BlockWithTrustedData, validateUTXO bool) (*externalapi.VirtualChangeSet, error) {
|
func (s *consensus) ValidateAndInsertBlockWithTrustedData(block *externalapi.BlockWithTrustedData, validateUTXO bool) error {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
virtualChangeSet, _, err := s.blockProcessor.ValidateAndInsertBlockWithTrustedData(block, validateUTXO)
|
_, _, err := s.blockProcessor.ValidateAndInsertBlockWithTrustedData(block, validateUTXO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
return virtualChangeSet, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes consensus
|
// Init initializes consensus
|
||||||
@ -193,21 +194,47 @@ func (s *consensus) BuildBlockTemplate(coinbaseData *externalapi.DomainCoinbaseD
|
|||||||
|
|
||||||
// ValidateAndInsertBlock validates the given block and, if valid, applies it
|
// ValidateAndInsertBlock validates the given block and, if valid, applies it
|
||||||
// to the current state
|
// to the current state
|
||||||
func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock, shouldValidateAgainstUTXO bool) (*externalapi.VirtualChangeSet, error) {
|
func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock, shouldValidateAgainstUTXO bool) error {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
virtualChangeSet, blockStatus, err := s.blockProcessor.ValidateAndInsertBlock(block, shouldValidateAgainstUTXO)
|
_, err := s.validateAndInsertBlockNoLock(block, shouldValidateAgainstUTXO)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *consensus) validateAndInsertBlockNoLock(block *externalapi.DomainBlock, updateVirtual bool) (*externalapi.VirtualChangeSet, error) {
|
||||||
|
// If virtual is in non-updated state, and the caller requests updating virtual -- then we must first
|
||||||
|
// resolve virtual so that the new block can be fully processed properly
|
||||||
|
if updateVirtual && s.virtualNotUpdated {
|
||||||
|
for s.virtualNotUpdated {
|
||||||
|
// We use 10000 << finality interval. See comment in `ResolveVirtual`.
|
||||||
|
// We give up responsiveness of consensus in this rare case.
|
||||||
|
_, err := s.resolveVirtualNoLock(10000) // Note `s.virtualNotUpdated` is updated within the call
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtualChangeSet, blockStatus, err := s.blockProcessor.ValidateAndInsertBlock(block, updateVirtual)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If block has a body, and yet virtual was not updated -- signify that virtual is in non-updated state
|
||||||
|
if !updateVirtual && blockStatus != externalapi.StatusHeaderOnly {
|
||||||
|
s.virtualNotUpdated = true
|
||||||
|
}
|
||||||
|
|
||||||
err = s.sendBlockAddedEvent(block, blockStatus)
|
err = s.sendBlockAddedEvent(block, blockStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.sendVirtualChangedEvent(virtualChangeSet, shouldValidateAgainstUTXO)
|
err = s.sendVirtualChangedEvent(virtualChangeSet, updateVirtual)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -861,7 +888,7 @@ func (s *consensus) PopulateMass(transaction *externalapi.DomainTransaction) {
|
|||||||
s.transactionValidator.PopulateMass(transaction)
|
s.transactionValidator.PopulateMass(transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consensus) ResolveVirtual() (*externalapi.VirtualChangeSet, bool, error) {
|
func (s *consensus) ResolveVirtual() (bool, error) {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
@ -869,28 +896,33 @@ func (s *consensus) ResolveVirtual() (*externalapi.VirtualChangeSet, bool, error
|
|||||||
// release the lock each time resolve 100 blocks.
|
// release the lock each time resolve 100 blocks.
|
||||||
// Note: maxBlocksToResolve should be smaller than finality interval in order to avoid a situation
|
// Note: maxBlocksToResolve should be smaller than finality interval in order to avoid a situation
|
||||||
// where UpdatePruningPointByVirtual skips a pruning point.
|
// where UpdatePruningPointByVirtual skips a pruning point.
|
||||||
virtualChangeSet, isCompletelyResolved, err := s.consensusStateManager.ResolveVirtual(100)
|
return s.resolveVirtualNoLock(100)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *consensus) resolveVirtualNoLock(maxBlocksToResolve uint64) (bool, error) {
|
||||||
|
virtualChangeSet, isCompletelyResolved, err := s.consensusStateManager.ResolveVirtual(maxBlocksToResolve)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
s.virtualNotUpdated = !isCompletelyResolved
|
||||||
|
|
||||||
stagingArea := model.NewStagingArea()
|
stagingArea := model.NewStagingArea()
|
||||||
err = s.pruningManager.UpdatePruningPointByVirtual(stagingArea)
|
err = s.pruningManager.UpdatePruningPointByVirtual(stagingArea)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = staging.CommitAllChanges(s.databaseContext, stagingArea)
|
err = staging.CommitAllChanges(s.databaseContext, stagingArea)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.sendVirtualChangedEvent(virtualChangeSet, true)
|
err = s.sendVirtualChangedEvent(virtualChangeSet, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return virtualChangeSet, isCompletelyResolved, nil
|
return isCompletelyResolved, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consensus) BuildPruningPointProof() (*externalapi.PruningPointProof, error) {
|
func (s *consensus) BuildPruningPointProof() (*externalapi.PruningPointProof, error) {
|
||||||
|
|||||||
@ -27,7 +27,7 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
|
|||||||
newHeader := invalidBlock.Header.ToMutable()
|
newHeader := invalidBlock.Header.ToMutable()
|
||||||
newHeader.SetTimeInMilliseconds(0)
|
newHeader.SetTimeInMilliseconds(0)
|
||||||
invalidBlock.Header = newHeader.ToImmutable()
|
invalidBlock.Header = newHeader.ToImmutable()
|
||||||
_, err = consensus.ValidateAndInsertBlock(invalidBlock, true)
|
err = consensus.ValidateAndInsertBlock(invalidBlock, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrTimeTooOld) {
|
if !errors.Is(err, ruleerrors.ErrTimeTooOld) {
|
||||||
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrTimeTooOld, err)
|
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrTimeTooOld, err)
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
|
|||||||
t.Fatalf("consensus.BuildBlock with an empty coinbase shouldn't fail: %v", err)
|
t.Fatalf("consensus.BuildBlock with an empty coinbase shouldn't fail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = consensus.ValidateAndInsertBlock(validBlock, true)
|
err = consensus.ValidateAndInsertBlock(validBlock, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("consensus.ValidateAndInsertBlock with a block straight from consensus.BuildBlock should not fail: %v", err)
|
t.Fatalf("consensus.ValidateAndInsertBlock with a block straight from consensus.BuildBlock should not fail: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ func TestFinality(t *testing.T) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = consensus.ValidateAndInsertBlock(block, true)
|
err = consensus.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -201,7 +201,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
|||||||
return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns
|
return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = consensus.ValidateAndInsertBlock(block, true)
|
err = consensus.ValidateAndInsertBlock(block, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return block, false
|
return block, false
|
||||||
} else if errors.Is(err, ruleerrors.ErrViolatingBoundedMergeDepth) {
|
} else if errors.Is(err, ruleerrors.ErrViolatingBoundedMergeDepth) {
|
||||||
@ -213,7 +213,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
processBlock := func(consensus testapi.TestConsensus, block *externalapi.DomainBlock, name string) {
|
processBlock := func(consensus testapi.TestConsensus, block *externalapi.DomainBlock, name string) {
|
||||||
_, err := consensus.ValidateAndInsertBlock(block, true)
|
err := consensus.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("TestBoundedMergeDepth: %s got unexpected error from ProcessBlock: %+v", name, err)
|
t.Fatalf("TestBoundedMergeDepth: %s got unexpected error from ProcessBlock: %+v", name, err)
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("TestBoundedMergeDepth: Failed building block: %+v", err)
|
t.Fatalf("TestBoundedMergeDepth: Failed building block: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = consensus.ValidateAndInsertBlock(block, true)
|
err = consensus.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("TestBoundedMergeDepth: Failed Inserting block to consensus: %v", err)
|
t.Fatalf("TestBoundedMergeDepth: Failed Inserting block to consensus: %v", err)
|
||||||
}
|
}
|
||||||
@ -268,7 +268,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
|||||||
t.Fatalf("GetBlockHeader: %+v", err)
|
t.Fatalf("GetBlockHeader: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tcSyncee.ValidateAndInsertBlock(block, true)
|
err = tcSyncee.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock %d: %+v", i, err)
|
t.Fatalf("ValidateAndInsertBlock %d: %+v", i, err)
|
||||||
}
|
}
|
||||||
@ -556,7 +556,7 @@ func TestFinalityResolveVirtual(t *testing.T) {
|
|||||||
block.Header = mutableHeader.ToImmutable()
|
block.Header = mutableHeader.ToImmutable()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tcAttacker.ValidateAndInsertBlock(block, true)
|
err = tcAttacker.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -583,14 +583,14 @@ func TestFinalityResolveVirtual(t *testing.T) {
|
|||||||
t.Logf("Side chain tip (%s) blue score %d", sideChainTipHash, sideChainTipGHOSTDAGData.BlueScore())
|
t.Logf("Side chain tip (%s) blue score %d", sideChainTipHash, sideChainTipGHOSTDAGData.BlueScore())
|
||||||
|
|
||||||
for _, block := range sideChain {
|
for _, block := range sideChain {
|
||||||
_, err := tc.ValidateAndInsertBlock(block, false)
|
err := tc.ValidateAndInsertBlock(block, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
_, isCompletelyResolved, err := tc.ResolveVirtual()
|
isCompletelyResolved, err := tc.ResolveVirtual()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,8 @@ type Consensus interface {
|
|||||||
Init(skipAddingGenesis bool) error
|
Init(skipAddingGenesis bool) error
|
||||||
BuildBlock(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlock, error)
|
BuildBlock(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlock, error)
|
||||||
BuildBlockTemplate(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlockTemplate, error)
|
BuildBlockTemplate(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlockTemplate, error)
|
||||||
ValidateAndInsertBlock(block *DomainBlock, shouldValidateAgainstUTXO bool) (*VirtualChangeSet, error)
|
ValidateAndInsertBlock(block *DomainBlock, shouldValidateAgainstUTXO bool) error
|
||||||
ValidateAndInsertBlockWithTrustedData(block *BlockWithTrustedData, validateUTXO bool) (*VirtualChangeSet, error)
|
ValidateAndInsertBlockWithTrustedData(block *BlockWithTrustedData, validateUTXO bool) error
|
||||||
ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error
|
ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error
|
||||||
ImportPruningPoints(pruningPoints []BlockHeader) error
|
ImportPruningPoints(pruningPoints []BlockHeader) error
|
||||||
BuildPruningPointProof() (*PruningPointProof, error)
|
BuildPruningPointProof() (*PruningPointProof, error)
|
||||||
@ -48,7 +48,7 @@ type Consensus interface {
|
|||||||
Anticone(blockHash *DomainHash) ([]*DomainHash, error)
|
Anticone(blockHash *DomainHash) ([]*DomainHash, error)
|
||||||
EstimateNetworkHashesPerSecond(startHash *DomainHash, windowSize int) (uint64, error)
|
EstimateNetworkHashesPerSecond(startHash *DomainHash, windowSize int) (uint64, error)
|
||||||
PopulateMass(transaction *DomainTransaction)
|
PopulateMass(transaction *DomainTransaction)
|
||||||
ResolveVirtual() (*VirtualChangeSet, bool, error)
|
ResolveVirtual() (bool, error)
|
||||||
BlockDAAWindowHashes(blockHash *DomainHash) ([]*DomainHash, error)
|
BlockDAAWindowHashes(blockHash *DomainHash) ([]*DomainHash, error)
|
||||||
TrustedDataDataDAAHeader(trustedBlockHash, daaBlockHash *DomainHash, daaBlockWindowIndex uint64) (*TrustedDataDataDAAHeader, error)
|
TrustedDataDataDAAHeader(trustedBlockHash, daaBlockHash *DomainHash, daaBlockWindowIndex uint64) (*TrustedDataDataDAAHeader, error)
|
||||||
TrustedBlockAssociatedGHOSTDAGDataBlockHashes(blockHash *DomainHash) ([]*DomainHash, error)
|
TrustedBlockAssociatedGHOSTDAGDataBlockHashes(blockHash *DomainHash) ([]*DomainHash, error)
|
||||||
|
|||||||
@ -47,6 +47,9 @@ type TestConsensus interface {
|
|||||||
|
|
||||||
AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
|
AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
|
||||||
*externalapi.VirtualChangeSet, error)
|
*externalapi.VirtualChangeSet, error)
|
||||||
|
UpdatePruningPointByVirtual() error
|
||||||
|
|
||||||
|
ResolveVirtualWithMaxParam(maxBlocksToResolve uint64) (bool, error)
|
||||||
|
|
||||||
MineJSON(r io.Reader, blockType MineJSONBlockType) (tips []*externalapi.DomainHash, err error)
|
MineJSON(r io.Reader, blockType MineJSONBlockType) (tips []*externalapi.DomainHash, err error)
|
||||||
ToJSON(w io.Writer) error
|
ToJSON(w io.Writer) error
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/multiset"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/multiset"
|
||||||
@ -165,12 +164,7 @@ func (bp *blockProcessor) validateAndInsertBlock(stagingArea *model.StagingArea,
|
|||||||
|
|
||||||
if reversalData != nil {
|
if reversalData != nil {
|
||||||
err = bp.consensusStateManager.ReverseUTXODiffs(blockHash, reversalData)
|
err = bp.consensusStateManager.ReverseUTXODiffs(blockHash, reversalData)
|
||||||
// It's still not known what causes this error, but we can ignore it and not reverse the UTXO diffs
|
if err != nil {
|
||||||
// and harm performance in some cases.
|
|
||||||
// TODO: Investigate why this error happens in the first place, and remove the workaround.
|
|
||||||
if errors.Is(err, consensusstatemanager.ErrReverseUTXODiffsUTXODiffChildNotFound) {
|
|
||||||
log.Errorf("Could not reverse UTXO diffs while resolving virtual: %s", err)
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, externalapi.StatusInvalid, err
|
return nil, externalapi.StatusInvalid, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,7 +79,7 @@ func TestBlockStatus(t *testing.T) {
|
|||||||
disqualifiedBlock.Header.PruningPoint(),
|
disqualifiedBlock.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(disqualifiedBlock, true)
|
err = tc.ValidateAndInsertBlock(disqualifiedBlock, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ func TestBlockStatus(t *testing.T) {
|
|||||||
disqualifiedBlock.Header.PruningPoint(),
|
disqualifiedBlock.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(invalidBlock, true)
|
err = tc.ValidateAndInsertBlock(invalidBlock, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("block is expected to be invalid")
|
t.Fatalf("block is expected to be invalid")
|
||||||
}
|
}
|
||||||
@ -139,11 +139,11 @@ func TestValidateAndInsertErrors(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("AddBlock: %+v", err)
|
t.Fatalf("AddBlock: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = tc.ValidateAndInsertBlock(blockWithStatusInvalid, true)
|
err = tc.ValidateAndInsertBlock(blockWithStatusInvalid, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Test ValidateAndInsertBlock: Expected an error, because the block is invalid.")
|
t.Fatalf("Test ValidateAndInsertBlock: Expected an error, because the block is invalid.")
|
||||||
}
|
}
|
||||||
_, err = tc.ValidateAndInsertBlock(blockWithStatusInvalid, true)
|
err = tc.ValidateAndInsertBlock(blockWithStatusInvalid, true)
|
||||||
if err == nil || !errors.Is(err, ruleerrors.ErrKnownInvalid) {
|
if err == nil || !errors.Is(err, ruleerrors.ErrKnownInvalid) {
|
||||||
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrKnownInvalid, err)
|
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrKnownInvalid, err)
|
||||||
}
|
}
|
||||||
@ -155,12 +155,12 @@ func TestValidateAndInsertErrors(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("AddBlock: %+v", err)
|
t.Fatalf("AddBlock: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
// resend the same block.
|
// resend the same block.
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err == nil || !errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
if err == nil || !errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
||||||
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrDuplicateBlock, err)
|
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrDuplicateBlock, err)
|
||||||
}
|
}
|
||||||
@ -173,12 +173,12 @@ func TestValidateAndInsertErrors(t *testing.T) {
|
|||||||
t.Fatalf("AddBlock: %+v", err)
|
t.Fatalf("AddBlock: %+v", err)
|
||||||
}
|
}
|
||||||
onlyHeader.Transactions = []*externalapi.DomainTransaction{}
|
onlyHeader.Transactions = []*externalapi.DomainTransaction{}
|
||||||
_, err = tc.ValidateAndInsertBlock(onlyHeader, true)
|
err = tc.ValidateAndInsertBlock(onlyHeader, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("AddBlock: %+v", err)
|
t.Fatalf("AddBlock: %+v", err)
|
||||||
}
|
}
|
||||||
// resend the same header.
|
// resend the same header.
|
||||||
_, err = tc.ValidateAndInsertBlock(onlyHeader, true)
|
err = tc.ValidateAndInsertBlock(onlyHeader, true)
|
||||||
if err == nil || !errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
if err == nil || !errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
||||||
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrDuplicateBlock, err)
|
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrDuplicateBlock, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ func addBlock(tc testapi.TestConsensus, parentHashes []*externalapi.DomainHash,
|
|||||||
}
|
}
|
||||||
|
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
consensusConfig.K = 0
|
consensusConfig.K = 0
|
||||||
consensusConfig.PruningProofM = 1
|
consensusConfig.PruningProofM = 1
|
||||||
|
|
||||||
syncConsensuses := func(tcSyncerRef, tcSynceeRef *testapi.TestConsensus) {
|
syncConsensuses := func(tcSyncerRef, tcSynceeRef *testapi.TestConsensus, updatePruningPointJustAfterImportingPruningPoint bool) {
|
||||||
tcSyncer, tcSyncee := *tcSyncerRef, *tcSynceeRef
|
tcSyncer, tcSyncee := *tcSyncerRef, *tcSynceeRef
|
||||||
pruningPointProof, err := tcSyncer.BuildPruningPointProof()
|
pruningPointProof, err := tcSyncer.BuildPruningPointProof()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -133,7 +133,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = synceeStaging.ValidateAndInsertBlockWithTrustedData(blockWithTrustedData, false)
|
err = synceeStaging.ValidateAndInsertBlockWithTrustedData(blockWithTrustedData, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlockWithTrustedData: %+v", err)
|
t.Fatalf("ValidateAndInsertBlockWithTrustedData: %+v", err)
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
t.Fatalf("GetBlockHeader: %+v", err)
|
t.Fatalf("GetBlockHeader: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = synceeStaging.ValidateAndInsertBlock(&externalapi.DomainBlock{Header: header}, false)
|
err = synceeStaging.ValidateAndInsertBlock(&externalapi.DomainBlock{Header: header}, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock %d: %+v", i, err)
|
t.Fatalf("ValidateAndInsertBlock %d: %+v", i, err)
|
||||||
}
|
}
|
||||||
@ -236,6 +236,13 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
t.Fatalf("ValidateAndInsertImportedPruningPoint: %+v", err)
|
t.Fatalf("ValidateAndInsertImportedPruningPoint: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if updatePruningPointJustAfterImportingPruningPoint {
|
||||||
|
err = synceeStaging.UpdatePruningPointByVirtual()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emptyCoinbase := &externalapi.DomainCoinbaseData{
|
emptyCoinbase := &externalapi.DomainCoinbaseData{
|
||||||
ScriptPublicKey: &externalapi.ScriptPublicKey{
|
ScriptPublicKey: &externalapi.ScriptPublicKey{
|
||||||
Script: nil,
|
Script: nil,
|
||||||
@ -266,7 +273,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
t.Fatalf("GetBlock: %+v", err)
|
t.Fatalf("GetBlock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = synceeStaging.ValidateAndInsertBlock(block, true)
|
err = synceeStaging.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
@ -292,7 +299,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
t.Fatalf("GetBlock: %+v", err)
|
t.Fatalf("GetBlock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = synceeStaging.ValidateAndInsertBlock(tip, true)
|
err = synceeStaging.ValidateAndInsertBlock(tip, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
@ -339,7 +346,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
t.Fatalf("GetBlock: %+v", err)
|
t.Fatalf("GetBlock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tcSyncee1.ValidateAndInsertBlock(block, true)
|
err = tcSyncee1.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
@ -386,7 +393,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tcSyncee1Ref := &tcSyncee1
|
tcSyncee1Ref := &tcSyncee1
|
||||||
syncConsensuses(&tcSyncer, tcSyncee1Ref)
|
syncConsensuses(&tcSyncer, tcSyncee1Ref, false)
|
||||||
|
|
||||||
// Test a situation where a consensus with pruned headers syncs another fresh consensus.
|
// Test a situation where a consensus with pruned headers syncs another fresh consensus.
|
||||||
tcSyncee2, teardownSyncee2, err := factory.NewTestConsensus(consensusConfig, "TestValidateAndInsertPruningPointSyncee2")
|
tcSyncee2, teardownSyncee2, err := factory.NewTestConsensus(consensusConfig, "TestValidateAndInsertPruningPointSyncee2")
|
||||||
@ -395,7 +402,17 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer teardownSyncee2(false)
|
defer teardownSyncee2(false)
|
||||||
|
|
||||||
syncConsensuses(tcSyncee1Ref, &tcSyncee2)
|
syncConsensuses(tcSyncee1Ref, &tcSyncee2, false)
|
||||||
|
|
||||||
|
// Check the regular sync but try to update the pruning point after the pruning point was imported. It tests a situation where the node
|
||||||
|
// was restarted before the virtual was resolved and then it calls UpdatePruningPointByVirtual on init.
|
||||||
|
tcSyncee3, teardownSyncee3, err := factory.NewTestConsensus(consensusConfig, "TestValidateAndInsertPruningPointSyncee3")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up tcSyncee1: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardownSyncee3(false)
|
||||||
|
|
||||||
|
syncConsensuses(&tcSyncer, &tcSyncee3, true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,7 +478,7 @@ func TestGetPruningPointUTXOs(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error building block above genesis: %+v", err)
|
t.Fatalf("Error building block above genesis: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(blockAboveGenesis, true)
|
err = testConsensus.ValidateAndInsertBlock(blockAboveGenesis, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error validating and inserting block above genesis: %+v", err)
|
t.Fatalf("Error validating and inserting block above genesis: %+v", err)
|
||||||
}
|
}
|
||||||
@ -473,7 +490,7 @@ func TestGetPruningPointUTXOs(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error building block with spendable coinbase: %+v", err)
|
t.Fatalf("Error building block with spendable coinbase: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(blockWithSpendableCoinbase, true)
|
err = testConsensus.ValidateAndInsertBlock(blockWithSpendableCoinbase, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error validating and inserting block with spendable coinbase: %+v", err)
|
t.Fatalf("Error validating and inserting block with spendable coinbase: %+v", err)
|
||||||
}
|
}
|
||||||
@ -512,7 +529,7 @@ func TestGetPruningPointUTXOs(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error building including block: %+v", err)
|
t.Fatalf("Error building including block: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(includingBlock, true)
|
err = testConsensus.ValidateAndInsertBlock(includingBlock, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error validating and inserting including block: %+v", err)
|
t.Fatalf("Error validating and inserting including block: %+v", err)
|
||||||
}
|
}
|
||||||
@ -523,7 +540,7 @@ func TestGetPruningPointUTXOs(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error building block: %+v", err)
|
t.Fatalf("Error building block: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(block, true)
|
err = testConsensus.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error validating and inserting block: %+v", err)
|
t.Fatalf("Error validating and inserting block: %+v", err)
|
||||||
}
|
}
|
||||||
@ -619,7 +636,7 @@ func BenchmarkGetPruningPointUTXOs(b *testing.B) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Error building block with spendable coinbase: %+v", err)
|
b.Fatalf("Error building block with spendable coinbase: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(blockWithSpendableCoinbase, true)
|
err = testConsensus.ValidateAndInsertBlock(blockWithSpendableCoinbase, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Error validating and inserting block with spendable coinbase: %+v", err)
|
b.Fatalf("Error validating and inserting block with spendable coinbase: %+v", err)
|
||||||
}
|
}
|
||||||
@ -657,7 +674,7 @@ func BenchmarkGetPruningPointUTXOs(b *testing.B) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Error building block: %+v", err)
|
b.Fatalf("Error building block: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(block, true)
|
err = testConsensus.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Error validating and inserting block: %+v", err)
|
b.Fatalf("Error validating and inserting block: %+v", err)
|
||||||
}
|
}
|
||||||
@ -677,7 +694,7 @@ func BenchmarkGetPruningPointUTXOs(b *testing.B) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Error building block: %+v", err)
|
b.Fatalf("Error building block: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(block, true)
|
err = testConsensus.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Error validating and inserting block: %+v", err)
|
b.Fatalf("Error validating and inserting block: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,7 +62,7 @@ func TestCheckBlockIsNotPruned(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(beforePruningBlock, true)
|
err = tc.ValidateAndInsertBlock(beforePruningBlock, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrPrunedBlock) {
|
if !errors.Is(err, ruleerrors.ErrPrunedBlock) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ func TestCheckParentBlockBodiesExist(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add only the header of anticonePruningBlock
|
// Add only the header of anticonePruningBlock
|
||||||
_, err = tc.ValidateAndInsertBlock(&externalapi.DomainBlock{
|
err = tc.ValidateAndInsertBlock(&externalapi.DomainBlock{
|
||||||
Header: anticonePruningBlock.Header,
|
Header: anticonePruningBlock.Header,
|
||||||
Transactions: nil,
|
Transactions: nil,
|
||||||
}, true)
|
}, true)
|
||||||
@ -143,7 +143,7 @@ func TestCheckParentBlockBodiesExist(t *testing.T) {
|
|||||||
|
|
||||||
// Add anticonePruningBlock's body and check that it's valid to point to
|
// Add anticonePruningBlock's body and check that it's valid to point to
|
||||||
// a header only block in the past of the pruning point.
|
// a header only block in the past of the pruning point.
|
||||||
_, err = tc.ValidateAndInsertBlock(anticonePruningBlock, true)
|
err = tc.ValidateAndInsertBlock(anticonePruningBlock, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
@ -189,7 +189,7 @@ func TestIsFinalizedTransaction(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error getting block: %+v", err)
|
t.Fatalf("Error getting block: %+v", err)
|
||||||
}
|
}
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error Inserting block: %+v", err)
|
t.Fatalf("Error Inserting block: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1052,14 +1052,14 @@ func CheckBlockHashMerkleRoot(t *testing.T, tc testapi.TestConsensus, consensusC
|
|||||||
blockWithInvalidMerkleRoot := block.Clone()
|
blockWithInvalidMerkleRoot := block.Clone()
|
||||||
blockWithInvalidMerkleRoot.Transactions[0].Version += 1
|
blockWithInvalidMerkleRoot.Transactions[0].Version += 1
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(blockWithInvalidMerkleRoot, true)
|
err = tc.ValidateAndInsertBlock(blockWithInvalidMerkleRoot, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrBadMerkleRoot) {
|
if !errors.Is(err, ruleerrors.ErrBadMerkleRoot) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that a block with invalid merkle root is not marked as invalid
|
// Check that a block with invalid merkle root is not marked as invalid
|
||||||
// and can be re-added with the right transactions.
|
// and can be re-added with the right transactions.
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ func TestValidateMedianTime(t *testing.T) {
|
|||||||
newHeader := block.Header.ToMutable()
|
newHeader := block.Header.ToMutable()
|
||||||
newHeader.SetTimeInMilliseconds(blockTime)
|
newHeader.SetTimeInMilliseconds(blockTime)
|
||||||
block.Header = newHeader.ToImmutable()
|
block.Header = newHeader.ToImmutable()
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if !errors.Is(err, expectedErr) {
|
if !errors.Is(err, expectedErr) {
|
||||||
t.Fatalf("expected error %s but got %+v", expectedErr, err)
|
t.Fatalf("expected error %s but got %+v", expectedErr, err)
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ func TestCheckParentsIncest(t *testing.T) {
|
|||||||
Transactions: nil,
|
Transactions: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(directParentsRelationBlock, true)
|
err = tc.ValidateAndInsertBlock(directParentsRelationBlock, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrInvalidParentsRelation) {
|
if !errors.Is(err, ruleerrors.ErrInvalidParentsRelation) {
|
||||||
t.Fatalf("unexpected error %+v", err)
|
t.Fatalf("unexpected error %+v", err)
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ func TestCheckParentsIncest(t *testing.T) {
|
|||||||
Transactions: nil,
|
Transactions: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(indirectParentsRelationBlock, true)
|
err = tc.ValidateAndInsertBlock(indirectParentsRelationBlock, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrInvalidParentsRelation) {
|
if !errors.Is(err, ruleerrors.ErrInvalidParentsRelation) {
|
||||||
t.Fatalf("unexpected error %+v", err)
|
t.Fatalf("unexpected error %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,7 +78,7 @@ func CheckBlockVersion(t *testing.T, tc testapi.TestConsensus, consensusConfig *
|
|||||||
block.Header.PruningPoint(),
|
block.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrWrongBlockVersion) {
|
if !errors.Is(err, ruleerrors.ErrWrongBlockVersion) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ func CheckBlockTimestampInIsolation(t *testing.T, tc testapi.TestConsensus, cfg
|
|||||||
block.Header.PruningPoint(),
|
block.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrTimeTooMuchInTheFuture) {
|
if !errors.Is(err, ruleerrors.ErrTimeTooMuchInTheFuture) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,7 +39,7 @@ func TestPOW(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
invalidBlockWrongPOW = solveBlockWithWrongPOW(invalidBlockWrongPOW)
|
invalidBlockWrongPOW = solveBlockWithWrongPOW(invalidBlockWrongPOW)
|
||||||
_, err = tc.ValidateAndInsertBlock(invalidBlockWrongPOW, true)
|
err = tc.ValidateAndInsertBlock(invalidBlockWrongPOW, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrInvalidPoW) {
|
if !errors.Is(err, ruleerrors.ErrInvalidPoW) {
|
||||||
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrInvalidPoW, err)
|
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrInvalidPoW, err)
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ func TestPOW(t *testing.T) {
|
|||||||
abovePowMaxBlock.Header.PruningPoint(),
|
abovePowMaxBlock.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(abovePowMaxBlock, true)
|
err = tc.ValidateAndInsertBlock(abovePowMaxBlock, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrTargetTooHigh) {
|
if !errors.Is(err, ruleerrors.ErrTargetTooHigh) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ func TestPOW(t *testing.T) {
|
|||||||
negativeTargetBlock.Header.PruningPoint(),
|
negativeTargetBlock.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(negativeTargetBlock, true)
|
err = tc.ValidateAndInsertBlock(negativeTargetBlock, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrNegativeTarget) {
|
if !errors.Is(err, ruleerrors.ErrNegativeTarget) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ func TestPOW(t *testing.T) {
|
|||||||
// Difficulty is too high on mainnet to actually mine.
|
// Difficulty is too high on mainnet to actually mine.
|
||||||
if consensusConfig.Name != "kaspa-mainnet" {
|
if consensusConfig.Name != "kaspa-mainnet" {
|
||||||
mining.SolveBlock(validBlock, random)
|
mining.SolveBlock(validBlock, random)
|
||||||
_, err = tc.ValidateAndInsertBlock(validBlock, true)
|
err = tc.ValidateAndInsertBlock(validBlock, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -161,7 +161,7 @@ func TestCheckParentHeadersExist(t *testing.T) {
|
|||||||
orphanBlock.Header.PruningPoint(),
|
orphanBlock.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(orphanBlock, true)
|
err = tc.ValidateAndInsertBlock(orphanBlock, true)
|
||||||
errMissingParents := &ruleerrors.ErrMissingParents{}
|
errMissingParents := &ruleerrors.ErrMissingParents{}
|
||||||
if !errors.As(err, errMissingParents) {
|
if !errors.As(err, errMissingParents) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
@ -193,7 +193,7 @@ func TestCheckParentHeadersExist(t *testing.T) {
|
|||||||
orphanBlock.Header.PruningPoint(),
|
orphanBlock.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(invalidBlock, true)
|
err = tc.ValidateAndInsertBlock(invalidBlock, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrTransactionVersionIsUnknown) {
|
if !errors.Is(err, ruleerrors.ErrTransactionVersionIsUnknown) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ func TestCheckParentHeadersExist(t *testing.T) {
|
|||||||
invalidBlockChild.Header.PruningPoint(),
|
invalidBlockChild.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(invalidBlockChild, true)
|
err = tc.ValidateAndInsertBlock(invalidBlockChild, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrInvalidAncestorBlock) {
|
if !errors.Is(err, ruleerrors.ErrInvalidAncestorBlock) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
@ -284,7 +284,7 @@ func TestCheckPruningPointViolation(t *testing.T) {
|
|||||||
blockWithPruningViolation.Header.PruningPoint(),
|
blockWithPruningViolation.Header.PruningPoint(),
|
||||||
)
|
)
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(blockWithPruningViolation, true)
|
err = tc.ValidateAndInsertBlock(blockWithPruningViolation, true)
|
||||||
if !errors.Is(err, ruleerrors.ErrPruningPointViolation) {
|
if !errors.Is(err, ruleerrors.ErrPruningPointViolation) {
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
"github.com/kaspanet/kaspad/util/staging"
|
"github.com/kaspanet/kaspad/util/staging"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -79,12 +78,7 @@ func (csm *consensusStateManager) ResolveVirtual(maxBlocksToResolve uint64) (*ex
|
|||||||
|
|
||||||
if reversalData != nil {
|
if reversalData != nil {
|
||||||
err = csm.ReverseUTXODiffs(resolveTip, reversalData)
|
err = csm.ReverseUTXODiffs(resolveTip, reversalData)
|
||||||
// It's still not known what causes this error, but we can ignore it and not reverse the UTXO diffs
|
if err != nil {
|
||||||
// and harm performance in some cases.
|
|
||||||
// TODO: Investigate why this error happens in the first place, and remove the workaround.
|
|
||||||
if errors.Is(err, ErrReverseUTXODiffsUTXODiffChildNotFound) {
|
|
||||||
log.Errorf("Could not reverse UTXO diffs while resolving virtual: %s", err)
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,214 @@
|
|||||||
|
package consensusstatemanager_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddBlockBetweenResolveVirtualCalls(t *testing.T) {
|
||||||
|
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
|
||||||
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestAddBlockBetweenResolveVirtualCalls")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up consensus: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardown(false)
|
||||||
|
|
||||||
|
// Create a chain of blocks
|
||||||
|
const initialChainLength = 10
|
||||||
|
previousBlockHash := consensusConfig.GenesisHash
|
||||||
|
for i := 0; i < initialChainLength; i++ {
|
||||||
|
previousBlockHash, _, err = tc.AddBlock([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block no. %d in initial chain: %+v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mine a chain with more blocks, to re-organize the DAG
|
||||||
|
const reorgChainLength = initialChainLength + 1
|
||||||
|
previousBlockHash = consensusConfig.GenesisHash
|
||||||
|
for i := 0; i < reorgChainLength; i++ {
|
||||||
|
previousBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block no. %d in re-org chain: %+v", i, err)
|
||||||
|
}
|
||||||
|
previousBlockHash = consensushashing.BlockHash(previousBlock)
|
||||||
|
|
||||||
|
// Do not UTXO validate in order to resolve virtual later
|
||||||
|
err = tc.ValidateAndInsertBlock(previousBlock, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block no. %d in re-org chain: %+v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve one step
|
||||||
|
_, err = tc.ResolveVirtualWithMaxParam(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyCoinbase := &externalapi.DomainCoinbaseData{
|
||||||
|
ScriptPublicKey: &externalapi.ScriptPublicKey{
|
||||||
|
Script: nil,
|
||||||
|
Version: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get template based on current resolve state
|
||||||
|
blockTemplate, err := tc.BuildBlockTemplate(emptyCoinbase, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error building block template during virtual resolution of reorg: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve one more step
|
||||||
|
isCompletelyResolved, err := tc.ResolveVirtualWithMaxParam(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the mined block (now virtual was modified)
|
||||||
|
err = tc.ValidateAndInsertBlock(blockTemplate.Block, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block during virtual resolution of reorg: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete resolving virtual
|
||||||
|
for !isCompletelyResolved {
|
||||||
|
isCompletelyResolved, err = tc.ResolveVirtualWithMaxParam(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddGenesisChildAfterOneResolveVirtualCall(t *testing.T) {
|
||||||
|
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
|
||||||
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestAddGenesisChildAfterOneResolveVirtualCall")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up consensus: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardown(false)
|
||||||
|
|
||||||
|
// Create a chain of blocks
|
||||||
|
const initialChainLength = 6
|
||||||
|
previousBlockHash := consensusConfig.GenesisHash
|
||||||
|
for i := 0; i < initialChainLength; i++ {
|
||||||
|
previousBlockHash, _, err = tc.AddBlock([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block no. %d in initial chain: %+v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mine a chain with more blocks, to re-organize the DAG
|
||||||
|
const reorgChainLength = initialChainLength + 1
|
||||||
|
previousBlockHash = consensusConfig.GenesisHash
|
||||||
|
for i := 0; i < reorgChainLength; i++ {
|
||||||
|
previousBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block no. %d in re-org chain: %+v", i, err)
|
||||||
|
}
|
||||||
|
previousBlockHash = consensushashing.BlockHash(previousBlock)
|
||||||
|
|
||||||
|
// Do not UTXO validate in order to resolve virtual later
|
||||||
|
err = tc.ValidateAndInsertBlock(previousBlock, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block no. %d in re-org chain: %+v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve one step
|
||||||
|
isCompletelyResolved, err := tc.ResolveVirtualWithMaxParam(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error adding block during virtual resolution of reorg: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete resolving virtual
|
||||||
|
for !isCompletelyResolved {
|
||||||
|
isCompletelyResolved, err = tc.ResolveVirtualWithMaxParam(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddGenesisChildAfterTwoResolveVirtualCalls(t *testing.T) {
|
||||||
|
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
|
||||||
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestAddGenesisChildAfterTwoResolveVirtualCalls")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up consensus: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardown(false)
|
||||||
|
|
||||||
|
// Create a chain of blocks
|
||||||
|
const initialChainLength = 6
|
||||||
|
previousBlockHash := consensusConfig.GenesisHash
|
||||||
|
for i := 0; i < initialChainLength; i++ {
|
||||||
|
previousBlockHash, _, err = tc.AddBlock([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block no. %d in initial chain: %+v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mine a chain with more blocks, to re-organize the DAG
|
||||||
|
const reorgChainLength = initialChainLength + 1
|
||||||
|
previousBlockHash = consensusConfig.GenesisHash
|
||||||
|
for i := 0; i < reorgChainLength; i++ {
|
||||||
|
previousBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block no. %d in re-org chain: %+v", i, err)
|
||||||
|
}
|
||||||
|
previousBlockHash = consensushashing.BlockHash(previousBlock)
|
||||||
|
|
||||||
|
// Do not UTXO validate in order to resolve virtual later
|
||||||
|
err = tc.ValidateAndInsertBlock(previousBlock, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error mining block no. %d in re-org chain: %+v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve one step
|
||||||
|
_, err = tc.ResolveVirtualWithMaxParam(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve one more step
|
||||||
|
isCompletelyResolved, err := tc.ResolveVirtualWithMaxParam(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error adding block during virtual resolution of reorg: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete resolving virtual
|
||||||
|
for !isCompletelyResolved {
|
||||||
|
isCompletelyResolved, err = tc.ResolveVirtualWithMaxParam(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -3,18 +3,10 @@ package consensusstatemanager
|
|||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
"github.com/kaspanet/kaspad/util/staging"
|
"github.com/kaspanet/kaspad/util/staging"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrReverseUTXODiffsUTXODiffChildNotFound indicates a UTXO diff child was not found while calling ReverseUTXODiffs.
|
|
||||||
// It's still not known what causes this error, but we can ignore it and not reverse the UTXO diffs
|
|
||||||
// and harm performance in some cases.
|
|
||||||
// TODO: Investigate why this error happens in the first place, and remove the workaround.
|
|
||||||
var ErrReverseUTXODiffsUTXODiffChildNotFound = errors.New("ErrReverseUTXODiffsUTXODiffChildNotFound")
|
|
||||||
|
|
||||||
func (csm *consensusStateManager) ReverseUTXODiffs(tipHash *externalapi.DomainHash,
|
func (csm *consensusStateManager) ReverseUTXODiffs(tipHash *externalapi.DomainHash,
|
||||||
reversalData *model.UTXODiffReversalData) error {
|
reversalData *model.UTXODiffReversalData) error {
|
||||||
|
|
||||||
@ -57,9 +49,6 @@ func (csm *consensusStateManager) ReverseUTXODiffs(tipHash *externalapi.DomainHa
|
|||||||
|
|
||||||
currentBlockUTXODiffChild, err := csm.utxoDiffStore.UTXODiffChild(csm.databaseContext, readStagingArea, currentBlock)
|
currentBlockUTXODiffChild, err := csm.utxoDiffStore.UTXODiffChild(csm.databaseContext, readStagingArea, currentBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if database.IsNotFoundError(err) {
|
|
||||||
return errors.Wrapf(ErrReverseUTXODiffsUTXODiffChildNotFound, "UTXO diff child was not found for block %s", currentBlock)
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
currentBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, readStagingArea, currentBlock, false)
|
currentBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, readStagingArea, currentBlock, false)
|
||||||
|
|||||||
@ -84,7 +84,7 @@ func TestConsensusStateManager_pickVirtualParents(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed building a block: %v", err)
|
t.Fatalf("Failed building a block: %v", err)
|
||||||
}
|
}
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed Inserting block to tc: %v", err)
|
t.Fatalf("Failed Inserting block to tc: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,7 @@ func TestDifficulty(t *testing.T) {
|
|||||||
newHeader := block.Header.ToMutable()
|
newHeader := block.Header.ToMutable()
|
||||||
newHeader.SetTimeInMilliseconds(blockTime)
|
newHeader.SetTimeInMilliseconds(blockTime)
|
||||||
block.Header = newHeader.ToImmutable()
|
block.Header = newHeader.ToImmutable()
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ func TestPastMedianTime(t *testing.T) {
|
|||||||
newHeader := block.Header.ToMutable()
|
newHeader := block.Header.ToMutable()
|
||||||
newHeader.SetTimeInMilliseconds(blockTime)
|
newHeader.SetTimeInMilliseconds(blockTime)
|
||||||
block.Header = newHeader.ToImmutable()
|
block.Header = newHeader.ToImmutable()
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -191,6 +191,46 @@ func (pm *pruningManager) UpdatePruningPointByVirtual(stagingArea *model.Staging
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type blockIteratorFromOneBlock struct {
|
||||||
|
done, isClosed bool
|
||||||
|
hash *externalapi.DomainHash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *blockIteratorFromOneBlock) First() bool {
|
||||||
|
if b.isClosed {
|
||||||
|
panic("Tried using a closed blockIteratorFromOneBlock")
|
||||||
|
}
|
||||||
|
|
||||||
|
b.done = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *blockIteratorFromOneBlock) Next() bool {
|
||||||
|
if b.isClosed {
|
||||||
|
panic("Tried using a closed blockIteratorFromOneBlock")
|
||||||
|
}
|
||||||
|
|
||||||
|
b.done = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *blockIteratorFromOneBlock) Get() (*externalapi.DomainHash, error) {
|
||||||
|
if b.isClosed {
|
||||||
|
panic("Tried using a closed blockIteratorFromOneBlock")
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.hash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *blockIteratorFromOneBlock) Close() error {
|
||||||
|
if b.isClosed {
|
||||||
|
panic("Tried using a closed blockIteratorFromOneBlock")
|
||||||
|
}
|
||||||
|
|
||||||
|
b.isClosed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (pm *pruningManager) nextPruningPointAndCandidateByBlockHash(stagingArea *model.StagingArea,
|
func (pm *pruningManager) nextPruningPointAndCandidateByBlockHash(stagingArea *model.StagingArea,
|
||||||
blockHash, suggestedLowHash *externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.DomainHash, error) {
|
blockHash, suggestedLowHash *externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.DomainHash, error) {
|
||||||
|
|
||||||
@ -222,12 +262,12 @@ func (pm *pruningManager) nextPruningPointAndCandidateByBlockHash(stagingArea *m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, blockHash, false)
|
currentPruningPoint, err := pm.pruningStore.PruningPoint(pm.databaseContext, stagingArea)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPruningPoint, err := pm.pruningStore.PruningPoint(pm.databaseContext, stagingArea)
|
ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, blockHash, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -240,9 +280,14 @@ func (pm *pruningManager) nextPruningPointAndCandidateByBlockHash(stagingArea *m
|
|||||||
// We iterate until the selected parent of the given block, in order to allow a situation where the given block hash
|
// We iterate until the selected parent of the given block, in order to allow a situation where the given block hash
|
||||||
// belongs to the virtual. This shouldn't change anything since the max blue score difference between a block and its
|
// belongs to the virtual. This shouldn't change anything since the max blue score difference between a block and its
|
||||||
// selected parent is K, and K << pm.pruningDepth.
|
// selected parent is K, and K << pm.pruningDepth.
|
||||||
iterator, err := pm.dagTraversalManager.SelectedChildIterator(stagingArea, ghostdagData.SelectedParent(), lowHash, true)
|
var iterator model.BlockIterator
|
||||||
if err != nil {
|
if blockHash.Equal(lowHash) {
|
||||||
return nil, nil, err
|
iterator = &blockIteratorFromOneBlock{hash: lowHash}
|
||||||
|
} else {
|
||||||
|
iterator, err = pm.dagTraversalManager.SelectedChildIterator(stagingArea, ghostdagData.SelectedParent(), lowHash, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defer iterator.Close()
|
defer iterator.Close()
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashset"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashset"
|
||||||
|
"github.com/kaspanet/kaspad/util/staging"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
@ -60,7 +61,7 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
virtualChangeSet, _, err := tc.blockProcessor.ValidateAndInsertBlock(block, true)
|
virtualChangeSet, err := tc.validateAndInsertBlockNoLock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -80,7 +81,7 @@ func (tc *testConsensus) AddUTXOInvalidHeader(parentHashes []*externalapi.Domain
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
virtualChangeSet, _, err := tc.blockProcessor.ValidateAndInsertBlock(&externalapi.DomainBlock{
|
virtualChangeSet, err := tc.validateAndInsertBlockNoLock(&externalapi.DomainBlock{
|
||||||
Header: header,
|
Header: header,
|
||||||
Transactions: nil,
|
Transactions: nil,
|
||||||
}, true)
|
}, true)
|
||||||
@ -103,7 +104,7 @@ func (tc *testConsensus) AddUTXOInvalidBlock(parentHashes []*externalapi.DomainH
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
virtualChangeSet, _, err := tc.blockProcessor.ValidateAndInsertBlock(block, true)
|
virtualChangeSet, err := tc.validateAndInsertBlockNoLock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -111,6 +112,13 @@ func (tc *testConsensus) AddUTXOInvalidBlock(parentHashes []*externalapi.DomainH
|
|||||||
return consensushashing.BlockHash(block), virtualChangeSet, nil
|
return consensushashing.BlockHash(block), virtualChangeSet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tc *testConsensus) ResolveVirtualWithMaxParam(maxBlocksToResolve uint64) (bool, error) {
|
||||||
|
tc.lock.Lock()
|
||||||
|
defer tc.lock.Unlock()
|
||||||
|
|
||||||
|
return tc.resolveVirtualNoLock(maxBlocksToResolve)
|
||||||
|
}
|
||||||
|
|
||||||
// jsonBlock is a json representation of a block in mine format
|
// jsonBlock is a json representation of a block in mine format
|
||||||
type jsonBlock struct {
|
type jsonBlock struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
@ -258,3 +266,16 @@ func (tc *testConsensus) BuildHeaderWithParents(parentHashes []*externalapi.Doma
|
|||||||
|
|
||||||
return tc.testBlockBuilder.BuildUTXOInvalidHeader(parentHashes)
|
return tc.testBlockBuilder.BuildUTXOInvalidHeader(parentHashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tc *testConsensus) UpdatePruningPointByVirtual() error {
|
||||||
|
tc.lock.Lock()
|
||||||
|
defer tc.lock.Unlock()
|
||||||
|
|
||||||
|
stagingArea := model.NewStagingArea()
|
||||||
|
err := tc.pruningManager.UpdatePruningPointByVirtual(stagingArea)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return staging.CommitAllChanges(tc.databaseContext, stagingArea)
|
||||||
|
}
|
||||||
|
|||||||
@ -318,7 +318,7 @@ func TestCheckLockTimeVerifyConditionedByAbsoluteTime(t *testing.T) {
|
|||||||
blockHeader := tipBlock.Header.ToMutable()
|
blockHeader := tipBlock.Header.ToMutable()
|
||||||
blockHeader.SetTimeInMilliseconds(timeStampBlockE + i*1000)
|
blockHeader.SetTimeInMilliseconds(timeStampBlockE + i*1000)
|
||||||
tipBlock.Header = blockHeader.ToImmutable()
|
tipBlock.Header = blockHeader.ToImmutable()
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(tipBlock, true)
|
err = testConsensus.ValidateAndInsertBlock(tipBlock, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error validating and inserting tip block: %v", err)
|
t.Fatalf("Error validating and inserting tip block: %v", err)
|
||||||
}
|
}
|
||||||
@ -439,7 +439,7 @@ func TestCheckLockTimeVerifyConditionedByAbsoluteTimeWithWrongLockTime(t *testin
|
|||||||
blockHeader := tipBlock.Header.ToMutable()
|
blockHeader := tipBlock.Header.ToMutable()
|
||||||
blockHeader.SetTimeInMilliseconds(timeStampBlockE + i*1000)
|
blockHeader.SetTimeInMilliseconds(timeStampBlockE + i*1000)
|
||||||
tipBlock.Header = blockHeader.ToImmutable()
|
tipBlock.Header = blockHeader.ToImmutable()
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(tipBlock, true)
|
err = testConsensus.ValidateAndInsertBlock(tipBlock, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error validating and inserting tip block: %v", err)
|
t.Fatalf("Error validating and inserting tip block: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,7 +57,7 @@ func TestCreateStagingConsensus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = domainInstance.StagingConsensus().ValidateAndInsertBlockWithTrustedData(genesisWithTrustedData, true)
|
err = domainInstance.StagingConsensus().ValidateAndInsertBlockWithTrustedData(genesisWithTrustedData, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlockWithTrustedData: %+v", err)
|
t.Fatalf("ValidateAndInsertBlockWithTrustedData: %+v", err)
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ func TestCreateStagingConsensus(t *testing.T) {
|
|||||||
t.Fatalf("BuildBlock: %+v", err)
|
t.Fatalf("BuildBlock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = domainInstance.StagingConsensus().ValidateAndInsertBlock(block, true)
|
err = domainInstance.StagingConsensus().ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ func TestCreateStagingConsensus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addGenesisToStagingConsensus()
|
addGenesisToStagingConsensus()
|
||||||
_, err = domainInstance.StagingConsensus().ValidateAndInsertBlock(block, true)
|
err = domainInstance.StagingConsensus().ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,7 +106,7 @@ func syncConsensuses(syncer, syncee externalapi.Consensus) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = syncee.ValidateAndInsertBlockWithTrustedData(blockWithTrustedData, false)
|
err = syncee.ValidateAndInsertBlockWithTrustedData(blockWithTrustedData, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -161,7 +161,7 @@ func syncConsensuses(syncer, syncee externalapi.Consensus) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = syncee.ValidateAndInsertBlock(block, false)
|
err = syncee.ValidateAndInsertBlock(block, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -232,7 +232,7 @@ func syncConsensuses(syncer, syncee externalapi.Consensus) error {
|
|||||||
log.Infof("Resolving virtual. Estimated progress: %d%%", percents)
|
log.Infof("Resolving virtual. Estimated progress: %d%%", percents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, isCompletelyResolved, err := syncee.ResolveVirtual()
|
isCompletelyResolved, err := syncee.ResolveVirtual()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,20 @@ func (mp *mempool) AllTransactions() []*externalapi.DomainTransaction {
|
|||||||
return mp.transactionsPool.getAllTransactions()
|
return mp.transactionsPool.getAllTransactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mp *mempool) GetOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
||||||
|
mp.mtx.RLock()
|
||||||
|
defer mp.mtx.RUnlock()
|
||||||
|
|
||||||
|
return mp.orphansPool.getOrphanTransaction(transactionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *mempool) AllOrphanTransactions() []*externalapi.DomainTransaction {
|
||||||
|
mp.mtx.RLock()
|
||||||
|
defer mp.mtx.RUnlock()
|
||||||
|
|
||||||
|
return mp.orphansPool.getAllOrphanTransactions()
|
||||||
|
}
|
||||||
|
|
||||||
func (mp *mempool) TransactionCount() int {
|
func (mp *mempool) TransactionCount() int {
|
||||||
mp.mtx.RLock()
|
mp.mtx.RLock()
|
||||||
defer mp.mtx.RUnlock()
|
defer mp.mtx.RUnlock()
|
||||||
|
|||||||
@ -328,3 +328,18 @@ func (op *orphansPool) randomNonHighPriorityOrphan() *model.OrphanTransaction {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (op *orphansPool) getOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
||||||
|
if orphanTransaction, ok := op.allOrphans[*transactionID]; ok {
|
||||||
|
return orphanTransaction.Transaction(), true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *orphansPool) getAllOrphanTransactions() []*externalapi.DomainTransaction {
|
||||||
|
allOrphanTransactions := make([]*externalapi.DomainTransaction, 0, len(op.allOrphans))
|
||||||
|
for _, mempoolTransaction := range op.allOrphans {
|
||||||
|
allOrphanTransactions = append(allOrphanTransactions, mempoolTransaction.Transaction())
|
||||||
|
}
|
||||||
|
return allOrphanTransactions
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
package miningmanager
|
package miningmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensusreference"
|
"github.com/kaspanet/kaspad/domain/consensusreference"
|
||||||
miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model"
|
miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model"
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MiningManager creates block templates for mining as well as maintaining
|
// MiningManager creates block templates for mining as well as maintaining
|
||||||
@ -16,6 +17,8 @@ type MiningManager interface {
|
|||||||
GetBlockTemplateBuilder() miningmanagermodel.BlockTemplateBuilder
|
GetBlockTemplateBuilder() miningmanagermodel.BlockTemplateBuilder
|
||||||
GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
||||||
AllTransactions() []*externalapi.DomainTransaction
|
AllTransactions() []*externalapi.DomainTransaction
|
||||||
|
GetOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
||||||
|
AllOrphanTransactions() []*externalapi.DomainTransaction
|
||||||
TransactionCount() int
|
TransactionCount() 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) (
|
||||||
@ -115,6 +118,17 @@ func (mm *miningManager) AllTransactions() []*externalapi.DomainTransaction {
|
|||||||
return mm.mempool.AllTransactions()
|
return mm.mempool.AllTransactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mm *miningManager) GetOrphanTransaction(
|
||||||
|
transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
||||||
|
|
||||||
|
return mm.mempool.GetOrphanTransaction(transactionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mm *miningManager) AllOrphanTransactions() []*externalapi.DomainTransaction {
|
||||||
|
|
||||||
|
return mm.mempool.AllOrphanTransactions()
|
||||||
|
}
|
||||||
|
|
||||||
func (mm *miningManager) TransactionCount() int {
|
func (mm *miningManager) TransactionCount() int {
|
||||||
return mm.mempool.TransactionCount()
|
return mm.mempool.TransactionCount()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,8 @@ type Mempool interface {
|
|||||||
RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error
|
RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error
|
||||||
GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
||||||
AllTransactions() []*externalapi.DomainTransaction
|
AllTransactions() []*externalapi.DomainTransaction
|
||||||
|
GetOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
||||||
|
AllOrphanTransactions() []*externalapi.DomainTransaction
|
||||||
TransactionCount() int
|
TransactionCount() int
|
||||||
RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error)
|
RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error)
|
||||||
IsTransactionOutputDust(output *externalapi.DomainTransactionOutput) bool
|
IsTransactionOutputDust(output *externalapi.DomainTransactionOutput) bool
|
||||||
|
|||||||
@ -38,8 +38,9 @@ const (
|
|||||||
defaultBanDuration = time.Hour * 24
|
defaultBanDuration = time.Hour * 24
|
||||||
defaultBanThreshold = 100
|
defaultBanThreshold = 100
|
||||||
//DefaultConnectTimeout is the default connection timeout when dialing
|
//DefaultConnectTimeout is the default connection timeout when dialing
|
||||||
DefaultConnectTimeout = time.Second * 30
|
DefaultConnectTimeout = time.Second * 30
|
||||||
defaultMaxRPCClients = 10
|
//DefaultMaxRPCClients is the default max number of RPC clients
|
||||||
|
DefaultMaxRPCClients = 128
|
||||||
defaultMaxRPCWebsockets = 25
|
defaultMaxRPCWebsockets = 25
|
||||||
defaultMaxRPCConcurrentReqs = 20
|
defaultMaxRPCConcurrentReqs = 20
|
||||||
defaultBlockMaxMass = 10_000_000
|
defaultBlockMaxMass = 10_000_000
|
||||||
@ -178,7 +179,7 @@ func defaultFlags() *Flags {
|
|||||||
MaxInboundPeers: defaultMaxInboundPeers,
|
MaxInboundPeers: defaultMaxInboundPeers,
|
||||||
BanDuration: defaultBanDuration,
|
BanDuration: defaultBanDuration,
|
||||||
BanThreshold: defaultBanThreshold,
|
BanThreshold: defaultBanThreshold,
|
||||||
RPCMaxClients: defaultMaxRPCClients,
|
RPCMaxClients: DefaultMaxRPCClients,
|
||||||
RPCMaxWebsockets: defaultMaxRPCWebsockets,
|
RPCMaxWebsockets: defaultMaxRPCWebsockets,
|
||||||
RPCMaxConcurrentReqs: defaultMaxRPCConcurrentReqs,
|
RPCMaxConcurrentReqs: defaultMaxRPCConcurrentReqs,
|
||||||
AppDir: defaultDataDir,
|
AppDir: defaultDataDir,
|
||||||
|
|||||||
@ -46,7 +46,7 @@ func NewNetAdapter(cfg *config.Config) (*NetAdapter, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rpcServer, err := grpcserver.NewRPCServer(cfg.RPCListeners)
|
rpcServer, err := grpcserver.NewRPCServer(cfg.RPCListeners, cfg.RPCMaxClients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,10 +94,11 @@ func (s *gRPCServer) SetOnConnectedHandler(onConnectedHandler server.OnConnected
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *gRPCServer) handleInboundConnection(ctx context.Context, stream grpcStream) error {
|
func (s *gRPCServer) handleInboundConnection(ctx context.Context, stream grpcStream) error {
|
||||||
err := s.incrementInboundConnectionCountAndLimitIfRequired()
|
connectionCount, err := s.incrementInboundConnectionCountAndLimitIfRequired()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer s.decrementInboundConnectionCount()
|
||||||
|
|
||||||
peerInfo, ok := peer.FromContext(ctx)
|
peerInfo, ok := peer.FromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -115,23 +116,23 @@ func (s *gRPCServer) handleInboundConnection(ctx context.Context, stream grpcStr
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("%s Incoming connection from %s", s.name, peerInfo.Addr)
|
log.Infof("%s Incoming connection from %s #%d", s.name, peerInfo.Addr, connectionCount)
|
||||||
|
|
||||||
<-connection.stopChan
|
<-connection.stopChan
|
||||||
s.decrementInboundConnectionCount()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *gRPCServer) incrementInboundConnectionCountAndLimitIfRequired() error {
|
func (s *gRPCServer) incrementInboundConnectionCountAndLimitIfRequired() (int, error) {
|
||||||
s.inboundConnectionCountLock.Lock()
|
s.inboundConnectionCountLock.Lock()
|
||||||
defer s.inboundConnectionCountLock.Unlock()
|
defer s.inboundConnectionCountLock.Unlock()
|
||||||
|
|
||||||
if s.maxInboundConnections > 0 && s.inboundConnectionCount == s.maxInboundConnections {
|
if s.maxInboundConnections > 0 && s.inboundConnectionCount == s.maxInboundConnections {
|
||||||
return errors.Errorf("limit of %d inbound connections has been exceeded", s.maxInboundConnections)
|
log.Warnf("Limit of %d %s inbound connections has been exceeded", s.maxInboundConnections, s.name)
|
||||||
|
return s.inboundConnectionCount, errors.Errorf("limit of %d %s inbound connections has been exceeded", s.maxInboundConnections, s.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.inboundConnectionCount++
|
s.inboundConnectionCount++
|
||||||
return nil
|
return s.inboundConnectionCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *gRPCServer) decrementInboundConnectionCount() {
|
func (s *gRPCServer) decrementInboundConnectionCount() {
|
||||||
|
|||||||
@ -609,6 +609,8 @@ in the mempool.
|
|||||||
| Field | Type | Label | Description |
|
| Field | Type | Label | Description |
|
||||||
| ----- | ---- | ----- | ----------- |
|
| ----- | ---- | ----- | ----------- |
|
||||||
| txId | [string](#string) | | The transaction's TransactionID. |
|
| txId | [string](#string) | | The transaction's TransactionID. |
|
||||||
|
| includeOrphanPool | [bool](#bool) | | |
|
||||||
|
| filterTransactionPool | [bool](#bool) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -638,6 +640,12 @@ GetMempoolEntriesRequestMessage requests information about all the transactions
|
|||||||
currently in the mempool.
|
currently in the mempool.
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| includeOrphanPool | [bool](#bool) | | |
|
||||||
|
| filterTransactionPool | [bool](#bool) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -668,6 +676,7 @@ currently in the mempool.
|
|||||||
| ----- | ---- | ----- | ----------- |
|
| ----- | ---- | ----- | ----------- |
|
||||||
| fee | [uint64](#uint64) | | |
|
| fee | [uint64](#uint64) | | |
|
||||||
| transaction | [RpcTransaction](#protowire.RpcTransaction) | | |
|
| transaction | [RpcTransaction](#protowire.RpcTransaction) | | |
|
||||||
|
| isOrphan | [bool](#bool) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1798,6 +1807,8 @@ See NotifyNewBlockTemplateRequestMessage
|
|||||||
| Field | Type | Label | Description |
|
| Field | Type | Label | Description |
|
||||||
| ----- | ---- | ----- | ----------- |
|
| ----- | ---- | ----- | ----------- |
|
||||||
| addresses | [string](#string) | repeated | |
|
| addresses | [string](#string) | repeated | |
|
||||||
|
| includeOrphanPool | [bool](#bool) | | |
|
||||||
|
| filterTransactionPool | [bool](#bool) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -215,6 +215,8 @@ message GetSelectedTipHashResponseMessage{
|
|||||||
message GetMempoolEntryRequestMessage{
|
message GetMempoolEntryRequestMessage{
|
||||||
// The transaction's TransactionID.
|
// The transaction's TransactionID.
|
||||||
string txId = 1;
|
string txId = 1;
|
||||||
|
bool includeOrphanPool = 2;
|
||||||
|
bool filterTransactionPool = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetMempoolEntryResponseMessage{
|
message GetMempoolEntryResponseMessage{
|
||||||
@ -226,6 +228,8 @@ message GetMempoolEntryResponseMessage{
|
|||||||
// GetMempoolEntriesRequestMessage requests information about all the transactions
|
// GetMempoolEntriesRequestMessage requests information about all the transactions
|
||||||
// currently in the mempool.
|
// currently in the mempool.
|
||||||
message GetMempoolEntriesRequestMessage{
|
message GetMempoolEntriesRequestMessage{
|
||||||
|
bool includeOrphanPool = 1;
|
||||||
|
bool filterTransactionPool = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetMempoolEntriesResponseMessage{
|
message GetMempoolEntriesResponseMessage{
|
||||||
@ -237,6 +241,7 @@ message GetMempoolEntriesResponseMessage{
|
|||||||
message MempoolEntry{
|
message MempoolEntry{
|
||||||
uint64 fee = 1;
|
uint64 fee = 1;
|
||||||
RpcTransaction transaction = 3;
|
RpcTransaction transaction = 3;
|
||||||
|
bool isOrphan = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConnectedPeerInfoRequestMessage requests information about all the p2p peers
|
// GetConnectedPeerInfoRequestMessage requests information about all the p2p peers
|
||||||
@ -697,6 +702,8 @@ message MempoolEntryByAddress{
|
|||||||
|
|
||||||
message GetMempoolEntriesByAddressesRequestMessage{
|
message GetMempoolEntriesByAddressesRequestMessage{
|
||||||
repeated string addresses = 1;
|
repeated string addresses = 1;
|
||||||
|
bool includeOrphanPool = 2;
|
||||||
|
bool filterTransactionPool = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetMempoolEntriesByAddressesResponseMessage{
|
message GetMempoolEntriesByAddressesResponseMessage{
|
||||||
|
|||||||
@ -9,14 +9,27 @@ func (x *KaspadMessage_GetMempoolEntriesRequest) toAppMessage() (appmessage.Mess
|
|||||||
if x == nil {
|
if x == nil {
|
||||||
return nil, errors.Wrapf(errorNil, "KaspadMessage_GetMempoolEntriesRequest is nil")
|
return nil, errors.Wrapf(errorNil, "KaspadMessage_GetMempoolEntriesRequest is nil")
|
||||||
}
|
}
|
||||||
return &appmessage.GetMempoolEntriesRequestMessage{}, nil
|
return x.GetMempoolEntriesRequest.toAppMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *KaspadMessage_GetMempoolEntriesRequest) fromAppMessage(_ *appmessage.GetMempoolEntriesRequestMessage) error {
|
func (x *KaspadMessage_GetMempoolEntriesRequest) fromAppMessage(message *appmessage.GetMempoolEntriesRequestMessage) error {
|
||||||
x.GetMempoolEntriesRequest = &GetMempoolEntriesRequestMessage{}
|
x.GetMempoolEntriesRequest = &GetMempoolEntriesRequestMessage{
|
||||||
|
IncludeOrphanPool: message.IncludeOrphanPool,
|
||||||
|
FilterTransactionPool: message.FilterTransactionPool,
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *GetMempoolEntriesRequestMessage) toAppMessage() (appmessage.Message, error) {
|
||||||
|
if x == nil {
|
||||||
|
return nil, errors.Wrapf(errorNil, "GetMempoolEntryRequestMessage is nil")
|
||||||
|
}
|
||||||
|
return &appmessage.GetMempoolEntriesRequestMessage{
|
||||||
|
IncludeOrphanPool: x.IncludeOrphanPool,
|
||||||
|
FilterTransactionPool: x.FilterTransactionPool,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *KaspadMessage_GetMempoolEntriesResponse) toAppMessage() (appmessage.Message, error) {
|
func (x *KaspadMessage_GetMempoolEntriesResponse) toAppMessage() (appmessage.Message, error) {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
return nil, errors.Wrapf(errorNil, "KaspadMessage_GetMempoolEntriesResponse is nil")
|
return nil, errors.Wrapf(errorNil, "KaspadMessage_GetMempoolEntriesResponse is nil")
|
||||||
|
|||||||
@ -7,14 +7,16 @@ import (
|
|||||||
|
|
||||||
func (x *KaspadMessage_GetMempoolEntriesByAddressesRequest) toAppMessage() (appmessage.Message, error) {
|
func (x *KaspadMessage_GetMempoolEntriesByAddressesRequest) toAppMessage() (appmessage.Message, error) {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
return nil, errors.Wrapf(errorNil, "KaspadMessage_GetMempoolEntriesRequest is nil")
|
return nil, errors.Wrapf(errorNil, "KaspadMessage_KaspadMessage_GetMempoolEntriesByAddressesRequest is nil")
|
||||||
}
|
}
|
||||||
return x.GetMempoolEntriesByAddressesRequest.toAppMessage()
|
return x.GetMempoolEntriesByAddressesRequest.toAppMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *KaspadMessage_GetMempoolEntriesByAddressesRequest) fromAppMessage(message *appmessage.GetMempoolEntriesByAddressesRequestMessage) error {
|
func (x *KaspadMessage_GetMempoolEntriesByAddressesRequest) fromAppMessage(message *appmessage.GetMempoolEntriesByAddressesRequestMessage) error {
|
||||||
x.GetMempoolEntriesByAddressesRequest = &GetMempoolEntriesByAddressesRequestMessage{
|
x.GetMempoolEntriesByAddressesRequest = &GetMempoolEntriesByAddressesRequestMessage{
|
||||||
Addresses: message.Addresses,
|
Addresses: message.Addresses,
|
||||||
|
IncludeOrphanPool: message.IncludeOrphanPool,
|
||||||
|
FilterTransactionPool: message.FilterTransactionPool,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -24,7 +26,9 @@ func (x *GetMempoolEntriesByAddressesRequestMessage) toAppMessage() (appmessage.
|
|||||||
return nil, errors.Wrapf(errorNil, "KaspadMessage_GetMempoolEntriesRequest is nil")
|
return nil, errors.Wrapf(errorNil, "KaspadMessage_GetMempoolEntriesRequest is nil")
|
||||||
}
|
}
|
||||||
return &appmessage.GetMempoolEntriesByAddressesRequestMessage{
|
return &appmessage.GetMempoolEntriesByAddressesRequestMessage{
|
||||||
Addresses: x.Addresses,
|
Addresses: x.Addresses,
|
||||||
|
IncludeOrphanPool: x.IncludeOrphanPool,
|
||||||
|
FilterTransactionPool: x.FilterTransactionPool,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,9 @@ func (x *KaspadMessage_GetMempoolEntryRequest) toAppMessage() (appmessage.Messag
|
|||||||
|
|
||||||
func (x *KaspadMessage_GetMempoolEntryRequest) fromAppMessage(message *appmessage.GetMempoolEntryRequestMessage) error {
|
func (x *KaspadMessage_GetMempoolEntryRequest) fromAppMessage(message *appmessage.GetMempoolEntryRequestMessage) error {
|
||||||
x.GetMempoolEntryRequest = &GetMempoolEntryRequestMessage{
|
x.GetMempoolEntryRequest = &GetMempoolEntryRequestMessage{
|
||||||
TxId: message.TxID,
|
TxId: message.TxID,
|
||||||
|
IncludeOrphanPool: message.IncludeOrphanPool,
|
||||||
|
FilterTransactionPool: message.FilterTransactionPool,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -24,7 +26,9 @@ func (x *GetMempoolEntryRequestMessage) toAppMessage() (appmessage.Message, erro
|
|||||||
return nil, errors.Wrapf(errorNil, "GetMempoolEntryRequestMessage is nil")
|
return nil, errors.Wrapf(errorNil, "GetMempoolEntryRequestMessage is nil")
|
||||||
}
|
}
|
||||||
return &appmessage.GetMempoolEntryRequestMessage{
|
return &appmessage.GetMempoolEntryRequestMessage{
|
||||||
TxID: x.TxId,
|
TxID: x.TxId,
|
||||||
|
IncludeOrphanPool: x.IncludeOrphanPool,
|
||||||
|
FilterTransactionPool: x.FilterTransactionPool,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +95,7 @@ func (x *MempoolEntry) toAppMessage() (*appmessage.MempoolEntry, error) {
|
|||||||
return &appmessage.MempoolEntry{
|
return &appmessage.MempoolEntry{
|
||||||
Fee: x.Fee,
|
Fee: x.Fee,
|
||||||
Transaction: transaction,
|
Transaction: transaction,
|
||||||
|
IsOrphan: x.IsOrphan,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +108,7 @@ func (x *MempoolEntry) fromAppMessage(message *appmessage.MempoolEntry) error {
|
|||||||
*x = MempoolEntry{
|
*x = MempoolEntry{
|
||||||
Fee: message.Fee,
|
Fee: message.Fee,
|
||||||
Transaction: transaction,
|
Transaction: transaction,
|
||||||
|
IsOrphan: message.IsOrphan,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,12 +14,9 @@ type rpcServer struct {
|
|||||||
// RPCMaxMessageSize is the max message size for the RPC server to send and receive
|
// RPCMaxMessageSize is the max message size for the RPC server to send and receive
|
||||||
const RPCMaxMessageSize = 1024 * 1024 * 1024 // 1 GB
|
const RPCMaxMessageSize = 1024 * 1024 * 1024 // 1 GB
|
||||||
|
|
||||||
// RPCMaxInboundConnections is the max amount of inbound connections for the RPC server
|
|
||||||
const RPCMaxInboundConnections = 128
|
|
||||||
|
|
||||||
// NewRPCServer creates a new RPCServer
|
// NewRPCServer creates a new RPCServer
|
||||||
func NewRPCServer(listeningAddresses []string) (server.Server, error) {
|
func NewRPCServer(listeningAddresses []string, rpcMaxInboundConnections int) (server.Server, error) {
|
||||||
gRPCServer := newGRPCServer(listeningAddresses, RPCMaxMessageSize, RPCMaxInboundConnections, "RPC")
|
gRPCServer := newGRPCServer(listeningAddresses, RPCMaxMessageSize, rpcMaxInboundConnections, "RPC")
|
||||||
rpcServer := &rpcServer{gRPCServer: *gRPCServer}
|
rpcServer := &rpcServer{gRPCServer: *gRPCServer}
|
||||||
protowire.RegisterRPCServer(gRPCServer.server, rpcServer)
|
protowire.RegisterRPCServer(gRPCServer.server, rpcServer)
|
||||||
return rpcServer, nil
|
return rpcServer, nil
|
||||||
|
|||||||
@ -3,8 +3,8 @@ package rpcclient
|
|||||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
|
||||||
// GetMempoolEntries sends an RPC request respective to the function's name and returns the RPC server's response
|
// GetMempoolEntries sends an RPC request respective to the function's name and returns the RPC server's response
|
||||||
func (c *RPCClient) GetMempoolEntries() (*appmessage.GetMempoolEntriesResponseMessage, error) {
|
func (c *RPCClient) GetMempoolEntries(includeOrphanPool bool, filterTransactionPool bool) (*appmessage.GetMempoolEntriesResponseMessage, error) {
|
||||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetMempoolEntriesRequestMessage())
|
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetMempoolEntriesRequestMessage(includeOrphanPool, filterTransactionPool))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,8 @@ package rpcclient
|
|||||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
|
||||||
// GetMempoolEntriesByAddresses sends an RPC request respective to the function's name and returns the RPC server's response
|
// GetMempoolEntriesByAddresses sends an RPC request respective to the function's name and returns the RPC server's response
|
||||||
func (c *RPCClient) GetMempoolEntriesByAddresses(addresses []string) (*appmessage.GetMempoolEntriesByAddressesResponseMessage, error) {
|
func (c *RPCClient) GetMempoolEntriesByAddresses(addresses []string, includeOrphanPool bool, filterTransactionPool bool) (*appmessage.GetMempoolEntriesByAddressesResponseMessage, error) {
|
||||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetMempoolEntriesByAddressesRequestMessage(addresses))
|
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetMempoolEntriesByAddressesRequestMessage(addresses, includeOrphanPool, filterTransactionPool))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,8 @@ package rpcclient
|
|||||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
|
||||||
// GetMempoolEntry sends an RPC request respective to the function's name and returns the RPC server's response
|
// GetMempoolEntry sends an RPC request respective to the function's name and returns the RPC server's response
|
||||||
func (c *RPCClient) GetMempoolEntry(txID string) (*appmessage.GetMempoolEntryResponseMessage, error) {
|
func (c *RPCClient) GetMempoolEntry(txID string, includeOrphanPool bool, filterTransactionPool bool) (*appmessage.GetMempoolEntryResponseMessage, error) {
|
||||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetMempoolEntryRequestMessage(txID))
|
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetMempoolEntryRequestMessage(txID, includeOrphanPool, filterTransactionPool))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,7 +122,7 @@ func mineOrFetchBlock(blockData JSONBlock, mdb *miningDB, testConsensus testapi.
|
|||||||
SolveBlock(block)
|
SolveBlock(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(block, true)
|
err = testConsensus.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "error in ValidateAndInsertBlock")
|
return nil, errors.Wrap(err, "error in ValidateAndInsertBlock")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,7 +57,7 @@ func TestGenerateFastPruningIBDTest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
header.SetNonce(tip.Header.Nonce() + i)
|
header.SetNonce(tip.Header.Nonce() + i)
|
||||||
block := &externalapi.DomainBlock{Header: header.ToImmutable(), Transactions: tip.Transactions}
|
block := &externalapi.DomainBlock{Header: header.ToImmutable(), Transactions: tip.Transactions}
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ func TestGenerateFastPruningIBDTest(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
@ -124,7 +124,7 @@ func TestGenerateFastPruningIBDTest(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
err = tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,7 @@ func prepareBlocks() (blocks []*externalapi.DomainBlock, topBlock *externalapi.D
|
|||||||
}
|
}
|
||||||
|
|
||||||
mine.SolveBlock(block)
|
mine.SolveBlock(block)
|
||||||
_, err = testConsensus.ValidateAndInsertBlock(block, true)
|
err = testConsensus.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrap(err, "error in ValidateAndInsertBlock")
|
return nil, nil, errors.Wrap(err, "error in ValidateAndInsertBlock")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,7 +86,7 @@ func testReorg(cfg *configFlags) {
|
|||||||
block.Header = mutableHeader.ToImmutable()
|
block.Header = mutableHeader.ToImmutable()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tcAttacker.ValidateAndInsertBlock(block, true)
|
err = tcAttacker.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ func testReorg(cfg *configFlags) {
|
|||||||
if i%100 == 0 {
|
if i%100 == 0 {
|
||||||
log.Infof("Validated %d blocks from the attacker chain", i)
|
log.Infof("Validated %d blocks from the attacker chain", i)
|
||||||
}
|
}
|
||||||
_, err := tc.ValidateAndInsertBlock(block, true)
|
err := tc.ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ const (
|
|||||||
miningAddress3 = "kaspasim:qqq754f2gdcjcnykwuwwr60c82rh5u6mxxe7yqxljnrxz9fu0h95kduq9ezng"
|
miningAddress3 = "kaspasim:qqq754f2gdcjcnykwuwwr60c82rh5u6mxxe7yqxljnrxz9fu0h95kduq9ezng"
|
||||||
miningAddress3PrivateKey = "f6c8f31fd359cbb97007034780bc4021f6ad01c6bc10499b79849efd4cc7ca39"
|
miningAddress3PrivateKey = "f6c8f31fd359cbb97007034780bc4021f6ad01c6bc10499b79849efd4cc7ca39"
|
||||||
|
|
||||||
defaultTimeout = 10 * time.Second
|
defaultTimeout = 30 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
func setConfig(t *testing.T, harness *appHarness, protocolVersion uint32) {
|
func setConfig(t *testing.T, harness *appHarness, protocolVersion uint32) {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/server/grpcserver"
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ func TestRPCMaxInboundConnections(t *testing.T) {
|
|||||||
rpcClients := []*testRPCClient{}
|
rpcClients := []*testRPCClient{}
|
||||||
doneChan := make(chan error)
|
doneChan := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
for i := 0; i < grpcserver.RPCMaxInboundConnections; i++ {
|
for i := 0; i < config.DefaultMaxRPCClients; i++ {
|
||||||
rpcClient, err := newTestRPCClient(harness.rpcAddress)
|
rpcClient, err := newTestRPCClient(harness.rpcAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
doneChan <- err
|
doneChan <- err
|
||||||
@ -60,7 +60,7 @@ func TestRPCMaxInboundConnections(t *testing.T) {
|
|||||||
t.Fatalf("newTestRPCClient: %s", err)
|
t.Fatalf("newTestRPCClient: %s", err)
|
||||||
}
|
}
|
||||||
case <-time.After(time.Second * 5):
|
case <-time.After(time.Second * 5):
|
||||||
t.Fatalf("Timeout for connecting %d RPC connections elapsed", grpcserver.RPCMaxInboundConnections)
|
t.Fatalf("Timeout for connecting %d RPC connections elapsed", config.DefaultMaxRPCClients)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to connect another client. We expect this to fail
|
// Try to connect another client. We expect this to fail
|
||||||
|
|||||||
@ -69,7 +69,7 @@ func TestTxRelay(t *testing.T) {
|
|||||||
|
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
|
|
||||||
_, err := payee.rpcClient.GetMempoolEntry(txID)
|
getMempoolEntryResponse, err := payee.rpcClient.GetMempoolEntry(txID, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "not found") {
|
if strings.Contains(err.Error(), "not found") {
|
||||||
continue
|
continue
|
||||||
@ -77,12 +77,16 @@ func TestTxRelay(t *testing.T) {
|
|||||||
|
|
||||||
t.Fatalf("Error getting mempool entry: %+v", err)
|
t.Fatalf("Error getting mempool entry: %+v", err)
|
||||||
}
|
}
|
||||||
|
mempoolEntry := getMempoolEntryResponse.Entry
|
||||||
|
if mempoolEntry.IsOrphan {
|
||||||
|
t.Fatalf("transaction %s is an orphan, although it shouldn't be", mempoolEntry.Transaction.VerboseData.TransactionID)
|
||||||
|
}
|
||||||
|
|
||||||
mempoolEntriesByAddresses, err := payee.rpcClient.GetMempoolEntriesByAddresses(mempoolAddressQuery)
|
getMempoolEntriesByAddressesResponse, err := payee.rpcClient.GetMempoolEntriesByAddresses(mempoolAddressQuery, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error getting mempool entry: %+v", err)
|
t.Fatalf("Error getting mempool entry: %+v", err)
|
||||||
}
|
}
|
||||||
for _, mempoolEntryByAddress := range mempoolEntriesByAddresses.Entries {
|
for _, mempoolEntryByAddress := range getMempoolEntriesByAddressesResponse.Entries {
|
||||||
if payee.miningAddress == mempoolEntryByAddress.Address {
|
if payee.miningAddress == mempoolEntryByAddress.Address {
|
||||||
if len(mempoolEntryByAddress.Sending) > 1 {
|
if len(mempoolEntryByAddress.Sending) > 1 {
|
||||||
t.Fatal("Error payee is sending")
|
t.Fatal("Error payee is sending")
|
||||||
@ -99,7 +103,16 @@ func TestTxRelay(t *testing.T) {
|
|||||||
t.Fatal("Error payer is reciving")
|
t.Fatal("Error payer is reciving")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
for _, mempoolEntry := range mempoolEntryByAddress.Receiving {
|
||||||
|
if mempoolEntry.IsOrphan {
|
||||||
|
t.Fatalf("transaction %s is an orphan, although it shouldn't be", mempoolEntry.Transaction.VerboseData.TransactionID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, mempoolEntry := range mempoolEntryByAddress.Sending {
|
||||||
|
if mempoolEntry.IsOrphan {
|
||||||
|
t.Fatalf("transaction %s is an orphan, although it shouldn't be", mempoolEntry.Transaction.VerboseData.TransactionID)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(txAddedToMempoolChan)
|
close(txAddedToMempoolChan)
|
||||||
|
|||||||
@ -136,11 +136,11 @@ func CalcWork(bits uint32) *big.Int {
|
|||||||
|
|
||||||
func getHashrate(target *big.Int, TargetTimePerBlock time.Duration) *big.Int {
|
func getHashrate(target *big.Int, TargetTimePerBlock time.Duration) *big.Int {
|
||||||
// From: https://bitcoin.stackexchange.com/a/5557/40800
|
// From: https://bitcoin.stackexchange.com/a/5557/40800
|
||||||
// difficulty = hashrate / (2^256 / max_target / block_rate_in_seconds)
|
// difficulty = hashrate / (2^256 / max_target / seconds_per_block)
|
||||||
// hashrate = difficulty * (2^256 / max_target / block_rate_in_seconds)
|
// hashrate = difficulty * (2^256 / max_target / seconds_per_block)
|
||||||
// difficulty = max_target / target
|
// difficulty = max_target / target
|
||||||
// hashrate = (max_target / target) * (2^256 / max_target / block_rate_in_seconds)
|
// hashrate = (max_target / target) * (2^256 / max_target / seconds_per_block)
|
||||||
// hashrate = 2^256 / (target * block_rate_in_seconds)
|
// hashrate = 2^256 / (target * seconds_per_block)
|
||||||
|
|
||||||
tmp := new(big.Int)
|
tmp := new(big.Int)
|
||||||
divisor := new(big.Int).Set(target)
|
divisor := new(big.Int).Set(target)
|
||||||
|
|||||||
@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
|
|||||||
const (
|
const (
|
||||||
appMajor uint = 0
|
appMajor uint = 0
|
||||||
appMinor uint = 12
|
appMinor uint = 12
|
||||||
appPatch uint = 1
|
appPatch uint = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// appBuild is defined as a variable so it can be overridden during the build
|
// appBuild is defined as a variable so it can be overridden during the build
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user