Skip to content

Commit b721a00

Browse files
authored
[Performance] Add CGO as an option for performance optimization (#47)
_tl;dr Ethereum's CGO backend delivers ~45% faster signing and ~84% faster verification than Cosmos SDK, with 90% fewer memory allocations during verification._ --- Benchmark outputs of this command: ```bash make benchmark_report ``` Showing: ```markdown 📊 Shannon SDK Benchmarks (portable vs ethereum) 🔬 Shannon SDK Benchmark Comparison ==================================== 📊 Testing Portable Backend (Pure Go) 📊 Testing Ethereum Backend (libsecp256k1) === SDK Performance Comparison === Benchmark Portable Ethereum Improvement Δ Time Δ % ------------------------------------------------------------------------------------------------------------------- BenchmarkSign 1.7 ms 766 μs 🚀 2.2x faster - 915 μs -54.4% BenchmarkSignWithCachedPrivateKey 1.8 ms 745 μs 🚀 2.4x faster - 1.0 ms -58.2% BenchmarkSignLargePayload 1.8 ms 776 μs 🚀 2.3x faster - 980 μs -55.8% BenchmarkSerializeSignature 42 μs 399 ns 🚀 104.6x faster - 41 μs -99.0% BenchmarkSignCore 1.5 ms 631 μs 🚀 2.4x faster - 890 μs -58.5% BenchmarkSignReuseRing 1.7 ms 784 μs 🚀 2.1x faster - 888 μs -53.1% BenchmarkVerifyRingSignature 1.0 ms 458 μs 🚀 2.2x faster - 553 μs -54.7% BenchmarkDeserializeAndVerifyRingSignature 1.1 ms 473 μs 🚀 2.3x faster - 597 μs -55.8% BenchmarkVerifyRingSignature5 2.5 ms 1.1 ms 🚀 2.3x faster - 1.4 ms -55.7% BenchmarkVerifyRingSignature10 5.1 ms 2.1 ms 🚀 2.4x faster - 3.0 ms -58.6% BenchmarkVerifyRingSignature20 9.9 ms 4.2 ms 🚀 2.4x faster - 5.7 ms -57.8% BenchmarkVerifyRingSignature40 20.6 ms 8.2 ms 🚀 2.5x faster - 12.4 ms -60.2% Summary Benchmarks: 12 Avg speedup: 10.83x Median speedup: 2.32x Avg Δ%%: -60.1% === Memory Usage Comparison === Benchmark Port B/op Port Allocs Eth B/op Eth Allocs Δ B/op Δ Allocs Δ% B Δ% Allocs ------------------------------------------------------------------------------------------------------------------------------------------------------ BenchmarkSign 9073 150 43108 1030 +34035 +880 +375.1% +586.7% BenchmarkSignWithCachedPrivateKey 8425 137 39030 898 +30605 +761 +363.3% +555.5% BenchmarkSignLargePayload 19827 150 54090 1058 +34263 +908 +172.8% +605.3% BenchmarkSerializeSignature 968 11 968 11 +0 +0 +0.0% +0.0% BenchmarkSignCore 5977 95 23070 376 +17093 +281 +286.0% +295.8% BenchmarkSignReuseRing 9073 150 43448 1072 +34375 +922 +378.9% +614.7% BenchmarkVerifyRingSignature 3392 53 19172 299 +15780 +246 +465.2% +464.2% BenchmarkDeserializeAndVerifyRingSignature 4512 77 30335 676 +25823 +599 +572.3% +777.9% BenchmarkVerifyRingSignature5 8480 131 47730 744 +39250 +613 +462.9% +467.9% BenchmarkVerifyRingSignature10 16961 261 95588 1489 +78627 +1228 +463.6% +470.5% BenchmarkVerifyRingSignature20 33920 521 191145 2976 +157225 +2455 +463.5% +471.2% BenchmarkVerifyRingSignature40 67904 1041 382960 5959 +315056 +4918 +464.0% +472.4% ```
1 parent 8854f9d commit b721a00

File tree

12 files changed

+1108
-112
lines changed

12 files changed

+1108
-112
lines changed

Makefile

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,39 @@
33
### Makefile Helpers ###
44
########################
55

6+
# Include modular makefiles
7+
include makefiles/benchmark.mk
8+
include makefiles/build.mk
9+
610
.PHONY: prompt_user
711
# Internal helper target - prompt the user before continuing
812
prompt_user:
913
@echo "Are you sure? [y/N] " && read ans && [ $${ans:-N} = y ]
1014

11-
.PHONY: list
12-
list: ## List all make targets
13-
@${MAKE} -pRrn : -f $(MAKEFILE_LIST) 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | sort
14-
1515
.PHONY: help
1616
.DEFAULT_GOAL := help
1717
help: ## Prints all the targets in all the Makefiles
18-
@grep -h -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-60s\033[0m %s\n", $$1, $$2}'
18+
@echo ""
19+
@echo "\033[1;34m📋 Shannon SDK Makefile Targets\033[0m"
20+
@echo ""
21+
@echo "\033[1;34m=== 🔍 Information & Discovery ===\033[0m"
22+
@grep -h -E '^(list|help):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-58s\033[0m %s\n", $$1, $$2}'
23+
@echo ""
24+
@echo "\033[1;34m=== 🧪 Testing ===\033[0m"
25+
@grep -h -E '^test_.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-58s\033[0m %s\n", $$1, $$2}'
26+
@echo ""
27+
@echo "\033[1;34m=== ⚡ Benchmarking ===\033[0m"
28+
@grep -h -E '^benchmark_.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-58s\033[0m %s\n", $$1, $$2}'
29+
@echo ""
30+
@echo "\033[1;34m=== 🔨 Building ===\033[0m"
31+
@grep -h -E '^(build_.*|clean_builds):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-58s\033[0m %s\n", $$1, $$2}'
32+
@echo ""
33+
@echo "\033[1;34m=== 🧹 Code Quality ===\033[0m"
34+
@grep -h -E '^go_lint:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-58s\033[0m %s\n", $$1, $$2}'
35+
@echo ""
36+
@echo "\033[1;34m=== 📝 TODO Management ===\033[0m"
37+
@grep -h -E '^todo_.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-58s\033[0m %s\n", $$1, $$2}'
38+
@echo ""
1939

2040
################
2141
### Protobuf ###
@@ -35,6 +55,8 @@ proto_regen:
3555
test_all: ## Run all go tests showing detailed output only on failures
3656
go test -v -count=1 -race -tags test ./...
3757

58+
59+
3860
###############
3961
### Linting ###
4062
###############

README.md

Lines changed: 134 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,21 @@ ShannonSDK is a Go-based toolkit for interacting with the POKT Network, designed
44

55
## Table of Contents <!-- omit in toc -->
66

7-
- [TechDebt: Updating the ShannonSDK](#techdebt-updating-the-shannonsdk)
8-
- [Overview](#overview)
9-
- [Key Features](#key-features)
10-
- [Complete working integration example](#complete-working-integration-example)
11-
- [Core Components](#core-components)
7+
- [TODO_TECHDEBT: Updating the ShannonSDK](#todo_techdebt-updating-the-shannonsdk)
128
- [Installation](#installation)
139
- [Quick Start](#quick-start)
10+
- [Complete working integration example](#complete-working-integration-example)
1411
- [Relay Request Workflow](#relay-request-workflow)
1512
- [Example Code](#example-code)
16-
- [API Reference](#api-reference)
13+
- [Shannon SDK Usage](#shannon-sdk-usage)
14+
- [Shannon SDK Core Components](#shannon-sdk-core-components)
15+
- [Crypto Backends](#crypto-backends)
16+
- [Comparison](#comparison)
17+
- [Benchmarking Crypto Backends](#benchmarking-crypto-backends)
1718

18-
## TechDebt: Updating the ShannonSDK
19+
## TODO_TECHDEBT: Updating the ShannonSDK
1920

20-
As of 07/2025, the two primary repositories dependant on ShannonSDK are:
21+
As of 09/2025, the two primary repositories dependant on ShannonSDK are:
2122

2223
- [Grove's Path](https://github.com/buildwithgrove/path)
2324
- [Pocket's Poktroll](https://github.com/pokt-network/poktroll)
@@ -51,44 +52,6 @@ git push
5152
# Merge the PR after the CI is green
5253
```
5354

54-
## Overview
55-
56-
ShannonSDK streamlines:
57-
58-
- Constructing POKT-compatible `RelayRequest`s
59-
- Verifying `RelayResponse`s from `RelayMiner`s
60-
- Building `Suppliers` co-processors
61-
- Abstracting protocol-specific details
62-
63-
The SDK provides an intuitive interface to manage `Sessions`, `Applications`, and `RelayRequests`.
64-
65-
## Key Features
66-
67-
- Secure request signing using ring signatures
68-
- Endpoint selection based on customizable filters
69-
- Robust error handling and validation
70-
- Protocol-specific serialization for HTTP requests/responses
71-
- Go-idiomatic API design
72-
73-
## Complete working integration example
74-
75-
A complete and working example of how to use the ShannonSDK can be found in `PATH`'s
76-
implementation of the `signer`. See [signer.go](https://github.com/buildwithgrove/path/blob/53d0f84cc0321c25d1e28b2ffb9b70714918870b/protocol/shannon/signer.go#L9).
77-
78-
## Core Components
79-
80-
| Component | Description |
81-
| ------------------ | ---------------------------------------------- |
82-
| Account Client | Query and manage account information |
83-
| Application Client | Handle application operations and queries |
84-
| ApplicationRing | Manage gateway delegations and ring signatures |
85-
| Block Client | Retrieve blockchain information |
86-
| Session Client | Manage session operations |
87-
| Shared Client | Interops with the onchain shared module |
88-
| Session Filter | Select supplier endpoints based on criteria |
89-
| Signer | Sign relay requests securely |
90-
| Relayer | Build and validate relay requests/responses |
91-
9255
## Installation
9356

9457
```bash
@@ -97,6 +60,11 @@ go get github.com/pokt-network/shannon-sdk
9760

9861
## Quick Start
9962

63+
### Complete working integration example
64+
65+
A complete and working example of how to use the ShannonSDK can be found in `PATH`'s
66+
implementation of the `signer`. See [signer.go](https://github.com/buildwithgrove/path/blob/53d0f84cc0321c25d1e28b2ffb9b70714918870b/protocol/shannon/signer.go#L9).
67+
10068
### Relay Request Workflow
10169

10270
The standard workflow for using ShannonSDK:
@@ -204,8 +172,12 @@ func main() {
204172
}
205173

206174
// 9. Sign the relay request
207-
signer := sdk.Signer{PrivateKeyHex: "YOUR_PRIVATE_KEY"}
208-
signedRelayReq, err := signer.Sign(context.Background(), relayReq, ring)
175+
signer, err := sdk.NewSignerFromHex("YOUR_PRIVATE_KEY")
176+
if err != nil {
177+
fmt.Printf("Error creating signer: %v\n", err)
178+
return
179+
}
180+
signedRelayReq, err := signer.Sign(context.Background(), relayReq, &ring)
209181
if err != nil {
210182
fmt.Printf("Error signing relay request: %v\n", err)
211183
return
@@ -263,16 +235,117 @@ func main() {
263235

264236
</details>
265237

266-
## API Reference
267-
268-
| Component | Description | Key Method |
269-
| --------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------- |
270-
| **AccountClient** | Fetches account information including public keys | `GetPubKeyFromAddress()` |
271-
| **ApplicationClient** | Manages application operations and queries | `GetApplication()`, `GetAllApplications()`, `GetApplicationsDelegatingToGateway()` |
272-
| **ApplicationRing** | Handles gateway delegations and ring signatures | `GetRing()` |
273-
| **BlockClient** | Retrieves blockchain information | `LatestBlockHeight()` |
274-
| **SessionClient** | Manages session operations | `GetSession()` |
275-
| **SharedClient** | Interops with the onchain shared module | `GetParams()` |
276-
| **SessionFilter** | Filters and selects supplier endpoints | `AllEndpoints()`, `FilteredEndpoints()` |
277-
| **Signer** | Signs relay requests with private keys | `Sign()` |
278-
| **Relayer Functions** | Builds and validates relay requests/responses | `BuildRelayRequest()`, `ValidateRelayResponse()` |
238+
## Shannon SDK Usage
239+
240+
ShannonSDK streamlines:
241+
242+
- Constructing POKT-compatible `RelayRequest`s
243+
- Verifying `RelayResponse`s from `RelayMiner`s
244+
- Building `Suppliers` co-processors
245+
- Abstracting protocol-specific details
246+
247+
The SDK provides an intuitive interface to manage `Sessions`, `Applications`, and `RelayRequests`.
248+
249+
### Shannon SDK Core Components
250+
251+
| Component | Description |
252+
| ------------------ | ---------------------------------------------- |
253+
| Account Client | Query and manage account information |
254+
| Application Client | Handle application operations and queries |
255+
| ApplicationRing | Manage gateway delegations and ring signatures |
256+
| Block Client | Retrieve blockchain information |
257+
| Session Client | Manage session operations |
258+
| Shared Client | Interops with the onchain shared module |
259+
| Session Filter | Select supplier endpoints based on criteria |
260+
| Signer | Sign relay requests securely |
261+
| Relayer | Build and validate relay requests/responses |
262+
263+
## Crypto Backends
264+
265+
⚠️The crypto backend is a BUILD-TIME configuration ⚠️
266+
267+
Shannon SDK uses ring signatures implemented in [ring-go](https://github.com/pokt-network/ring-go), which in turn
268+
uses [go-dleq](https://github.com/pokt-network/go-dleq) and a `secp256k1` library. Those repos select fast vs portable
269+
implementations via build tags. This SDK follows their selection — there’s nothing to toggle at runtime.
270+
271+
### Comparison
272+
273+
| Backend | Build Tags / Env | Dependencies | Performance | Portability |
274+
| ---------------------- | -------------------------------------------- | ----------------------------- | ---------------------------------------- | -------------------------- |
275+
| **Portable (Pure Go)** | `CGO_ENABLED=0` (default) | None | Excellent (Decred secp256k1 via ring-go) | Runs anywhere |
276+
| **Ethereum secp256k1** | `CGO_ENABLED=1` + `-tags=ethereum_secp256k1` | `gcc`, `libsecp256k1` headers | Faster signing/verification | Requires CGO + system libs |
277+
278+
To use the faster backend locally (copy/paste):
279+
280+
```bash
281+
# Build
282+
CGO_ENABLED=1 go build -tags=ethereum_secp256k1 ./...
283+
284+
# Run tests/benchmarks
285+
CGO_ENABLED=1 go test -tags=ethereum_secp256k1 -bench=. -benchmem ./...
286+
```
287+
288+
NOTE: You may need to add other flags to enable CGO, such as `-ldflags "-linkshared"` depending on your system.
289+
290+
### Benchmarking Crypto Backends
291+
292+
To see the benchmarks, run this command:
293+
294+
```bash
295+
make benchmark_report
296+
```
297+
298+
<details>
299+
<summary>Benchmark Output</summary>
300+
301+
```bash
302+
📊 Shannon SDK Benchmarks (portable vs ethereum)
303+
🔬 Shannon SDK Benchmark Comparison
304+
====================================
305+
306+
📊 Testing Portable Backend (Pure Go)
307+
308+
📊 Testing Ethereum Backend (libsecp256k1)
309+
310+
=== SDK Performance Comparison ===
311+
312+
## Benchmark Portable Ethereum Improvement Δ Time Δ %
313+
314+
BenchmarkSign 1.7 ms 766 μs 🚀 2.2x faster - 915 μs -54.4%
315+
BenchmarkSignWithCachedPrivateKey 1.8 ms 745 μs 🚀 2.4x faster - 1.0 ms -58.2%
316+
BenchmarkSignLargePayload 1.8 ms 776 μs 🚀 2.3x faster - 980 μs -55.8%
317+
BenchmarkSerializeSignature 42 μs 399 ns 🚀 104.6x faster - 41 μs -99.0%
318+
BenchmarkSignCore 1.5 ms 631 μs 🚀 2.4x faster - 890 μs -58.5%
319+
BenchmarkSignReuseRing 1.7 ms 784 μs 🚀 2.1x faster - 888 μs -53.1%
320+
BenchmarkVerifyRingSignature 1.0 ms 458 μs 🚀 2.2x faster - 553 μs -54.7%
321+
BenchmarkDeserializeAndVerifyRingSignature 1.1 ms 473 μs 🚀 2.3x faster - 597 μs -55.8%
322+
BenchmarkVerifyRingSignature5 2.5 ms 1.1 ms 🚀 2.3x faster - 1.4 ms -55.7%
323+
BenchmarkVerifyRingSignature10 5.1 ms 2.1 ms 🚀 2.4x faster - 3.0 ms -58.6%
324+
BenchmarkVerifyRingSignature20 9.9 ms 4.2 ms 🚀 2.4x faster - 5.7 ms -57.8%
325+
BenchmarkVerifyRingSignature40 20.6 ms 8.2 ms 🚀 2.5x faster - 12.4 ms -60.2%
326+
327+
Summary
328+
Benchmarks: 12
329+
Avg speedup: 10.83x
330+
Median speedup: 2.32x
331+
Avg Δ%%: -60.1%
332+
333+
=== Memory Usage Comparison ===
334+
335+
## Benchmark Port B/op Port Allocs Eth B/op Eth Allocs Δ B/op Δ Allocs Δ% B Δ% Allocs
336+
337+
BenchmarkSign 9073 150 43108 1030 +34035 +880 +375.1% +586.7%
338+
BenchmarkSignWithCachedPrivateKey 8425 137 39030 898 +30605 +761 +363.3% +555.5%
339+
BenchmarkSignLargePayload 19827 150 54090 1058 +34263 +908 +172.8% +605.3%
340+
BenchmarkSerializeSignature 968 11 968 11 +0 +0 +0.0% +0.0%
341+
BenchmarkSignCore 5977 95 23070 376 +17093 +281 +286.0% +295.8%
342+
BenchmarkSignReuseRing 9073 150 43448 1072 +34375 +922 +378.9% +614.7%
343+
BenchmarkVerifyRingSignature 3392 53 19172 299 +15780 +246 +465.2% +464.2%
344+
BenchmarkDeserializeAndVerifyRingSignature 4512 77 30335 676 +25823 +599 +572.3% +777.9%
345+
BenchmarkVerifyRingSignature5 8480 131 47730 744 +39250 +613 +462.9% +467.9%
346+
BenchmarkVerifyRingSignature10 16961 261 95588 1489 +78627 +1228 +463.6% +470.5%
347+
BenchmarkVerifyRingSignature20 33920 521 191145 2976 +157225 +2455 +463.5% +471.2%
348+
BenchmarkVerifyRingSignature40 67904 1041 382960 5959 +315056 +4918 +464.0% +472.4%
349+
```
350+
351+
</details>

account.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ type PoktNodeAccountFetcher interface {
3232
}
3333

3434
// AccountClient is used to interact with the account module.
35-
//
36-
// Example usage:
37-
// - Get the public key corresponding to an address.
3835
type AccountClient struct {
3936
PoktNodeAccountFetcher
4037
}

application.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,22 @@ import (
1313
"github.com/pokt-network/ring-go"
1414
)
1515

16+
// ApplicationRing groups the application and helper required to construct a *ring.Ring.
1617
type ApplicationRing struct {
1718
types.Application
1819
PublicKeyFetcher
1920
}
2021

22+
func NewApplicationRing(
23+
app types.Application,
24+
publicKeyFetcher PublicKeyFetcher,
25+
) *ApplicationRing {
26+
return &ApplicationRing{
27+
Application: app,
28+
PublicKeyFetcher: publicKeyFetcher,
29+
}
30+
}
31+
2132
// ApplicationClient is the interface to interact with the on-chain application-module.
2233
//
2334
// - Used to get the list of applications and the details of a specific application

0 commit comments

Comments
 (0)