mirror of https://github.com/hyperledger/besu
Split Transaction Gas Calculation from EVM Calculation (#2659)
In preparation for the EVM library pull out the transaction related gas calculations and move them into their own `TransactionGasCalculator.` This has 4 calls right now, none of which occur inside the EVM: * Intrinsic gas cost * Code Deposit gas cost * Max refund quotient * Max Privacy Marker Transaction intrinsic gas cost. Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>pull/2661/head
parent
650b5a01b1
commit
f9b17cf92b
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* 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.ethereum.mainnet; |
||||||
|
|
||||||
|
import static java.util.Collections.emptyList; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.core.AccessListEntry; |
||||||
|
import org.hyperledger.besu.ethereum.core.Address; |
||||||
|
import org.hyperledger.besu.ethereum.core.Gas; |
||||||
|
import org.hyperledger.besu.ethereum.core.GasAndAccessedState; |
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction; |
||||||
|
|
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import com.google.common.collect.HashMultimap; |
||||||
|
import com.google.common.collect.Multimap; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
|
||||||
|
public class BerlinTransactionGasCalculator extends IstanbulTransactionGasCalculator { |
||||||
|
|
||||||
|
// new constants for EIP-2929
|
||||||
|
private static final Gas ACCESS_LIST_ADDRESS_COST = Gas.of(2400); |
||||||
|
protected static final Gas ACCESS_LIST_STORAGE_COST = Gas.of(1900); |
||||||
|
|
||||||
|
@Override |
||||||
|
public GasAndAccessedState transactionIntrinsicGasCostAndAccessedState( |
||||||
|
final Transaction transaction) { |
||||||
|
// As per https://eips.ethereum.org/EIPS/eip-2930
|
||||||
|
final List<AccessListEntry> accessList = transaction.getAccessList().orElse(emptyList()); |
||||||
|
|
||||||
|
long accessedStorageCount = 0; |
||||||
|
final Set<Address> accessedAddresses = new HashSet<>(); |
||||||
|
final Multimap<Address, Bytes32> accessedStorage = HashMultimap.create(); |
||||||
|
|
||||||
|
for (final AccessListEntry accessListEntry : accessList) { |
||||||
|
final Address address = accessListEntry.getAddress(); |
||||||
|
|
||||||
|
accessedAddresses.add(address); |
||||||
|
for (final Bytes32 storageKeyBytes : accessListEntry.getStorageKeys()) { |
||||||
|
accessedStorage.put(address, storageKeyBytes); |
||||||
|
++accessedStorageCount; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return new GasAndAccessedState( |
||||||
|
super.transactionIntrinsicGasCostAndAccessedState(transaction) |
||||||
|
.getGas() |
||||||
|
.plus(ACCESS_LIST_ADDRESS_COST.times(accessList.size())) |
||||||
|
.plus(ACCESS_LIST_STORAGE_COST.times(accessedStorageCount)), |
||||||
|
accessedAddresses, |
||||||
|
accessedStorage); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
/* |
||||||
|
* 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.ethereum.mainnet; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.core.Gas; |
||||||
|
import org.hyperledger.besu.ethereum.core.GasAndAccessedState; |
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
|
||||||
|
public class FrontierTransactionGasCalculator implements TransactionGasCalculator { |
||||||
|
|
||||||
|
private static final Gas TX_DATA_ZERO_COST = Gas.of(4L); |
||||||
|
|
||||||
|
private static final Gas TX_DATA_NON_ZERO_COST = Gas.of(68L); |
||||||
|
|
||||||
|
private static final Gas TX_BASE_COST = Gas.of(21_000L); |
||||||
|
|
||||||
|
private static final Gas TX_CREATE_EXTRA_COST = Gas.of(0L); |
||||||
|
|
||||||
|
private static final Gas CODE_DEPOSIT_BYTE_COST = Gas.of(200L); |
||||||
|
|
||||||
|
@Override |
||||||
|
public GasAndAccessedState transactionIntrinsicGasCostAndAccessedState( |
||||||
|
final Transaction transaction) { |
||||||
|
final Bytes payload = transaction.getPayload(); |
||||||
|
int zeros = 0; |
||||||
|
for (int i = 0; i < payload.size(); i++) { |
||||||
|
if (payload.get(i) == 0) { |
||||||
|
++zeros; |
||||||
|
} |
||||||
|
} |
||||||
|
final int nonZeros = payload.size() - zeros; |
||||||
|
|
||||||
|
Gas cost = |
||||||
|
TX_BASE_COST |
||||||
|
.plus(TX_DATA_ZERO_COST.times(zeros)) |
||||||
|
.plus(TX_DATA_NON_ZERO_COST.times(nonZeros)); |
||||||
|
|
||||||
|
if (transaction.isContractCreation()) { |
||||||
|
cost = cost.plus(txCreateExtraGasCost()); |
||||||
|
} |
||||||
|
|
||||||
|
return new GasAndAccessedState(cost); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the additional gas cost for contract creation transactions |
||||||
|
* |
||||||
|
* @return the additional gas cost for contract creation transactions |
||||||
|
*/ |
||||||
|
protected Gas txCreateExtraGasCost() { |
||||||
|
return TX_CREATE_EXTRA_COST; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Gas codeDepositGasCost(final int codeSize) { |
||||||
|
return CODE_DEPOSIT_BYTE_COST.times(codeSize); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Gas getMaximumPmtCost() { |
||||||
|
// what would be the gas for PMT with hash of all non-zeros
|
||||||
|
int nonZeros = 64; |
||||||
|
return TX_BASE_COST.plus(TX_DATA_NON_ZERO_COST.times(nonZeros)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
/* |
||||||
|
* 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.ethereum.mainnet; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.core.Gas; |
||||||
|
import org.hyperledger.besu.ethereum.core.GasAndAccessedState; |
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
|
||||||
|
public class IstanbulTransactionGasCalculator extends HomesteadTransactionGasCalculator { |
||||||
|
|
||||||
|
private static final Gas TX_DATA_ZERO_COST = Gas.of(4L); |
||||||
|
private static final Gas ISTANBUL_TX_DATA_NON_ZERO_COST = Gas.of(16L); |
||||||
|
private static final Gas TX_BASE_COST = Gas.of(21_000L); |
||||||
|
|
||||||
|
@Override |
||||||
|
public GasAndAccessedState transactionIntrinsicGasCostAndAccessedState( |
||||||
|
final Transaction transaction) { |
||||||
|
final Bytes payload = transaction.getPayload(); |
||||||
|
int zeros = 0; |
||||||
|
for (int i = 0; i < payload.size(); i++) { |
||||||
|
if (payload.get(i) == 0) { |
||||||
|
++zeros; |
||||||
|
} |
||||||
|
} |
||||||
|
final int nonZeros = payload.size() - zeros; |
||||||
|
|
||||||
|
Gas cost = |
||||||
|
TX_BASE_COST |
||||||
|
.plus(TX_DATA_ZERO_COST.times(zeros)) |
||||||
|
.plus(ISTANBUL_TX_DATA_NON_ZERO_COST.times(nonZeros)); |
||||||
|
|
||||||
|
if (transaction.isContractCreation()) { |
||||||
|
cost = cost.plus(txCreateExtraGasCost()); |
||||||
|
} |
||||||
|
|
||||||
|
return new GasAndAccessedState(cost); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Gas getMaximumPmtCost() { |
||||||
|
int nonZeros = 64; |
||||||
|
return TX_BASE_COST.plus(ISTANBUL_TX_DATA_NON_ZERO_COST.times(nonZeros)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* 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.ethereum.mainnet; |
||||||
|
|
||||||
|
public class LondonTransactionGasCalculator extends BerlinTransactionGasCalculator { |
||||||
|
|
||||||
|
// redefinitions for EIP-3529
|
||||||
|
private static final int NEW_MAX_REFUND_QUOTIENT = 5; |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaxRefundQuotient() { |
||||||
|
return NEW_MAX_REFUND_QUOTIENT; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* 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.ethereum.mainnet; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.core.Gas; |
||||||
|
import org.hyperledger.besu.ethereum.core.GasAndAccessedState; |
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction; |
||||||
|
|
||||||
|
/** |
||||||
|
* Provides various gas cost lookups and calculations used during transaction processing outside the |
||||||
|
* EVM. |
||||||
|
* |
||||||
|
* <p>The {@code TransactionGasCalculator} is meant to encapsulate all {@link Gas}-related |
||||||
|
* calculations not needed during EVM execution or caused by EVM execution. EVM Relevant or caused |
||||||
|
* gas calculations live in the {@link org.hyperledger.besu.ethereum.vm.GasCalculator}. Current |
||||||
|
* calculations revolve around block encoding of transactions, account creation, how much refund to |
||||||
|
* apply, and private transaction gas reservations. |
||||||
|
*/ |
||||||
|
public interface TransactionGasCalculator { |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a {@link Transaction}s intrinsic gas cost, i.e. the cost deriving from its encoded |
||||||
|
* binary representation when stored on-chain. |
||||||
|
* |
||||||
|
* @param transaction The transaction |
||||||
|
* @return the transaction's intrinsic gas cost |
||||||
|
*/ |
||||||
|
GasAndAccessedState transactionIntrinsicGasCostAndAccessedState(Transaction transaction); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the cost for a {@link AbstractMessageProcessor} to deposit the code in storage |
||||||
|
* |
||||||
|
* @param codeSize The size of the code in bytes |
||||||
|
* @return the code deposit cost |
||||||
|
*/ |
||||||
|
Gas codeDepositGasCost(int codeSize); |
||||||
|
|
||||||
|
/** |
||||||
|
* A measure of the maximum amount of refunded gas a transaction will be credited with. |
||||||
|
* |
||||||
|
* @return the quotient of the equation `txGasCost / refundQuotient`. |
||||||
|
*/ |
||||||
|
default long getMaxRefundQuotient() { |
||||||
|
return 2; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Maximum Cost of a Privacy Marker Transaction (PMT). See {@link |
||||||
|
* org.hyperledger.besu.plugin.services.privacy.PrivateMarkerTransactionFactory} |
||||||
|
* |
||||||
|
* @return the maximum gas cost |
||||||
|
*/ |
||||||
|
// what would be the gas for a PMT with hash of all non-zeros
|
||||||
|
Gas getMaximumPmtCost(); |
||||||
|
} |
Loading…
Reference in new issue