Exemple #1
0
 public ColoredBalanceChangeEntry(OrderedBalanceChange balanceChange, ColoredTransaction coloredTransaction)
 {
     _Colored = coloredTransaction;
     for (var i = 0; i < balanceChange.SpentIndices.Count; i++)
     {
         var spentIndex = balanceChange.SpentIndices[i];
         var entry      = coloredTransaction.Inputs.FirstOrDefault(o => o.Index == (uint)spentIndex);
         if (entry != null)
         {
             AddSpentCoin(entry.Asset, balanceChange.SpentCoins[(int)i]);
         }
         else
         {
             AddSpentCoin(null, balanceChange.SpentCoins[(int)i]);
         }
     }
     foreach (var coin in balanceChange.ReceivedCoins)
     {
         var entry = coloredTransaction.GetColoredEntry(coin.Outpoint.N);
         if (entry != null)
         {
             AddReceivedCoin(entry.Asset, coin, !coloredTransaction.Issuances.Contains(entry));
         }
         else
         {
             AddReceivedCoin(null, coin, false);
         }
     }
 }
            public Entity(DynamicTableEntity entity)
            {
                var splitted = entity.RowKey.Split(new string[] { "-" }, StringSplitOptions.None);

                _PartitionKey = entity.PartitionKey;
                Timestamp     = entity.Timestamp;
                TxId          = new uint256(splitted[0]);
                Type          = GetType(splitted[1]);
                if (splitted.Length >= 3 && splitted[2] != string.Empty)
                {
                    BlockId = new uint256(splitted[2]);
                }
                var bytes = Helper.GetEntityProperty(entity, "a");

                if (bytes != null && bytes.Length != 0)
                {
                    Transaction = new Transaction();
                    Transaction.ReadWrite(bytes);
                }
                bytes = Helper.GetEntityProperty(entity, "b");
                if (bytes != null && bytes.Length != 0)
                {
                    ColoredTransaction = new ColoredTransaction();
                    ColoredTransaction.ReadWrite(bytes);
                }
                _PreviousTxOuts = Helper.DeserializeList <TxOut>(Helper.GetEntityProperty(entity, "c"));
            }
            public Entity(DynamicTableEntity entity, ConsensusFactory consensusFactory)
            {
                var splitted = entity.RowKey.Split(new string[] { "-" }, StringSplitOptions.None);

                _PartitionKey = entity.PartitionKey;
                Timestamp     = entity.Timestamp;
                TxId          = uint256.Parse(splitted[0]);
                Type          = GetType(splitted[1]);
                if (splitted.Length >= 3 && splitted[2] != string.Empty)
                {
                    BlockId = uint256.Parse(splitted[2]);
                }
                var bytes = Helper.GetEntityProperty(entity, "a");

                if (bytes != null && bytes.Length != 0)
                {
                    Transaction = consensusFactory.CreateTransaction();
                    Transaction.ReadWrite(bytes, consensusFactory);
                }
                bytes = Helper.GetEntityProperty(entity, "b");
                if (bytes != null && bytes.Length != 0)
                {
                    ColoredTransaction = new ColoredTransaction();
                    ColoredTransaction.ReadWrite(bytes, consensusFactory);
                }
                _PreviousTxOuts = Helper.DeserializeList <TxOut>(Helper.GetEntityProperty(entity, "c"), consensusFactory);

                var timestamp = Helper.GetEntityProperty(entity, "d");

                if (timestamp != null && timestamp.Length == 8)
                {
                    Timestamp = new DateTimeOffset((long)ToUInt64(timestamp, 0), TimeSpan.Zero);
                }
            }
Exemple #4
0
        private void CanFetchTransactionFromCoinprismCore(string test)
        {
            var tester   = CreateTester(test);
            var expected = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            var actual   = new CoinprismColoredTransactionRepository().Get(tester.TestedTxId);

            Assert.True(actual.ToBytes().SequenceEqual(expected.ToBytes()));
        }
