[PAN-2989] EIP-1884 - Repricing for trie-size-dependent opcodes (#1795)

* [PAN-2989] EIP-1884 - Repricing for trie-size-dependent opcodes

Add the new gas costs and new operation to the EVM.
Add contract balance to message frame

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Danno Ferrin 5 years ago committed by GitHub
parent 59bf464c99
commit c4e7dcbe80
  1. 1
      ethereum/core/src/jmh/java/tech/pegasys/pantheon/ethereum/vm/operations/OperationBenchmarkHelper.java
  2. 21
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/IstanbulGasCalculator.java
  3. 5
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetEvmRegistries.java
  4. 2
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionProcessor.java
  5. 2
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionProcessor.java
  6. 1
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/AbstractCallOperation.java
  7. 20
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/MessageFrame.java
  8. 1
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/operations/AbstractCreateOperation.java
  9. 35
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/operations/SelfBalanceOperation.java
  10. 7
      ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/MessageFrameTestFixture.java
  11. 11
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/EnvironmentInformation.java
  12. 1
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java
  13. 9
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/operations/ExtCodeHashOperationTest.java

@ -98,6 +98,7 @@ public class OperationBenchmarkHelper {
.address(messageFrame.getContractAddress()) .address(messageFrame.getContractAddress())
.originator(messageFrame.getOriginatorAddress()) .originator(messageFrame.getOriginatorAddress())
.contract(messageFrame.getRecipientAddress()) .contract(messageFrame.getRecipientAddress())
.contractBalance(messageFrame.getContractBalance())
.gasPrice(messageFrame.getGasPrice()) .gasPrice(messageFrame.getGasPrice())
.inputData(messageFrame.getInputData()) .inputData(messageFrame.getInputData())
.sender(messageFrame.getSenderAddress()) .sender(messageFrame.getSenderAddress())

@ -25,6 +25,9 @@ public class IstanbulGasCalculator extends ConstantinopleFixGasCalculator {
private static final Gas TX_BASE_COST = Gas.of(21_000L); private static final Gas TX_BASE_COST = Gas.of(21_000L);
private static final Gas SLOAD_GAS = Gas.of(800); private static final Gas SLOAD_GAS = Gas.of(800);
private static final Gas BALANCE_OPERATION_GAS_COST = Gas.of(700);
private static final Gas EXTCODE_HASH_COST = Gas.of(700);
private static final Gas SSTORE_SET_GAS = Gas.of(20_000); private static final Gas SSTORE_SET_GAS = Gas.of(20_000);
private static final Gas SSTORE_RESET_GAS = Gas.of(5_000); private static final Gas SSTORE_RESET_GAS = Gas.of(5_000);
private static final Gas SSTORE_CLEARS_SCHEDULE = Gas.of(15_000); private static final Gas SSTORE_CLEARS_SCHEDULE = Gas.of(15_000);
@ -114,4 +117,22 @@ public class IstanbulGasCalculator extends ConstantinopleFixGasCalculator {
} }
} }
} }
@Override
// As per https://eips.ethereum.org/EIPS/eip-1884
public Gas getSloadOperationGasCost() {
return SLOAD_GAS;
}
@Override
// As per https://eips.ethereum.org/EIPS/eip-1884
public Gas getBalanceOperationGasCost() {
return BALANCE_OPERATION_GAS_COST;
}
@Override
// As per https://eips.ethereum.org/EIPS/eip-1884
public Gas extCodeHashOperationGasCost() {
return EXTCODE_HASH_COST;
}
} }

@ -81,6 +81,7 @@ import tech.pegasys.pantheon.ethereum.vm.operations.SLtOperation;
import tech.pegasys.pantheon.ethereum.vm.operations.SModOperation; import tech.pegasys.pantheon.ethereum.vm.operations.SModOperation;
import tech.pegasys.pantheon.ethereum.vm.operations.SStoreOperation; import tech.pegasys.pantheon.ethereum.vm.operations.SStoreOperation;
import tech.pegasys.pantheon.ethereum.vm.operations.SarOperation; import tech.pegasys.pantheon.ethereum.vm.operations.SarOperation;
import tech.pegasys.pantheon.ethereum.vm.operations.SelfBalanceOperation;
import tech.pegasys.pantheon.ethereum.vm.operations.SelfDestructOperation; import tech.pegasys.pantheon.ethereum.vm.operations.SelfDestructOperation;
import tech.pegasys.pantheon.ethereum.vm.operations.Sha3Operation; import tech.pegasys.pantheon.ethereum.vm.operations.Sha3Operation;
import tech.pegasys.pantheon.ethereum.vm.operations.ShlOperation; import tech.pegasys.pantheon.ethereum.vm.operations.ShlOperation;
@ -266,12 +267,10 @@ abstract class MainnetEvmRegistries {
final int accountVersion, final int accountVersion,
final BigInteger chainId) { final BigInteger chainId) {
registerConstantinopleOpcodes(registry, gasCalculator, accountVersion); registerConstantinopleOpcodes(registry, gasCalculator, accountVersion);
registry.put(
new SStoreOperation(gasCalculator, SStoreOperation.EIP_1706_MINIMUM),
Account.DEFAULT_VERSION);
registry.put( registry.put(
new ChainIdOperation(gasCalculator, Bytes32.leftPad(BytesValue.of(chainId.toByteArray()))), new ChainIdOperation(gasCalculator, Bytes32.leftPad(BytesValue.of(chainId.toByteArray()))),
Account.DEFAULT_VERSION); Account.DEFAULT_VERSION);
registry.put(new SelfBalanceOperation(gasCalculator), Account.DEFAULT_VERSION);
registry.put( registry.put(
new SStoreOperation(gasCalculator, SStoreOperation.EIP_1706_MINIMUM), new SStoreOperation(gasCalculator, SStoreOperation.EIP_1706_MINIMUM),
Account.DEFAULT_VERSION); Account.DEFAULT_VERSION);

@ -234,6 +234,7 @@ public class MainnetTransactionProcessor implements TransactionProcessor {
.address(contractAddress) .address(contractAddress)
.originator(senderAddress) .originator(senderAddress)
.contract(contractAddress) .contract(contractAddress)
.contractBalance(sender.getBalance())
.contractAccountVersion(createContractAccountVersion) .contractAccountVersion(createContractAccountVersion)
.gasPrice(transaction.getGasPrice()) .gasPrice(transaction.getGasPrice())
.inputData(BytesValue.EMPTY) .inputData(BytesValue.EMPTY)
@ -264,6 +265,7 @@ public class MainnetTransactionProcessor implements TransactionProcessor {
.address(to) .address(to)
.originator(senderAddress) .originator(senderAddress)
.contract(to) .contract(to)
.contractBalance(contract != null ? contract.getBalance() : Wei.ZERO)
.contractAccountVersion( .contractAccountVersion(
contract != null ? contract.getVersion() : Account.DEFAULT_VERSION) contract != null ? contract.getVersion() : Account.DEFAULT_VERSION)
.gasPrice(transaction.getGasPrice()) .gasPrice(transaction.getGasPrice())

@ -230,6 +230,7 @@ public class PrivateTransactionProcessor {
.address(privateContractAddress) .address(privateContractAddress)
.originator(senderAddress) .originator(senderAddress)
.contract(privateContractAddress) .contract(privateContractAddress)
.contractBalance(Wei.ZERO)
.contractAccountVersion(createContractAccountVersion) .contractAccountVersion(createContractAccountVersion)
.initialGas(Gas.MAX_VALUE) .initialGas(Gas.MAX_VALUE)
.gasPrice(transaction.getGasPrice()) .gasPrice(transaction.getGasPrice())
@ -259,6 +260,7 @@ public class PrivateTransactionProcessor {
.address(to) .address(to)
.originator(senderAddress) .originator(senderAddress)
.contract(to) .contract(to)
.contractBalance(contract != null ? contract.getBalance() : Wei.ZERO)
.contractAccountVersion( .contractAccountVersion(
contract != null ? contract.getVersion() : Account.DEFAULT_VERSION) contract != null ? contract.getVersion() : Account.DEFAULT_VERSION)
.initialGas(Gas.MAX_VALUE) .initialGas(Gas.MAX_VALUE)

@ -172,6 +172,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
.address(address(frame)) .address(address(frame))
.originator(frame.getOriginatorAddress()) .originator(frame.getOriginatorAddress())
.contract(to) .contract(to)
.contractBalance(contract != null ? contract.getBalance() : Wei.ZERO)
.contractAccountVersion( .contractAccountVersion(
contract != null ? contract.getVersion() : Account.DEFAULT_VERSION) contract != null ? contract.getVersion() : Account.DEFAULT_VERSION)
.gasPrice(frame.getGasPrice()) .gasPrice(frame.getGasPrice())

@ -207,6 +207,7 @@ public class MessageFrame {
private final Address recipient; private final Address recipient;
private final Address originator; private final Address originator;
private final Address contract; private final Address contract;
private final Wei contractBalance;
private final int contractAccountVersion; private final int contractAccountVersion;
private final Wei gasPrice; private final Wei gasPrice;
private final BytesValue inputData; private final BytesValue inputData;
@ -240,6 +241,7 @@ public class MessageFrame {
final Address recipient, final Address recipient,
final Address originator, final Address originator,
final Address contract, final Address contract,
final Wei contractBalance,
final int contractAccountVersion, final int contractAccountVersion,
final Wei gasPrice, final Wei gasPrice,
final BytesValue inputData, final BytesValue inputData,
@ -274,6 +276,7 @@ public class MessageFrame {
this.recipient = recipient; this.recipient = recipient;
this.originator = originator; this.originator = originator;
this.contract = contract; this.contract = contract;
this.contractBalance = contractBalance;
this.contractAccountVersion = contractAccountVersion; this.contractAccountVersion = contractAccountVersion;
this.gasPrice = gasPrice; this.gasPrice = gasPrice;
this.inputData = inputData; this.inputData = inputData;
@ -753,6 +756,15 @@ public class MessageFrame {
return contract; return contract;
} }
/**
* Returns the balance of the contract currently executing.
*
* @return the balance of the contract currently executing
*/
public Wei getContractBalance() {
return contractBalance;
}
/** /**
* Returns the current gas price. * Returns the current gas price.
* *
@ -864,6 +876,7 @@ public class MessageFrame {
private Address address; private Address address;
private Address originator; private Address originator;
private Address contract; private Address contract;
private Wei contractBalance;
private int contractAccountVersion = -1; private int contractAccountVersion = -1;
private Wei gasPrice; private Wei gasPrice;
private BytesValue inputData; private BytesValue inputData;
@ -921,6 +934,11 @@ public class MessageFrame {
return this; return this;
} }
public Builder contractBalance(final Wei contractBalance) {
this.contractBalance = contractBalance;
return this;
}
public Builder contractAccountVersion(final int contractAccountVersion) { public Builder contractAccountVersion(final int contractAccountVersion) {
checkArgument(contractAccountVersion >= 0, "Contract account version cannot be negative"); checkArgument(contractAccountVersion >= 0, "Contract account version cannot be negative");
this.contractAccountVersion = contractAccountVersion; this.contractAccountVersion = contractAccountVersion;
@ -1011,6 +1029,7 @@ public class MessageFrame {
checkState(address != null, "Missing message frame recipient"); checkState(address != null, "Missing message frame recipient");
checkState(originator != null, "Missing message frame originator"); checkState(originator != null, "Missing message frame originator");
checkState(contract != null, "Missing message frame contract"); checkState(contract != null, "Missing message frame contract");
checkState(contractBalance != null, "Missing message frame contractBalance");
checkState(gasPrice != null, "Missing message frame getGasRemaining price"); checkState(gasPrice != null, "Missing message frame getGasRemaining price");
checkState(inputData != null, "Missing message frame input data"); checkState(inputData != null, "Missing message frame input data");
checkState(sender != null, "Missing message frame sender"); checkState(sender != null, "Missing message frame sender");
@ -1038,6 +1057,7 @@ public class MessageFrame {
address, address,
originator, originator,
contract, contract,
contractBalance,
contractAccountVersion, contractAccountVersion,
gasPrice, gasPrice,
inputData, inputData,

@ -111,6 +111,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
.address(contractAddress) .address(contractAddress)
.originator(frame.getOriginatorAddress()) .originator(frame.getOriginatorAddress())
.contract(contractAddress) .contract(contractAddress)
.contractBalance(account.getBalance())
.contractAccountVersion(frame.getContractAccountVersion()) .contractAccountVersion(frame.getContractAccountVersion())
.gasPrice(frame.getGasPrice()) .gasPrice(frame.getGasPrice())
.inputData(BytesValue.EMPTY) .inputData(BytesValue.EMPTY)

@ -0,0 +1,35 @@
/*
* Copyright 2018 ConsenSys AG.
*
* 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.
*/
package tech.pegasys.pantheon.ethereum.vm.operations;
import tech.pegasys.pantheon.ethereum.core.Gas;
import tech.pegasys.pantheon.ethereum.vm.AbstractOperation;
import tech.pegasys.pantheon.ethereum.vm.GasCalculator;
import tech.pegasys.pantheon.ethereum.vm.MessageFrame;
public class SelfBalanceOperation extends AbstractOperation {
public SelfBalanceOperation(final GasCalculator gasCalculator) {
super(0x47, "SELFBALANCE", 0, 1, false, 1, gasCalculator);
}
@Override
public Gas cost(final MessageFrame frame) {
return gasCalculator().getLowTierGasCost();
}
@Override
public void execute(final MessageFrame frame) {
frame.pushStackItem(frame.getContractBalance().getBytes());
}
}

@ -42,6 +42,7 @@ public class MessageFrameTestFixture {
private Address sender = DEFAUT_ADDRESS; private Address sender = DEFAUT_ADDRESS;
private Address originator = DEFAUT_ADDRESS; private Address originator = DEFAUT_ADDRESS;
private Address contract = DEFAUT_ADDRESS; private Address contract = DEFAUT_ADDRESS;
private Wei contractBalance = Wei.of(1);
private int contractAccountVersion = Account.DEFAULT_VERSION; private int contractAccountVersion = Account.DEFAULT_VERSION;
private Wei gasPrice = Wei.ZERO; private Wei gasPrice = Wei.ZERO;
private Wei value = Wei.ZERO; private Wei value = Wei.ZERO;
@ -109,6 +110,11 @@ public class MessageFrameTestFixture {
return this; return this;
} }
public MessageFrameTestFixture contractBalance(final Wei contractBalance) {
this.contractBalance = contractBalance;
return this;
}
public MessageFrameTestFixture contractAccountVersion(final int contractAccountVersion) { public MessageFrameTestFixture contractAccountVersion(final int contractAccountVersion) {
this.contractAccountVersion = contractAccountVersion; this.contractAccountVersion = contractAccountVersion;
return this; return this;
@ -173,6 +179,7 @@ public class MessageFrameTestFixture {
.value(value) .value(value)
.apparentValue(value) .apparentValue(value)
.contract(contract) .contract(contract)
.contractBalance(contractBalance)
.contractAccountVersion(contractAccountVersion) .contractAccountVersion(contractAccountVersion)
.code(code) .code(code)
.blockHeader(blockHeader) .blockHeader(blockHeader)

@ -34,6 +34,8 @@ public class EnvironmentInformation {
private final Address accountAddress; private final Address accountAddress;
private final Wei accountBalance;
private BlockHeader blockHeader; private BlockHeader blockHeader;
private final Address callerAddress; private final Address callerAddress;
@ -69,6 +71,7 @@ public class EnvironmentInformation {
@JsonCreator @JsonCreator
public EnvironmentInformation( public EnvironmentInformation(
@JsonProperty("address") final String account, @JsonProperty("address") final String account,
@JsonProperty("balance") final String balance,
@JsonProperty("caller") final String caller, @JsonProperty("caller") final String caller,
@JsonProperty("code") final CodeMock code, @JsonProperty("code") final CodeMock code,
@JsonProperty("data") final String data, @JsonProperty("data") final String data,
@ -81,6 +84,7 @@ public class EnvironmentInformation {
code, code,
0, 0,
account == null ? null : Address.fromHexString(account), account == null ? null : Address.fromHexString(account),
balance == null ? Wei.ZERO : Wei.fromHexString(balance),
caller == null ? null : Address.fromHexString(caller), caller == null ? null : Address.fromHexString(caller),
origin == null ? null : Address.fromHexString(origin), origin == null ? null : Address.fromHexString(origin),
data == null ? null : BytesValue.fromHexString(data), data == null ? null : BytesValue.fromHexString(data),
@ -94,6 +98,7 @@ public class EnvironmentInformation {
final Code code, final Code code,
final int depth, final int depth,
final Address accountAddress, final Address accountAddress,
final Wei accountBalance,
final Address callerAddress, final Address callerAddress,
final Address originAddress, final Address originAddress,
final BytesValue data, final BytesValue data,
@ -104,6 +109,7 @@ public class EnvironmentInformation {
this.code = code; this.code = code;
this.depth = depth; this.depth = depth;
this.accountAddress = accountAddress; this.accountAddress = accountAddress;
this.accountBalance = accountBalance;
this.callerAddress = callerAddress; this.callerAddress = callerAddress;
this.originAddress = originAddress; this.originAddress = originAddress;
this.data = data; this.data = data;
@ -132,6 +138,11 @@ public class EnvironmentInformation {
return accountAddress; return accountAddress;
} }
/** @return The balance of the currently executing account */
public Wei getAccountBalance() {
return accountBalance;
}
/** @return Address of the caller. */ /** @return Address of the caller. */
public Address getCallerAddress() { public Address getCallerAddress() {
return callerAddress; return callerAddress;

@ -135,6 +135,7 @@ public class VMReferenceTest extends AbstractRetryingTest {
.worldState(worldState.updater()) .worldState(worldState.updater())
.initialGas(spec.getExec().getGas()) .initialGas(spec.getExec().getGas())
.contract(execEnv.getAccountAddress()) .contract(execEnv.getAccountAddress())
.contractBalance(execEnv.getAccountBalance())
.address(execEnv.getAccountAddress()) .address(execEnv.getAccountAddress())
.originator(execEnv.getOriginAddress()) .originator(execEnv.getOriginAddress())
.gasPrice(execEnv.getGasPrice()) .gasPrice(execEnv.getGasPrice())

@ -29,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.core.MutableAccount;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.core.WorldUpdater; import tech.pegasys.pantheon.ethereum.core.WorldUpdater;
import tech.pegasys.pantheon.ethereum.mainnet.ConstantinopleGasCalculator; import tech.pegasys.pantheon.ethereum.mainnet.ConstantinopleGasCalculator;
import tech.pegasys.pantheon.ethereum.mainnet.IstanbulGasCalculator;
import tech.pegasys.pantheon.ethereum.vm.MessageFrame; import tech.pegasys.pantheon.ethereum.vm.MessageFrame;
import tech.pegasys.pantheon.ethereum.vm.Words; import tech.pegasys.pantheon.ethereum.vm.Words;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
@ -49,12 +50,20 @@ public class ExtCodeHashOperationTest {
private final ExtCodeHashOperation operation = private final ExtCodeHashOperation operation =
new ExtCodeHashOperation(new ConstantinopleGasCalculator()); new ExtCodeHashOperation(new ConstantinopleGasCalculator());
private final ExtCodeHashOperation operationIstanbul =
new ExtCodeHashOperation(new IstanbulGasCalculator());
@Test @Test
public void shouldCharge400Gas() { public void shouldCharge400Gas() {
assertThat(operation.cost(createMessageFrame(REQUESTED_ADDRESS))).isEqualTo(Gas.of(400)); assertThat(operation.cost(createMessageFrame(REQUESTED_ADDRESS))).isEqualTo(Gas.of(400));
} }
@Test
public void istanbulShouldCharge700Gas() {
assertThat(operationIstanbul.cost(createMessageFrame(REQUESTED_ADDRESS)))
.isEqualTo(Gas.of(700));
}
@Test @Test
public void shouldReturnZeroWhenAccountDoesNotExist() { public void shouldReturnZeroWhenAccountDoesNotExist() {
final Bytes32 result = executeOperation(REQUESTED_ADDRESS); final Bytes32 result = executeOperation(REQUESTED_ADDRESS);

Loading…
Cancel
Save