Skip to content

Commit

Permalink
Blob gas info in receipts (#5767)
Browse files Browse the repository at this point in the history
* Blob gas info in receipts

* Fix gas price

* Fix spaces

* Add tests

* Supports blobs

* Ignore on null

* Fix suggestions

* Fix build

---------

Co-authored-by: Nikita Mescheryakov <[email protected]>
  • Loading branch information
2 people authored and flcl42 committed Jun 12, 2023
1 parent 4fc22f1 commit 3e6253d
Show file tree
Hide file tree
Showing 13 changed files with 116 additions and 40 deletions.
7 changes: 5 additions & 2 deletions src/Nethermind/Nethermind.Evm/IntrinsicGasCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,14 @@ private static long AccessListCost(Transaction transaction, IReleaseSpec release

public static ulong CalculateDataGas(int blobCount) => (ulong)blobCount * Eip4844Constants.DataGasPerBlob;

public static ulong CalculateDataGas(Transaction transaction) =>
CalculateDataGas(transaction.BlobVersionedHashes?.Length ?? 0);

public static UInt256 CalculateDataGasPrice(BlockHeader header, Transaction transaction) =>
CalculateDataGas(transaction.BlobVersionedHashes?.Length ?? 0) * CalculateDataGasPricePerUnit(header);
CalculateDataGas(transaction) * CalculateDataGasPricePerUnit(header);

public static UInt256 CalculateDataGasPrice(BlockHeader header) =>
header.DataGasUsed.Value * CalculateDataGasPricePerUnit(header);
header.DataGasUsed!.Value * CalculateDataGasPricePerUnit(header);

public static UInt256 CalculateDataGasPricePerUnit(BlockHeader header)
{
Expand Down
35 changes: 35 additions & 0 deletions src/Nethermind/Nethermind.Evm/TransactionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,40 @@ tx.To is not null
: tx.IsSystem()
? tx.SenderAddress
: ContractAddress.From(tx.SenderAddress, nonce > 0 ? nonce - 1 : nonce);

public static TxGasInfo GetGasInfo(this Transaction tx, bool is1559Enabled, BlockHeader header)
{
UInt256 effectiveGasPrice = tx.CalculateEffectiveGasPrice(is1559Enabled, header.BaseFeePerGas);
ulong? dataGas = null;
UInt256? dataGasPrice = null;
if (tx.SupportsBlobs)
{
dataGas = IntrinsicGasCalculator.CalculateDataGas(tx);
dataGasPrice = IntrinsicGasCalculator.CalculateDataGasPrice(header, tx);
}

return new(effectiveGasPrice, dataGasPrice, dataGas);
}
}

public struct TxGasInfo
{
public TxGasInfo() { }

public TxGasInfo(UInt256? effectiveGasPrice, UInt256? dataGasPrice, ulong? dataGasUsed)
{
EffectiveGasPrice = effectiveGasPrice;
DataGasPrice = dataGasPrice;
DataGasUsed = dataGasUsed;
}

public TxGasInfo(UInt256? effectiveGasPrice)
{
EffectiveGasPrice = effectiveGasPrice;
}

public UInt256? EffectiveGasPrice { get; private set; }
public UInt256? DataGasPrice { get; private set; }
public ulong? DataGasUsed { get; private set; }
}
}
45 changes: 34 additions & 11 deletions src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using NSubstitute;
using NUnit.Framework;
using Nethermind.Config;
using Nethermind.Evm;

namespace Nethermind.Facade.Test
{
Expand Down Expand Up @@ -231,20 +232,34 @@ public void Bridge_head_is_correct(long headNumber)
_blockchainBridge.HeadBlock.Should().Be(head);
}

[TestCase(true)]
[TestCase(false)]
public void GetReceiptAndEffectiveGasPrice_returns_correct_results(bool isCanonical)
[TestCase(true, true)]
[TestCase(false, true)]
[TestCase(true, false)]
[TestCase(false, false)]
public void GetReceiptAndGasInfo_returns_correct_results(bool isCanonical, bool postEip4844)
{
Keccak txHash = TestItem.KeccakA;
Keccak blockHash = TestItem.KeccakB;
UInt256 effectiveGasPrice = 123;

Transaction tx = Build.A.Transaction
.WithGasPrice(effectiveGasPrice)
.TestObject;
Block block = Build.A.Block
.WithTransactions(tx)
.TestObject;
Transaction tx = postEip4844
? Build.A.Transaction
.WithGasPrice(effectiveGasPrice)
.WithType(TxType.Blob)
.WithMaxFeePerDataGas(2)
.WithBlobVersionedHashes(2)
.TestObject
: Build.A.Transaction
.WithGasPrice(effectiveGasPrice)
.TestObject;
Block block = postEip4844
? Build.A.Block
.WithTransactions(tx)
.WithExcessDataGas(2)
.TestObject
: Build.A.Block
.WithTransactions(tx)
.TestObject;
TxReceipt receipt = Build.A.Receipt
.WithBlockHash(blockHash)
.WithTransactionHash(txHash)
Expand All @@ -255,8 +270,16 @@ public void GetReceiptAndEffectiveGasPrice_returns_correct_results(bool isCanoni
_receiptStorage.FindBlockHash(txHash).Returns(blockHash);
_receiptStorage.Get(block).Returns(new[] { receipt });

(TxReceipt Receipt, UInt256? EffectiveGasPrice, int LogIndexStart) result = isCanonical ? (receipt, effectiveGasPrice, 0) : (null, null, 0);
_blockchainBridge.GetReceiptAndEffectiveGasPrice(txHash).Should().BeEquivalentTo(result);
(TxReceipt? Receipt, TxGasInfo? GasInfo, int LogIndexStart) result = postEip4844
? (receipt, new(effectiveGasPrice, 262144, 262144), 0)
: (receipt, new(effectiveGasPrice), 0);

if (!isCanonical)
{
result = (null, null, 0);
}

_blockchainBridge.GetReceiptAndGasInfo(txHash).Should().BeEquivalentTo(result);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>annotations</Nullable>
</PropertyGroup>

<ItemGroup>
Expand Down
9 changes: 4 additions & 5 deletions src/Nethermind/Nethermind.Facade/BlockchainBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public Block? HeadBlock

public bool IsMining { get; }

public (TxReceipt Receipt, UInt256? EffectiveGasPrice, int LogIndexStart) GetReceiptAndEffectiveGasPrice(Keccak txHash)
public (TxReceipt? Receipt, TxGasInfo? GasInfo, int LogIndexStart) GetReceiptAndGasInfo(Keccak txHash)
{
Keccak blockHash = _receiptFinder.FindBlockHash(txHash);
if (blockHash is not null)
Expand All @@ -96,15 +96,14 @@ public Block? HeadBlock
int logIndexStart = txReceipts.GetBlockLogFirstIndex(txReceipt.Index);
Transaction tx = block.Transactions[txReceipt.Index];
bool is1559Enabled = _specProvider.GetSpecFor1559(block.Number).IsEip1559Enabled;
UInt256 effectiveGasPrice = tx.CalculateEffectiveGasPrice(is1559Enabled, block.Header.BaseFeePerGas);
return (txReceipt, effectiveGasPrice, logIndexStart);
return (txReceipt, tx.GetGasInfo(is1559Enabled, block.Header), logIndexStart);
}
}

return (null, null, 0);
}

public (TxReceipt Receipt, Transaction Transaction, UInt256? baseFee) GetTransaction(Keccak txHash)
public (TxReceipt? Receipt, Transaction Transaction, UInt256? baseFee) GetTransaction(Keccak txHash)
{
Keccak blockHash = _receiptFinder.FindBlockHash(txHash);
if (blockHash is not null)
Expand Down Expand Up @@ -271,7 +270,7 @@ private void CallAndRestore(

if (releaseSpec.IsEip4844Enabled)
{
callHeader.DataGasUsed = IntrinsicGasCalculator.CalculateDataGas(transaction.BlobVersionedHashes?.Length ?? 0);
callHeader.DataGasUsed = IntrinsicGasCalculator.CalculateDataGas(transaction);
callHeader.ExcessDataGas = treatBlockHeaderAsParentBlock
? IntrinsicGasCalculator.CalculateExcessDataGas(blockHeader, releaseSpec)
: blockHeader.ExcessDataGas;
Expand Down
5 changes: 3 additions & 2 deletions src/Nethermind/Nethermind.Facade/IBlockchainBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Nethermind.Blockchain.Find;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Evm;
using Nethermind.Facade.Filters;
using Nethermind.Int256;
using Nethermind.Trie;
Expand All @@ -21,8 +22,8 @@ public interface IBlockchainBridge : ILogFinder
void RecoverTxSenders(Block block);
Address? RecoverTxSender(Transaction tx);
TxReceipt GetReceipt(Keccak txHash);
(TxReceipt Receipt, UInt256? EffectiveGasPrice, int LogIndexStart) GetReceiptAndEffectiveGasPrice(Keccak txHash);
(TxReceipt Receipt, Transaction Transaction, UInt256? baseFee) GetTransaction(Keccak txHash);
(TxReceipt? Receipt, TxGasInfo? GasInfo, int LogIndexStart) GetReceiptAndGasInfo(Keccak txHash);
(TxReceipt? Receipt, Transaction Transaction, UInt256? baseFee) GetTransaction(Keccak txHash);
BlockchainBridge.CallOutput Call(BlockHeader header, Transaction tx, CancellationToken cancellationToken);
BlockchainBridge.CallOutput EstimateGas(BlockHeader header, Transaction tx, CancellationToken cancellationToken);
BlockchainBridge.CallOutput CreateAccessList(BlockHeader header, Transaction tx, CancellationToken cancellationToken, bool optimize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void Are_log_indexes_unique()
};

UInt256 effectiveGasPrice = new(5526);
ReceiptForRpc receiptForRpc = new(txHash, receipt1, effectiveGasPrice);
ReceiptForRpc receiptForRpc = new(txHash, receipt1, new(effectiveGasPrice));
long?[] indexes = receiptForRpc.Logs.Select(log => log.LogIndex).ToArray();
long?[] expected = { 0, 1, 2 };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -818,8 +818,9 @@ public async Task Eth_get_block_by_number_with_recovering_sender_from_receipts()
Assert.That(serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"author\":\"0x0000000000000000000000000000000000000000\",\"difficulty\":\"0xf4240\",\"extraData\":\"0x010203\",\"gasLimit\":\"0x3d0900\",\"gasUsed\":\"0x0\",\"hash\":\"0xe3026a6708b90d5cb25557ac38ddc3f5ef550af10f31e1cf771524da8553fa1c\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"mixHash\":\"0x2ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e2\",\"nonce\":\"0x00000000000003e8\",\"number\":\"0x1\",\"parentHash\":\"0xff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09c\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"size\":\"0x221\",\"stateRoot\":\"0x1ef7300d8961797263939a3d29bbba4ccf1702fabf02d8ad7a20b454edb6fd2f\",\"totalDifficulty\":\"0x0\",\"timestamp\":\"0xf4240\",\"transactions\":[{\"nonce\":\"0x0\",\"blockHash\":\"0xe3026a6708b90d5cb25557ac38ddc3f5ef550af10f31e1cf771524da8553fa1c\",\"blockNumber\":\"0x1\",\"transactionIndex\":\"0x0\",\"from\":\"0x2d36e6c27c34ea22620e7b7c45de774599406cf3\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\",\"gasPrice\":\"0x1\",\"gas\":\"0x5208\",\"data\":\"0x\",\"input\":\"0x\",\"type\":\"0x0\"}],\"transactionsRoot\":\"0x29cc403075ed3d1d6af940d577125cc378ee5a26f7746cbaf87f1cf4a38258b5\",\"uncles\":[]},\"id\":67}"));
}

[Test]
public async Task Eth_get_transaction_receipt()
[TestCase(false)]
[TestCase(true)]
public async Task Eth_get_transaction_receipt(bool postEip4844)
{
using Context ctx = await Context.Create();
IBlockchainBridge blockchainBridge = Substitute.For<IBlockchainBridge>();
Expand All @@ -840,15 +841,20 @@ public async Task Eth_get_transaction_receipt()
.WithLogs(entries).TestObject;
TxReceipt[] receiptsTab = { receipt };

blockchainBridge.GetReceiptAndEffectiveGasPrice(Arg.Any<Keccak>()).Returns((receipt, UInt256.One, 0));

blockchainBridge.GetReceiptAndGasInfo(Arg.Any<Keccak>())
.Returns((receipt, postEip4844 ? new(UInt256.One, 2, 3) : new(UInt256.One), 0));
blockFinder.FindBlock(Arg.Any<BlockParameter>()).Returns(block);
receiptFinder.Get(Arg.Any<Block>()).Returns(receiptsTab);
receiptFinder.Get(Arg.Any<Keccak>()).Returns(receiptsTab);

ctx.Test = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).WithBlockFinder(blockFinder).WithReceiptFinder(receiptFinder).WithBlockchainBridge(blockchainBridge).Build();
string serialized = ctx.Test.TestEthRpc("eth_getTransactionReceipt", TestItem.KeccakA.ToString());

Assert.That(serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"transactionHash\":\"0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760\",\"transactionIndex\":\"0x2\",\"blockHash\":\"0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72\",\"blockNumber\":\"0x2\",\"cumulativeGasUsed\":\"0x3e8\",\"gasUsed\":\"0x64\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\",\"to\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"contractAddress\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"logs\":[{\"removed\":false,\"logIndex\":\"0x0\",\"transactionIndex\":\"0x2\",\"transactionHash\":\"0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760\",\"blockHash\":\"0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72\",\"blockNumber\":\"0x2\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]},{\"removed\":false,\"logIndex\":\"0x1\",\"transactionIndex\":\"0x2\",\"transactionHash\":\"0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760\",\"blockHash\":\"0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72\",\"blockNumber\":\"0x2\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]}],\"logsBloom\":\"0x00000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"root\":\"0x1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a69111\",\"status\":\"0x1\",\"error\":\"error\",\"type\":\"0x0\"},\"id\":67}"));
if (postEip4844)
Assert.That(serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"transactionHash\":\"0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760\",\"transactionIndex\":\"0x2\",\"blockHash\":\"0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72\",\"blockNumber\":\"0x2\",\"cumulativeGasUsed\":\"0x3e8\",\"gasUsed\":\"0x64\",\"dataGasUsed\":\"0x3\",\"dataGasPrice\":\"0x2\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\",\"to\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"contractAddress\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"logs\":[{\"removed\":false,\"logIndex\":\"0x0\",\"transactionIndex\":\"0x2\",\"transactionHash\":\"0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760\",\"blockHash\":\"0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72\",\"blockNumber\":\"0x2\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]},{\"removed\":false,\"logIndex\":\"0x1\",\"transactionIndex\":\"0x2\",\"transactionHash\":\"0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760\",\"blockHash\":\"0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72\",\"blockNumber\":\"0x2\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]}],\"logsBloom\":\"0x00000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"root\":\"0x1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a69111\",\"status\":\"0x1\",\"error\":\"error\",\"type\":\"0x0\"},\"id\":67}"));
else
Assert.That(serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"transactionHash\":\"0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760\",\"transactionIndex\":\"0x2\",\"blockHash\":\"0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72\",\"blockNumber\":\"0x2\",\"cumulativeGasUsed\":\"0x3e8\",\"gasUsed\":\"0x64\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\",\"to\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"contractAddress\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"logs\":[{\"removed\":false,\"logIndex\":\"0x0\",\"transactionIndex\":\"0x2\",\"transactionHash\":\"0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760\",\"blockHash\":\"0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72\",\"blockNumber\":\"0x2\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]},{\"removed\":false,\"logIndex\":\"0x1\",\"transactionIndex\":\"0x2\",\"transactionHash\":\"0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760\",\"blockHash\":\"0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72\",\"blockNumber\":\"0x2\",\"address\":\"0x0000000000000000000000000000000000000000\",\"data\":\"0x\",\"topics\":[\"0x0000000000000000000000000000000000000000000000000000000000000000\"]}],\"logsBloom\":\"0x00000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"root\":\"0x1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a69111\",\"status\":\"0x1\",\"error\":\"error\",\"type\":\"0x0\"},\"id\":67}"));
}