Exemple #5
0
        //[Fact]
        public void TestFun()
        {
            var repo    = new NoSqlColoredTransactionRepository(new BlockrTransactionRepository());
            var colored = ColoredTransaction.FetchColors(uint256.Parse("b4399a545c4ddd640920d63af75e7367fe4d94b2d7f7a3423105e25ac5f165a6"), repo);

            var prismColored = new CoinprismColoredTransactionRepository().Get(uint256.Parse("b4399a545c4ddd640920d63af75e7367fe4d94b2d7f7a3423105e25ac5f165a6"));

            Assert.True(colored.ToBytes().SequenceEqual(prismColored.ToBytes()));
        }
        public static IEnumerable <ColoredCoin> Find(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
        {
            if (txId == null)
            {
                txId = tx.GetHash();
            }
            ColoredTransaction colored = tx.GetColoredTransaction(repo);

            return(Find(txId, tx, colored));
        }
 public Entity(uint256 txId, ColoredTransaction colored)
 {
     if (txId == null)
     {
         throw new ArgumentNullException("txId");
     }
     TxId = txId;
     ColoredTransaction = colored;
     Type = TransactionEntryType.Colored;
 }
            public DynamicTableEntity CreateTableEntity()
            {
                var entity = new DynamicTableEntity();

                entity.ETag         = "*";
                entity.PartitionKey = PartitionKey;
                entity.RowKey       = TxId + "-" + TypeLetter + "-" + BlockId;
                if (Transaction != null)
                {
                    Helper.SetEntityProperty(entity, "a", Transaction.ToBytes());
                }
                if (ColoredTransaction != null)
                {
                    Helper.SetEntityProperty(entity, "b", ColoredTransaction.ToBytes());
                }
                Helper.SetEntityProperty(entity, "c", Helper.SerializeList(PreviousTxOuts));
                return(entity);
            }
            public DynamicTableEntity CreateTableEntity()
            {
                var entity = new DynamicTableEntity();

                entity.ETag         = "*";
                entity.PartitionKey = PartitionKey;
                entity.RowKey       = TxId + "-" + TypeLetter + "-" + BlockId;
                if (Transaction != null)
                {
                    Helper.SetEntityProperty(entity, "a", Transaction.ToBytes());
                }
                if (ColoredTransaction != null)
                {
                    Helper.SetEntityProperty(entity, "b", ColoredTransaction.ToBytes());
                }
                Helper.SetEntityProperty(entity, "c", Helper.SerializeList(PreviousTxOuts, Transaction?.GetConsensusFactory() ?? PreviousTxOuts.Select(t => t.GetConsensusFactory()).FirstOrDefault()));
                Helper.SetEntityProperty(entity, "d", Utils.ToBytes((ulong)Timestamp.UtcTicks, true));
                return(entity);
            }
Exemple #10
0
 public static IEnumerable <ColoredCoin> Find(uint256 txId, Transaction tx, ColoredTransaction colored)
 {
     if (colored == null)
     {
         throw new ArgumentNullException("colored");
     }
     if (tx == null)
     {
         throw new ArgumentNullException("tx");
     }
     if (txId == null)
     {
         txId = tx.GetHash();
     }
     foreach (var entry in colored.Issuances.Concat(colored.Transfers))
     {
         var txout = tx.Outputs[entry.Index];
         yield return(new ColoredCoin(entry.Asset, new Coin(new OutPoint(txId, entry.Index), txout)));
     }
 }
        public override ITableEntity ToEntity()
        {
            var entity = new DynamicTableEntity
            {
                PartitionKey = PartitionKey,
                RowKey       = $"{TxId}-{BlockId}"
            };

            if (Transaction != null)
            {
                Helper.SetEntityProperty(entity, "tx", Transaction.ToBytes());
            }

            if (ColoredTransaction != null)
            {
                Helper.SetEntityProperty(entity, "ctx", ColoredTransaction.ToBytes());
            }

            Helper.SetEntityProperty(entity, "previoustxouts", Helper.SerializeList(PreviousTxOuts));
            Helper.SetEntityProperty(entity, "time", NBitcoin.Utils.ToBytes((ulong)Timestamp.UtcTicks, true));

            return(entity);
        }
        public TransactionEntity(DynamicTableEntity entity) : base(entity.PartitionKey)
        {
            var splitted = entity.RowKey.Split(new[] { "-" }, StringSplitOptions.None);

            Timestamp = entity.Timestamp;
            TxId      = uint256.Parse(splitted[0]);
            Type      = GetType(splitted[1]);

            if (splitted.Length >= 3 && splitted[2] != string.Empty)
            {
                BlockId = uint256.Parse(splitted[2]);
            }

            var bytes = Helper.GetEntityProperty(entity, "tx");

            if (bytes != null && bytes.Length != 0)
            {
                Transaction = new Transaction();
                Transaction.ReadWrite(bytes);
            }

            bytes = Helper.GetEntityProperty(entity, "ctx");
            if (bytes != null && bytes.Length != 0)
            {
                ColoredTransaction = new ColoredTransaction();
                ColoredTransaction.ReadWrite(bytes);
            }

            PreviousTxOuts = Helper.DeserializeList <TxOut>(Helper.GetEntityProperty(entity, "previoustxouts"));

            var timestamp = Helper.GetEntityProperty(entity, "time");

            if (timestamp != null && timestamp.Length == 8)
            {
                Timestamp = new DateTimeOffset((long)ToUInt64(timestamp, 0), TimeSpan.Zero);
            }
        }
Exemple #13
0
        internal OrderedBalanceChange(DynamicTableEntity entity)
        {
            var splitted = entity.RowKey.Split(new string[] { "-" }, StringSplitOptions.RemoveEmptyEntries);

            Height    = Helper.StringToHeight(splitted[1]);
            BalanceId = BalanceId.Parse(splitted[0]);

            var locator     = BalanceLocator.Parse(string.Join("-", splitted.Skip(1).ToArray()), true);
            var confLocator = locator as ConfirmedBalanceLocator;

            if (confLocator != null)
            {
                Height        = confLocator.Height;
                TransactionId = confLocator.TransactionId;
                BlockId       = confLocator.BlockHash;
            }

            var unconfLocator = locator as UnconfirmedBalanceLocator;

            if (unconfLocator != null)
            {
                TransactionId = unconfLocator.TransactionId;
            }

            SeenUtc = entity.Properties["s"].DateTime.Value;

            _SpentOutpoints = Helper.DeserializeList <OutPoint>(Helper.GetEntityProperty(entity, "a"));

            if (entity.Properties.ContainsKey("b0"))
            {
                _SpentCoins = new CoinCollection(Helper.DeserializeList <Spendable>(Helper.GetEntityProperty(entity, "b")).Select(s => new Coin()
                {
                    Outpoint = s.OutPoint,
                    TxOut    = s.TxOut
                }).ToList());
            }
            else if (_SpentOutpoints.Count == 0)
            {
                _SpentCoins = new CoinCollection();
            }

            _SpentIndices = Helper.DeserializeList <IntCompactVarInt>(Helper.GetEntityProperty(entity, "ss")).Select(i => (uint)i.ToLong()).ToList();

            var receivedIndices = Helper.DeserializeList <IntCompactVarInt>(Helper.GetEntityProperty(entity, "c")).Select(i => (uint)i.ToLong()).ToList();
            var receivedTxOuts  = Helper.DeserializeList <TxOut>(Helper.GetEntityProperty(entity, "d"));

            _ReceivedCoins = new CoinCollection();
            for (int i = 0; i < receivedIndices.Count; i++)
            {
                _ReceivedCoins.Add(new Coin()
                {
                    Outpoint = new OutPoint(TransactionId, receivedIndices[i]),
                    TxOut    = receivedTxOuts[i]
                });
            }

            var flags = entity.Properties["e"].StringValue;

            HasOpReturn = flags[0] == 'o';
            IsCoinbase  = flags[1] == 'o';

            _MatchedRules = Helper.DeserializeObject <List <MatchedRule> >(entity.Properties["f"].StringValue).ToList();

            if (entity.Properties.ContainsKey("g"))
            {
                var ctx = new ColoredTransaction();
                ctx.FromBytes(entity.Properties["g"].BinaryValue);
                ColoredTransaction = ctx;
            }

            if (entity.Properties.ContainsKey("h"))
            {
                _ScriptPubKey = new Script(entity.Properties["h"].BinaryValue);
            }

            var data = Helper.GetEntityProperty(entity, "cu");

            if (data != null)
            {
                CustomData = Encoding.UTF8.GetString(data);
            }
        }
Exemple #14
0
        public void CanColorizeOutputs()
        {
            ColoredCoinTester tester = CreateTester(this.networkMain, "CanColorizeIssuanceTransaction");

            ColoredTransaction colored1 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);

            Assert.True(colored1.Inputs.Count == 0);
            Assert.True(colored1.Issuances.Count == 1);
            Assert.True(colored1.Transfers.Count == 0);
            Assert.Equal("Af59wop4VJjXk2DAzoX9scAUCcAsghPHFX", colored1.Issuances[0].Asset.Id.GetWif(this.networkMain).ToString());

            tester = CreateTester(this.networkMain, "CanColorizeTransferTransaction");
            ColoredTransaction colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);

            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Inputs[0].Asset == colored1.Issuances[0].Asset);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 2);
            Assert.Equal("Af59wop4VJjXk2DAzoX9scAUCcAsghPHFX", colored2.Transfers[0].Asset.Id.GetWif(this.networkMain).ToString());

            tester = CreateTester(this.networkMain, "CanColorizeTransferTransaction");
            Transaction tx = tester.Repository.Transactions.Get(tester.TestedTxId);

            //If there are less items in the  asset quantity list  than the number of colorable outputs (all the outputs except the marker output), the outputs in excess receive an asset quantity of zero.
            tx.Outputs.Add(new TxOut());
            tx.Outputs.Add(new TxOut());
            tx.Outputs.Add(new TxOut());
            tester.TestedTxId = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Inputs[0].Asset == colored1.Issuances[0].Asset);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 2);
            Assert.Equal("Af59wop4VJjXk2DAzoX9scAUCcAsghPHFX", colored2.Transfers[0].Asset.Id.GetWif(this.networkMain).ToString());
            AssetMoney[] destroyed = colored2.GetDestroyedAssets();
            Assert.True(destroyed.Length == 0);

            tester = CreateTester(this.networkMain, "CanColorizeTransferTransaction");
            tx     = tester.Repository.Transactions.Get(tester.TestedTxId);
            //If there are more items in the  asset quantity list  than the number of colorable outputs, the transaction is deemed invalid, and all outputs are uncolored.
            ColorMarker payload = tx.GetColoredMarker();

            payload.Quantities         = payload.Quantities.Concat(new ulong[] { 1, 2 }).ToArray();
            tx.Outputs[0].ScriptPubKey = payload.GetScript();
            Assert.False(tx.HasValidColoredMarker());
            tester.TestedTxId = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 0);

            tester = CreateTester(this.networkMain, "CanColorizeTransferTransaction");
            tx     = tester.Repository.Transactions.Get(tester.TestedTxId);
            //If the marker output is malformed, the transaction is invalid, and all outputs are uncolored.
            tx.Outputs[0].ScriptPubKey = new Script();
            tester.TestedTxId          = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 0);

            tester = CreateTester(this.networkMain, "CanColorizeTransferTransaction");
            tx     = tester.Repository.Transactions.Get(tester.TestedTxId);
            //If there are less asset units in the input sequence than in the output sequence, the transaction is considered invalid and all outputs are uncolored.
            payload = tx.GetColoredMarker();
            payload.Quantities[0]      = 1001;
            tx.Outputs[0].ScriptPubKey = payload.GetScript();
            tester.TestedTxId          = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 0);

            tester = CreateTester(this.networkMain, "CanColorizeTransferTransaction");
            tx     = tester.Repository.Transactions.Get(tester.TestedTxId);
            //If there are more asset units in the input sequence than in the output sequence, the transaction is considered valid
            payload = tx.GetColoredMarker();
            payload.Quantities[0]      = 999;
            tx.Outputs[0].ScriptPubKey = payload.GetScript();
            tester.TestedTxId          = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 2);
            destroyed = colored2.GetDestroyedAssets();
            Assert.True(destroyed.Length == 1);
            Assert.True(destroyed[0].Quantity == 1);
            Assert.True(destroyed[0].Id == colored2.Inputs[0].Asset.Id);

            //Verify that FetchColor update the repository
            var persistent = new NoSqlColoredTransactionRepository(KnownNetworks.Main, tester.Repository.Transactions, new InMemoryNoSqlRepository(KnownNetworks.Main));

            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, persistent);
            Assert.NotNull(persistent.Get(tester.TestedTxId));

            //Verify cached loadbulk correctly
            var cached = new CachedColoredTransactionRepository(persistent);

            persistent.Put(tester.TestedTxId, null);
            cached.WriteThrough = false;
            colored2            = ColoredTransaction.FetchColors(tester.TestedTxId, cached);
            cached.ReadThrough  = false;
            Assert.Null(cached.Get(tester.TestedTxId));            //Should not have written in the cache (cache outdated, thinking it is still null)
            Assert.NotNull(persistent.Get(tester.TestedTxId));     //But should have written in the inner repository
            Assert.NotNull(cached.Get(tx.Inputs[0].PrevOut.Hash)); //However, the previous transaction should have been loaded by loadbulk via ReadThrough
        }
