Search in sources :

Example 6 with WorldUpdater

use of org.hyperledger.besu.evm.worldstate.WorldUpdater in project besu by hyperledger.

the class StateDiffGenerator method generateStateDiff.

public Stream<Trace> generateStateDiff(final TransactionTrace transactionTrace) {
    final List<TraceFrame> traceFrames = transactionTrace.getTraceFrames();
    if (traceFrames.size() < 1) {
        return Stream.empty();
    }
    // This corresponds to the world state after the TX executed
    // It is two deep because of the way we addressed Spurious Dragon.
    final WorldUpdater transactionUpdater = traceFrames.get(0).getWorldUpdater().parentUpdater().get().parentUpdater().get();
    // This corresponds to the world state prior to the TX execution,
    // Either the initial block state or the state of the prior TX
    final WorldUpdater previousUpdater = transactionUpdater.parentUpdater().get();
    final StateDiffTrace stateDiffResult = new StateDiffTrace();
    for (final Account updatedAccount : transactionUpdater.getTouchedAccounts()) {
        final Address accountAddress = updatedAccount.getAddress();
        final Account rootAccount = previousUpdater.get(accountAddress);
        // calculate storage diff
        final Map<String, DiffNode> storageDiff = new TreeMap<>();
        for (final Map.Entry<UInt256, UInt256> entry : ((UpdateTrackingAccount<?>) updatedAccount).getUpdatedStorage().entrySet()) {
            // FIXME cast
            final UInt256 newValue = entry.getValue();
            if (rootAccount == null) {
                if (!UInt256.ZERO.equals(newValue)) {
                    storageDiff.put(entry.getKey().toHexString(), new DiffNode(null, newValue.toHexString()));
                }
            } else {
                final UInt256 originalValue = rootAccount.getStorageValue(entry.getKey());
                if (!originalValue.equals(newValue)) {
                    storageDiff.put(entry.getKey().toHexString(), new DiffNode(originalValue.toHexString(), newValue.toHexString()));
                }
            }
        }
        // populate the diff object
        final AccountDiff accountDiff = new AccountDiff(createDiffNode(rootAccount, updatedAccount, StateDiffGenerator::balanceAsHex), createDiffNode(rootAccount, updatedAccount, StateDiffGenerator::codeAsHex), createDiffNode(rootAccount, updatedAccount, StateDiffGenerator::nonceAsHex), storageDiff);
        if (accountDiff.hasDifference()) {
            stateDiffResult.put(accountAddress.toHexString(), accountDiff);
        }
    }
    // Add deleted accounts
    for (final Address accountAddress : transactionUpdater.getDeletedAccountAddresses()) {
        final Account deletedAccount = previousUpdater.get(accountAddress);
        if (deletedAccount == null) {
            continue;
        }
        final AccountDiff accountDiff = new AccountDiff(createDiffNode(deletedAccount, null, StateDiffGenerator::balanceAsHex), createDiffNode(deletedAccount, null, StateDiffGenerator::codeAsHex), createDiffNode(deletedAccount, null, StateDiffGenerator::nonceAsHex), Collections.emptyMap());
        stateDiffResult.put(accountAddress.toHexString(), accountDiff);
    }
    return Stream.of(stateDiffResult);
}
Also used : Account(org.hyperledger.besu.evm.account.Account) UpdateTrackingAccount(org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount) Address(org.hyperledger.besu.datatypes.Address) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) TreeMap(java.util.TreeMap) TreeMap(java.util.TreeMap) Map(java.util.Map) TraceFrame(org.hyperledger.besu.ethereum.debug.TraceFrame) UInt256(org.apache.tuweni.units.bigints.UInt256)

Example 7 with WorldUpdater

use of org.hyperledger.besu.evm.worldstate.WorldUpdater in project besu by hyperledger.

the class TransactionTracer method traceTransactionToFile.

