Example #1
0
			public ColoredCoinTester([CallerMemberName]string test = null)
			{
				var testcase = JsonConvert.DeserializeObject<TestCase[]>(File.ReadAllText("Data/openasset-known-tx.json"))
					.First(t => t.test == test);
				NoSqlTransactionRepository repository = new NoSqlTransactionRepository();
				foreach(var tx in testcase.txs)
				{
					var txObj = Transaction.Parse(tx);
					repository.Put(txObj.GetHash(), txObj);
				}
				TestedTxId = uint256.Parse(testcase.testedtx);
				Repository = new NoSqlColoredTransactionRepository(repository, new InMemoryNoSqlRepository());
			}
Example #2
0
		public void CanBuildColoredTransaction()
		{
			var gold = new Key();
			var silver = new Key();
			var goldId = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
			var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

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

			var repo = new NoSqlColoredTransactionRepository();

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

			repo.Transactions.Put(init);

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

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

			var coins = new List<ICoin>();
			coins.AddRange(issuanceCoins);
			var txBuilder = new TransactionBuilder();
			txBuilder.StandardTransactionPolicy = RelayPolicy;
			//Can issue gold to satoshi and bob
			var tx = txBuilder
				.AddCoins(coins.ToArray())
				.AddKeys(gold)
				.IssueAsset(satoshi.PubKey, new AssetMoney(goldId, 1000))
				.IssueAsset(bob.PubKey, new AssetMoney(goldId, 500))
				.SendFees("0.1")
				.SetChange(gold.PubKey)
				.BuildTransaction(true);
			Assert.True(txBuilder.Verify(tx, "0.1"));

			//Ensure BTC from the IssuanceCoin are returned
			Assert.Equal(Money.Parse("0.89994240"), tx.Outputs[2].Value);
			Assert.Equal(gold.PubKey.ScriptPubKey, tx.Outputs[2].ScriptPubKey);

			repo.Transactions.Put(tx);

			var colored = tx.GetColoredTransaction(repo);
			Assert.Equal(2, colored.Issuances.Count);
			Assert.True(colored.Issuances.All(i => i.Asset.Id == goldId));
			AssertHasAsset(tx, colored, colored.Issuances[0], goldId, 500, bob.PubKey);
			AssertHasAsset(tx, colored, colored.Issuances[1], goldId, 1000, satoshi.PubKey);

			var coloredCoins = ColoredCoin.Find(tx, colored).ToArray();
			Assert.Equal(2, coloredCoins.Length);

			//Can issue silver to bob, and send some gold to satoshi
			coins.Add(coloredCoins.First(c => c.ScriptPubKey == bob.PubKey.ScriptPubKey));
			txBuilder = new TransactionBuilder();
			txBuilder.StandardTransactionPolicy = EasyPolicy;
			tx = txBuilder
				.AddCoins(coins.ToArray())
				.AddKeys(silver, bob)
				.SetChange(bob.PubKey)
				.IssueAsset(bob.PubKey, new AssetMoney(silverId, 10))
				.SendAsset(satoshi.PubKey, new AssetMoney(goldId, 30))
				.BuildTransaction(true);

			Assert.True(txBuilder.Verify(tx));
			colored = tx.GetColoredTransaction(repo);
			Assert.Equal(1, colored.Inputs.Count);
			Assert.Equal(goldId, colored.Inputs[0].Asset.Id);
			Assert.Equal(500, colored.Inputs[0].Asset.Quantity);
			Assert.Equal(1, colored.Issuances.Count);
			Assert.Equal(2, colored.Transfers.Count);
			AssertHasAsset(tx, colored, colored.Transfers[0], goldId, 470, bob.PubKey);
			AssertHasAsset(tx, colored, colored.Transfers[1], goldId, 30, satoshi.PubKey);

			repo.Transactions.Put(tx);


			//Can swap : 
			//satoshi wants to send 100 gold to bob 
			//bob wants to send 200 silver, 5 gold and 0.9 BTC to satoshi

			//Satoshi receive gold
			txBuilder = new TransactionBuilder();
			txBuilder.StandardTransactionPolicy = RelayPolicy;
			tx = txBuilder
					.AddKeys(gold)
					.AddCoins(issuanceCoins)
					.IssueAsset(satoshi.PubKey, new AssetMoney(goldId, 1000UL))
					.SetChange(gold.PubKey)
					.SendFees(Money.Coins(0.0004m))
					.BuildTransaction(true);
			Assert.True(txBuilder.Verify(tx));
			repo.Transactions.Put(tx);
			var satoshiCoin = ColoredCoin.Find(tx, repo).First();


			//Gold receive 2.5 BTC
			tx = new Transaction()
			{
				Outputs =
				{
					new TxOut("2.5",gold.PubKey)
				}
			};
			repo.Transactions.Put(tx.GetHash(), tx);

			//Bob receive silver and 2 btc
			txBuilder = new TransactionBuilder();
			txBuilder.StandardTransactionPolicy = RelayPolicy;
			tx = txBuilder
					.AddKeys(silver, gold)
					.AddCoins(issuanceCoins)
					.AddCoins(new Coin(new OutPoint(tx.GetHash(), 0), new TxOut("2.5", gold.PubKey.ScriptPubKey)))
					.IssueAsset(bob.PubKey, new AssetMoney(silverId, 300UL))
					.Send(bob.PubKey, "2.00")
					.SendFees(Money.Coins(0.0004m))
					.SetChange(gold.PubKey)
					.BuildTransaction(true);
			Assert.True(txBuilder.Verify(tx));
			repo.Transactions.Put(tx);

			var bobSilverCoin = ColoredCoin.Find(tx, repo).First();
			var bobBitcoin = new Coin(new OutPoint(tx.GetHash(), 2), tx.Outputs[2]);

			//Bob receive gold
			txBuilder = new TransactionBuilder();
			txBuilder.StandardTransactionPolicy = RelayPolicy;
			tx = txBuilder
					.AddKeys(gold)
					.AddCoins(issuanceCoins)
					.IssueAsset(bob.PubKey, new AssetMoney(goldId, 50UL))
					.SetChange(gold.PubKey)
					.SendFees(Money.Coins(0.0004m))
					.BuildTransaction(true);
			Assert.True(txBuilder.Verify(tx));
			repo.Transactions.Put(tx.GetHash(), tx);

			var bobGoldCoin = ColoredCoin.Find(tx, repo).First();

			txBuilder = new TransactionBuilder();
			txBuilder.StandardTransactionPolicy = RelayPolicy;
			tx = txBuilder
				.AddCoins(satoshiCoin)
				.AddCoins(satoshiBTC)
				.SendAsset(bob.PubKey, new AssetMoney(goldId, 100))
				.SendFees(Money.Coins(0.0004m))
				.SetChange(satoshi.PubKey)
				.Then()
				.AddCoins(bobSilverCoin, bobGoldCoin, bobBitcoin)
				.SendAsset(satoshi.PubKey, new AssetMoney(silverId, 200))
				.Send(satoshi.PubKey, "0.9")
				.SendAsset(satoshi.PubKey, new AssetMoney(goldId, 5))
				.SetChange(bob.PubKey)
				.BuildTransaction(false);

			colored = tx.GetColoredTransaction(repo);

			AssertHasAsset(tx, colored, colored.Inputs[0], goldId, 1000, null);
			AssertHasAsset(tx, colored, colored.Inputs[1], silverId, 300, null);

			AssertHasAsset(tx, colored, colored.Transfers[0], goldId, 900, satoshi.PubKey);
			AssertHasAsset(tx, colored, colored.Transfers[1], goldId, 100, bob.PubKey);

			AssertHasAsset(tx, colored, colored.Transfers[2], silverId, 100, bob.PubKey);
			AssertHasAsset(tx, colored, colored.Transfers[3], silverId, 200, satoshi.PubKey);

			AssertHasAsset(tx, colored, colored.Transfers[4], goldId, 45, bob.PubKey);
			AssertHasAsset(tx, colored, colored.Transfers[5], goldId, 5, satoshi.PubKey);

			Assert.True(tx.Outputs[8].Value == Money.Parse("1.0999424"));
			Assert.True(tx.Outputs[8].ScriptPubKey == bob.PubKey.ScriptPubKey);
			Assert.True(tx.Outputs[9].Value == Money.Parse("0.9"));
			Assert.True(tx.Outputs[9].ScriptPubKey == satoshi.PubKey.ScriptPubKey);

			tx = txBuilder.AddKeys(satoshi, bob).SignTransaction(tx);
			Assert.True(txBuilder.Verify(tx));


			//Bob send coins to Satoshi, but alice pay for the dust
			var funding =
				new TransactionBuilder()
				{
					StandardTransactionPolicy = RelayPolicy
				}
				.AddCoins(issuanceCoins)
				.AddKeys(gold)
				.IssueAsset(bob.PubKey.Hash, new AssetMoney(goldId, 100UL))
				.SetChange(gold.PubKey.Hash)
				.SendFees(Money.Coins(0.0004m))
				.BuildTransaction(true);

			repo.Transactions.Put(funding);

			var bobGold = ColoredCoin.Find(funding, repo).ToArray();

			Transaction transfer = null;
			try
			{
				transfer =
					new TransactionBuilder()
					{
						StandardTransactionPolicy = RelayPolicy
					}
					.AddCoins(bobGold)
					.SendAsset(alice.PubKey.Hash, new AssetMoney(goldId, 40UL))
					.SetChange(bob.PubKey.Hash)
					.BuildTransaction(true);
				Assert.False(true, "Should have thrown");
			}
			catch(NotEnoughFundsException ex) //Not enough dust to send the change
			{
				Assert.True(((Money)ex.Missing).Satoshi == 2730);
				var rate = new FeeRate(Money.Coins(0.0004m));
				txBuilder = new TransactionBuilder();
				txBuilder.StandardTransactionPolicy = RelayPolicy;
				transfer =
					txBuilder
					.AddCoins(bobGold)
					.AddCoins(((IssuanceCoin)issuanceCoins[0]).Bearer)
					.AddKeys(gold, bob)
					.SendAsset(alice.PubKey, new AssetMoney(goldId, 40UL))
					.SetChange(bob.PubKey, ChangeType.Colored)
					.SetChange(gold.PubKey.Hash, ChangeType.Uncolored)
					.SendEstimatedFees(rate)
					.BuildTransaction(true);
				var fee = transfer.GetFee(txBuilder.FindSpentCoins(transfer));
				Assert.True(txBuilder.Verify(transfer, fee));

				repo.Transactions.Put(funding.GetHash(), funding);

				colored = ColoredTransaction.FetchColors(transfer, repo);
				AssertHasAsset(transfer, colored, colored.Transfers[0], goldId, 60, bob.PubKey);
				AssertHasAsset(transfer, colored, colored.Transfers[1], goldId, 40, alice.PubKey);

				var change = transfer.Outputs.Last(o => o.ScriptPubKey == gold.PubKey.Hash.ScriptPubKey);
				Assert.Equal(Money.Coins(0.99980450m), change.Value);

				Assert.Equal(gold.PubKey.Hash, change.ScriptPubKey.GetDestination());

				//Verify issuancecoin can have an url
				var issuanceCoin = (IssuanceCoin)issuanceCoins[0];
				issuanceCoin.DefinitionUrl = new Uri("http://toto.com/");
				txBuilder = new TransactionBuilder();
				tx = txBuilder
					.AddKeys(gold)
					.AddCoins(issuanceCoin)
					.IssueAsset(bob, new AssetMoney(gold.PubKey, 10))
					.SetChange(gold)
					.BuildTransaction(true);

				Assert.Equal("http://toto.com/", tx.GetColoredMarker().GetMetadataUrl().AbsoluteUri);
			}
		}
