Пример #1
0
 private TaprootFullPubKey(ECXOnlyPubKey outputKey, bool outputParity, TaprootInternalPubKey internalKey, uint256?merkleRoot) : base(outputKey)
 {
     OutputKey       = new TaprootPubKey(outputKey);
     OutputKeyParity = outputParity;
     InternalKey     = internalKey;
     MerkleRoot      = merkleRoot;
 }
Пример #2
0
        public void ReadTLV(TLVReader reader, Network network)
        {
            if (reader.ReadU16() != TLVType)
            {
                throw new FormatException("Invalid TLV type for sign");
            }
            ContractId = reader.ReadUInt256();
            CetSigs    = CetSigs.ParseFromTLV(reader);

            using (var r = reader.StartReadRecord())
            {
                if (r.Type != FundingSignaturesTLVType)
                {
                    throw new FormatException("Invalid TLV type for funding signatures");
                }
                FundingSigs = new List <WitScript>();
                var witnesses = r.ReadU16();
                for (int i = 0; i < witnesses; i++)
                {
                    var elementsCount = reader.ReadU16();
                    var witnessBytes  = new byte[elementsCount][];
                    for (int y = 0; y < elementsCount; y++)
                    {
                        var elementSize = reader.ReadU16();
                        witnessBytes[y] = new byte[elementSize];
                        r.ReadBytes(witnessBytes[y]);
                    }
                    FundingSigs.Add(new WitScript(witnessBytes));
                }
            }
        }
Пример #3
0
 public static TaprootKeyPair CreateTaprootPair(Key key, uint256?merkleRoot)
 {
     if (key is null)
     {
         throw new ArgumentNullException(nameof(key));
     }
     return(new TaprootKeyPair(key, key.PubKey.GetTaprootFullPubKey(merkleRoot)));
 }
 public TaprootExecutionData(int inputIndex, uint256?tapleaf)
 {
     if (inputIndex < 0)
     {
         throw new ArgumentOutOfRangeException(nameof(inputIndex));
     }
     InputIndex  = inputIndex;
     HashVersion = tapleaf is null ? HashVersion.Taproot : HashVersion.Tapscript;
     TapleafHash = tapleaf;
 }
Пример #5
0
 public SmartTransaction(Transaction transaction, uint height, uint256?blockHash = null, int blockIndex = 0, bool isReplacement = false, DateTimeOffset firstSeen = default)
 {
     Transaction = transaction;
     Transaction.PrecomputeHash(false, true);
     Height        = height;
     BlockHash     = blockHash;
     BlockIndex    = blockIndex;
     FirstSeen     = firstSeen == default ? DateTimeOffset.UtcNow : firstSeen;
     IsReplacement = isReplacement;
 }
        public bool CheckTapTweak(TaprootInternalPubKey internalPubKey, uint256?merkleRoot, bool parity)
        {
            if (internalPubKey is null)
            {
                throw new ArgumentNullException(nameof(internalPubKey));
            }

            Span <byte> tweak32 = stackalloc byte[32];

            TaprootFullPubKey.ComputeTapTweak(internalPubKey, merkleRoot, tweak32);
            return(this.pubkey.CheckIsTweakedWith(internalPubKey.pubkey, tweak32, parity));
        }
Пример #7
0
 internal static void ComputeTapTweak(TaprootInternalPubKey internalKey, uint256?merkleRoot, Span <byte> tweak32)
 {
     using Secp256k1.SHA256 sha = new Secp256k1.SHA256();
     sha.InitializeTagged("TapTweak");
     internalKey.pubkey.WriteToSpan(tweak32);
     sha.Write(tweak32);
     if (merkleRoot is uint256)
     {
         merkleRoot.ToBytes(tweak32);
         sha.Write(tweak32);
     }
     sha.GetHash(tweak32);
 }
Пример #8
0
        public static TaprootFullPubKey Create(TaprootInternalPubKey internalKey, uint256?merkleRoot)
        {
            if (internalKey is null)
            {
                throw new ArgumentNullException(nameof(internalKey));
            }
            Span <byte> tweak32 = stackalloc byte[32];

            ComputeTapTweak(internalKey, merkleRoot, tweak32);
            var outputKey = internalKey.pubkey.AddTweak(tweak32).ToXOnlyPubKey(out var parity);

            return(new TaprootFullPubKey(outputKey, parity, internalKey, merkleRoot));
        }
