mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-22 14:56:44 +00:00

* Implement EnqueueTransactionIDsForPropagation. * Fix tests. * Fix TxRelayTest. * Add a log for transaction propagation. Co-authored-by: Ori Newman <orinewman1@gmail.com>
192 lines
7.6 KiB
Go
192 lines
7.6 KiB
Go
package transactionrelay_test
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay"
|
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
|
"github.com/kaspanet/kaspad/domain"
|
|
"github.com/kaspanet/kaspad/domain/consensus"
|
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
|
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
|
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
|
"github.com/kaspanet/kaspad/util/panics"
|
|
|
|
"github.com/kaspanet/kaspad/app/appmessage"
|
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
|
)
|
|
|
|
type mocTransactionsRelayContext struct {
|
|
netAdapter *netadapter.NetAdapter
|
|
domain domain.Domain
|
|
sharedRequestedTransactions *transactionrelay.SharedRequestedTransactions
|
|
}
|
|
|
|
func (m *mocTransactionsRelayContext) NetAdapter() *netadapter.NetAdapter {
|
|
return m.netAdapter
|
|
}
|
|
|
|
func (m *mocTransactionsRelayContext) Domain() domain.Domain {
|
|
return m.domain
|
|
}
|
|
|
|
func (m *mocTransactionsRelayContext) SharedRequestedTransactions() *transactionrelay.SharedRequestedTransactions {
|
|
return m.sharedRequestedTransactions
|
|
}
|
|
|
|
func (m *mocTransactionsRelayContext) EnqueueTransactionIDsForPropagation(transactionIDs []*externalapi.DomainTransactionID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mocTransactionsRelayContext) OnTransactionAddedToMempool() {
|
|
}
|
|
|
|
// TestHandleRelayedTransactionsNotFound tests the flow of HandleRelayedTransactions when the peer doesn't
|
|
// have the requested transactions in the mempool.
|
|
func TestHandleRelayedTransactionsNotFound(t *testing.T) {
|
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
|
|
|
var log = logger.RegisterSubSystem("PROT")
|
|
var spawn = panics.GoroutineWrapperFunc(log)
|
|
factory := consensus.NewFactory()
|
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestHandleRelayedTransactionsNotFound")
|
|
if err != nil {
|
|
t.Fatalf("Error setting up test consensus: %+v", err)
|
|
}
|
|
defer teardown(false)
|
|
|
|
sharedRequestedTransactions := transactionrelay.NewSharedRequestedTransactions()
|
|
adapter, err := netadapter.NewNetAdapter(config.DefaultConfig())
|
|
if err != nil {
|
|
t.Fatalf("Failed to create a NetAdapter: %v", err)
|
|
}
|
|
domainInstance, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), tc.Database())
|
|
if err != nil {
|
|
t.Fatalf("Failed to set up a domain instance: %v", err)
|
|
}
|
|
context := &mocTransactionsRelayContext{
|
|
netAdapter: adapter,
|
|
domain: domainInstance,
|
|
sharedRequestedTransactions: sharedRequestedTransactions,
|
|
}
|
|
incomingRoute := router.NewRoute("incoming")
|
|
defer incomingRoute.Close()
|
|
peerIncomingRoute := router.NewRoute("outgoing")
|
|
defer peerIncomingRoute.Close()
|
|
|
|
txID1 := externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
|
|
txID2 := externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02})
|
|
txIDs := []*externalapi.DomainTransactionID{txID1, txID2}
|
|
invMessage := appmessage.NewMsgInvTransaction(txIDs)
|
|
err = incomingRoute.Enqueue(invMessage)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err)
|
|
}
|
|
// The goroutine is representing the peer's actions.
|
|
spawn("peerResponseToTheTransactionsRequest", func() {
|
|
msg, err := peerIncomingRoute.Dequeue()
|
|
if err != nil {
|
|
t.Fatalf("Dequeue: %v", err)
|
|
}
|
|
inv := msg.(*appmessage.MsgRequestTransactions)
|
|
|
|
if len(txIDs) != len(inv.IDs) {
|
|
t.Fatalf("TestHandleRelayedTransactions: expected %d transactions ID, but got %d", len(txIDs), len(inv.IDs))
|
|
}
|
|
|
|
for i, id := range inv.IDs {
|
|
if txIDs[i].String() != id.String() {
|
|
t.Fatalf("TestHandleRelayedTransactions: expected equal txID: expected %s, but got %s", txIDs[i].String(), id.String())
|
|
}
|
|
err = incomingRoute.Enqueue(appmessage.NewMsgTransactionNotFound(txIDs[i]))
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err)
|
|
}
|
|
}
|
|
// Insert an unexpected message type to stop the infinity loop.
|
|
err = incomingRoute.Enqueue(&appmessage.MsgAddresses{})
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err)
|
|
}
|
|
})
|
|
|
|
err = transactionrelay.HandleRelayedTransactions(context, incomingRoute, peerIncomingRoute)
|
|
// Since we inserted an unexpected message type to stop the infinity loop,
|
|
// we expect the error will be infected from this specific message and also the
|
|
// error will count as a protocol message.
|
|
if protocolErr := (protocolerrors.ProtocolError{}); err == nil || !errors.As(err, &protocolErr) {
|
|
t.Fatalf("Expected to protocol error")
|
|
} else {
|
|
if !protocolErr.ShouldBan {
|
|
t.Fatalf("Exepcted shouldBan true, but got false.")
|
|
}
|
|
if !strings.Contains(err.Error(), "unexpected Addresses [code 3] message in the block relay flow while expecting an inv message") {
|
|
t.Fatalf("Unexpected error: expected: an error due to existence of an Addresses message "+
|
|
"in the block relay flow, but got: %v", protocolErr.Cause)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestOnClosedIncomingRoute verifies that an appropriate error message will be returned when
|
|
// trying to dequeue a message from a closed route.
|
|
func TestOnClosedIncomingRoute(t *testing.T) {
|
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
|
|
|
factory := consensus.NewFactory()
|
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestOnClosedIncomingRoute")
|
|
if err != nil {
|
|
t.Fatalf("Error setting up test consensus: %+v", err)
|
|
}
|
|
defer teardown(false)
|
|
|
|
sharedRequestedTransactions := transactionrelay.NewSharedRequestedTransactions()
|
|
adapter, err := netadapter.NewNetAdapter(config.DefaultConfig())
|
|
if err != nil {
|
|
t.Fatalf("Failed to creat a NetAdapter : %v", err)
|
|
}
|
|
domainInstance, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), tc.Database())
|
|
if err != nil {
|
|
t.Fatalf("Failed to set up a domain instance: %v", err)
|
|
}
|
|
context := &mocTransactionsRelayContext{
|
|
netAdapter: adapter,
|
|
domain: domainInstance,
|
|
sharedRequestedTransactions: sharedRequestedTransactions,
|
|
}
|
|
incomingRoute := router.NewRoute("incoming")
|
|
outgoingRoute := router.NewRoute("outgoing")
|
|
defer outgoingRoute.Close()
|
|
|
|
txID := externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
|
|
txIDs := []*externalapi.DomainTransactionID{txID}
|
|
|
|
err = incomingRoute.Enqueue(&appmessage.MsgInvTransaction{TxIDs: txIDs})
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err)
|
|
}
|
|
incomingRoute.Close()
|
|
err = transactionrelay.HandleRelayedTransactions(context, incomingRoute, outgoingRoute)
|
|
if err == nil || !errors.Is(err, router.ErrRouteClosed) {
|
|
t.Fatalf("Unexpected error: expected: %v, got : %v", router.ErrRouteClosed, err)
|
|
}
|
|
})
|
|
}
|