Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

standardize BlobTxMissingBlobs error message #8129

Merged
merged 9 commits into from
Feb 3, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public static string BlobTxGasLimitExceeded(ulong totalDataGas, ulong maxBlobGas
$"BlobTxGasLimitExceeded: Transaction's totalDataGas={totalDataGas} exceeded MaxBlobGas per transaction={maxBlobGas}.";

public const string BlobTxMissingBlobs =
"BlobTxMissingBlobs: Blob transaction must have blobs.";
"blob transaction missing blob hashes";

public const string MissingBlobVersionedHash =
"MissingBlobVersionedHash: Must be set.";
Expand Down
339 changes: 339 additions & 0 deletions src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,4 +319,343 @@ public void Call_sets_maxFeePerBlobGas()
Arg.Is<BlockExecutionContext>(static blkCtx => blkCtx.Header.Beneficiary == TestItem.AddressB),
Arg.Any<ITxTracer>());
}

[Test]
public void Call_tx_returns_InsufficientSenderBalanceError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 100 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.InsufficientSenderBalance);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: insufficient sender balance (supplied gas 100)"));
}

[Test]
public void EstimateGas_tx_returns_InsufficientSenderBalanceError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 100 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.InsufficientSenderBalance);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: insufficient sender balance (supplied gas 100)"));
}

[Test]
public void Call_tx_returns_SenderNotSpecifiedError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 123 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.SenderNotSpecified);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: sender not specified (supplied gas 123)"));
}

[Test]
public void EstimateGas_tx_returns_SenderNotSpecifiedError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 123 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.SenderNotSpecified);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: sender not specified (supplied gas 123)"));
}

[Test]
public void Call_tx_returns_MalformedTransactionError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.MalformedTransaction);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: malformed (supplied gas 0)"));
}

[Test]
public void EstimateGas_tx_returns_MalformedTransactionError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.MalformedTransaction);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: malformed (supplied gas 0)"));
}

[Test]
public void Call_tx_returns_WrongTransactionNonceError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 456 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.WrongTransactionNonce);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: wrong transaction nonce (supplied gas 456)"));
}

[Test]
public void EstimateGas_tx_returns_WrongTransactionNonceError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 456 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.WrongTransactionNonce);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: wrong transaction nonce (supplied gas 456)"));
}

[Test]
public void Call_tx_returns_NonceOverflowError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 0 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.NonceOverflow);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: nonce overflow (supplied gas 0)"));
}

[Test]
public void EstimateGas_tx_returns_NonceOverflowError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 0 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.NonceOverflow);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: nonce overflow (supplied gas 0)"));
}

[Test]
public void Call_tx_returns_MinerPremiumIsNegativeError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 1 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.MinerPremiumNegative);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: miner premium is negative (supplied gas 1)"));
}

[Test]
public void EstimateGas_tx_returns_MinerPremiumIsNegativeError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 1 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.MinerPremiumNegative);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: miner premium is negative (supplied gas 1)"));
}

[Test]
public void Call_tx_returns_BlockGasLimitExceededError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 1 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.BlockGasLimitExceeded);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: Block gas limit exceeded (supplied gas 1)"));
}

[Test]
public void EstimateGas_tx_returns_BlockGasLimitExceededError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 1 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.BlockGasLimitExceeded);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: Block gas limit exceeded (supplied gas 1)"));
}


[Test]
public void Call_tx_returns_SenderHasDeployedCodeError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 1 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.SenderHasDeployedCode);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: sender has deployed code (supplied gas 1)"));
}

[Test]
public void EstimateGas_tx_returns_SenderHasDeployedCodeError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new() { GasLimit = 1 };
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.SenderHasDeployedCode);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: sender has deployed code (supplied gas 1)"));
}

[Test]
public void Call_tx_returns_TransactionSizeOverMaxInitCodeSizeError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.TransactionSizeOverMaxInitCodeSize);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: EIP-3860 - transaction size over max init code size (supplied gas 0)"));
}

