@@ -109,11 +109,33 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec
109109 return tx
110110}
111111
112- func pricedDataTransaction (nonce uint64 , gaslimit uint64 , gasprice * big.Int , key * ecdsa.PrivateKey , bytes uint64 ) * types.Transaction {
113- data := make ([]byte , bytes )
114- crand .Read (data )
115-
116- tx , _ := types .SignTx (types .NewTransaction (nonce , common.Address {}, big .NewInt (0 ), gaslimit , gasprice , data ), types.HomesteadSigner {}, key )
112+ // pricedDataTransaction generates a signed transaction with fixed-size data,
113+ // and ensures that the resulting signature components (r and s) are exactly 32 bytes each,
114+ // producing transactions with deterministic size.
115+ //
116+ // This avoids variability in transaction size caused by leading zeros being omitted in
117+ // RLP encoding of r/s. Since r and s are derived from ECDSA, they occasionally have leading
118+ // zeros and thus can be shorter than 32 bytes.
119+ //
120+ // For example:
121+ //
122+ // r: 0 leading zeros, bytesSize: 32, bytes: [221 ... 101]
123+ // s: 1 leading zeros, bytesSize: 31, bytes: [0 75 ... 47]
124+ func pricedDataTransaction (nonce uint64 , gaslimit uint64 , gasprice * big.Int , key * ecdsa.PrivateKey , dataBytes uint64 ) * types.Transaction {
125+ var tx * types.Transaction
126+
127+ // 10 attempts is statistically sufficient since leading zeros in ECDSA signatures are rare and randomly distributed.
128+ var retryTimes = 10
129+ for i := 0 ; i < retryTimes ; i ++ {
130+ data := make ([]byte , dataBytes )
131+ crand .Read (data )
132+
133+ tx , _ = types .SignTx (types .NewTransaction (nonce , common.Address {}, big .NewInt (0 ), gaslimit , gasprice , data ), types.HomesteadSigner {}, key )
134+ _ , r , s := tx .RawSignatureValues ()
135+ if len (r .Bytes ()) == 32 && len (s .Bytes ()) == 32 {
136+ break
137+ }
138+ }
117139 return tx
118140}
119141
@@ -1240,7 +1262,7 @@ func TestAllowedTxSize(t *testing.T) {
12401262 const largeDataLength = txMaxSize - 200 // enough to have a 5 bytes RLP encoding of the data length number
12411263 txWithLargeData := pricedDataTransaction (0 , pool .currentHead .Load ().GasLimit , big .NewInt (1 ), key , largeDataLength )
12421264 maxTxLengthWithoutData := txWithLargeData .Size () - largeDataLength // 103 bytes
1243- maxTxDataLength := txMaxSize - maxTxLengthWithoutData // 131072 - 103 = 130953 bytes
1265+ maxTxDataLength := txMaxSize - maxTxLengthWithoutData // 131072 - 103 = 130969 bytes
12441266
12451267 // Try adding a transaction with maximal allowed size
12461268 tx := pricedDataTransaction (0 , pool .currentHead .Load ().GasLimit , big .NewInt (1 ), key , maxTxDataLength )
0 commit comments