Skip to content

Commit 7ec43c8

Browse files
daniellehrnersiladu
authored andcommitted
adding tests and javadoc comments
Signed-off-by: Daniel Lehrner <[email protected]>
1 parent 3735091 commit 7ec43c8

File tree

3 files changed

+81
-8
lines changed

3 files changed

+81
-8
lines changed

ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@
1616

1717
import static org.assertj.core.api.Assertions.assertThat;
1818

19+
import org.hyperledger.besu.datatypes.AccessListEntry;
1920
import org.hyperledger.besu.ethereum.core.Transaction;
21+
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
2022
import org.hyperledger.besu.ethereum.rlp.RLP;
2123
import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator;
2224
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
2325
import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator;
26+
import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator;
27+
import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator;
2428

29+
import java.util.List;
2530
import java.util.stream.Stream;
2631

2732
import org.apache.tuweni.bytes.Bytes;
33+
import org.apache.tuweni.bytes.Bytes32;
2834
import org.assertj.core.api.Assertions;
2935
import org.junit.jupiter.api.Test;
3036
import org.junit.jupiter.params.ParameterizedTest;
@@ -36,6 +42,8 @@ public class IntrinsicGasTest {
3642
public static Stream<Arguments> data() {
3743
final GasCalculator frontier = new FrontierGasCalculator();
3844
final GasCalculator istanbul = new IstanbulGasCalculator();
45+
final GasCalculator shanghai = new ShanghaiGasCalculator();
46+
final GasCalculator prague = new PragueGasCalculator();
3947
return Stream.of(
4048
// EnoughGAS
4149
Arguments.of(
@@ -81,16 +89,36 @@ public static Stream<Arguments> data() {
8189
Arguments.of(
8290
istanbul,
8391
21116L,
84-
"0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"));
92+
"0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"),
93+
// CallData Gas Increase
94+
Arguments.of(
95+
prague,
96+
21290L,
97+
"0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"),
98+
// AccessList
99+
Arguments.of(
100+
shanghai,
101+
25300L,
102+
"0x01f89a018001826a4094095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f794a95e7baea6a6c7c4c2dfeb977efac326af552d87e1a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80a05cbd172231fc0735e0fb994dd5b1a4939170a260b36f0427a8a80866b063b948a07c230f7f578dd61785c93361b9871c0706ebfa6d06e3f4491dc9558c5202ed36"));
85103
}
86104

87105
@ParameterizedTest
88106
@MethodSource("data")
89107
public void validateGasCost(
90108
final GasCalculator gasCalculator, final long expectedGas, final String txRlp) {
91-
Transaction t = Transaction.readFrom(RLP.input(Bytes.fromHexString(txRlp)));
109+
Bytes rlp = Bytes.fromHexString(txRlp);
110+
111+
// non-frontier transactions need to be opaque for parsing to work
112+
if (rlp.get(0) > 0) {
113+
final BytesValueRLPOutput output = new BytesValueRLPOutput();
114+
output.writeBytes(rlp);
115+
rlp = output.encoded();
116+
}
117+
118+
Transaction t = Transaction.readFrom(RLP.input(rlp));
92119
Assertions.assertThat(
93-
gasCalculator.transactionIntrinsicGasCost(t.getPayload(), t.isContractCreation()))
120+
gasCalculator.transactionIntrinsicGasCost(
121+
t.getPayload(), t.isContractCreation(), evmGasUsed(gasCalculator, t)))
94122
.isEqualTo(expectedGas);
95123
}
96124

@@ -100,4 +128,21 @@ void dryRunDetector() {
100128
.withFailMessage("This test is here so gradle --dry-run executes this class")
101129
.isTrue();
102130
}
131+
132+
long evmGasUsed(final GasCalculator gasCalculator, final Transaction transaction) {
133+
final List<AccessListEntry> accessListEntries = transaction.getAccessList().orElse(List.of());
134+
135+
int accessListStorageCount = 0;
136+
for (final var entry : accessListEntries) {
137+
final List<Bytes32> storageKeys = entry.storageKeys();
138+
accessListStorageCount += storageKeys.size();
139+
}
140+
final long accessListGas =
141+
gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount);
142+
143+
final long codeDelegationGas =
144+
gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize());
145+
146+
return accessListGas + codeDelegationGas;
147+
}
103148
}

ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() {
128128
.gasLimit(10)
129129
.chainId(Optional.empty())
130130
.createTransaction(senderKeys);
131-
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(50L);
131+
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean(), anyLong())).thenReturn(50L);
132132

