Exemplo n.º 1
0
 private static IColoredTransactionRepository EnsureCachedRepository(IColoredTransactionRepository repo)
 {
     if (repo is CachedColoredTransactionRepository)
     {
         return(repo);
     }
     repo = new CachedColoredTransactionRepository(repo);
     return(repo);
 }
 public async Task<bool> EnsureColoredTransactionLoadedAsync(IColoredTransactionRepository repository)
 {
     if(ColoredTransaction != null)
     {
         this.UpdateToColoredCoins();
         return true;
     }
     if(!(repository is CachedColoredTransactionRepository))
         repository = new CachedColoredTransactionRepository(repository);
     var tx = await repository.Transactions.GetAsync(TransactionId).ConfigureAwait(false);
     if(tx == null)
         return false;
     try
     {
         var color = await tx.GetColoredTransactionAsync(repository).ConfigureAwait(false);
         if(color == null)
             return false;
         ColoredTransaction = color;
         this.UpdateToColoredCoins();
         return true;
     }
     catch(TransactionNotFoundException)
     {
         return false;
     }
 }
Exemplo n.º 3
0
		private static async Task<ColoredTransaction> FetchColorsWithAncestorsSolved(uint256 txId, Transaction tx, CachedColoredTransactionRepository repo)
		{
			ColoredTransaction colored = new ColoredTransaction();

			Queue<ColoredEntry> previousAssetQueue = new Queue<ColoredEntry>();
			for(uint i = 0 ; i < tx.Inputs.Count ; i++)
			{
				var txin = tx.Inputs[i];
				var prevColored = repo.GetFromCache(txin.PrevOut.Hash);
				if(prevColored == null)
					continue;
				var prevAsset = prevColored.GetColoredEntry(txin.PrevOut.N);
				if(prevAsset != null)
				{
					var input = new ColoredEntry()
					{
						Index = i,
						Asset = prevAsset.Asset
					};
					previousAssetQueue.Enqueue(input);
					colored.Inputs.Add(input);
				}
			}

			uint markerPos = 0;
			var marker = ColorMarker.Get(tx, out markerPos);
			if(marker == null)
			{
				return colored;
			}
			colored.Marker = marker;
			if(!marker.HasValidQuantitiesCount(tx))
			{
				return colored;
			}

			AssetId issuedAsset = null;
			for(uint i = 0 ; i < markerPos ; i++)
			{
				var entry = new ColoredEntry();
				entry.Index = i;
				entry.Asset = new AssetMoney(entry.Asset.Id, i >= marker.Quantities.Length ? 0 : marker.Quantities[i]);
				if(entry.Asset.Quantity == 0)
					continue;

				if(issuedAsset == null)
				{
					var txIn = tx.Inputs.FirstOrDefault();
					if(txIn == null)
						continue;
					var prev = await repo.Transactions.GetAsync(txIn.PrevOut.Hash).ConfigureAwait(false);
					if(prev == null)
						throw new TransactionNotFoundException("This open asset transaction is issuing assets, but it needs a parent transaction in the TransactionRepository to know the address of the issued asset (missing : " + txIn.PrevOut.Hash + ")", txIn.PrevOut.Hash);
					issuedAsset = prev.Outputs[(int)txIn.PrevOut.N].ScriptPubKey.Hash.ToAssetId();
				}
				entry.Asset = new AssetMoney(issuedAsset, entry.Asset.Quantity);
				colored.Issuances.Add(entry);
			}

			long used = 0;
			for(uint i = markerPos + 1 ; i < tx.Outputs.Count ; i++)
			{
				var entry = new ColoredEntry();
				entry.Index = i;
				//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.
				entry.Asset = new AssetMoney(entry.Asset.Id, (i - 1) >= marker.Quantities.Length ? 0 : marker.Quantities[i - 1]);
				if(entry.Asset.Quantity == 0)
					continue;

				//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. 
				if(previousAssetQueue.Count == 0)
				{
					colored.Transfers.Clear();
					colored.Issuances.Clear();
					return colored;
				}
				entry.Asset = new AssetMoney(previousAssetQueue.Peek().Asset.Id, entry.Asset.Quantity);
				var remaining = entry.Asset.Quantity;
				while(remaining != 0)
				{
					if(previousAssetQueue.Count == 0 || previousAssetQueue.Peek().Asset.Id != entry.Asset.Id)
					{
						colored.Transfers.Clear();
						colored.Issuances.Clear();
						return colored;
					}
					var assertPart = Math.Min(previousAssetQueue.Peek().Asset.Quantity - used, remaining);
					remaining = remaining - assertPart;
					used += assertPart;
					if(used == previousAssetQueue.Peek().Asset.Quantity)
					{
						previousAssetQueue.Dequeue();
						used = 0;
					}
				}
				colored.Transfers.Add(entry);
			}
			return colored;
		}
