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