-
Notifications
You must be signed in to change notification settings - Fork 434
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into feature/eip-7742
- Loading branch information
Showing
16 changed files
with
518 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
namespace Evm.T8n.Errors; | ||
|
||
public class GethErrorMappings | ||
{ | ||
private const string WrongTransactionNonceError = "wrong transaction nonce"; | ||
private const string WrongTransactionNonceGethError = "nonce too low: address {0}, tx: {1} state: {2}"; | ||
|
||
private const string MissingTxToError = "TxMissingTo: Must be set."; | ||
private const string MissingTxToGethError = "rlp: input string too short for common.Address, decoding into (types.Transaction)(types.BlobTx).To"; | ||
|
||
public static string GetErrorMapping(string error, params object[] arguments) | ||
{ | ||
return error switch | ||
{ | ||
WrongTransactionNonceError => string.Format(WrongTransactionNonceGethError, arguments), | ||
MissingTxToError => string.Format(MissingTxToGethError), | ||
_ => error | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
namespace Evm.T8n.JsonTypes; | ||
|
||
public readonly record struct RejectedTx(int Index, string Error); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
using System.Text.Json.Serialization; | ||
using Ethereum.Test.Base; | ||
using Nethermind.Core; | ||
using Nethermind.Core.Collections; | ||
using Nethermind.Core.Crypto; | ||
using Nethermind.Core.Specs; | ||
using Nethermind.Evm; | ||
using Nethermind.Evm.Tracing; | ||
using Nethermind.Int256; | ||
using Nethermind.Serialization.Rlp; | ||
using Nethermind.State; | ||
using Nethermind.State.Proofs; | ||
|
||
namespace Evm.T8n.JsonTypes; | ||
|
||
public class T8nResult | ||
{ | ||
public Hash256? StateRoot { get; set; } | ||
public Hash256? TxRoot { get; set; } | ||
public Hash256? ReceiptsRoot { get; set; } | ||
public Hash256? WithdrawalsRoot { get; set; } | ||
public Hash256? LogsHash { get; set; } | ||
public Bloom? LogsBloom { get; set; } | ||
public TxReceipt[]? Receipts { get; set; } | ||
public RejectedTx[]? Rejected { get; set; } | ||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] | ||
public UInt256? CurrentDifficulty { get; set; } | ||
public UInt256? GasUsed { get; set; } | ||
public UInt256? CurrentBaseFee { get; set; } | ||
public UInt256? CurrentExcessBlobGas { get; set; } | ||
public UInt256? BlobGasUsed { get; set; } | ||
public Dictionary<Address, AccountState> Accounts { get; set; } = []; | ||
public byte[] TransactionsRlp { get; set; } = []; | ||
|
||
|
||
public static T8nResult ConstructT8nResult(WorldState stateProvider, | ||
Block block, | ||
T8nTest test, | ||
StorageTxTracer storageTracer, | ||
BlockReceiptsTracer blockReceiptsTracer, | ||
ISpecProvider specProvider, | ||
TransactionExecutionReport txReport) | ||
{ | ||
IReceiptSpec receiptSpec = specProvider.GetSpec(block.Header); | ||
Hash256 txRoot = TxTrie.CalculateRoot(txReport.SuccessfulTransactions.ToArray()); | ||
Hash256 receiptsRoot = ReceiptTrie<TxReceipt>.CalculateRoot(receiptSpec, | ||
txReport.SuccessfulTransactionReceipts.ToArray(), new ReceiptMessageDecoder()); | ||
LogEntry[] logEntries = txReport.SuccessfulTransactionReceipts | ||
.SelectMany(receipt => receipt.Logs ?? Enumerable.Empty<LogEntry>()) | ||
.ToArray(); | ||
var bloom = new Bloom(logEntries); | ||
var gasUsed = blockReceiptsTracer.TxReceipts.Count == 0 ? 0 : (ulong)blockReceiptsTracer.LastReceipt.GasUsedTotal; | ||
ulong? blobGasUsed = test.Spec.IsEip4844Enabled ? BlobGasCalculator.CalculateBlobGas(txReport.ValidTransactions.ToArray()) : null; | ||
|
||
T8nResult t8NResult = new() | ||
{ | ||
StateRoot = stateProvider.StateRoot, | ||
TxRoot = txRoot, | ||
ReceiptsRoot = receiptsRoot, | ||
LogsBloom = bloom, | ||
LogsHash = Keccak.Compute(Rlp.OfEmptySequence.Bytes), | ||
Receipts = txReport.SuccessfulTransactionReceipts.ToArray(), | ||
Rejected = txReport.RejectedTransactionReceipts.Count == 0 | ||
? null | ||
: txReport.RejectedTransactionReceipts.ToArray(), | ||
CurrentDifficulty = test.CurrentDifficulty, | ||
GasUsed = new UInt256(gasUsed), | ||
CurrentBaseFee = test.CurrentBaseFee, | ||
WithdrawalsRoot = block.WithdrawalsRoot, | ||
CurrentExcessBlobGas = block.ExcessBlobGas, | ||
BlobGasUsed = blobGasUsed, | ||
TransactionsRlp = Rlp.Encode(txReport.SuccessfulTransactions.ToArray()).Bytes, | ||
Accounts = CollectAccounts(test, stateProvider, storageTracer, block), | ||
}; | ||
|
||
return t8NResult; | ||
} | ||
|
||
private static Dictionary<Address, AccountState> CollectAccounts(T8nTest test, WorldState stateProvider, StorageTxTracer storageTracer, Block block) | ||
{ | ||
Dictionary<Address, AccountState?> accounts = test.Alloc.Keys.ToDictionary(address => address, | ||
address => GetAccountState(address, stateProvider, storageTracer)); | ||
|
||
accounts.AddRange(test.Ommers.ToDictionary(ommer => ommer.Address, | ||
ommer => GetAccountState(ommer.Address, stateProvider, storageTracer))); | ||
|
||
if (block.Beneficiary is not null) | ||
{ | ||
accounts[block.Beneficiary] = GetAccountState(block.Beneficiary, stateProvider, storageTracer); | ||
} | ||
|
||
foreach (Transaction tx in test.Transactions) | ||
{ | ||
if (tx.To is not null && !accounts.ContainsKey(tx.To)) | ||
{ | ||
accounts[tx.To] = GetAccountState(tx.To, stateProvider, storageTracer); | ||
} | ||
if (tx.SenderAddress is not null && !accounts.ContainsKey(tx.SenderAddress)) | ||
{ | ||
accounts[tx.SenderAddress] = GetAccountState(tx.SenderAddress, stateProvider, storageTracer); | ||
} | ||
} | ||
|
||
return accounts | ||
.Where(addressAndAccount => addressAndAccount.Value is not null) | ||
.ToDictionary(addressAndAccount => addressAndAccount.Key, addressAndAccount => addressAndAccount.Value!); | ||
} | ||
|
||
private static AccountState? GetAccountState(Address address, WorldState stateProvider, StorageTxTracer storageTxTracer) | ||
{ | ||
if (!stateProvider.AccountExists(address)) return null; | ||
|
||
Account account = stateProvider.GetAccount(address); | ||
var code = stateProvider.GetCode(address); | ||
var accountState = new AccountState | ||
{ | ||
Nonce = account.Nonce, | ||
Balance = account.Balance, | ||
Code = code | ||
}; | ||
|
||
accountState.Storage = storageTxTracer.GetStorage(address) ?? []; | ||
|
||
return accountState; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
using Nethermind.Core; | ||
|
||
namespace Evm.T8n.JsonTypes; | ||
|
||
|
||
public class TransactionExecutionReport | ||
{ | ||
public List<RejectedTx> RejectedTransactionReceipts { get; set; } = []; | ||
public List<Transaction> ValidTransactions { get; set; } = []; | ||
public List<Transaction> SuccessfulTransactions { get; set; } = []; | ||
public List<TxReceipt> SuccessfulTransactionReceipts { get; set; } = []; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
using Nethermind.Core; | ||
using Nethermind.Evm.Tracing; | ||
using Nethermind.Int256; | ||
|
||
namespace Evm.T8n; | ||
|
||
public class StorageTxTracer : TxTracer, IBlockTracer | ||
{ | ||
private readonly Dictionary<Address, Dictionary<UInt256, byte[]>> _storages = new(); | ||
public bool IsTracingRewards => false; | ||
public override bool IsTracingOpLevelStorage => true; | ||
|
||
public override void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan<byte> newValue, | ||
ReadOnlySpan<byte> currentValue) | ||
{ | ||
if (!_storages.TryGetValue(address, out _)) | ||
{ | ||
_storages[address] = []; | ||
} | ||
|
||
_storages[address][storageIndex] = newValue.ToArray(); | ||
} | ||
|
||
public Dictionary<UInt256, byte[]>? GetStorage(Address address) | ||
{ | ||
_storages.TryGetValue(address, out Dictionary<UInt256, byte[]>? storage); | ||
return storage; | ||
} | ||
|
||
public void ReportReward(Address author, string rewardType, UInt256 rewardValue) { } | ||
|
||
public void StartNewBlockTrace(Block block) { } | ||
|
||
public ITxTracer StartNewTxTrace(Transaction? tx) => this; | ||
|
||
public void EndTxTrace() { } | ||
|
||
public void EndBlockTrace() { } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
using Evm.T8n.Errors; | ||
using Nethermind.Core; | ||
using Nethermind.Core.Crypto; | ||
using Nethermind.Evm; | ||
|
||
namespace Evm.T8n; | ||
|
||
public class T8nBlockHashProvider : IBlockhashProvider | ||
{ | ||
private readonly Dictionary<long, Hash256?> _blockHashes = new(); | ||
private static readonly int _maxDepth = 256; | ||
|
||
public Hash256? GetBlockhash(BlockHeader currentBlock, in long number) | ||
{ | ||
long current = currentBlock.Number; | ||
if (number >= current || number < current - Math.Min(current, _maxDepth)) | ||
{ | ||
return null; | ||
} | ||
|
||
return _blockHashes.GetValueOrDefault(number, null) ?? | ||
throw new T8nException($"BlockHash for block {number} not provided", | ||
T8nErrorCodes.ErrorMissingBlockhash); | ||
} | ||
|
||
public void Insert(Hash256 blockHash, long number) | ||
{ | ||
_blockHashes[number] = blockHash; | ||
} | ||
} |
Oops, something went wrong.