Skip to content

Commit

Permalink
Add DATAHASH opcode
Browse files Browse the repository at this point in the history
  • Loading branch information
flcl42 committed Dec 13, 2022
1 parent 5bccabe commit b021b8b
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 13 deletions.
60 changes: 60 additions & 0 deletions src/Nethermind/Nethermind.Evm.Test/Eip4844Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using FluentAssertions;
using Nethermind.Specs;
using NUnit.Framework;
using System;
using Nethermind.Int256;
using System.Linq;

namespace Nethermind.Evm.Test;

[TestFixture]
public class Eip4844Tests : VirtualMachineTestsBase
{
protected override long BlockNumber => MainnetSpecProvider.GrayGlacierBlockNumber;
protected override ulong Timestamp => MainnetSpecProvider.ShardingForkBlockTimestamp;

[TestCase(0, 0, Description = "Should return 0 when no hashes")]
[TestCase(1, 1, Description = "Should return 0 when out of range")]
[TestCase(2, 1, Description = "Should return 0 when way out of range")]
[TestCase(0, 1, Description = "Should return hash, when exists")]
[TestCase(1, 3, Description = "Should return hash, when exists")]
public void Test_datahash_index_in_range(int index, int datahashesCount)
{
byte[][] hashes = new byte[datahashesCount][];
for (int i = 0; i < datahashesCount; i++)
{
hashes[i] = new byte[32];
for (int n = 0; n < datahashesCount; n++)
{
hashes[i][n] = (byte)((i * 3 + 10 * 7) % 256);
}
}
byte[] expectedOutput = datahashesCount > index ? hashes[index] : new byte[32];

// Cost of transaction call + PUSH1 x4 + MSTORE (entry cost + 1 memory cell used)
const long GasCostOfCallingWrapper = GasCostOf.Transaction + GasCostOf.VeryLow * 5 + GasCostOf.Memory;

byte[] code = Prepare.EvmCode
.PushData(new UInt256((ulong)index))
.DATAHASH()
.MSTORE(0)
.Return(32, 0)
.Done;

TestAllTracerWithOutput result = Execute(BlockNumber, 50000, code, blobVersionedHashes: hashes, timestamp: Timestamp);

result.StatusCode.Should().Be(StatusCode.Success);
result.ReturnValue.SequenceEqual(expectedOutput);
AssertGas(result, GasCostOfCallingWrapper + GasCostOf.DataHash);
}

protected override TestAllTracerWithOutput CreateTracer()
{
TestAllTracerWithOutput tracer = base.CreateTracer();
tracer.IsTracingAccess = false;
return tracer;
}
}
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Evm.Test/InvalidOpcodeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public class InvalidOpcodeTests : VirtualMachineTestsBase
ShanghaiInstructions.Union(
new Instruction[]
{
// TODO: Add DATAHASH
Instruction.DATAHASH,
}
).ToArray();

Expand Down
8 changes: 5 additions & 3 deletions src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ protected TestAllTracerWithOutput Execute(params byte[] code)
return tracer;
}