Example #3
0
		public void CanBuildShuffleColoredTransaction()
		{
			var gold = new Key();
			var silver = new Key();
			var goldId = gold.PubKey.ScriptPubKey.Hash.ToAssetId();
			var silverId = silver.PubKey.ScriptPubKey.Hash.ToAssetId();

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

			var repo = new NoSqlColoredTransactionRepository(new NoSqlTransactionRepository(), new InMemoryNoSqlRepository());

			var init = new Transaction()
			{
				Outputs =
				{
					new TxOut("1.0", gold.PubKey),
					new TxOut("1.0", silver.PubKey),
					new TxOut("1.0", satoshi.PubKey)
				}
			};
			repo.Transactions.Put(init.GetHash(), init);

			var issuanceCoins =
				init
				.Outputs
				.Take(2)
				.Select((o, i) => new IssuanceCoin(new OutPoint(init.GetHash(), i), init.Outputs[i]))
				.OfType<ICoin>().ToArray();

			var satoshiBTC = new Coin(new OutPoint(init.GetHash(), 2), init.Outputs[2]);

			var coins = new List<ICoin>();
			coins.AddRange(issuanceCoins);
			var txBuilder = new TransactionBuilder(1);
			txBuilder.StandardTransactionPolicy = RelayPolicy;
			//Can issue gold to satoshi and bob
			var tx = txBuilder
				.AddCoins(coins.ToArray())
				.AddKeys(gold)
				.IssueAsset(satoshi.PubKey, new AssetMoney(goldId, 1000))
				.IssueAsset(bob.PubKey, new AssetMoney(goldId, 500))
				.SendFees("0.1")
				.SetChange(gold.PubKey)
				.BuildTransaction(true);
			Assert.True(txBuilder.Verify(tx, "0.1"));

			//Ensure BTC from the IssuanceCoin are returned
			Assert.Equal(Money.Parse("0.89994240"), tx.Outputs[2].Value);
			Assert.Equal(gold.PubKey.ScriptPubKey, tx.Outputs[2].ScriptPubKey);

			//Can issue and send in same transaction
			repo.Transactions.Put(tx.GetHash(), tx);


			var cc = ColoredCoin.Find(tx, repo);
			for(int i = 0 ; i < 20 ; i++)
			{
				txBuilder = new TransactionBuilder(i);
				txBuilder.StandardTransactionPolicy = RelayPolicy;
				tx = txBuilder
					.AddCoins(satoshiBTC)
					.AddCoins(cc)
					.AddKeys(satoshi)
					.SendAsset(gold, new AssetMoney(goldId, 10))
					.SetChange(satoshi)
					.Then()
					.AddKeys(gold)
					.AddCoins(issuanceCoins)
					.IssueAsset(bob, new AssetMoney(goldId, 1))
					.SetChange(gold)
					.Shuffle()
					.BuildTransaction(true);

				repo.Transactions.Put(tx.GetHash(), tx);

				var ctx = tx.GetColoredTransaction(repo);
				Assert.Equal(1, ctx.Issuances.Count);
				Assert.Equal(2, ctx.Transfers.Count);
			}
		}
Example #4
0
		private static Transaction CreateSpecTransaction(NoSqlColoredTransactionRepository repo, Money dust, BitcoinAddress receiver, Transaction prior, Transaction issuanceA1, Transaction issuanceA2)
		{
			var testedTx = new Transaction();
			testedTx.Inputs.Add(new TxIn(new OutPoint(issuanceA1.GetHash(), 0)));
			testedTx.Inputs.Add(new TxIn(new OutPoint(issuanceA1.GetHash(), 1)));
			testedTx.Inputs.Add(new TxIn(new OutPoint(prior.GetHash(), 0)));
			testedTx.Inputs.Add(new TxIn(new OutPoint(issuanceA1.GetHash(), 2)));
			testedTx.Inputs.Add(new TxIn(new OutPoint(issuanceA1.GetHash(), 3)));
			testedTx.Inputs.Add(new TxIn(new OutPoint(issuanceA2.GetHash(), 0)));

			testedTx.Outputs.Add(new TxOut(Money.Parse("0.6"), receiver));
			testedTx.Outputs.Add(new TxOut(dust, receiver));
			testedTx.Outputs.Add(new TxOut(dust, new ColorMarker(new ulong[] { 0, 10, 6, 0, 7, 3 }).GetScript()));
			testedTx.Outputs.Add(new TxOut(dust, receiver));
			testedTx.Outputs.Add(new TxOut(dust, receiver));
			testedTx.Outputs.Add(new TxOut(dust, receiver));
			testedTx.Outputs.Add(new TxOut(dust, receiver));
			repo.Transactions.Put(testedTx.GetHash(), testedTx);
			return testedTx;
		}