[Test]
public void EstimateGas_tx_returns_TransactionSizeOverMaxInitCodeSizeError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.TransactionSizeOverMaxInitCodeSize);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: EIP-3860 - transaction size over max init code size (supplied gas 0)"));
}

[Test]
public void Call_tx_returns_GasLimitBelowIntrinsicGasError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.GasLimitBelowIntrinsicGas);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: gas limit below intrinsic gas (supplied gas 0)"));
}

[Test]
public void EstimateGas_tx_returns_GasLimitBelowIntrinsicGasError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.GasLimitBelowIntrinsicGas);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: gas limit below intrinsic gas (supplied gas 0)"));
}

[Test]
public void Call_tx_returns_InsufficientMaxFeePerGasForSenderBalanceError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.InsufficientMaxFeePerGasForSenderBalance);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.EqualTo("err: insufficient MaxFeePerGas for sender balance (supplied gas 0)"));
}

[Test]
public void EstimateGas_tx_returns_InsufficientMaxFeePerGasForSenderBalanceError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();
_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.InsufficientMaxFeePerGasForSenderBalance);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.EqualTo("err: insufficient MaxFeePerGas for sender balance (supplied gas 0)"));
}

[Test]
public void Call_tx_returns_noError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();

_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.Ok);

CallOutput callOutput = _blockchainBridge.Call(header, tx);

Assert.That(callOutput.Error, Is.Null);
}

[Test]
public void EstimateGas_tx_returns_noError()
{
BlockHeader header = Build.A.BlockHeader
.TestObject;
Transaction tx = new();

_transactionProcessor.CallAndRestore(Arg.Any<Transaction>(), Arg.Any<BlockExecutionContext>(), Arg.Any<ITxTracer>())
.Returns(TransactionResult.Ok);

CallOutput callOutput = _blockchainBridge.EstimateGas(header, tx, 1);

Assert.That(callOutput.Error, Is.Null);
}
}
12 changes: 9 additions & 3 deletions src/Nethermind/Nethermind.Facade/BlockchainBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public CallOutput Call(BlockHeader header, Transaction tx, Dictionary<Address, A

return new CallOutput
{
Error = tryCallResult.Success ? callOutputTracer.Error : tryCallResult.Error,
Error = ConstructError(tryCallResult, callOutputTracer.Error, tx.GasLimit),
GasSpent = callOutputTracer.GasSpent,
OutputData = callOutputTracer.ReturnValue,
InputError = !tryCallResult.Success
Expand Down Expand Up @@ -204,7 +204,7 @@ public CallOutput EstimateGas(BlockHeader header, Transaction tx, int errorMargi

return new CallOutput
{
Error = tryCallResult.Success ? estimateGasTracer.Error : tryCallResult.Error,
Error = ConstructError(tryCallResult, estimateGasTracer.Error, tx.GasLimit),
GasSpent = estimate,
InputError = !tryCallResult.Success
};
Expand All @@ -223,7 +223,7 @@ public CallOutput CreateAccessList(BlockHeader header, Transaction tx, Cancellat

return new CallOutput
{
Error = tryCallResult.Success ? callOutputTracer.Error : tryCallResult.Error,
Error = ConstructError(tryCallResult, callOutputTracer.Error, tx.GasLimit),
GasSpent = accessTxTracer.GasSpent,
OperationGas = callOutputTracer.OperationGas,
OutputData = callOutputTracer.ReturnValue,
Expand Down Expand Up @@ -432,5 +432,11 @@ public IEnumerable<FilterLog> FindLogs(LogFilter filter, CancellationToken cance
{
return _logFinder.FindLogs(filter, cancellationToken);
}

private string? ConstructError(TransactionResult txResult, string? tracerError, long gasLimit)
{
if (txResult.Success) return tracerError;
return txResult.Error is not null ? $"err: {txResult.Error} (supplied gas {gasLimit})" : null;
}
}
}
Loading