Tracing Fixes - Mark Transaction Boundaries for Standard Tracing and CallOperation Gas Costs (#2120)

Signed-off-by: Ratan Rai Sur <ratan.r.sur@gmail.com>
pull/2127/head
Ratan (Rai) Sur 4 years ago committed by GitHub
parent dd0e8b0bcf
commit ded6faeacd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java
  2. 10
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java
  3. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BerlinGasCalculator.java
  4. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/FrontierGasCalculator.java
  5. 1
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
  6. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TangerineWhistleGasCalculator.java
  7. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/GasCalculator.java
  8. 29
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/StandardJsonTracer.java
  9. 9
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldState.java

@ -18,6 +18,7 @@ import static java.util.function.Predicate.isEqual;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.AbstractWorldUpdater;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.Transaction;
@ -97,9 +98,10 @@ public class TransactionTracer {
.performActionWithBlock(
blockHash,
(body, header, blockchain, worldState, transactionProcessor) -> {
final WorldUpdater worldUpdater = worldState.updater();
WorldUpdater stackedUpdater = worldState.updater().updater();
final List<String> traces = new ArrayList<>();
for (int i = 0; i < body.getTransactions().size(); i++) {
((AbstractWorldUpdater.StackedUpdater) stackedUpdater).markTransactionBoundary();
final Transaction transaction = body.getTransactions().get(i);
if (selectedHash.isEmpty()
|| selectedHash.filter(isEqual(transaction.getHash())).isPresent()) {
@ -110,7 +112,7 @@ public class TransactionTracer {
processTransaction(
header,
blockchain,
worldUpdater,
stackedUpdater,
transaction,
transactionProcessor,
new StandardJsonTracer(out, showMemory));
@ -126,7 +128,7 @@ public class TransactionTracer {
processTransaction(
header,
blockchain,
worldUpdater,
stackedUpdater,
transaction,
transactionProcessor,
OperationTracer.NO_TRACING);

@ -23,6 +23,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.ImmutableTransactionTraceParams;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.AbstractWorldUpdater;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader;
@ -226,6 +227,8 @@ public class TransactionTracerTest {
when(blockBody.getTransactions()).thenReturn(transactions);
when(blockchain.getBlockBody(blockHash)).thenReturn(Optional.of(blockBody));
final WorldUpdater updater = mock(WorldUpdater.class);
when(mutableWorldState.updater()).thenReturn(updater);
final List<String> transactionTraces =
transactionTracer.traceTransactionToFile(
blockHash,
@ -251,11 +254,14 @@ public class TransactionTracerTest {
when(blockBody.getTransactions()).thenReturn(Collections.singletonList(transaction));
when(blockchain.getBlockBody(blockHash)).thenReturn(Optional.of(blockBody));
final WorldUpdater updater = mutableWorldState.updater();
final WorldUpdater updater = mock(WorldUpdater.class);
when(mutableWorldState.updater()).thenReturn(updater);
final WorldUpdater stackedUpdater = mock(AbstractWorldUpdater.StackedUpdater.class);
when(updater.updater()).thenReturn(stackedUpdater);
final Address coinbase = blockHeader.getCoinbase();
when(transactionProcessor.processTransaction(
eq(blockchain),
eq(updater),
eq(stackedUpdater),
eq(blockHeader),
eq(transaction),
eq(coinbase),

@ -136,7 +136,7 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
}
@Override
protected Gas callOperationBaseGasCost() {
public Gas callOperationBaseGasCost() {
return Gas.ZERO;
}

@ -212,7 +212,8 @@ public class FrontierGasCalculator implements GasCalculator {
*
* @return the base gas cost to execute a call operation
*/
protected Gas callOperationBaseGasCost() {
@Override
public Gas callOperationBaseGasCost() {
return CALL_OPERATION_BASE_GAS_COST;
}

@ -252,7 +252,6 @@ public class MainnetTransactionProcessor {
final PrivateMetadataUpdater privateMetadataUpdater) {
try {
LOG.trace("Starting execution of {}", transaction);
ValidationResult<TransactionInvalidReason> validationResult =
transactionValidator.validate(transaction, blockHeader.getBaseFee());
// Make sure the transaction is intrinsically valid before trying to

@ -47,7 +47,7 @@ public class TangerineWhistleGasCalculator extends HomesteadGasCalculator {
}
@Override
protected Gas callOperationBaseGasCost() {
public Gas callOperationBaseGasCost() {
return CALL_OPERATION_BASE_GAS_COST;
}

@ -155,6 +155,13 @@ public interface GasCalculator {
// Call/Create Operation Calculations
/**
* Returns the base gas cost to execute a call operation.
*
* @return the base gas cost to execute a call operation
*/
Gas callOperationBaseGasCost();
/**
* Returns the gas cost for one of the various CALL operations.
*

@ -33,6 +33,8 @@ import org.apache.tuweni.units.bigints.UInt256;
public class StandardJsonTracer implements OperationTracer {
private static final int EIP_150_DIVISOR = 64;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final PrintStream out;
@ -86,8 +88,19 @@ public class StandardJsonTracer implements OperationTracer {
final OperationResult executeResult = executeOperation.execute();
traceLine.put("refund", messageFrame.getGasRefund().toLong());
traceLine.put(
"gasCost", executeResult.getGasCost().map(gas -> shortNumber(gas.asUInt256())).orElse(""));
if (AbstractCallOperation.class.isAssignableFrom(
messageFrame.getCurrentOperation().getClass())) {
final AbstractCallOperation callOperation =
(AbstractCallOperation) messageFrame.getCurrentOperation();
traceLine.put(
"gasCost", shortNumber((computeCallGas(callOperation, messageFrame).asUInt256())));
} else {
traceLine.put(
"gasCost",
executeResult.getGasCost().map(gas -> shortNumber(gas.asUInt256())).orElse(""));
}
if (showMemory) {
traceLine.put(
"memory",
@ -113,6 +126,18 @@ public class StandardJsonTracer implements OperationTracer {
out.println(traceLine.toString());
}
private Gas computeCallGas(
final AbstractCallOperation callOperation, final MessageFrame messageFrame) {
final GasCalculator gasCalculator = callOperation.gasCalculator();
// as part of EIP 150 the returned costGas is gas - base * 63 / 64.
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
final Gas callCost = callOperation.gas(messageFrame);
final Gas gasAvailable = callCost.minus(messageFrame.getGasCost().orElse(Gas.ZERO));
final Gas gas = gasAvailable.minus(gasAvailable.dividedBy(EIP_150_DIVISOR));
final Gas baseCost = gasCalculator.callOperationBaseGasCost();
return ((gas.compareTo(callCost) < 0) ? gas : callCost).plus(baseCost);
}
@Override
public void tracePrecompileCall(
final MessageFrame frame, final Gas gasRequirement, final Bytes output) {}

@ -310,11 +310,10 @@ public class DefaultMutableWorldState implements MutableWorldState {
@Override
public UInt256 getStorageValue(final UInt256 key) {
final Optional<Bytes> val = storageTrie().get(Hash.hash(key.toBytes()));
if (val.isEmpty()) {
return UInt256.ZERO;
}
return convertToUInt256(val.get());
return storageTrie()
.get(Hash.hash(key.toBytes()))
.map(DefaultMutableWorldState::convertToUInt256)
.orElse(UInt256.ZERO);
}
@Override

Loading…
Cancel
Save