Skip to content

Commit

Permalink
Modify Gas estimation logic for GoQuorum mode (hyperledger#2282)
Browse files Browse the repository at this point in the history
* modify tx simulator for possibly private tx

Signed-off-by: Sally MacFarlane <sally.macfarlane@consensys.net>
  • Loading branch information
macfarla authored May 18, 2021
1 parent fff119b commit 3627662
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import static org.hyperledger.besu.ethereum.goquorum.GoQuorumPrivateStateUtil.getPrivateWorldStateAtBlock;

import org.hyperledger.besu.config.GoQuorumOptions;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
Expand Down Expand Up @@ -71,6 +72,11 @@ public class TransactionSimulator {
private static final Address DEFAULT_FROM =
Address.fromHexString("0x0000000000000000000000000000000000000000");

// Hex-encoded 64 byte array of "17" values
private static final Bytes MAX_PRIVATE_INTRINSIC_DATA_HEX =
Bytes.fromHexString(
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");

private final Blockchain blockchain;
private final WorldStateArchive worldStateArchive;
private final ProtocolSchedule protocolSchedule;
Expand Down Expand Up @@ -157,12 +163,25 @@ public Optional<TransactionSimulatorResult> process(
callParams.getGasLimit() >= 0 ? callParams.getGasLimit() : header.getGasLimit();
final Wei gasPrice = callParams.getGasPrice() != null ? callParams.getGasPrice() : Wei.ZERO;
final Wei value = callParams.getValue() != null ? callParams.getValue() : Wei.ZERO;
final Bytes payload = callParams.getPayload() != null ? callParams.getPayload() : Bytes.EMPTY;

// If GoQuorum privacy enabled, and value = zero, do simulation with max non-zero bytes.
// It is possible to have a data field that has a lower intrinsic value than the PTM hash
// so this checks the tx as if we were to place a PTM hash (with all non-zero values).
// This means a potential over-estimate of gas, rather than the exact cost to run right now.
final Bytes payload =
GoQuorumOptions.goQuorumCompatibilityMode && value.isZero()
? MAX_PRIVATE_INTRINSIC_DATA_HEX
: (callParams.getPayload() != null ? callParams.getPayload() : Bytes.EMPTY);

if (transactionValidationParams.isAllowExceedingBalance()) {
updater.getOrCreate(senderAddress).getMutable().setBalance(Wei.of(UInt256.MAX_VALUE));
}

final ProtocolSpec protocolSpec = protocolSchedule.getByBlockNumber(header.getNumber());

final MainnetTransactionProcessor transactionProcessor =
protocolSchedule.getByBlockNumber(header.getNumber()).getTransactionProcessor();

final Transaction.Builder transactionBuilder =
Transaction.builder()
.type(TransactionType.FRONTIER)
Expand All @@ -179,10 +198,6 @@ public Optional<TransactionSimulatorResult> process(

final Transaction transaction = transactionBuilder.build();

final ProtocolSpec protocolSpec = protocolSchedule.getByBlockNumber(header.getNumber());

final MainnetTransactionProcessor transactionProcessor =
protocolSchedule.getByBlockNumber(header.getNumber()).getTransactionProcessor();
final TransactionProcessingResult result =
transactionProcessor.processTransaction(
blockchain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;

import org.hyperledger.besu.config.GoQuorumOptions;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
Expand Down Expand Up @@ -53,6 +54,7 @@
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -75,6 +77,11 @@ public class TransactionSimulatorTest {
private static final Hash DEFAULT_BLOCK_HEADER_HASH =
Hash.fromHexString("0x0000000000000000000000000000000000000000000000000000000000000001");

// Hex-encoded 64 byte array of "17" values
private static final Bytes MAX_PRIVATE_INTRINSIC_DATA_HEX =
Bytes.fromHexString(
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");

private TransactionSimulator transactionSimulator;

@Mock private Blockchain blockchain;
Expand All @@ -91,6 +98,12 @@ public void setUp() {
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule);
}

@After
public void tearDown() {
GoQuorumOptions.goQuorumCompatibilityMode =
GoQuorumOptions.GOQUORUM_COMPATIBILITY_MODE_DEFAULT_VALUE;
}

@Test
public void shouldReturnEmptyWhenBlockDoesNotExist() {
when(blockchain.getBlockHeader(eq(1L))).thenReturn(Optional.empty());
Expand Down Expand Up @@ -128,6 +141,35 @@ public void shouldReturnSuccessfulResultWhenProcessingIsSuccessful() {
verifyTransactionWasProcessed(expectedTransaction);
}

@Test
public void shouldReturnSuccessfulResultWhenProcessingPotentiallyPrivateTxIsSuccessful() {
final CallParameter callParameter = legacyTransactionCallParameter();

GoQuorumOptions.goQuorumCompatibilityMode = true;

mockBlockchainForBlockHeader(Hash.ZERO, 1L);
mockWorldStateForAccount(Hash.ZERO, callParameter.getFrom(), 1L);

final Transaction expectedTransaction =
Transaction.builder()
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
.payload(MAX_PRIVATE_INTRINSIC_DATA_HEX)
.signature(FAKE_SIGNATURE)
.build();
mockProcessorStatusForTransaction(1L, expectedTransaction, Status.SUCCESSFUL);

final Optional<TransactionSimulatorResult> result =
transactionSimulator.process(callParameter, 1L);

assertThat(result.get().isSuccessful()).isTrue();
verifyTransactionWasProcessed(expectedTransaction);
}

@Test
public void shouldIncreaseBalanceAccountWhenExceedingBalanceAllowed() {
final CallParameter callParameter = legacyTransactionCallParameter();
Expand Down

0 comments on commit 3627662

Please sign in to comment.