133133
assertThat(
134134
validator.validate(
@@ -398,7 +398,7 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() {
398398
transaction, Optional.empty(), Optional.empty(), transactionValidationParams))
399399
.isEqualTo(ValidationResult.invalid(INVALID_TRANSACTION_FORMAT));
400400

401-
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(0L);
401+
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean(), anyLong())).thenReturn(0L);
402402

403403
assertThat(
404404
eip1559Validator.validate(
@@ -475,7 +475,7 @@ public void shouldAcceptValidEIP1559() {
475475
.chainId(Optional.of(BigInteger.ONE))
476476
.createTransaction(senderKeys);
477477
final Optional<Wei> basefee = Optional.of(Wei.of(150000L));
478-
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(50L);
478+
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean(), anyLong())).thenReturn(50L);
479479

480480
assertThat(
481481
validator.validate(transaction, basefee, Optional.empty(), transactionValidationParams))
@@ -500,7 +500,7 @@ public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransaction
500500
.type(TransactionType.EIP1559)
501501
.chainId(Optional.of(BigInteger.ONE))
502502
.createTransaction(senderKeys);
503-
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(50L);
503+
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean(), anyLong())).thenReturn(50L);
504504

505505
assertThat(
506506
validator.validate(

evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class FrontierGasCalculator implements GasCalculator {
3838

3939
private static final long TX_DATA_NON_ZERO_COST = 68L;
4040

41+
/** Minimum base cost that every transaction needs to pay */
4142
protected static final long TX_BASE_COST = 21_000L;
4243

4344
private static final long TX_CREATE_EXTRA_COST = 0L;
@@ -139,6 +140,14 @@ public long transactionIntrinsicGasCost(
139140
return clampedAdd(TX_BASE_COST, dynamicIntrinsicGasCost);
140141
}
141142

143+
/**
144+
* Calculates the dynamic part of the intrinsic gas cost
145+
*
146+
* @param payload the call data payload
147+
* @param isContractCreation whether the transaction is a contract creation
148+
* @param evmGasUsed how much gas is used by access lists and code delegations
149+
* @return the dynamic part of the intrinsic gas cost
150+
*/
142151
protected long dynamicIntrinsicGasCost(
143152
final Bytes payload, final boolean isContractCreation, final long evmGasUsed) {
144153
final int payloadSize = payload.size();
@@ -160,21 +169,40 @@ protected long dynamicIntrinsicGasCost(
160169
return cost;
161170
}
162171

172+
/**
173+
* Calculates the cost of the call data
174+
*
175+
* @param payloadSize the total size of the payload
176+
* @param zeroBytes the number of zero bytes in the payload
177+
* @return the cost of the call data
178+
*/
163179
protected long callDataCost(final long payloadSize, final long zeroBytes) {
164180
return clampedAdd(
165181
TX_DATA_NON_ZERO_COST * (payloadSize - zeroBytes), TX_DATA_ZERO_COST * zeroBytes);
166182
}
167183

184+
/**
185+
* Counts the zero bytes in the payload
186+
*
187+
* @param payload the payload
188+
* @return the number of zero bytes in the payload
189+
*/
168190
protected static long zeroBytes(final Bytes payload) {
169191
int zeros = 0;
170192
for (int i = 0; i < payload.size(); i++) {
171193
if (payload.get(i) == 0) {
172-
++zeros;
194+
zeros += 1;
173195
}
174196
}
175197
return zeros;
176198
}
177199

200+
/**
201+
* Returns the gas cost for contract creation transactions
202+
*
203+
* @param ignored the size of the contract creation code (ignored in Frontier)
204+
* @return the gas cost for contract creation transactions
205+
*/
178206
protected long contractCreationCost(final int ignored) {
179207
return txCreateExtraGasCost();
180208
}

0 commit comments

Comments
 (0)