public async Task <Coin> OutpointToCoinAsync(InputRegistrationRequest request, CancellationToken cancellationToken) { OutPoint input = request.Input; if (Prison.TryGet(input, out var inmate) && (!Config.AllowNotedInputRegistration || inmate.Punishment != Punishment.Noted)) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputBanned); } var txOutResponse = await Rpc.GetTxOutAsync(input.Hash, (int)input.N, includeMempool : true, cancellationToken).ConfigureAwait(false); if (txOutResponse is null) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputSpent); } if (txOutResponse.Confirmations == 0) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputUnconfirmed); } if (txOutResponse.IsCoinBase && txOutResponse.Confirmations <= 100) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputImmature); } return(new Coin(input, txOutResponse.TxOut)); }
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 void PrisonOperations() { var p = new Prison(); var id1 = BitcoinFactory.CreateUint256(); var utxo = BitcoinFactory.CreateOutPoint(); p.Punish(utxo, Punishment.Noted, id1); Assert.Single(p.GetInmates()); Assert.Equal(1, p.CountInmates().noted); Assert.Equal(0, p.CountInmates().banned); Assert.True(p.TryGet(utxo, out _)); // Updates to banned. p.Punish(utxo, Punishment.Banned, id1); Assert.Single(p.GetInmates()); Assert.Equal(0, p.CountInmates().noted); Assert.Equal(1, p.CountInmates().banned); Assert.True(p.TryGet(utxo, out _)); // Removes. Assert.True(p.TryRelease(utxo, out _)); Assert.Empty(p.GetInmates()); // Noting twice flips to banned. p.Punish(utxo, Punishment.Noted, id1); p.Punish(utxo, Punishment.Noted, id1); Assert.Single(p.GetInmates()); Assert.Equal(0, p.CountInmates().noted); Assert.Equal(1, p.CountInmates().banned); Assert.True(p.TryGet(utxo, out _)); Assert.True(p.TryRelease(utxo, out _)); // Updates round. var id2 = BitcoinFactory.CreateUint256(); p.Punish(utxo, Punishment.Banned, id1); p.Punish(utxo, Punishment.Banned, id2); Assert.Single(p.GetInmates()); Assert.True(p.TryGet(utxo, out var inmate)); Assert.Equal(id2, inmate !.LastDisruptedRoundId); Assert.True(p.TryRelease(utxo, out _)); }
public static async Task <IDictionary <Coin, byte[]> > PreProcessAsync( InputsRegistrationRequest request, Prison prison, IRPCClient rpc, WabiSabiConfig config) { var inputRoundSignaturePairs = request.InputRoundSignaturePairs; var inputs = inputRoundSignaturePairs.Select(x => x.Input); int inputCount = inputs.Count(); if (inputCount != inputs.Distinct().Count()) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.NonUniqueInputs); } if (inputs.Any(x => prison.TryGet(x, out var inmate) && (!config.AllowNotedInputRegistration || inmate.Punishment != Punishment.Noted))) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputBanned); } Dictionary <Coin, byte[]> coinRoundSignaturePairs = new(); foreach (var inputRoundSignaturePair in inputRoundSignaturePairs) { OutPoint input = inputRoundSignaturePair.Input; var txOutResponse = await rpc.GetTxOutAsync(input.Hash, (int)input.N, includeMempool : true).ConfigureAwait(false); if (txOutResponse is null) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputSpent); } if (txOutResponse.Confirmations == 0) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputUnconfirmed); } if (txOutResponse.IsCoinBase && txOutResponse.Confirmations <= 100) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputImmature); } if (!txOutResponse.TxOut.ScriptPubKey.IsScriptType(ScriptType.P2WPKH)) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.ScriptNotAllowed); } coinRoundSignaturePairs.Add(new Coin(input, txOutResponse.TxOut), inputRoundSignaturePair.RoundSignature); } return(coinRoundSignaturePairs); }
public async Task <Coin> OutpointToCoinAsync(InputRegistrationRequest request, CancellationToken cancellationToken) { OutPoint input = request.Input; if (Prison.TryGet(input, out var inmate)) { DateTimeOffset bannedUntil; if (inmate.Punishment == Punishment.LongBanned) { bannedUntil = inmate.Started + Config.ReleaseUtxoFromPrisonAfterLongBan; throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputLongBanned, exceptionData: new InputBannedExceptionData(bannedUntil)); } if (!Config.AllowNotedInputRegistration || inmate.Punishment != Punishment.Noted) { bannedUntil = inmate.Started + Config.ReleaseUtxoFromPrisonAfter; throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputBanned, exceptionData: new InputBannedExceptionData(bannedUntil)); } } var txOutResponse = await Rpc.GetTxOutAsync(input.Hash, (int)input.N, includeMempool : true, cancellationToken).ConfigureAwait(false); if (txOutResponse is null) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputSpent); } if (txOutResponse.Confirmations == 0) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputUnconfirmed); } if (txOutResponse.IsCoinBase && txOutResponse.Confirmations <= 100) { throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputImmature); } return(new Coin(input, txOutResponse.TxOut)); }