From 9f42d25a2f5d2faee6089167e7cf726f351bcdc6 Mon Sep 17 00:00:00 2001 From: Luca Moser <moser.luca@gmail.com> Date: Sun, 14 Jun 2020 14:25:36 +0200 Subject: [PATCH] check transaction availability in partition --- .../tester/framework/framework.go | 4 +- .../consensus/consensus_conflicts_test.go | 48 ++++++++++++++++--- .../tester/tests/testutil.go | 32 +++++++++++-- 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/tools/integration-tests/tester/framework/framework.go b/tools/integration-tests/tester/framework/framework.go index 4c19cc4a..f246f21f 100644 --- a/tools/integration-tests/tester/framework/framework.go +++ b/tools/integration-tests/tester/framework/framework.go @@ -80,7 +80,7 @@ func (f *Framework) CreateNetwork(name string, peers int, minimumNeighbors int, // create peers/GoShimmer nodes for i := 0; i < peers; i++ { config := GoShimmerConfig{ - Bootstrap: true, + Bootstrap: i == 0, BootstrapInitialIssuanceTimePeriodSec: bootstrapInitialIssuanceTimePeriodSec, Faucet: i == 0, } @@ -128,7 +128,7 @@ func (f *Framework) CreateNetworkWithPartitions(name string, peers, partitions, // create peers/GoShimmer nodes for i := 0; i < peers; i++ { - config := GoShimmerConfig{Bootstrap: true} + config := GoShimmerConfig{Bootstrap: i == 0} if _, err = network.CreatePeer(config); err != nil { return nil, err } diff --git a/tools/integration-tests/tester/tests/consensus/consensus_conflicts_test.go b/tools/integration-tests/tester/tests/consensus/consensus_conflicts_test.go index 1c22d2e5..842e4780 100644 --- a/tools/integration-tests/tester/tests/consensus/consensus_conflicts_test.go +++ b/tools/integration-tests/tester/tests/consensus/consensus_conflicts_test.go @@ -21,14 +21,19 @@ import ( // TestConsensusConflicts issues valid conflicting value objects and makes sure that // the conflicts are resolved via FPC. func TestConsensusConflicts(t *testing.T) { - n, err := f.CreateNetworkWithPartitions("consensus_TestConsensusConflicts", 8, 2, 2) + n, err := f.CreateNetworkWithPartitions("consensus_TestConsensusConflicts", 8, 2, 4) require.NoError(t, err) defer tests.ShutdownNetwork(t, n) time.Sleep(10 * time.Second) // split the network - //assert.NoError(t, n.Split(n.Peers()[:len(n.Peers())/2], n.Peers()[len(n.Peers())/2:])) + for i, partition := range n.Partitions() { + log.Printf("partition %d peers:", i) + for _, p := range partition.Peers() { + log.Println(p.ID().String()) + } + } // genesis wallet genesisSeedBytes, err := base58.Decode("7R1itJx5hVuo9w9hjg5cwKFmek4HMSoBDgJZN8hKGxih") @@ -44,6 +49,8 @@ func TestConsensusConflicts(t *testing.T) { conflictingTxIDs := make([]string, len(n.Partitions())) receiverWallets := make([]*wallet.Wallet, len(n.Partitions())) for i, partition := range n.Partitions() { + + // create a new receiver wallet for the given partition partitionReceiverWallet := wallet.New() destAddr := partitionReceiverWallet.Seed().Address(0) receiverWallets[i] = partitionReceiverWallet @@ -56,9 +63,27 @@ func TestConsensusConflicts(t *testing.T) { })) tx = tx.Sign(signaturescheme.ED25519(*genesisWallet.Seed().KeyPair(0))) conflictingTxs[i] = tx - conflictingTxIDs[i] = tx.ID().String() - log.Println("issuing conflict transaction on partition", i, tx.ID().String()) - _, err := partition.Peers()[0].SendTransaction(tx.Bytes()) + + // issue the transaction on the first peer of the partition + issuerPeer := partition.Peers()[0] + txID, err := issuerPeer.SendTransaction(tx.Bytes()) + conflictingTxIDs[i] = txID + log.Printf("issued conflict transaction %s on partition %d on peer %s", txID, i, issuerPeer.ID().String()) + assert.NoError(t, err) + + // check that the transaction is actually available on all the peers of the partition + missing, err := tests.AwaitTransactionAvailability(partition.Peers(), []string{txID}, 4*time.Second) + if err != nil { + assert.NoError(t, err, "transactions should have been available in partition") + for p, missingOnPeer := range missing { + log.Printf("missing on peer %s:", p) + for missingTx := range missingOnPeer { + log.Println("tx id: ", missingTx) + } + } + return + } + require.NoError(t, err) } @@ -78,8 +103,17 @@ func TestConsensusConflicts(t *testing.T) { } log.Println("waiting for transactions to be available on all peers...") - err = tests.AwaitTransactionAvailability(n.Peers(), conflictingTxIDs, 30*time.Second) - assert.NoError(t, err, "transactions should have been available") + missing, err := tests.AwaitTransactionAvailability(n.Peers(), conflictingTxIDs, 30*time.Second) + if err != nil { + assert.NoError(t, err, "transactions should have been available") + for p, missingOnPeer := range missing { + log.Printf("missing on peer %s:", p) + for missingTx := range missingOnPeer { + log.Println("tx id: ", missingTx) + } + } + return + } expectations := map[string]*tests.ExpectedTransaction{} for _, conflictingTx := range conflictingTxs { diff --git a/tools/integration-tests/tester/tests/testutil.go b/tools/integration-tests/tester/tests/testutil.go index 38cee7a2..65ff8628 100644 --- a/tools/integration-tests/tester/tests/testutil.go +++ b/tools/integration-tests/tester/tests/testutil.go @@ -16,6 +16,7 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/messagelayer/payload" "github.com/iotaledger/goshimmer/plugins/webapi/value/utils" "github.com/iotaledger/goshimmer/tools/integration-tests/tester/framework" + "github.com/iotaledger/hive.go/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -456,10 +457,13 @@ func CheckTransactions(t *testing.T, peers []*framework.Peer, transactionIDs map } // AwaitTransactionAvailability awaits until the given transaction IDs become available on all given peers or -// the max duration is reached. -func AwaitTransactionAvailability(peers []*framework.Peer, transactionIDs []string, maxAwait time.Duration) error { +// the max duration is reached. Returns a map of missing transactions per peer. An error is returned if at least +// one peer does not have all specified transactions available. +func AwaitTransactionAvailability(peers []*framework.Peer, transactionIDs []string, maxAwait time.Duration) (missing map[string]map[string]types.Empty, err error) { s := time.Now() - for ; time.Since(s) < maxAwait; { + var missingMu sync.Mutex + missing = map[string]map[string]types.Empty{} + for ; time.Since(s) < maxAwait; time.Sleep(1 * time.Second) { var wg sync.WaitGroup wg.Add(len(peers)) counter := int32(len(peers) * len(transactionIDs)) @@ -469,18 +473,36 @@ func AwaitTransactionAvailability(peers []*framework.Peer, transactionIDs []stri for _, txID := range transactionIDs { _, err := p.GetTransactionByID(txID) if err == nil { + missingMu.Lock() + m, has := missing[p.ID().String()] + if has { + delete(m, txID) + if len(m) == 0 { + delete(missing, p.ID().String()) + } + } + missingMu.Unlock() atomic.AddInt32(&counter, -1) + continue } + missingMu.Lock() + m, has := missing[p.ID().String()] + if !has { + m = map[string]types.Empty{} + } + m[txID] = types.Empty{} + missing[p.ID().String()] = m + missingMu.Unlock() } }(p) } wg.Wait() if counter == 0 { // everything available - return nil + return missing, nil } } - return ErrTransactionNotAvailableInTime + return missing, ErrTransactionNotAvailableInTime } // ShutdownNetwork shuts down the network and reports errors. -- GitLab