1import{l as u,s as l}from"../chunks/nSm94fJ8.js";import"../chunks/Ml5Nij3X.js";import{f as r,s as a,a as d,b as h,n as k}from"../chunks/BCIWmdPb.js";import{M as v}from"../chunks/Cgcgaten.js";import{T as g}from"../chunks/-gH2OSDE.js";import{S as f}from"../chunks/CdGjDYbZ.js";const s={title:"Leaders & Delegators",description:"How KCC1 coordinates a transition when several covenant instances participate - choosing the right output context, assigning leader and delegator roles by input position, and why delegation is contract-wide.",updated:"2026-08-14T00:00:00.000Z"},{title:O,description:T,updated:S}=s;var y=r(`<p><a href="/learn/covenants/covenant-ids">Covenant IDs</a> give a lineage an identity that consensus tracks. When more than one instance of that lineage is spent in a single transaction, a coordination problem appears that consensus does not solve: every input runs its own script, and each one is asked to approve the same transition.</p> <p>Without a convention, this goes wrong in two directions. Every input redundantly re-validating everything is expensive and easy to make inconsistent. Every input validating only its own slice is worse - each can be individually correct while the group is collectively broken.</p> <p>KCC1 §9 settles both with a convention.</p> <h2 id="picking-the-right-context"><a href="#picking-the-right-context">Picking the right context</a></h2> <p>The <a href="/learn/covenants/covenant-ids#querying-the-structure-from-script">two scopes</a> consensus exposes - local authorized-output, and shared Covenant ID - are not interchangeable. The rule KCC1 states:</p> <blockquote><p>When validation is scoped to one authorizing input, the covenant <strong>must</strong> use that inputâs authorized-output context. When validation is scoped to all participants sharing a Covenant ID, it <strong>must</strong> use the shared Covenant ID output context.</p></blockquote> <p>The failure mode is asymmetric. A covenant that validates only its <em>local</em> authorized outputs, when the protocolâs rule is about the <em>whole</em> covenant group, passes each input individually while the transaction as a whole breaks the invariant. Three inputs each correctly checking their own slice can collectively mint tokens if none checks the total.</p> <p>The reverse mistake - using the shared context for a local rule - is wasteful but not unsound.</p> <h2 id="roles-by-position"><a href="#roles-by-position">Roles by position</a></h2> <p>Rather than have every participant re-derive who is responsible for what, KCC1 assigns roles by position:</p> <blockquote><p>In the shared context for the active Covenant ID, the <strong>first input is the leader</strong> and every later input is a <strong>delegator</strong>. Since the context is ordered by input index, the leader is the lowest-indexed input carrying that Covenant ID. A one-input group has a leader and no delegators.</p></blockquote> <!> <p>The three rules:</p> <ol><li><strong>Position fixes the role.</strong> The first input takes the leader path; every later input takes a delegator path. Each path <strong>must reject the opposite position</strong> - a leader entrypoint running at input 3 must fail, and a delegator entrypoint running at input 0 must fail.</li> <li><strong>The leader validates the complete shared transition</strong> - participant and continuation cardinality, coverage, and authentication of every program, template, or state that validation relies on.</li> <li><strong>Each delegator validates any protocol-specific local conditions</strong> needed to rely safely on the leader.</li></ol> <p>Membership needs no separate check when the active Covenant ID comes from the active input: the shared context includes that input by definition.</p> <h2 id="what-the-checks-look-like"><a href="#what-the-checks-look-like">What the checks look like</a></h2> <p>The following is the structure the <a href="/learn/programmability/silverscript">SilverScript</a> compiler generates for a covenant-bound declaration. The leader:</p> <pre class="language-js"><code class="language-js">entry <span class="token function">__leader_transition</span><span class="token punctuation">(</span><span class="token parameter">State<span class="token punctuation">[</span><span class="token punctuation">]</span> new_states<span class="token punctuation">,</span> sig leader_sig</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> 2 byte<span class="token punctuation">[</span><span class="token number">32</span><span class="token punctuation">]</span> cov_id <span class="token operator">=</span> <span class="token function">OpInputCovenantId</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>activeInputIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> 3 4 int in_count <span class="token operator">=</span> <span class="token function">OpCovInputCount</span><span class="token punctuation">(</span>cov_id<span class="token punctuation">)</span><span class="token punctuation">;</span> 5 int out_count <span class="token operator">=</span> <span class="token function">OpCovOutputCount</span><span class="token punctuation">(</span>cov_id<span class="token punctuation">)</span><span class="token punctuation">;</span> 6 <span class="token function">require</span><span class="token punctuation">(</span>out_count <span class="token operator">==</span> new_states<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> 7 8 <span class="token comment">// k = 0 must be this input, or we are not the leader</span> 9 <span class="token function">require</span><span class="token punctuation">(</span><span class="token function">OpCovInputIdx</span><span class="token punctuation">(</span>cov_id<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">this</span><span class="token punctuation">.</span>activeInputIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> 10 11 <span class="token comment">// gather every participating input's prior state</span>
12 State<span class="token punctuation">[</span><span class="token punctuation">]</span> prev_states <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> 13 <span class="token keyword">for</span> <span class="token punctuation">(</span>k<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> in_count<span class="token punctuation">,</span> max_ins<span class="token punctuation">)</span> <span class="token punctuation">{</span> 14 int in_idx <span class="token operator">=</span> <span class="token function">OpCovInputIdx</span><span class="token punctuation">(</span>cov_id<span class="token punctuation">,</span> k<span class="token punctuation">)</span><span class="token punctuation">;</span> 15 prev_states <span class="token operator">=</span> prev_states<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token function">readInputState</span><span class="token punctuation">(</span>in_idx<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 16 <span class="token punctuation">}</span> 17 18 <span class="token function">__policy</span><span class="token punctuation">(</span>prev_states<span class="token punctuation">,</span> new_states<span class="token punctuation">,</span> leader_sig<span class="token punctuation">)</span><span class="token punctuation">;</span> 19 20 <span class="token comment">// validate every continuation output</span> 21 <span class="token keyword">for</span> <span class="token punctuation">(</span>k<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> out_count<span class="token punctuation">,</span> max_outs<span class="token punctuation">)</span> <span class="token punctuation">{</span> 22 <span class="token function">validateOutputState</span><span class="token punctuation">(</span><span class="token function">OpCovOutputIdx</span><span class="token punctuation">(</span>cov_id<span class="token punctuation">,</span> k<span class="token punctuation">)</span><span class="token punctuation">,</span> new_states<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 23 <span class="token punctuation">}</span> 24<span class="token punctuation">}</span></code></pre> <p>The delegator is much smaller:</p> <pre class="language-js"><code class="language-js">entry <span class="token function">__delegate_transition</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> 25 byte<span class="token punctuation">[</span><span class="token number">32</span><span class="token punctuation">]</span> cov_id <span class="token operator">=</span> <span class="token function">OpInputCovenantId</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>activeInputIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> 26 <span class="token comment">// must NOT be the leader position</span> 27 <span class="token function">require</span><span class="token punctuation">(</span><span class="token function">OpCovInputIdx</span><span class="token punctuation">(</span>cov_id<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>activeInputIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> 28<span class="token punctuation">}</span></code></pre> <!> <p>The delegator does not verify the policy - it verifies that <strong>the input at position 0 was obliged to</strong>. Since every inputâs script must succeed for the transaction to be valid, and input 0 can only succeed by running the full leader validation, the delegatorâs one check is sufficient.</p> <h2 id="why-delegation-is-contract-wide"><a href="#why-delegation-is-contract-wide">Why delegation is contract-wide</a></h2> <p>KCC1 does not spell out the following issue, but SilverScriptâs design notes do, and it explains a compiler restriction.</p> <p>A generated delegate authenticates the <em>contract</em> at input 0, but it <strong>cannot tell which entrypoint that input selected</strong>. If the same contract also exposed an authorized-output-bound entrypoint, that entrypoint could occupy input 0 - satisfying every delegatorâs check - while never validating the complete covenant group.</p> <p>The delegators would all defer to a leader that was not actually acting as one.</p> <p>SilverScript therefore rejects contracts that mix authorized-output-bound and covenant-bound declarations: any contract with a covenant-bound declaration is a <strong>leader contract</strong>, and all its covenant declarations must be covenant-bound. A hand-written entrypoint in a leader contract must explicitly pick one of three roles:</p> <ol><li>reject shared execution entirely, by requiring <code>OpCovInputCount(cov_id) == 1</code>;</li> <li>act as a delegate, by rejecting covenant input 0; or</li> <li>act as a leader, by requiring covenant input 0 and validating the complete group.</li></ol> <p>The compiler cannot verify hand-written covenant-group logic, so it requires an explicit acknowledgment attribute instead of silently trusting it.</p> <h2 id="single-group-enforcement"><a href="#single-group-enforcement">Single-group enforcement</a></h2> <p>
28A covenant using the local authorized-output context can additionally require that its Covenant ID has exactly one continuation group in the transaction:</p> <pre class="language-js"><code class="language-js">byte<span class="token punctuation">[</span><span class="token number">32</span><span class="token punctuation">]</span> cov_id <span class="token operator">=</span> <span class="token function">OpInputCovenantId</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>activeInputIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> 29<span class="token function">require</span><span class="token punctuation">(</span><span class="token function">OpCovOutputCount</span><span class="token punctuation">(</span>cov_id<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token function">OpAuthOutputCount</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>activeInputIndex<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre> <p>This requires that every output carrying the covenantâs ID is authorized by this input. Without it, a transaction could contain several independent authorization groups for the same covenant, each locally valid.</p> <p>No separate validity check on <code>cov_id</code> is needed - <code>OpCovOutputCount</code> fails if the value is not valid covenant-id data.</p> <h2 id="next"><a href="#next">Next</a></h2> <p><a href="/learn/covenants/control-principals">Control Principals</a> - KCC2, and how an ABI declares who controls a covenant.</p> <h2 id="references"><a href="#references">References</a></h2> <ul><li><a href="https://github.com/kaspanet/kccs/pull/3" rel="noopener noreferrer" target="_blank">KCC1 §9 - ID-Aware Transitions and Roles</a></li> <li><a href="/learn/covenants/covenant-ids">Covenant IDs & Bindings</a> - the consensus layer this builds on</li> <li><a href="/learn/covenants/opcodes">Covenant Opcodes</a></li></ul>`,1);function q(e,o){const p=u(o,["children","$$slots","$$events","$$legacy"]);v(e,l(()=>p,()=>s,{children:(i,m)=>{var n=y(),t=a(d(n),22);g(t,{label:"shared transition",inputsLabel:"Inputs (covenant A)",outputsLabel:"Outputs (covenant A)",inputs:[{title:"Input 0 - LEADER",subtitle:"lowest index carrying covenant A",kind:"covenant",badge:"amount 400",lines:["validates the entire transition"]},{title:"Input 1 - delegator",subtitle:"joins the leaderâs transition",kind:"covenant",badge:"amount 600",lines:["checks only that it is not input 0"]}],outputs:[{title:"Output 0",subtitle:"covenant binding â A",kind:"covenant",badge:"amount 1000",lines:["validated by the leader"]}],note:"Every participating input takes the role fixed by its position. Each path must reject the opposite position.",caption:"A merge: two token UTXOs consolidated into one. Only input 0 does the real work."});var c=a(t,18);f(c,{stackLabel:"What each input proves",caption:"The delegator's single check is what makes the division safe: it guarantees a leader exists at position 0 and that this input is not it.",steps:[{op:"input 0 runs __leader_transition",note:"reads all inputs, runs policy, validates all outputs",stack:["complete transition validated"]},{op:"input 1 runs __delegate_transition",note:"confirms it is not at covenant-input position 0",stack:["deferred to leader"]},{op:"consensus",note:"both inputs must succeed for the tx to be valid",stack:["transition accepted"]}]}),k(34),h(i,n)},$$slots:{default:!0}}))}export{q as component};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.