Skip to content

Instantly share code, notes, and snippets.

@lenkan
Last active March 11, 2026 13:38
Show Gist options
  • Select an option

  • Save lenkan/c03db9084631695fe8ab522c25a2d431 to your computer and use it in GitHub Desktop.

Select an option

Save lenkan/c03db9084631695fe8ab522c25a2d431 to your computer and use it in GitHub Desktop.
Reproduction for witness not storing delegation authorization seal

Delegation problem (KERI/KLI)

This gist reproduces a bug in KERI/KLI: when inspecting delegate kevers, the delegate witness incorrectly reports the delegator as "Not Anchored" even though the delegator and delegate both show "Anchored" for the same identifier, with the same witness count, receipts, and threshold.

The bug

The script sets up a delegator and a delegate, each with a witness, then runs kli kevers from three places:

  1. Delegator — delegated identifier shows ✔ Anchored
  2. Delegate — delegated identifier shows ✔ Anchored
  3. Delegate witness — delegated identifier shows ✘ Not Anchored (incorrect)

So the delegate witness has the same receipt/threshold data but reports "Not Anchored" instead of "Anchored".

Example output

--------------------------------
Delegate kevers from delegator, note showing 'Anchored'
--------------------------------
Identifier: EDkvcqndMxTC8-70_m6G4U1KmsTdeQ4vh4qddK-MCef5
Seq No: 0
Delegated Identifier
    Delegator:  EAhA4AGEJuZu3bQaKL07PfI_Shy9VOa-JM8mfo0qH3Hx ✔ Anchored


Witnesses:
Count:          1
Receipts:       1
Threshold:      1

Public Keys:
        1. DJuDd2GgFwtPGiMCQ9aCaEbNEkxxauCoOB0hfOtnQusR

--------------------------------
Delegate kevers from delegate, note showing 'Anchored'
--------------------------------
Identifier: EDkvcqndMxTC8-70_m6G4U1KmsTdeQ4vh4qddK-MCef5
Seq No: 0
Delegated Identifier
    Delegator:  EAhA4AGEJuZu3bQaKL07PfI_Shy9VOa-JM8mfo0qH3Hx ✔ Anchored


Witnesses:
Count:          1
Receipts:       1
Threshold:      1

Public Keys:
        1. DJuDd2GgFwtPGiMCQ9aCaEbNEkxxauCoOB0hfOtnQusR

--------------------------------
Delegate kevers from delegate witness, note showing 'Not anchored'
--------------------------------
Identifier: EDkvcqndMxTC8-70_m6G4U1KmsTdeQ4vh4qddK-MCef5
Seq No: 0
Delegated Identifier
    Delegator:  EAhA4AGEJuZu3bQaKL07PfI_Shy9VOa-JM8mfo0qH3Hx ✘ Not Anchored


Witnesses:
Count:          1
Receipts:       1
Threshold:      1

Public Keys:
        1. DJuDd2GgFwtPGiMCQ9aCaEbNEkxxauCoOB0hfOtnQusR

Prerequisites

  • Bash
  • Python 3 (for kli; the script can install dependencies from requirements.txt if missing)
  • curl (used to wait for witnesses to be ready)

Clone and run

Clone the gist

HTTPS:

git clone https://gist.github.com/c03db9084631695fe8ab522c25a2d431.git delegation-problem
cd delegation-problem

SSH:

git clone git@gist.github.com:c03db9084631695fe8ab522c25a2d431.git delegation-problem
cd delegation-problem

Run the script

chmod +x delegation-problem.sh
./delegation-problem.sh

If kli is not installed, the script will create a Python virtualenv (.venv) and install dependencies from requirements.txt. On subsequent runs you can activate the venv first to reuse it:

source .venv/bin/activate
./delegation-problem.sh

Install keri from a local clone (optional)

To run against a local keripy checkout (e.g. to test fixes), create a venv and install keri in editable mode, then run the script with that env active:

python3 -m venv .venv
source .venv/bin/activate
pip install -e ../keripy
./delegation-problem.sh

Use the path where you have cloned keripy (e.g. ../keripy, ~/code/keripy, or an absolute path). The script will see kli on your PATH and skip installing from requirements.txt.

Notes

  • The script starts local witness servers and cleans them up on exit (including via Ctrl+C).
  • It uses random suffixes for delegator/delegate names to avoid clashes between runs.
  • At the end it runs kli kevers from the delegator, delegate, and delegate witness; compare the "Delegated Identifier" line to see Anchored vs Not Anchored.
