diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 2fdf890320..1ba080b749 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -108,11 +108,33 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec return tx } -func pricedDataTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey, bytes uint64) *types.Transaction { - data := make([]byte, bytes) - crand.Read(data) +// pricedDataTransaction generates a signed transaction with fixed-size data, +// and ensures that the resulting signature components (r and s) are exactly 32 bytes each, +// producing transactions with deterministic size. +// +// This avoids variability in transaction size caused by leading zeros being omitted in +// RLP encoding of r/s. Since r and s are derived from ECDSA, they occasionally have leading +// zeros and thus can be shorter than 32 bytes. +// +// For example: +// +// r: 0 leading zeros, bytesSize: 32, bytes: [221 ... 101] +// s: 1 leading zeros, bytesSize: 31, bytes: [0 75 ... 47] +func pricedDataTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey, dataBytes uint64) *types.Transaction { + var tx *types.Transaction - tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gaslimit, gasprice, data), types.HomesteadSigner{}, key) + // 10 attempts is statistically sufficient since leading zeros in ECDSA signatures are rare and randomly distributed. + var retryTimes = 10 + for i := 0; i < retryTimes; i++ { + data := make([]byte, dataBytes) + crand.Read(data) + + tx, _ = types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gaslimit, gasprice, data), types.HomesteadSigner{}, key) + _, r, s := tx.RawSignatureValues() + if len(r.Bytes()) == 32 && len(s.Bytes()) == 32 { + break + } + } return tx } @@ -1239,7 +1261,7 @@ func TestAllowedTxSize(t *testing.T) { const largeDataLength = txMaxSize - 200 // enough to have a 5 bytes RLP encoding of the data length number txWithLargeData := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, largeDataLength) maxTxLengthWithoutData := txWithLargeData.Size() - largeDataLength // 103 bytes - maxTxDataLength := txMaxSize - maxTxLengthWithoutData // 131072 - 103 = 130953 bytes + maxTxDataLength := txMaxSize - maxTxLengthWithoutData // 131072 - 103 = 130969 bytes // Try adding a transaction with maximal allowed size tx := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength)