Exemplo n.º 1
0
        public Transaction Build()
        {
            ulong        toLocalSatoshi    = _channel.LocalCommitmentTxParameters.ToLocalMsat.MSatToSatoshi().CheckedSubtract(_channel.IsFunder ? FeeSatoshi : 0);
            ulong        toRemoteSatoshi   = _channel.LocalCommitmentTxParameters.ToRemoteMsat.MSatToSatoshi().CheckedSubtract(_channel.IsFunder ? 0 : FeeSatoshi);
            List <TxOut> outputs           = new List <TxOut>();
            var          dustLimitSatoshis = Math.Max(_channel.LocalChannelParameters.DustLimitSatoshis, _channel.RemoteChannelParameters.DustLimitSatoshis);

            if (toLocalSatoshi >= dustLimitSatoshis)
            {
                outputs.Add(BuildToLocalOutput(_channel, toLocalSatoshi));
            }

            if (toRemoteSatoshi >= dustLimitSatoshis)
            {
                outputs.Add(BuildToRemoteOutput(_channel, toRemoteSatoshi));
            }

            Transaction tx = Transaction.Create(_networkParameters.Network);

            TxIn txIn = new TxIn(new OutPoint(uint256.Parse(_channel.FundingTransactionId), _channel.FundingOutputIndex));

            txIn.Sequence  = 0xFFFFFFFF;
            txIn.ScriptSig = MultiSignaturePubKey.GenerateMultisigPubKey(_channel.LocalCommitmentTxParameters.FundingKey,
                                                                         _channel.RemoteCommitmentTxParameters.FundingKey).WitHash.ScriptPubKey;

            tx.Inputs.Add(txIn);
            tx.Outputs.AddRange(outputs);
            tx.Outputs.Sort(new Bip69OutputOrdering());
            tx.Version  = 2;
            tx.LockTime = 0;

            return(tx);
        }
        public Transaction Build()
        {
            var   trimmedOfferedHtlcs         = GetTrimmedOfferedHtlcs();
            var   trimmedReceivedHtlcs        = GetTrimmedReceivedHtlcs();
            ulong feeSatoshi                  = CalculateFee(trimmedOfferedHtlcs, trimmedReceivedHtlcs);
            ulong toLocalSatoshi              = CommitmentTxParams.ToLocalMsat.MSatToSatoshi().CheckedSubtract(IsFunder ? feeSatoshi : 0);
            ulong toRemoteSatoshi             = CommitmentTxParams.ToRemoteMsat.MSatToSatoshi().CheckedSubtract(IsFunder ? 0 : feeSatoshi);
            List <(Htlc, TxOut)> htlcTxOutMap = new List <(Htlc, TxOut)>();
            List <TxOut>         outputs      = new List <TxOut>();

            if (toRemoteSatoshi >= ChannelParameters.DustLimitSatoshis)
            {
                outputs.Add(BuildToRemoteOutput(toRemoteSatoshi));
            }

            if (toLocalSatoshi >= ChannelParameters.DustLimitSatoshis)
            {
                outputs.Add(BuildToLocalDelayedOutput(toLocalSatoshi));
            }

            outputs.AddRange(trimmedOfferedHtlcs.Select(htlc =>
            {
                var txOut = BuildOfferedHtlcOutput(htlc);
                htlcTxOutMap.Add((htlc, txOut));
                return(txOut);
            }));

            outputs.AddRange(trimmedReceivedHtlcs.Select(htlc =>
            {
                var txOut = BuildReceivedHtlcOutput(htlc);
                htlcTxOutMap.Add((htlc, txOut));
                return(txOut);
            }));

            ulong obscuredTxNumber = IsFunder
                ? TransactionNumber.CalculateObscured(CommitmentTxParams.TransactionNumber, CommitmentTxParams.PaymentBasepoint, RemotePaymentBasePoint)
                : TransactionNumber.CalculateObscured(CommitmentTxParams.TransactionNumber, RemotePaymentBasePoint, CommitmentTxParams.PaymentBasepoint);
            ulong sequence = TransactionNumber.CalculateSequence(obscuredTxNumber);
            ulong lockTime = TransactionNumber.CalculateLockTime(obscuredTxNumber);

            Transaction tx   = Transaction.Create(Network);
            TxIn        txIn = new TxIn(new OutPoint(uint256.Parse(FundingTransactionHash), FundingTransactionOutputIndex));

            txIn.Sequence  = new Sequence((uint)sequence);
            txIn.ScriptSig = MultiSignaturePubKey.GenerateMultisigPubKey(CommitmentTxParams.FundingKey, RemoteFundingPubKey).WitHash.ScriptPubKey;

            tx.Inputs.Add(txIn);
            tx.Outputs.AddRange(outputs);
            tx.LockTime = new LockTime((uint)lockTime);
            tx.Version  = 2;

            tx.Outputs.Sort(new Bip69OutputOrdering());
            _htlcOutputIndexMap = htlcTxOutMap.ToDictionary(k => k.Item1, v => tx.Outputs.FindIndex(o => o == v.Item2));

            return(_commitmentTransaction = tx);
        }
        public void GenerateScriptPubKeyTest()
        {
            ECKeyPair pubKey1 = new ECKeyPair("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb", false);
            ECKeyPair pubKey2 = new ECKeyPair("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1", false);

            var result = MultiSignaturePubKey.GenerateMultisigPubKey(pubKey1, pubKey2);

            Assert.Equal("5221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae",
                         result.ToBytes().ToHex());
        }
        public TransactionSignature SignCommitmentTransaction(Key fundingPrivateKey, Transaction unsignedCommitmentTransaction = null)
        {
            var unsigned     = unsignedCommitmentTransaction ?? Build();
            var redeemScript = MultiSignaturePubKey.GenerateMultisigPubKey(CommitmentTxParams.FundingKey, RemoteFundingPubKey);
            var input        = unsigned.Inputs[0];
            var inputCoin    = new Coin(input.PrevOut, new TxOut(Money.Satoshis(FundingAmount), input.ScriptSig));
            var scriptCoin   = inputCoin.ToScriptCoin(redeemScript);

            TransactionBuilder builder2 = new TransactionBuilder();

            builder2.AddCoins(scriptCoin);
            builder2.AddKeys(fundingPrivateKey);

            return(unsigned.SignInput(fundingPrivateKey, scriptCoin));
        }