Exemple #15
0
        //https://github.com/OpenAssets/open-assets-protocol/blob/master/specification.mediawiki
        public void CanColorizeSpecScenario()
        {
            var   repo    = new NoSqlColoredTransactionRepository(KnownNetworks.Main);
            Money dust    = Money.Parse("0.00005");
            var   colored = new ColoredTransaction();
            var   a1      = new AssetKey(this.networkMain);
            var   a2      = new AssetKey(this.networkMain);
            var   h       = new AssetKey(this.networkMain);
            BitcoinPubKeyAddress sender   = new Key().PubKey.GetAddress(this.networkMain);
            BitcoinPubKeyAddress receiver = new Key().PubKey.GetAddress(this.networkMain);

            colored.Marker = new ColorMarker(new ulong[] { 0, 10, 6, 0, 7, 3 });
            colored.Inputs.Add(new ColoredEntry(0, new AssetMoney(a1.Id, 3UL)));
            colored.Inputs.Add(new ColoredEntry(1, new AssetMoney(a1.Id, 2UL)));
            colored.Inputs.Add(new ColoredEntry(3, new AssetMoney(a1.Id, 5UL)));
            colored.Inputs.Add(new ColoredEntry(4, new AssetMoney(a1.Id, 3UL)));
            colored.Inputs.Add(new ColoredEntry(5, new AssetMoney(a2.Id, 9UL)));

            colored.Issuances.Add(new ColoredEntry(1, new AssetMoney(h.Id, 10UL)));
            colored.Transfers.Add(new ColoredEntry(3, new AssetMoney(a1.Id, 6UL)));
            colored.Transfers.Add(new ColoredEntry(5, new AssetMoney(a1.Id, 7UL)));
            colored.Transfers.Add(new ColoredEntry(6, new AssetMoney(a2.Id, 3UL)));
            AssetMoney[] destroyed = colored.GetDestroyedAssets();
            Assert.True(destroyed.Length == 1);
            Assert.True(destroyed[0].Quantity == 6);
            Assert.True(destroyed[0].Id == a2.Id);
            colored   = colored.Clone();
            destroyed = colored.GetDestroyedAssets();
            Assert.True(destroyed.Length == 1);
            Assert.True(destroyed[0].Quantity == 6);
            Assert.True(destroyed[0].Id == a2.Id);

            Transaction prior = this.networkMain.CreateTransaction();

            prior.Outputs.Add(new TxOut(dust, a1.ScriptPubKey));
            prior.Outputs.Add(new TxOut(dust, a2.ScriptPubKey));
            prior.Outputs.Add(new TxOut(dust, h.ScriptPubKey));
            repo.Transactions.Put(prior.GetHash(), prior);

            Transaction issuanceA1 = this.networkMain.CreateTransaction();

            issuanceA1.Inputs.Add(new TxIn(new OutPoint(prior.GetHash(), 0)));
            issuanceA1.Outputs.Add(new TxOut(dust, h.ScriptPubKey));
            issuanceA1.Outputs.Add(new TxOut(dust, sender));
            issuanceA1.Outputs.Add(new TxOut(dust, sender));
            issuanceA1.Outputs.Add(new TxOut(dust, sender));
            issuanceA1.Outputs.Add(new TxOut(dust, new ColorMarker(new ulong[] { 3, 2, 5, 3 }).GetScript()));
            repo.Transactions.Put(issuanceA1.GetHash(), issuanceA1);

            Transaction issuanceA2 = this.networkMain.CreateTransaction();

            issuanceA2.Inputs.Add(new TxIn(new OutPoint(prior.GetHash(), 1)));
            issuanceA2.Outputs.Add(new TxOut(dust, sender));
            issuanceA2.Outputs.Add(new TxOut(dust, new ColorMarker(new ulong[] { 9 }).GetScript()));
            repo.Transactions.Put(issuanceA2.GetHash(), issuanceA2);

            Transaction        testedTx      = CreateSpecTransaction(repo, dust, receiver, prior, issuanceA1, issuanceA2);
            ColoredTransaction actualColored = testedTx.GetColoredTransaction(repo);

            Assert.True(colored.ToBytes().SequenceEqual(actualColored.ToBytes()));

            //Finally, for each transfer output, if the asset units forming that output all have the same asset address, the output gets assigned that asset address. If any output contains units from more than one distinct asset address, the whole transaction is considered invalid, and all outputs are uncolored.
            Transaction testedBadTx = CreateSpecTransaction(repo, dust, receiver, prior, issuanceA1, issuanceA2);

            testedBadTx.Outputs[2] = new TxOut(dust, new ColorMarker(new ulong[] { 0, 10, 6, 0, 6, 4 }).GetScript());
            repo.Transactions.Put(testedBadTx.GetHash(), testedBadTx);
            colored = testedBadTx.GetColoredTransaction(repo);

            destroyed = colored.GetDestroyedAssets();
            Assert.True(destroyed.Length == 2);
            Assert.True(destroyed[0].Id == a1.Id);
            Assert.True(destroyed[0].Quantity == 13);
            Assert.True(destroyed[1].Id == a2.Id);
            Assert.True(destroyed[1].Quantity == 9);

            //If there are more items in the  asset quantity list  than the number of colorable outputs, the transaction is deemed invalid, and all outputs are uncolored.
            testedBadTx            = CreateSpecTransaction(repo, dust, receiver, prior, issuanceA1, issuanceA2);
            testedBadTx.Outputs[2] = new TxOut(dust, new ColorMarker(new ulong[] { 0, 10, 6, 0, 7, 4, 10, 10 }).GetScript());
            repo.Transactions.Put(testedBadTx.GetHash(), testedBadTx);

            colored = testedBadTx.GetColoredTransaction(repo);

            destroyed = colored.GetDestroyedAssets();
            Assert.True(destroyed.Length == 2);
            Assert.True(destroyed[0].Id == a1.Id);
            Assert.True(destroyed[0].Quantity == 13);
            Assert.True(destroyed[1].Id == a2.Id);
            Assert.True(destroyed[1].Quantity == 9);
        }
