From c40a6fcf74c8798c3f5855d87679f62238077f74 Mon Sep 17 00:00:00 2001 From: Taccat Isid Date: Thu, 14 Oct 2021 09:52:22 +1300 Subject: [PATCH] protect access to GoQuorum flag by getter and write once setter Signed-off-by: Taccat Isid --- .../org/hyperledger/besu/cli/BesuCommand.java | 12 ++++++--- .../besu/cli/CommandTestAbstract.java | 8 ++++++ .../besu/config/GoQuorumOptions.java | 27 ++++++++++++++++--- .../api/graphql/GraphQLDataFetchers.java | 2 +- .../pojoadapter/TransactionAdapter.java | 4 +-- .../jsonrpc/internal/methods/EthGetCode.java | 2 +- .../GoQuorumSendRawPrivateTransaction.java | 19 ++++++++++++- .../api/util/DomainObjectDecodeUtils.java | 2 +- ...GoQuorumSendRawPrivateTransactionTest.java | 8 +++--- .../core/encoding/TransactionDecoder.java | 2 +- .../core/encoding/TransactionDecoderTest.java | 8 +++--- 11 files changed, 71 insertions(+), 23 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 4dd8f06bdc31..049698307a70 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1119,7 +1119,7 @@ void setBannedNodeIds(final List values) { private Vertx vertx; private EnodeDnsConfiguration enodeDnsConfiguration; private KeyValueStorageProvider keyValueStorageProvider; - private Boolean isGoQuorumCompatibilityMode = false; + protected Boolean isGoQuorumCompatibilityMode = false; public BesuCommand( final Logger logger, @@ -1206,9 +1206,7 @@ public void run() { if (genesisFile != null) { genesisConfigOptions = readGenesisConfigOptions(); if (genesisConfigOptions.isQuorum()) { - // this static flag is read by the RLP decoder - GoQuorumOptions.goQuorumCompatibilityMode = true; - isGoQuorumCompatibilityMode = true; + enableGoQuorumCompatibilityMode(); } } @@ -2736,4 +2734,10 @@ private Optional getEcCurveFromGenesisFile() { } return genesisConfigOptions.getEcCurve(); } + + protected void enableGoQuorumCompatibilityMode() { + // this static flag is read by the RLP decoder + GoQuorumOptions.setGoQuorumCompatibilityMode(true); + isGoQuorumCompatibilityMode = true; + } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index e1a48ea8f20a..4709eefb1631 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -427,6 +427,14 @@ KeyPair loadKeyPair() { return keyPair; } + @Override + protected void enableGoQuorumCompatibilityMode() { + // We do *not* set the static GoQuorumOptions for test runs as + // these are only allowed to be set once during the program + // runtime. + isGoQuorumCompatibilityMode = true; + } + public CommandSpec getSpec() { return spec; } diff --git a/config/src/main/java/org/hyperledger/besu/config/GoQuorumOptions.java b/config/src/main/java/org/hyperledger/besu/config/GoQuorumOptions.java index 194346188257..0c688675d086 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GoQuorumOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/GoQuorumOptions.java @@ -19,8 +19,29 @@ * with MainNet. */ public class GoQuorumOptions { - // To make it easier for tests to reset the value to default - public static final boolean GOQUORUM_COMPATIBILITY_MODE_DEFAULT_VALUE = false; + private static final boolean GOQUORUM_COMPATIBILITY_MODE_DEFAULT_VALUE = false; - public static boolean goQuorumCompatibilityMode = GOQUORUM_COMPATIBILITY_MODE_DEFAULT_VALUE; + private static Boolean goQuorumCompatibilityMode; + + public static void setGoQuorumCompatibilityMode(final boolean goQuorumCompatibilityMode) { + if (GoQuorumOptions.goQuorumCompatibilityMode == null) { + GoQuorumOptions.goQuorumCompatibilityMode = goQuorumCompatibilityMode; + } else { + throw new Error("goQuorumCompatibilityMode can not be changed after having been assigned"); + } + } + + public static boolean getGoQuorumCompatibilityMode() { + if (goQuorumCompatibilityMode == null) { + // If the quorum mode has never been set, we default it + // here. This allows running individual unit tests that + // query the quorum mode without having to include a + // setGoQuorumCompatibilityMode call in their setup + // procedure. For production use, this case is not + // triggered as we set the quorum mode very early during + // startup. + goQuorumCompatibilityMode = GOQUORUM_COMPATIBILITY_MODE_DEFAULT_VALUE; + } + return goQuorumCompatibilityMode; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java index 60c2f02adb93..5beecb0dd62f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java @@ -284,7 +284,7 @@ private TransactionAdapter getTransactionAdapter( final TransactionWithMetadata transactionWithMetadata) { final Transaction transaction = transactionWithMetadata.getTransaction(); final boolean isGoQuorumPrivateTransaction = - transaction.isGoQuorumPrivateTransaction(GoQuorumOptions.goQuorumCompatibilityMode); + transaction.isGoQuorumPrivateTransaction(GoQuorumOptions.getGoQuorumCompatibilityMode()); return isGoQuorumPrivateTransaction && goQuorumPrivacyParameters.isPresent() ? updatePrivatePayload(transaction) : new TransactionAdapter(transactionWithMetadata); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java index 2c3b684ca813..64285264a9f5 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java @@ -190,12 +190,12 @@ public List getLogs(final DataFetchingEnvironment environment) { public boolean getIsPrivate() { return transactionWithMetadata .getTransaction() - .isGoQuorumPrivateTransaction(GoQuorumOptions.goQuorumCompatibilityMode); + .isGoQuorumPrivateTransaction(GoQuorumOptions.getGoQuorumCompatibilityMode()); } public Optional getPrivateInputData() { final Transaction transaction = transactionWithMetadata.getTransaction(); - if (transaction.isGoQuorumPrivateTransaction(GoQuorumOptions.goQuorumCompatibilityMode)) { + if (transaction.isGoQuorumPrivateTransaction(GoQuorumOptions.getGoQuorumCompatibilityMode())) { return Optional.ofNullable(transaction.getPayload()); } return Optional.of(Bytes.EMPTY); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java index 065d30254a37..ebe0ba19db65 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java @@ -64,7 +64,7 @@ protected BlockParameterOrBlockHash blockParameterOrBlockHash( @Override protected String resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) { final Address address = request.getRequiredParameter(0, Address.class); - final boolean isGoQuorumCompatibilityMode = GoQuorumOptions.goQuorumCompatibilityMode; + final boolean isGoQuorumCompatibilityMode = GoQuorumOptions.getGoQuorumCompatibilityMode(); if (isGoQuorumCompatibilityMode && privacyParameters.isPresent()) { // get from private state if we can final Optional blockHeader = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/GoQuorumSendRawPrivateTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/GoQuorumSendRawPrivateTransaction.java index 65af69998a7e..9d2992e6c610 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/GoQuorumSendRawPrivateTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/GoQuorumSendRawPrivateTransaction.java @@ -19,6 +19,7 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter.convertTransactionInvalidReason; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.DECODE_ERROR; +import org.hyperledger.besu.config.GoQuorumOptions; import org.hyperledger.besu.enclave.GoQuorumEnclave; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; @@ -30,6 +31,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.privacy.GoQuorumSendRawTxArgs; import org.hyperledger.besu.ethereum.rlp.RLP; @@ -47,14 +49,28 @@ public class GoQuorumSendRawPrivateTransaction implements JsonRpcMethod { final TransactionPool transactionPool; private final PrivacyIdProvider privacyIdProvider; private final GoQuorumEnclave enclave; + private final boolean goQuorumCompatibilityMode; public GoQuorumSendRawPrivateTransaction( final GoQuorumEnclave enclave, final TransactionPool transactionPool, final PrivacyIdProvider privacyIdProvider) { + this( + enclave, + transactionPool, + privacyIdProvider, + GoQuorumOptions.getGoQuorumCompatibilityMode()); + } + + public GoQuorumSendRawPrivateTransaction( + final GoQuorumEnclave enclave, + final TransactionPool transactionPool, + final PrivacyIdProvider privacyIdProvider, + final boolean goQuorumCompatibilityMode) { this.enclave = enclave; this.transactionPool = transactionPool; this.privacyIdProvider = privacyIdProvider; + this.goQuorumCompatibilityMode = goQuorumCompatibilityMode; } @Override @@ -72,7 +88,8 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { try { final Transaction transaction = - Transaction.readFrom(RLP.input(Bytes.fromHexString(rawPrivateTransaction))); + TransactionDecoder.decodeForWire( + RLP.input(Bytes.fromHexString(rawPrivateTransaction)), goQuorumCompatibilityMode); checkAndHandlePrivateTransaction(transaction, rawTxArgs, requestContext); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java index 6dc45a980be6..a51dc2497e8c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java @@ -31,7 +31,7 @@ public static Transaction decodeRawTransaction(final String rawTransaction) throws InvalidJsonRpcRequestException { try { Bytes txnBytes = Bytes.fromHexString(rawTransaction); - final boolean isGoQuorumCompatibilityMode = GoQuorumOptions.goQuorumCompatibilityMode; + final boolean isGoQuorumCompatibilityMode = GoQuorumOptions.getGoQuorumCompatibilityMode(); return TransactionDecoder.decodeOpaqueBytes(txnBytes, isGoQuorumCompatibilityMode); } catch (final IllegalArgumentException | RLPException e) { LOG.debug(e); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/goquorum/GoQuorumSendRawPrivateTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/goquorum/GoQuorumSendRawPrivateTransactionTest.java index 43e14a65c4d3..ea62d042f2b1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/goquorum/GoQuorumSendRawPrivateTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/goquorum/GoQuorumSendRawPrivateTransactionTest.java @@ -21,7 +21,6 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; -import org.hyperledger.besu.config.GoQuorumOptions; import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; @@ -80,7 +79,10 @@ public class GoQuorumSendRawPrivateTransactionTest { @Before public void before() { - method = new GoQuorumSendRawPrivateTransaction(enclave, transactionPool, privacyIdProvider); + boolean goQuorumCompatibilityMode = true; + method = + new GoQuorumSendRawPrivateTransaction( + enclave, transactionPool, privacyIdProvider, goQuorumCompatibilityMode); } @Test @@ -126,8 +128,6 @@ public void requestHasNullArrayParameter() { @Test public void validTransactionIsSentToTransactionPool() { - GoQuorumOptions.goQuorumCompatibilityMode = true; - when(enclave.sendSignedTransaction(any(), any())).thenReturn(null); when(transactionPool.addLocalTransaction(any(Transaction.class))) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java index 38b17b0ca1bf..5f1831e270bb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java @@ -62,7 +62,7 @@ interface Decoder { Suppliers.memoize(SignatureAlgorithmFactory::getInstance); public static Transaction decodeForWire(final RLPInput rlpInput) { - return decodeForWire(rlpInput, GoQuorumOptions.goQuorumCompatibilityMode); + return decodeForWire(rlpInput, GoQuorumOptions.getGoQuorumCompatibilityMode()); } public static Transaction decodeForWire( diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoderTest.java index 94ebd6c06b25..9645379864d7 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoderTest.java @@ -17,7 +17,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import org.hyperledger.besu.config.GoQuorumOptions; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; @@ -41,16 +40,15 @@ public class TransactionDecoderTest { @Test public void decodeGoQuorumPrivateTransactionRlp() { - GoQuorumOptions.goQuorumCompatibilityMode = true; + boolean goQuorumCompatibilityMode = true; RLPInput input = RLP.input(Bytes.fromHexString(GOQUORUM_PRIVATE_TX_RLP)); - final Transaction transaction = TransactionDecoder.decodeForWire(input); + final Transaction transaction = + TransactionDecoder.decodeForWire(input, goQuorumCompatibilityMode); assertThat(transaction).isNotNull(); assertThat(transaction.getV()).isEqualTo(38); assertThat(transaction.getSender()) .isEqualByComparingTo(Address.fromHexString("0xed9d02e382b34818e88b88a309c7fe71e65f419d")); - GoQuorumOptions.goQuorumCompatibilityMode = - GoQuorumOptions.GOQUORUM_COMPATIBILITY_MODE_DEFAULT_VALUE; } @Test