mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-09 23:38:08 -05:00
Move gas refund calculation from MainnetTransactionProcessor to GasCalculator (#8106)
* move gas refund calculation from MainnetTransactionProcessor to RefundCalculator Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net> * fix MainnetTransactionProcessorTest Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net> * add test for FrontierRefundCalculator Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net> * add test for FrontierRefundCalculator Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net> * add PragueRefundCalculator dummy Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net> * move refund logic to gas calculator, delete RefundCalculator Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net> --------- Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>
This commit is contained in:
@@ -500,11 +500,8 @@ public class MainnetTransactionProcessor {
|
||||
|
||||
// Refund the sender by what we should and pay the miner fee (note that we're doing them one
|
||||
// after the other so that if it is the same account somehow, we end up with the right result)
|
||||
final long selfDestructRefund =
|
||||
gasCalculator.getSelfDestructRefundAmount() * initialFrame.getSelfDestructs().size();
|
||||
final long baseRefundGas =
|
||||
initialFrame.getGasRefund() + selfDestructRefund + codeDelegationRefund;
|
||||
final long refundedGas = refunded(transaction, initialFrame.getRemainingGas(), baseRefundGas);
|
||||
final long refundedGas =
|
||||
gasCalculator.calculateGasRefund(transaction, initialFrame, codeDelegationRefund);
|
||||
final Wei refundedWei = transactionGasPrice.multiply(refundedGas);
|
||||
final Wei balancePriorToRefund = sender.getBalance();
|
||||
sender.incrementBalance(refundedWei);
|
||||
@@ -635,15 +632,6 @@ public class MainnetTransactionProcessor {
|
||||
};
|
||||
}
|
||||
|
||||
protected long refunded(
|
||||
final Transaction transaction, final long gasRemaining, final long gasRefund) {
|
||||
// Integer truncation takes care of the floor calculation needed after the divide.
|
||||
final long maxRefundAllowance =
|
||||
(transaction.getGasLimit() - gasRemaining) / gasCalculator.getMaxRefundQuotient();
|
||||
final long refundAllowance = Math.min(maxRefundAllowance, gasRefund);
|
||||
return gasRemaining + refundAllowance;
|
||||
}
|
||||
|
||||
private String printableStackTraceFromThrowable(final RuntimeException re) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
|
||||
import static org.hyperledger.besu.evm.internal.Words.numWords;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
import org.hyperledger.besu.datatypes.Transaction;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.evm.account.Account;
|
||||
import org.hyperledger.besu.evm.frame.MessageFrame;
|
||||
@@ -566,4 +567,25 @@ public class FrontierGasCalculator implements GasCalculator {
|
||||
public long getMinimumTransactionCost() {
|
||||
return TX_BASE_COST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long calculateGasRefund(
|
||||
final Transaction transaction,
|
||||
final MessageFrame initialFrame,
|
||||
final long codeDelegationRefund) {
|
||||
final long selfDestructRefund =
|
||||
getSelfDestructRefundAmount() * initialFrame.getSelfDestructs().size();
|
||||
final long baseRefundGas =
|
||||
initialFrame.getGasRefund() + selfDestructRefund + codeDelegationRefund;
|
||||
return refunded(transaction, initialFrame.getRemainingGas(), baseRefundGas);
|
||||
}
|
||||
|
||||
private long refunded(
|
||||
final Transaction transaction, final long gasRemaining, final long gasRefund) {
|
||||
// Integer truncation takes care of the floor calculation needed after the divide.
|
||||
final long maxRefundAllowance =
|
||||
(transaction.getGasLimit() - gasRemaining) / getMaxRefundQuotient();
|
||||
final long refundAllowance = Math.min(maxRefundAllowance, gasRefund);
|
||||
return gasRemaining + refundAllowance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package org.hyperledger.besu.evm.gascalculator;
|
||||
|
||||
import org.hyperledger.besu.datatypes.AccessListEntry;
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
import org.hyperledger.besu.datatypes.Transaction;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.evm.account.Account;
|
||||
import org.hyperledger.besu.evm.frame.MessageFrame;
|
||||
@@ -664,4 +665,15 @@ public interface GasCalculator {
|
||||
default long calculateDelegateCodeGasRefund(final long alreadyExistingAccountSize) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the gas refund for a transaction.
|
||||
*
|
||||
* @param transaction the transaction
|
||||
* @param initialFrame the initial frame
|
||||
* @param codeDelegationRefund the code delegation refund
|
||||
* @return the gas refund
|
||||
*/
|
||||
long calculateGasRefund(
|
||||
Transaction transaction, MessageFrame initialFrame, long codeDelegationRefund);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright contributors to Hyperledger Besu.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.evm.gascalculator;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
import org.hyperledger.besu.datatypes.Transaction;
|
||||
import org.hyperledger.besu.evm.frame.MessageFrame;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class FrontierGasCalculatorTest {
|
||||
private final GasCalculator gasCalculator = new FrontierGasCalculator();
|
||||
|
||||
@Mock private Transaction transaction;
|
||||
@Mock private MessageFrame messageFrame;
|
||||
|
||||
@Test
|
||||
void shouldCalculateRefundWithNoSelfDestructs() {
|
||||
// Arrange
|
||||
when(messageFrame.getSelfDestructs()).thenReturn(Collections.emptySet());
|
||||
when(messageFrame.getGasRefund()).thenReturn(1000L);
|
||||
when(messageFrame.getRemainingGas()).thenReturn(5000L);
|
||||
when(transaction.getGasLimit()).thenReturn(100000L);
|
||||
|
||||
// Act
|
||||
long refund = gasCalculator.calculateGasRefund(transaction, messageFrame, 500L);
|
||||
|
||||
// Assert
|
||||
assertThat(refund)
|
||||
.isEqualTo(6500L); // 5000 (remaining) + min(1500 (total refund), 19000 (max allowance))
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCalculateRefundWithMultipleSelfDestructs() {
|
||||
// Arrange
|
||||
Set<Address> selfDestructs = new HashSet<>();
|
||||
selfDestructs.add(Address.wrap(Bytes.random(20)));
|
||||
selfDestructs.add(Address.wrap(Bytes.random(20)));
|
||||
|
||||
when(messageFrame.getSelfDestructs()).thenReturn(selfDestructs);
|
||||
when(messageFrame.getGasRefund()).thenReturn(1000L);
|
||||
when(messageFrame.getRemainingGas()).thenReturn(5000L);
|
||||
when(transaction.getGasLimit()).thenReturn(100000L);
|
||||
|
||||
// Act
|
||||
long refund = gasCalculator.calculateGasRefund(transaction, messageFrame, 500L);
|
||||
|
||||
// Assert
|
||||
assertThat(refund)
|
||||
.isEqualTo(52500L); // 5000 (remaining) + min(47500 (total refund), 49500 (max allowance))
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRespectMaxRefundAllowance() {
|
||||
// Arrange
|
||||
when(messageFrame.getSelfDestructs()).thenReturn(Collections.emptySet());
|
||||
when(messageFrame.getGasRefund()).thenReturn(100000L);
|
||||
when(messageFrame.getRemainingGas()).thenReturn(20000L);
|
||||
when(transaction.getGasLimit()).thenReturn(100000L);
|
||||
|
||||
// Act
|
||||
long refund = gasCalculator.calculateGasRefund(transaction, messageFrame, 1000L);
|
||||
|
||||
// Assert
|
||||
assertThat(refund)
|
||||
.isEqualTo(60000L); // 20000 (remaining) + min(101000 (total refund), 40000 (max allowance))
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleZeroValuesCorrectly() {
|
||||
// Arrange
|
||||
when(messageFrame.getSelfDestructs()).thenReturn(Collections.emptySet());
|
||||
when(messageFrame.getGasRefund()).thenReturn(0L);
|
||||
when(messageFrame.getRemainingGas()).thenReturn(0L);
|
||||
when(transaction.getGasLimit()).thenReturn(100000L);
|
||||
|
||||
// Act
|
||||
long refund = gasCalculator.calculateGasRefund(transaction, messageFrame, 0L);
|
||||
|
||||
// Assert
|
||||
assertThat(refund).isEqualTo(0L);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user