Exemplo n.º 5
0
        public TransactionSignature SignClosingTransaction(Transaction unsignedClosingTx)
        {
            var redeemScript = MultiSignaturePubKey.GenerateMultisigPubKey(_channel.LocalCommitmentTxParameters.FundingKey,
                                                                           _channel.RemoteCommitmentTxParameters.FundingKey);
            var input                   = unsignedClosingTx.Inputs[0];
            var amount                  = _channel.FundingSatoshis;
            var inputCoin               = new Coin(input.PrevOut, new TxOut(Money.Satoshis(amount), input.ScriptSig));
            var scriptCoin              = inputCoin.ToScriptCoin(redeemScript);
            var fundingPrivateKey       = new Key(_channel.LocalCommitmentTxParameters.FundingKey.PrivateKeyData);
            TransactionBuilder builder2 = new TransactionBuilder();

            builder2.AddCoins(scriptCoin);
            builder2.AddKeys(fundingPrivateKey);

            return(unsignedClosingTx.SignInput(fundingPrivateKey, scriptCoin));
        }
Exemplo n.º 6
0
        public FundingTransaction CreateFundingTransaction(ulong amount, ulong feeRate, ECKeyPair pubKey1, ECKeyPair pubKey2)
        {
            var script       = MultiSignaturePubKey.GenerateMultisigPubKey(pubKey1, pubKey2);
            var redeemScript = script.WitHash.ScriptPubKey;
            var unspent      = _blockchainClientService.ListUtxo(1, Int32.MaxValue, _walletService.PubKeyAddress);

            _logger.LogInformation("Transaction Funding: found " + unspent.Count + " UTXO to fund the funding transaction");
            var totalAmount  = (ulong)unspent.Select(u => u.AmountSatoshi).Sum();
            var fee          = TransactionFee.CalculateFee(feeRate, 1000);
            var neededAmount = fee + amount;

            if (neededAmount > totalAmount)
            {
                throw new FundingException($"Not enough funds. Needed at least {neededAmount} Satoshi, but only {totalAmount} Satoshi are available.");
            }

            (Transaction fundingTransaction, List <Coin> inputCoins) = CreateFundingTransactionFromUtxo(amount, unspent, script, feeRate);
            ushort fundingOutputIndex = (ushort)fundingTransaction.Outputs.FindIndex(o => o.ScriptPubKey == redeemScript);

            return(new FundingTransaction(fundingTransaction, fundingOutputIndex, inputCoins, _walletService.PubKeyAddress.ScriptPubKey.ToBytes()));
        }