From ab89efe3dc3b8221e843922147c6188dc030a518 Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Sun, 2 May 2021 16:16:57 +0300 Subject: [PATCH] Update relayTransactions unit tests. (#1623) * [NOD-1344] relaytransactions: simple unit tests * [NOD-1344] Add mid-complexity unit tests for relaytransactions * Improve TestHandleRelayedTransactionssub tests * Improve TestHandleRequestedTransactions sub tests * [NOD-1344] Fix Simple call test * [NOD-1344] Fix tests after redesign * Divide transactionrelay_test.go to 2 separated tests and updates the tests. * Changes due to review:change the test files name and the test function names, adds new comments and fix typo. * Delete an unnecessary comparison to True in the if statement condition. * Update the branch to v0.11.0-dev. Co-authored-by: karim1king Co-authored-by: tal Co-authored-by: Svarog --- .../handle_relayed_transactions_test.go | 189 ++++++++++++++++++ .../handle_requested_transactions_test.go | 88 ++++++++ 2 files changed, 277 insertions(+) create mode 100644 app/protocol/flows/transactionrelay/handle_relayed_transactions_test.go create mode 100644 app/protocol/flows/transactionrelay/handle_requested_transactions_test.go diff --git a/app/protocol/flows/transactionrelay/handle_relayed_transactions_test.go b/app/protocol/flows/transactionrelay/handle_relayed_transactions_test.go new file mode 100644 index 0000000000..1c4e19360c --- /dev/null +++ b/app/protocol/flows/transactionrelay/handle_relayed_transactions_test.go @@ -0,0 +1,189 @@ +package transactionrelay_test + +import ( + "errors" + "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/infrastructure/logger" + "github.com/kaspanet/kaspad/util/panics" + "strings" + "testing" + + "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) Broadcast(appmessage.Message) 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, 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() + defer incomingRoute.Close() + peerIncomingRoute := router.NewRoute() + 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, 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() + outgoingRoute := router.NewRoute() + 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) + } + }) +} diff --git a/app/protocol/flows/transactionrelay/handle_requested_transactions_test.go b/app/protocol/flows/transactionrelay/handle_requested_transactions_test.go new file mode 100644 index 0000000000..b1d02b74fd --- /dev/null +++ b/app/protocol/flows/transactionrelay/handle_requested_transactions_test.go @@ -0,0 +1,88 @@ +package transactionrelay_test + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay" + "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/infrastructure/config" + "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/kaspanet/kaspad/util/panics" + "github.com/pkg/errors" + "testing" +) + +// TestHandleRequestedTransactionsNotFound tests the flow of HandleRequestedTransactions +// when the requested transactions don't found in the mempool. +func TestHandleRequestedTransactionsNotFound(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, "TestHandleRequestedTransactionsNotFound") + 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, 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() + outgoingRoute := router.NewRoute() + defer outgoingRoute.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} + msg := appmessage.NewMsgRequestTransactions(txIDs) + err = incomingRoute.Enqueue(msg) + if err != nil { + t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err) + } + // The goroutine is representing the peer's actions. + spawn("peerResponseToTheTransactionsMessages", func() { + for i, id := range txIDs { + msg, err := outgoingRoute.Dequeue() + if err != nil { + t.Fatalf("Dequeue: %s", err) + } + outMsg := msg.(*appmessage.MsgTransactionNotFound) + if txIDs[i].String() != outMsg.ID.String() { + t.Fatalf("TestHandleRelayedTransactions: expected equal txID: expected %s, but got %s", txIDs[i].String(), id.String()) + } + } + // Closed the incomingRoute for stop the infinity loop. + incomingRoute.Close() + }) + + err = transactionrelay.HandleRequestedTransactions(context, incomingRoute, outgoingRoute) + // Make sure the error is due to the closed route. + if err == nil || !errors.Is(err, router.ErrRouteClosed) { + t.Fatalf("Unexpected error: expected: %v, got : %v", router.ErrRouteClosed, err) + } + }) +}