Exemplo n.º 4
0
		private static IColoredTransactionRepository EnsureCachedRepository(IColoredTransactionRepository repo)
		{
			if(repo is CachedColoredTransactionRepository)
				return repo;
			repo = new CachedColoredTransactionRepository(new NoDuplicateColoredTransactionRepository(repo));
			return repo;
		}
Exemplo n.º 5
0
        private static async Task <ColoredTransaction> FetchColorsWithAncestorsSolved(uint256 txId, Transaction tx, CachedColoredTransactionRepository repo)
        {
            ColoredTransaction colored = new ColoredTransaction();

            Queue <ColoredEntry> previousAssetQueue = new Queue <ColoredEntry>();

            for (uint i = 0; i < tx.Inputs.Count; i++)
            {
                var txin        = tx.Inputs[i];
                var prevColored = repo.GetFromCache(txin.PrevOut.Hash);
                if (prevColored == null)
                {
                    continue;
                }
                var prevAsset = prevColored.GetColoredEntry(txin.PrevOut.N);
                if (prevAsset != null)
                {
                    var input = new ColoredEntry()
                    {
                        Index = i,
                        Asset = prevAsset.Asset
                    };
                    previousAssetQueue.Enqueue(input);
                    colored.Inputs.Add(input);
                }
            }

            uint markerPos = 0;
            var  marker    = ColorMarker.Get(tx, out markerPos);

            if (marker == null)
            {
                return(colored);
            }
            colored.Marker = marker;
            if (!marker.HasValidQuantitiesCount(tx))
            {
                return(colored);
            }

            AssetId issuedAsset = null;

            for (uint i = 0; i < markerPos; i++)
            {
                var entry = new ColoredEntry();
                entry.Index = i;
                entry.Asset = new AssetMoney(entry.Asset.Id, i >= marker.Quantities.Length ? 0 : marker.Quantities[i]);
                if (entry.Asset.Quantity == 0)
                {
                    continue;
                }

                if (issuedAsset == null)
                {
                    var txIn = tx.Inputs.FirstOrDefault();
                    if (txIn == null)
                    {
                        continue;
                    }
                    var prev = await repo.Transactions.GetAsync(txIn.PrevOut.Hash).ConfigureAwait(false);

                    if (prev == null)
                    {
                        throw new TransactionNotFoundException("This open asset transaction is issuing assets, but it needs a parent transaction in the TransactionRepository to know the address of the issued asset (missing : " + txIn.PrevOut.Hash + ")", txIn.PrevOut.Hash);
                    }
                    issuedAsset = prev.Outputs[(int)txIn.PrevOut.N].ScriptPubKey.Hash.ToAssetId();
                }
                entry.Asset = new AssetMoney(issuedAsset, entry.Asset.Quantity);
                colored.Issuances.Add(entry);
            }

            long used = 0;

            for (uint i = markerPos + 1; i < tx.Outputs.Count; i++)
            {
                var entry = new ColoredEntry();
                entry.Index = i;
                //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.
                entry.Asset = new AssetMoney(entry.Asset.Id, (i - 1) >= marker.Quantities.Length ? 0 : marker.Quantities[i - 1]);
                if (entry.Asset.Quantity == 0)
                {
                    continue;
                }

                //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.
                if (previousAssetQueue.Count == 0)
                {
                    colored.Transfers.Clear();
                    colored.Issuances.Clear();
                    return(colored);
                }
                entry.Asset = new AssetMoney(previousAssetQueue.Peek().Asset.Id, entry.Asset.Quantity);
                var remaining = entry.Asset.Quantity;
                while (remaining != 0)
                {
                    if (previousAssetQueue.Count == 0 || previousAssetQueue.Peek().Asset.Id != entry.Asset.Id)
                    {
                        colored.Transfers.Clear();
                        colored.Issuances.Clear();
                        return(colored);
                    }
                    var assertPart = Math.Min(previousAssetQueue.Peek().Asset.Quantity - used, remaining);
                    remaining = remaining - assertPart;
                    used     += assertPart;
                    if (used == previousAssetQueue.Peek().Asset.Quantity)
                    {
                        previousAssetQueue.Dequeue();
                        used = 0;
                    }
                }
                colored.Transfers.Add(entry);
            }
            return(colored);
        }
Exemplo n.º 6
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);

			//Verify that FetchColor update the repository
			var persistent = new NoSqlColoredTransactionRepository(tester.Repository.Transactions, new InMemoryNoSqlRepository());
			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
		}