public Task <CreateTransactionResponse> GetDestroyTransaction(BitcoinAddress bitcoinAddres, decimal modelAmount, IAsset asset, Guid transactionId)
        {
            return(Retry.Try(async() =>
            {
                var context = new TransactionBuildContext(_connectionParams.Network, _pregeneratedOutputsQueueFactory);

                return await context.Build(async() =>
                {
                    var builder = new TransactionBuilder();

                    var assetId = new BitcoinAssetId(asset.BlockChainAssetId, _connectionParams.Network).AssetId;
                    var coins =
                        (await _bitcoinOutputsService.GetColoredUnspentOutputs(bitcoinAddres.ToString(), assetId)).ToList();

                    builder.SetChange(bitcoinAddres, ChangeType.Colored);
                    builder.AddCoins(coins);

                    var assetMoney = new AssetMoney(assetId, modelAmount, asset.MultiplierPower);

                    var changeAddress = BitcoinAddress.Create(_baseSettings.ChangeAddress, _connectionParams.Network);

                    _transactionBuildHelper.SendAssetWithChange(builder, context, coins, changeAddress, assetMoney, bitcoinAddres);

                    await _transactionBuildHelper.AddFee(builder, context);

                    var tx = builder.BuildTransaction(true);

                    uint markerPosition;
                    var colorMarker = ColorMarker.Get(tx, out markerPosition);

                    for (var i = 0; i < colorMarker.Quantities.Length; i++)
                    {
                        if ((long)colorMarker.Quantities[i] == assetMoney.Quantity &&
                            tx.Outputs[i + 1].ScriptPubKey.GetDestinationAddress(_connectionParams.Network) == changeAddress)
                        {
                            colorMarker.Quantities[i] = 0;
                            break;
                        }
                    }

                    tx.Outputs[markerPosition].ScriptPubKey = colorMarker.GetScript();

                    await SaveSpentOutputs(transactionId, tx);

                    await _signRequestRepository.InsertTransactionId(transactionId);

                    await SaveNewOutputs(transactionId, tx, context);

                    return new CreateTransactionResponse(tx.ToHex(), transactionId);
                });
            }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log));
        }
            private TxOut EnsureMarkerInserted()
            {
                uint position;

                if (ColorMarker.Get(Transaction, out position) != null)
                {
                    return(Transaction.Outputs[position]);
                }
                var txout = Transaction.AddOutput(new TxOut()
                {
                    ScriptPubKey = new ColorMarker().GetScript()
                });

                txout.Value = Money.Zero;
                return(txout);
            }
        private ICoin FindCoin(Transaction tr, string multisig, string walletRedeemScript, decimal amount, IAsset asset)
        {
            if (OpenAssetsHelper.IsBitcoin(asset.Id))
            {
                var money = new Money(amount, MoneyUnit.BTC);
                return(tr.Outputs.AsCoins().FirstOrDefault(o => o.Amount == money &&
                                                           o.ScriptPubKey.GetDestinationAddress(_connectionParams.Network).ToString() == multisig));
            }
            var  assetMoney = new AssetMoney(new BitcoinAssetId(asset.BlockChainAssetId), amount, asset.MultiplierPower);
            uint markerPosition;
            var  marker = ColorMarker.Get(tr, out markerPosition);
            var  found  = tr.Outputs.AsIndexedOutputs()
                          .FirstOrDefault(o => o.TxOut.ScriptPubKey.GetDestinationAddress(_connectionParams.Network)?.ToString() == multisig &&
                                          o.N > markerPosition && marker.Quantities[o.N - markerPosition - 1] == (ulong)assetMoney.Quantity);

            return(found?.ToCoin().ToScriptCoin(new Script(walletRedeemScript)).ToColoredCoin(assetMoney));
        }
