Skip to content

Commit f11e1db

Browse files
committed
test(eip8141): pin blob-carrying frame-tx signature-hash coverage
1 parent 86cbfbe commit f11e1db

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

src/Nethermind/Nethermind.Core.Test/Encoding/FrameTxDecoderTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,30 @@ public void ComputeSigHash_FrameFieldChanges_HashChanges()
109109
Assert.That(FrameTxSigHash.ComputeValue(second), Is.Not.EqualTo(FrameTxSigHash.ComputeValue(first)));
110110
}
111111

112+
[Test]
113+
public void ComputeSigHash_MaxFeePerBlobGasChanges_HashChanges()
114+
{
115+
// The blob fields are the last two elements of the signing preimage (matching EELS #3047's
116+
// FrameTransaction layout); the signature must commit to them.
117+
Transaction first = CreateFrameTx();
118+
first.MaxFeePerBlobGas = 7;
119+
Transaction second = CreateFrameTx();
120+
second.MaxFeePerBlobGas = 8;
121+
122+
Assert.That(FrameTxSigHash.ComputeValue(second), Is.Not.EqualTo(FrameTxSigHash.ComputeValue(first)));
123+
}
124+
125+
[Test]
126+
public void ComputeSigHash_BlobVersionedHashesChange_HashChanges()
127+
{
128+
Transaction first = CreateFrameTx();
129+
first.BlobVersionedHashes = [FilledBytes(32, 0x01)];
130+
Transaction second = CreateFrameTx();
131+
second.BlobVersionedHashes = [FilledBytes(32, 0x02)];
132+
133+
Assert.That(FrameTxSigHash.ComputeValue(second), Is.Not.EqualTo(FrameTxSigHash.ComputeValue(first)));
134+
}
135+
112136
private static IEnumerable<TestCaseData> RoundtripCases()
113137
{
114138
yield return new TestCaseData(CreateFrameTx()).SetName("Roundtrip_MinimalSingleFrame");

src/Nethermind/Nethermind.Evm.Test/FrameTxSignatureValidatorTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,36 @@ public void Validate_Secp256k1SignsCanonicalHashWithExplicitSigner_ReturnsTrue()
4949
Assert.That(error, Is.Null);
5050
}
5151

52+
[Test]
53+
public void Validate_Secp256k1BlobCarryingTx_ReturnsTrueAndResolvesSigner()
54+
{
55+
// A blob-carrying frame tx: the blob fields are in the sig-hash preimage (EIP-8141 /
56+
// EELS #3047), so a signature computed over that hash validates and resolves the signer.
57+
Transaction tx = CreateFrameTx();
58+
tx.MaxFeePerBlobGas = 3;
59+
tx.BlobVersionedHashes = [BlobVersionedHash(0x01), BlobVersionedHash(0x02)];
60+
tx.FrameSignatures = [Secp256k1Entry(tx, TestItem.PrivateKeyB, signer: TestItem.PrivateKeyB.Address)];
61+
62+
Assert.That(Validate(tx, out string? error), Is.True);
63+
Assert.That(error, Is.Null);
64+
}
65+
66+
[Test]
67+
public void Validate_BlobFieldTamperedAfterSigning_ReturnsFalse()
68+
{
69+
// The signature commits to the blob fields; mutating one after signing must invalidate it,
70+
// proving the sig-hash preimage covers max_fee_per_blob_gas and blob_versioned_hashes.
71+
Transaction tx = CreateFrameTx();
72+
tx.MaxFeePerBlobGas = 3;
73+
tx.BlobVersionedHashes = [BlobVersionedHash(0x01)];
74+
tx.FrameSignatures = [Secp256k1Entry(tx, TestItem.PrivateKeyB, signer: TestItem.PrivateKeyB.Address)];
75+
76+
tx.BlobVersionedHashes = [BlobVersionedHash(0x02)];
77+
78+
Assert.That(Validate(tx, out string? error), Is.False);
79+
Assert.That(error, Is.EqualTo(FrameTxSignatureValidator.InvalidSignature));
80+
}
81+
5282
[Test]
5383
public void Validate_Secp256k1WithAbsentSigner_ResolvesToTxSender()
5484
{
@@ -327,6 +357,13 @@ private static byte[] ToVrs(Signature signature)
327357
return bytes;
328358
}
329359

360+
private static byte[] BlobVersionedHash(byte fill)
361+
{
362+
byte[] hash = new byte[Hash256.Size];
363+
hash.AsSpan().Fill(fill);
364+
return hash;
365+
}
366+
330367
private static byte[] Pad32(byte[] value)
331368
{
332369
if (value.Length == 32) return value;

0 commit comments

Comments
 (0)