public List<String> traceTransactionToFile(final Hash blockHash, final Optional<TransactionTraceParams> transactionTraceParams, final Path traceDir) {
    final Optional<Hash> selectedHash = transactionTraceParams.map(TransactionTraceParams::getTransactionHash).map(Hash::fromHexString);
    final boolean showMemory = transactionTraceParams.map(TransactionTraceParams::traceOptions).map(TraceOptions::isMemoryEnabled).orElse(true);
    if (!Files.isDirectory(traceDir) && !traceDir.toFile().mkdirs()) {
        throw new RuntimeException(String.format("Trace directory '%s' does not exist and could not be made.", traceDir));
    }
    return blockReplay.performActionWithBlock(blockHash, (body, header, blockchain, worldState, transactionProcessor) -> {
        WorldUpdater stackedUpdater = worldState.updater().updater();
        final List<String> traces = new ArrayList<>();
        for (int i = 0; i < body.getTransactions().size(); i++) {
            ((StackedUpdater<?, ?>) stackedUpdater).markTransactionBoundary();
            final Transaction transaction = body.getTransactions().get(i);
            if (selectedHash.isEmpty() || selectedHash.filter(isEqual(transaction.getHash())).isPresent()) {
                final File traceFile = generateTraceFile(traceDir, blockHash, i, transaction);
                try (PrintStream out = new PrintStream(new FileOutputStream(traceFile))) {
                    final Stopwatch timer = Stopwatch.createStarted();
                    final TransactionProcessingResult result = processTransaction(header, blockchain, stackedUpdater, transaction, transactionProcessor, new StandardJsonTracer(out, showMemory));
                    out.println(summaryTrace(transaction, timer.stop().elapsed(TimeUnit.NANOSECONDS), result));
                    traces.add(traceFile.getPath());
                } catch (FileNotFoundException e) {
                    throw new RuntimeException("Unable to create transaction trace : " + e.getMessage());
                }
            } else {
                processTransaction(header, blockchain, stackedUpdater, transaction, transactionProcessor, OperationTracer.NO_TRACING);
            }
        }
        return Optional.of(traces);
    }).orElse(new ArrayList<>());
}
Also used : TraceOptions(org.hyperledger.besu.ethereum.debug.TraceOptions) StackedUpdater(org.hyperledger.besu.evm.worldstate.StackedUpdater) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) Stopwatch(com.google.common.base.Stopwatch) OperationTracer(org.hyperledger.besu.evm.tracing.OperationTracer) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) ArrayList(java.util.ArrayList) TransactionTraceParams(org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams) UInt256(org.apache.tuweni.units.bigints.UInt256) Path(java.nio.file.Path) PrintStream(java.io.PrintStream) Files(java.nio.file.Files) BlockHeader(org.hyperledger.besu.ethereum.core.BlockHeader) Blockchain(org.hyperledger.besu.ethereum.chain.Blockchain) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) Predicate.isEqual(java.util.function.Predicate.isEqual) FileOutputStream(java.io.FileOutputStream) MainnetTransactionProcessor(org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor) BlockHashLookup(org.hyperledger.besu.ethereum.vm.BlockHashLookup) DebugOperationTracer(org.hyperledger.besu.ethereum.vm.DebugOperationTracer) File(java.io.File) FileNotFoundException(java.io.FileNotFoundException) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult) TimeUnit(java.util.concurrent.TimeUnit) List(java.util.List) ImmutableTransactionValidationParams(org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams) Optional(java.util.Optional) Transaction(org.hyperledger.besu.ethereum.core.Transaction) StandardJsonTracer(org.hyperledger.besu.evm.tracing.StandardJsonTracer) Hash(org.hyperledger.besu.datatypes.Hash) PrintStream(java.io.PrintStream) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) Stopwatch(com.google.common.base.Stopwatch) FileNotFoundException(java.io.FileNotFoundException) TransactionTraceParams(org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams) Hash(org.hyperledger.besu.datatypes.Hash) StandardJsonTracer(org.hyperledger.besu.evm.tracing.StandardJsonTracer) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult) Transaction(org.hyperledger.besu.ethereum.core.Transaction) FileOutputStream(java.io.FileOutputStream) ArrayList(java.util.ArrayList) List(java.util.List) File(java.io.File)

Example 8 with WorldUpdater

use of org.hyperledger.besu.evm.worldstate.WorldUpdater in project besu by hyperledger.

the class TraceTransactionIntegrationTest method shouldTraceSStoreOperation.