Пример #9
0
        private async Task <Repository.DLCState> GetDLC(uint256?contractId)
        {
            if (contractId is null)
            {
                // TODO: Allow to pass a hint via command line
                throw new CommandException("signed", "This accept message does not match any of our DLC");
            }
            else
            {
                var dlc = await Repository.GetDLC(contractId);

                if (dlc is null)
                {
                    throw new CommandException("signed", "This accept message does not match any of our DLC");
                }
                return(dlc);
            }
        }
Пример #10
0
        public SmartTransaction(Transaction transaction, Height height, uint256?blockHash = null, int blockIndex = 0, SmartLabel?label = null, bool isReplacement = false, DateTimeOffset firstSeen = default)
        {
            Transaction = transaction;

            // Because we don't modify those transactions, we can cache the hash
            Transaction.PrecomputeHash(false, true);

            Label = label ?? SmartLabel.Empty;

            Height     = height;
            BlockHash  = blockHash;
            BlockIndex = blockIndex;

            FirstSeen = firstSeen == default ? DateTimeOffset.UtcNow : firstSeen;

            IsReplacement = isReplacement;
            WalletInputs  = new HashSet <SmartCoin>(Transaction.Inputs.Count);
            WalletOutputs = new HashSet <SmartCoin>(Transaction.Outputs.Count);
        }
Пример #11
0
        public TaprootSignature SignTaprootKeySpend(uint256 hash, uint256?merkleRoot, uint256?aux, TaprootSigHash sigHash)
        {
            if (hash == null)
            {
                throw new ArgumentNullException(nameof(hash));
            }
            AssertNotDisposed();
            var eckey = _ECKey;

            if (PubKey.Parity)
            {
                eckey = new Secp256k1.ECPrivKey(_ECKey.sec.Negate(), _ECKey.ctx, true);
            }
            Span <byte> buf = stackalloc byte[32];

            TaprootFullPubKey.ComputeTapTweak(PubKey.TaprootInternalKey, merkleRoot, buf);
            eckey = eckey.TweakAdd(buf);
            hash.ToBytes(buf);
            var sig = aux?.ToBytes() is byte[] auxbytes?eckey.SignBIP340(buf, auxbytes) : eckey.SignBIP340(buf);

            return(new TaprootSignature(new SchnorrSignature(sig), sigHash));
        }
Пример #12
0
        public void ReadTLV(TLVReader reader, Network network)
        {
            if (reader.ReadU16() != TLVType)
            {
                throw new FormatException("Invalid TLV type for accept");
            }
            TemporaryContractId = reader.ReadUInt256();
            TotalCollateral     = Money.Satoshis(reader.ReadU64());
            PubKeys             = new PubKeyObject();
            var pk = new byte[33];

            reader.ReadBytes(pk);
            PubKeys.FundingKey    = new PubKey(pk, true);
            PubKeys.PayoutAddress = reader.ReadScript().GetDestinationAddress(network);
            var inputLen = reader.ReadU16();

            FundingInputs = new FundingInput[inputLen];
            for (int i = 0; i < inputLen; i++)
            {
                FundingInputs[i] = FundingInput.ParseFromTLV(reader, network);
            }
            ChangeAddress = reader.ReadScript().GetDestinationAddress(network);
            CetSigs       = CetSigs.ParseFromTLV(reader);
        }
 public TaprootFullPubKey GetTaprootFullPubKey(uint256?merkleRoot)
 {
     return(TaprootFullPubKey.Create(this, merkleRoot));
 }
 public bool VerifyTaproot(uint256 hash, uint256?merkleRoot, SchnorrSignature signature)
 {
     return(this.GetTaprootFullPubKey(merkleRoot).OutputKey.VerifySignature(hash, signature));
 }
Пример #15
0
    /// <inheritdoc />
    public override uint256?ReadJson(JsonReader reader, Type objectType, uint256?existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        string?value = (string?)reader.Value;

        return(value is null ? default : new uint256(value));
    }
