Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
8414560
fix(spv): harden DIFF1 proof-header computation
piotr-roslaniec Jul 22, 2026
ed12d9f
test(spv): cover DIFF1 predicate and proof-skip handling
piotr-roslaniec Jul 23, 2026
39f821d
refactor(ethereum): split tBTC chain adapter into per-concern files
piotr-roslaniec Jul 23, 2026
990ea23
test(electrum): extend retry window for public electrs
piotr-roslaniec Nov 30, 2025
d2d47f5
test(ethereum): require mainnet rpc env
piotr-roslaniec Nov 30, 2025
c7b0143
test(tbtcpg): fix expected error unmarshaling
piotr-roslaniec Nov 30, 2025
07fcac1
ci: pass ETHEREUM_MAINNET_RPC_URL into integration job
piotr-roslaniec Nov 30, 2025
633d154
fix(ethereum): avoid tx decoding in block lookup
piotr-roslaniec Nov 30, 2025
49b50dd
fix(test): skip ethereum mainnet integration when RPC URL is missing
piotr-roslaniec May 23, 2026
cd12b31
fix(deps): remediate critical npm security vulnerabilities
piotr-roslaniec Mar 16, 2026
149be90
: fix npm vulnerabilities in solidity-v1
piotr-roslaniec Mar 17, 2026
d3ea270
ENG-630: Remove SECURITY-FIXES.md from PR
piotr-roslaniec Mar 18, 2026
5b50d34
ENG-630: Remove .npmrc from PR
piotr-roslaniec May 23, 2026
54aee63
ENG-630: bump provision-keep-client to Node 20 so overrides are honored
lrsaturnino May 28, 2026
9a6a79f
perf(bench): add Phase 0-1 benchmark infrastructure and quick-win ben…
piotr-roslaniec May 6, 2026
8ee6015
test(bench): add Phase 2 benchmarks for libp2p channel delivery and B…
piotr-roslaniec May 6, 2026
40b1b96
feat(clientinfo): add opt-in pprof endpoint and profiling runbook
piotr-roslaniec May 6, 2026
36df22f
fix(clientinfo): remove duplicate pprof handler registration
piotr-roslaniec May 6, 2026
8664629
test(bench): fix zero benchmark and add realistic N=100 ephemeral key…
piotr-roslaniec May 6, 2026
44c033c
test(bench): add ephemeral key marshal/unmarshal benchmarks to beacon…
piotr-roslaniec May 6, 2026
dfb578f
perf(tecdsa): defer ephemeral key parsing from O(N²) to O(N)
piotr-roslaniec May 6, 2026
5f01fe7
ci(bench): add benchstat regression gate to client-bench job
piotr-roslaniec May 6, 2026
b3e68f0
test(tecdsa): add regression tests for lazy ephemeral key parsing err…
piotr-roslaniec May 6, 2026
802c24f
fix(clientinfo): suppress gosec G108 on intentional pprof import
piotr-roslaniec May 6, 2026
0a5a097
fix(ci): calibrate coverage gate threshold to actual baseline
piotr-roslaniec May 7, 2026
a09b3d3
ci: re-trigger CI
piotr-roslaniec May 7, 2026
fdbd264
fix(make): correct stale .PHONY declaration
piotr-roslaniec May 7, 2026
0378b85
refactor(clientinfo): split registerAllMetrics and trim redundant com…
piotr-roslaniec Jul 22, 2026
8116f11
refactor(tbtc): remove dead coordination-failed flag and redundant co…
piotr-roslaniec Jul 22, 2026
f699e6b
refactor(tbtc): introduce named types and dedupe repeated constructs
piotr-roslaniec Jul 22, 2026
5f8342c
fix(tbtcpg,protocol): preserve error causes and align naming/docs
piotr-roslaniec Jul 22, 2026
1ce1b7f
fix(tbtc): preserve final signing group resolution error
piotr-roslaniec Jul 22, 2026
0e54637
refactor(spv): use typed metric constants and drop passthrough wrapper
piotr-roslaniec Jul 22, 2026
d7b769c
style: normalize marshaling filename spelling
piotr-roslaniec Jul 22, 2026
834d5c9
fix(tbtc): reattach ValidateMovingFundsSafetyMargin godoc
piotr-roslaniec Jul 22, 2026
7ca1c22
docs: describe tools.go pins as build-time-only deps
piotr-roslaniec Jul 22, 2026
94f0739
docs(tbtc): flag DepositKey as a source-compatibility break
lrsaturnino Jul 29, 2026
7757933
test(tbtcpg,clientinfo): cover the two PR-introduced behavior fixes
lrsaturnino Jul 29, 2026
b6945c3
fix(tbtcpg,clientinfo): address CodeRabbit review findings
piotr-roslaniec Aug 10, 2026
09d00cf
Add follower-side soft check for below-floor sweep fees
mswilkison Jul 20, 2026
5b185cb
test: guard mirrored sweep-fee constants against drift
piotr-roslaniec Jul 22, 2026
8f2a596
fix(tbtc): harden follower sweep-fee soft check
piotr-roslaniec Jul 23, 2026
6df699b
test(tbtc): cover follower-side sweep-fee soft check
lrsaturnino Jul 29, 2026
581783e
test(tbtcpg): fix per-request-fee-warning test for aggregate cap clamp
piotr-roslaniec Aug 7, 2026
9ed27a1
ci: re-trigger
piotr-roslaniec Aug 18, 2026
1c2d981
ci: re-trigger
piotr-roslaniec Aug 18, 2026
a0998be
ENG-469 Stabilize integration suites: Electrum skips, retries, env RP…
piotr-roslaniec Aug 18, 2026
9c939ad
fix(deps): remove @umpirsky/country-list malware; harden provision-ke…
piotr-roslaniec Aug 18, 2026
09aba44
fix(spv): harden DIFF1 proof-header computation (#4186)
piotr-roslaniec Aug 18, 2026
7851945
chore: low-risk code-quality cleanup across tBTC/beacon node (#4185)
piotr-roslaniec Aug 18, 2026
b4f8ef0
Add follower-side soft check for below-floor sweep fees (#4194)
piotr-roslaniec Aug 18, 2026
3a7b398
refactor(ethereum): split tBTC chain adapter into per-concern files (…
piotr-roslaniec Aug 18, 2026
22388f6
perf: benchmark infrastructure, O(N²)→O(N) ephemeral key optimisation…
piotr-roslaniec Aug 18, 2026
abf025b
fix(chain,bench): wallet error format, redemptionKey fmt, dkg reflect…
piotr-roslaniec Aug 18, 2026
80bdd5b
fix(clientinfo): register SPV proof-skip counters, drop metric lazy-c…
piotr-roslaniec Aug 18, 2026
504c5b3
docs: file-level breadcrumbs, profiling runbook link, tools.go wordin…
piotr-roslaniec Aug 18, 2026
ff18152
chore(initcontainer): drop root, --ignore-scripts, build-time audit
piotr-roslaniec Aug 18, 2026
9afc30e
fix(chain,ci,tecdsa): TxMaxFee mapping, member-index lower bound, CI …
piotr-roslaniec Aug 18, 2026
346a9fc
fix(gosec): restore #nosec G108 suppression on net/http/pprof import
piotr-roslaniec Aug 18, 2026
d6dc72e
fix: address multi-agent review findings on PR #4256
piotr-roslaniec Aug 19, 2026
47bad76
ci: restrict client-bench to manual workflow_dispatch
piotr-roslaniec Aug 19, 2026
c2e305a
refactor: collapse wallet-tx fee buffer to single percent field
piotr-roslaniec Aug 19, 2026
e101004
chore: remove retired KEEP-era infrastructure tree
piotr-roslaniec Aug 19, 2026
988bd46
fix(infra-removal): preserve live tbtc-v2-maintainer overlay and disc…
piotr-roslaniec Aug 19, 2026
377ae3c
chore: remove retired KEEP-era infrastructure tree (#4272)
piotr-roslaniec Aug 19, 2026
3121f21
fix(infra): restore live tBTC-v2 overlays and correct retirement notes
lrsaturnino Aug 19, 2026
f529822
fix(infra): correct keep-maintainer image org and retirement notes
lrsaturnino Aug 19, 2026
ff95a45
fix(infra): restore live tBTC-v2 overlays and correct retirement note…
piotr-roslaniec Aug 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions .github/workflows/client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
push:
branches:
- main
- dev
paths-ignore:
- "docs/**"
- "infrastructure/**"
Expand Down Expand Up @@ -192,6 +193,21 @@ jobs:
path: coverage/coverage.out
if-no-files-found: warn

# Coverage gate: 14% minimum total. Baseline measured at PR #4256
# (2026-08-19); no automated baseline-update mechanism exists.
- name: Check coverage gate
run: |
docker run --rm \
-v "${{ github.workspace }}/coverage:/coverage" \
go-build-env \
go tool cover -func /coverage/coverage.out > /tmp/cover-func.txt
TOTAL=$(grep '^total:' /tmp/cover-func.txt | awk '{print $3}' | tr -d '%')
echo "Total coverage: ${TOTAL}%"
PASS=$(awk -v t="$TOTAL" 'BEGIN { print (t+0 >= 14) ? "yes" : "no" }')
if [ "$PASS" != "yes" ]; then
echo "::error::Coverage ${TOTAL}% is below the 14% minimum threshold"
exit 1
fi

- name: Build Docker Runtime Image
if: github.event_name != 'workflow_dispatch'
Expand Down Expand Up @@ -358,6 +374,93 @@ jobs:
install-go: false
checks: "-SA1019"

client-bench:
needs: [client-build-test-publish]
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
actions: read
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24"
cache: false

- name: Download Docker Build Image
uses: actions/download-artifact@v4
with:
name: go-build-env-image
path: /tmp

- name: Load Docker Build Image
run: |
docker load --input /tmp/go-build-env-image.tar

- name: Download previous benchmark results
id: download-prev
uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6
continue-on-error: true
with:
name: go-bench
path: bench-prev
workflow: client.yml
branch: main
if_no_artifact_found: warn

- name: Run benchmarks
run: |
docker run \
--workdir /go/src/github.com/keep-network/keep-core \
go-build-env \
go test -bench=. -benchmem -count=10 -run='^$' ./pkg/... \
> bench.txt
cat bench.txt

- name: Install benchstat
run: go install golang.org/x/perf/cmd/benchstat@v0.0.0-20260813145340-fd4a688df892

# Benchmark regression gate: >12% slower than main's last `go-bench`
# artifact. Baseline measured at PR #4256 (2026-08-19). This job only
# runs on manual `workflow_dispatch` - no automatic push/PR trigger.
# GAP: benchmarks added in this PR have no main-side baseline, so
# benchstat silently skips them on first run; they only become
# gated after shipping to main and someone manually dispatches this
# workflow again on main to record a baseline artifact.
# No automated baseline-record mechanism exists in this workflow.
- name: Compare benchmarks
if: steps.download-prev.outcome == 'success' && hashFiles('bench-prev/**') != ''
run: |
benchstat bench-prev/*.txt bench.txt | tee benchstat-results.txt
python3 - <<'EOF'
import sys, re
content = open('benchstat-results.txt').read()
regressions = []
for line in content.splitlines():
if '~' in line or not line.strip():
continue
m = re.search(r'\+(\d+\.\d+)%', line)
if m and float(m.group(1)) > 12:
regressions.append(line)
if regressions:
print('Performance regressions >12% detected:')
for r in regressions:
print(' ', r)
sys.exit(1)
EOF

- name: Upload benchmark results
if: always()
uses: actions/upload-artifact@v4
with:
name: go-bench
path: bench.txt
overwrite: true
if-no-files-found: warn

client-integration-test:
needs: [client-detect-changes, electrum-integration-detect-changes, client-build-test-publish]
if: |
Expand All @@ -379,8 +482,11 @@ jobs:
docker load --input /tmp/go-build-env-image.tar

- name: Run Go Integration Tests
env:
ETHEREUM_MAINNET_RPC_URL: ${{ secrets.ETHEREUM_MAINNET_RPC_URL }}
run: |
docker run \
-e ETHEREUM_MAINNET_RPC_URL \
--workdir /go/src/github.com/keep-network/keep-core \
go-build-env \
gotestsum -- -timeout 20m -tags=integration ./...
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
*.swp
*.swo

# Infrastructure
/infrastructure/gcp/service-accounts*

# Secret directory used in Kubernetes configurations
/infrastructure/kube/**/.secret/
/infrastructure/kube/**/*.secret
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,7 @@ cmd-help: build
@echo '$$ $(app_name) start --help' > docs/resources/client-start-help
./$(app_name) start --help >> docs/resources/client-start-help

.PHONY: all development sepolia download_artifacts generate gen_proto build cmd-help release build_multi
bench:
go test -bench=. -benchmem -count=10 -run='^$$' ./pkg/...

.PHONY: all development sepolia mainnet local get_artifacts generate gen_proto build cmd-help release build_multi bench
28 changes: 28 additions & 0 deletions cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,25 @@ func initTbtcFlags(cmd *cobra.Command, cfg *config.Config) {
tbtc.DefaultKeyGenerationConcurrency,
"tECDSA key generation concurrency.",
)

cmd.Flags().IntVar(
&cfg.Tbtc.WalletTxSatPerVByteFloor,
"tbtc.walletTxSatPerVByteFloor",
tbtc.DefaultWalletTxSatPerVByteFloor,
"Minimum fee rate (sat/vByte) applied to wallet Bitcoin transactions "+
"(deposit sweeps, redemptions, moving funds, moved funds sweeps). "+
"Applies to both the leader-side floor in tbtcpg and the "+
"follower-side soft check; 0 means use the default.",
)

cmd.Flags().IntVar(
&cfg.Tbtc.WalletTxFeeBufferPercent,
"tbtc.walletTxFeeBufferPercent",
tbtc.DefaultWalletTxFeeBufferPercent,
"Safety-buffer percentage applied over the per-vByte fee rate "+
"(bufferedRate = ceil(rawRate * (100+Percent) / 100)); "+
"0 means use the default.",
)
}

// Initialize flags for Maintainer configuration.
Expand Down Expand Up @@ -373,6 +392,15 @@ func initMaintainerFlags(command *cobra.Command, cfg *config.Config) {
"The wait time which should be applied when there are no more "+
"transaction proofs to submit.",
)
command.Flags().UintVar(
&cfg.Maintainer.Spv.MaxProofHeaders,
"spv.maxProofHeaders",
spv.DefaultMaxProofHeaders,
"The maximum number of block headers allowed when assembling an SPV "+
"proof. Bounds the forward walk over headers and so the number of "+
"consecutive leading minimum-difficulty (DIFF1) headers a proof "+
"can absorb before it becomes unprovable.",
)
}

// Initialize flags for Developer configuration.
Expand Down
15 changes: 15 additions & 0 deletions cmd/flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
ethereumEcdsa "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen"
ethereumTbtc "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen"
ethereumThreshold "github.com/keep-network/keep-core/pkg/chain/ethereum/threshold/gen"
"github.com/keep-network/keep-core/pkg/tbtc"
)

var cmdFlagsTests = map[string]struct {
Expand Down Expand Up @@ -225,6 +226,20 @@ var cmdFlagsTests = map[string]struct {
expectedValueFromFlag: 101,
defaultValue: runtime.GOMAXPROCS(0),
},
"tbtc.walletTxSatPerVByteFloor": {
readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.WalletTxSatPerVByteFloor },
flagName: "--tbtc.walletTxSatPerVByteFloor",
flagValue: "7",
expectedValueFromFlag: 7,
defaultValue: tbtc.DefaultWalletTxSatPerVByteFloor,
},
"tbtc.walletTxFeeBufferPercent": {
readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.WalletTxFeeBufferPercent },
flagName: "--tbtc.walletTxFeeBufferPercent",
flagValue: "30",
expectedValueFromFlag: 30,
defaultValue: tbtc.DefaultWalletTxFeeBufferPercent,
},
"maintainer.bitcoinDifficulty": {
readValueFunc: func(c *config.Config) interface{} { return c.Maintainer.BitcoinDifficulty.Enabled },
flagName: "--bitcoinDifficulty",
Expand Down
2 changes: 1 addition & 1 deletion cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func initializeClientInfo(
signing chain.Signing,
blockCounter chain.BlockCounter,
) *clientinfo.Registry {
registry, isConfigured := clientinfo.Initialize(ctx, config.ClientInfo.Port)
registry, isConfigured := clientinfo.Initialize(ctx, config.ClientInfo)
if !isConfigured {
logger.Infof("client info endpoint not configured")
return nil
Expand Down
3 changes: 1 addition & 2 deletions docs/dev-ops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

= Kubernetes

At Keep we run on GCP + Kubernetes. To accommodate the aforementioned
At Keep we run on GCP and Kubernetes. To accommodate the
xref:./run-keep-node.adoc#system-considerations[System Considerations]
we use the following pattern for each of our environments:

Expand All @@ -16,4 +16,3 @@ we use the following pattern for each of our environments:
- A LoadBalancer Service for each client.
- A StatefulSet for each client.

You can see our Testnet Kubernetes configurations link:https://github.com/threshold-network/keep-core/tree/main/infrastructure/kube/keep-test[here].
1 change: 1 addition & 0 deletions docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@

* xref:./registration.adoc[Registration]
* xref:./run-keep-node.adoc[Run Keep Client Node]
* xref:./profiling.md[Profiling & pprof runbook]
* xref:./development/README.adoc[Developers]
* xref:./dev-ops.adoc[DevOps]
Loading
Loading