@Test
public void shouldTraceSStoreOperation() {
    final KeyPair keyPair = SignatureAlgorithmFactory.getInstance().generateKeyPair();
    final Transaction createTransaction = Transaction.builder().type(TransactionType.FRONTIER).gasLimit(300_000).gasPrice(Wei.ZERO).nonce(0).payload(Bytes.fromHexString(CONTRACT_CREATION_DATA)).value(Wei.ZERO).signAndBuild(keyPair);
    final BlockHeader genesisBlockHeader = genesisBlock.getHeader();
    final MutableWorldState worldState = worldStateArchive.getMutable(genesisBlockHeader.getStateRoot(), genesisBlockHeader.getHash()).get();
    final WorldUpdater createTransactionUpdater = worldState.updater();
    TransactionProcessingResult result = transactionProcessor.processTransaction(blockchain, createTransactionUpdater, genesisBlockHeader, createTransaction, genesisBlockHeader.getCoinbase(), blockHashLookup, false, TransactionValidationParams.blockReplay());
    assertThat(result.isSuccessful()).isTrue();
    final Account createdContract = createTransactionUpdater.getTouchedAccounts().stream().filter(account -> !account.getCode().isEmpty()).findAny().get();
    createTransactionUpdater.commit();
    // Now call the transaction to execute the SSTORE.
    final DebugOperationTracer tracer = new DebugOperationTracer(new TraceOptions(true, true, true));
    final Transaction executeTransaction = Transaction.builder().type(TransactionType.FRONTIER).gasLimit(300_000).gasPrice(Wei.ZERO).nonce(1).payload(Bytes.fromHexString(CALL_SET_OTHER)).to(createdContract.getAddress()).value(Wei.ZERO).signAndBuild(keyPair);
    final WorldUpdater storeUpdater = worldState.updater();
    result = transactionProcessor.processTransaction(blockchain, storeUpdater, genesisBlockHeader, executeTransaction, genesisBlockHeader.getCoinbase(), tracer, blockHashLookup, false);
    assertThat(result.isSuccessful()).isTrue();
    // No storage changes before the SSTORE call.
    TraceFrame frame = tracer.getTraceFrames().get(170);
    assertThat(frame.getOpcode()).isEqualTo("DUP6");
    assertStorageContainsExactly(frame);
    // Storage changes show up in the SSTORE frame.
    frame = tracer.getTraceFrames().get(171);
    assertThat(frame.getOpcode()).isEqualTo("SSTORE");
    assertStorageContainsExactly(frame, entry("0x01", "0x6261720000000000000000000000000000000000000000000000000000000006"));
    // And storage changes are still present in future frames.
    frame = tracer.getTraceFrames().get(172);
    assertThat(frame.getOpcode()).isEqualTo("PUSH2");
    assertStorageContainsExactly(frame, entry("0x01", "0x6261720000000000000000000000000000000000000000000000000000000006"));
}
Also used : Account(org.hyperledger.besu.evm.account.Account) KeyPair(org.hyperledger.besu.crypto.KeyPair) Transaction(org.hyperledger.besu.ethereum.core.Transaction) MutableWorldState(org.hyperledger.besu.ethereum.core.MutableWorldState) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) TraceOptions(org.hyperledger.besu.ethereum.debug.TraceOptions) BlockHeader(org.hyperledger.besu.ethereum.core.BlockHeader) TraceFrame(org.hyperledger.besu.ethereum.debug.TraceFrame) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult) Test(org.junit.jupiter.api.Test)

Example 9 with WorldUpdater

use of org.hyperledger.besu.evm.worldstate.WorldUpdater in project besu by hyperledger.

the class AbstractBlockCreator method rewardBeneficiary.

/* Copied from BlockProcessor (with modifications). */
boolean rewardBeneficiary(final MutableWorldState worldState, final ProcessableBlockHeader header, final List<BlockHeader> ommers, final Address miningBeneficiary, final Wei blockReward, final boolean skipZeroBlockRewards) {
    // TODO(tmm): Added to make this work, should come from blockProcessor.
    final int MAX_GENERATION = 6;
    if (skipZeroBlockRewards && blockReward.isZero()) {
        return true;
    }
    final Wei coinbaseReward = protocolSpec.getBlockProcessor().getCoinbaseReward(blockReward, header.getNumber(), ommers.size());
    final WorldUpdater updater = worldState.updater();
    final EvmAccount beneficiary = updater.getOrCreate(miningBeneficiary);
    beneficiary.getMutable().incrementBalance(coinbaseReward);
    for (final BlockHeader ommerHeader : ommers) {
        if (ommerHeader.getNumber() - header.getNumber() > MAX_GENERATION) {
            LOG.trace("Block processing error: ommer block number {} more than {} generations current block number {}", ommerHeader.getNumber(), MAX_GENERATION, header.getNumber());
            return false;
        }
        final EvmAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase());
        final Wei ommerReward = protocolSpec.getBlockProcessor().getOmmerReward(blockReward, header.getNumber(), ommerHeader.getNumber());
        ommerCoinbase.getMutable().incrementBalance(ommerReward);
    }
    updater.commit();
    return true;
}
Also used : EvmAccount(org.hyperledger.besu.evm.account.EvmAccount) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) Wei(org.hyperledger.besu.datatypes.Wei) SealableBlockHeader(org.hyperledger.besu.ethereum.core.SealableBlockHeader) ProcessableBlockHeader(org.hyperledger.besu.ethereum.core.ProcessableBlockHeader) BlockHeader(org.hyperledger.besu.ethereum.core.BlockHeader)

Example 10 with WorldUpdater

use of org.hyperledger.besu.evm.worldstate.WorldUpdater in project besu by hyperledger.

the class BlockTransactionSelector method evaluateTransaction.

/*
   * Passed into the PendingTransactions, and is called on each transaction until sufficient
   * transactions are found which fill a block worth of gas.
   *
   * This function will continue to be called until the block under construction is suitably
   * full (in terms of gasLimit) and the provided transaction's gasLimit does not fit within
   * the space remaining in the block.
   *
   */