Example #4
0
        public void AggregateOutputs(Transaction tr)
        {
            var finalOutputs = new Dictionary <string, TxOut>();

            var marker    = ColorMarker.Get(tr);
            var quantites = new Dictionary <string, ulong>();

            foreach (var trOutput in tr.Outputs.AsIndexedOutputs().Skip(marker == null ? 0 : 1))
            {
                var key = trOutput.TxOut.ScriptPubKey.ToHex();

                if (finalOutputs.ContainsKey(key))
                {
                    finalOutputs[key].Value += trOutput.TxOut.Value;
                    if (marker != null && marker.Quantities.Length >= trOutput.N)
                    {
                        quantites[key] += marker.Quantities[(int)trOutput.N - 1];
                    }
                }
                else
                {
                    finalOutputs[key] = trOutput.TxOut;
                    if (marker != null && marker.Quantities.Length >= trOutput.N)
                    {
                        quantites[key] = marker.Quantities[(int)trOutput.N - 1];
                    }
                }
            }
            tr.Outputs.Clear();

            var outputs = finalOutputs.ToList();

            if (marker != null)
            {
                var newMarker = new ColorMarker();
                newMarker.Quantities = outputs.Select(o => quantites.ContainsKey(o.Key) ? quantites[o.Key] : 0).ToArray();
                tr.Outputs.Add(new TxOut()
                {
                    ScriptPubKey = newMarker.GetScript(),
                    Value        = Money.Zero
                });
            }
            tr.Outputs.AddRange(outputs.Select(o => o.Value));
        }
        public static void DestroyColorCoin(Transaction tr, AssetMoney money, BitcoinAddress destination, Network network)
        {
            if (money == null || money.Quantity <= 0)
            {
                return;
            }
            uint markerPosition;
            var  colorMarker = ColorMarker.Get(tr, out markerPosition);

            for (var i = 0; i < colorMarker.Quantities.Length; i++)
            {
                if ((long)colorMarker.Quantities[i] == money.Quantity &&
                    tr.Outputs[i + 1].ScriptPubKey.GetDestinationAddress(network) == destination)
                {
                    colorMarker.Quantities[i] = 0;
                    break;
                }
            }

            tr.Outputs[markerPosition].ScriptPubKey = colorMarker.GetScript();
        }
Example #6
0
        public async Task <TransactionNinjaModel> GetTransactionAsync(string txId, bool colored = false)
        {
            var relativePath   = String.Format("transactions/{0}", txId);
            var transactionUrl = new Uri(Url, relativePath);

            if (colored)
            {
                var builder = new UriBuilder(transactionUrl);
                builder.Query  = "colored=true";
                transactionUrl = builder.Uri;
            }

            var json = await InvokeMethod(transactionUrl);

            var result          = JsonConvert.DeserializeObject <TransactionNinjaModel>(json);
            var transactionInfo = Transaction.Parse(result.Hex);

            result.IsCoinBase = transactionInfo.IsCoinBase;
            result.IsColor    = transactionInfo.HasValidColoredMarker();

            if (result.IsColor && colored)
            {
                var colorMarker = ColorMarker.Get(transactionInfo);
                result.TransactionUrl = colorMarker.GetMetadataUrl();
            }

            //if(!result.IsColor)
            //{
            //    result.CleanupOutputs();
            //}

            if (result.IsColor && colored == false)
            {
                return(await GetTransactionAsync(txId, true));
            }

            result.CalculateInputsWithReturnedChange();

            return(result);
        }
