Skip to content

Commit

Permalink
Remove 5 flow control exceptions (#7537)
Browse files Browse the repository at this point in the history
  • Loading branch information
benaadams authored Oct 2, 2024
1 parent dcc9ef1 commit 5e1dfc0
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 99 deletions.
74 changes: 63 additions & 11 deletions src/Nethermind/Nethermind.Evm/EvmPooledMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,30 @@ public void Save(in UInt256 location, Span<byte> value)
value.CopyTo(_memory.AsSpan((int)location, value.Length));
}

private static void CheckMemoryAccessViolation(in UInt256 location, in UInt256 length, out ulong newLength, out bool outOfGas)
{
if (location.IsLargerThanULong() || length.IsLargerThanULong())
{
outOfGas = true;
newLength = 0;
return;
}

CheckMemoryAccessViolationInner(location.u0, length.u0, out newLength, out outOfGas);
}

private static void CheckMemoryAccessViolation(in UInt256 location, in UInt256 length, out ulong newLength)
{
if (location.IsLargerThanULong() || length.IsLargerThanULong())
{
ThrowOutOfGasException();
}

CheckMemoryAccessViolation(location.u0, length.u0, out newLength);
CheckMemoryAccessViolationInner(location.u0, length.u0, out newLength, out bool outOfGas);
if (outOfGas)
{
ThrowOutOfGasException();
}
}

private static void CheckMemoryAccessViolation(in UInt256 location, ulong length, out ulong newLength)
Expand All @@ -78,17 +94,24 @@ private static void CheckMemoryAccessViolation(in UInt256 location, ulong length
ThrowOutOfGasException();
}

CheckMemoryAccessViolation(location.u0, length, out newLength);
CheckMemoryAccessViolationInner(location.u0, length, out newLength, out bool outOfGas);
if (outOfGas)
{
ThrowOutOfGasException();
}
}

private static void CheckMemoryAccessViolation(ulong location, ulong length, out ulong newLength)
private static void CheckMemoryAccessViolationInner(ulong location, ulong length, out ulong newLength, out bool outOfGas)
{
ulong totalSize = location + length;
if (totalSize < location || totalSize > long.MaxValue)
{
ThrowOutOfGasException();
outOfGas = true;
newLength = 0;
return;
}

outOfGas = false;
newLength = totalSize;
}

Expand Down Expand Up @@ -197,19 +220,23 @@ private void ClearForTracing(ulong size)
}
}

public long CalculateMemoryCost(in UInt256 location, in UInt256 length)
public long CalculateMemoryCost(in UInt256 location, in UInt256 length, out bool outOfGas)
{
outOfGas = false;
if (length.IsZero)
{
return 0L;
}

CheckMemoryAccessViolation(in location, in length, out ulong newSize);
CheckMemoryAccessViolation(in location, in length, out ulong newSize, out outOfGas);
if (outOfGas) return 0;

if (newSize > Size)
{
long newActiveWords = Div32Ceiling(newSize);
long activeWords = Div32Ceiling(Size);
long newActiveWords = Div32Ceiling(newSize, out outOfGas);
if (outOfGas) return 0;
long activeWords = Div32Ceiling(Size, out outOfGas);
if (outOfGas) return 0;

// TODO: guess it would be well within ranges but this needs to be checked and comment need to be added with calculations
ulong cost = (ulong)
Expand All @@ -230,6 +257,17 @@ public long CalculateMemoryCost(in UInt256 location, in UInt256 length)
return 0L;
}

public long CalculateMemoryCost(in UInt256 location, in UInt256 length)
{
long result = CalculateMemoryCost(in location, in length, out bool outOfGas);
if (outOfGas)
{
throw new OutOfGasException();
}

return result;
}

public TraceMemory GetTrace()
{
ulong size = Size;
Expand All @@ -247,11 +285,12 @@ public void Dispose()
}
}

public static long Div32Ceiling(in UInt256 length)
public static long Div32Ceiling(in UInt256 length, out bool outOfGas)
{
if (length.IsLargerThanULong())
{
ThrowOutOfGasException();
outOfGas = true;
return 0;
}

ulong result = length.u0;
Expand All @@ -264,12 +303,25 @@ public static long Div32Ceiling(in UInt256 length)

if (result > int.MaxValue)
{
ThrowOutOfGasException();
outOfGas = true;
return 0;
}

outOfGas = false;
return (long)result;
}

public static long Div32Ceiling(in UInt256 length)
{
long result = Div32Ceiling(in length, out bool outOfGas);
if (outOfGas)
{
ThrowOutOfGasException();
}

return result;
}

private void UpdateSize(in UInt256 location, in UInt256 length, bool rentIfNeeded = true)
{
UpdateSize((ulong)(location + length), rentIfNeeded);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,10 @@ protected virtual void ExecuteEvmCall(
if (tx.IsContractCreation)
{
// if transaction is a contract creation then recipient address is the contract deployment address
PrepareAccountForContractDeployment(env.ExecutingAccount, spec);
if (!PrepareAccountForContractDeployment(env.ExecutingAccount, spec))
{
goto Fail;
}
}

ExecutionType executionType = tx.IsContractCreation ? ExecutionType.CREATE : ExecutionType.TRANSACTION;
Expand Down Expand Up @@ -616,14 +619,16 @@ protected virtual void PayFees(Transaction tx, BlockHeader header, IReleaseSpec
}
}

protected void PrepareAccountForContractDeployment(Address contractAddress, IReleaseSpec spec)
protected bool PrepareAccountForContractDeployment(Address contractAddress, IReleaseSpec spec)
{
if (WorldState.AccountExists(contractAddress) && contractAddress.IsNonZeroAccount(spec, _codeInfoRepository, WorldState))
{
if (Logger.IsTrace) Logger.Trace($"Contract collision at {contractAddress}");

ThrowTransactionCollisionException();
return false;
}

return true;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down Expand Up @@ -658,10 +663,6 @@ protected virtual long Refund(Transaction tx, BlockHeader header, IReleaseSpec s
[DoesNotReturn]
[StackTraceHidden]
private static void ThrowInvalidDataException(string message) => throw new InvalidDataException(message);

[DoesNotReturn]
[StackTraceHidden]
private static void ThrowTransactionCollisionException() => throw new TransactionCollisionException();
}

public readonly struct TransactionResult(string? error)
Expand Down
Loading

0 comments on commit 5e1dfc0

Please sign in to comment.