예제 #1
0
        private async Task <PSBT> SignPSBT(PSBT psbt, NRustLightningNetwork network)
        {
            var repo        = _repositoryProvider.GetRepository(network);
            var outpoints   = psbt.Inputs.Select(txIn => txIn.PrevOut);
            var signingKeys = new List <Key>();

            await foreach (var(desc, i) in repo.GetSpendableOutputDescriptors(outpoints).Select((x, i) => (x, i)))
            {
                if (desc is null)
                {
                    // We don't have any information in repo. This probably means the UTXO is not LN-origin
                    // (i.e. those are the funds user provided by on-chain)
                    continue;
                }
                switch (desc)
                {
                case SpendableOutputDescriptor.StaticOutput _:
                    // signature for this input will be generated by Destination key (see below).
                    // so no need for any operation.
                    break;

                case SpendableOutputDescriptor.DynamicOutputP2WSH p2wshOutput:
                {
                    var(param1, param2) = p2wshOutput.Item.KeyDerivationParams.ToValueTuple();
                    var amountSat         = (ulong)p2wshOutput.Item.Output.Value.Satoshi;
                    var channelKeys       = _keysRepository.DeriveChannelKeys(amountSat, param1, param2);
                    var delayedPaymentKey = Generators.derivePrivKey(_secp256k1Ctx,
                                                                     channelKeys.DelayedPaymentBaseKey, p2wshOutput.Item.PerCommitmentPoint.PubKey);
                    var toSelfDelay            = p2wshOutput.Item.ToSelfDelay;
                    var revokeableRedeemScript =
                        _keysRepository.GetRevokeableRedeemScript(p2wshOutput.Item.RemoteRevocationPubKey,
                                                                  toSelfDelay, delayedPaymentKey.PubKey);
                    Debug.Assert(
                        p2wshOutput.Item.Output.ScriptPubKey.Equals(revokeableRedeemScript.WitHash.ScriptPubKey));
                    psbt.AddScripts(revokeableRedeemScript);
                    psbt.Inputs[i].SetSequence(toSelfDelay);
                    signingKeys.Add(delayedPaymentKey);
                    break;
                }

                case SpendableOutputDescriptor.StaticOutputRemotePayment remoteOutput:
                {
                    var(p1, p2) = remoteOutput.Item.KeyDerivationParams.ToValueTuple();
                    var amountSat = (ulong)remoteOutput.Item.Output.Value;
                    var keys      = _keysRepository.DeriveChannelKeys(amountSat, p1, p2);
                    Debug.Assert(
                        keys.PaymentKey.PubKey.WitHash.ScriptPubKey.Equals(remoteOutput.Item.Output.ScriptPubKey));
                    signingKeys.Add(keys.PaymentKey);
                    break;
                }

                default:
                    throw new Exception($"Unreachable! Unknown output descriptor type {desc}");
                }
            }

            // sign for user provided on-chain funds utxos.
            if (BaseXPrivs.TryGetValue(network, out var xpriv))
            {
                psbt.SignAll(ScriptPubKeyType.Segwit, xpriv);
            }

            // sign for static-outputs. Which RL gave us as a result of off-chain balance handling.
            var destinationKey = _keysRepository.GetDestinationKey();

            psbt.SignWithKeys(destinationKey);

            // sign with other keys which we have saved in repo.
            foreach (var sk in signingKeys)
            {
                psbt.SignWithKeys(sk);
            }

            return(psbt);
        }