panurus

Token Validation Service Benchmark

This document describes how to benchmark the Token Validation Service at the node level using the Fabric Smart Client (FSC) framework.

Overview

The Token Validation Service benchmarks measure the performance of token request validation (including transfers, issues, and auditing) through different architectural layers:

  1. Local View Benchmark - Direct in-process validation (no network overhead)
  2. API Benchmark - Validation through FSC’s View API (local node)
  3. gRPC API Benchmark - Validation through gRPC client-server architecture (network overhead included)
  4. Distributed Benchmark - Two-node setup with separate client and server machines

These benchmarks complement the core driver benchmarks by testing the complete validation service layer including FSC integration, network communication, and node orchestration.

Motivation

The Token Validation Service benchmarks serve several critical purposes:

Performance Validation

Architecture Comparison

Optimization Guidance

Prerequisites

Panurus comes pre-equipped with test data containing cryptographic parameters and sample token transfers located at:

token/core/zkatdlog/nogh/v1/regression/testdata/zero

This directory includes:

Note: The test data is already included in the repository. You only need to regenerate it if you want to create custom test cases with different parameters or token configurations. To regenerate test data on demand:

cd token/core/zkatdlog/nogh/v1/regression
go test -run TestRegression -v

The test data is required by all benchmark types (Local, API, gRPC, and Distributed).

Quickstart

1. Local View Benchmark

Tests token validation directly in-process without any network or API overhead. This establishes the performance baseline.

cd cmd/token_validation_service
GOGC=10000 go test -run ^$ -bench=BenchmarkLocalTokenValidation -benchtime=30s -count=5 -cpu=1,4,8,16,32,64

Parameters:

2. API Benchmark (Local Node)

Tests token validation through FSC’s View API on a single node. Measures API overhead compared to direct validation.

cd cmd/token_validation_service
GC=10000 go test -bench=BenchmarkAPI -benchtime=30s

What it does:

3. gRPC API Benchmark (Local)

Tests token validation through gRPC client-server architecture on localhost. Measures network serialization overhead.

cd cmd/token_validation_service
GOGC=10000 go test -bench=BenchmarkAPIGRPC -benchtime=30s -count=5 -cpu=32 -numConn=1,2,4,8

Parameters:

What it does:

4. Distributed Two-Node Benchmark

To setup AWS EC2 nodes See: AWS Benchmark 2 Machines

For realistic deployment testing with separate client and server machines:

Architecture:

  1. Machine 1 is the server (FC Node)
  2. Machine 2 is the client sending to the server and gathering the metrics

Setup:

  1. Add ssh pubkey of server to client known_hosts (If not already connected)
  2. Start the server:
cd cmd/token_validation_service
GOGC=10000 go run ./server/

Wait until you see the output:

Running fscnode test-node

[Note: We set GOGC to 10K but you don’t have to]

  1. In the client, copy the node data from the server
    We can use Rsync for this: ```bash cd cmd/token_validation_service

rsync -avz ://panurus/cmd/token_validation_service/out/ ./out

Note: Make sure full path and server name are correct

4. Replace the IP (or full name DNS can resolve) to the Server IP in the client out folder:

```bash
sed 's#127.0.0.1#123.456.789#g' ./out/testdata/fsc/nodes/test-node.0/client-config.yaml -i
  1. Start client and tee output to file
GOGC=10000 go run ./client/ -benchtime=30s -count=5 -workloads=token-validation-service -cpu=1,2,4,8,16,32,48,64 -numConn=1,2,4,8 2>&1 | tee out.txt &

This setup is ideal for:

  1. Set up python environment:
python -m venv .venv 
source .venv/bin/activate
pip install streamlit pandas plotly
  1. Place the results in .txt files in a folder called bench.

  2. Run:

    streamlit run cmd/benchmarking/plotly_plot_node.py
    

Real world example:

They both already have each-others SSH Keys, so I don’t need to do it again.

On dectrust2, Server Runs:

cd cmd/token_validation_service
GOGC=10000 go run ./server/

I wait to see:

Running fscnode test-node

On dectrust1:

cd ~/effi/panurus/cmd/token_validation_service
rsync -avz root@dectrust2.vpc.cloud9.ibm.com:/root/effi/panurus/cmd/token_validation_service/out/ ./out
sed 's#127.0.0.1#dectrust1.vpc.cloud9.ibm.com#g' ./out/testdata/fsc/nodes/test-node.0/client-config.yaml -i
GOGC=10000 nohup go run ./client/ -benchtime=30s -count=5 -workloads=zkp -cpu=1,2,4,8,16,32 -numConn=1,2,4,8 2>&1 | tee example-2node.txt &

I also run gRPC benchmark without the 2 node setup:

GOGC=10000 go test -bench=BenchmarkAPIGRPC -benchtime=30s -count=5 -cpu=32 -numConn=1,2,4,8 | tee example-grpc.txt

I now move the outputs to bench folder and run the visualisation:

mv example-2node.txt bench
mv example-grpc.txt

(Optional) I setup python venv:

python -m venv .venv 
source .venv/bin/activate
pip install streamlit pandas

Now I can run the visualisation:

streamlit run cmd/benchmarking/plotly_plot_node.py 

Understanding Results

Metrics Reported

Each benchmark reports:

Example Output

BenchmarkLocalTokenValidation/out-tokens=2in-tokens=2-32    1000    30000000 ns/op    33333 TPS

Interpretation:

Selecting the range-proof system (IPA vs CSP)

The benchmarks are agnostic to the range-proof system used by the token transfers: the proof type is baked into the public parameters (params.txt) of whichever test-root you point at. Two corpora ship under testdata/zero:

Range-proof system Test-root (relative to cmd/token_validation_service)
IPA / bulletproof (default) ../../token/core/zkatdlog/nogh/v1/regression/testdata/zero/32-BLS12_381_BBS_GURVY
CSP ../../token/core/zkatdlog/nogh/v1/regression/testdata/zero/csp/32-BLS12_381_BBS_GURVY

Every benchmark (BenchmarkLocalTokenValidation, BenchmarkAPI, BenchmarkAPIGRPC) and the standalone client accept a -testRoot flag that overrides the corpus. When omitted it defaults to the IPA test-root above. To benchmark CSP proofs instead, pass the csp test-root:

cd cmd/token_validation_service

# Local baseline against CSP proofs
GOGC=10000 go test -run ^$ -bench=BenchmarkLocalTokenValidation -benchtime=30s -cpu=1,4,8,16,32 \
  -testRoot=../../token/core/zkatdlog/nogh/v1/regression/testdata/zero/csp/32-BLS12_381_BBS_GURVY

# API benchmark against CSP proofs
GOGC=10000 go test -run ^$ -bench=BenchmarkAPI -benchtime=30s \
  -testRoot=../../token/core/zkatdlog/nogh/v1/regression/testdata/zero/csp/32-BLS12_381_BBS_GURVY

# gRPC benchmark against CSP proofs
GOGC=10000 go test -run ^$ -bench=BenchmarkAPIGRPC -benchtime=30s -cpu=32 -numConn=1,2,4,8 \
  -testRoot=../../token/core/zkatdlog/nogh/v1/regression/testdata/zero/csp/32-BLS12_381_BBS_GURVY

# Standalone client (distributed benchmark) against CSP proofs
GOGC=10000 go run ./client/ -testRoot=../../token/core/zkatdlog/nogh/v1/regression/testdata/zero/csp/32-BLS12_381_BBS_GURVY

Swap 32-BLS12_381_BBS_GURVY for another configuration (32-BN254, 64-BLS12_381_BBS_GURVY, 64-BN254) to change the curve/bit-length.

Regenerating the CSP corpus (only needed for custom parameters; the data ships in the repo):

cd token/core/zkatdlog/nogh/v1/regression/testdata/zero/generator
go run . -proof_type=csp -bits=32,64 -curves=BN254,BLS12_381_BBS_GURVY -num_inputs=1,2 -num_outputs=1,2

The -proof_type flag selects the system (csp for CSP; omit it, or use bf/bulletproof, for the IPA default). CSP output is written to the separate zero/csp/ subtree so it never overwrites the IPA vectors.