Skip to main content

Privacy plugin

You can define your own strategy for private transactions by building a plugin that extends Hyperledger Besu functionality.

The plugin can take many forms, but it must provide Besu with a private transaction when required.


The privacy plugin is an early access feature and plugin interfaces are subject to change between releases.


Enable the privacy plugin by starting Besu and including the --Xprivacy-plugin-enabled command line option. The registered plugin must implement the PrivacyPluginPayloadProvider interface.

Use the payload provider interface

The privacy plugin must define the privacy marker transaction (PMT) payload. Use the payload to retrieve the contents of the private transaction which could be a link to a location in an enclave, or an encrypted form of the private payload itself.

Besu doesn't need to know how the private transaction is distributed, it just needs to know what the private transaction for the PMT is.

Send transactions

When submitting a private transaction using eea_sendRawTransaction, the signed transaction must be sent to 0x000000000000000000000000000000000000007a to indicate which privacy precompiled contract is being used.

The transaction flow is as follows:

  1. The JSON-RPC endpoint passes the private transaction to the private transaction manager (for example Tessera).
  2. The private transaction manager sends the private transaction to the privacy plugin.
  3. The plugin decides what data to store onchain in the payload, for example the encrypted and serialized private transaction.
  4. The plugin returns what needs to be stored in the payload for the PMT.
  5. The private transaction handler creates a PMT for the private transaction, and propagates the PMT using devP2P in the same way as a public Ethereum transaction.

Mine transactions

The process of mining transactions happens in reverse to sending transactions.

  1. The Mainnet transaction processor processes the PMT in the same way as any other public transaction. On nodes containing the privacy precompile contract specified in the to attribute of the PMT, the Mainnet transaction processor passes the PMT to the privacy precompile contract.


    Nodes receiving the PMT that do not contain the specified privacy precompile contract will ignore the PMT.

  2. The privacy precompile contract queries the plugin for the private transaction using the PMT.

  3. The privacy precompile contract passes the private transaction to the private transaction manager. The privacy group ID specifies the private world state to use.

  4. The private transaction manager executes the transaction. The private transaction manager can read and write to the private world state, and read from the public world state.

Transaction factory

An additional extension is available to help you define how PMTs are signed. Currently, Besu supports fixed or random key signing for PMTs.

The extension allows you to use a more dynamic approach, for example different keys for different groups.

Your plugin needs to register the PrivateMarkerTransactionFactory interface which is called before submitting a PMT to the transaction pool. The responsibility then lies with the plugin to sign and serialize the PMT.

Register your plugin

To enable Besu to use your privacy plugin, you must implement the PrivacyPluginService interface and you must call setPayloadProvider.

public class TestPrivacyPlugin implements BesuPlugin {

private PrivacyPluginService service;

public void register(BesuContext context) {
service = context.getService(PrivacyPluginService.class).get();

public void start() {
service.setPayloadProvider(new PrivacyPluginPayloadProvider() {
public Bytes generateMarkerPayload(PrivateTransaction privateTransaction, String privacyUserId) {
// perform logic to serialize the payload of the marker transaction
// in this example we are serialising the private transaction using rlp
return org.hyperledger.besu.ethereum.privacy.PrivateTransaction.serialize(privateTransaction).encoded();

public Optional<PrivateTransaction> getPrivateTransactionFromPayload(Transaction transaction) {
// perform logic to deserialize payload from the marker transaction

final BytesValueRLPInput bytesValueRLPInput =
new BytesValueRLPInput(transaction.getPayload(), false);

return Optional.of(org.hyperledger.besu.ethereum.privacy.PrivateTransaction.readFrom(bytesValueRLPInput));

public void stop() {