Make HdPubKey compulsory
MODIFY
WalletWasabi.Tests/RegressionTests/CoinJoinTests.cs
WalletWasabi.Tests/RegressionTests/CoinJoinTests.cs
@@ -12,6 +12,7 @@ using System.Security;
using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.BitcoinCore.Rpc;
+using WalletWasabi.Blockchain.Analysis.Clustering;
using WalletWasabi.Blockchain.Blocks;
using WalletWasabi.Blockchain.Keys;
using WalletWasabi.Blockchain.TransactionOutputs;
@@ -260,8 +261,9 @@ namespace WalletWasabi.Tests.RegressionTests
{
// Test DelayedClientRoundRegistration logic.
ClientRoundRegistration first = null;
+ var randomKey = KeyManager.CreateNew(out _, "").GenerateNewKey(SmartLabel.Empty, KeyState.Clean, false);
var second = new ClientRoundRegistration(aliceClient,
- new[] { new SmartCoin(new Coin(uint256.One, 1, Money.Zero, Script.Empty), new[] { new OutPoint(uint256.One, 1) }, Height.Unknown, true, 2) },
+ new[] { new SmartCoin(new Coin(uint256.One, 1, Money.Zero, randomKey.P2wpkhScript), randomKey, new[] { new OutPoint(uint256.One, 1) }, Height.Unknown, true, 2) },
BitcoinAddress.Create("12Rty3c8j3QiZSwLVaBtch6XUMZaja3RC7", Network.Main));
first = second;
second = null;
@@ -1109,7 +1111,7 @@ namespace WalletWasabi.Tests.RegressionTests
var height = await rpc.GetBlockCountAsync();
var bechCoin = tx.Outputs.GetCoins(bech.ScriptPubKey).Single();
- var smartCoin = new SmartCoin(bechCoin, tx.Inputs.ToOutPoints().ToArray(), height + 1, replaceable: false, anonymitySet: tx.GetAnonymitySet(bechCoin.Outpoint.N));
+ var smartCoin = new SmartCoin(bechCoin, key, tx.Inputs.ToOutPoints().ToArray(), height + 1, replaceable: false, anonymitySet: tx.GetAnonymitySet(bechCoin.Outpoint.N));
var chaumianClient = new CoinJoinClient(synchronizer, rpc.Network, keyManager);
@@ -1217,10 +1219,10 @@ namespace WalletWasabi.Tests.RegressionTests
var bech3Coin = tx3.Outputs.GetCoins(bech3.ScriptPubKey).Single();
var bech4Coin = tx4.Outputs.GetCoins(bech4.ScriptPubKey).Single();
- var smartCoin1 = new SmartCoin(bech1Coin, tx1.Inputs.ToOutPoints().ToArray(), height, replaceable: false, anonymitySet: tx1.GetAnonymitySet(bech1Coin.Outpoint.N));
- var smartCoin2 = new SmartCoin(bech2Coin, tx2.Inputs.ToOutPoints().ToArray(), height, replaceable: false, anonymitySet: tx2.GetAnonymitySet(bech2Coin.Outpoint.N));
- var smartCoin3 = new SmartCoin(bech3Coin, tx3.Inputs.ToOutPoints().ToArray(), height, replaceable: false, anonymitySet: tx3.GetAnonymitySet(bech3Coin.Outpoint.N));
- var smartCoin4 = new SmartCoin(bech4Coin, tx4.Inputs.ToOutPoints().ToArray(), height, replaceable: false, anonymitySet: tx4.GetAnonymitySet(bech4Coin.Outpoint.N));
+ var smartCoin1 = new SmartCoin(bech1Coin, key1, tx1.Inputs.ToOutPoints().ToArray(), height, replaceable: false, anonymitySet: tx1.GetAnonymitySet(bech1Coin.Outpoint.N));
+ var smartCoin2 = new SmartCoin(bech2Coin, key2, tx2.Inputs.ToOutPoints().ToArray(), height, replaceable: false, anonymitySet: tx2.GetAnonymitySet(bech2Coin.Outpoint.N));
+ var smartCoin3 = new SmartCoin(bech3Coin, key3, tx3.Inputs.ToOutPoints().ToArray(), height, replaceable: false, anonymitySet: tx3.GetAnonymitySet(bech3Coin.Outpoint.N));
+ var smartCoin4 = new SmartCoin(bech4Coin, key4, tx4.Inputs.ToOutPoints().ToArray(), height, replaceable: false, anonymitySet: tx4.GetAnonymitySet(bech4Coin.Outpoint.N));
var chaumianClient1 = new CoinJoinClient(synchronizer, rpc.Network, keyManager);
var chaumianClient2 = new CoinJoinClient(synchronizer, rpc.Network, keyManager);
@@ -1242,8 +1244,9 @@ namespace WalletWasabi.Tests.RegressionTests
Assert.True(smartCoin1.CoinJoinInProgress);
Assert.True(smartCoin2.CoinJoinInProgress);
+ var randomKey = keyManager.GenerateNewKey(SmartLabel.Empty, KeyState.Clean, isInternal: false);
// Make sure it does not throw.
- await chaumianClient1.DequeueCoinsFromMixAsync(new SmartCoin(new Coin(network.Consensus.ConsensusFactory.CreateTransaction().GetHash(), 1, Money.Parse("3"), new Script()), new[] { new OutPoint(uint256.One, 0) }, Height.Mempool, replaceable: false, anonymitySet: 1), DequeueReason.UserRequested);
+ await chaumianClient1.DequeueCoinsFromMixAsync(new SmartCoin(new Coin(network.Consensus.ConsensusFactory.CreateTransaction().GetHash(), 1, Money.Parse("3"), randomKey.P2wpkhScript), randomKey, new[] { new OutPoint(uint256.One, 0) }, Height.Mempool, replaceable: false, anonymitySet: 1), DequeueReason.UserRequested);
Assert.True(2 == (await chaumianClient1.QueueCoinsToMixAsync(password, smartCoin1, smartCoin2)).Count());
await chaumianClient1.DequeueCoinsFromMixAsync(smartCoin1, DequeueReason.UserRequested);

MODIFY
WalletWasabi.Tests/UnitTests/SmartCoinTests.cs
WalletWasabi.Tests/UnitTests/SmartCoinTests.cs
using NBitcoin;
using System.Linq;
+using WalletWasabi.Blockchain.Analysis.Clustering;
+using WalletWasabi.Blockchain.Keys;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Models;
using Xunit;
@@ -14,6 +16,9 @@ namespace WalletWasabi.Tests.UnitTests
var tx = Transaction.Parse("0100000000010176f521a178a4b394b647169a89b29bb0d95b6bce192fd686d533eb4ea98464a20000000000ffffffff02ed212d020000000016001442da650f25abde0fef57badd745df7346e3e7d46fbda6400000000001976a914bd2e4029ce7d6eca7d2c3779e8eac36c952afee488ac02483045022100ea43ccf95e1ac4e8b305c53761da7139dbf6ff164e137a6ce9c09e15f316c22902203957818bc505bbafc181052943d7ab1f3ae82c094bf749813e8f59108c6c268a012102e59e61f20c7789aa73faf5a92dc8c0424e538c635c55d64326d95059f0f8284200000000", Network.TestNet);
var txId = tx.GetHash();
var index = 0U;
+ var km = KeyManager.CreateNew(out _, "");
+ var hdpk = km.GenerateNewKey(SmartLabel.Empty, KeyState.Clean, false);
+ tx.Outputs[0].ScriptPubKey = hdpk.P2wpkhScript;
var output = tx.Outputs[0];
var scriptPubKey = output.ScriptPubKey;
var amount = output.Value;
@@ -22,10 +27,10 @@ namespace WalletWasabi.Tests.UnitTests
var height = Height.Mempool;
var label = "foo";
- var coin = new SmartCoin(new Coin(txId, index, amount, scriptPubKey), spentOutputs, height, tx.RBF, tx.GetAnonymitySet(index), label, txId);
+ var coin = new SmartCoin(new Coin(txId, index, amount, scriptPubKey), hdpk, spentOutputs, height, tx.RBF, tx.GetAnonymitySet(index), label, txId);
// If the txId or the index differ, equality should think it's a different coin.
- var differentCoin = new SmartCoin(new Coin(txId, index + 1, amount, scriptPubKey), spentOutputs, height, tx.RBF, tx.GetAnonymitySet(index + 1), label, txId);
+ var differentCoin = new SmartCoin(new Coin(txId, index + 1, amount, scriptPubKey), hdpk, spentOutputs, height, tx.RBF, tx.GetAnonymitySet(index + 1), label, txId);
var differentOutput = tx.Outputs[1];
var differentSpentOutputs = new[]
{
@@ -33,7 +38,7 @@ namespace WalletWasabi.Tests.UnitTests
};
// If the txId and the index are the same, equality should think it's the same coin.
- var sameCoin = new SmartCoin(new Coin(txId, index, differentOutput.Value, differentOutput.ScriptPubKey), differentSpentOutputs, Height.Unknown, tx.RBF, tx.GetAnonymitySet(index), "boo", null);
+ var sameCoin = new SmartCoin(new Coin(txId, index, differentOutput.Value, differentOutput.ScriptPubKey), hdpk, differentSpentOutputs, Height.Unknown, tx.RBF, tx.GetAnonymitySet(index), "boo");
Assert.Equal(coin, sameCoin);
Assert.NotEqual(coin, differentCoin);

MODIFY
WalletWasabi.Tests/UnitTests/Transactions/PayjoinTests.cs
WalletWasabi.Tests/UnitTests/Transactions/PayjoinTests.cs
@@ -44,7 +44,7 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
};
pubKey.SetLabel(slabel);
pubKey.SetKeyState(KeyState.Used);
- return new SmartCoin(new Coin(RandomUtils.GetUInt256(), (uint)randomIndex(), Money.Coins(amount), pubKey.P2wpkhScript), spentOutput, height, false, anonymitySet, slabel, pubKey: pubKey);
+ return new SmartCoin(new Coin(RandomUtils.GetUInt256(), (uint)randomIndex(), Money.Coins(amount), pubKey.P2wpkhScript), pubKey, spentOutput, height, false, anonymitySet, slabel);
}
public static PSBT GenerateRandomTransaction()

