github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/miner/ordering_test.go (about) 1 // Copyright 2014 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 miner 18 19 import ( 20 "crypto/ecdsa" 21 "math/big" 22 "math/rand" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/core/txpool" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/crypto" 30 "github.com/holiman/uint256" 31 ) 32 33 func TestTransactionPriceNonceSortLegacy(t *testing.T) { 34 t.Parallel() 35 testTransactionPriceNonceSort(t, nil) 36 } 37 38 func TestTransactionPriceNonceSort1559(t *testing.T) { 39 t.Parallel() 40 testTransactionPriceNonceSort(t, big.NewInt(0)) 41 testTransactionPriceNonceSort(t, big.NewInt(5)) 42 testTransactionPriceNonceSort(t, big.NewInt(50)) 43 } 44 45 // Tests that transactions can be correctly sorted according to their price in 46 // decreasing order, but at the same time with increasing nonces when issued by 47 // the same account. 48 func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) { 49 // Generate a batch of accounts to start with 50 keys := make([]*ecdsa.PrivateKey, 25) 51 for i := 0; i < len(keys); i++ { 52 keys[i], _ = crypto.GenerateKey() 53 } 54 signer := types.LatestSignerForChainID(common.Big1) 55 56 // Generate a batch of transactions with overlapping values, but shifted nonces 57 groups := map[common.Address][]*txpool.LazyTransaction{} 58 expectedCount := 0 59 for start, key := range keys { 60 addr := crypto.PubkeyToAddress(key.PublicKey) 61 count := 25 62 for i := 0; i < 25; i++ { 63 var tx *types.Transaction 64 gasFeeCap := rand.Intn(50) 65 if baseFee == nil { 66 tx = types.NewTx(&types.LegacyTx{ 67 Nonce: uint64(start + i), 68 To: &common.Address{}, 69 Value: big.NewInt(100), 70 Gas: 100, 71 GasPrice: big.NewInt(int64(gasFeeCap)), 72 Data: nil, 73 }) 74 } else { 75 tx = types.NewTx(&types.DynamicFeeTx{ 76 Nonce: uint64(start + i), 77 To: &common.Address{}, 78 Value: big.NewInt(100), 79 Gas: 100, 80 GasFeeCap: big.NewInt(int64(gasFeeCap)), 81 GasTipCap: big.NewInt(int64(rand.Intn(gasFeeCap + 1))), 82 Data: nil, 83 }) 84 if count == 25 && int64(gasFeeCap) < baseFee.Int64() { 85 count = i 86 } 87 } 88 tx, err := types.SignTx(tx, signer, key) 89 if err != nil { 90 t.Fatalf("failed to sign tx: %s", err) 91 } 92 groups[addr] = append(groups[addr], &txpool.LazyTransaction{ 93 Hash: tx.Hash(), 94 Tx: tx, 95 Time: tx.Time(), 96 GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()), 97 GasTipCap: uint256.MustFromBig(tx.GasTipCap()), 98 Gas: tx.Gas(), 99 BlobGas: tx.BlobGas(), 100 }) 101 } 102 expectedCount += count 103 } 104 // Sort the transactions and cross check the nonce ordering 105 txset := newTransactionsByPriceAndNonce(signer, groups, baseFee) 106 107 txs := types.Transactions{} 108 for tx, _ := txset.Peek(); tx != nil; tx, _ = txset.Peek() { 109 txs = append(txs, tx.Tx) 110 txset.Shift() 111 } 112 if len(txs) != expectedCount { 113 t.Errorf("expected %d transactions, found %d", expectedCount, len(txs)) 114 } 115 for i, txi := range txs { 116 fromi, _ := types.Sender(signer, txi) 117 118 // Make sure the nonce order is valid 119 for j, txj := range txs[i+1:] { 120 fromj, _ := types.Sender(signer, txj) 121 if fromi == fromj && txi.Nonce() > txj.Nonce() { 122 t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce()) 123 } 124 } 125 // If the next tx has different from account, the price must be lower than the current one 126 if i+1 < len(txs) { 127 next := txs[i+1] 128 fromNext, _ := types.Sender(signer, next) 129 tip, err := txi.EffectiveGasTip(baseFee) 130 nextTip, nextErr := next.EffectiveGasTip(baseFee) 131 if err != nil || nextErr != nil { 132 t.Errorf("error calculating effective tip: %v, %v", err, nextErr) 133 } 134 if fromi != fromNext && tip.Cmp(nextTip) < 0 { 135 t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice()) 136 } 137 } 138 } 139 } 140 141 // Tests that if multiple transactions have the same price, the ones seen earlier 142 // are prioritized to avoid network spam attacks aiming for a specific ordering. 143 func TestTransactionTimeSort(t *testing.T) { 144 t.Parallel() 145 // Generate a batch of accounts to start with 146 keys := make([]*ecdsa.PrivateKey, 5) 147 for i := 0; i < len(keys); i++ { 148 keys[i], _ = crypto.GenerateKey() 149 } 150 signer := types.HomesteadSigner{} 151 152 // Generate a batch of transactions with overlapping prices, but different creation times 153 groups := map[common.Address][]*txpool.LazyTransaction{} 154 for start, key := range keys { 155 addr := crypto.PubkeyToAddress(key.PublicKey) 156 157 tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 100, big.NewInt(1), nil), signer, key) 158 tx.SetTime(time.Unix(0, int64(len(keys)-start))) 159 160 groups[addr] = append(groups[addr], &txpool.LazyTransaction{ 161 Hash: tx.Hash(), 162 Tx: tx, 163 Time: tx.Time(), 164 GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()), 165 GasTipCap: uint256.MustFromBig(tx.GasTipCap()), 166 Gas: tx.Gas(), 167 BlobGas: tx.BlobGas(), 168 }) 169 } 170 // Sort the transactions and cross check the nonce ordering 171 txset := newTransactionsByPriceAndNonce(signer, groups, nil) 172 173 txs := types.Transactions{} 174 for tx, _ := txset.Peek(); tx != nil; tx, _ = txset.Peek() { 175 txs = append(txs, tx.Tx) 176 txset.Shift() 177 } 178 if len(txs) != len(keys) { 179 t.Errorf("expected %d transactions, found %d", len(keys), len(txs)) 180 } 181 for i, txi := range txs { 182 fromi, _ := types.Sender(signer, txi) 183 if i+1 < len(txs) { 184 next := txs[i+1] 185 fromNext, _ := types.Sender(signer, next) 186 187 if txi.GasPrice().Cmp(next.GasPrice()) < 0 { 188 t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice()) 189 } 190 // Make sure time order is ascending if the txs have the same gas price 191 if txi.GasPrice().Cmp(next.GasPrice()) == 0 && txi.Time().After(next.Time()) { 192 t.Errorf("invalid received time ordering: tx #%d (A=%x T=%v) > tx #%d (A=%x T=%v)", i, fromi[:4], txi.Time(), i+1, fromNext[:4], next.Time()) 193 } 194 } 195 } 196 }