Example #7
0
        /// <summary>
        /// determine asset ids using order-based coloring method
        /// </summary>
        public static IEnumerable <ICoin> OrderBasedColoringOutputs(Transaction tr, TransactionBuildContext context)
        {
            uint markerPosition;
            var  marker = ColorMarker.Get(tr, out markerPosition);

            if (marker == null)
            {
                return(tr.Outputs.AsCoins());
            }
            List <ICoin> outputsWithAsset = new List <ICoin>();

            var inputAmounts = context.GetAssetAmounts.ToList();
            var inputAssets  = context.GetAssetIds().ToList();


            int inputIndex    = 0;
            int outputIndex   = (int)markerPosition + 1;
            int quantityIndex = 0;

            int issueIndex = 0;

            while (issueIndex < markerPosition && quantityIndex < marker.Quantities.Length)
            {
                var outputAmount = marker.Quantities[quantityIndex];
                if (outputAmount == 0)
                {
                    outputsWithAsset.Add(new Coin(tr, (uint)issueIndex));
                }
                else
                {
                    outputsWithAsset.Add(new Coin(tr, (uint)issueIndex).ToColoredCoin(context.IssuedAssetId, outputAmount));
                }

                issueIndex++;
                quantityIndex++;
            }

            outputsWithAsset.AddRange(tr.Outputs.AsCoins().Skip(issueIndex).Take((int)markerPosition - issueIndex).Where(x => x.Amount != Money.Zero));

            try
            {
                while (inputIndex < context.Coins.Count && outputIndex < tr.Outputs.Count && quantityIndex < marker.Quantities.Length)
                {
                    var outputAmount = (long)marker.Quantities[quantityIndex];
                    if (outputAmount == 0)
                    {
                        outputsWithAsset.Add(new Coin(tr, (uint)outputIndex));
                    }
                    else
                    {
                        long   coverAmount = 0;
                        string assetId     = null;
                        while (coverAmount < outputAmount && inputIndex < context.Coins.Count)
                        {
                            var currentAsset = inputAssets[inputIndex];
                            if (currentAsset != null && currentAsset != assetId && assetId != null)
                            {
                                throw new BackendException("Can't determine assets of outputs", ErrorCode.Exception);
                            }
                            assetId = assetId ?? currentAsset;

                            var amount = Math.Min(outputAmount - coverAmount, inputAmounts[inputIndex]);
                            inputAmounts[inputIndex] -= amount;
                            coverAmount += amount;
                            if (inputAmounts[inputIndex] <= 0)
                            {
                                inputIndex++;
                            }
                        }
                        if (coverAmount < outputAmount)
                        {
                            throw new BackendException("Invalid color marker", ErrorCode.Exception);
                        }
                        var coin = new Coin(tr, (uint)outputIndex);
                        if (assetId != null)
                        {
                            outputsWithAsset.Add(coin.ToColoredCoin(new BitcoinAssetId(assetId, context.Network).AssetId, (ulong)outputAmount));
                        }
                        else
                        {
                            outputsWithAsset.Add(coin);
                        }
                    }
                    outputIndex++;
                    quantityIndex++;
                }
                outputsWithAsset.AddRange(tr.Outputs.AsCoins().Skip(1 + marker.Quantities.Length).Where(x => x.Amount != Money.Zero));
                return(outputsWithAsset);
            }
            catch (BackendException)
            {
                return(new List <ICoin>());
            }
        }
Example #8
0
        public async Task <Core.Domain.Block> GetBlock(string id)
        {
            var blockId = NBitcoin.uint256.Parse(id);

            var blockRecord = await Task.Run <NBitcoin.Block>(() => _client.GetBlock(blockId));

            ConcurrentChain chain;

            if (_chain == null)
            {
                _chain = _client.GetMainChain();
            }

            chain = _chain;

            var confirmed = chain.GetBlock(blockId);

            if (blockRecord == null)
            {
                return(null);
            }

            var blockInformation = new BlockInformation
            {
                BlockId        = confirmed.HashBlock,
                BlockHeader    = confirmed.Header,
                Confirmations  = chain.Tip.Height - confirmed.Height + 1,
                Height         = confirmed.Height,
                MedianTimePast = confirmed.GetMedianTimePast(),
                BlockTime      = confirmed.Header.BlockTime
            };

            var transactionList = new List <Core.Domain.Transaction>();

            foreach (var t in blockRecord.Transactions)
            {
                var transInfo     = _client.GetTransaction(t.GetHash());
                var colored       = NBitcoin.OpenAsset.Extensions.HasValidColoredMarker(t);
                var tranExtraInfo = GetTransactionInfo(transInfo, colored, blockInformation);

                var transJson = Serializer.ToString <GetTransactionResponse>(tranExtraInfo, NBitcoin.Network.TestNet);
                var model     = Serializer.ToObject <TransactionNinjaModel>(transJson, NBitcoin.Network.TestNet);

                if (colored)
                {
                    var colorMarker = ColorMarker.Get(t);
                    model.TransactionUrl = colorMarker.GetMetadataUrl();
                }

                model.CalculateInputsWithReturnedChange();

                var transaction = GetTransaction(model);

                transactionList.Add(transaction);
            }

            var block = new Core.Domain.Block()
            {
                Hash              = id,
                Height            = confirmed.Height,
                Time              = confirmed.Header.BlockTime.UtcDateTime,
                Confirmations     = chain.Tip.Height - confirmed.Height + 1,
                Difficulty        = confirmed.Header.Bits.Difficulty,
                MerkleRoot        = confirmed.Header.HashMerkleRoot.ToString(),
                Nonce             = confirmed.Header.Nonce,
                PreviousBlock     = confirmed.Header.HashPrevBlock.ToString(),
                Transactions      = transactionList,
                TotalTransactions = transactionList.Count
            };

            return(block);
        }