diff options
Diffstat (limited to 'src/ark/exit.js')
| -rw-r--r-- | src/ark/exit.js | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/src/ark/exit.js b/src/ark/exit.js index e2b253f..616c6a1 100644 --- a/src/ark/exit.js +++ b/src/ark/exit.js @@ -18,7 +18,7 @@ import { schnorr, secp256k1 } from '@noble/curves/secp256k1'; import { concatBytes } from './proto.js'; import { pubkeyPolicyTaproot, txid } from './send.js'; -import { vtxoTransactions, harkLeafTaproot, tapLeafHash, taprootScriptSighash } from './refresh.js'; +import { vtxoTransactions, harkLeafTaproot, harkUnlockWitnessShape, tapLeafHash, taprootScriptSighash } from './refresh.js'; const u16le = (n) => Uint8Array.of(n & 0xff, (n >> 8) & 0xff); const u32le = (n) => Uint8Array.of(n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, (n >>> 24) & 0xff); @@ -57,8 +57,16 @@ export function serializeTxW(tx, witnesses) { // The vtxo's chain as broadcastable transactions, oldest first. // Throws if any transition lacks its signature (an unsigned chain can't exit). -export function signedExitTxs(vtxo, serverPub) { - const items = vtxoTransactions(vtxo, serverPub); +export const signedExitTxs = (vtxo, serverPub) => exitChain(vtxo, serverPub, false); + +// Just the vsize of each hop's transaction, with the same "can this chain +// exit at all" checks — but no elliptic-curve work: the output keys are +// stand-ins of the right length. For fee estimates only; nothing here is +// broadcastable. +export const exitTxVsizes = (vtxo, serverPub) => exitChain(vtxo, serverPub, true).map((t) => t.vsize); + +function exitChain(vtxo, serverPub, sizeOnly) { + const items = vtxoTransactions(vtxo, serverPub, sizeOnly); return items.map((it, i) => { const t = vtxo.genesis[i].transition; let witness; @@ -70,14 +78,20 @@ export function signedExitTxs(vtxo, serverPub) { throw new Error('vtxo chain is missing its unlock preimage — cannot exit'); } const preimage = hex.decode(t.unlock.preimage); - const tp = harkLeafTaproot(hex.decode(t.userPubkey), serverPub, vtxo.expiryHeight, sha256(preimage)); - const cb = concatBytes(Uint8Array.of(0xc0 | tp.outputParity), tp.internalXOnly, tp.expiryLeaf); - witness = [hex.decode(t.signature), preimage, tp.unlockScript, cb]; + if (sizeOnly) { + const shape = harkUnlockWitnessShape(sha256(preimage)); + witness = [hex.decode(t.signature), preimage, shape.unlockScript, shape.controlBlock]; + } else { + const tp = harkLeafTaproot(hex.decode(t.userPubkey), serverPub, vtxo.expiryHeight, sha256(preimage)); + const cb = concatBytes(Uint8Array.of(0xc0 | tp.outputParity), tp.internalXOnly, tp.expiryLeaf); + witness = [hex.decode(t.signature), preimage, tp.unlockScript, cb]; + } } else { throw new Error('unsupported genesis transition: ' + t.type); } - const idInternal = txid(it.tx); const { raw, vsize } = serializeTxW(it.tx, [witness]); + if (sizeOnly) return { vsize }; + const idInternal = txid(it.tx); return { txid: hex.encode(idInternal.slice().reverse()), txidInternal: idInternal, |