Example #5
0
		//https://github.com/OpenAssets/open-assets-protocol/blob/master/specification.mediawiki
		public void CanColorizeSpecScenario()
		{
			var repo = new NoSqlColoredTransactionRepository();
			var dust = Money.Parse("0.00005");
			var colored = new ColoredTransaction();
			var a1 = new AssetKey();
			var a2 = new AssetKey();
			var h = new AssetKey();
			var sender = new Key().PubKey.GetAddress(Network.Main);
			var receiver = new Key().PubKey.GetAddress(Network.Main);

			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)));
			var 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);

			var prior = new Transaction();
			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);

			var issuanceA1 = new Transaction();
			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);

			var issuanceA2 = new Transaction();
			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);

			var testedTx = CreateSpecTransaction(repo, dust, receiver, prior, issuanceA1, issuanceA2);
			var 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.

			var 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);
		}
Example #6
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()));
		}
Example #7
0
        static void Main(string[] args)
        {
            var goldGuy = new BitcoinSecret("KyuzoVnpsqW529yzozkzP629wUDBsPmm4QEkh9iKnvw3Dy5JJiNg");
            var silverGuy = new BitcoinSecret("L4KvjpqDtdGEn7Lw6HdDQjbg74MwWRrFZMQTgJozeHAKJw5rQ2Kn");

            var firstPerson = new BitcoinSecret("5Jnw9Td7PaG6PWBrU7ZCfxyVXsHSsNxdZ9sg5dnZstcr12DLVbJ");
            var secondPerson = new BitcoinSecret("5Jn4zJkzS2BWNu7AMRTdSJ6mS7JYfJg27oXKAichaRBbp97ZKks");
            var exchangeEntity = new BitcoinSecret("5KA7FeABKmMKerWmkJzYM9FdoqScZEMVcS9u6wvT3EhgF5ZUWv5");

            var bitcoinProviderEntity = new BitcoinSecret("5Jcz2A17aAt4bcQP5GEn6itt72JsLwrksNRVKqazy7n284b1bKj");

            var issuanceCoinsTransaction = new Transaction()
            {
                Outputs =
                {
                    new TxOut("1.0", goldGuy.PubKey),
                    new TxOut("1.0", silverGuy.PubKey),
                    new TxOut("1.0", firstPerson.PubKey),
                    new TxOut("1.0", secondPerson.PubKey),
                }
            };

            IssuanceCoin[] issuanceCoins = issuanceCoinsTransaction
                        .Outputs
                        .Take(2)
                        .Select((o, i) => new Coin(new OutPoint(issuanceCoinsTransaction.GetHash(), i), o))
                        .Select(c => new IssuanceCoin(c))
                        .ToArray();

            var goldIssuanceCoin = issuanceCoins[0];
            var silverIssuanceCoin = issuanceCoins[1];
            var firstPersonInitialCoin = new Coin(new OutPoint(issuanceCoinsTransaction, 2), issuanceCoinsTransaction.Outputs[2]);
            var secondPersonInitialCoin = new Coin(new OutPoint(issuanceCoinsTransaction, 3), issuanceCoinsTransaction.Outputs[3]);

            var goldId = goldIssuanceCoin.AssetId;
            var silverId = silverIssuanceCoin.AssetId;

            var txRepo = new NoSqlTransactionRepository();
            txRepo.Put(issuanceCoinsTransaction.GetHash(), issuanceCoinsTransaction);

            var ctxRepo = new NoSqlColoredTransactionRepository(txRepo);

            TransactionBuilder txBuilder = new TransactionBuilder();

            // Issuing gold to first person
            // This happens in gold issuer client
            Transaction tx = txBuilder
                .AddKeys(goldGuy.PrivateKey)
                .AddCoins(goldIssuanceCoin)
                .IssueAsset(firstPerson.GetAddress(), new AssetMoney(goldId, 20))
                .SetChange(goldGuy.GetAddress())
                .BuildTransaction(true);

            txRepo.Put(tx.GetHash(), tx);
            var ctx = tx.GetColoredTransaction(ctxRepo);
            var coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();
            ColoredCoin firstPersonGoldCoin = coloredCoins[0];

            // Issuing silver to second person
            // This happens in silver issuer client
            txBuilder = new TransactionBuilder();
            tx = txBuilder
                .AddKeys(silverGuy.PrivateKey)
                .AddCoins(silverIssuanceCoin)
                .IssueAsset(secondPerson.GetAddress(), new AssetMoney(silverId, 30))
                .SetChange(silverGuy.GetAddress())
                .BuildTransaction(true);

            txRepo.Put(tx.GetHash(), tx);
            ctx = tx.GetColoredTransaction(ctxRepo);
            coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();
            ColoredCoin secondPersonSilverCoin = coloredCoins[0];

            // Sending first person gold to exchange
            // This happens in first user client
            var bitcoinProviderCoin = CreateTransactionFeeCoin(bitcoinProviderEntity.PubKey, txRepo);
            txBuilder = new TransactionBuilder();
            tx = txBuilder
                .AddCoins(bitcoinProviderCoin)
                .AddKeys(bitcoinProviderEntity.PrivateKey)
                .AddCoins(firstPersonGoldCoin)
                .AddKeys(firstPerson.PrivateKey)
                .SendAssetToExchange(exchangeEntity.GetAddress(), new AssetMoney(goldId, 5))
                .SetChange(firstPerson.PubKey)
                .BuildTransaction(true);
            txRepo.Put(tx.GetHash(), tx);
            ctx = tx.GetColoredTransaction(ctxRepo);
            coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();
            ColoredCoin firstPersonColoredCoinInExchange = coloredCoins[1];

            // Creating the time-locked transaction which the first user can post to the
            // network to claim his/her coin from exchange (it works if the exchange does not touch the coins
            // This happens in exchange and the transaction is delivered to first user client
            bitcoinProviderCoin = CreateTransactionFeeCoin(bitcoinProviderEntity.PubKey, txRepo);
            txBuilder = new TransactionBuilder();
            tx = txBuilder
                .AddCoins(bitcoinProviderCoin)
                .AddKeys(bitcoinProviderEntity.PrivateKey)
                .AddCoins(firstPersonColoredCoinInExchange)
                .AddKeys(firstPerson.PrivateKey)
                .SendAsset(firstPerson.PubKey, new AssetMoney(firstPersonColoredCoinInExchange.Amount.Id,
                    firstPersonColoredCoinInExchange.Amount.Quantity))
                .SetChange(exchangeEntity.PubKey)
                .SetLockTime(new LockTime(1000000))
                .BuildTransaction(true);
            string reclaimTransactionForFirstUser = tx.ToHex();

            // Create first person exchange request
            // This happens in first person client
            JObject firstPersonRequestToExchange = CreateExchangeRequest("ExactMatch", goldId.ToString(),
                silverId.ToString(), 5, 2);
            var firstRequestSignature = firstPerson.PrivateKey.SignMessage(firstPersonRequestToExchange.ToString(Formatting.None));

            // Sending second person silver to exchange
            // This happens in second person client
            bitcoinProviderCoin = CreateTransactionFeeCoin(bitcoinProviderEntity.PubKey, txRepo);
            txBuilder = new TransactionBuilder();
            tx = txBuilder
                .AddCoins(bitcoinProviderCoin)
                .AddKeys(bitcoinProviderEntity.PrivateKey)
                .AddCoins(secondPersonSilverCoin)
                .AddKeys(secondPerson.PrivateKey)
                .SendAssetToExchange(exchangeEntity.GetAddress(), new AssetMoney(silverId, 12))
                .SetChange(secondPerson.PubKey)
                .BuildTransaction(true);
            txRepo.Put(tx.GetHash(), tx);
            ctx = tx.GetColoredTransaction(ctxRepo);
            coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();
            ColoredCoin secondPersonColoredCoinInExchange = coloredCoins[1];

            // Create second person exchange request
            // This happens in second person client
            JObject secondPersonRequestToExchange = CreateExchangeRequest("ExactMatch", silverId.ToString(),
                goldId.ToString(), 30, 0.5f);
            var secondRequestSignature = secondPerson.PrivateKey.SignMessage(secondPersonRequestToExchange.ToString(Formatting.None));

            // Creating exchange reason
            // This happens in exchange
            var exchangeReason = CreateExchangeMatch(firstPersonRequestToExchange, firstRequestSignature,
                secondPersonRequestToExchange, secondRequestSignature, exchangeEntity.PrivateKey);

            // Performing the exchange operation
            // This happens in exchange
            bitcoinProviderCoin = CreateTransactionFeeCoin(bitcoinProviderEntity.PubKey, txRepo);
            txBuilder = new TransactionBuilder();
            tx = txBuilder
                .AddCoins(bitcoinProviderCoin)
                .AddKeys(bitcoinProviderEntity.PrivateKey)
                .AddCoins(firstPersonColoredCoinInExchange)
                .AddKeys(exchangeEntity.PrivateKey)
                .AddCoins(secondPersonColoredCoinInExchange)
                .AddKeys(exchangeEntity.PrivateKey)
                .PerformExchangeOperation(firstPerson.GetAddress(), new AssetMoney(silverId, 10),
                secondPerson.GetAddress(), new AssetMoney(goldId, 5), exchangeReason.ToString(Formatting.None))
                .SetChange(exchangeEntity.GetAddress())
                .BuildTransaction(true);
            txRepo.Put(tx.GetHash(), tx);
            ctx = tx.GetColoredTransaction(ctxRepo);
            coloredCoins = ColoredCoin.Find(tx, ctx).ToArray();

            txRepo.Put(tx.GetHash(), tx);
        }
Example #8
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
		}