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