Skip to content

Commit

Permalink
Tracing private transactions feature (#6161)
Browse files Browse the repository at this point in the history
* add private tx tracing feature

Signed-off-by: Nischal Sharma <nischal@web3labs.com>
Signed-off-by: Stefan Pingel <16143240+pinges@users.noreply.github.com>
Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
  • Loading branch information
3 people authored Aug 13, 2024
1 parent 290f21c commit 50f8add
Show file tree
Hide file tree
Showing 24 changed files with 1,966 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
### Additions and Improvements
- Expose set finalized/safe block in plugin api BlockchainService. These method can be used by plugins to set finalized/safe block for a PoA network (such as QBFT, IBFT and Clique).[#7382](https://github.com/hyperledger/besu/pull/7382)
- In process RPC service [#7395](https://github.com/hyperledger/besu/pull/7395)
- Added support for tracing private transactions using `priv_traceTransaction` API. [#6161](https://github.com/hyperledger/besu/pull/6161)
- Wrap WorldUpdater into EVMWorldupdater [#7434](https://github.com/hyperledger/besu/pull/7434)


### Bug fixes
- Correct entrypoint in Docker evmtool [#7430](https://github.com/hyperledger/besu/pull/7430)
- Fix protocol schedule check for devnets [#7429](https://github.com/hyperledger/besu/pull/7429)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction;

import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.privacy.PrivacyGroupUtil;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.condition.PrivGetTransactionReceiptTransaction;
Expand All @@ -25,6 +26,7 @@
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivGetCodeTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivGetLogsTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivGetTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivTraceTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.filter.PrivGetFilterChangesTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.filter.PrivGetFilterLogsTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.filter.PrivNewFilterTransaction;
Expand Down Expand Up @@ -115,6 +117,11 @@ public PrivGetLogsTransaction privGetLogs(
return new PrivGetLogsTransaction(privacyGroupId, filterParameter);
}

public PrivTraceTransaction privTraceTransaction(
final String privacyGroupId, final Hash transactionHash) {
return new PrivTraceTransaction(privacyGroupId, transactionHash);
}

public RemoveFromFlexiblePrivacyGroupTransaction removeFromPrivacyGroup(
final String privacyGroupId,
final String remover,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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.tests.acceptance.dsl.transaction.privacy;

import static org.assertj.core.api.Assertions.assertThat;

import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;

import java.io.IOException;

public class PrivTraceTransaction implements Transaction<String> {

private final String privacyGroupId;
private final Hash transactionHash;

public PrivTraceTransaction(final String privacyGroupId, final Hash transactionHash) {
this.privacyGroupId = privacyGroupId;
this.transactionHash = transactionHash;
}

@Override
public String execute(final NodeRequests node) {
try {
final PrivacyRequestFactory.PrivTraceTransaction response =
node.privacy().privTraceTransaction(privacyGroupId, transactionHash).send();

assertThat(response).as("check response is not null").isNotNull();
assertThat(response.getResult()).as("check result in response is not null").isNotNull();

return response.getResult();
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ public static class GetPrivacyPrecompileAddressResponse extends Response<Address
public static class GetPrivateTransactionResponse
extends Response<PrivateTransactionGroupResponse> {}

public static class PrivTraceTransaction extends Response<String> {}

public static class CreatePrivacyGroupResponse extends Response<String> {}

public static class DeletePrivacyGroupResponse extends Response<String> {}
Expand Down Expand Up @@ -455,6 +457,16 @@ public Request<?, EthLog> privGetLogs(
"priv_getLogs", Arrays.asList(privacyGroupId, filterParameter), web3jService, EthLog.class);
}

public Request<?, PrivTraceTransaction> privTraceTransaction(
final String privacyGroupId, final Hash transactionHash) {

return new Request<>(
"priv_traceTransaction",
Arrays.asList(privacyGroupId, transactionHash),
web3jService,
PrivTraceTransaction.class);
}

public Request<?, EthFilter> privNewFilter(
final String privacyGroupId, final LogFilterJsonParameter filterParameter) {
return new Request<>(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* 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.tests.acceptance.privacy;

import static org.assertj.core.api.Assertions.assertThat;
import static org.web3j.utils.Restriction.UNRESTRICTED;

import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
import org.hyperledger.besu.tests.web3j.generated.SimpleStorage;
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
import org.hyperledger.enclave.testutil.EnclaveType;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Optional;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.web3j.utils.Restriction;

public class PrivTraceTransactionAcceptanceTest extends ParameterizedEnclaveTestBase {

private final PrivacyNode node;

private final PrivacyNode wrongNode;

public PrivTraceTransactionAcceptanceTest(
final Restriction restriction,
final EnclaveType enclaveType,
final EnclaveEncryptorType enclaveEncryptorType)
throws IOException {

super(restriction, enclaveType, enclaveEncryptorType);

node =
privacyBesu.createPrivateTransactionEnabledMinerNode(
restriction + "-node",
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
enclaveType,
Optional.empty(),
false,
false,
restriction == UNRESTRICTED);

wrongNode =
privacyBesu.createPrivateTransactionEnabledMinerNode(
restriction + "-node",
PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType),
enclaveType,
Optional.empty(),
false,
false,
restriction == UNRESTRICTED);

privacyCluster.start(node);
privacyCluster.start(wrongNode);
}

@Test
public void getTransactionTrace() throws JsonProcessingException {
final String privacyGroupId = createPrivacyGroup();
final SimpleStorage simpleStorageContract = deploySimpleStorageContract(privacyGroupId);

Hash transactionHash =
Hash.fromHexString(doTransaction(privacyGroupId, simpleStorageContract, 0));

final String result =
node.execute(privacyTransactions.privTraceTransaction(privacyGroupId, transactionHash));

assertThat(result).isNotNull();
ObjectMapper mapper = new ObjectMapper();

JsonNode rootNode = mapper.readTree(result);
JsonNode resultNode = rootNode.get("result");

assertThat(resultNode).isNotNull();
assertThat(resultNode.isArray()).isTrue();
assertThat(resultNode.size()).isGreaterThan(0);

JsonNode trace = resultNode.get(0);
assertThat(trace.get("action").get("callType").asText()).isEqualTo("call");
assertThat(trace.get("action").get("from").asText()).isEqualTo(node.getAddress().toString());
assertThat(trace.get("action").get("input").asText()).startsWith("0x60fe47b1");
assertThat(trace.get("action").get("to").asText())
.isEqualTo(simpleStorageContract.getContractAddress());
assertThat(trace.get("action").get("value").asText()).isEqualTo("0x0");
assertThat(trace.get("blockHash").asText()).isNotEmpty();
assertThat(trace.get("blockNumber").asInt()).isGreaterThan(0);
assertThat(trace.get("transactionHash").asText()).isEqualTo(transactionHash.toString());
assertThat(trace.get("type").asText()).isEqualTo("call");

final String wrongPrivacyGroupId = createWrongPrivacyGroup();

final String resultEmpty =
wrongNode.execute(
privacyTransactions.privTraceTransaction(wrongPrivacyGroupId, transactionHash));

ObjectMapper mapperEmpty = new ObjectMapper();

JsonNode rootNodeEmpty = mapperEmpty.readTree(resultEmpty);
JsonNode resultNodeEmpty = rootNodeEmpty.get("result");

assertThat(resultNodeEmpty).isNotNull();
assertThat(resultNodeEmpty.isArray()).isTrue();
assertThat(resultNodeEmpty.isEmpty()).isTrue();

final String resultWrongHash =
wrongNode.execute(privacyTransactions.privTraceTransaction(privacyGroupId, Hash.EMPTY));

ObjectMapper mapperWrongHash = new ObjectMapper();

JsonNode rootNodeWrongHash = mapperWrongHash.readTree(resultWrongHash);
JsonNode resultNodeWrongHash = rootNodeWrongHash.get("result");

assertThat(resultNodeWrongHash).isNotNull();
assertThat(resultNodeWrongHash.isArray()).isTrue();
assertThat(resultNodeWrongHash.isEmpty()).isTrue();
}

private String createPrivacyGroup() {
return node.execute(createPrivacyGroup("myGroupName", "my group description", node));
}

private String createWrongPrivacyGroup() {
return wrongNode.execute(createPrivacyGroup("myGroupName", "my group description", wrongNode));
}

private SimpleStorage deploySimpleStorageContract(final String privacyGroupId) {
final SimpleStorage simpleStorage =
node.execute(
privateContractTransactions.createSmartContractWithPrivacyGroupId(
SimpleStorage.class,
node.getTransactionSigningKey(),
restriction,
node.getEnclaveKey(),
privacyGroupId));

privateContractVerifier
.validPrivateContractDeployed(
simpleStorage.getContractAddress(), node.getAddress().toString())
.verify(simpleStorage);

return simpleStorage;
}

private String doTransaction(
final String privacyGroupId, final SimpleStorage simpleStorageContract, final int value) {
return node.execute(
privateContractTransactions.callSmartContractWithPrivacyGroupId(
simpleStorageContract.getContractAddress(),
simpleStorageContract.set(BigInteger.valueOf(value)).encodeFunctionCall(),
node.getTransactionSigningKey(),
restriction,
node.getEnclaveKey(),
privacyGroupId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public enum RpcMethod {
PRIV_GET_FILTER_LOGS("priv_getFilterLogs"),
PRIV_SUBSCRIBE("priv_subscribe"),
PRIV_UNSUBSCRIBE("priv_unsubscribe"),
PRIV_TRACE_TRANSACTION("priv_traceTransaction"),
PRIVX_FIND_PRIVACY_GROUP_OLD("privx_findOnchainPrivacyGroup"),
PRIVX_FIND_PRIVACY_GROUP("privx_findFlexiblePrivacyGroup"),
EEA_SEND_RAW_TRANSACTION("eea_sendRawTransaction"),
Expand Down
Loading

0 comments on commit 50f8add

Please sign in to comment.