Пример #16
0
        public async Task <(PaymentReceivedType, LNMoney)> PaymentReceived(Primitives.PaymentHash paymentHash, LNMoney amount, uint256?secret = null)
        {
            var tx = await _engine.OpenTransaction();

            using var invoiceRow = await tx.GetTable(DBKeys.HashToInvoice).Get(paymentHash.ToBytes(false));

            if (invoiceRow != null)
            {
                var res = PaymentRequest.Parse(await invoiceRow.ReadValueString());
                if (res.IsError)
                {
                    throw new NRustLightningException($"Failed to read payment request for {res.ErrorValue}");
                }
                var req = res.ResultValue;
                if (req.AmountValue is null)
                {
                    return(PaymentReceivedType.Ok, amount);
                }

                var intendedAmount = req.AmountValue.Value;
                if (amount.MilliSatoshi < intendedAmount.MilliSatoshi)
                {
                    return(PaymentReceivedType.AmountTooLow, intendedAmount);
                }

                if (intendedAmount.MilliSatoshi * 2 < amount.MilliSatoshi)
                {
                    return(PaymentReceivedType.AmountTooHigh, intendedAmount);
                }

                return(PaymentReceivedType.Ok, intendedAmount);
            }
            return(PaymentReceivedType.UnknownPaymentHash, amount);
        }
Пример #17
0
 public TaprootFullPubKey GetTaprootFullPubKey(uint256?merkleRoot)
 {
     return(TaprootInternalKey.GetTaprootFullPubKey(merkleRoot));
 }
Пример #18
0
        public static InputRoundSignaturePair CreateInputRoundSignaturePair(Key?key = null, uint256?roundHash = null)
        {
            var rh = roundHash ?? BitcoinFactory.CreateUint256();

            if (key is null)
            {
                using Key k = new();
                return(new InputRoundSignaturePair(
                           BitcoinFactory.CreateOutPoint(),
                           k.SignCompact(rh)));
            }
            else
            {
                return(new InputRoundSignaturePair(
                           BitcoinFactory.CreateOutPoint(),
                           key.SignCompact(rh)));
            }
        }
Пример #19
0
 /// <inheritdoc />
 public override void WriteJson(JsonWriter writer, uint256?value, JsonSerializer serializer)
 {
     writer.WriteValue(value?.ToString());
 }
Пример #20
0
        public void ReadTLV(TLVReader reader, Network network)
        {
            if (reader.ReadU16() != TLVType)
            {
                throw new FormatException("Invalid TLV type for offer");
            }
            reader.ReadByte();             // contract_flags
            ChainHash = reader.ReadUInt256();
            if (network.GenesisHash != network.GenesisHash)
            {
                throw new FormatException("Invalid ChainHash");
            }
            Span <byte> buf = stackalloc byte[64];

            using (var ciRecord = reader.StartReadRecord())
            {
                if (ciRecord.Type != TLVContractInfoType)
                {
                    throw new FormatException("Invalid TLV type for contract info");
                }
                List <ContractInfo> cis = new List <ContractInfo>();
                while (!ciRecord.IsEnd)
                {
                    ciRecord.ReadBytes(buf.Slice(0, 32));
                    var sats = ciRecord.ReadU64();
                    cis.Add(new Messages.ContractInfo(new DiscreteOutcome(buf.Slice(0, 32).ToArray()), Money.Satoshis(sats)));
                }
                ContractInfo = cis.ToArray();
            }
            using (var oracleRecord = reader.StartReadRecord())
            {
                if (oracleRecord.Type != TLVOracleInfoType)
                {
                    throw new FormatException("Invalid TLV type for oracle info");
                }
                oracleRecord.ReadBytes(buf.Slice(0, 64));
                OracleInfo = OracleInfo.Create(buf);
            }
            PubKeys = new PubKeyObject();
            reader.ReadBytes(buf.Slice(0, 33));
            PubKeys.FundingKey    = new PubKey(buf.Slice(0, 33).ToArray());
            PubKeys.PayoutAddress = reader.ReadScript().GetDestinationAddress(network);
            if (PubKeys.PayoutAddress is null)
            {
                throw new FormatException("Invalid script");
            }
            TotalCollateral = Money.Satoshis(reader.ReadU64());
            var fiCount             = reader.ReadU16();
            List <FundingInput> fis = new List <FundingInput>();

            while (fiCount > 0)
            {
                fis.Add(FundingInput.ParseFromTLV(reader, network));
                fiCount--;
            }
            FundingInputs = fis.ToArray();
            ChangeAddress = reader.ReadScript().GetDestinationAddress(network);
            if (ChangeAddress is null)
            {
                throw new FormatException("Invalid script");
            }
            FeeRate  = new FeeRate(Money.Satoshis(reader.ReadU64()), 1);
            Timeouts = new Timeouts()
            {
                ContractMaturity = reader.ReadU32(),
                ContractTimeout  = reader.ReadU32()
            };
        }
