github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/cmd/devp2p/internal/ethtest/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 ethtest 18 19 import ( 20 "fmt" 21 "math/big" 22 "strings" 23 "time" 24 25 "github.com/ethw3/go-ethereuma/common" 26 "github.com/ethw3/go-ethereuma/core/types" 27 "github.com/ethw3/go-ethereuma/crypto" 28 "github.com/ethw3/go-ethereuma/internal/utesting" 29 "github.com/ethw3/go-ethereuma/params" 30 ) 31 32 //var faucetAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") 33 var faucetKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 34 35 func (s *Suite) sendSuccessfulTxs(t *utesting.T) error { 36 tests := []*types.Transaction{ 37 getNextTxFromChain(s), 38 unknownTx(s), 39 } 40 for i, tx := range tests { 41 if tx == nil { 42 return fmt.Errorf("could not find tx to send") 43 } 44 t.Logf("Testing tx propagation %d: sending tx %v %v %v\n", i, tx.Hash().String(), tx.GasPrice(), tx.Gas()) 45 // get previous tx if exists for reference in case of old tx propagation 46 var prevTx *types.Transaction 47 if i != 0 { 48 prevTx = tests[i-1] 49 } 50 // write tx to connection 51 if err := sendSuccessfulTx(s, tx, prevTx); err != nil { 52 return fmt.Errorf("send successful tx test failed: %v", err) 53 } 54 } 55 return nil 56 } 57 58 func sendSuccessfulTx(s *Suite, tx *types.Transaction, prevTx *types.Transaction) error { 59 sendConn, recvConn, err := s.createSendAndRecvConns() 60 if err != nil { 61 return err 62 } 63 defer sendConn.Close() 64 defer recvConn.Close() 65 if err = sendConn.peer(s.chain, nil); err != nil { 66 return fmt.Errorf("peering failed: %v", err) 67 } 68 // Send the transaction 69 if err = sendConn.Write(&Transactions{tx}); err != nil { 70 return fmt.Errorf("failed to write to connection: %v", err) 71 } 72 // peer receiving connection to node 73 if err = recvConn.peer(s.chain, nil); err != nil { 74 return fmt.Errorf("peering failed: %v", err) 75 } 76 77 // update last nonce seen 78 nonce = tx.Nonce() 79 80 // Wait for the transaction announcement 81 for { 82 switch msg := recvConn.readAndServe(s.chain, timeout).(type) { 83 case *Transactions: 84 recTxs := *msg 85 // if you receive an old tx propagation, read from connection again 86 if len(recTxs) == 1 && prevTx != nil { 87 if recTxs[0] == prevTx { 88 continue 89 } 90 } 91 for _, gotTx := range recTxs { 92 if gotTx.Hash() == tx.Hash() { 93 // Ok 94 return nil 95 } 96 } 97 return fmt.Errorf("missing transaction: got %v missing %v", recTxs, tx.Hash()) 98 case *NewPooledTransactionHashes: 99 txHashes := *msg 100 // if you receive an old tx propagation, read from connection again 101 if len(txHashes) == 1 && prevTx != nil { 102 if txHashes[0] == prevTx.Hash() { 103 continue 104 } 105 } 106 for _, gotHash := range txHashes { 107 if gotHash == tx.Hash() { 108 // Ok 109 return nil 110 } 111 } 112 return fmt.Errorf("missing transaction announcement: got %v missing %v", txHashes, tx.Hash()) 113 default: 114 return fmt.Errorf("unexpected message in sendSuccessfulTx: %s", pretty.Sdump(msg)) 115 } 116 } 117 } 118 119 func (s *Suite) sendMaliciousTxs(t *utesting.T) error { 120 badTxs := []*types.Transaction{ 121 getOldTxFromChain(s), 122 invalidNonceTx(s), 123 hugeAmount(s), 124 hugeGasPrice(s), 125 hugeData(s), 126 } 127 128 // setup receiving connection before sending malicious txs 129 recvConn, err := s.dial() 130 if err != nil { 131 return fmt.Errorf("dial failed: %v", err) 132 } 133 defer recvConn.Close() 134 if err = recvConn.peer(s.chain, nil); err != nil { 135 return fmt.Errorf("peering failed: %v", err) 136 } 137 138 for i, tx := range badTxs { 139 t.Logf("Testing malicious tx propagation: %v\n", i) 140 if err = sendMaliciousTx(s, tx); err != nil { 141 return fmt.Errorf("malicious tx test failed:\ntx: %v\nerror: %v", tx, err) 142 } 143 } 144 // check to make sure bad txs aren't propagated 145 return checkMaliciousTxPropagation(s, badTxs, recvConn) 146 } 147 148 func sendMaliciousTx(s *Suite, tx *types.Transaction) error { 149 conn, err := s.dial() 150 if err != nil { 151 return fmt.Errorf("dial failed: %v", err) 152 } 153 defer conn.Close() 154 if err = conn.peer(s.chain, nil); err != nil { 155 return fmt.Errorf("peering failed: %v", err) 156 } 157 158 // write malicious tx 159 if err = conn.Write(&Transactions{tx}); err != nil { 160 return fmt.Errorf("failed to write to connection: %v", err) 161 } 162 return nil 163 } 164 165 var nonce = uint64(99) 166 167 // sendMultipleSuccessfulTxs sends the given transactions to the node and 168 // expects the node to accept and propagate them. 169 func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, txs []*types.Transaction) error { 170 txMsg := Transactions(txs) 171 t.Logf("sending %d txs\n", len(txs)) 172 173 sendConn, recvConn, err := s.createSendAndRecvConns() 174 if err != nil { 175 return err 176 } 177 defer sendConn.Close() 178 defer recvConn.Close() 179 if err = sendConn.peer(s.chain, nil); err != nil { 180 return fmt.Errorf("peering failed: %v", err) 181 } 182 if err = recvConn.peer(s.chain, nil); err != nil { 183 return fmt.Errorf("peering failed: %v", err) 184 } 185 186 // Send the transactions 187 if err = sendConn.Write(&txMsg); err != nil { 188 return fmt.Errorf("failed to write message to connection: %v", err) 189 } 190 191 // update nonce 192 nonce = txs[len(txs)-1].Nonce() 193 194 // Wait for the transaction announcement(s) and make sure all sent txs are being propagated. 195 // all txs should be announced within 3 announcements. 196 recvHashes := make([]common.Hash, 0) 197 198 for i := 0; i < 3; i++ { 199 switch msg := recvConn.readAndServe(s.chain, timeout).(type) { 200 case *Transactions: 201 for _, tx := range *msg { 202 recvHashes = append(recvHashes, tx.Hash()) 203 } 204 case *NewPooledTransactionHashes: 205 recvHashes = append(recvHashes, *msg...) 206 default: 207 if !strings.Contains(pretty.Sdump(msg), "i/o timeout") { 208 return fmt.Errorf("unexpected message while waiting to receive txs: %s", pretty.Sdump(msg)) 209 } 210 } 211 // break once all 2000 txs have been received 212 if len(recvHashes) == 2000 { 213 break 214 } 215 if len(recvHashes) > 0 { 216 _, missingTxs := compareReceivedTxs(recvHashes, txs) 217 if len(missingTxs) > 0 { 218 continue 219 } else { 220 t.Logf("successfully received all %d txs", len(txs)) 221 return nil 222 } 223 } 224 } 225 _, missingTxs := compareReceivedTxs(recvHashes, txs) 226 if len(missingTxs) > 0 { 227 for _, missing := range missingTxs { 228 t.Logf("missing tx: %v", missing.Hash()) 229 } 230 return fmt.Errorf("missing %d txs", len(missingTxs)) 231 } 232 return nil 233 } 234 235 // checkMaliciousTxPropagation checks whether the given malicious transactions were 236 // propagated by the node. 237 func checkMaliciousTxPropagation(s *Suite, txs []*types.Transaction, conn *Conn) error { 238 switch msg := conn.readAndServe(s.chain, time.Second*8).(type) { 239 case *Transactions: 240 // check to see if any of the failing txs were in the announcement 241 recvTxs := make([]common.Hash, len(*msg)) 242 for i, recvTx := range *msg { 243 recvTxs[i] = recvTx.Hash() 244 } 245 badTxs, _ := compareReceivedTxs(recvTxs, txs) 246 if len(badTxs) > 0 { 247 return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs) 248 } 249 case *NewPooledTransactionHashes: 250 badTxs, _ := compareReceivedTxs(*msg, txs) 251 if len(badTxs) > 0 { 252 return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs) 253 } 254 case *Error: 255 // Transaction should not be announced -> wait for timeout 256 return nil 257 default: 258 return fmt.Errorf("unexpected message in sendFailingTx: %s", pretty.Sdump(msg)) 259 } 260 return nil 261 } 262 263 // compareReceivedTxs compares the received set of txs against the given set of txs, 264 // returning both the set received txs that were present within the given txs, and 265 // the set of txs that were missing from the set of received txs 266 func compareReceivedTxs(recvTxs []common.Hash, txs []*types.Transaction) (present []*types.Transaction, missing []*types.Transaction) { 267 // create a map of the hashes received from node 268 recvHashes := make(map[common.Hash]common.Hash) 269 for _, hash := range recvTxs { 270 recvHashes[hash] = hash 271 } 272 273 // collect present txs and missing txs separately 274 present = make([]*types.Transaction, 0) 275 missing = make([]*types.Transaction, 0) 276 for _, tx := range txs { 277 if _, exists := recvHashes[tx.Hash()]; exists { 278 present = append(present, tx) 279 } else { 280 missing = append(missing, tx) 281 } 282 } 283 return present, missing 284 } 285 286 func unknownTx(s *Suite) *types.Transaction { 287 tx := getNextTxFromChain(s) 288 if tx == nil { 289 return nil 290 } 291 var to common.Address 292 if tx.To() != nil { 293 to = *tx.To() 294 } 295 txNew := types.NewTransaction(tx.Nonce()+1, to, tx.Value(), tx.Gas(), tx.GasPrice(), tx.Data()) 296 return signWithFaucet(s.chain.chainConfig, txNew) 297 } 298 299 func getNextTxFromChain(s *Suite) *types.Transaction { 300 // Get a new transaction 301 for _, blocks := range s.fullChain.blocks[s.chain.Len():] { 302 txs := blocks.Transactions() 303 if txs.Len() != 0 { 304 return txs[0] 305 } 306 } 307 return nil 308 } 309 310 func generateTxs(s *Suite, numTxs int) (map[common.Hash]common.Hash, []*types.Transaction, error) { 311 txHashMap := make(map[common.Hash]common.Hash, numTxs) 312 txs := make([]*types.Transaction, numTxs) 313 314 nextTx := getNextTxFromChain(s) 315 if nextTx == nil { 316 return nil, nil, fmt.Errorf("failed to get the next transaction") 317 } 318 gas := nextTx.Gas() 319 320 nonce = nonce + 1 321 // generate txs 322 for i := 0; i < numTxs; i++ { 323 tx := generateTx(s.chain.chainConfig, nonce, gas) 324 if tx == nil { 325 return nil, nil, fmt.Errorf("failed to get the next transaction") 326 } 327 txHashMap[tx.Hash()] = tx.Hash() 328 txs[i] = tx 329 nonce = nonce + 1 330 } 331 return txHashMap, txs, nil 332 } 333 334 func generateTx(chainConfig *params.ChainConfig, nonce uint64, gas uint64) *types.Transaction { 335 var to common.Address 336 tx := types.NewTransaction(nonce, to, big.NewInt(1), gas, big.NewInt(1), []byte{}) 337 return signWithFaucet(chainConfig, tx) 338 } 339 340 func getOldTxFromChain(s *Suite) *types.Transaction { 341 for _, blocks := range s.fullChain.blocks[:s.chain.Len()-1] { 342 txs := blocks.Transactions() 343 if txs.Len() != 0 { 344 return txs[0] 345 } 346 } 347 return nil 348 } 349 350 func invalidNonceTx(s *Suite) *types.Transaction { 351 tx := getNextTxFromChain(s) 352 if tx == nil { 353 return nil 354 } 355 var to common.Address 356 if tx.To() != nil { 357 to = *tx.To() 358 } 359 txNew := types.NewTransaction(tx.Nonce()-2, to, tx.Value(), tx.Gas(), tx.GasPrice(), tx.Data()) 360 return signWithFaucet(s.chain.chainConfig, txNew) 361 } 362 363 func hugeAmount(s *Suite) *types.Transaction { 364 tx := getNextTxFromChain(s) 365 if tx == nil { 366 return nil 367 } 368 amount := largeNumber(2) 369 var to common.Address 370 if tx.To() != nil { 371 to = *tx.To() 372 } 373 txNew := types.NewTransaction(tx.Nonce(), to, amount, tx.Gas(), tx.GasPrice(), tx.Data()) 374 return signWithFaucet(s.chain.chainConfig, txNew) 375 } 376 377 func hugeGasPrice(s *Suite) *types.Transaction { 378 tx := getNextTxFromChain(s) 379 if tx == nil { 380 return nil 381 } 382 gasPrice := largeNumber(2) 383 var to common.Address 384 if tx.To() != nil { 385 to = *tx.To() 386 } 387 txNew := types.NewTransaction(tx.Nonce(), to, tx.Value(), tx.Gas(), gasPrice, tx.Data()) 388 return signWithFaucet(s.chain.chainConfig, txNew) 389 } 390 391 func hugeData(s *Suite) *types.Transaction { 392 tx := getNextTxFromChain(s) 393 if tx == nil { 394 return nil 395 } 396 var to common.Address 397 if tx.To() != nil { 398 to = *tx.To() 399 } 400 txNew := types.NewTransaction(tx.Nonce(), to, tx.Value(), tx.Gas(), tx.GasPrice(), largeBuffer(2)) 401 return signWithFaucet(s.chain.chainConfig, txNew) 402 } 403 404 func signWithFaucet(chainConfig *params.ChainConfig, tx *types.Transaction) *types.Transaction { 405 signer := types.LatestSigner(chainConfig) 406 signedTx, err := types.SignTx(tx, signer, faucetKey) 407 if err != nil { 408 return nil 409 } 410 return signedTx 411 }