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