github.com/theQRL/go-zond@v0.2.1/cmd/devp2p/internal/zondtest/transaction.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package zondtest
    18  
    19  // TODO(now.youtrack.cloud/issue/TGZ-6)
    20  /*
    21  import (
    22  	"errors"
    23  	"fmt"
    24  	"math/big"
    25  	"strings"
    26  	"time"
    27  
    28  	"github.com/theQRL/go-zond/common"
    29  	"github.com/theQRL/go-zond/core/types"
    30  	"github.com/theQRL/go-zond/crypto/pqcrypto"
    31  	"github.com/theQRL/go-zond/internal/utesting"
    32  	"github.com/theQRL/go-zond/params"
    33  )
    34  
    35  // var faucetAddr, _ = common.NewAddressFromString("Z71562b71999873DB5b286dF957af199Ec94617F7")
    36  var faucetKey, _ = pqcrypto.HexToDilithium("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    37  
    38  func (s *Suite) sendSuccessfulTxs(t *utesting.T) error {
    39  	tests := []*types.Transaction{
    40  		getNextTxFromChain(s),
    41  		unknownTx(s),
    42  	}
    43  	for i, tx := range tests {
    44  		if tx == nil {
    45  			return errors.New("could not find tx to send")
    46  		}
    47  		t.Logf("Testing tx propagation %d: sending tx %v %v %v\n", i, tx.Hash().String(), tx.GasPrice(), tx.Gas())
    48  		// get previous tx if exists for reference in case of old tx propagation
    49  		var prevTx *types.Transaction
    50  		if i != 0 {
    51  			prevTx = tests[i-1]
    52  		}
    53  		// write tx to connection
    54  		if err := sendSuccessfulTx(s, tx, prevTx); err != nil {
    55  			return fmt.Errorf("send successful tx test failed: %v", err)
    56  		}
    57  	}
    58  	return nil
    59  }
    60  
    61  func sendSuccessfulTx(s *Suite, tx *types.Transaction, prevTx *types.Transaction) error {
    62  	sendConn, recvConn, err := s.createSendAndRecvConns()
    63  	if err != nil {
    64  		return err
    65  	}
    66  	defer sendConn.Close()
    67  	defer recvConn.Close()
    68  	if err = sendConn.peer(s.chain, nil); err != nil {
    69  		return fmt.Errorf("peering failed: %v", err)
    70  	}
    71  	// Send the transaction
    72  	if err = sendConn.Write(&Transactions{tx}); err != nil {
    73  		return fmt.Errorf("failed to write to connection: %v", err)
    74  	}
    75  	// peer receiving connection to node
    76  	if err = recvConn.peer(s.chain, nil); err != nil {
    77  		return fmt.Errorf("peering failed: %v", err)
    78  	}
    79  
    80  	// update last nonce seen
    81  	nonce = tx.Nonce()
    82  
    83  	// Wait for the transaction announcement
    84  	for {
    85  		switch msg := recvConn.readAndServe(s.chain, timeout).(type) {
    86  		case *Transactions:
    87  			recTxs := *msg
    88  			// if you receive an old tx propagation, read from connection again
    89  			if len(recTxs) == 1 && prevTx != nil {
    90  				if recTxs[0] == prevTx {
    91  					continue
    92  				}
    93  			}
    94  			for _, gotTx := range recTxs {
    95  				if gotTx.Hash() == tx.Hash() {
    96  					// Ok
    97  					return nil
    98  				}
    99  			}
   100  			return fmt.Errorf("missing transaction: got %v missing %v", recTxs, tx.Hash())
   101  		case *NewPooledTransactionHashes66:
   102  			txHashes := *msg
   103  			// if you receive an old tx propagation, read from connection again
   104  			if len(txHashes) == 1 && prevTx != nil {
   105  				if txHashes[0] == prevTx.Hash() {
   106  					continue
   107  				}
   108  			}
   109  			for _, gotHash := range txHashes {
   110  				if gotHash == tx.Hash() {
   111  					// Ok
   112  					return nil
   113  				}
   114  			}
   115  			return fmt.Errorf("missing transaction announcement: got %v missing %v", txHashes, tx.Hash())
   116  		case *NewPooledTransactionHashes:
   117  			txHashes := msg.Hashes
   118  			if len(txHashes) != len(msg.Sizes) {
   119  				return fmt.Errorf("invalid msg size lengths: hashes: %v sizes: %v", len(txHashes), len(msg.Sizes))
   120  			}
   121  			if len(txHashes) != len(msg.Types) {
   122  				return fmt.Errorf("invalid msg type lengths: hashes: %v types: %v", len(txHashes), len(msg.Types))
   123  			}
   124  			// if you receive an old tx propagation, read from connection again
   125  			if len(txHashes) == 1 && prevTx != nil {
   126  				if txHashes[0] == prevTx.Hash() {
   127  					continue
   128  				}
   129  			}
   130  			for index, gotHash := range txHashes {
   131  				if gotHash == tx.Hash() {
   132  					if msg.Sizes[index] != uint32(tx.Size()) {
   133  						return fmt.Errorf("invalid tx size: got %v want %v", msg.Sizes[index], tx.Size())
   134  					}
   135  					if msg.Types[index] != tx.Type() {
   136  						return fmt.Errorf("invalid tx type: got %v want %v", msg.Types[index], tx.Type())
   137  					}
   138  					// Ok
   139  					return nil
   140  				}
   141  			}
   142  			return fmt.Errorf("missing transaction announcement: got %v missing %v", txHashes, tx.Hash())
   143  
   144  		default:
   145  			return fmt.Errorf("unexpected message in sendSuccessfulTx: %s", pretty.Sdump(msg))
   146  		}
   147  	}
   148  }
   149  
   150  func (s *Suite) sendMaliciousTxs(t *utesting.T) error {
   151  	badTxs := []*types.Transaction{
   152  		getOldTxFromChain(s),
   153  		invalidNonceTx(s),
   154  		hugeAmount(s),
   155  		hugeGasPrice(s),
   156  		hugeData(s),
   157  	}
   158  
   159  	// setup receiving connection before sending malicious txs
   160  	recvConn, err := s.dial()
   161  	if err != nil {
   162  		return fmt.Errorf("dial failed: %v", err)
   163  	}
   164  	defer recvConn.Close()
   165  	if err = recvConn.peer(s.chain, nil); err != nil {
   166  		return fmt.Errorf("peering failed: %v", err)
   167  	}
   168  
   169  	for i, tx := range badTxs {
   170  		t.Logf("Testing malicious tx propagation: %v\n", i)
   171  		if err = sendMaliciousTx(s, tx); err != nil {
   172  			return fmt.Errorf("malicious tx test failed:\ntx: %v\nerror: %v", tx, err)
   173  		}
   174  	}
   175  	// check to make sure bad txs aren't propagated
   176  	return checkMaliciousTxPropagation(s, badTxs, recvConn)
   177  }
   178  
   179  func sendMaliciousTx(s *Suite, tx *types.Transaction) error {
   180  	conn, err := s.dial()
   181  	if err != nil {
   182  		return fmt.Errorf("dial failed: %v", err)
   183  	}
   184  	defer conn.Close()
   185  	if err = conn.peer(s.chain, nil); err != nil {
   186  		return fmt.Errorf("peering failed: %v", err)
   187  	}
   188  
   189  	// write malicious tx
   190  	if err = conn.Write(&Transactions{tx}); err != nil {
   191  		return fmt.Errorf("failed to write to connection: %v", err)
   192  	}
   193  	return nil
   194  }
   195  
   196  var nonce = uint64(99)
   197  
   198  // sendMultipleSuccessfulTxs sends the given transactions to the node and
   199  // expects the node to accept and propagate them.
   200  func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, txs []*types.Transaction) error {
   201  	txMsg := Transactions(txs)
   202  	t.Logf("sending %d txs\n", len(txs))
   203  
   204  	sendConn, recvConn, err := s.createSendAndRecvConns()
   205  	if err != nil {
   206  		return err
   207  	}
   208  	defer sendConn.Close()
   209  	defer recvConn.Close()
   210  	if err = sendConn.peer(s.chain, nil); err != nil {
   211  		return fmt.Errorf("peering failed: %v", err)
   212  	}
   213  	if err = recvConn.peer(s.chain, nil); err != nil {
   214  		return fmt.Errorf("peering failed: %v", err)
   215  	}
   216  
   217  	// Send the transactions
   218  	if err = sendConn.Write(&txMsg); err != nil {
   219  		return fmt.Errorf("failed to write message to connection: %v", err)
   220  	}
   221  
   222  	// update nonce
   223  	nonce = txs[len(txs)-1].Nonce()
   224  
   225  	// Wait for the transaction announcement(s) and make sure all sent txs are being propagated.
   226  	// all txs should be announced within a couple announcements.
   227  	recvHashes := make([]common.Hash, 0)
   228  
   229  	for i := 0; i < 20; i++ {
   230  		switch msg := recvConn.readAndServe(s.chain, timeout).(type) {
   231  		case *Transactions:
   232  			for _, tx := range *msg {
   233  				recvHashes = append(recvHashes, tx.Hash())
   234  			}
   235  		case *NewPooledTransactionHashes66:
   236  			recvHashes = append(recvHashes, *msg...)
   237  		case *NewPooledTransactionHashes:
   238  			recvHashes = append(recvHashes, msg.Hashes...)
   239  		default:
   240  			if !strings.Contains(pretty.Sdump(msg), "i/o timeout") {
   241  				return fmt.Errorf("unexpected message while waiting to receive txs: %s", pretty.Sdump(msg))
   242  			}
   243  		}
   244  		// break once all 2000 txs have been received
   245  		if len(recvHashes) == 2000 {
   246  			break
   247  		}
   248  		if len(recvHashes) > 0 {
   249  			_, missingTxs := compareReceivedTxs(recvHashes, txs)
   250  			if len(missingTxs) > 0 {
   251  				continue
   252  			} else {
   253  				t.Logf("successfully received all %d txs", len(txs))
   254  				return nil
   255  			}
   256  		}
   257  	}
   258  	_, missingTxs := compareReceivedTxs(recvHashes, txs)
   259  	if len(missingTxs) > 0 {
   260  		for _, missing := range missingTxs {
   261  			t.Logf("missing tx: %v", missing.Hash())
   262  		}
   263  		return fmt.Errorf("missing %d txs", len(missingTxs))
   264  	}
   265  	return nil
   266  }
   267  
   268  // checkMaliciousTxPropagation checks whether the given malicious transactions were
   269  // propagated by the node.
   270  func checkMaliciousTxPropagation(s *Suite, txs []*types.Transaction, conn *Conn) error {
   271  	switch msg := conn.readAndServe(s.chain, time.Second*8).(type) {
   272  	case *Transactions:
   273  		// check to see if any of the failing txs were in the announcement
   274  		recvTxs := make([]common.Hash, len(*msg))
   275  		for i, recvTx := range *msg {
   276  			recvTxs[i] = recvTx.Hash()
   277  		}
   278  		badTxs, _ := compareReceivedTxs(recvTxs, txs)
   279  		if len(badTxs) > 0 {
   280  			return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs)
   281  		}
   282  	case *NewPooledTransactionHashes66:
   283  		badTxs, _ := compareReceivedTxs(*msg, txs)
   284  		if len(badTxs) > 0 {
   285  			return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs)
   286  		}
   287  	case *NewPooledTransactionHashes:
   288  		badTxs, _ := compareReceivedTxs(msg.Hashes, txs)
   289  		if len(badTxs) > 0 {
   290  			return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs)
   291  		}
   292  	case *Error:
   293  		// Transaction should not be announced -> wait for timeout
   294  		return nil
   295  	default:
   296  		return fmt.Errorf("unexpected message in sendFailingTx: %s", pretty.Sdump(msg))
   297  	}
   298  	return nil
   299  }
   300  
   301  // compareReceivedTxs compares the received set of txs against the given set of txs,
   302  // returning both the set received txs that were present within the given txs, and
   303  // the set of txs that were missing from the set of received txs
   304  func compareReceivedTxs(recvTxs []common.Hash, txs []*types.Transaction) (present []*types.Transaction, missing []*types.Transaction) {
   305  	// create a map of the hashes received from node
   306  	recvHashes := make(map[common.Hash]common.Hash)
   307  	for _, hash := range recvTxs {
   308  		recvHashes[hash] = hash
   309  	}
   310  
   311  	// collect present txs and missing txs separately
   312  	present = make([]*types.Transaction, 0)
   313  	missing = make([]*types.Transaction, 0)
   314  	for _, tx := range txs {
   315  		if _, exists := recvHashes[tx.Hash()]; exists {
   316  			present = append(present, tx)
   317  		} else {
   318  			missing = append(missing, tx)
   319  		}
   320  	}
   321  	return present, missing
   322  }
   323  
   324  func unknownTx(s *Suite) *types.Transaction {
   325  	tx := getNextTxFromChain(s)
   326  	if tx == nil {
   327  		return nil
   328  	}
   329  	var to common.Address
   330  	if tx.To() != nil {
   331  		to = *tx.To()
   332  	}
   333  	txNew := types.NewTx(&types.DynamicFeeTx{
   334  		Nonce: tx.Nonce() + 1,
   335  		To:    &to,
   336  		Value: tx.Value(),
   337  		Gas:   tx.Gas(),
   338  		GasFeeCap: tx.GasPrice(),
   339  		Data:  tx.Data(),
   340  	})
   341  	return signWithFaucet(s.chain.chainConfig, txNew)
   342  }
   343  
   344  func getNextTxFromChain(s *Suite) *types.Transaction {
   345  	// Get a new transaction
   346  	for _, blocks := range s.fullChain.blocks[s.chain.Len():] {
   347  		txs := blocks.Transactions()
   348  		if txs.Len() != 0 {
   349  			return txs[0]
   350  		}
   351  	}
   352  	return nil
   353  }
   354  
   355  func generateTxs(s *Suite, numTxs int) (map[common.Hash]common.Hash, []*types.Transaction, error) {
   356  	txHashMap := make(map[common.Hash]common.Hash, numTxs)
   357  	txs := make([]*types.Transaction, numTxs)
   358  
   359  	nextTx := getNextTxFromChain(s)
   360  	if nextTx == nil {
   361  		return nil, nil, errors.New("failed to get the next transaction")
   362  	}
   363  	gas := nextTx.Gas()
   364  
   365  	nonce = nonce + 1
   366  	// generate txs
   367  	for i := 0; i < numTxs; i++ {
   368  		tx := generateTx(s.chain.chainConfig, nonce, gas)
   369  		if tx == nil {
   370  			return nil, nil, errors.New("failed to get the next transaction")
   371  		}
   372  		txHashMap[tx.Hash()] = tx.Hash()
   373  		txs[i] = tx
   374  		nonce = nonce + 1
   375  	}
   376  	return txHashMap, txs, nil
   377  }
   378  
   379  func generateTx(chainConfig *params.ChainConfig, nonce uint64, gas uint64) *types.Transaction {
   380  	var to common.Address
   381  	tx := types.NewTx(&types.DynamicFeeTx{
   382  		Nonce: nonce,
   383  		To:    &to,
   384  		Value: big.NewInt(1),
   385  		Gas:   gas,
   386  		GasFeeCap: big.NewInt(1),
   387  		Data:  []byte{},
   388  	})
   389  	return signWithFaucet(chainConfig, tx)
   390  }
   391  
   392  func getOldTxFromChain(s *Suite) *types.Transaction {
   393  	for _, blocks := range s.fullChain.blocks[:s.chain.Len()-1] {
   394  		txs := blocks.Transactions()
   395  		if txs.Len() != 0 {
   396  			return txs[0]
   397  		}
   398  	}
   399  	return nil
   400  }
   401  
   402  func invalidNonceTx(s *Suite) *types.Transaction {
   403  	tx := getNextTxFromChain(s)
   404  	if tx == nil {
   405  		return nil
   406  	}
   407  	var to common.Address
   408  	if tx.To() != nil {
   409  		to = *tx.To()
   410  	}
   411  	txNew := types.NewTx(&types.DynamicFeeTx{
   412  		Nonce: tx.Nonce() - 2,
   413  		To:    &to,
   414  		Value: tx.Value(),
   415  		Gas:   tx.Gas(),
   416  		GasFeeCap: tx.GasPrice(),
   417  		Data:  tx.Data(),
   418  	})
   419  	return signWithFaucet(s.chain.chainConfig, txNew)
   420  }
   421  
   422  func hugeAmount(s *Suite) *types.Transaction {
   423  	tx := getNextTxFromChain(s)
   424  	if tx == nil {
   425  		return nil
   426  	}
   427  	amount := largeNumber(2)
   428  	var to common.Address
   429  	if tx.To() != nil {
   430  		to = *tx.To()
   431  	}
   432  	txNew := types.NewTx(&types.DynamicFeeTx{
   433  		Nonce: tx.Nonce(),
   434  		To:    &to,
   435  		Value: amount,
   436  		Gas:   tx.Gas(),
   437  		GasFeeCap: tx.GasPrice(),
   438  		Data:  tx.Data(),
   439  	})
   440  	return signWithFaucet(s.chain.chainConfig, txNew)
   441  }
   442  
   443  func hugeGasPrice(s *Suite) *types.Transaction {
   444  	tx := getNextTxFromChain(s)
   445  	if tx == nil {
   446  		return nil
   447  	}
   448  	gasPrice := largeNumber(2)
   449  	var to common.Address
   450  	if tx.To() != nil {
   451  		to = *tx.To()
   452  	}
   453  	txNew := types.NewTx(&types.DynamicFeeTx{
   454  		Nonce:     tx.Nonce(),
   455  		To:        &to,
   456  		Value:     tx.Value(),
   457  		Gas:       tx.Gas(),
   458  		GasFeeCap: gasPrice,
   459  		Data:      tx.Data(),
   460  	})
   461  	return signWithFaucet(s.chain.chainConfig, txNew)
   462  }
   463  
   464  func hugeData(s *Suite) *types.Transaction {
   465  	tx := getNextTxFromChain(s)
   466  	if tx == nil {
   467  		return nil
   468  	}
   469  	var to common.Address
   470  	if tx.To() != nil {
   471  		to = *tx.To()
   472  	}
   473  	txNew := types.NewTx(&types.DynamicFeeTx{
   474  		Nonce: tx.Nonce(),
   475  		To:    &to,
   476  		Value: tx.Value(),
   477  		Gas:   tx.Gas(),
   478  		GasFeeCap: tx.GasPrice(),
   479  		Data:  largeBuffer(2),
   480  	})
   481  	return signWithFaucet(s.chain.chainConfig, txNew)
   482  }
   483  
   484  func signWithFaucet(chainConfig *params.ChainConfig, tx *types.Transaction) *types.Transaction {
   485  	signer := types.LatestSigner(chainConfig)
   486  	signedTx, err := types.SignTx(tx, signer, faucetKey)
   487  	if err != nil {
   488  		return nil
   489  	}
   490  	return signedTx
   491  }
   492  */