protected TestAllTracerWithOutput Execute(long blockNumber, long gasLimit, byte[] code, long blockGasLimit = DefaultBlockGasLimit, ulong timestamp = 0)
protected TestAllTracerWithOutput Execute(long blockNumber, long gasLimit, byte[] code, long blockGasLimit = DefaultBlockGasLimit, ulong timestamp = 0, byte[][] blobVersionedHashes = null)
{
(Block block, Transaction transaction) = PrepareTx(blockNumber, gasLimit, code, blockGasLimit: blockGasLimit, timestamp: timestamp);
(Block block, Transaction transaction) = PrepareTx(blockNumber, gasLimit, code, blockGasLimit: blockGasLimit, timestamp: timestamp, blobVersionedHashes: blobVersionedHashes);
TestAllTracerWithOutput tracer = CreateTracer();
_processor.Execute(transaction, block.Header, tracer);
return tracer;
Expand All @@ -125,7 +125,8 @@ protected TestAllTracerWithOutput Execute(long blockNumber, long gasLimit, byte[
SenderRecipientAndMiner senderRecipientAndMiner = null,
int value = 1,
long blockGasLimit = DefaultBlockGasLimit,
ulong timestamp = 0)
ulong timestamp = 0,
byte[][] blobVersionedHashes = null)
{
senderRecipientAndMiner ??= SenderRecipientAndMiner.Default;
TestState.CreateAccount(senderRecipientAndMiner.Sender, 100.Ether());
Expand All @@ -144,6 +145,7 @@ protected TestAllTracerWithOutput Execute(long blockNumber, long gasLimit, byte[
.WithGasLimit(gasLimit)
.WithGasPrice(1)
.WithValue(value)
.WithBlobHashes(blobVersionedHashes)
.To(senderRecipientAndMiner.Recipient)
.SignedAndResolved(_ethereumEcdsa, senderRecipientAndMiner.SenderKey)
.TestObject;
Expand Down
9 changes: 2 additions & 7 deletions src/Nethermind/Nethermind.Evm/ByteCodeBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections;
using System.Collections.Generic;
using Nethermind.Core;
using Nethermind.Core.Collections;
using Nethermind.Core.Extensions;
using Nethermind.Int256;
using Nethermind.Serialization.Json;
using Org.BouncyCastle.Asn1.Mozilla;

namespace Nethermind.Evm
{
Expand Down Expand Up @@ -92,6 +85,8 @@ public static Prepare SELFBALANCE(this Prepare @this)
=> @this.Op(Instruction.SELFBALANCE);
public static Prepare BASEFEE(this Prepare @this)
=> @this.Op(Instruction.BASEFEE);
public static Prepare DATAHASH(this Prepare @this)
=> @this.Op(Instruction.DATAHASH);
public static Prepare POP(this Prepare @this)
=> @this.Op(Instruction.POP);
public static Prepare PC(this Prepare @this)
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm/GasCostOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public static class GasCostOf
public const long TxDataNonZero = 68;
public const long TxDataNonZeroEip2028 = 16;
public const long Transaction = 21000;
public const long DataHash = 3;
public const long Log = 375;
public const long LogTopic = 375;
public const long LogData = 8;
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm/Instruction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public enum Instruction : byte
CHAINID = 0x46,
SELFBALANCE = 0x47,
BASEFEE = 0x48,
DATAHASH = 0x49,

POP = 0x50,
MLOAD = 0x51,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ senderBalance < (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + value
recipientOrNull = recipient;

ExecutionEnvironment env = new();
env.TxExecutionContext = new TxExecutionContext(block, caller, effectiveGasPrice);
env.TxExecutionContext = new TxExecutionContext(block, caller, effectiveGasPrice, transaction.BlobVersionedHashes);
env.Value = value;
env.TransferValue = value;
env.Caller = caller;
Expand Down
4 changes: 3 additions & 1 deletion src/Nethermind/Nethermind.Evm/TxExecutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ namespace Nethermind.Evm
public BlockHeader Header { get; }
public Address Origin { get; }
public UInt256 GasPrice { get; }
public byte[][]? BlobVersionedHashes { get; }

public TxExecutionContext(BlockHeader blockHeader, Address origin, in UInt256 gasPrice)
public TxExecutionContext(BlockHeader blockHeader, Address origin, in UInt256 gasPrice, byte[][] blobVersionedHashes)
{
Header = blockHeader;
Origin = origin;
GasPrice = gasPrice;
BlobVersionedHashes = blobVersionedHashes;
}
}
}
26 changes: 26 additions & 0 deletions src/Nethermind/Nethermind.Evm/VirtualMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,32 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length)
stack.PushUInt256(in baseFee);
break;
}
case Instruction.DATAHASH:
{
if (!spec.IsEip4844Enabled)
{
EndInstructionTraceError(EvmExceptionType.BadInstruction);
return CallResult.InvalidInstructionException;
}

if (!UpdateGas(GasCostOf.DataHash, ref gasAvailable))
{
EndInstructionTraceError(EvmExceptionType.OutOfGas);
return CallResult.OutOfGasException;
}

stack.PopUInt256(out UInt256 blobIndex);

if (txCtx.BlobVersionedHashes is not null && blobIndex < txCtx.BlobVersionedHashes.Length)
{
stack.PushBytes(txCtx.BlobVersionedHashes[blobIndex.u0]);
}
else
{
stack.PushZero();
}
break;
}
case Instruction.POP:
{
if (!UpdateGas(GasCostOf.Base, ref gasAvailable))
Expand Down

0 comments on commit b021b8b

Please sign in to comment.