Exemple #16
0
 public static IEnumerable <ColoredCoin> Find(Transaction tx, ColoredTransaction colored)
 {
     return(Find(null, tx, colored));
 }
Exemple #17
0
        public void CanColorizeOutputs()
        {
            var tester = CreateTester("CanColorizeIssuanceTransaction");

            var colored1 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);

            Assert.True(colored1.Inputs.Count == 0);
            Assert.True(colored1.Issuances.Count == 1);
            Assert.True(colored1.Transfers.Count == 0);
            Assert.Equal("Af59wop4VJjXk2DAzoX9scAUCcAsghPHFX", colored1.Issuances[0].Asset.Id.GetWif(Network.Main).ToString());

            tester = CreateTester("CanColorizeTransferTransaction");
            var colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);

            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Inputs[0].Asset == colored1.Issuances[0].Asset);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 2);
            Assert.Equal("Af59wop4VJjXk2DAzoX9scAUCcAsghPHFX", colored2.Transfers[0].Asset.Id.GetWif(Network.Main).ToString());

            tester = CreateTester("CanColorizeTransferTransaction");
            var tx = tester.Repository.Transactions.Get(tester.TestedTxId);

            //If there are less items in the  asset quantity list  than the number of colorable outputs (all the outputs except the marker output), the outputs in excess receive an asset quantity of zero.
            tx.Outputs.Add(new TxOut());
            tx.Outputs.Add(new TxOut());
            tx.Outputs.Add(new TxOut());
            tester.TestedTxId = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Inputs[0].Asset == colored1.Issuances[0].Asset);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 2);
            Assert.Equal("Af59wop4VJjXk2DAzoX9scAUCcAsghPHFX", colored2.Transfers[0].Asset.Id.GetWif(Network.Main).ToString());
            var destroyed = colored2.GetDestroyedAssets();

            Assert.True(destroyed.Length == 0);

            tester = CreateTester("CanColorizeTransferTransaction");
            tx     = tester.Repository.Transactions.Get(tester.TestedTxId);
            //If there are more items in the  asset quantity list  than the number of colorable outputs, the transaction is deemed invalid, and all outputs are uncolored.
            var payload = tx.GetColoredMarker();

            payload.Quantities         = payload.Quantities.Concat(new ulong[] { 1, 2 }).ToArray();
            tx.Outputs[0].ScriptPubKey = payload.GetScript();
            Assert.False(tx.HasValidColoredMarker());
            tester.TestedTxId = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 0);

            tester = CreateTester("CanColorizeTransferTransaction");
            tx     = tester.Repository.Transactions.Get(tester.TestedTxId);
            //If the marker output is malformed, the transaction is invalid, and all outputs are uncolored.
            tx.Outputs[0].ScriptPubKey = new Script();
            tester.TestedTxId          = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 0);


            tester = CreateTester("CanColorizeTransferTransaction");
            tx     = tester.Repository.Transactions.Get(tester.TestedTxId);
            //If there are less asset units in the input sequence than in the output sequence, the transaction is considered invalid and all outputs are uncolored.
            payload = tx.GetColoredMarker();
            payload.Quantities[0]      = 1001;
            tx.Outputs[0].ScriptPubKey = payload.GetScript();
            tester.TestedTxId          = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 0);


            tester = CreateTester("CanColorizeTransferTransaction");
            tx     = tester.Repository.Transactions.Get(tester.TestedTxId);
            //If there are more asset units in the input sequence than in the output sequence, the transaction is considered valid
            payload = tx.GetColoredMarker();
            payload.Quantities[0]      = 999;
            tx.Outputs[0].ScriptPubKey = payload.GetScript();
            tester.TestedTxId          = tx.GetHash();
            tester.Repository.Transactions.Put(tester.TestedTxId, tx);
            colored2 = ColoredTransaction.FetchColors(tester.TestedTxId, tester.Repository);
            Assert.True(colored2.Inputs.Count == 1);
            Assert.True(colored2.Issuances.Count == 0);
            Assert.True(colored2.Transfers.Count == 2);
            destroyed = colored2.GetDestroyedAssets();
            Assert.True(destroyed.Length == 1);
            Assert.True(destroyed[0].Quantity == 1);
            Assert.True(destroyed[0].Id == colored2.Inputs[0].Asset.Id);
        }
Exemple #18
0
        public static void Execute()
        {
            // NBitcoin allows you either to depend on a web service, either to provide
            // your own implementation for fetching the color of a Transaction

            // Let’s introduce two issuers: Silver and Gold. And three participants: Bob, Alice and Satoshi.
            // Let’s create a fake transaction that give some bitcoins to Silver, Gold and Satoshi.

            var gold     = new Key();
            var silver   = new Key();
            var goldId   = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
            var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

            var bob     = new Key();
            var alice   = new Key();
            var satoshi = new Key();

            var init = new Transaction()
            {
                Outputs = { new TxOut("1.0", gold),
                            new TxOut("1.0", silver),
                            new TxOut("1.0", satoshi) }
            };

            // In NBitcoin, the summary of color transfers and issuances is described by a class called
            // FetchColor, which will permit you to extract colored information
            // The trick when writing unit tests is to use an in memory IColoredTransactionRepository:
            var repo = new NoSqlColoredTransactionRepository();

            // we can put our init transaction inside.
            repo.Transactions.Put(init);
            // you can extract the color:
            ColoredTransaction color = ColoredTransaction.FetchColors(init, repo);

            Console.WriteLine("color: " + color);

            /*
             * {
             *  "inputs": [],
             *  "issuances": [],
             *  "transfers": [],
             *  "destructions": []
             * }
             */
            // let’s use the two coins sent to Silver and Gold as Issuance Coins.
            var issuanceCoins = init.Outputs.AsCoins()
                                .Take(2).Select((c, i) => new IssuanceCoin(c))
                                .OfType <ICoin>()
                                .ToArray();
            // Gold is the first coin, Silver the second one.
            // From that you can send Gold to Satoshi with the TransactionBuilder,

            // imagine that Satoshi wants to send 4 gold to Alice.
            // First, he will fetch the ColoredCoin out of the transaction.
            var sendGoldToSatoshi = init;
            var goldCoin          = ColoredCoin.Find(sendGoldToSatoshi, color).FirstOrDefault();
            // build a transaction like that:
            var builder           = new TransactionBuilder();
            var sendToBobAndAlice = builder.AddKeys(satoshi)
                                    .AddCoins(goldCoin)
                                    .SendAsset(alice, new AssetMoney(goldId, 4))
                                    .SetChange(satoshi)
                                    .BuildTransaction(true);
            // you are out of 600 satoshi.
            // You can fix the problem by adding the last Coin of 1 BTC
            // in the init transaction that belongs to satoshi.
            var satoshiBtc = init.Outputs.AsCoins().Last();

            builder = new TransactionBuilder();
            var sendToAlice = builder.AddKeys(satoshi)
                              .AddCoins(goldCoin, satoshiBtc)
                              .SendAsset(alice, new AssetMoney(goldId, 4))
                              .SetChange(satoshi)
                              .BuildTransaction(true);

            repo.Transactions.Put(sendToAlice);
            color = ColoredTransaction.FetchColors(sendToAlice, repo);

            // Let’s see the transaction and its colored part:
            Console.WriteLine("sendToAlice: " + sendToAlice);
            Console.WriteLine("color: " + color);
        }
