Skip to main content

Nethereum.AppChain.Policy

NuGet: Nethereum.AppChain.Policy | Source: src/Nethereum.AppChain.Policy/

Nethereum.AppChain.Policy

PREVIEW — This package is in preview. APIs may change between releases.

Access control and governance for Nethereum AppChain — your business, your rules.

Overview​

AppChain operation is centralised by design. This package gives the operator control over who can write, what they can write, and how much they can write — while keeping those rules transparent and verifiable. Policies can start as simple local configuration and optionally migrate to an L1 smart contract for decentralised governance.

The package supports writer/admin authorisation using merkle tree proofs (gas-efficient on-chain verification of large allowlists), calldata size limits, log output limits, and per-block gas limits. A BootstrapPolicyService handles local policy management, an EvmPolicyService reads policies from L1, and a PolicySyncWorker periodically syncs policy state from L1.

Key Features​

  • Merkle Tree Authorization: Writers and admins validated via merkle proofs for gas-efficient on-chain verification
  • Bootstrap → L1 Migration: Start with local policies, migrate to L1 contract when ready
  • Epoch-Based Updates: Atomic policy updates tied to epoch numbers
  • Policy Sync Worker: Background service syncs policy changes from L1
  • Calldata & Gas Limits: Configurable per-transaction calldata size and per-block gas limits
  • Blacklist Support: Separate merkle tree for blacklisted addresses

Installation​

dotnet add package Nethereum.AppChain.Policy

Dependencies​

  • Nethereum.CoreChain - Chain state access
  • Nethereum.Web3 - L1 contract interaction for policy queries
  • Nethereum.Contracts - Contract function encoding/decoding
  • Nethereum.Util - Keccak hashing for merkle tree computation
  • Microsoft.Extensions.Hosting.Abstractions - IHostedService for policy sync

Key Concepts​

Merkle Tree Authorization​

Rather than storing all authorized addresses on-chain (expensive), the policy contract stores only the merkle root. Writers prove their authorization by submitting a merkle proof that their address is included in the tree. This enables gas-efficient verification of large allowlists.

var migrationService = new PolicyMigrationService();
byte[] root = migrationService.ComputeMerkleRoot(allowedAddresses);
byte[][] proof = migrationService.ComputeMerkleProof(myAddress, allowedAddresses);
bool valid = migrationService.VerifyMerkleProof(myAddress, root, proof);

Bootstrap → L1 Flow​

  1. Bootstrap: Start with local BootstrapPolicyService containing allowed writers/admins
  2. Operate: Chain runs with local policy enforcement
  3. Migrate: When L1 contract deployed, compute merkle roots and submit to contract
  4. Switch: PolicySyncWorker detects L1 policy, transitions to EvmPolicyService

Epochs​

Policy changes are versioned by epoch number. Each epoch represents an atomic update to the entire policy state. The PolicySyncWorker detects epoch changes and refreshes the cached policy.

Quick Start​

using Nethereum.AppChain.Policy;

// Bootstrap with local policy
var bootstrapConfig = new BootstrapPolicyConfig
{
AllowedWriters = new[] { writer1, writer2 },
AllowedAdmins = new[] { admin1 },
MaxCalldataBytes = 128_000,
MaxLogBytes = 64_000
};

var policyService = new BootstrapPolicyService(bootstrapConfig);
bool canWrite = await policyService.IsValidWriterAsync(writer1, proof, null);

Usage Examples​

Example 1: Query L1 Policy​

using Nethereum.AppChain.Policy;

var policyService = new EvmPolicyService(web3, contractAddress);
var policy = await policyService.GetCurrentPolicyAsync();

Console.WriteLine($"Epoch: {policy.Epoch}");
Console.WriteLine($"Max Calldata: {policy.MaxCalldataBytes}");
Console.WriteLine($"Writers Root: {policy.WritersRoot.ToHex()}");

Example 2: Manage Local Policy​

var bootstrap = new BootstrapPolicyService(bootstrapConfig);

// Dynamic policy updates without restart
bootstrap.AddWriter(newWriterAddress);
bootstrap.RemoveWriter(revokedAddress);
bootstrap.AddAdmin(newAdminAddress);

Console.WriteLine($"Is admin: {bootstrap.IsValidAdmin(adminAddress)}");

Example 3: Prepare Migration Data​

var migration = new PolicyMigrationService();
var data = migration.PrepareMigrationData(bootstrapConfig);

// data.WritersRoot - merkle root for writers
// data.AdminsRoot - merkle root for admins
// data.WriterProofs - per-address merkle proofs
// data.AdminProofs - per-address merkle proofs

API Reference​

EvmPolicyService​

L1 policy contract interaction.

public class EvmPolicyService : IPolicyService
{
public Task<PolicyInfo> GetCurrentPolicyAsync();
public Task<byte[]?> GetWritersRootAsync();
public Task<byte[]?> GetAdminsRootAsync();
public Task<BigInteger> GetEpochAsync();
public Task<bool> IsValidWriterAsync(string address, byte[][] proof, byte[]? blacklistProof);
}

BootstrapPolicyService​

Local policy management with optional L1 migration.

public class BootstrapPolicyService : IPolicyService
{
public bool IsMigratedToL1 { get; }
public void AddWriter(string address);
public void RemoveWriter(string address);
public void AddAdmin(string address);
public bool IsValidAdmin(string address);
}

PolicySyncWorker​

Background service for L1 policy synchronization.

public class PolicySyncWorker : IHostedService
{
public Task StartAsync(CancellationToken ct);
public Task StopAsync(CancellationToken ct);
public Task ForceSyncAsync();
public event Action<PolicyInfo>? OnPolicyUpdated;
}

PolicyMigrationService​

Merkle tree computation and proof generation.

  • ComputeMerkleRoot(addresses) : byte[]
  • ComputeMerkleProof(address, allAddresses) : byte[][]
  • VerifyMerkleProof(address, root, proof) : bool
  • PrepareMigrationData(config) : MigrationData

Used By (Consumers)​

Dependencies​

Additional Resources​