mirror of https://github.com/hyperledger/besu
Evm speedup (#2796)
Broad reaching optimizations to speed up EVM calculations * Generally speaking, use int and long where it is more appropriate than UInt256 (memory indexes mostly) * Move the internal stack to Bytes from UInt256 * Re-work the flow of many operations to account for the above Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>pull/2804/head
parent
2541b155f8
commit
2415000caf
@ -1,54 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 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. |
|
||||||
* |
|
||||||
* SPDX-License-Identifier: Apache-2.0 |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.hyperledger.besu.evm; |
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkState; |
|
||||||
|
|
||||||
import org.hyperledger.besu.datatypes.Address; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.ArrayList; |
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonParser; |
|
||||||
import com.fasterxml.jackson.core.JsonToken; |
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext; |
|
||||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer; |
|
||||||
import org.apache.tuweni.bytes.Bytes32; |
|
||||||
|
|
||||||
public class AccessListEntryDeserializer extends StdDeserializer<AccessListEntry> { |
|
||||||
private AccessListEntryDeserializer() { |
|
||||||
this(null); |
|
||||||
} |
|
||||||
|
|
||||||
protected AccessListEntryDeserializer(final Class<?> vc) { |
|
||||||
super(vc); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public AccessListEntry deserialize(final JsonParser p, final DeserializationContext ctxt) |
|
||||||
throws IOException { |
|
||||||
checkState(p.nextFieldName().equals("address")); |
|
||||||
final Address address = Address.fromHexString(p.nextTextValue()); |
|
||||||
checkState(p.nextFieldName().equals("storageKeys")); |
|
||||||
checkState(p.nextToken().equals(JsonToken.START_ARRAY)); |
|
||||||
final ArrayList<Bytes32> storageKeys = new ArrayList<>(); |
|
||||||
while (!p.nextToken().equals(JsonToken.END_ARRAY)) { |
|
||||||
storageKeys.add(Bytes32.fromHexString(p.getText())); |
|
||||||
} |
|
||||||
p.nextToken(); // consume end of object
|
|
||||||
return new AccessListEntry(address, storageKeys); |
|
||||||
} |
|
||||||
} |
|
@ -1,52 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 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. |
|
||||||
* |
|
||||||
* SPDX-License-Identifier: Apache-2.0 |
|
||||||
*/ |
|
||||||
package org.hyperledger.besu.evm; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator; |
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider; |
|
||||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer; |
|
||||||
import org.apache.tuweni.bytes.Bytes32; |
|
||||||
|
|
||||||
public class AccessListEntrySerializer extends StdSerializer<AccessListEntry> { |
|
||||||
|
|
||||||
AccessListEntrySerializer() { |
|
||||||
this(null); |
|
||||||
} |
|
||||||
|
|
||||||
protected AccessListEntrySerializer(final Class<AccessListEntry> t) { |
|
||||||
super(t); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void serialize( |
|
||||||
final AccessListEntry accessListEntry, |
|
||||||
final JsonGenerator gen, |
|
||||||
final SerializerProvider provider) |
|
||||||
throws IOException { |
|
||||||
gen.writeStartObject(); |
|
||||||
gen.writeFieldName("address"); |
|
||||||
gen.writeString(accessListEntry.getAddress().toHexString()); |
|
||||||
gen.writeFieldName("storageKeys"); |
|
||||||
final List<Bytes32> storageKeys = accessListEntry.getStorageKeys(); |
|
||||||
gen.writeArray( |
|
||||||
storageKeys.stream().map(Bytes32::toHexString).toArray(String[]::new), |
|
||||||
0, |
|
||||||
storageKeys.size()); |
|
||||||
gen.writeEndObject(); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,383 @@ |
|||||||
|
/* |
||||||
|
* 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.fluent; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
import org.hyperledger.besu.datatypes.Wei; |
||||||
|
import org.hyperledger.besu.evm.Code; |
||||||
|
import org.hyperledger.besu.evm.EVM; |
||||||
|
import org.hyperledger.besu.evm.Gas; |
||||||
|
import org.hyperledger.besu.evm.MainnetEVMs; |
||||||
|
import org.hyperledger.besu.evm.contractvalidation.ContractValidationRule; |
||||||
|
import org.hyperledger.besu.evm.contractvalidation.MaxCodeSizeRule; |
||||||
|
import org.hyperledger.besu.evm.contractvalidation.PrefixCodeRule; |
||||||
|
import org.hyperledger.besu.evm.frame.BlockValues; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
import org.hyperledger.besu.evm.precompile.MainnetPrecompiledContracts; |
||||||
|
import org.hyperledger.besu.evm.precompile.PrecompileContractRegistry; |
||||||
|
import org.hyperledger.besu.evm.processor.ContractCreationProcessor; |
||||||
|
import org.hyperledger.besu.evm.processor.MessageCallProcessor; |
||||||
|
import org.hyperledger.besu.evm.tracing.OperationTracer; |
||||||
|
import org.hyperledger.besu.evm.worldstate.WorldUpdater; |
||||||
|
|
||||||
|
import java.util.ArrayDeque; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Deque; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Objects; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import com.google.common.collect.HashMultimap; |
||||||
|
import com.google.common.collect.Multimap; |
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
|
||||||
|
public class EVMExecutor { |
||||||
|
|
||||||
|
private PrecompileContractRegistry precompileContractRegistry; |
||||||
|
private EVM evm; |
||||||
|
private boolean commitWorldState = false; |
||||||
|
private WorldUpdater worldUpdater = new SimpleWorld(); |
||||||
|
private Gas gas = Gas.MAX_VALUE; |
||||||
|
private Address receiver = Address.ZERO; |
||||||
|
private Address sender = Address.ZERO; |
||||||
|
private Wei gasPriceGWei = Wei.ZERO; |
||||||
|
private Bytes callData = Bytes.EMPTY; |
||||||
|
private Wei ethValue = Wei.ZERO; |
||||||
|
private Code code = new Code(Bytes.EMPTY); |
||||||
|
private BlockValues blockValues = new SimpleBlockValues(); |
||||||
|
private OperationTracer tracer = OperationTracer.NO_TRACING; |
||||||
|
private boolean requireDeposit = true; |
||||||
|
private List<ContractValidationRule> contractValidationRules = |
||||||
|
List.of(MaxCodeSizeRule.of(0x6000), PrefixCodeRule.of()); |
||||||
|
private long initialNonce = 0; |
||||||
|
private Collection<Address> forceCommitAddresses = List.of(Address.fromHexString("0x03")); |
||||||
|
private Set<Address> accessListWarmAddresses = Set.of(); |
||||||
|
private Multimap<Address, Bytes32> accessListWarmStorage = HashMultimap.create(); |
||||||
|
private MessageCallProcessor messageCallProcessor = null; |
||||||
|
private ContractCreationProcessor contractCreationProcessor = null; |
||||||
|
|
||||||
|
public static EVMExecutor evm(final EVM evm) { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = evm; |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor frontier() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.frontier(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); |
||||||
|
executor.contractValidationRules = List.of(); |
||||||
|
executor.requireDeposit = false; |
||||||
|
executor.forceCommitAddresses = List.of(); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor homestead() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.homestead(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); |
||||||
|
executor.contractValidationRules = List.of(); |
||||||
|
executor.forceCommitAddresses = List.of(); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor spuriousDragon() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.spuriousDragon(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); |
||||||
|
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor tangerineWhistle() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.tangerineWhistle(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); |
||||||
|
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor byzantium() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.byzantium(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator()); |
||||||
|
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor constantinople() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.constantinople(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator()); |
||||||
|
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor petersburg() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.petersburg(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator()); |
||||||
|
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor istanbul() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.istanbul(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator()); |
||||||
|
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor berlin() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.berlin(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator()); |
||||||
|
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
public static EVMExecutor london() { |
||||||
|
EVMExecutor executor = new EVMExecutor(); |
||||||
|
executor.evm = MainnetEVMs.istanbul(); |
||||||
|
executor.precompileContractRegistry = |
||||||
|
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator()); |
||||||
|
return executor; |
||||||
|
} |
||||||
|
|
||||||
|
private MessageCallProcessor thisMessageCallProcessor() { |
||||||
|
return Objects.requireNonNullElseGet( |
||||||
|
messageCallProcessor, () -> new MessageCallProcessor(evm, precompileContractRegistry)); |
||||||
|
} |
||||||
|
|
||||||
|
private ContractCreationProcessor thisContractCreationProcessor() { |
||||||
|
return Objects.requireNonNullElseGet( |
||||||
|
contractCreationProcessor, |
||||||
|
() -> |
||||||
|
new ContractCreationProcessor( |
||||||
|
evm.getGasCalculator(), |
||||||
|
evm, |
||||||
|
requireDeposit, |
||||||
|
contractValidationRules, |
||||||
|
initialNonce, |
||||||
|
forceCommitAddresses)); |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes execute( |
||||||
|
final Code code, final Bytes inputData, final Wei value, final Address receiver) { |
||||||
|
this.code = code; |
||||||
|
this.callData = inputData; |
||||||
|
this.ethValue = value; |
||||||
|
this.receiver = receiver; |
||||||
|
return execute(); |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes execute( |
||||||
|
final Bytes codeBytes, final Bytes inputData, final Wei value, final Address receiver) { |
||||||
|
this.code = new Code(codeBytes); |
||||||
|
this.callData = inputData; |
||||||
|
this.ethValue = value; |
||||||
|
this.receiver = receiver; |
||||||
|
return execute(); |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes execute() { |
||||||
|
MessageCallProcessor mcp = thisMessageCallProcessor(); |
||||||
|
ContractCreationProcessor ccp = thisContractCreationProcessor(); |
||||||
|
final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>(); |
||||||
|
MessageFrame initialMessageFrame = |
||||||
|
MessageFrame.builder() |
||||||
|
.type(MessageFrame.Type.MESSAGE_CALL) |
||||||
|
.messageFrameStack(messageFrameStack) |
||||||
|
.worldUpdater(worldUpdater.updater()) |
||||||
|
.initialGas(gas) |
||||||
|
.contract(Address.ZERO) |
||||||
|
.address(receiver) |
||||||
|
.originator(sender) |
||||||
|
.sender(sender) |
||||||
|
.gasPrice(gasPriceGWei) |
||||||
|
.inputData(callData) |
||||||
|
.value(ethValue) |
||||||
|
.apparentValue(ethValue) |
||||||
|
.code(code) |
||||||
|
.blockValues(blockValues) |
||||||
|
.depth(0) |
||||||
|
.completer(c -> {}) |
||||||
|
.miningBeneficiary(Address.ZERO) |
||||||
|
.blockHashLookup(h -> null) |
||||||
|
.accessListWarmAddresses(accessListWarmAddresses) |
||||||
|
.accessListWarmStorage(accessListWarmStorage) |
||||||
|
.build(); |
||||||
|
messageFrameStack.add(initialMessageFrame); |
||||||
|
|
||||||
|
while (!messageFrameStack.isEmpty()) { |
||||||
|
final MessageFrame messageFrame = messageFrameStack.peek(); |
||||||
|
switch (messageFrame.getType()) { |
||||||
|
case CONTRACT_CREATION: |
||||||
|
mcp.process(messageFrame, tracer); |
||||||
|
break; |
||||||
|
case MESSAGE_CALL: |
||||||
|
ccp.process(messageFrame, tracer); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
if (commitWorldState) { |
||||||
|
worldUpdater.commit(); |
||||||
|
} |
||||||
|
return initialMessageFrame.getReturnData(); |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor commitWorldState() { |
||||||
|
this.commitWorldState = true; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor commitWorldState(final boolean commitWorldState) { |
||||||
|
this.commitWorldState = commitWorldState; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor worldUpdater(final WorldUpdater worldUpdater) { |
||||||
|
this.worldUpdater = worldUpdater; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor gas(final Gas gas) { |
||||||
|
this.gas = gas; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor receiver(final Address receiver) { |
||||||
|
this.receiver = receiver; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor sender(final Address sender) { |
||||||
|
this.sender = sender; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor gasPriceGWei(final Wei gasPriceGWei) { |
||||||
|
this.gasPriceGWei = gasPriceGWei; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor callData(final Bytes callData) { |
||||||
|
this.callData = callData; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor ethValue(final Wei ethValue) { |
||||||
|
this.ethValue = ethValue; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor code(final Code code) { |
||||||
|
this.code = code; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor code(final Bytes codeBytes) { |
||||||
|
this.code = new Code(codeBytes); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor blockValues(final BlockValues blockValues) { |
||||||
|
this.blockValues = blockValues; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor tracer(final OperationTracer tracer) { |
||||||
|
this.tracer = tracer; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor precompileContractRegistry( |
||||||
|
final PrecompileContractRegistry precompileContractRegistry) { |
||||||
|
this.precompileContractRegistry = precompileContractRegistry; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor requireDeposit(final boolean requireDeposit) { |
||||||
|
this.requireDeposit = requireDeposit; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor initialNonce(final long initialNonce) { |
||||||
|
this.initialNonce = initialNonce; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor contractValidationRules( |
||||||
|
final List<ContractValidationRule> contractValidationRules) { |
||||||
|
this.contractValidationRules = contractValidationRules; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* List of EIP-718 contracts that require special delete handling. By default, this is only the |
||||||
|
* RIPEMD precompile contract. |
||||||
|
* |
||||||
|
* @see <a |
||||||
|
* href="https://github.com/ethereum/EIPs/issues/716">https://github.com/ethereum/EIPs/issues/716</a>
|
||||||
|
* @param forceCommitAddresses collection of addresses for special handling |
||||||
|
* @return fluent executor |
||||||
|
*/ |
||||||
|
public EVMExecutor forceCommitAddresses(final Collection<Address> forceCommitAddresses) { |
||||||
|
this.forceCommitAddresses = forceCommitAddresses; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor accessListWarmAddresses(final Set<Address> accessListWarmAddresses) { |
||||||
|
this.accessListWarmAddresses = accessListWarmAddresses; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor warmAddress(final Address... addresses) { |
||||||
|
this.accessListWarmAddresses.addAll(List.of(addresses)); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor accessListWarmStorage(final Multimap<Address, Bytes32> accessListWarmStorage) { |
||||||
|
this.accessListWarmStorage = accessListWarmStorage; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor accessListWarmStorage(final Address address, final Bytes32... slots) { |
||||||
|
this.accessListWarmStorage.putAll(address, List.of(slots)); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor messageCallProcessor(final MessageCallProcessor messageCallProcessor) { |
||||||
|
this.messageCallProcessor = messageCallProcessor; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public EVMExecutor contractCallProcessor( |
||||||
|
final ContractCreationProcessor contractCreationProcessor) { |
||||||
|
this.contractCreationProcessor = contractCreationProcessor; |
||||||
|
return this; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,158 @@ |
|||||||
|
/* |
||||||
|
* 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.fluent; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
import org.hyperledger.besu.datatypes.Hash; |
||||||
|
import org.hyperledger.besu.datatypes.Wei; |
||||||
|
import org.hyperledger.besu.evm.ModificationNotAllowedException; |
||||||
|
import org.hyperledger.besu.evm.account.Account; |
||||||
|
import org.hyperledger.besu.evm.account.AccountStorageEntry; |
||||||
|
import org.hyperledger.besu.evm.account.EvmAccount; |
||||||
|
import org.hyperledger.besu.evm.account.MutableAccount; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.NavigableMap; |
||||||
|
import java.util.function.Supplier; |
||||||
|
|
||||||
|
import com.google.common.base.Suppliers; |
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
import org.apache.tuweni.units.bigints.UInt256; |
||||||
|
|
||||||
|
public class SimpleAccount implements EvmAccount, MutableAccount { |
||||||
|
|
||||||
|
private final Account parent; |
||||||
|
|
||||||
|
private Address address; |
||||||
|
private final Supplier<Hash> addressHash = |
||||||
|
Suppliers.memoize(() -> address == null ? Hash.ZERO : Hash.hash(address)); |
||||||
|
private long nonce; |
||||||
|
private Wei balance; |
||||||
|
private Bytes code; |
||||||
|
private Supplier<Hash> codeHash = |
||||||
|
Suppliers.memoize(() -> code == null ? Hash.EMPTY : Hash.hash(code)); |
||||||
|
private final Map<UInt256, UInt256> storage = new HashMap<>(); |
||||||
|
|
||||||
|
public SimpleAccount(final Address address, final long nonce, final Wei balance) { |
||||||
|
this(null, address, nonce, balance, Bytes.EMPTY); |
||||||
|
} |
||||||
|
|
||||||
|
public SimpleAccount( |
||||||
|
final Account parent, |
||||||
|
final Address address, |
||||||
|
final long nonce, |
||||||
|
final Wei balance, |
||||||
|
final Bytes code) { |
||||||
|
this.parent = parent; |
||||||
|
this.address = address; |
||||||
|
this.nonce = nonce; |
||||||
|
this.balance = balance; |
||||||
|
this.code = code; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Address getAddress() { |
||||||
|
return address; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Hash getAddressHash() { |
||||||
|
return addressHash.get(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getNonce() { |
||||||
|
return nonce; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Wei getBalance() { |
||||||
|
return balance; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Bytes getCode() { |
||||||
|
return code; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Hash getCodeHash() { |
||||||
|
return codeHash.get(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public UInt256 getStorageValue(final UInt256 key) { |
||||||
|
if (storage.containsKey(key)) { |
||||||
|
return storage.get(key); |
||||||
|
} else { |
||||||
|
return getOriginalStorageValue(key); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public UInt256 getOriginalStorageValue(final UInt256 key) { |
||||||
|
if (parent != null) { |
||||||
|
return parent.getStorageValue(key); |
||||||
|
} else { |
||||||
|
return UInt256.ZERO; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom( |
||||||
|
final Bytes32 startKeyHash, final int limit) { |
||||||
|
throw new UnsupportedOperationException( |
||||||
|
"Storage iteration not supported in simple account facade"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public MutableAccount getMutable() throws ModificationNotAllowedException { |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setNonce(final long value) { |
||||||
|
nonce = value; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setBalance(final Wei value) { |
||||||
|
balance = value; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setCode(final Bytes code) { |
||||||
|
this.code = code; |
||||||
|
codeHash = Suppliers.memoize(() -> this.code == null ? Hash.EMPTY : Hash.hash(this.code)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStorageValue(final UInt256 key, final UInt256 value) { |
||||||
|
storage.put(key, value); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void clearStorage() { |
||||||
|
storage.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Map<UInt256, UInt256> getUpdatedStorage() { |
||||||
|
return storage; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
/* |
||||||
|
* 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.fluent; |
||||||
|
|
||||||
|
import org.hyperledger.besu.evm.frame.BlockValues; |
||||||
|
|
||||||
|
/** A concrete BlockValues object that takes all the defaults */ |
||||||
|
public class SimpleBlockValues implements BlockValues {} |
@ -0,0 +1,109 @@ |
|||||||
|
/* |
||||||
|
* 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.fluent; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
import org.hyperledger.besu.datatypes.Wei; |
||||||
|
import org.hyperledger.besu.evm.account.Account; |
||||||
|
import org.hyperledger.besu.evm.account.EvmAccount; |
||||||
|
import org.hyperledger.besu.evm.worldstate.WorldUpdater; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Optional; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
public class SimpleWorld implements WorldUpdater { |
||||||
|
|
||||||
|
SimpleWorld parent; |
||||||
|
Map<Address, SimpleAccount> accounts = new HashMap<>(); |
||||||
|
|
||||||
|
public SimpleWorld() { |
||||||
|
this(null); |
||||||
|
} |
||||||
|
|
||||||
|
public SimpleWorld(final SimpleWorld parent) { |
||||||
|
this.parent = parent; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public WorldUpdater updater() { |
||||||
|
return new SimpleWorld(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Account get(final Address address) { |
||||||
|
if (accounts.containsKey(address)) { |
||||||
|
return accounts.get(address); |
||||||
|
} else if (parent != null) { |
||||||
|
return parent.get(address); |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public EvmAccount createAccount(final Address address, final long nonce, final Wei balance) { |
||||||
|
SimpleAccount account = new SimpleAccount(address, nonce, balance); |
||||||
|
accounts.put(address, account); |
||||||
|
return account; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public EvmAccount getAccount(final Address address) { |
||||||
|
if (accounts.containsKey(address)) { |
||||||
|
return accounts.get(address); |
||||||
|
} else if (parent != null) { |
||||||
|
return parent.getAccount(address); |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void deleteAccount(final Address address) { |
||||||
|
accounts.put(address, null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<? extends Account> getTouchedAccounts() { |
||||||
|
return accounts.values(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<Address> getDeletedAccountAddresses() { |
||||||
|
return accounts.entrySet().stream() |
||||||
|
.filter(e -> e.getValue() == null) |
||||||
|
.map(Map.Entry::getKey) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void revert() { |
||||||
|
accounts = new HashMap<>(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void commit() { |
||||||
|
parent.accounts.putAll(accounts); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Optional<WorldUpdater> parentUpdater() { |
||||||
|
return Optional.empty(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
/* |
||||||
|
* 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.internal; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.apache.tuweni.units.bigints.UInt256; |
||||||
|
|
||||||
|
public class StorageEntry { |
||||||
|
private final UInt256 offset; |
||||||
|
private final Bytes value; |
||||||
|
|
||||||
|
public StorageEntry(final UInt256 offset, final Bytes value) { |
||||||
|
this.offset = offset; |
||||||
|
this.value = value; |
||||||
|
} |
||||||
|
|
||||||
|
public UInt256 getOffset() { |
||||||
|
return offset; |
||||||
|
} |
||||||
|
|
||||||
|
public Bytes getValue() { |
||||||
|
return value; |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue