github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/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/tirogen/go-ethereum/common" 26 "github.com/tirogen/go-ethereum/core/types" 27 "github.com/tirogen/go-ethereum/crypto" 28 "github.com/tirogen/go-ethereum/internal/utesting" 29 "github.com/tirogen/go-ethereum/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 *NewPooledTransactionHashes66: 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 case *NewPooledTransactionHashes: 114 txHashes := msg.Hashes 115 if len(txHashes) != len(msg.Sizes) { 116 return fmt.Errorf("invalid msg size lengths: hashes: %v sizes: %v", len(txHashes), len(msg.Sizes)) 117 } 118 if len(txHashes) != len(msg.Types) { 119 return fmt.Errorf("invalid msg type lengths: hashes: %v types: %v", len(txHashes), len(msg.Types)) 120 } 121 // if you receive an old tx propagation, read from connection again 122 if len(txHashes) == 1 && prevTx != nil { 123 if txHashes[0] == prevTx.Hash() { 124 continue 125 } 126 } 127 for index, gotHash := range txHashes { 128 if gotHash == tx.Hash() { 129 if msg.Sizes[index] != uint32(tx.Size()) { 130 return fmt.Errorf("invalid tx size: got %v want %v", msg.Sizes[index], tx.Size()) 131 } 132 if msg.Types[index] != tx.Type() { 133 return fmt.Errorf("invalid tx type: got %v want %v", msg.Types[index], tx.Type()) 134 } 135 // Ok 136 return nil 137 } 138 } 139 return fmt.Errorf("missing transaction announcement: got %v missing %v", txHashes, tx.Hash()) 140 141 default: 142 return fmt.Errorf("unexpected message in sendSuccessfulTx: %s", pretty.Sdump(msg)) 143 } 144 } 145 } 146 147 func (s *Suite) sendMaliciousTxs(t *utesting.T) error { 148 badTxs := []*types.Transaction{ 149 getOldTxFromChain(s), 150 invalidNonceTx(s), 151 hugeAmount(s), 152 hugeGasPrice(s), 153 hugeData(s), 154 } 155 156 // setup receiving connection before sending malicious txs 157 recvConn, err := s.dial() 158 if err != nil { 159 return fmt.Errorf("dial failed: %v", err) 160 } 161 defer recvConn.Close() 162 if err = recvConn.peer(s.chain, nil); err != nil { 163 return fmt.Errorf("peering failed: %v", err) 164 } 165 166 for i, tx := range badTxs { 167 t.Logf("Testing malicious tx propagation: %v\n", i) 168 if err = sendMaliciousTx(s, tx); err != nil { 169 return fmt.Errorf("malicious tx test failed:\ntx: %v\nerror: %v", tx, err) 170 } 171 } 172 // check to make sure bad txs aren't propagated 173 return checkMaliciousTxPropagation(s, badTxs, recvConn) 174 } 175 176 func sendMaliciousTx(s *Suite, tx *types.Transaction) error { 177 conn, err := s.dial() 178 if err != nil { 179 return fmt.Errorf("dial failed: %v", err) 180 } 181 defer conn.Close() 182 if err = conn.peer(s.chain, nil); err != nil { 183 return fmt.Errorf("peering failed: %v", err) 184 } 185 186 // write malicious tx 187 if err = conn.Write(&Transactions{tx}); err != nil { 188 return fmt.Errorf("failed to write to connection: %v", err) 189 } 190 return nil 191 } 192 193 var nonce = uint64(99) 194 195 // sendMultipleSuccessfulTxs sends the given transactions to the node and 196 // expects the node to accept and propagate them. 197 func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, txs []*types.Transaction) error { 198 txMsg := Transactions(txs) 199 t.Logf("sending %d txs\n", len(txs)) 200 201 sendConn, recvConn, err := s.createSendAndRecvConns() 202 if err != nil { 203 return err 204 } 205 defer sendConn.Close() 206 defer recvConn.Close() 207 if err = sendConn.peer(s.chain, nil); err != nil { 208 return fmt.Errorf("peering failed: %v", err) 209 } 210 if err = recvConn.peer(s.chain, nil); err != nil { 211 return fmt.Errorf("peering failed: %v", err) 212 } 213 214 // Send the transactions 215 if err = sendConn.Write(&txMsg); err != nil { 216 return fmt.Errorf("failed to write message to connection: %v", err) 217 } 218 219 // update nonce 220 nonce = txs[len(txs)-1].Nonce() 221 222 // Wait for the transaction announcement(s) and make sure all sent txs are being propagated. 223 // all txs should be announced within a couple announcements. 224 recvHashes := make([]common.Hash, 0) 225 226 for i := 0; i < 20; i++ { 227 switch msg := recvConn.readAndServe(s.chain, timeout).(type) { 228 case *Transactions: 229 for _, tx := range *msg { 230 recvHashes = append(recvHashes, tx.Hash()) 231 } 232 case *NewPooledTransactionHashes66: 233 recvHashes = append(recvHashes, *msg...) 234 case *NewPooledTransactionHashes: 235 recvHashes = append(recvHashes, msg.Hashes...) 236 default: 237 if !strings.Contains(pretty.Sdump(msg), "i/o timeout") { 238 return fmt.Errorf("unexpected message while waiting to receive txs: %s", pretty.Sdump(msg)) 239 } 240 } 241 // break once all 2000 txs have been received 242 if len(recvHashes) == 2000 { 243 break 244 } 245 if len(recvHashes) > 0 { 246 _, missingTxs := compareReceivedTxs(recvHashes, txs) 247 if len(missingTxs) > 0 { 248 continue 249 } else { 250 t.Logf("successfully received all %d txs", len(txs)) 251 return nil 252 } 253 } 254 } 255 _, missingTxs := compareReceivedTxs(recvHashes, txs) 256 if len(missingTxs) > 0 { 257 for _, missing := range missingTxs { 258 t.Logf("missing tx: %v", missing.Hash()) 259 } 260 return fmt.Errorf("missing %d txs", len(missingTxs)) 261 } 262 return nil 263 } 264 265 // checkMaliciousTxPropagation checks whether the given malicious transactions were 266 // propagated by the node. 267 func checkMaliciousTxPropagation(s *Suite, txs []*types.Transaction, conn *Conn) error { 268 switch msg := conn.readAndServe(s.chain, time.Second*8).(type) { 269 case *Transactions: 270 // check to see if any of the failing txs were in the announcement 271 recvTxs := make([]common.Hash, len(*msg)) 272 for i, recvTx := range *msg { 273 recvTxs[i] = recvTx.Hash() 274 } 275 badTxs, _ := compareReceivedTxs(recvTxs, txs) 276 if len(badTxs) > 0 { 277 return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs) 278 } 279 case *NewPooledTransactionHashes66: 280 badTxs, _ := compareReceivedTxs(*msg, txs) 281 if len(badTxs) > 0 { 282 return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs) 283 } 284 case *NewPooledTransactionHashes: 285 badTxs, _ := compareReceivedTxs(msg.Hashes, txs) 286 if len(badTxs) > 0 { 287 return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs) 288 } 289 case *Error: 290 // Transaction should not be announced -> wait for timeout 291 return nil 292 default: 293 return fmt.Errorf("unexpected message in sendFailingTx: %s", pretty.Sdump(msg)) 294 } 295 return nil 296 } 297 298 // compareReceivedTxs compares the received set of txs against the given set of txs, 299 // returning both the set received txs that were present within the given txs, and 300 // the set of txs that were missing from the set of received txs 301 func compareReceivedTxs(recvTxs []common.Hash, txs []*types.Transaction) (present []*types.Transaction, missing []*types.Transaction) { 302 // create a map of the hashes received from node 303 recvHashes := make(map[common.Hash]common.Hash) 304 for _, hash := range recvTxs { 305 recvHashes[hash] = hash 306 } 307 308 // collect present txs and missing txs separately 309 present = make([]*types.Transaction, 0) 310 missing = make([]*types.Transaction, 0) 311 for _, tx := range txs { 312 if _, exists := recvHashes[tx.Hash()]; exists { 313 present = append(present, tx) 314 } else { 315 missing = append(missing, tx) 316 } 317 } 318 return present, missing 319 } 320 321 func unknownTx(s *Suite) *types.Transaction { 322 tx := getNextTxFromChain(s) 323 if tx == nil { 324 return nil 325 } 326 var to common.Address 327 if tx.To() != nil { 328 to = *tx.To() 329 } 330 txNew := types.NewTransaction(tx.Nonce()+1, to, tx.Value(), tx.Gas(), tx.GasPrice(), tx.Data()) 331 return signWithFaucet(s.chain.chainConfig, txNew) 332 } 333 334 func getNextTxFromChain(s *Suite) *types.Transaction { 335 // Get a new transaction 336 for _, blocks := range s.fullChain.blocks[s.chain.Len():] { 337 txs := blocks.Transactions() 338 if txs.Len() != 0 { 339 return txs[0] 340 } 341 } 342 return nil 343 } 344 345 func generateTxs(s *Suite, numTxs int) (map[common.Hash]common.Hash, []*types.Transaction, error) { 346 txHashMap := make(map[common.Hash]common.Hash, numTxs) 347 txs := make([]*types.Transaction, numTxs) 348 349 nextTx := getNextTxFromChain(s) 350 if nextTx == nil { 351 return nil, nil, fmt.Errorf("failed to get the next transaction") 352 } 353 gas := nextTx.Gas() 354 355 nonce = nonce + 1 356 // generate txs 357 for i := 0; i < numTxs; i++ { 358 tx := generateTx(s.chain.chainConfig, nonce, gas) 359 if tx == nil { 360 return nil, nil, fmt.Errorf("failed to get the next transaction") 361 } 362 txHashMap[tx.Hash()] = tx.Hash() 363 txs[i] = tx 364 nonce = nonce + 1 365 } 366 return txHashMap, txs, nil 367 } 368 369 func generateTx(chainConfig *params.ChainConfig, nonce uint64, gas uint64) *types.Transaction { 370 var to common.Address 371 tx := types.NewTransaction(nonce, to, big.NewInt(1), gas, big.NewInt(1), []byte{}) 372 return signWithFaucet(chainConfig, tx) 373 } 374 375 func getOldTxFromChain(s *Suite) *types.Transaction { 376 for _, blocks := range s.fullChain.blocks[:s.chain.Len()-1] { 377 txs := blocks.Transactions() 378 if txs.Len() != 0 { 379 return txs[0] 380 } 381 } 382 return nil 383 } 384 385 func invalidNonceTx(s *Suite) *types.Transaction { 386 tx := getNextTxFromChain(s) 387 if tx == nil { 388 return nil 389 } 390 var to common.Address 391 if tx.To() != nil { 392 to = *tx.To() 393 } 394 txNew := types.NewTransaction(tx.Nonce()-2, to, tx.Value(), tx.Gas(), tx.GasPrice(), tx.Data()) 395 return signWithFaucet(s.chain.chainConfig, txNew) 396 } 397 398 func hugeAmount(s *Suite) *types.Transaction { 399 tx := getNextTxFromChain(s) 400 if tx == nil { 401 return nil 402 } 403 amount := largeNumber(2) 404 var to common.Address 405 if tx.To() != nil { 406 to = *tx.To() 407 } 408 txNew := types.NewTransaction(tx.Nonce(), to, amount, tx.Gas(), tx.GasPrice(), tx.Data()) 409 return signWithFaucet(s.chain.chainConfig, txNew) 410 } 411 412 func hugeGasPrice(s *Suite) *types.Transaction { 413 tx := getNextTxFromChain(s) 414 if tx == nil { 415 return nil 416 } 417 gasPrice := largeNumber(2) 418 var to common.Address 419 if tx.To() != nil { 420 to = *tx.To() 421 } 422 txNew := types.NewTransaction(tx.Nonce(), to, tx.Value(), tx.Gas(), gasPrice, tx.Data()) 423 return signWithFaucet(s.chain.chainConfig, txNew) 424 } 425 426 func hugeData(s *Suite) *types.Transaction { 427 tx := getNextTxFromChain(s) 428 if tx == nil { 429 return nil 430 } 431 var to common.Address 432 if tx.To() != nil { 433 to = *tx.To() 434 } 435 txNew := types.NewTransaction(tx.Nonce(), to, tx.Value(), tx.Gas(), tx.GasPrice(), largeBuffer(2)) 436 return signWithFaucet(s.chain.chainConfig, txNew) 437 } 438 439 func signWithFaucet(chainConfig *params.ChainConfig, tx *types.Transaction) *types.Transaction { 440 signer := types.LatestSigner(chainConfig) 441 signedTx, err := types.SignTx(tx, signer, faucetKey) 442 if err != nil { 443 return nil 444 } 445 return signedTx 446 }