#!/bin/bash
set -e
# If kli is not installed, install from requirements.txt
if ! command -v kli &> /dev/null; then
echo "kli could not be found, installing from requirements.txt..."
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
fi
pkill kli || true
function cleanup() {
pkill kli || true
}
trap cleanup EXIT
suffix=$(head /dev/urandom | tr -dc a-z0-9 | head -c4)
delegator="delegator_${suffix}"
delegator_witness="delegator_witness_${suffix}"
delegate="delegate_${suffix}"
delegate_witness="delegate_witness_${suffix}"
delegator_witness_http_port="5642"
delegator_witness_tcp_port="5632"
delegate_witness_http_port="5643"
delegate_witness_tcp_port="5633"
delegator_witness_url="http://127.0.0.1:$delegator_witness_http_port"
delegate_witness_url="http://127.0.0.1:$delegate_witness_http_port"
config_dir="$(mktemp -d)/keri"
mkdir -p "$config_dir/keri/cf"
delegator_config_json="$config_dir/keri/cf/delegator_config.json"
delegate_config_json="$config_dir/keri/cf/delegate_config.json"
kli init --name "$delegator_witness" --nopasscode
kli incept --name "$delegator_witness" --alias witness --icount 1 --ncount 0 --isith 1 --nsith 0 --toad 0
delegator_witness_aid=$(kli aid --name "$delegator_witness" --alias witness)
kli ends add --name "$delegator_witness" --alias witness --eid "$delegator_witness_aid" --role controller
kli location add --name "$delegator_witness" --alias witness --url "$delegator_witness_url"
kli witness start --name "$delegator_witness" --alias witness -H "$delegator_witness_http_port" -T "$delegator_witness_tcp_port" &
delegator_witness_pid=$!
while ! curl -s "$delegator_witness_url" > /dev/null; do
echo "Waiting for delegator witness to be ready..."
sleep 1
done
kli init --name "$delegate_witness" --nopasscode
kli incept --name "$delegate_witness" --alias witness --icount 1 --ncount 0 --isith 1 --nsith 0 --toad 0
delegate_witness_aid=$(kli aid --name "$delegate_witness" --alias witness)
kli ends add --name "$delegate_witness" --alias witness --eid "$delegate_witness_aid" --role controller
kli location add --name "$delegate_witness" --alias witness --url "$delegate_witness_url"
kli witness start --name "$delegate_witness" --alias witness -H "$delegate_witness_http_port" -T "$delegate_witness_tcp_port" &
delegate_witness_pid=$!
while ! curl -s "$delegate_witness_url" > /dev/null; do
echo "Waiting for delegate witness to be ready..."
sleep 1
done
cat << EOF > "$delegator_config_json"
{
"dt": "2026-03-10T00:00:00.000000+00:00",
"iurls": [
"$delegator_witness_url/oobi/$delegator_witness_aid/controller"
]
}
EOF
cat << EOF > "$delegate_config_json"
{
"dt": "2026-03-10T00:00:00.000000+00:00",
"iurls": [
"$delegate_witness_url/oobi/$delegate_witness_aid/controller"
]
}
EOF
kli init --name "$delegator" --config-dir "$config_dir" --config-file delegator_config --nopasscode
kli init --name "$delegate" --config-dir "$config_dir" --config-file delegate_config --nopasscode
kli incept --name "$delegator" --alias delegator --icount 1 --ncount 1 --isith 1 --nsith 1 --transferable --toad 1 --wit "$delegator_witness_aid"
kli ends add --name "$delegator" --alias delegator --eid "$delegator_witness_aid" --role mailbox
delegator_aid=$(kli aid --name "$delegator" --alias delegator)
delegator_oobi=$(kli oobi generate --name "$delegator" --alias delegator --role witness | tail -n 1)
kli incept --name "$delegate" --alias proxy --icount 1 --ncount 1 --isith 1 --nsith 1 --transferable --toad 1 --wit "$delegate_witness_aid"
kli ends add --name "$delegate" --alias proxy --eid "$delegate_witness_aid" --role mailbox
proxy_oobi=$(kli oobi generate --name "$delegate" --alias proxy --role witness | tail -n 1)
kli oobi resolve --name "$delegate" --oobi-alias delegator --oobi "$delegator_oobi"
kli oobi resolve --name "$delegator" --oobi-alias delegate --oobi "$proxy_oobi"
kli incept --name "$delegate" --alias delegate --icount 1 --ncount 1 --isith 1 --nsith 1 --transferable --toad 1 --wit "$delegate_witness_aid" --delpre "$delegator_aid" --proxy proxy &
PID_LIST="$!"
kli delegate confirm --name "$delegator" --alias delegator --interact -Y &
PID_LIST+=" $!"
wait $PID_LIST
kli ends add --name "$delegate" --alias delegate --eid "$delegate_witness_aid" --role mailbox
delegate_aid=$(kli aid --name "$delegate" --alias delegate)
delegate_oobi=$(kli oobi generate --name "$delegate" --alias delegate --role witness | tail -n 1)
echo "--------------------------------"
echo "Delegate kevers from delegator, note showing 'Anchored'"
echo "--------------------------------"
kli kevers --name "$delegator" --prefix "$delegate_aid"
echo "--------------------------------"
echo "Delegate kevers from delegate, note showing 'Anchored'"
echo "--------------------------------"
kli kevers --name "$delegate" --prefix "$delegate_aid"
echo "--------------------------------"
echo "Delegate kevers from delegate witness, note showing 'Not anchored'"
echo "--------------------------------"
kli kevers --name "$delegate_witness" --prefix "$delegate_aid"
apispec==6.10.0
attrs==25.4.0
blake3==1.0.8
cbor2==5.8.0
cffi==2.0.0
cryptography==46.0.5
falcon==4.2.0
hio==0.6.14
hjson==3.1.0
http_sfv==0.9.9
jsonschema==4.26.0
jsonschema-specifications==2025.9.1
keri==1.2.12
lmdb==1.7.5
mnemonic==0.21
msgpack==1.1.2
multicommand==1.0.0
multidict==6.7.1
ordered-set==4.1.0
packaging==26.0
prettytable==3.17.0
pycparser==3.0
pysodium==0.7.18
PyYAML==6.0.3
qrcode==8.2
referencing==0.37.0
rpds-py==0.30.0
semver==3.0.4
typing_extensions==4.15.0
wcwidth==0.6.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment