package main

import (
	"flag"
	"github.com/exchain/go-exchain/exchain"
	nebulav1 "github.com/exchain/go-exchain/exchain/protocol/gen/go/nebula/v1"
	"google.golang.org/protobuf/proto"
	"log"
	"time"
)

var (
	txCount      = flag.Int("txcount", 100000, "tx count")
	blockTxCount = flag.Int("btx", 10000, "block tx count")
	loopCount    = flag.Int("loopcount", 100, "loop count")
)

// do benchmark test.
func main() {
	flag.Parse()
	if *loopCount <= 0 {
		*loopCount = 1
	}
	// do tx serialize benchmark test.
	if *txCount > 0 {
		benchLimitTx()
		benchMarketTx()
		benchCancelTx()
	}
	if *blockTxCount > 0 {
		benchBlock()
	}
}

func benchLimitTx() {
	count := *txCount
	txs := exchain.TestMakeTxs(nebulav1.TxType_LimitTx, count)
	t1 := time.Now()
	// benchmark limit tx serialize and unserialize.
	for i := 0; i < *loopCount; i++ {
		tx := txs.Txs[i%count]
		d, err := proto.Marshal(tx)
		if err != nil {
			panic(err)
		}
		ntx := new(nebulav1.Transaction)
		err = proto.Unmarshal(d, ntx)
		if ntx.TxType != tx.TxType {
			panic("unserialize tx type error")
		}
	}
	tps := float64(1) * float64(*loopCount) * 1000 / float64(time.Since(t1).Milliseconds())
	log.Printf("limit tx serialize and unserialize cost: %v, tx count:%d, loop count: %d, tps:%f\n", time.Since(t1), count, *loopCount, tps)
}

func benchMarketTx() {
	count := *txCount
	txs := exchain.TestMakeTxs(nebulav1.TxType_MarketTx, count)
	t1 := time.Now()
	// benchmark market tx serialize and unserialize.
	for i := 0; i < *loopCount; i++ {
		tx := txs.Txs[i%count]
		d, err := proto.Marshal(tx)
		if err != nil {
			panic(err)
		}
		ntx := new(nebulav1.Transaction)
		err = proto.Unmarshal(d, ntx)
		if ntx.TxType != tx.TxType {
			panic("unserialize tx type error")
		}
	}
	tps := float64(1) * float64(*loopCount) * 1000 / float64(time.Since(t1).Milliseconds())
	log.Printf("market tx serialize and unserialize cost: %v, tx count:%d, loop count: %d, tps:%f\n", time.Since(t1), count, *loopCount, tps)
}

func benchCancelTx() {
	count := *txCount
	txs := exchain.TestMakeTxs(nebulav1.TxType_CancelTx, count)
	t1 := time.Now()
	// benchmark cancel tx serialize and unserialize.
	for i := 0; i < *loopCount; i++ {
		tx := txs.Txs[i%count]
		d, err := proto.Marshal(tx)
		if err != nil {
			panic(err)
		}
		ntx := new(nebulav1.Transaction)
		err = proto.Unmarshal(d, ntx)
		if ntx.TxType != tx.TxType {
			panic("unserialize tx type error")
		}
	}
	tps := float64(1) * float64(*loopCount) * 1000 / float64(time.Since(t1).Milliseconds())
	log.Printf("cancel tx serialize and unserialize cost: %v, tx count:%d, loop count: %d, tps:%f\n", time.Since(t1), count, *loopCount, tps)
}

func benchBlock() {
	count := *blockTxCount
	blocks := make([]*nebulav1.Block, 0, *loopCount)
	for i := 0; i < *loopCount; i++ {
		blocks = append(blocks, exchain.TestMakeBlock(count))
	}
	t1 := time.Now()
	// benchmark block serialize and unserialize.
	for i := 0; i < *loopCount; i++ {
		b := blocks[i]
		d, err := proto.Marshal(b)
		if err != nil {
			panic(err)
		}
		nb := new(nebulav1.Block)
		err = proto.Unmarshal(d, nb)
		if len(nb.Transactions.Txs) != len(b.Transactions.Txs) {
			panic("unserialize block error")
		}
	}
	tps := float64(1) * float64(*loopCount) * 1000 / float64(time.Since(t1).Milliseconds())
	log.Printf("block serialize and unserialize cost: %v, tx count:%d, loop count: %d, tps:%f\n", time.Since(t1), count, *loopCount, tps)
}