Пример #21
0
        public static InputRoundSignaturePair CreateInputRoundSignaturePair(Key?key = null, uint256?roundHash = null)
        {
            var rh       = roundHash ?? BitcoinFactory.CreateUint256();
            var outpoint = BitcoinFactory.CreateOutPoint();
            var coinJoinInputCommitmentData = new CoinJoinInputCommitmentData("CoinJoinCoordinatorIdentifier", rh);

            var signingKey = key ?? new();

            return(new InputRoundSignaturePair(
                       outpoint,
                       OwnershipProof.GenerateCoinJoinInputProof(signingKey, coinJoinInputCommitmentData).ToBytes()));
        }
Пример #22
0
        public static InputRoundSignaturePair[] CreateInputRoundSignaturePairs(int count, uint256?roundHash = null)
        {
            List <InputRoundSignaturePair> pairs = new();

            for (int i = 0; i < count; i++)
            {
                pairs.Add(CreateInputRoundSignaturePair(null, roundHash));
            }

            return(pairs.ToArray());
        }
Пример #23
0
 public static IEnumerable <InputRoundSignaturePair> CreateInputRoundSignaturePairs(int count, uint256?roundHash = null)
 {
     for (int i = 0; i < count; i++)
     {
         yield return(CreateInputRoundSignaturePair(null, roundHash));
     }
 }
Пример #24
0
        public static InputRoundSignaturePair[] CreateInputRoundSignaturePairs(IEnumerable <Key> keys, uint256?roundHash = null)
        {
            List <InputRoundSignaturePair> pairs = new();

            foreach (var key in keys)
            {
                pairs.Add(CreateInputRoundSignaturePair(key, roundHash));
            }
            return(pairs.ToArray());
        }
Пример #25
0
 public TaprootSignature SignTaprootKeySpend(uint256 hash, uint256?merkleRoot, TaprootSigHash sigHash)
 {
     return(SignTaprootKeySpend(hash, merkleRoot, null, sigHash));
 }
