github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/cmd/dummytx/dummytx.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"crypto/ecdsa"
     6  	"crypto/rand"
     7  	common2 "github.com/bigzoro/my_simplechain/cmd/dummytx/common"
     8  	"github.com/bigzoro/my_simplechain/cmd/dummytx/config"
     9  	"log"
    10  	"math/big"
    11  	"strconv"
    12  	"time"
    13  
    14  	"github.com/bigzoro/my_simplechain/common"
    15  	"github.com/bigzoro/my_simplechain/core/types"
    16  	"github.com/bigzoro/my_simplechain/crypto"
    17  	"github.com/bigzoro/my_simplechain/ethclient"
    18  )
    19  
    20  const (
    21  	warnPrefix = "\x1b[93mwarn:\x1b[0m"
    22  	errPrefix  = "\x1b[91merror:\x1b[0m"
    23  )
    24  
    25  func init() {
    26  	log.SetFlags(log.Lshortfile | log.LstdFlags)
    27  }
    28  
    29  type Sender struct {
    30  	url           string
    31  	keyFile       string
    32  	certFile      string
    33  	rootCAFile    []string
    34  	ctx           context.Context
    35  	client        *ethclient.Client
    36  	senders       []common.Address
    37  	pks           []*ecdsa.PrivateKey
    38  	receiver      common.Address
    39  	gasPrice      *big.Int
    40  	gasLimit      *big.Int
    41  	dummyInternal int64
    42  	chainID       string
    43  	txsCount      int64
    44  	signal        chan bool
    45  	firstNonce    uint64
    46  }
    47  
    48  func newSender(ctx context.Context, config *config.Config, txsCount int64) *Sender {
    49  	var s = &Sender{
    50  		url:           config.SipeAddr,
    51  		keyFile:       config.PrivateKey,
    52  		certFile:      config.Cert,
    53  		rootCAFile:    config.CACerts,
    54  		ctx:           ctx,
    55  		receiver:      common.HexToAddress(config.Receiver),
    56  		gasPrice:      big.NewInt(config.GasPrice),
    57  		gasLimit:      big.NewInt(config.GasPriceLimit),
    58  		dummyInternal: config.DummyInternal,
    59  		txsCount:      txsCount,
    60  		chainID:       config.ChainId,
    61  		signal:        make(chan bool, 1),
    62  	}
    63  
    64  	for i, pk := range config.SenderPrivateKey {
    65  		key, err := common2.GetKey(pk, config.SenderPrivateKeyPassword[i])
    66  		if err != nil {
    67  			log.Fatalf(errPrefix+" get private key file: %v", err)
    68  		}
    69  		privateKey := key.PrivateKey
    70  		s.pks = append(s.pks, privateKey)
    71  		publicKey := privateKey.Public()
    72  		publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
    73  		if !ok {
    74  			log.Fatalf(errPrefix + " cannot assert type: publicKey is not of type *ecdsa.PublicKey")
    75  		}
    76  		fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
    77  		log.Printf("sender:%d %s\n", i, fromAddress.String())
    78  
    79  		s.senders = append(s.senders, fromAddress)
    80  	}
    81  	return s
    82  }
    83  
    84  func (s *Sender) connect() {
    85  	client, err := ethclient.Dial(s.url, s.certFile, s.keyFile, s.rootCAFile)
    86  	if err != nil {
    87  		log.Fatalf(errPrefix+" connect %s: %v", s.url, err)
    88  	}
    89  
    90  	s.client = client
    91  }
    92  
    93  func (s *Sender) dummyTx() {
    94  	gasPrice, err := s.client.SuggestGasPrice(s.ctx)
    95  	if err != nil {
    96  		log.Fatalf(errPrefix+" get gas price: %v", err)
    97  	}
    98  	s.gasPrice = gasPrice
    99  
   100  	for i, sender := range s.senders {
   101  		go s.loopSendTxsByNum(i, sender)
   102  	}
   103  }
   104  
   105  func (s *Sender) claimFunds() {
   106  	value := new(big.Int).Mul(big.NewInt(10000), big.NewInt(1)) // in wei (10000 eth)
   107  	for i, sender := range s.senders {
   108  		nonce, err := s.client.PendingNonceAt(s.ctx, sender)
   109  		if err != nil {
   110  			log.Fatalf(errPrefix+" get new nonce: %v", err)
   111  		}
   112  		tx := types.NewTransaction(nonce, sender, value, s.gasLimit.Uint64(), s.gasPrice, nil)
   113  		//Remove signature for POA test
   114  		chainID, err := strconv.ParseInt(s.chainID, 10, 64)
   115  		if err != nil {
   116  			log.Fatalf(errPrefix+"chainid transfer failed %v", err)
   117  		}
   118  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(new(big.Int).SetInt64(chainID)), s.pks[i])
   119  		if err != nil {
   120  			log.Fatalf(errPrefix+" sign tx in claimFunds: %v", err)
   121  		}
   122  		err = s.client.SendTransaction(s.ctx, signedTx)
   123  		if err != nil {
   124  			log.Fatalf(errPrefix+" sign tx in claimFunds: %v", err)
   125  		}
   126  		nonce++
   127  	}
   128  	log.Printf("waiting %v seconds for claim funds txs finalize to block...\n", s.dummyInternal)
   129  	time.Sleep(time.Duration(s.dummyInternal) * time.Second)
   130  }
   131  
   132  func (s *Sender) loopSendTxsByNum(index int, fromAddress common.Address) {
   133  	nonce, err := s.client.PendingNonceAt(s.ctx, fromAddress)
   134  	if err != nil {
   135  		log.Fatalf(errPrefix+" get new nonce: %v", err)
   136  	}
   137  	s.firstNonce = nonce
   138  	for i := 0; i < int(s.txsCount); i++ {
   139  		go s.sendTx(nonce+uint64(i), index, fromAddress)
   140  	}
   141  }
   142  
   143  func (s *Sender) sendTx(nonce uint64, index int, fromAddress common.Address) {
   144  	var (
   145  		data [20 + 64]byte
   146  	)
   147  	copy(data[:], fromAddress.Bytes())
   148  	_, _ = rand.Read(data[20:]) //hash
   149  	s.sendDummyTx(nonce, data[:], fromAddress, index)
   150  }
   151  
   152  func (s *Sender) sendDummyTx(nonce uint64, data []byte, fromAddress common.Address, index int) {
   153  	tx := types.NewTransaction(nonce, fromAddress, big.NewInt(0), s.gasLimit.Uint64(), s.gasPrice, data)
   154  	//Remove signature for POA test
   155  	chainID, err := strconv.ParseInt(s.chainID, 10, 64)
   156  	if err != nil {
   157  		log.Fatalf(errPrefix+"chainid transfer failed %v", err)
   158  	}
   159  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(new(big.Int).SetInt64(chainID)), s.pks[index])
   160  	if err != nil {
   161  		log.Fatalf(errPrefix+"sign tx: %v", err)
   162  	}
   163  	err = s.client.SendTransaction(s.ctx, signedTx)
   164  	if err != nil {
   165  		log.Printf(warnPrefix+" send tx: %v", err)
   166  	}
   167  }
   168  
   169  func (s *Sender) calcTotalCount(ctx context.Context) {
   170  	heads := make(chan *types.Header, 1)
   171  	sub, err := s.client.SubscribeNewHead(context.Background(), heads)
   172  	if err != nil {
   173  		log.Fatalf(errPrefix+"Failed to subscribe to head events %v", err)
   174  	}
   175  	defer sub.Unsubscribe()
   176  
   177  	var (
   178  		txsCount           uint
   179  		finalCount         uint64
   180  		start              = time.Now()
   181  		calcTotalCountExit = func(txsCount uint64, seconds float64) {
   182  			log.Printf("total finalize %v txs in %v seconds, %v txs/s", txsCount, seconds, float64(txsCount)/seconds)
   183  		}
   184  	)
   185  	for {
   186  		select {
   187  		case <-ctx.Done():
   188  			calcTotalCountExit(finalCount, time.Since(start).Seconds())
   189  			s.signal <- true
   190  			return
   191  		case head := <-heads:
   192  			txsCount, err = s.client.TransactionCount(ctx, head.Hash())
   193  			if err != nil {
   194  				log.Printf(warnPrefix+"get txCount of block %v: %v", head.Hash(), err)
   195  			}
   196  
   197  			log.Printf("Time %8.2fs\tblock Number %6d\ttxCount %6d", time.Since(start).Seconds(), head.Number.Uint64(), txsCount)
   198  
   199  			finalCount += uint64(txsCount)
   200  			nonce, err := s.client.NonceAt(s.ctx, s.senders[0], big.NewInt(int64(head.Number.Uint64())))
   201  			if err != nil {
   202  				continue
   203  			}
   204  			if s.firstNonce+uint64(s.txsCount) == nonce {
   205  				calcTotalCountExit(finalCount, time.Since(start).Seconds())
   206  				s.signal <- true
   207  				return
   208  			}
   209  		default:
   210  			//do nothing
   211  		}
   212  	}
   213  }