mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-16 17:03:46 +00:00
Use predetermined generation of transactions
- Same ECDSA key - Deterministic generation of data
This commit is contained in:
parent
ea1376e0b1
commit
399949cfa2
1 changed files with 39 additions and 35 deletions
|
|
@ -18,6 +18,7 @@ package legacypool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -1197,10 +1198,19 @@ func TestPendingGlobalLimiting(t *testing.T) {
|
||||||
func TestAllowedTxSize(t *testing.T) {
|
func TestAllowedTxSize(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create a test account and fund it
|
pool, _ := setupPool()
|
||||||
pool, key := setupPool()
|
|
||||||
defer pool.Close()
|
defer pool.Close()
|
||||||
|
|
||||||
|
// We use a deterministic ecdsa key to obtain signed transactions of pre-determined sizes.
|
||||||
|
key := &ecdsa.PrivateKey{
|
||||||
|
PublicKey: ecdsa.PublicKey{
|
||||||
|
Curve: elliptic.P256(),
|
||||||
|
X: new(big.Int).SetBytes(common.Hex2Bytes("78e68ff485cc934e4096f24091931e91334d6841c6c2be93d1a930e59783902d")),
|
||||||
|
Y: new(big.Int).SetBytes(common.Hex2Bytes("ca8db229299a4f937eeb0a36c451751cd59df978aceaaf190c28783c321cf267")),
|
||||||
|
},
|
||||||
|
D: new(big.Int).SetBytes(common.Hex2Bytes("e521e757356c1f197f704502dfa10333993e3705ca3d304d6a349461ed67ae71")),
|
||||||
|
}
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
testAddBalance(pool, account, big.NewInt(1000000000))
|
testAddBalance(pool, account, big.NewInt(1000000000))
|
||||||
|
|
||||||
|
|
@ -1212,7 +1222,7 @@ func TestAllowedTxSize(t *testing.T) {
|
||||||
t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err)
|
t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err)
|
||||||
}
|
}
|
||||||
// Try adding a transaction with random allowed size
|
// Try adding a transaction with random allowed size
|
||||||
tx = sizedDataTransaction(t, uint64(rand.Intn(txMaxSize+1)), 1, gasLimit, key)
|
tx = sizedDataTransaction(t, txMaxSize/2, 1, gasLimit, key)
|
||||||
if err := pool.addRemoteSync(tx); err != nil {
|
if err := pool.addRemoteSync(tx); err != nil {
|
||||||
t.Fatalf("failed to add transaction of random allowed size: %v", err)
|
t.Fatalf("failed to add transaction of random allowed size: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1221,8 +1231,8 @@ func TestAllowedTxSize(t *testing.T) {
|
||||||
if err := pool.addRemoteSync(tx); err == nil {
|
if err := pool.addRemoteSync(tx); err == nil {
|
||||||
t.Fatalf("expected rejection on slightly oversize transaction")
|
t.Fatalf("expected rejection on slightly oversize transaction")
|
||||||
}
|
}
|
||||||
// Try adding a transaction above maximum size by more than one
|
// Try adding a transaction above maximum size by two
|
||||||
tx = sizedDataTransaction(t, txMaxSize+2+uint64(rand.Intn(10*txMaxSize)), 2, gasLimit, key)
|
tx = sizedDataTransaction(t, txMaxSize+2, 2, gasLimit, key)
|
||||||
if err := pool.addRemoteSync(tx); err == nil {
|
if err := pool.addRemoteSync(tx); err == nil {
|
||||||
t.Fatalf("expected rejection on oversize transaction")
|
t.Fatalf("expected rejection on oversize transaction")
|
||||||
}
|
}
|
||||||
|
|
@ -1241,7 +1251,7 @@ func TestAllowedTxSize(t *testing.T) {
|
||||||
|
|
||||||
// sizedDataTransaction generates a transaction with the size matching the `targetSize` given
|
// sizedDataTransaction generates a transaction with the size matching the `targetSize` given
|
||||||
// as argument. It uses the nonce, gasLimit and key given as arguments to generate the transaction.
|
// as argument. It uses the nonce, gasLimit and key given as arguments to generate the transaction.
|
||||||
// Note some target sizes cannot be generated, notably: 99, 154, 258, 356, 65539 and 65538.
|
// Note around 1% of all possible sizes under [txMaxSize] cannot be generated by this function.
|
||||||
func sizedDataTransaction(t *testing.T, targetSize, nonce, gasLimit uint64, key *ecdsa.PrivateKey) (
|
func sizedDataTransaction(t *testing.T, targetSize, nonce, gasLimit uint64, key *ecdsa.PrivateKey) (
|
||||||
tx *types.Transaction) {
|
tx *types.Transaction) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
@ -1258,38 +1268,32 @@ func sizedDataTransaction(t *testing.T, targetSize, nonce, gasLimit uint64, key
|
||||||
|
|
||||||
// Find data length to reach the target size, assuming a signature of length 65.
|
// Find data length to reach the target size, assuming a signature of length 65.
|
||||||
// This is done because the data length header varies from 0 to 5 bytes.
|
// This is done because the data length header varies from 0 to 5 bytes.
|
||||||
var dataLength uint64
|
dataLength := targetSize - minimumSize
|
||||||
for dataLength = targetSize - minimumSize; dataLength > 0; dataLength-- {
|
data := make([]byte, dataLength)
|
||||||
data := make([]byte, dataLength)
|
for dataLength > 0 {
|
||||||
// Base this transaction on the transaction created in [pricedDataTransaction].
|
|
||||||
txWithData := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gasLimit, gasPrice, data)
|
txWithData := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gasLimit, gasPrice, data)
|
||||||
sizeWithSignature := txWithData.Size() + targetSignatureLength
|
signedTx, err := types.SignTx(txWithData, types.HomesteadSigner{}, key)
|
||||||
// Note sizeWithSignature can decrease by 2 bytes eventhough the data length was decreased by 1 only.
|
if txSignatureLen(signedTx) != targetSignatureLength {
|
||||||
if sizeWithSignature < targetSize {
|
// try again with other data to get a signature of the desired length
|
||||||
break
|
for i := range data {
|
||||||
|
data[i]++
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
require.NoError(t, err, "signing transaction")
|
||||||
|
case signedTx.Size() == targetSize:
|
||||||
|
return signedTx
|
||||||
|
case signedTx.Size() < targetSize:
|
||||||
|
t.Fatalf("target size %d cannot be reached (%d smaller for data length %d)", targetSize, signedTx.Size(), dataLength)
|
||||||
|
default: // larger than targetSize
|
||||||
|
dataLength--
|
||||||
|
data = data[:dataLength]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
t.Fatalf("target size %d cannot be reached", targetSize)
|
||||||
previousDataLength := dataLength
|
return nil
|
||||||
for {
|
|
||||||
tx = pricedDataTransaction(nonce, gasLimit, gasPrice, key, dataLength)
|
|
||||||
size := tx.Size()
|
|
||||||
if size == targetSize {
|
|
||||||
return tx
|
|
||||||
} else if txSignatureLen(tx) != targetSignatureLength {
|
|
||||||
continue // re-generate with new random data to obtain a signature of 65 bytes.
|
|
||||||
}
|
|
||||||
// The final RLP encoding size sometimes varies by 1 to 2 bytes compared to the target size.
|
|
||||||
newDataLength := dataLength + 1
|
|
||||||
if size > targetSize {
|
|
||||||
newDataLength = dataLength - 1
|
|
||||||
}
|
|
||||||
if newDataLength == previousDataLength {
|
|
||||||
t.Fatalf("impossible to generate a transaction of length %d", targetSize)
|
|
||||||
}
|
|
||||||
previousDataLength = dataLength
|
|
||||||
dataLength = newDataLength
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func txSignatureLen(tx *types.Transaction) uint64 {
|
func txSignatureLen(tx *types.Transaction) uint64 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue