[PAN-2829] Add opcode and precompiled support for versioning (#1683)

Different opcode sets and precompiled contract sets for different account versions

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Danno Ferrin 5 years ago committed by GitHub
parent bbbb5af404
commit 1a12fdbccf
  1. 1
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Account.java
  2. 266
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetEvmRegistries.java
  3. 3
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetMessageCallProcessor.java
  4. 58
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetPrecompiledContractRegistries.java
  5. 10
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java
  6. 19
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/PrecompileContractRegistry.java
  7. 8
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpecBuilder.java
  8. 5
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/Code.java
  9. 16
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/EVM.java
  10. 28
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/OperationRegistry.java
  11. 2
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/operations/JumpOperation.java
  12. 2
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/operations/JumpiOperation.java
  13. 3
      pantheon/src/test/java/tech/pegasys/pantheon/PrivacyTest.java

@ -39,7 +39,6 @@ public interface Account {
long DEFAULT_NONCE = 0L;
Wei DEFAULT_BALANCE = Wei.ZERO;
int DEFAULT_VERSION = 0;
int ISTANBUL_VERSION = 1;
/**
* The Keccak-256 hash of the account address.

@ -12,9 +12,9 @@
*/
package tech.pegasys.pantheon.ethereum.mainnet;
import tech.pegasys.pantheon.ethereum.core.Account;
import tech.pegasys.pantheon.ethereum.vm.EVM;
import tech.pegasys.pantheon.ethereum.vm.GasCalculator;
import tech.pegasys.pantheon.ethereum.vm.Operation;
import tech.pegasys.pantheon.ethereum.vm.OperationRegistry;
import tech.pegasys.pantheon.ethereum.vm.operations.AddModOperation;
import tech.pegasys.pantheon.ethereum.vm.operations.AddOperation;
@ -92,185 +92,173 @@ import tech.pegasys.pantheon.ethereum.vm.operations.SwapOperation;
import tech.pegasys.pantheon.ethereum.vm.operations.TimestampOperation;
import tech.pegasys.pantheon.ethereum.vm.operations.XorOperation;
import java.util.List;
import java.util.function.Function;
import com.google.common.collect.ImmutableList;
/** Provides EVMs supporting the appropriate operations for mainnet hard forks. */
public abstract class MainnetEvmRegistries {
abstract class MainnetEvmRegistries {
private interface OperationFactory extends Function<GasCalculator, Operation> {}
static EVM frontier(final GasCalculator gasCalculator) {
final OperationRegistry registry = new OperationRegistry();
private static final List<OperationFactory> FRONTIER_OPERATION_FACTORIES;
private static final List<OperationFactory> HOMESTEAD_OPERATION_FACTORIES;
private static final List<OperationFactory> BYZANTIUM_OPERATION_FACTORIES;
private static final List<OperationFactory> CONSTANTINOPLE_OPERATION_FACTORIES;
registerFrontierOpcodes(registry, gasCalculator, Account.DEFAULT_VERSION);
static {
FRONTIER_OPERATION_FACTORIES = buildFrontierFactories();
HOMESTEAD_OPERATION_FACTORIES = buildHomesteadFactories(FRONTIER_OPERATION_FACTORIES);
BYZANTIUM_OPERATION_FACTORIES = buildByzantiumFactories(HOMESTEAD_OPERATION_FACTORIES);
CONSTANTINOPLE_OPERATION_FACTORIES =
buildConstantinopleFactories(BYZANTIUM_OPERATION_FACTORIES);
return new EVM(registry, new InvalidOperation(gasCalculator));
}
private static EVM createAndPopulate(
final List<OperationFactory> factories, final GasCalculator gasCalculator) {
static EVM homestead(final GasCalculator gasCalculator) {
final OperationRegistry registry = new OperationRegistry();
for (final OperationFactory factory : factories) {
final Operation operation = factory.apply(gasCalculator);
registry.put(operation.getOpcode(), operation);
}
registerHomesteadOpcodes(registry, gasCalculator, Account.DEFAULT_VERSION);
return new EVM(registry, new InvalidOperation(gasCalculator));
}
public static EVM frontier(final GasCalculator gasCalculator) {
return createAndPopulate(FRONTIER_OPERATION_FACTORIES, gasCalculator);
}
static EVM byzantium(final GasCalculator gasCalculator) {
final OperationRegistry registry = new OperationRegistry();
public static EVM homestead(final GasCalculator gasCalculator) {
return createAndPopulate(HOMESTEAD_OPERATION_FACTORIES, gasCalculator);
}
registerByzantiumOpcodes(registry, gasCalculator, Account.DEFAULT_VERSION);
public static EVM byzantium(final GasCalculator gasCalculator) {
return createAndPopulate(BYZANTIUM_OPERATION_FACTORIES, gasCalculator);
return new EVM(registry, new InvalidOperation(gasCalculator));
}
public static EVM constantinople(final GasCalculator gasCalculator) {
return createAndPopulate(CONSTANTINOPLE_OPERATION_FACTORIES, gasCalculator);
static EVM constantinople(final GasCalculator gasCalculator) {
final OperationRegistry registry = new OperationRegistry();
registerConstantinopleOpcodes(registry, gasCalculator, Account.DEFAULT_VERSION);
return new EVM(registry, new InvalidOperation(gasCalculator));
}
private static List<OperationFactory> buildFrontierFactories() {
final ImmutableList.Builder<OperationFactory> builder = ImmutableList.builder();
static EVM istanbul(final GasCalculator gasCalculator) {
final OperationRegistry registry = new OperationRegistry(2);
builder.add(AddOperation::new);
builder.add(AddOperation::new);
builder.add(MulOperation::new);
builder.add(SubOperation::new);
builder.add(DivOperation::new);
builder.add(SDivOperation::new);
builder.add(ModOperation::new);
builder.add(SModOperation::new);
builder.add(ExpOperation::new);
builder.add(AddModOperation::new);
builder.add(MulModOperation::new);
builder.add(SignExtendOperation::new);
builder.add(LtOperation::new);
builder.add(GtOperation::new);
builder.add(SLtOperation::new);
builder.add(SGtOperation::new);
builder.add(EqOperation::new);
builder.add(IsZeroOperation::new);
builder.add(AndOperation::new);
builder.add(OrOperation::new);
builder.add(XorOperation::new);
builder.add(NotOperation::new);
builder.add(ByteOperation::new);
builder.add(Sha3Operation::new);
builder.add(AddressOperation::new);
builder.add(BalanceOperation::new);
builder.add(OriginOperation::new);
builder.add(CallerOperation::new);
builder.add(CallValueOperation::new);
builder.add(CallDataLoadOperation::new);
builder.add(CallDataSizeOperation::new);
builder.add(CallDataCopyOperation::new);
builder.add(CodeSizeOperation::new);
builder.add(CodeCopyOperation::new);
builder.add(GasPriceOperation::new);
builder.add(ExtCodeCopyOperation::new);
builder.add(ExtCodeSizeOperation::new);
builder.add(BlockHashOperation::new);
builder.add(CoinbaseOperation::new);
builder.add(TimestampOperation::new);
builder.add(NumberOperation::new);
builder.add(DifficultyOperation::new);
builder.add(GasLimitOperation::new);
builder.add(PopOperation::new);
builder.add(MLoadOperation::new);
builder.add(MStoreOperation::new);
builder.add(MStore8Operation::new);
builder.add(SLoadOperation::new);
builder.add(SStoreOperation::new);
builder.add(JumpOperation::new);
builder.add(JumpiOperation::new);
builder.add(PCOperation::new);
builder.add(MSizeOperation::new);
builder.add(GasOperation::new);
builder.add(JumpDestOperation::new);
builder.add(ReturnOperation::new);
builder.add(InvalidOperation::new);
builder.add(StopOperation::new);
builder.add(SelfDestructOperation::new);
builder.add(CreateOperation::new);
builder.add(CallOperation::new);
builder.add(CallCodeOperation::new);
registerIstanbulOpcodes(registry, gasCalculator, Account.DEFAULT_VERSION);
return new EVM(registry, new InvalidOperation(gasCalculator));
}
private static void registerFrontierOpcodes(
final OperationRegistry registry,
final GasCalculator gasCalculator,
final int accountVersion) {
registry.put(new AddOperation(gasCalculator), accountVersion);
registry.put(new AddOperation(gasCalculator), accountVersion);
registry.put(new MulOperation(gasCalculator), accountVersion);
registry.put(new SubOperation(gasCalculator), accountVersion);
registry.put(new DivOperation(gasCalculator), accountVersion);
registry.put(new SDivOperation(gasCalculator), accountVersion);
registry.put(new ModOperation(gasCalculator), accountVersion);
registry.put(new SModOperation(gasCalculator), accountVersion);
registry.put(new ExpOperation(gasCalculator), accountVersion);
registry.put(new AddModOperation(gasCalculator), accountVersion);
registry.put(new MulModOperation(gasCalculator), accountVersion);
registry.put(new SignExtendOperation(gasCalculator), accountVersion);
registry.put(new LtOperation(gasCalculator), accountVersion);
registry.put(new GtOperation(gasCalculator), accountVersion);
registry.put(new SLtOperation(gasCalculator), accountVersion);
registry.put(new SGtOperation(gasCalculator), accountVersion);
registry.put(new EqOperation(gasCalculator), accountVersion);
registry.put(new IsZeroOperation(gasCalculator), accountVersion);
registry.put(new AndOperation(gasCalculator), accountVersion);
registry.put(new OrOperation(gasCalculator), accountVersion);
registry.put(new XorOperation(gasCalculator), accountVersion);
registry.put(new NotOperation(gasCalculator), accountVersion);
registry.put(new ByteOperation(gasCalculator), accountVersion);
registry.put(new Sha3Operation(gasCalculator), accountVersion);
registry.put(new AddressOperation(gasCalculator), accountVersion);
registry.put(new BalanceOperation(gasCalculator), accountVersion);
registry.put(new OriginOperation(gasCalculator), accountVersion);
registry.put(new CallerOperation(gasCalculator), accountVersion);
registry.put(new CallValueOperation(gasCalculator), accountVersion);
registry.put(new CallDataLoadOperation(gasCalculator), accountVersion);
registry.put(new CallDataSizeOperation(gasCalculator), accountVersion);
registry.put(new CallDataCopyOperation(gasCalculator), accountVersion);
registry.put(new CodeSizeOperation(gasCalculator), accountVersion);
registry.put(new CodeCopyOperation(gasCalculator), accountVersion);
registry.put(new GasPriceOperation(gasCalculator), accountVersion);
registry.put(new ExtCodeCopyOperation(gasCalculator), accountVersion);
registry.put(new ExtCodeSizeOperation(gasCalculator), accountVersion);
registry.put(new BlockHashOperation(gasCalculator), accountVersion);
registry.put(new CoinbaseOperation(gasCalculator), accountVersion);
registry.put(new TimestampOperation(gasCalculator), accountVersion);
registry.put(new NumberOperation(gasCalculator), accountVersion);
registry.put(new DifficultyOperation(gasCalculator), accountVersion);
registry.put(new GasLimitOperation(gasCalculator), accountVersion);
registry.put(new PopOperation(gasCalculator), accountVersion);
registry.put(new MLoadOperation(gasCalculator), accountVersion);
registry.put(new MStoreOperation(gasCalculator), accountVersion);
registry.put(new MStore8Operation(gasCalculator), accountVersion);
registry.put(new SLoadOperation(gasCalculator), accountVersion);
registry.put(new SStoreOperation(gasCalculator), accountVersion);
registry.put(new JumpOperation(gasCalculator), accountVersion);
registry.put(new JumpiOperation(gasCalculator), accountVersion);
registry.put(new PCOperation(gasCalculator), accountVersion);
registry.put(new MSizeOperation(gasCalculator), accountVersion);
registry.put(new GasOperation(gasCalculator), accountVersion);
registry.put(new JumpDestOperation(gasCalculator), accountVersion);
registry.put(new ReturnOperation(gasCalculator), accountVersion);
registry.put(new InvalidOperation(gasCalculator), accountVersion);
registry.put(new StopOperation(gasCalculator), accountVersion);
registry.put(new SelfDestructOperation(gasCalculator), accountVersion);
registry.put(new CreateOperation(gasCalculator), accountVersion);
registry.put(new CallOperation(gasCalculator), accountVersion);
registry.put(new CallCodeOperation(gasCalculator), accountVersion);
// Register the PUSH1, PUSH2, ..., PUSH32 operations.
for (int i = 1; i <= 32; ++i) {
final int n = i;
builder.add(f -> new PushOperation(n, f));
registry.put(new PushOperation(i, gasCalculator), accountVersion);
}
// Register the DUP1, DUP2, ..., DUP16 operations.
for (int i = 1; i <= 16; ++i) {
final int n = i;
builder.add(f -> new DupOperation(n, f));
registry.put(new DupOperation(i, gasCalculator), accountVersion);
}
// Register the SWAP1, SWAP2, ..., SWAP16 operations.
for (int i = 1; i <= 16; ++i) {
final int n = i;
builder.add(f -> new SwapOperation(n, f));
registry.put(new SwapOperation(i, gasCalculator), accountVersion);
}
// Register the LOG0, LOG1, ..., LOG4 operations.
for (int i = 0; i < 5; ++i) {
final int n = i;
builder.add(f -> new LogOperation(n, f));
registry.put(new LogOperation(i, gasCalculator), accountVersion);
}
return builder.build();
}
private static List<OperationFactory> buildHomesteadFactories(
final List<OperationFactory> factories) {
final ImmutableList.Builder<OperationFactory> builder = ImmutableList.builder();
builder.addAll(factories);
builder.add(DelegateCallOperation::new);
return builder.build();
private static void registerHomesteadOpcodes(
final OperationRegistry registry,
final GasCalculator gasCalculator,
final int accountVersion) {
registerFrontierOpcodes(registry, gasCalculator, accountVersion);
registry.put(new DelegateCallOperation(gasCalculator), accountVersion);
}
private static List<OperationFactory> buildByzantiumFactories(
final List<OperationFactory> factories) {
final ImmutableList.Builder<OperationFactory> builder = ImmutableList.builder();
builder.addAll(factories);
builder.add(ReturnDataCopyOperation::new);
builder.add(ReturnDataSizeOperation::new);
builder.add(RevertOperation::new);
builder.add(StaticCallOperation::new);
return builder.build();
private static void registerByzantiumOpcodes(
final OperationRegistry registry,
final GasCalculator gasCalculator,
final int accountVersion) {
registerHomesteadOpcodes(registry, gasCalculator, accountVersion);
registry.put(new ReturnDataCopyOperation(gasCalculator), accountVersion);
registry.put(new ReturnDataSizeOperation(gasCalculator), accountVersion);
registry.put(new RevertOperation(gasCalculator), accountVersion);
registry.put(new StaticCallOperation(gasCalculator), accountVersion);
}
private static List<OperationFactory> buildConstantinopleFactories(
final List<OperationFactory> factories) {
final ImmutableList.Builder<OperationFactory> builder = ImmutableList.builder();
builder.addAll(factories);
builder.add(Create2Operation::new);
builder.add(SarOperation::new);
builder.add(ShlOperation::new);
builder.add(ShrOperation::new);
builder.add(ExtCodeHashOperation::new);
private static void registerConstantinopleOpcodes(
final OperationRegistry registry,
final GasCalculator gasCalculator,
final int accountVersion) {
registerByzantiumOpcodes(registry, gasCalculator, accountVersion);
registry.put(new Create2Operation(gasCalculator), accountVersion);
registry.put(new SarOperation(gasCalculator), accountVersion);
registry.put(new ShlOperation(gasCalculator), accountVersion);
registry.put(new ShrOperation(gasCalculator), accountVersion);
registry.put(new ExtCodeHashOperation(gasCalculator), accountVersion);
}
return builder.build();
private static void registerIstanbulOpcodes(
final OperationRegistry registry,
final GasCalculator gasCalculator,
final int accountVersion) {
registerConstantinopleOpcodes(registry, gasCalculator, accountVersion);
registerConstantinopleOpcodes(registry, gasCalculator, 1);
}
}

@ -51,7 +51,8 @@ public class MainnetMessageCallProcessor extends AbstractMessageProcessor {
transferValue(frame);
// Check first if the message call is to a pre-compile contract
final PrecompiledContract precompile = precompiles.get(frame.getContractAddress());
final PrecompiledContract precompile =
precompiles.get(frame.getContractAddress(), frame.getContractAccountVersion());
if (precompile != null) {
executePrecompile(precompile, frame);
} else {

@ -12,6 +12,7 @@
*/
package tech.pegasys.pantheon.ethereum.mainnet;
import tech.pegasys.pantheon.ethereum.core.Account;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.mainnet.precompiles.AltBN128AddPrecompiledContract;
import tech.pegasys.pantheon.ethereum.mainnet.precompiles.AltBN128MulPrecompiledContract;
@ -30,45 +31,70 @@ public abstract class MainnetPrecompiledContractRegistries {
private MainnetPrecompiledContractRegistries() {}
private static void populateForFrontier(
final PrecompileContractRegistry registry, final GasCalculator gasCalculator) {
registry.put(Address.ECREC, new ECRECPrecompiledContract(gasCalculator));
registry.put(Address.SHA256, new SHA256PrecompiledContract(gasCalculator));
registry.put(Address.RIPEMD160, new RIPEMD160PrecompiledContract(gasCalculator));
registry.put(Address.ID, new IDPrecompiledContract(gasCalculator));
final PrecompileContractRegistry registry,
final GasCalculator gasCalculator,
final int accountVersion) {
registry.put(Address.ECREC, accountVersion, new ECRECPrecompiledContract(gasCalculator));
registry.put(Address.SHA256, accountVersion, new SHA256PrecompiledContract(gasCalculator));
registry.put(
Address.RIPEMD160, accountVersion, new RIPEMD160PrecompiledContract(gasCalculator));
registry.put(Address.ID, accountVersion, new IDPrecompiledContract(gasCalculator));
}
public static PrecompileContractRegistry frontier(
final PrecompiledContractConfiguration precompiledContractConfiguration) {
final PrecompileContractRegistry registry = new PrecompileContractRegistry();
populateForFrontier(registry, precompiledContractConfiguration.getGasCalculator());
populateForFrontier(
registry, precompiledContractConfiguration.getGasCalculator(), Account.DEFAULT_VERSION);
return registry;
}
private static void populateForByzantium(
final PrecompileContractRegistry registry, final GasCalculator gasCalculator) {
populateForFrontier(registry, gasCalculator);
final PrecompileContractRegistry registry,
final GasCalculator gasCalculator,
final int accountVersion) {
populateForFrontier(registry, gasCalculator, accountVersion);
registry.put(
Address.MODEXP,
accountVersion,
new BigIntegerModularExponentiationPrecompiledContract(gasCalculator));
registry.put(
Address.ALTBN128_ADD, accountVersion, new AltBN128AddPrecompiledContract(gasCalculator));
registry.put(
Address.ALTBN128_MUL, accountVersion, new AltBN128MulPrecompiledContract(gasCalculator));
registry.put(
Address.MODEXP, new BigIntegerModularExponentiationPrecompiledContract(gasCalculator));
registry.put(Address.ALTBN128_ADD, new AltBN128AddPrecompiledContract(gasCalculator));
registry.put(Address.ALTBN128_MUL, new AltBN128MulPrecompiledContract(gasCalculator));
registry.put(Address.ALTBN128_PAIRING, new AltBN128PairingPrecompiledContract(gasCalculator));
Address.ALTBN128_PAIRING,
accountVersion,
new AltBN128PairingPrecompiledContract(gasCalculator));
}
public static PrecompileContractRegistry byzantium(
final PrecompiledContractConfiguration precompiledContractConfiguration) {
final PrecompileContractRegistry registry = new PrecompileContractRegistry();
populateForByzantium(registry, precompiledContractConfiguration.getGasCalculator());
populateForByzantium(
registry, precompiledContractConfiguration.getGasCalculator(), Account.DEFAULT_VERSION);
return registry;
}
public static PrecompileContractRegistry appendPrivacy(
final PrecompileContractRegistry registry,
public static PrecompileContractRegistry istanbul(
final PrecompiledContractConfiguration precompiledContractConfiguration) {
Address address =
final PrecompileContractRegistry registry = new PrecompileContractRegistry();
populateForByzantium(
registry, precompiledContractConfiguration.getGasCalculator(), Account.DEFAULT_VERSION);
populateForByzantium(registry, precompiledContractConfiguration.getGasCalculator(), 1);
return registry;
}
static PrecompileContractRegistry appendPrivacy(
final PrecompileContractRegistry registry,
final PrecompiledContractConfiguration precompiledContractConfiguration,
final int accountVersion) {
final Address address =
Address.privacyPrecompiled(
precompiledContractConfiguration.getPrivacyParameters().getPrivacyAddress());
registry.put(
address,
accountVersion,
new PrivacyPrecompiledContract(
precompiledContractConfiguration.getGasCalculator(),
precompiledContractConfiguration.getPrivacyParameters()));

@ -50,6 +50,8 @@ public abstract class MainnetProtocolSpecs {
public static final int SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT = 24576;
public static final int ISTANBUL_ACCOUNT_VERSION = 1;
private static final Address RIPEMD160_PRECOMPILE =
Address.fromHexString("0x0000000000000000000000000000000000000003");
@ -288,6 +290,8 @@ public abstract class MainnetProtocolSpecs {
final int stackSizeLimit = configStackSizeLimit.orElse(DEFAULT_MAX_STACK_SIZE);
return constantinopleFixDefinition(
chainId, configContractSizeLimit, configStackSizeLimit, enableRevertReason)
.evmBuilder(MainnetEvmRegistries::istanbul)
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::istanbul)
.transactionProcessorBuilder(
(gasCalculator,
transactionValidator,
@ -300,7 +304,7 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
stackSizeLimit,
Account.ISTANBUL_VERSION))
ISTANBUL_ACCOUNT_VERSION))
.privateTransactionProcessorBuilder(
(gasCalculator,
transactionValidator,
@ -313,7 +317,7 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
false,
stackSizeLimit,
Account.ISTANBUL_VERSION))
ISTANBUL_ACCOUNT_VERSION))
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
new MainnetContractCreationProcessor(
@ -323,7 +327,7 @@ public abstract class MainnetProtocolSpecs {
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES,
Account.ISTANBUL_VERSION))
ISTANBUL_ACCOUNT_VERSION))
.name("Istanbul");
}

@ -14,23 +14,26 @@ package tech.pegasys.pantheon.ethereum.mainnet;
import tech.pegasys.pantheon.ethereum.core.Address;
import java.util.HashMap;
import java.util.Map;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
/** Encapsulates a group of {@link PrecompiledContract}s used together. */
public class PrecompileContractRegistry {
private final Map<Address, PrecompiledContract> precompiles;
private final Table<Address, Integer, PrecompiledContract> precompiles;
public PrecompileContractRegistry() {
this.precompiles = new HashMap<>();
this.precompiles = HashBasedTable.create(16, 2);
}
public PrecompiledContract get(final Address address) {
return precompiles.get(address);
public PrecompiledContract get(final Address address, final int contractAccountVersion) {
return precompiles.get(address, contractAccountVersion);
}
public void put(final Address address, final PrecompiledContract precompile) {
precompiles.put(address, precompile);
public void put(
final Address address,
final int contractAccountVersion,
final PrecompiledContract precompile) {
precompiles.put(address, contractAccountVersion, precompile);
}
}

@ -15,6 +15,7 @@ package tech.pegasys.pantheon.ethereum.mainnet;
import static com.google.common.base.Preconditions.checkNotNull;
import tech.pegasys.pantheon.ethereum.BlockValidator;
import tech.pegasys.pantheon.ethereum.core.Account;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderFunctions;
import tech.pegasys.pantheon.ethereum.core.BlockImporter;
@ -131,7 +132,9 @@ public class ProtocolSpecBuilder<T> {
precompileContractRegistryBuilder.apply(precompiledContractConfiguration);
if (precompiledContractConfiguration.getPrivacyParameters().isEnabled()) {
MainnetPrecompiledContractRegistries.appendPrivacy(
registry, precompiledContractConfiguration);
registry, precompiledContractConfiguration, Account.DEFAULT_VERSION);
MainnetPrecompiledContractRegistries.appendPrivacy(
registry, precompiledContractConfiguration, 1);
}
return registry;
};
@ -276,7 +279,8 @@ public class ProtocolSpecBuilder<T> {
gasCalculator, transactionValidator, contractCreationProcessor, messageCallProcessor);
Address address = Address.privacyPrecompiled(privacyParameters.getPrivacyAddress());
PrivacyPrecompiledContract privacyPrecompiledContract =
(PrivacyPrecompiledContract) precompileContractRegistry.get(address);
(PrivacyPrecompiledContract)
precompileContractRegistry.get(address, Account.DEFAULT_VERSION);
privacyPrecompiledContract.setPrivateTransactionProcessor(privateTransactionProcessor);
}

@ -72,10 +72,12 @@ public class Code {
* Determine whether a specified destination is a valid jump target.
*
* @param evm the EVM executing this code
* @param frame The current message frame
* @param destination The destination we're checking for validity.
* @return Whether or not this location is a valid jump destination.
*/
public boolean isValidJumpDestination(final EVM evm, final UInt256 destination) {
public boolean isValidJumpDestination(
final EVM evm, final MessageFrame frame, final UInt256 destination) {
if (!destination.fitsInt()) return false;
final int jumpDestination = destination.toInt();
@ -86,6 +88,7 @@ public class Code {
validJumpDestinations = new BitSet(getSize());
evm.forEachOperation(
this,
frame.getContractAccountVersion(),
(final Operation op, final Integer offset) -> {
if (op.getOpcode() == JumpDestOperation.OPCODE) {
validJumpDestinations.set(offset);

@ -47,12 +47,14 @@ public class EVM {
}
public void forEachOperation(
final Code code, final BiConsumer<Operation, Integer> operationDelegate) {
final Code code,
final int contractAccountVersion,
final BiConsumer<Operation, Integer> operationDelegate) {
int pc = 0;
final int length = code.getSize();
while (pc < length) {
final Operation curOp = operationAtOffset(code, pc);
final Operation curOp = operationAtOffset(code, contractAccountVersion, pc);
operationDelegate.accept(curOp, pc);
pc += curOp.getOpSize();
}
@ -60,7 +62,8 @@ public class EVM {
private void executeNextOperation(final MessageFrame frame, final OperationTracer operationTracer)
throws ExceptionalHaltException {
frame.setCurrentOperation(operationAtOffset(frame.getCode(), frame.getPC()));
frame.setCurrentOperation(
operationAtOffset(frame.getCode(), frame.getContractAccountVersion(), frame.getPC()));
evaluateExceptionalHaltReasons(frame);
final Optional<Gas> currentGasCost = calculateGasCost(frame);
operationTracer.traceExecution(
@ -135,13 +138,14 @@ public class EVM {
}
}
private Operation operationAtOffset(final Code code, final int offset) {
private Operation operationAtOffset(
final Code code, final int contractAccountVersion, final int offset) {
final BytesValue bytecode = code.getBytes();
// If the length of the program code is shorter than the required offset, halt execution.
if (offset >= bytecode.size()) {
return operations.get(STOP_OPCODE);
return operations.get(STOP_OPCODE, contractAccountVersion);
}
return operations.getOrDefault(bytecode.get(offset), invalidOperation);
return operations.getOrDefault(bytecode.get(offset), contractAccountVersion, invalidOperation);
}
}

@ -12,31 +12,39 @@
*/
package tech.pegasys.pantheon.ethereum.vm;
import com.google.common.base.Preconditions;
/** Encapsulates a group of {@link Operation}s used together. */
public class OperationRegistry {
private static final int NUM_OPERATIONS = 256;
private final Operation[] operations;
private final Operation[][] operations;
public OperationRegistry() {
this.operations = new Operation[NUM_OPERATIONS];
this(1);
}
public OperationRegistry(final int numVersions) {
Preconditions.checkArgument(numVersions >= 1);
this.operations = new Operation[numVersions][NUM_OPERATIONS];
}
public Operation get(final byte opcode) {
return get(opcode & 0xff);
public Operation get(final byte opcode, final int version) {
return get(opcode & 0xff, version);
}
public Operation get(final int opcode) {
return operations[opcode];
public Operation get(final int opcode, final int version) {
return operations[version][opcode];
}
public void put(final int opcode, final Operation operation) {
operations[opcode] = operation;
public void put(final Operation operation, final int version) {
operations[version][operation.getOpcode()] = operation;
}
public Operation getOrDefault(final byte opcode, final Operation defaultOperation) {
final Operation operation = get(opcode);
public Operation getOrDefault(
final byte opcode, final int version, final Operation defaultOperation) {
final Operation operation = get(opcode, version);
if (operation == null) {
return defaultOperation;

@ -49,7 +49,7 @@ public class JumpOperation extends AbstractOperation {
final Code code = frame.getCode();
final UInt256 potentialJumpDestination = frame.getStackItem(0).asUInt256();
return !code.isValidJumpDestination(evm, potentialJumpDestination)
return !code.isValidJumpDestination(evm, frame, potentialJumpDestination)
? Optional.of(ExceptionalHaltReason.INVALID_JUMP_DESTINATION)
: Optional.empty();
}

@ -60,7 +60,7 @@ public class JumpiOperation extends AbstractOperation {
final Code code = frame.getCode();
final UInt256 potentialJumpDestination = frame.getStackItem(0).asUInt256();
return !code.isValidJumpDestination(evm, potentialJumpDestination)
return !code.isValidJumpDestination(evm, frame, potentialJumpDestination)
? Optional.of(ExceptionalHaltReason.INVALID_JUMP_DESTINATION)
: Optional.empty();
}

@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import tech.pegasys.pantheon.config.GenesisConfigFile;
import tech.pegasys.pantheon.controller.PantheonController;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Account;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider;
import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder;
@ -72,7 +73,7 @@ public class PrivacyTest {
.getProtocolSchedule()
.getByBlockNumber(1)
.getPrecompileContractRegistry()
.get(privacyContractAddress);
.get(privacyContractAddress, Account.DEFAULT_VERSION);
assertThat(precompiledContract.getName()).isEqualTo("Privacy");
}
}

Loading…
Cancel
Save