github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/cmd/ctool/core/tx_stability.go (about) 1 package core 2 3 import ( 4 "crypto/ecdsa" 5 "encoding/gob" 6 "encoding/json" 7 "fmt" 8 "github.com/PlatONnetwork/PlatON-Go/core/types" 9 "github.com/PlatONnetwork/PlatON-Go/crypto" 10 "github.com/PlatONnetwork/PlatON-Go/crypto/secp256k1" 11 "gopkg.in/urfave/cli.v1" 12 "io/ioutil" 13 "math/rand" 14 "os" 15 "path/filepath" 16 "sync" 17 "time" 18 ) 19 20 var ( 21 accountPool = make(map[string]*PriAccount) 22 StressTransferValue = 1000 23 txCh = make(chan *types.Transaction, 10) 24 wg = &sync.WaitGroup{} 25 26 DefaultPrivateKeyFilePath = "./test/privateKeys.txt" 27 DefaultAccountAddrFilePath = "./test/addr.json" 28 29 StabilityCmd = cli.Command{ 30 Name: "stability", 31 Aliases: []string{"stab"}, 32 Usage: "start stability test ", 33 Action: stabilityTest, 34 Flags: stabilityCmdFlags, 35 } 36 StabPrepareCmd = cli.Command{ 37 Name: "prepare", 38 Aliases: []string{"pre"}, 39 Usage: "prepare some accounts are used for stability test ", 40 Action: prepareAccount, 41 Flags: stabPrepareCmdFlags, 42 } 43 ) 44 45 func prepareAccount(c *cli.Context) { 46 pkFile := c.String(PKFilePathFlag.Name) 47 size := c.Int(AccountSizeFlag.Name) 48 value := c.String(TransferValueFlag.Name) 49 50 parseConfigJson(c.String(ConfigPathFlag.Name)) 51 52 err := PrepareAccount(size, pkFile, value) 53 if err != nil { 54 panic(fmt.Errorf("send raw transaction error,%s", err.Error())) 55 } 56 } 57 58 func stabilityTest(c *cli.Context) { 59 pkFile := c.String(PKFilePathFlag.Name) 60 times := c.Int(StabExecTimesFlag.Name) 61 interval := c.Int(SendTxIntervalFlag.Name) 62 63 parseConfigJson(c.String(ConfigPathFlag.Name)) 64 65 err := StabilityTest(pkFile, times, interval) 66 if err != nil { 67 panic(fmt.Errorf("stress test error,%s", err.Error())) 68 } 69 } 70 71 type PriAccount struct { 72 Priv *ecdsa.PrivateKey 73 Nonce uint64 74 } 75 76 func generateAccount(size int, pkFile string) { 77 addrs := make([]string, size) 78 for i := 0; i < size; i++ { 79 privateKey, _ := crypto.GenerateKey() 80 address := crypto.PubkeyToAddress(privateKey.PublicKey).Hex() 81 accountPool[address] = &PriAccount{privateKey, 0} 82 addrs[i] = address 83 } 84 savePrivateKeyPool(pkFile) 85 saveAddrs(addrs, pkFile) 86 } 87 88 func savePrivateKeyPool(pkFile string) { 89 if pkFile == "" { 90 pkFile = DefaultPrivateKeyFilePath 91 } 92 gob.Register(&secp256k1.BitCurve{}) 93 file, err := os.Create(pkFile) 94 if err != nil { 95 panic(fmt.Errorf("save private key err,%s,%s", pkFile, err.Error())) 96 } 97 os.Truncate(pkFile, 0) 98 enc := gob.NewEncoder(file) 99 err = enc.Encode(accountPool) 100 if err != nil { 101 panic(err.Error()) 102 } 103 } 104 105 func saveAddrs(addrs []string, pkFile string) { 106 addrsPath := DefaultAccountAddrFilePath 107 if pkFile != "" { 108 addrsPath = filepath.Dir(pkFile) + "/addr.json" 109 } 110 os.Truncate(DefaultAccountAddrFilePath, 0) 111 byts, err := json.MarshalIndent(addrs, "", "\t") 112 _, err = os.Create(addrsPath) 113 if err != nil { 114 panic(fmt.Errorf("create addr.json error%s \n", err.Error())) 115 } 116 err = ioutil.WriteFile(addrsPath, byts, 0644) 117 if err != nil { 118 panic(fmt.Errorf("write to addr.json error%s \n", err.Error())) 119 } 120 } 121 122 func PrepareAccount(size int, pkFile, value string) error { 123 124 if len(accountPool) == 0 { 125 generateAccount(size, pkFile) 126 } 127 128 for addr := range accountPool { 129 hash, err := SendTransaction("", addr, value) 130 if err != nil { 131 return fmt.Errorf("prepare error,send from coinbase error,%s", err.Error()) 132 } 133 fmt.Printf("transfer hash: %s \n", hash) 134 } 135 fmt.Printf("prepare %d account finish...", size) 136 return nil 137 } 138 139 func StabilityTest(pkFile string, times, interval int) error { 140 if len(accountPool) == 0 { 141 parsePkFile(pkFile) 142 } 143 144 addrs := getAllAddress(pkFile) 145 146 for i := 0; i < times; i++ { 147 if interval != 0 { 148 time.Sleep(time.Duration(interval) * time.Millisecond) 149 } 150 from, to := getRandomAddr(addrs) 151 if from == "" || to == "" { 152 continue 153 } 154 155 acc, ok := accountPool[from] 156 if !ok { 157 return fmt.Errorf("private key not found,addr:%s", from) 158 } 159 160 wg.Add(1) 161 go getTransactionGo(acc, from, to) 162 163 wg.Add(1) 164 go sendTransactionGo() 165 } 166 167 wg.Wait() 168 169 savePrivateKeyPool(pkFile) 170 171 return nil 172 } 173 174 func sendTransactionGo() { 175 defer func() { 176 if err := recover(); err != nil { 177 fmt.Printf("send raw transaction failed:%s \n", err) 178 //debug.PrintStack() 179 wg.Done() 180 } 181 }() 182 183 hash, _ := sendRawTransaction(<-txCh) 184 fmt.Printf("tx hash:%s\n", hash) 185 wg.Done() 186 } 187 188 func getTransactionGo(acc *PriAccount, from, to string) { 189 defer func() { 190 if err := recover(); err != nil { 191 fmt.Println("get transaction error:", err) 192 //debug.PrintStack() 193 wg.Done() 194 } 195 }() 196 197 newTx := getSignedTransaction(from, to, int64(StressTransferValue), acc.Priv, acc.Nonce) 198 lock := &sync.Mutex{} 199 lock.Lock() 200 201 acc.Nonce++ 202 fmt.Printf("add =%s,Nonce:%d \n", from, acc.Nonce) 203 204 lock.Unlock() 205 206 txCh <- newTx 207 wg.Done() 208 } 209 210 func parsePkFile(pkFile string) { 211 if pkFile == "" { 212 dir, _ := os.Getwd() 213 pkFile = dir + DefaultPrivateKeyFilePath 214 } 215 gob.Register(&secp256k1.BitCurve{}) 216 file, err := os.Open(pkFile) 217 dec := gob.NewDecoder(file) 218 err2 := dec.Decode(&accountPool) 219 if err2 != nil { 220 panic(err.Error()) 221 } 222 } 223 224 func getAllAddress(pkFile string) []string { 225 addrsPath := "" 226 if pkFile != "" { 227 addrsPath = filepath.Dir(pkFile) + "/addr.json" 228 } else { 229 dir, _ := os.Getwd() 230 addrsPath = dir + DefaultAccountAddrFilePath 231 } 232 233 bytes, err := ioutil.ReadFile(addrsPath) 234 if err != nil { 235 panic(fmt.Errorf("get all address array error,%s \n", err.Error())) 236 } 237 var addrs []string 238 err = json.Unmarshal(bytes, &addrs) 239 if err != nil { 240 panic(fmt.Errorf("parse address to array error,%s \n", err.Error())) 241 } 242 243 return addrs 244 } 245 246 func getRandomAddr(addrs []string) (string, string) { 247 if len(addrs) == 0 { 248 return "", "" 249 } 250 fromIndex := rand.Intn(len(addrs)) 251 toIndex := rand.Intn(len(addrs)) 252 for toIndex == fromIndex { 253 toIndex = rand.Intn(len(addrs)) 254 } 255 return addrs[fromIndex], addrs[toIndex] 256 }