Expand Down Expand Up @@ -903,7 +909,7 @@ public async Task Eth_get_transaction_receipt_when_block_has_few_receipts()
Logs = logEntries
};

blockchainBridge.GetReceiptAndEffectiveGasPrice(Arg.Any<Keccak>()).Returns((receipt2, UInt256.One, 2));
blockchainBridge.GetReceiptAndGasInfo(Arg.Any<Keccak>()).Returns((receipt2, new(UInt256.One), 2));

TxReceipt[] receipts = { receipt1, receipt2 };

Expand Down Expand Up @@ -959,7 +965,7 @@ public async Task Eth_getTransactionReceipt_return_info_about_mined_tx()
blockFinder.FindBlock(Arg.Any<BlockParameter>()).Returns(block);
receiptFinder.Get(Arg.Any<Block>()).Returns(receiptsTab);
receiptFinder.Get(Arg.Any<Keccak>()).Returns(receiptsTab);
blockchainBridge.GetReceiptAndEffectiveGasPrice(Arg.Any<Keccak>()).Returns((receipt, UInt256.One, 0));
blockchainBridge.GetReceiptAndGasInfo(Arg.Any<Keccak>()).Returns((receipt, new(UInt256.One), 0));

ctx.Test = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).WithBlockFinder(blockFinder).WithReceiptFinder(receiptFinder).WithBlockchainBridge(blockchainBridge).Build();
string serialized = ctx.Test.TestEthRpc("eth_getTransactionReceipt", tx.Hash!.ToString());
Expand Down
Loading

0 comments on commit 3e6253d

Please sign in to comment.