MODIFY
WalletWasabi.Tests/UnitTests/Transactions/TransactionFactoryTests.cs
WalletWasabi.Tests/UnitTests/Transactions/TransactionFactoryTests.cs
@@ -594,7 +594,7 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
};
pubKey.SetLabel(slabel);
pubKey.SetKeyState(KeyState.Used);
- return new SmartCoin(new Coin(RandomUtils.GetUInt256(), (uint)randomIndex(), Money.Coins(amount), pubKey.P2wpkhScript), spentOutput, height, false, anonymitySet, slabel, pubKey: pubKey);
+ return new SmartCoin(new Coin(RandomUtils.GetUInt256(), (uint)randomIndex(), Money.Coins(amount), pubKey.P2wpkhScript), pubKey, spentOutput, height, false, anonymitySet, slabel);
}
private TransactionFactory CreateTransactionFactory(

MODIFY
WalletWasabi/Blockchain/TransactionBuilding/BuildTransactionResult.cs
WalletWasabi/Blockchain/TransactionBuilding/BuildTransactionResult.cs
using NBitcoin;
using System.Collections.Generic;
+using System.Linq;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Blockchain.Transactions;
using WalletWasabi.Helpers;
@@ -8,7 +9,7 @@ namespace WalletWasabi.Blockchain.TransactionBuilding
{
public class BuildTransactionResult
{
- public BuildTransactionResult(SmartTransaction transaction, PSBT psbt, bool spendsUnconfirmed, bool signed, Money fee, decimal feePercentOfSent, IEnumerable<SmartCoin> outerWalletOutputs, IEnumerable<SmartCoin> innerWalletOutputs, IEnumerable<SmartCoin> spentCoins)
+ public BuildTransactionResult(SmartTransaction transaction, PSBT psbt, bool spendsUnconfirmed, bool signed, Money fee, decimal feePercentOfSent, IEnumerable<Coin> outerWalletOutputs, IEnumerable<SmartCoin> innerWalletOutputs, IEnumerable<SmartCoin> spentCoins)
{
Transaction = Guard.NotNull(nameof(transaction), transaction);
Psbt = Guard.NotNull(nameof(psbt), psbt);
@@ -16,9 +17,9 @@ namespace WalletWasabi.Blockchain.TransactionBuilding
Signed = signed;
Fee = fee ?? Money.Zero;
FeePercentOfSent = feePercentOfSent;
- OuterWalletOutputs = outerWalletOutputs ?? new List<SmartCoin>();
- InnerWalletOutputs = innerWalletOutputs ?? new List<SmartCoin>();
- SpentCoins = Guard.NotNullOrEmpty(nameof(spentCoins), spentCoins);
+ OuterWalletOutputs = outerWalletOutputs;
+ InnerWalletOutputs = innerWalletOutputs;
+ SpentCoins = spentCoins;
}
public SmartTransaction Transaction { get; }
@@ -27,7 +28,7 @@ namespace WalletWasabi.Blockchain.TransactionBuilding
public bool Signed { get; }
public Money Fee { get; }
public decimal FeePercentOfSent { get; }
- public IEnumerable<SmartCoin> OuterWalletOutputs { get; }
+ public IEnumerable<Coin> OuterWalletOutputs { get; }
public IEnumerable<SmartCoin> InnerWalletOutputs { get; }
public IEnumerable<SmartCoin> SpentCoins { get; }
}

MODIFY
WalletWasabi/Blockchain/TransactionOutputs/SmartCoin.cs
WalletWasabi/Blockchain/TransactionOutputs/SmartCoin.cs
@@ -34,7 +34,7 @@ namespace WalletWasabi.Blockchain.TransactionOutputs
#region Constructors
- public SmartCoin(Coin coin, OutPoint[] spentOutputs, Height height, bool replaceable, int anonymitySet, SmartLabel label = null, uint256 spenderTransactionId = null, bool coinJoinInProgress = false, DateTimeOffset? bannedUntilUtc = null, bool spentAccordingToBackend = false, HdPubKey pubKey = null)
+ public SmartCoin(Coin coin, HdPubKey pubKey, OutPoint[] spentOutputs, Height height, bool replaceable, int anonymitySet, SmartLabel label = null, uint256 spenderTransactionId = null, bool coinJoinInProgress = false, DateTimeOffset? bannedUntilUtc = null, bool spentAccordingToBackend = false)
{
Coin = coin;
HashCode = (TransactionId, Index).GetHashCode();
@@ -51,7 +51,7 @@ namespace WalletWasabi.Blockchain.TransactionOutputs
HdPubKey = pubKey;
- Label = SmartLabel.Merge(HdPubKey?.Label, label);
+ Label = SmartLabel.Merge(HdPubKey.Label, label);
Cluster = new Cluster(this);

MODIFY
WalletWasabi/Blockchain/TransactionProcessing/TransactionProcessor.cs
WalletWasabi/Blockchain/TransactionProcessing/TransactionProcessor.cs
@@ -202,7 +202,7 @@ namespace WalletWasabi.Blockchain.TransactionProcessing
}
var c = new Coin(txId, i, output.Value, output.ScriptPubKey);
- SmartCoin newCoin = new SmartCoin(c, tx.Transaction.Inputs.ToOutPoints().ToArray(), tx.Height, tx.IsRBF, anonset, foundKey.Label, spenderTransactionId: null, false, pubKey: foundKey); // Do not inherit locked status from key, that's different.
+ SmartCoin newCoin = new SmartCoin(c, foundKey, tx.Transaction.Inputs.ToOutPoints().ToArray(), tx.Height, tx.IsRBF, anonset, foundKey.Label, spenderTransactionId: null, false); // Do not inherit locked status from key, that's different.
result.ReceivedCoins.Add(newCoin);
// If we did not have it.

MODIFY
WalletWasabi/Blockchain/Transactions/TransactionFactory.cs
WalletWasabi/Blockchain/Transactions/TransactionFactory.cs
@@ -269,28 +269,27 @@ namespace WalletWasabi.Blockchain.Transactions
}
var label = SmartLabel.Merge(payments.Requests.Select(x => x.Label).Concat(spentCoins.Select(x => x.Label)));
- var outerWalletOutputs = new List<SmartCoin>();
+ var outerWalletOutputs = new List<Coin>();
var innerWalletOutputs = new List<SmartCoin>();
for (var i = 0U; i < tx.Outputs.Count; i++)
{
TxOut output = tx.Outputs[i];
- var anonset = tx.GetAnonymitySet(i) + spentCoins.Min(x => x.AnonymitySet) - 1; // Minus 1, because count own only once.
+ var coin = new Coin(tx.GetHash(), i, output.Value, output.ScriptPubKey);
var foundKey = KeyManager.GetKeyForScriptPubKey(output.ScriptPubKey);
- var c = new Coin(tx.GetHash(), i, output.Value, output.ScriptPubKey);
- var coin = new SmartCoin(c, tx.Inputs.ToOutPoints().ToArray(), Height.Unknown, tx.RBF, anonset, pubKey: foundKey);
- label = SmartLabel.Merge(label, coin.Label); // foundKey's label is already added to the coinlabel.
-
- if (foundKey is null)
+ if (foundKey is { })
{
- outerWalletOutputs.Add(coin);
+ var anonset = tx.GetAnonymitySet(i) + spentCoins.Min(x => x.AnonymitySet) - 1; // Minus 1, because count own only once.
+ var smartCoin = new SmartCoin(coin, foundKey, tx.Inputs.ToOutPoints().ToArray(), Height.Unknown, tx.RBF, anonset);
+ label = SmartLabel.Merge(label, smartCoin.Label); // foundKey's label is already added to the coinlabel.
+ innerWalletOutputs.Add(smartCoin);
}
else
{
- innerWalletOutputs.Add(coin);
+ outerWalletOutputs.Add(coin);
}
}
- foreach (var coin in outerWalletOutputs.Concat(innerWalletOutputs))
+ foreach (var coin in innerWalletOutputs)
{
var foundPaymentRequest = payments.Requests.FirstOrDefault(x => x.Destination.ScriptPubKey == coin.ScriptPubKey);
@@ -304,8 +303,7 @@ namespace WalletWasabi.Blockchain.Transactions
coin.Label = SmartLabel.Merge(coin.Label, foundPaymentRequest.Label);
}
- var foundKey = KeyManager.GetKeyForScriptPubKey(coin.ScriptPubKey);
- foundKey?.SetLabel(coin.Label); // The foundkeylabel has already been added previously, so no need to concatenate.
+ coin.HdPubKey.SetLabel(coin.Label); // The foundkeylabel has already been added previously, so no need to concatenate.
}
Logger.LogInfo($"Transaction is successfully built: {tx.GetHash()}.");

Make HdPubKey compulsory