Exemple #19
0
        void Start()
        {
            var gold     = new Key();
            var silver   = new Key();
            var goldId   = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
            var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

            var bob     = new Key();
            var alice   = new Key();
            var satoshi = new Key();

            var init = new Transaction
            {
                Outputs =
                {
                    new TxOut("1.0", gold),
                    new TxOut("1.0", silver),
                    new TxOut("1.0", satoshi)
                }
            };

            var repo = new NoSqlColoredTransactionRepository();

            repo.Transactions.Put(init);

            ColoredTransaction color = ColoredTransaction.FetchColors(init, repo);

            UnityEngine.Debug.Log(color);

            var issuanceCoins =
                init
                .Outputs
                .AsCoins()
                .Take(2)
                .Select((c, i) => new IssuanceCoin(c))
                .OfType <ICoin>()
                .ToArray();

            var builder           = new TransactionBuilder();
            var sendGoldToSatoshi =
                builder
                .AddKeys(gold)
                .AddCoins(issuanceCoins[0])
                .IssueAsset(satoshi, new AssetMoney(goldId, 10))
                .SetChange(gold)
                .BuildTransaction(true);

            repo.Transactions.Put(sendGoldToSatoshi);
            color = ColoredTransaction.FetchColors(sendGoldToSatoshi, repo);
            UnityEngine.Debug.Log(color);

            var goldCoin = ColoredCoin.Find(sendGoldToSatoshi, color).FirstOrDefault();

            builder = new TransactionBuilder();
            var sendToBobAndAlice =
                builder
                .AddKeys(satoshi)
                .AddCoins(goldCoin)
                .SendAsset(alice, new AssetMoney(goldId, 4))
                .SetChange(satoshi)
                .BuildTransaction(true);


            var satoshiBtc = init.Outputs.AsCoins().Last();

            builder = new TransactionBuilder();
            var sendToAlice =
                builder
                .AddKeys(satoshi)
                .AddCoins(goldCoin, satoshiBtc)
                .SendAsset(alice, new AssetMoney(goldId, 4))
                .SetChange(satoshi)
                .BuildTransaction(true);

            repo.Transactions.Put(sendToAlice);
            color = ColoredTransaction.FetchColors(sendToAlice, repo);

            UnityEngine.Debug.Log(sendToAlice);
            UnityEngine.Debug.Log(color);
        }
        private static void Main()
        {
            //========================================================================================
            //Section. Unit tests

            //You can see that previously I hard coded the properties of ColoredCoin.
            //The reason is that I wanted only to show you how to construct a Transaction out of ColoredCoin coins.
            //In real life, you would either depend on a third party API to fetch the colored coins of a transaction or a balance. Which might be not a good idea, because it adds a trust dependency to your program with the API provider.
            //NBitcoin allows you either to depend on a web service or to provide your own implementation for fetching the color of a Transaction. This allows you to have a flexible way to unit test your code, using another implementation or your own.
            //Let’s introduce two issuers: Silver and Gold. And three participants: Bob, Alice and Satoshi.
            //Let’s create a fake transaction that give some bitcoins to Silver, Gold and Satoshi.
            var gold     = new Key();
            var silver   = new Key();
            var goldId   = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
            var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

            var bob     = new Key();
            var alice   = new Key();
            var satoshi = new Key();

            var init = new Transaction
            {
                Outputs =
                {
                    new TxOut("1.0", gold),
                    new TxOut("1.0", silver),
                    new TxOut("1.0", satoshi)
                }
            };

            //Init does not contain any Colored Coin issuance and Transfer. But imagine that you want to be sure of it, how would you proceed?
            //In NBitcoin, the summary of color transfers and issuances is described by a class called ColoredTransaction.

            //Picture depiction:
            //IBitcoinSerializable interface.
            //3 classes(ColoredTransaction, ColoredEntry, Asset) implement IBitcoinSerializable interface.


            //You can see that the ColoredTransaction class will tell you:
            //1.Which TxIn spends which Asset
            //2.Which TxOut emits which Asset
            //3.Which TxOut transfers which Asset

            //But the method that interests us right now is FetchColor, which will permit you to extract colored information out of the transaction you gave in input.
            //You see that it depends on a IColoredTransactionRepository.
            //In other words, IColoredTransactionRepository type object should be passed into FetchColor() method as one of the arguments of it.
            //Picture depiction.


            //IColoredTransactionRepository is only a store that will give you the ColoredTransaction from the txid. However, you can see that it depends on ITransactionRepository, which maps a Transaction id to its transaction.
            //An implementation of IColoredTransactionRepository is CoinprismColoredTransactionRepository which is a public API for colored coins operations.
            //However, you can easily do your own, here is how FetchColors method works.
            //The simplest case is: The IColoredTransactionRepository knows the color, in such case FetchColors method only returns that result.
            //Picture depiction:



            //The second case is that the IColoredTransactionRepository does not know anything about the color of the transaction.
            //So FetchColors method will need to compute the color itself according to the open asset specification.
            //However, for computing the color, FetchColors method needs the color of the parent transactions.
            //So it fetches each of them on the ITransactionRepository, and calls FetchColors method on each of them.
            //Once FetchColors method has resolved the color of the parent’s recursively, it computes the transaction color, and caches the result back in the IColoredTransactionRepository.

            //Picture depiction:


            //            By doing that, future requests to fetch the color of a transaction will be resolved quickly.
            //Some IColoredTransactionRepository are read-only(like CoinprismColoredTransactionRepository), so the Put operation is ignored.
            //So, back to our example: The trick when writing unit tests is to use an in-memory IColoredTransactionRepository:
            var repo = new NoSqlColoredTransactionRepository();

            //Now, we can put our init transaction to the inside.
            repo.Transactions.Put(init);

            //Note that Put is an extension methods, so you will need to add
            //using NBitcoin.OpenAsset;
            //at the top of the file to get access to it.


            //And now, you can extract the color:

            ColoredTransaction color = ColoredTransaction.FetchColors(init, repo);

            Console.WriteLine(color);
            //Output:
            //{
            // "inputs": [],
            // "issuances": [],
            // "transfers": [],
            // "destructions": []
            //}
            //As expected, the init transaction has no inputs, issuances, transfers or destructions of Colored Coins.


            //So now, let’s use the two coins sent to Silver and Gold as Issuance Coins.
            var issuanceCoins = init
                                .Outputs
                                .AsCoins()
                                .Take(2)
                                .Select((c, i) => new IssuanceCoin(c))
                                .OfType <ICoin>()
                                .ToArray();
            //Gold is the first coin, Silver the second one.

            //From that you can send Gold to Satoshi with the TransactionBuilder, as we have done in the previous exercise, and put the resulting transaction in the repository, and print the result.

            //Output:
            //{
            // "inputs": [],
            // "issuances": [
            //    {
            //      "index": 0,
            //      "asset": "ATEwaRSNeCgBjxjcur7JtfypFjqQgAtLJs",
            //      "quantity": 10
            //    }
            //  ],
            //  "transfers": [],
            //  "destructions": []
            //}
            //This means that the first TxOut bears 10 gold.

            //Now imagine that Satoshi wants to send 4 gold to Alice.
            //First, satoshi should get the coins from the gold coin.
            //For that, build a transaction like that:
            var builder           = new TransactionBuilder();
            var sendGoldToSatoshi =
                builder
                .AddKeys(gold)
                .AddCoins(issuanceCoins[0])
                .IssueAsset(satoshi, new AssetMoney(goldId, 10))
                .SetChange(gold)
                .BuildTransaction(true);

            repo.Transactions.Put(sendGoldToSatoshi);
            color = ColoredTransaction.FetchColors(sendGoldToSatoshi, repo);
            Console.WriteLine(color);

            //Satoshi will fetch the ColoredCoin which he recieved from the gold coin out of the transaction.
            var goldCoin = ColoredCoin.Find(sendGoldToSatoshi, color).FirstOrDefault();

            //And satoshi sends the coin to Alice.
            builder = new TransactionBuilder();
            var sendToAliceWithNotEnoughFundsException =
                builder
                .AddKeys(satoshi)
                .AddCoins(goldCoin)
                .SendAsset(alice, new AssetMoney(goldId, 4))
                .SetChange(satoshi)
                .BuildTransaction(true);

            Console.WriteLine(sendToAliceWithNotEnoughFundsException);
            //Except you will get the exception NotEnoughFundsException.
            //The reason is that the transaction is composed of 600 satoshis in input(the goldCoin which satoshi owns), and 1200 satoshis in output. (One TxOut for sending assets to Alice, and the other one for sending back the change to Satoshi.)
            //In other words, in TxIn(total 600 coming) < in TxOut(total 1200 going out)
            //This means that you are out of 600 satoshis.
            //You can fix the problem by adding the last Coin of 1 BTC in the init transaction that belongs to satoshi.
            var satoshiBtc = init.Outputs.AsCoins().Last();

            builder = new TransactionBuilder();
            //Send the coin to Alice this time without a NotEnoughFundsException.
            var sendToAlice =
                builder
                .AddKeys(satoshi)
                .AddCoins(goldCoin, satoshiBtc)
                .SendAsset(alice, new AssetMoney(goldId, 4))
                .SetChange(satoshi)
                .BuildTransaction(true);

            repo.Transactions.Put(sendToAlice);
            color = ColoredTransaction.FetchColors(sendToAlice, repo);


            //Let’s see the transaction and its colored part:
            Console.WriteLine(sendToAlice);
            Console.WriteLine(color);

            //{
            //  ….
            //  "in": [
            //    {
            //      "prev_out": {
            //        "hash": "46117f3ef44f2dfd87e0bc3f461f48fe9e2a3a2281c9b3802e339c5895fc325e",
            //        "n": 0
            //      },
            //      "scriptSig": "304502210083424305549d4bb1632e2c67736383558f3e1d7fb30ce7b5a3d7b87a53cdb3940220687ea53db678b467b98a83679dec43d27e89234ce802daf14ed059e7a09557e801 03e232cda91e719075a95ede4c36ea1419efbc145afd8896f36310b76b8020d4b1"
            //    },
            //    {
            //      "prev_out": {
            //        "hash": "aefa62270999baa0d57ddc7d2e1524dd3828e81a679adda810657581d7d6d0f6",
            //        "n": 2
            //      },
            //      "scriptSig": "30440220364a30eb4c8a82cc2a79c54d0518b8ba0cf4e49c73a5bbd17fe1a5683a0dfa640220285e98f3d336f1fa26fb318be545162d6a36ce1103c8f6c547320037cb1fb8e901 03e232cda91e719075a95ede4c36ea1419efbc145afd8896f36310b76b8020d4b1"
            //    }
            //  ],
            //  "out": [
            //    {
            //      "value": "0.00000000",
            //      "scriptPubKey": "OP_RETURN 4f41010002060400"
            //    },
            //    {
            //      "value": "0.00000600",
            //      "scriptPubKey": "OP_DUP OP_HASH160 5bb41cd29f4e838b4b0fdcd0b95447dcf32c489d OP_EQUALVERIFY OP_CHECKSIG"
            //    },
            //    {
            //      "value": "0.00000600",
            //      "scriptPubKey": "OP_DUP OP_HASH160 469c5243cb08c82e78a8020360a07ddb193f2aa8 OP_EQUALVERIFY OP_CHECKSIG"
            //    },
            //    {
            //      "value": "0.99999400",
            //      "scriptPubKey": "OP_DUP OP_HASH160 5bb41cd29f4e838b4b0fdcd0b95447dcf32c489d OP_EQUALVERIFY OP_CHECKSIG"
            //    }
            //  ]
            //}
            //Colored :
            //{
            //  "inputs": [
            //    {
            //      "index": 0,
            //      "asset": " ATEwaRSNeCgBjxjcur7JtfypFjqQgAtLJs ",
            //      "quantity": 10
            //    }
            //  ],
            //  "issuances": [],
            //  "transfers": [
            //    {
            //      "index": 1,
            //      "asset": " ATEwaRSNeCgBjxjcur7JtfypFjqQgAtLJs ",
            //      "quantity": 6
            //    },
            //    {
            //      "index": 2,
            //      "asset": " ATEwaRSNeCgBjxjcur7JtfypFjqQgAtLJs ",
            //      "quantity": 4
            //    }
            //  ],
            //  "destructions": []
            //}

            //We have finally made a unit test that emits and transfers some assets without any external dependencies.
            //You can make your own IColoredTransactionRepository if you don’t want to depend on a third party service.
            //You can find more complex scenarios in NBitcoin tests, and also one of my articles “Build them all” in Codeproject. (Like multi-sig issuance and colored coin swaps.)
        }
