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