public async Task RegisterBannedCoinAsync() { using CancellationTokenSource timeoutCts = new(TimeSpan.FromMinutes(2)); var bannedOutPoint = BitcoinFactory.CreateOutPoint(); var httpClient = _apiApplicationFactory.WithWebHostBuilder(builder => builder.ConfigureServices(services => { var inmate = new Inmate(bannedOutPoint, Punishment.LongBanned, DateTimeOffset.UtcNow, uint256.One); services.AddScoped <Prison>(_ => new Prison(new[] { inmate })); })).CreateClient(); var apiClient = await _apiApplicationFactory.CreateArenaClientAsync(httpClient); var rounds = (await apiClient.GetStatusAsync(RoundStateRequest.Empty, timeoutCts.Token)).RoundStates; var round = rounds.First(x => x.CoinjoinState is ConstructionState); // If an output is not in the utxo dataset then it is not unspent, this // means that the output is spent or simply doesn't even exist. using var signingKey = new Key(); var ownershipProof = WabiSabiFactory.CreateOwnershipProof(signingKey, round.Id); var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(async() => await apiClient.RegisterInputAsync(round.Id, bannedOutPoint, ownershipProof, timeoutCts.Token)); Assert.Equal(WabiSabiProtocolErrorCode.InputLongBanned, ex.ErrorCode); var inputBannedData = Assert.IsType <InputBannedExceptionData>(ex.ExceptionData); Assert.True(inputBannedData.BannedUntil > DateTimeOffset.UtcNow); }
public async Task DoesntUpdateAsync(Network network) { await using var txStore = new AllTransactionStore(PrepareWorkDir(), network); await txStore.InitializeAsync(ensureBackwardsCompatibility : false); var tx = BitcoinFactory.CreateSmartTransaction(); Assert.False(txStore.TryUpdate(tx)); // Assert TryUpdate didn't modify anything. Assert.NotNull(txStore.ConfirmedStore); Assert.NotNull(txStore.MempoolStore); Assert.Empty(txStore.GetTransactions()); Assert.Empty(txStore.GetTransactionHashes()); Assert.Empty(txStore.MempoolStore.GetTransactions()); Assert.Empty(txStore.MempoolStore.GetTransactionHashes()); Assert.Empty(txStore.ConfirmedStore.GetTransactions()); Assert.Empty(txStore.ConfirmedStore.GetTransactionHashes()); uint256 txHash = BitcoinFactory.CreateSmartTransaction().GetHash(); Assert.False(txStore.Contains(txHash)); Assert.True(txStore.IsEmpty()); Assert.False(txStore.TryGetTransaction(txHash, out _)); }
public void SetUsedLabelIncludePrivateFunds() { var selection = new LabelSelectionViewModel(Money.Parse("1.5")); var pockets = new List <Pocket>(); pockets.AddPocket(1.0M, out _, "Dan"); var privateCoins = new[] { BitcoinFactory.CreateSmartCoin(LabelTestExtensions.NewKey(anonymitySet: 999), 0.5m), BitcoinFactory.CreateSmartCoin(LabelTestExtensions.NewKey(anonymitySet: 999), 0.5m), }; var coinsView = new CoinsView(privateCoins.ToArray()); var pocket = new Pocket((SmartLabel.Empty, coinsView)); pockets.Add(pocket); selection.Reset(pockets.ToArray()); var output = selection.AutoSelectPockets("Dan"); selection.SetUsedLabel(output.SelectMany(x => x.Coins), privateThreshold: 10); Assert.True(selection.EnoughSelected); }
public void PreferLessCoinsOverExactAmount() { var keys = Enumerable.Range(0, 10) .Select(_ => KeyManager.GenerateNewKey(new SmartLabel("Juan"), KeyState.Clean, false)) .ToList(); var cluster = new Cluster(keys); var smartCoins = keys .Select((key, i) => { var coin = BitcoinFactory.CreateSmartCoin(key, 0.1m * (i + 1)); coin.HdPubKey.Cluster = cluster; return(coin); }) .ToList(); smartCoins.Add(BitcoinFactory.CreateSmartCoin(keys[0], 0.11m)); var selector = new SmartCoinSelector(smartCoins); var someCoins = smartCoins.Select(x => x.Coin); var coinsToSpend = selector.Select(someCoins, Money.Coins(0.41m)); var theOnlyOne = Assert.Single(coinsToSpend.Cast <Coin>()); Assert.Equal(0.5m, theOnlyOne.Amount.ToUnit(MoneyUnit.BTC)); }
public void PreferSameScript() { var keys = Enumerable.Range(0, 12) .Select(_ => KeyManager.GenerateNewKey(new SmartLabel("Juan"), KeyState.Clean, false)) .ToList(); var cluster = new Cluster(keys); var smartCoins = keys .ConvertAll(key => { var coin = BitcoinFactory.CreateSmartCoin(key, 0.2m); coin.HdPubKey.Cluster = cluster; return(coin); }); smartCoins.Add(BitcoinFactory.CreateSmartCoin(keys[0], 0.11m)); var selector = new SmartCoinSelector(smartCoins); var coinsToSpend = selector.Select(Enumerable.Empty <Coin>(), Money.Coins(0.31m)).Cast <Coin>().ToList(); Assert.Equal(2, coinsToSpend.Count); Assert.Equal(coinsToSpend[0].ScriptPubKey, coinsToSpend[1].ScriptPubKey); Assert.Equal(0.31m, coinsToSpend.Sum(x => x.Amount.ToUnit(MoneyUnit.BTC))); }
public void PreferMorePrivateClusterScript() { var keys1 = Enumerable.Range(0, 5) .Select(_ => KeyManager.GenerateNewKey(new SmartLabel("Juan"), KeyState.Clean, false)) .ToList(); var juanCluster = new Cluster(keys1); var coinsKnownByJuan = keys1 .ConvertAll(key => { var coin = BitcoinFactory.CreateSmartCoin(key, 0.2m); coin.HdPubKey.Cluster = juanCluster; return(coin); }); var keys2 = Enumerable.Range(0, 2) .Select(_ => KeyManager.GenerateNewKey(new SmartLabel("Juan"), KeyState.Clean, false)) .ToList(); var betoCluster = new Cluster(keys2); var coinsKnownByBeto = keys2 .ConvertAll(key => { var coin = BitcoinFactory.CreateSmartCoin(key, 0.2m); coin.HdPubKey.Cluster = betoCluster; return(coin); }); var selector = new SmartCoinSelector(coinsKnownByJuan.Concat(coinsKnownByBeto)); var coinsToSpend = selector.Select(Enumerable.Empty <Coin>(), Money.Coins(0.3m)).Cast <Coin>().ToList(); Assert.Equal(2, coinsToSpend.Count); Assert.Equal(0.4m, coinsToSpend.Sum(x => x.Amount.ToUnit(MoneyUnit.BTC))); }
public async Task ReleasesInmatesAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); // Create prison. CoordinatorParameters coordinatorParameters = new(workDir); coordinatorParameters.RuntimeCoordinatorConfig.ReleaseUtxoFromPrisonAfter = TimeSpan.FromMilliseconds(1); using var w = new Warden(coordinatorParameters.UtxoWardenPeriod, coordinatorParameters.PrisonFilePath, coordinatorParameters.RuntimeCoordinatorConfig); await w.StartAsync(CancellationToken.None); var i1 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Noted, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); var i2 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Banned, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); var p = w.Prison; p.Punish(i1); p.Punish(i2); Assert.NotEmpty(p.GetInmates()); // Wait until releases from prison. await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); Assert.Empty(p.GetInmates()); await w.StopAsync(CancellationToken.None); }
public void CanMergeSingleOperations() { var tx = BitcoinFactory.CreateSmartTransaction(); var append = new Append(tx); var unmergedAppendOperations = new[] { append }; var mergedOperations = OperationMerger.Merge(unmergedAppendOperations); var expectedOperation = Assert.Single(mergedOperations); var expectedAppendOperationInstance = Assert.IsType <Append>(expectedOperation); var expectedTx = Assert.Single(expectedAppendOperationInstance.Transactions); Assert.Equal(expectedTx, tx); var remove = new Remove(tx.GetHash()); var unmergedRemoveOperations = new[] { remove }; mergedOperations = OperationMerger.Merge(unmergedRemoveOperations); expectedOperation = Assert.Single(mergedOperations); var expectedRemoveOperationInstance = Assert.IsType <Remove>(expectedOperation); var expectedTxHash = Assert.Single(expectedRemoveOperationInstance.Transactions); Assert.Equal(expectedTxHash, tx.GetHash()); var update = new Update(tx); var unmergedUpdateOperations = new[] { update }; mergedOperations = OperationMerger.Merge(unmergedUpdateOperations); expectedOperation = Assert.Single(mergedOperations); var expectedUpdateOperationInstance = Assert.IsType <Update>(expectedOperation); expectedTx = Assert.Single(expectedUpdateOperationInstance.Transactions); Assert.Equal(expectedTx, tx); }
public async Task SuccessAsync() { WabiSabiConfig cfg = new(); var round = WabiSabiFactory.CreateRound(cfg); var initialRemaining = round.RemainingInputVsizeAllocation; var alice = WabiSabiFactory.CreateAlice(round); round.Alices.Add(alice); Assert.True(round.RemainingInputVsizeAllocation < initialRemaining); using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, round); await using ArenaRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient()); // There's no such alice yet, so success. var req = new InputsRemovalRequest(round.Id, BitcoinFactory.CreateUint256()); await handler.RemoveInputAsync(req, CancellationToken.None); // There was the alice we want to remove so success. req = new InputsRemovalRequest(round.Id, alice.Id); await handler.RemoveInputAsync(req, CancellationToken.None); // Ensure that removing an alice freed up the input vsize // allocation from the round Assert.Equal(initialRemaining, round.RemainingInputVsizeAllocation); await arena.StopAsync(CancellationToken.None); }
public async Task CanInitializeEmptyAsync(Network network) { var dir = PrepareWorkDir(); await using var txStore = new AllTransactionStore(dir, network); await txStore.InitializeAsync(ensureBackwardsCompatibility : false); Assert.NotNull(txStore.ConfirmedStore); Assert.NotNull(txStore.MempoolStore); Assert.Empty(txStore.GetTransactions()); Assert.Empty(txStore.GetTransactionHashes()); Assert.Empty(txStore.MempoolStore.GetTransactions()); Assert.Empty(txStore.MempoolStore.GetTransactionHashes()); Assert.Empty(txStore.ConfirmedStore.GetTransactions()); Assert.Empty(txStore.ConfirmedStore.GetTransactionHashes()); uint256 txHash = BitcoinFactory.CreateSmartTransaction().GetHash(); Assert.False(txStore.Contains(txHash)); Assert.True(txStore.IsEmpty()); Assert.False(txStore.TryGetTransaction(txHash, out _)); var mempoolFile = Path.Combine(dir, "Mempool", "Transactions.dat"); var txFile = Path.Combine(dir, "ConfirmedTransactions", Constants.ConfirmedTransactionsVersion, "Transactions.dat"); var mempoolContent = await File.ReadAllBytesAsync(mempoolFile); var txContent = await File.ReadAllBytesAsync(txFile); Assert.True(File.Exists(mempoolFile)); Assert.True(File.Exists(txFile)); Assert.Empty(mempoolContent); Assert.Empty(txContent); }
public async Task NoPrisonSerializationAsync() { // Don't serialize when there's no change. var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); // Create prison. CoordinatorParameters coordinatorParameters = new(workDir); using var w = new Warden(coordinatorParameters.UtxoWardenPeriod, coordinatorParameters.PrisonFilePath, coordinatorParameters.RuntimeCoordinatorConfig); await w.StartAsync(CancellationToken.None); var i1 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Noted, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); var i2 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Banned, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); w.Prison.Punish(i1); w.Prison.Punish(i2); // Wait until serializes. await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); // Make sure it does not serialize again as there was no change. File.Delete(w.PrisonFilePath); await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); Assert.False(File.Exists(w.PrisonFilePath)); await w.StopAsync(CancellationToken.None); }
public async Task InputRegistrationFullAsync() { WabiSabiConfig cfg = new() { MaxInputCountByRound = 3 }; var round = WabiSabiFactory.CreateRound(cfg); using Key key = new(); var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id); using Arena arena = await ArenaBuilder.From(cfg).CreateAndStartAsync(round); await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21)); round.Alices.Add(WabiSabiFactory.CreateAlice(round)); round.Alices.Add(WabiSabiFactory.CreateAlice(round)); round.Alices.Add(WabiSabiFactory.CreateAlice(round)); var arenaClient = WabiSabiFactory.CreateArenaClient(arena); var ex = await Assert.ThrowsAsync <WrongPhaseException>( async() => await arenaClient.RegisterInputAsync(round.Id, BitcoinFactory.CreateOutPoint(), ownershipProof, CancellationToken.None)); Assert.Equal(WabiSabiProtocolErrorCode.WrongPhase, ex.ErrorCode); Assert.Equal(Phase.InputRegistration, round.Phase); await arena.StopAsync(CancellationToken.None); }
public async Task InputUnconfirmedAsync() { using Key key = new(); WabiSabiConfig cfg = new(); var round = WabiSabiFactory.CreateRound(cfg); var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id); var mockRpc = new Mock <IRPCClient>(); mockRpc.Setup(rpc => rpc.GetTxOutAsync(It.IsAny <uint256>(), It.IsAny <int>(), It.IsAny <bool>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new NBitcoin.RPC.GetTxOutResponse { Confirmations = 0 }); using Arena arena = await ArenaBuilder.From(cfg).With(mockRpc).CreateAndStartAsync(round); var arenaClient = WabiSabiFactory.CreateArenaClient(arena); var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>( async() => await arenaClient.RegisterInputAsync(round.Id, BitcoinFactory.CreateOutPoint(), ownershipProof, CancellationToken.None)); Assert.Equal(WabiSabiProtocolErrorCode.InputUnconfirmed, ex.ErrorCode); await arena.StopAsync(CancellationToken.None); }
public async Task InputImmatureAsync() { using Key key = new(); WabiSabiConfig cfg = new(); var round = WabiSabiFactory.CreateRound(cfg); var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id); var rpc = WabiSabiFactory.CreatePreconfiguredRpcClient(); var rpcCfg = rpc.SetupSequence(rpc => rpc.GetTxOutAsync(It.IsAny <uint256>(), It.IsAny <int>(), It.IsAny <bool>(), It.IsAny <CancellationToken>())); foreach (var i in Enumerable.Range(1, 100)) { rpcCfg = rpcCfg.ReturnsAsync(new NBitcoin.RPC.GetTxOutResponse { Confirmations = i, IsCoinBase = true }); } using Arena arena = await ArenaBuilder.From(cfg).With(rpc).CreateAndStartAsync(round); var arenaClient = WabiSabiFactory.CreateArenaClient(arena); var req = WabiSabiFactory.CreateInputRegistrationRequest(round: round); foreach (var i in Enumerable.Range(1, 100)) { var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>( async() => await arenaClient.RegisterInputAsync(round.Id, BitcoinFactory.CreateOutPoint(), ownershipProof, CancellationToken.None)); Assert.Equal(WabiSabiProtocolErrorCode.InputImmature, ex.ErrorCode); } await arena.StopAsync(CancellationToken.None); }
public async Task RemoveInputAsyncTestAsync() { var config = new WabiSabiConfig(); var round = WabiSabiFactory.CreateRound(config); round.SetPhase(Phase.ConnectionConfirmation); var fundingTx = BitcoinFactory.CreateSmartTransaction(ownOutputCount: 1); var coin = fundingTx.WalletOutputs.First().Coin; var alice = new Alice(coin, new OwnershipProof(), round, Guid.NewGuid(), false); round.Alices.Add(alice); using Arena arena = await ArenaBuilder.From(config).CreateAndStartAsync(round); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); var idempotencyRequestCache = new IdempotencyRequestCache(memoryCache); using CoinJoinFeeRateStatStore coinJoinFeeRateStatStore = new(config, arena.Rpc); var wabiSabiApi = new WabiSabiController(idempotencyRequestCache, arena, coinJoinFeeRateStatStore); var apiClient = new ArenaClient(null !, null !, wabiSabiApi); round.SetPhase(Phase.InputRegistration); await apiClient.RemoveInputAsync(round.Id, alice.Id, CancellationToken.None); Assert.Empty(round.Alices); }
public async Task InputCanBeNotedAsync() { using Key key = new(); var outpoint = BitcoinFactory.CreateOutPoint(); WabiSabiConfig cfg = new(); var round = WabiSabiFactory.CreateRound(cfg); Prison prison = new(); using Arena arena = await ArenaBuilder.From(cfg, prison).CreateAndStartAsync(round); prison.Punish(outpoint, Punishment.Noted, uint256.One); var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key); var arenaClient = WabiSabiFactory.CreateArenaClient(arena); var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>( async() => await arenaClient.RegisterInputAsync(round.Id, outpoint, ownershipProof, CancellationToken.None)); Assert.NotEqual(WabiSabiProtocolErrorCode.InputBanned, ex.ErrorCode); await arena.StopAsync(CancellationToken.None); }
public async Task RegisterCoinIdempotencyAsync() { using var signingKey = new Key(); var coinToRegister = new Coin( BitcoinFactory.CreateOutPoint(), new TxOut(Money.Coins(1), signingKey.PubKey.WitHash.ScriptPubKey)); var httpClient = _apiApplicationFactory.WithWebHostBuilder(builder => { builder.ConfigureServices(services => { var rpc = BitcoinFactory.GetMockMinimalRpc(); rpc.OnGetTxOutAsync = (_, _, _) => new() { Confirmations = 101, IsCoinBase = false, ScriptPubKeyType = "witness_v0_keyhash", TxOut = coinToRegister.TxOut }; services.AddScoped <IRPCClient>(s => rpc); }); }).CreateClient(); var apiClient = await _apiApplicationFactory.CreateArenaClientAsync(new StuttererHttpClient(httpClient)); var rounds = await apiClient.GetStatusAsync(CancellationToken.None); var round = rounds.First(x => x.CoinjoinState is ConstructionState); var response = await apiClient.RegisterInputAsync(round.Id, coinToRegister.Outpoint, signingKey, CancellationToken.None); Assert.NotEqual(uint256.Zero, response.Value); }
public async Task WrongPhaseAsync() { WabiSabiConfig cfg = new(); using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg); await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21)); var round = arena.Rounds.First(); var req = new InputsRemovalRequest(round.Id, BitcoinFactory.CreateUint256()); foreach (Phase phase in Enum.GetValues(typeof(Phase))) { if (phase != Phase.InputRegistration) { round.SetPhase(phase); await using ArenaRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient()); var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(async() => await handler.RemoveInputAsync(req, CancellationToken.None)); Assert.Equal(WabiSabiProtocolErrorCode.WrongPhase, ex.ErrorCode); } } await arena.StopAsync(CancellationToken.None); }
public static void AddPocket(this List <Pocket> pockets, decimal amount, out Pocket pocket, params string[] labels) { var label = new SmartLabel(labels); var coinsView = new CoinsView(new[] { BitcoinFactory.CreateSmartCoin(NewKey(label), amount) }); pocket = new Pocket((label, coinsView)); pockets.Add(pocket); }
public static SmartCoin CreateCoin(decimal amount, string label = "", int anonymitySet = 1) { var coin = BitcoinFactory.CreateSmartCoin(NewKey(label: label, anonymitySet: anonymitySet), amount); coin.HdPubKey.SetAnonymitySet(anonymitySet); return(coin); }
public void EmptyPrison() { var p = new Prison(); Assert.Empty(p.GetInmates()); Assert.Equal(0, p.CountInmates().noted); Assert.Equal(0, p.CountInmates().banned); Assert.False(p.TryGet(BitcoinFactory.CreateOutPoint(), out _)); }
public async Task CanHandleConfirmationAsync() { var coreNode = await TestNodeBuilder.CreateAsync(); using HostedServices services = new(); services.Register <MempoolMirror>(() => new MempoolMirror(TimeSpan.FromSeconds(2), coreNode.RpcClient, coreNode.P2pNode), "Mempool Mirror"); try { var rpc = coreNode.RpcClient; var network = rpc.Network; await services.StartAllAsync(); var mempoolInstance = services.Get <MempoolMirror>(); var walletName = "RandomWalletName"; await rpc.CreateWalletAsync(walletName); var spendAmount = new Money(0.0004m, MoneyUnit.BTC); await rpc.GenerateAsync(101); var rpcMempoolBeforeSend = await rpc.GetRawMempoolAsync(); var localMempoolBeforeSend = mempoolInstance.GetMempoolHashes(); Assert.Equal(rpcMempoolBeforeSend.Length, localMempoolBeforeSend.Count); await rpc.SendToAddressAsync(BitcoinFactory.CreateBitcoinAddress(network), spendAmount); while (!(await rpc.GetRawMempoolAsync()).Any()) { await Task.Delay(50); } await mempoolInstance.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); var localMempoolAfterSend = mempoolInstance.GetMempoolHashes(); Assert.Equal(1, localMempoolAfterSend.Count); Assert.Single(localMempoolAfterSend); await rpc.GenerateAsync(1); while ((await rpc.GetRawMempoolAsync()).Any()) { await Task.Delay(50); } await mempoolInstance.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); var localMempoolAfterBlockMined = mempoolInstance.GetMempoolHashes(); Assert.Empty(localMempoolAfterBlockMined); } finally { await services.StopAllAsync(); await coreNode.TryStopAsync(); } }
public async Task CanHandleTheSameTxSentManyTimesAsync() { var coreNode = await TestNodeBuilder.CreateAsync(); using HostedServices services = new(); services.Register <MempoolMirror>(() => new MempoolMirror(TimeSpan.FromSeconds(2), coreNode.RpcClient, coreNode.P2pNode), "Mempool Mirror"); try { var rpc = coreNode.RpcClient; var network = rpc.Network; await services.StartAllAsync(); var mempoolInstance = services.Get <MempoolMirror>(); var walletName = "RandomWalletName"; await rpc.CreateWalletAsync(walletName); using var k1 = new Key(); var blockIds = await rpc.GenerateToAddressAsync(1, k1.PubKey.WitHash.GetAddress(network)); var block = await rpc.GetBlockAsync(blockIds[0]); var coinBaseTx = block.Transactions[0]; var tx = Transaction.Create(network); tx.Inputs.Add(coinBaseTx, 0); tx.Outputs.Add(Money.Coins(49.9999m), BitcoinFactory.CreateBitcoinAddress(network)); tx.Sign(k1.GetBitcoinSecret(network), coinBaseTx.Outputs.AsCoins().First()); var valid = tx.Check(); await rpc.GenerateAsync(101); for (int i = 0; i < 5; i++) { await rpc.SendRawTransactionAsync(tx); } while (!(await rpc.GetRawMempoolAsync()).Any()) { await Task.Delay(50); } await mempoolInstance.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); var localMempoolHashes = mempoolInstance.GetMempoolHashes(); Assert.Single(localMempoolHashes); Assert.Contains(tx.GetHash(), localMempoolHashes); } finally { await services.StopAllAsync(); await coreNode.TryStopAsync(); } }
public void ManyInManyOut() { var analyser = ServiceFactory.CreateBlockchainAnalyzer(); var tx = BitcoinFactory.CreateSmartTransaction(3, 3, 0, 0); analyser.Analyze(tx); Assert.Empty(tx.WalletInputs); Assert.Empty(tx.WalletOutputs); }
public void AddressReusePunishment() { // If there's reuse in input and output side, then output side didn't gain, nor lose anonymity. var analyser = ServiceFactory.CreateBlockchainAnalyzer(); var km = ServiceFactory.CreateKeyManager(); var reuse = BitcoinFactory.CreateHdPubKey(km); var tx = BitcoinFactory.CreateSmartTransaction( 9, Enumerable.Repeat(Money.Coins(1m), 9), new[] { (Money.Coins(1.1m), 100, BitcoinFactory.CreateHdPubKey(km)) },
public void WholeCoinReceive() { var analyser = ServiceFactory.CreateBlockchainAnalyzer(); var tx = BitcoinFactory.CreateSmartTransaction(1, 0, 0, 1); analyser.Analyze(tx); var coin = Assert.Single(tx.WalletOutputs); Assert.Equal(1, coin.HdPubKey.AnonymitySet); }
public async Task CanDoOperationsAsync() { await using var txStore = new TransactionStoreMock(); var network = Network.Main; await txStore.InitializeAsync(network); Assert.True(txStore.IsEmpty()); var stx = BitcoinFactory.CreateSmartTransaction(); var operation = txStore.TryAddOrUpdate(stx); Assert.True(operation.isAdded); Assert.False(operation.isUpdated); var isRemoved = txStore.TryRemove(stx.GetHash(), out SmartTransaction removed); Assert.True(isRemoved); Assert.Equal(stx, removed); operation = txStore.TryAddOrUpdate(stx); Assert.True(operation.isAdded); Assert.False(operation.isUpdated); operation = txStore.TryAddOrUpdate(stx); Assert.False(operation.isAdded); Assert.False(operation.isUpdated); operation = txStore.TryAddOrUpdate( new SmartTransaction( stx.Transaction, height: stx.Height, stx.BlockHash, stx.BlockIndex, "totally random new label", stx.IsReplacement, stx.FirstSeen)); Assert.False(operation.isAdded); Assert.True(operation.isUpdated); operation = txStore.TryAddOrUpdate(stx); Assert.False(operation.isAdded); Assert.False(operation.isUpdated); Assert.False(txStore.IsEmpty()); Assert.True(txStore.TryGetTransaction(stx.GetHash(), out SmartTransaction sameStx)); Assert.True(txStore.Contains(stx.GetHash())); Assert.Equal(stx, sameStx); txStore.TryRemove(stx.GetHash(), out _); Assert.True(txStore.IsEmpty()); Assert.Empty(txStore.GetTransactions()); txStore.TryAddOrUpdate(stx); txStore.TryAddOrUpdate(stx); Assert.Single(txStore.GetTransactions()); Assert.Single(txStore.GetTransactionHashes()); }
public async Task RoundNotFoundAsync() { using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(); await using ArenaRequestHandler handler = new(new WabiSabiConfig(), new Prison(), arena, new MockRpcClient()); var req = new InputsRemovalRequest(uint256.Zero, BitcoinFactory.CreateUint256()); var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(async() => await handler.RemoveInputAsync(req, CancellationToken.None)); Assert.Equal(WabiSabiProtocolErrorCode.RoundNotFound, ex.ErrorCode); await arena.StopAsync(CancellationToken.None); }
public static PSBT GenerateRandomTransaction() { var key = new Key(); var tx = Network.Main.CreateTransactionBuilder() .AddCoins(Coin(0.5m, key.PubKey.WitHash.ScriptPubKey)) .AddKeys(key) .Send(BitcoinFactory.CreateScript(), Money.Coins(0.5m)) .BuildPSBT(true); tx.Finalize(); return(tx); }
public async Task RoundNotFoundAsync() { using Key key = new(); using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(new(), WabiSabiFactory.CreatePreconfiguredRpcClient()); var arenaClient = WabiSabiFactory.CreateArenaClient(arena); var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>( async() => await arenaClient.RegisterInputAsync(uint256.Zero, BitcoinFactory.CreateOutPoint(), key, CancellationToken.None)); Assert.Equal(WabiSabiProtocolErrorCode.RoundNotFound, ex.ErrorCode); await arena.StopAsync(CancellationToken.None); }