Exemple #21
0
        public async Task <TransactionEntry> GetTransactionAsync(bool loadPreviousOutput, bool fetchColor, uint256 txId)
        {
            if (txId == null)
            {
                return(null);
            }
            TransactionEntry result = null;

            var table          = Configuration.GetTransactionTable();
            var searchedEntity = new TransactionEntry.Entity(txId);
            var query          = new TableQuery <DynamicTableEntity>()
                                 .Where(
                TableQuery.CombineFilters(
                    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, searchedEntity.PartitionKey),
                    TableOperators.And,
                    TableQuery.CombineFilters(
                        TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThan, txId.ToString() + "-"),
                        TableOperators.And,
                        TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, txId.ToString() + "|")
                        )
                    ));

            query.TakeCount = 10; //Should not have more
            List <TransactionEntry.Entity> entities = new List <TransactionEntry.Entity>();

            foreach (var e in await table.ExecuteQuerySegmentedAsync(query, null).ConfigureAwait(false))
            {
                if (e.IsFat())
                {
                    entities.Add(new TransactionEntry.Entity(await FetchFatEntity(e).ConfigureAwait(false), ConsensuFactory));
                }
                else
                {
                    entities.Add(new TransactionEntry.Entity(e, ConsensuFactory));
                }
            }
            if (entities.Count == 0)
            {
                result = null;
            }
            else
            {
                result = new TransactionEntry(entities.ToArray());
                if (result.Transaction == null)
                {
                    foreach (var block in result.BlockIds.Select(id => GetBlock(id)).Where(b => b != null))
                    {
                        result.Transaction      = block.Transactions.FirstOrDefault(t => t.GetHash() == txId);
                        entities[0].Transaction = result.Transaction;
                        if (entities[0].Transaction != null)
                        {
                            await UpdateEntity(table, entities[0].CreateTableEntity()).ConfigureAwait(false);
                        }
                        break;
                    }
                }

                if (fetchColor && result.ColoredTransaction == null)
                {
                    result.ColoredTransaction = await ColoredTransaction.FetchColorsAsync(txId, result.Transaction, new CachedColoredTransactionRepository(new IndexerColoredTransactionRepository(Configuration))).ConfigureAwait(false);

                    entities[0].ColoredTransaction = result.ColoredTransaction;
                    if (entities[0].ColoredTransaction != null)
                    {
                        await UpdateEntity(table, entities[0].CreateTableEntity()).ConfigureAwait(false);
                    }
                }
                var needTxOut = result.SpentCoins == null && loadPreviousOutput && result.Transaction != null;
                if (needTxOut)
                {
                    var inputs  = result.Transaction.Inputs.Select(o => o.PrevOut).ToArray();
                    var parents = await
                                  GetTransactionsAsync(false, false, inputs
                                                       .Select(i => i.Hash)
                                                       .ToArray()).ConfigureAwait(false);

                    for (int i = 0; i < parents.Length; i++)
                    {
                        if (parents[i] == null)
                        {
                            IndexerTrace.MissingTransactionFromDatabase(result.Transaction.Inputs[i].PrevOut.Hash);
                            return(null);
                        }
                    }

                    var outputs = parents.Select((p, i) => p.Transaction.Outputs[inputs[i].N]).ToArray();

                    result.SpentCoins = Enumerable
                                        .Range(0, inputs.Length)
                                        .Select(i => new Spendable(inputs[i], outputs[i]))
                                        .ToList();
                    entities[0].PreviousTxOuts.Clear();
                    entities[0].PreviousTxOuts.AddRange(outputs);
                    if (entities[0].IsLoaded)
                    {
                        await UpdateEntity(table, entities[0].CreateTableEntity()).ConfigureAwait(false);
                    }
                }
            }
            return(result != null && result.Transaction != null ? result : null);
        }
        public static void ColoredCoins()
        {
            // ISSUING AN ASSET
            // In Open Asset, the Asset ID is derived from the issuers ScriptPubKey. To issue a Colored Coin, you must prove ownership of the ScriptPubKey by spending from it.
            // The coin you spend for issuing colored coins is called the "Issuance Coin" in NBitcoin. Create an issuance coin:
            // coin being used for issuing the asset:
            //{
            //    "transactionId": "eb49a599c749c82d824caf9dd69c4e359261d49bbb0b9d6dc18c59bc9214e43b",
            //    "index": 0,
            //    "value": 2000000,
            //    "scriptPubKey": "76a914c81e8e7b7ffca043b088a992795b15887c96159288ac",
            //    "redeemScript": null
            //}
            var coin = new Coin(
                fromTxHash: new uint256("eb49a599c749c82d824caf9dd69c4e359261d49bbb0b9d6dc18c59bc9214e43b"),
                fromOutputIndex: 0,
                amount: Money.Satoshis(2000000),
                scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914c81e8e7b7ffca043b088a992795b15887c96159288ac")));

            var issuance = new IssuanceCoin(coin);
            // build and sign transaction using TransactionBuilder
            var nico    = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe");
            var bookKey = new BitcoinSecret("???"); // program errors bc we don't have nico's private key/secret
            TransactionBuilder builder = new TransactionBuilder();

            var tx = builder
                     .AddCoins(coin)
                     .AddKeys(bookKey)
                     .IssueAsset(nico, new NBitcoin.OpenAsset.AssetMoney(issuance.AssetId, quantity: 10)) // this is new part relevant to issuing colored coins
                     .SendFees(Money.Coins(0.0001m))
                     .SetChange(bookKey.GetAddress())
                     .BuildTransaction(sign: true);

            Console.WriteLine(tx);
            // after tx verification, it's ready to be sent to the network
            Console.WriteLine(builder.Verify(tx));
            // review: broadcasting with QBitNinja:
            var client = new QBitNinjaClient(Network.Main);
            BroadcastResponse broadcastResponse = client.Broadcast(tx).Result;

            if (!broadcastResponse.Success)
            {
                Console.WriteLine("ErrorCode: " + broadcastResponse.Error.ErrorCode);
                Console.WriteLine("Error message: " + broadcastResponse.Error.Reason);
            }
            else
            {
                Console.WriteLine("Success!");
            }
            // or broadcast with your own Bitcoin Core node:
            using (var node = Node.ConnectToLocal(Network.Main))
            {
                node.VersionHandshake();
                node.SendMessage(new InvPayload(InventoryType.MSG_TX, tx.GetHash())); // first send just the hash of your transaction
                node.SendMessage(new TxPayload(tx));                                  // then send signed transaction
                Thread.Sleep(500);
            }

            // Colored Coins have their own address format that only colored coin wallets understand, to prevent sending colored coins to wallets that don't support it
            nico = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe");
            Console.WriteLine(nico.ToColoredAddress());

            // colored coin Asset ID is derived from issuer's ScriptPubKey. here is how to get the ID:
            var book    = BitcoinAddress.Create("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB");
            var assetId = new AssetId(book).GetWif(Network.Main);

            Console.WriteLine(assetId);

            // TRANSFER AN ASSET
            // to send received colored coins, you need to build a ColredCoin
            // received transaction to spent:
            //{
            //    "transactionId": "fa6db7a2e478f3a8a0d1a77456ca5c9fa593e49fd0cf65c7e349e5a4cbe58842",
            //    "index": 0,
            //    "value": 600,
            //    "scriptPubKey": "76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac",
            //    "redeemScript": null,
            //    "assetId": "AVAVfLSb1KZf9tJzrUVpktjxKUXGxUTD4e",
            //    "quantity": 10
            //}
            //var coin2 = new Coin(
            //    fromTxHash: new uint256("fa6db7a2e478f3a8a0d1a77456ca5c9fa593e49fd0cf65c7e349e5a4cbe58842"),
            //    fromOutputIndex: 0,
            //    amount: Money.Satoshis(600),
            //    scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac")));
            //BitcoinAssetId assetId2 = new BitcoinAssetId("AVAVfLSb1KZf9tJzrUVpktjxKUXGxUTD4e");
            //ColoredCoin colored = coin2.ToColoredCoin(assetId2, 10);

            //// also, in this exampled, we needed another coin forFees to pay the tx fee
            //var forFees = new Coin(
            //    fromTxHash: new uint256("7f296e96ec3525511b836ace0377a9fbb723a47bdfb07c6bc3a6f2a0c23eba26"),
            //    fromOutputIndex: 0,
            //    amount: Money.Satoshis(4425000),
            //    scriptPubKey: new Script(Encoders.Hex.DecodeData("76a914356facdac5f5bcae995d13e667bb5864fd1e7d5988ac")));

            //TransactionBuilder builder2 = new TransactionBuilder();
            //var tx2 = builder2
            //    .AddCoins(colored, forFees) // note: added newly created colored coin, and coin to pay fees in this example
            //    .AddKeys(bookKey)
            //    .SendAsset(book, new AssetMoney(assetId2, 10))
            //    .SetChange(nico)
            //    .SendFees(Money.Coins(0.0001m))
            //    .BuildTransaction(true);

            //Console.WriteLine(tx2); // again, errors b/c we don't have Nico's secret and I don't feel like creating another real tx and dealing with privacy when I push this to github

            // UNIT TESTS
            // create 2 issuers silver and gold, and fake tx to give bitcoin to silver, gold, satoshi
            var gold     = new Key();
            var silver   = new Key();
            var goldId   = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
            var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

            var alice   = new Key();
            var bob     = new Key();
            var satoshi = new Key();

            var init = new Transaction()
            {
                Outputs =
                {
                    new TxOut("1.0", gold),
                    new TxOut("1.0", silver),
                    new TxOut("1.0", satoshi)
                }
            };
            // in NBitcoin the sammary of color coin issuance and transfer is described by class ColoredTransaction
            // the trick to writing unit tests is to use an in memory IColoredTransactionRepository
            var repo = new NoSqlColoredTransactionRepository();

            // now we can put the init tx inside
            repo.Transactions.Put(init);
            // now we can get the color
            ColoredTransaction color = ColoredTransaction.FetchColors(init, repo);

            Console.WriteLine(color);
            // now we will use the coins sent to silver and gold as Issuance coins
            var issuanceCoins = init
                                .Outputs
                                .AsCoins()
                                .Take(2)
                                .Select((c, i) => new IssuanceCoin(c))
                                .OfType <ICoin>()
                                .ToArray();
            var sendGoldToSatoshi = new Transaction(); // use TransactionBuilder to send Gold to Satoshi, then put resulting tx in repo and print result

            var goldCoin = ColoredCoin.Find(sendGoldToSatoshi, color).FirstOrDefault();

            builder = new TransactionBuilder();
            var sendToBobAndAlice = builder
                                    .AddKeys(satoshi)
                                    .AddCoins(goldCoin)
                                    .SendAsset(alice, new AssetMoney(goldId, 4))
                                    .SetChange(satoshi)
                                    .BuildTransaction(true);
            // not enough funds; goldCoin input only has 600sats and need 1200 for output to transfer assets to Alice and change to satoshi; add coin
            var satoshiBtc = init.Outputs.AsCoins().Last();

            builder = new TransactionBuilder();
            var sendToAlice = builder
                              .AddKeys(satoshi)
                              .AddCoins(goldCoin, satoshiBtc)
                              .SendAsset(alice, new AssetMoney(goldId, 4))
                              .SetChange(satoshi)
                              .BuildTransaction(true);

            repo.Transactions.Put(sendToAlice);
            color = ColoredTransaction.FetchColors(sendToAlice, repo);
            // see transaction and its color
            Console.WriteLine(sendToAlice);
            Console.WriteLine(color);
            // have made a unit test that emits and transfers some assets w/o any external dependencies
        }
 public Task PutAsync(uint256 txId, ColoredTransaction colored)
 {
     _Configuration.CreateIndexer().Index(new TransactionEntry.Entity(txId, colored));
     return(Task.FromResult(false));
 }
 public TransactionEntity(string partitionKey, uint256 txId, ColoredTransaction colored) : base(partitionKey)
 {
     TxId = txId ?? throw new ArgumentNullException("txId");
     ColoredTransaction = colored;
     Type = TransactionEntryType.Colored;
 }
        public async Task <TransactionEntry> GetTransactionAsync(bool lazyLoadPreviousOutput, bool fetchColor, uint256 txId)
        {
            if (txId == null)
            {
                return(null);
            }
            TransactionEntry result = null;

            var table          = Configuration.GetTransactionTable();
            var searchedEntity = new TransactionEntry.Entity(txId);
            var query          = new TableQuery()
                                 .Where(
                TableQuery.CombineFilters(
                    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, searchedEntity.PartitionKey),
                    TableOperators.And,
                    TableQuery.CombineFilters(
                        TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThan, txId.ToString() + "-"),
                        TableOperators.And,
                        TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, txId.ToString() + "|")
                        )
                    ));

            query.TakeCount = 10; //Should not have more
            var entities = (await table.ExecuteQuerySegmentedAsync(query, null).ConfigureAwait(false))
                           .Select(e => new TransactionEntry.Entity(e)).ToArray();

            if (entities.Length == 0)
            {
                result = null;
            }
            else
            {
                result = new TransactionEntry(entities);
                if (result.Transaction == null)
                {
                    foreach (var block in result.BlockIds.Select(id => GetBlock(id)).Where(b => b != null))
                    {
                        result.Transaction      = block.Transactions.FirstOrDefault(t => t.GetHash() == txId);
                        entities[0].Transaction = result.Transaction;
                        if (entities[0].Transaction != null)
                        {
                            await table.ExecuteAsync(TableOperation.Merge(entities[0].CreateTableEntity())).ConfigureAwait(false);
                        }
                        break;
                    }
                }

                if (fetchColor && result.ColoredTransaction == null)
                {
                    result.ColoredTransaction      = ColoredTransaction.FetchColors(txId, result.Transaction, new IndexerColoredTransactionRepository(Configuration));
                    entities[0].ColoredTransaction = result.ColoredTransaction;
                    if (entities[0].ColoredTransaction != null)
                    {
                        await table.ExecuteAsync(TableOperation.Merge(entities[0].CreateTableEntity())).ConfigureAwait(false);
                    }
                }

                var needTxOut = result.SpentCoins == null && lazyLoadPreviousOutput && result.Transaction != null;
                if (needTxOut)
                {
                    var tasks =
                        result.Transaction
                        .Inputs
                        .Select(async txin =>
                    {
                        var parentTx = await GetTransactionAsync(false, false, txin.PrevOut.Hash).ConfigureAwait(false);
                        if (parentTx == null)
                        {
                            IndexerTrace.MissingTransactionFromDatabase(txin.PrevOut.Hash);
                            return(null);
                        }
                        return(parentTx.Transaction.Outputs[(int)txin.PrevOut.N]);
                    })
                        .ToArray();

                    await Task.WhenAll(tasks).ConfigureAwait(false);

                    if (tasks.All(t => t.Result != null))
                    {
                        var outputs = tasks.Select(t => t.Result).ToArray();
                        result.SpentCoins = outputs.Select((o, n) => new Spendable(result.Transaction.Inputs[n].PrevOut, o)).ToList();
                        entities[0].PreviousTxOuts.Clear();
                        entities[0].PreviousTxOuts.AddRange(outputs);
                        if (entities[0].IsLoaded)
                        {
                            await table.ExecuteAsync(TableOperation.Merge(entities[0].CreateTableEntity())).ConfigureAwait(false);
                        }
                    }
                }

                if (result.Transaction == null)
                {
                    result = null;
                }
            }

            return(result);
        }
Exemple #26
0
 public void Put(uint256 txId, ColoredTransaction colored)
 {
     _Configuration.CreateIndexer().Index(new TransactionEntry.Entity(txId, colored));
 }