github.com/fff-chain/go-fff@v0.0.0-20220726032732-1c84420b8a99/cmd/devp2p/internal/ethtest/transaction.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser 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 // The go-ethereum library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package ethtest 18 19 import ( 20 "math/big" 21 "strings" 22 "time" 23 24 "github.com/fff-chain/go-fff/common" 25 "github.com/fff-chain/go-fff/core/types" 26 "github.com/fff-chain/go-fff/crypto" 27 "github.com/fff-chain/go-fff/internal/utesting" 28 "github.com/fff-chain/go-fff/params" 29 ) 30 31 //var faucetAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") 32 var faucetKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 33 34 func sendSuccessfulTx(t *utesting.T, s *Suite, tx *types.Transaction) { 35 sendConn := s.setupConnection(t) 36 defer sendConn.Close() 37 sendSuccessfulTxWithConn(t, s, tx, sendConn) 38 } 39 40 func sendSuccessfulTxWithConn(t *utesting.T, s *Suite, tx *types.Transaction, sendConn *Conn) { 41 t.Logf("sending tx: %v %v %v\n", tx.Hash().String(), tx.GasPrice(), tx.Gas()) 42 // Send the transaction 43 if err := sendConn.Write(&Transactions{tx}); err != nil { 44 t.Fatal(err) 45 } 46 // update last nonce seen 47 nonce = tx.Nonce() 48 49 recvConn := s.setupConnection(t) 50 // Wait for the transaction announcement 51 switch msg := recvConn.ReadAndServe(s.chain, timeout).(type) { 52 case *Transactions: 53 recTxs := *msg 54 for _, gotTx := range recTxs { 55 if gotTx.Hash() == tx.Hash() { 56 // Ok 57 return 58 } 59 } 60 t.Fatalf("missing transaction: got %v missing %v", recTxs, tx.Hash()) 61 case *NewPooledTransactionHashes: 62 txHashes := *msg 63 for _, gotHash := range txHashes { 64 if gotHash == tx.Hash() { 65 return 66 } 67 } 68 t.Fatalf("missing transaction announcement: got %v missing %v", txHashes, tx.Hash()) 69 default: 70 t.Fatalf("unexpected message in sendSuccessfulTx: %s", pretty.Sdump(msg)) 71 } 72 } 73 74 var nonce = uint64(99) 75 76 func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, sendConn *Conn, txs []*types.Transaction) { 77 txMsg := Transactions(txs) 78 t.Logf("sending %d txs\n", len(txs)) 79 80 recvConn := s.setupConnection(t) 81 defer recvConn.Close() 82 83 // Send the transactions 84 if err := sendConn.Write(&txMsg); err != nil { 85 t.Fatal(err) 86 } 87 // update nonce 88 nonce = txs[len(txs)-1].Nonce() 89 // Wait for the transaction announcement(s) and make sure all sent txs are being propagated 90 recvHashes := make([]common.Hash, 0) 91 // all txs should be announced within 3 announcements 92 for i := 0; i < 3; i++ { 93 switch msg := recvConn.ReadAndServe(s.chain, timeout).(type) { 94 case *Transactions: 95 for _, tx := range *msg { 96 recvHashes = append(recvHashes, tx.Hash()) 97 } 98 case *NewPooledTransactionHashes: 99 recvHashes = append(recvHashes, *msg...) 100 default: 101 if !strings.Contains(pretty.Sdump(msg), "i/o timeout") { 102 t.Fatalf("unexpected message while waiting to receive txs: %s", pretty.Sdump(msg)) 103 } 104 } 105 // break once all 2000 txs have been received 106 if len(recvHashes) == 2000 { 107 break 108 } 109 if len(recvHashes) > 0 { 110 _, missingTxs := compareReceivedTxs(recvHashes, txs) 111 if len(missingTxs) > 0 { 112 continue 113 } else { 114 t.Logf("successfully received all %d txs", len(txs)) 115 return 116 } 117 } 118 } 119 _, missingTxs := compareReceivedTxs(recvHashes, txs) 120 if len(missingTxs) > 0 { 121 for _, missing := range missingTxs { 122 t.Logf("missing tx: %v", missing.Hash()) 123 } 124 t.Fatalf("missing %d txs", len(missingTxs)) 125 } 126 } 127 128 func waitForTxPropagation(t *utesting.T, s *Suite, txs []*types.Transaction, recvConn *Conn) { 129 // Wait for another transaction announcement 130 switch msg := recvConn.ReadAndServe(s.chain, time.Second*8).(type) { 131 case *Transactions: 132 // check to see if any of the failing txs were in the announcement 133 recvTxs := make([]common.Hash, len(*msg)) 134 for i, recvTx := range *msg { 135 recvTxs[i] = recvTx.Hash() 136 } 137 badTxs, _ := compareReceivedTxs(recvTxs, txs) 138 if len(badTxs) > 0 { 139 for _, tx := range badTxs { 140 t.Logf("received bad tx: %v", tx) 141 } 142 t.Fatalf("received %d bad txs", len(badTxs)) 143 } 144 case *NewPooledTransactionHashes: 145 badTxs, _ := compareReceivedTxs(*msg, txs) 146 if len(badTxs) > 0 { 147 for _, tx := range badTxs { 148 t.Logf("received bad tx: %v", tx) 149 } 150 t.Fatalf("received %d bad txs", len(badTxs)) 151 } 152 case *Error: 153 // Transaction should not be announced -> wait for timeout 154 return 155 default: 156 t.Fatalf("unexpected message in sendFailingTx: %s", pretty.Sdump(msg)) 157 } 158 } 159 160 // compareReceivedTxs compares the received set of txs against the given set of txs, 161 // returning both the set received txs that were present within the given txs, and 162 // the set of txs that were missing from the set of received txs 163 func compareReceivedTxs(recvTxs []common.Hash, txs []*types.Transaction) (present []*types.Transaction, missing []*types.Transaction) { 164 // create a map of the hashes received from node 165 recvHashes := make(map[common.Hash]common.Hash) 166 for _, hash := range recvTxs { 167 recvHashes[hash] = hash 168 } 169 170 // collect present txs and missing txs separately 171 present = make([]*types.Transaction, 0) 172 missing = make([]*types.Transaction, 0) 173 for _, tx := range txs { 174 if _, exists := recvHashes[tx.Hash()]; exists { 175 present = append(present, tx) 176 } else { 177 missing = append(missing, tx) 178 } 179 } 180 return present, missing 181 } 182 183 func unknownTx(t *utesting.T, s *Suite) *types.Transaction { 184 tx := getNextTxFromChain(t, s) 185 var to common.Address 186 if tx.To() != nil { 187 to = *tx.To() 188 } 189 txNew := types.NewTransaction(tx.Nonce()+1, to, tx.Value(), tx.Gas(), tx.GasPrice(), tx.Data()) 190 return signWithFaucet(t, s.chain.chainConfig, txNew) 191 } 192 193 func getNextTxFromChain(t *utesting.T, s *Suite) *types.Transaction { 194 // Get a new transaction 195 var tx *types.Transaction 196 for _, blocks := range s.fullChain.blocks[s.chain.Len():] { 197 txs := blocks.Transactions() 198 if txs.Len() != 0 { 199 tx = txs[0] 200 break 201 } 202 } 203 if tx == nil { 204 t.Fatal("could not find transaction") 205 } 206 return tx 207 } 208 209 func generateTxs(t *utesting.T, s *Suite, numTxs int) (map[common.Hash]common.Hash, []*types.Transaction) { 210 txHashMap := make(map[common.Hash]common.Hash, numTxs) 211 txs := make([]*types.Transaction, numTxs) 212 213 nextTx := getNextTxFromChain(t, s) 214 gas := nextTx.Gas() 215 216 nonce = nonce + 1 217 // generate txs 218 for i := 0; i < numTxs; i++ { 219 tx := generateTx(t, s.chain.chainConfig, nonce, gas) 220 txHashMap[tx.Hash()] = tx.Hash() 221 txs[i] = tx 222 nonce = nonce + 1 223 } 224 return txHashMap, txs 225 } 226 227 func generateTx(t *utesting.T, chainConfig *params.ChainConfig, nonce uint64, gas uint64) *types.Transaction { 228 var to common.Address 229 tx := types.NewTransaction(nonce, to, big.NewInt(1), gas, big.NewInt(1), []byte{}) 230 return signWithFaucet(t, chainConfig, tx) 231 } 232 233 func getOldTxFromChain(t *utesting.T, s *Suite) *types.Transaction { 234 var tx *types.Transaction 235 for _, blocks := range s.fullChain.blocks[:s.chain.Len()-1] { 236 txs := blocks.Transactions() 237 if txs.Len() != 0 { 238 tx = txs[0] 239 break 240 } 241 } 242 if tx == nil { 243 t.Fatal("could not find transaction") 244 } 245 return tx 246 } 247 248 func invalidNonceTx(t *utesting.T, s *Suite) *types.Transaction { 249 tx := getNextTxFromChain(t, s) 250 var to common.Address 251 if tx.To() != nil { 252 to = *tx.To() 253 } 254 txNew := types.NewTransaction(tx.Nonce()-2, to, tx.Value(), tx.Gas(), tx.GasPrice(), tx.Data()) 255 return signWithFaucet(t, s.chain.chainConfig, txNew) 256 } 257 258 func hugeAmount(t *utesting.T, s *Suite) *types.Transaction { 259 tx := getNextTxFromChain(t, s) 260 amount := largeNumber(2) 261 var to common.Address 262 if tx.To() != nil { 263 to = *tx.To() 264 } 265 txNew := types.NewTransaction(tx.Nonce(), to, amount, tx.Gas(), tx.GasPrice(), tx.Data()) 266 return signWithFaucet(t, s.chain.chainConfig, txNew) 267 } 268 269 func hugeGasPrice(t *utesting.T, s *Suite) *types.Transaction { 270 tx := getNextTxFromChain(t, s) 271 gasPrice := largeNumber(2) 272 var to common.Address 273 if tx.To() != nil { 274 to = *tx.To() 275 } 276 txNew := types.NewTransaction(tx.Nonce(), to, tx.Value(), tx.Gas(), gasPrice, tx.Data()) 277 return signWithFaucet(t, s.chain.chainConfig, txNew) 278 } 279 280 func hugeData(t *utesting.T, s *Suite) *types.Transaction { 281 tx := getNextTxFromChain(t, s) 282 var to common.Address 283 if tx.To() != nil { 284 to = *tx.To() 285 } 286 txNew := types.NewTransaction(tx.Nonce(), to, tx.Value(), tx.Gas(), tx.GasPrice(), largeBuffer(2)) 287 return signWithFaucet(t, s.chain.chainConfig, txNew) 288 } 289 290 func signWithFaucet(t *utesting.T, chainConfig *params.ChainConfig, tx *types.Transaction) *types.Transaction { 291 signer := types.LatestSigner(chainConfig) 292 signedTx, err := types.SignTx(tx, signer, faucetKey) 293 if err != nil { 294 t.Fatalf("could not sign tx: %v\n", err) 295 } 296 return signedTx 297 }