Пример #26
0
        public void Synchronize()
        {
            Task.Run(async() =>
            {
                try
                {
                    if (Interlocked.Read(ref _workerCount) >= 2)
                    {
                        return;
                    }

                    Interlocked.Increment(ref _workerCount);
                    while (Interlocked.Read(ref _workerCount) != 1)
                    {
                        await Task.Delay(100).ConfigureAwait(false);
                    }

                    if (IsStopping)
                    {
                        return;
                    }

                    try
                    {
                        Interlocked.Exchange(ref _serviceStatus, Running);

                        while (IsRunning)
                        {
                            try
                            {
                                SyncInfo syncInfo = await GetSyncInfoAsync().ConfigureAwait(false);

                                uint currentHeight;
                                uint256?currentHash = null;
                                using (await IndexLock.LockAsync())
                                {
                                    if (Index.Count != 0)
                                    {
                                        var lastIndex = Index[^ 1];
                                        currentHeight = lastIndex.Header.Height;
                                        currentHash   = lastIndex.Header.BlockHash;
                                    }
                                    else
                                    {
                                        currentHash = StartingHeight == 0
                                                                                        ? uint256.Zero
                                                                                        : await RpcClient.GetBlockHashAsync((int)StartingHeight - 1).ConfigureAwait(false);
                                        currentHeight = StartingHeight - 1;
                                    }
                                }

                                var coreNotSynced   = !syncInfo.IsCoreSynchronized;
                                var tipReached      = syncInfo.BlockCount == currentHeight;
                                var isTimeToRefresh = DateTimeOffset.UtcNow - syncInfo.BlockchainInfoUpdated > TimeSpan.FromMinutes(5);
                                if (coreNotSynced || tipReached || isTimeToRefresh)
                                {
                                    syncInfo = await GetSyncInfoAsync().ConfigureAwait(false);
                                }

                                // If wasabi filter height is the same as core we may be done.
                                if (syncInfo.BlockCount == currentHeight)
                                {
                                    // Check that core is fully synced
                                    if (syncInfo.IsCoreSynchronized && !syncInfo.InitialBlockDownload)
                                    {
                                        // Mark the process notstarted, so it can be started again
                                        // and finally block can mark it as stopped.
                                        Interlocked.Exchange(ref _serviceStatus, NotStarted);
                                        return;
                                    }
                                    else
                                    {
                                        // Knots is catching up give it a 10 seconds
                                        await Task.Delay(10000).ConfigureAwait(false);
                                        continue;
                                    }
                                }

                                uint nextHeight        = currentHeight + 1;
                                uint256 blockHash      = await RpcClient.GetBlockHashAsync((int)nextHeight).ConfigureAwait(false);
                                VerboseBlockInfo block = await RpcClient.GetVerboseBlockAsync(blockHash).ConfigureAwait(false);

                                // Check if we are still on the best chain,
                                // if not rewind filters till we find the fork.
                                if (currentHash != block.PrevBlockHash)
                                {
                                    Logger.LogWarning("Reorg observed on the network.");

                                    await ReorgOneAsync().ConfigureAwait(false);

                                    // Skip the current block.
                                    continue;
                                }

                                var scripts = FetchScripts(block);

                                GolombRiceFilter filter;
                                if (scripts.Any())
                                {
                                    filter = new GolombRiceFilterBuilder()
                                             .SetKey(block.Hash)
                                             .SetP(20)
                                             .SetM(1 << 20)
                                             .AddEntries(scripts.Select(x => x.ToCompressedBytes()))
                                             .Build();
                                }
                                else
                                {
                                    // We cannot have empty filters, because there was a bug in GolombRiceFilterBuilder that evaluates empty filters to true.
                                    // And this must be fixed in a backwards compatible way, so we create a fake filter with a random scp instead.
                                    filter = CreateDummyEmptyFilter(block.Hash);
                                }

                                var smartHeader = new SmartHeader(block.Hash, block.PrevBlockHash, nextHeight, block.BlockTime);
                                var filterModel = new FilterModel(smartHeader, filter);

                                await File.AppendAllLinesAsync(IndexFilePath, new[] { filterModel.ToLine() }).ConfigureAwait(false);

                                using (await IndexLock.LockAsync())
                                {
                                    Index.Add(filterModel);
                                }

                                // If not close to the tip, just log debug.
                                if (syncInfo.BlockCount - nextHeight <= 3 || nextHeight % 100 == 0)
                                {
                                    Logger.LogInfo($"Created filter for block: {nextHeight}.");
                                }
                                else
                                {
                                    Logger.LogDebug($"Created filter for block: {nextHeight}.");
                                }
                                LastFilterBuildTime = DateTimeOffset.UtcNow;
                            }
Пример #27
0
 public TaprootKeyPair CreateTaprootKeyPair(uint256?merkleRoot)
 {
     return(TaprootKeyPair.CreateTaprootPair(this, merkleRoot));
 }
Пример #28
0
 public static IEnumerable <InputRoundSignaturePair> CreateInputRoundSignaturePairs(IEnumerable <Key> keys, uint256?roundHash = null)
 {
     foreach (var key in keys)
     {
         yield return(CreateInputRoundSignaturePair(key, roundHash));
     }
 }
        public void Synchronize()
        {
            // Check permissions.
            using var _ = File.Open(IndexFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);

            Task.Run(async() =>
            {
                try
                {
                    if (Interlocked.Read(ref _workerCount) >= 2)
                    {
                        return;
                    }

                    Interlocked.Increment(ref _workerCount);
                    while (Interlocked.Read(ref _workerCount) != 1)
                    {
                        await Task.Delay(100).ConfigureAwait(false);
                    }

                    if (IsStopping)
                    {
                        return;
                    }

                    try
                    {
                        Interlocked.Exchange(ref _serviceStatus, Running);

                        while (IsRunning)
                        {
                            try
                            {
                                SyncInfo syncInfo = await GetSyncInfoAsync().ConfigureAwait(false);

                                uint currentHeight;
                                uint256?currentHash = null;
                                using (await IndexLock.LockAsync())
                                {
                                    if (Index.Count != 0)
                                    {
                                        var lastIndex = Index[^ 1];
                                        currentHeight = lastIndex.Header.Height;
                                        currentHash   = lastIndex.Header.BlockHash;
                                    }
                                    else
                                    {
                                        currentHash = StartingHeight == 0
                                                                                        ? uint256.Zero
                                                                                        : await RpcClient.GetBlockHashAsync((int)StartingHeight - 1).ConfigureAwait(false);
                                        currentHeight = StartingHeight - 1;
                                    }
                                }

                                var coreNotSynced   = !syncInfo.IsCoreSynchronized;
                                var tipReached      = syncInfo.BlockCount == currentHeight;
                                var isTimeToRefresh = DateTimeOffset.UtcNow - syncInfo.BlockchainInfoUpdated > TimeSpan.FromMinutes(5);
                                if (coreNotSynced || tipReached || isTimeToRefresh)
                                {
                                    syncInfo = await GetSyncInfoAsync().ConfigureAwait(false);
                                }

                                // If wasabi filter height is the same as core we may be done.
                                if (syncInfo.BlockCount == currentHeight)
                                {
                                    // Check that core is fully synced
                                    if (syncInfo.IsCoreSynchronized && !syncInfo.InitialBlockDownload)
                                    {
                                        // Mark the process notstarted, so it can be started again
                                        // and finally block can mark it as stopped.
                                        Interlocked.Exchange(ref _serviceStatus, NotStarted);
                                        return;
                                    }
                                    else
                                    {
                                        // Knots is catching up give it a 10 seconds
                                        await Task.Delay(10000).ConfigureAwait(false);
                                        continue;
                                    }
                                }

                                uint nextHeight        = currentHeight + 1;
                                uint256 blockHash      = await RpcClient.GetBlockHashAsync((int)nextHeight).ConfigureAwait(false);
                                VerboseBlockInfo block = await RpcClient.GetVerboseBlockAsync(blockHash).ConfigureAwait(false);

                                // Check if we are still on the best chain,
                                // if not rewind filters till we find the fork.
                                if (currentHash != block.PrevBlockHash)
                                {
                                    Logger.LogWarning("Reorg observed on the network.");

                                    await ReorgOneAsync().ConfigureAwait(false);

                                    // Skip the current block.
                                    continue;
                                }

                                var filter = BuildFilterForBlock(block);

                                var smartHeader = new SmartHeader(block.Hash, block.PrevBlockHash, nextHeight, block.BlockTime);
                                var filterModel = new FilterModel(smartHeader, filter);

                                await File.AppendAllLinesAsync(IndexFilePath, new[] { filterModel.ToLine() }).ConfigureAwait(false);

                                using (await IndexLock.LockAsync())
                                {
                                    Index.Add(filterModel);
                                }

                                // If not close to the tip, just log debug.
                                if (syncInfo.BlockCount - nextHeight <= 3 || nextHeight % 100 == 0)
                                {
                                    Logger.LogInfo($"Created filter for block: {nextHeight}.");
                                }
                                else
                                {
                                    Logger.LogDebug($"Created filter for block: {nextHeight}.");
                                }
                                LastFilterBuildTime = DateTimeOffset.UtcNow;
                            }
Пример #30
0
        public async Task <(PaymentReceivedType, LNMoney)> PaymentReceived(Primitives.PaymentHash paymentHash, LNMoney amount, uint256?secret = null)
        {
            var invoice = await _repository.GetInvoice(paymentHash);

            if (invoice != null)
            {
                if (invoice.AmountValue is null)
                {
                    return(PaymentReceivedType.Ok, amount);
                }

                var intendedAmount = invoice.AmountValue.Value;
                if (amount.MilliSatoshi < intendedAmount.MilliSatoshi)
                {
                    return(PaymentReceivedType.AmountTooLow, intendedAmount);
                }

                if (intendedAmount.MilliSatoshi * 2 < amount.MilliSatoshi)
                {
                    return(PaymentReceivedType.AmountTooHigh, intendedAmount);
                }

                return(PaymentReceivedType.Ok, intendedAmount);
            }
            return(PaymentReceivedType.UnknownPaymentHash, amount);
        }