private TransactionSelectionResult evaluateTransaction(final Transaction transaction) {
    if (isCancelled.get()) {
        throw new CancellationException("Cancelled during transaction selection.");
    }
    if (transactionTooLargeForBlock(transaction)) {
        LOG.trace("{} too large to select for block creation", transaction);
        if (blockOccupancyAboveThreshold()) {
            return TransactionSelectionResult.COMPLETE_OPERATION;
        } else {
            return TransactionSelectionResult.CONTINUE;
        }
    }
    // If the gas price specified by the transaction is less than this node is willing to accept,
    // do not include it in the block.
    final Wei actualMinTransactionGasPriceInBlock = feeMarket.getTransactionPriceCalculator().price(transaction, processableBlockHeader.getBaseFee());
    if (minTransactionGasPrice.compareTo(actualMinTransactionGasPriceInBlock) > 0) {
        LOG.warn("Gas fee of {} lower than configured minimum {}, deleting", transaction, minTransactionGasPrice);
        return TransactionSelectionResult.DELETE_TRANSACTION_AND_CONTINUE;
    }
    final WorldUpdater worldStateUpdater = worldState.updater();
    final BlockHashLookup blockHashLookup = new BlockHashLookup(processableBlockHeader, blockchain);
    final boolean isGoQuorumPrivateTransaction = transaction.isGoQuorumPrivateTransaction(transactionProcessor.getTransactionValidator().getGoQuorumCompatibilityMode());
    TransactionProcessingResult effectiveResult;
    if (isGoQuorumPrivateTransaction) {
        final ValidationResult<TransactionInvalidReason> validationResult = validateTransaction(processableBlockHeader, transaction, worldStateUpdater);
        if (!validationResult.isValid()) {
            LOG.warn("Invalid transaction: {}. Block {} Transaction {}", validationResult.getErrorMessage(), processableBlockHeader.getParentHash().toHexString(), transaction.getHash().toHexString());
            return transactionSelectionResultForInvalidResult(validationResult);
        } else {
            // valid GoQuorum private tx, we need to hand craft the receipt and increment the nonce
            effectiveResult = publicResultForWhenWeHaveAPrivateTransaction(transaction);
            worldStateUpdater.getOrCreate(transaction.getSender()).getMutable().incrementNonce();
        }
    } else {
        effectiveResult = transactionProcessor.processTransaction(blockchain, worldStateUpdater, processableBlockHeader, transaction, miningBeneficiary, blockHashLookup, false, TransactionValidationParams.mining());
    }
    if (!effectiveResult.isInvalid()) {
        worldStateUpdater.commit();
        LOG.trace("Selected {} for block creation", transaction);
        updateTransactionResultTracking(transaction, effectiveResult);
    } else {
        return transactionSelectionResultForInvalidResult(effectiveResult.getValidationResult());
    }
    return TransactionSelectionResult.CONTINUE;
}
Also used : BlockHashLookup(org.hyperledger.besu.ethereum.vm.BlockHashLookup) CancellationException(java.util.concurrent.CancellationException) TransactionInvalidReason(org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) Wei(org.hyperledger.besu.datatypes.Wei) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult)

Aggregations

WorldUpdater (org.hyperledger.besu.evm.worldstate.WorldUpdater)72 MutableWorldState (org.hyperledger.besu.ethereum.core.MutableWorldState)37 MutableAccount (org.hyperledger.besu.evm.account.MutableAccount)33 Test (org.junit.Test)33 TransactionProcessingResult (org.hyperledger.besu.ethereum.processing.TransactionProcessingResult)16 Wei (org.hyperledger.besu.datatypes.Wei)14 BlockHeader (org.hyperledger.besu.ethereum.core.BlockHeader)14 Address (org.hyperledger.besu.datatypes.Address)13 ArrayList (java.util.ArrayList)12 Hash (org.hyperledger.besu.datatypes.Hash)12 Transaction (org.hyperledger.besu.ethereum.core.Transaction)12 MessageFrame (org.hyperledger.besu.evm.frame.MessageFrame)11 Bytes (org.apache.tuweni.bytes.Bytes)9 Bytes32 (org.apache.tuweni.bytes.Bytes32)9 BlockHashLookup (org.hyperledger.besu.ethereum.vm.BlockHashLookup)9 UInt256 (org.apache.tuweni.units.bigints.UInt256)8 ProcessableBlockHeader (org.hyperledger.besu.ethereum.core.ProcessableBlockHeader)8 Code (org.hyperledger.besu.evm.Code)8 Account (org.hyperledger.besu.evm.account.Account)8 Map (java.util.Map)6