Skip to content
Permalink
Browse files

Try implementing noting

  • Loading branch information...
nopara73 committed Nov 21, 2018
1 parent 603dd6c commit 52fe7c0a2d39b9a0e8fab2ff7e75e3413065a263
@@ -156,15 +156,10 @@ public async Task<IActionResult> PostInputsAsync([FromBody]InputsRequest request
}

OutPoint outpoint = inputProof.Input.ToOutPoint();
if (Coordinator.UtxoReferee.BannedUtxos.TryGetValue(outpoint, out (int severity, DateTimeOffset timeOfBan) bannedElem))
var bannedElem = await Coordinator.UtxoReferee.TryGetBannedAsync(outpoint, notedToo: false);
if (bannedElem != null)
{
int maxBan = (int)TimeSpan.FromHours((long)Global.RoundConfig.DosDurationHours).TotalMinutes;
int banLeft = maxBan - (int)(DateTimeOffset.UtcNow - bannedElem.timeOfBan).TotalMinutes;
if (banLeft > 0)
{
return BadRequest($"Input is banned from participation for {banLeft} minutes: {inputProof.Input.Index}:{inputProof.Input.TransactionId}.");
}
await Coordinator.UtxoReferee.UnbanAsync(outpoint);
return BadRequest($"Input is banned from participation for {(int)bannedElem.Value.bannedRemaining.TotalMinutes} minutes: {inputProof.Input.Index}:{inputProof.Input.TransactionId}.");
}

GetTxOutResponse getTxOutResponse = await RpcClient.GetTxOutAsync(inputProof.Input.TransactionId, (int)inputProof.Input.Index, includeMempool: true);
@@ -339,7 +334,7 @@ public async Task<IActionResult> PostConfirmationAsync([FromQuery]string uniqueI

if (alicesToBan.Any())
{
await Coordinator.UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, alicesToBan.SelectMany(x => x.Inputs).Select(y => y.Outpoint).ToArray());
await Coordinator.UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, forceNoted: false, round.RoundId, alicesToBan.SelectMany(x => x.Inputs).Select(y => y.Outpoint).ToArray());
}

int aliceCountAfterConnectionConfirmationTimeout = round.CountAlices();
@@ -1604,7 +1604,7 @@ public async Task CcjTestsAsync()
decimal coordinatorFeePercent = 0.2m;
int anonymitySet = 2;
int connectionConfirmationTimeout = 50;
var roundConfig = new CcjRoundConfig(denomination, 2, coordinatorFeePercent, anonymitySet, 100, connectionConfirmationTimeout, 50, 50, 2, 24);
var roundConfig = new CcjRoundConfig(denomination, 2, coordinatorFeePercent, anonymitySet, 100, connectionConfirmationTimeout, 50, 50, 2, 24, false);
coordinator.UpdateRoundConfig(roundConfig);
coordinator.AbortAllRoundsInInputRegistration(nameof(RegTests), "");

@@ -1817,16 +1817,16 @@ public async Task CcjTestsAsync()
var spendingTx = network.Consensus.ConsensusFactory.CreateTransaction();
var bannedCoin = inputsRequest.Inputs.First().Input;
var utxos = coordinator.UtxoReferee;
Assert.Contains(utxos.BannedUtxos, x => x.Key == bannedCoin);
Assert.NotNull(await utxos.TryGetBannedAsync(bannedCoin.ToOutPoint(), false));
spendingTx.Inputs.Add(new TxIn(bannedCoin.ToOutPoint()));
spendingTx.Outputs.Add(new TxOut(Money.Coins(1), new Key().PubKey.GetSegwitAddress(network)));
var fakeBlockWithSpendingBannedCoins = network.Consensus.ConsensusFactory.CreateBlock();
fakeBlockWithSpendingBannedCoins.Transactions.Add(spendingTx);

await coordinator.ProcessBlockAsync(fakeBlockWithSpendingBannedCoins);

Assert.Contains(utxos.BannedUtxos, x => x.Key == new OutPoint(spendingTx.GetHash(), 0));
Assert.DoesNotContain(utxos.BannedUtxos, x => x.Key == bannedCoin);
Assert.NotNull(await utxos.TryGetBannedAsync(new OutPoint(spendingTx.GetHash(), 0), false));
Assert.Null(await utxos.TryGetBannedAsync(bannedCoin.ToOutPoint(), false));

states = await satoshiClient.GetAllRoundStatesAsync();
foreach (var rs in states.Where(x => x.Phase == CcjRoundPhase.InputRegistration))
@@ -2073,9 +2073,10 @@ public async Task BanningTestsAsync()
decimal coordinatorFeePercent = 0.1m;
int anonymitySet = 3;
int connectionConfirmationTimeout = 120;
var roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 1, 1, 1, 24);
var roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 1, 1, 1, 24, true);
coordinator.UpdateRoundConfig(roundConfig);
coordinator.AbortAllRoundsInInputRegistration(nameof(RegTests), "");

await rpc.GenerateAsync(3); // So to make sure we have enough money.

Uri baseUri = new Uri(RegTestFixture.BackendEndPoint);
@@ -2179,18 +2180,87 @@ public async Task BanningTestsAsync()
}
}

await Task.Delay(3000);
using (var satoshiClient = new SatoshiClient(baseUri))
{
var times = 0;
while (!(await satoshiClient.GetAllRoundStatesAsync()).All(x => x.Phase == CcjRoundPhase.InputRegistration))
{
await Task.Delay(100);
if (times > 50) // 5 sec, 3 should be enough
{
throw new TimeoutException("Not all rouns were in InputRegistration.");
}
times++;
}
}

int bannedCount = coordinator.UtxoReferee.CountBanned(false);
Assert.Equal(0, bannedCount);

aliceClients.Clear();
foreach (var user in inputRegistrationUsers)
{
aliceClients.Add(AliceClient.CreateNewAsync(network, user.changeOutputAddress, user.blinded.blindedData, user.inputProofModels, baseUri));
}

roundId = 0;
users = new List<((BigInteger blindingFactor, byte[] blindedData) blinded, BitcoinAddress activeOutputAddress, BitcoinAddress changeOutputAddress, IEnumerable<InputProofModel> inputProofModels, List<(Key key, BitcoinWitPubKeyAddress address, uint256 txHash, Transaction tx, OutPoint input)> userInputData, AliceClient aliceClient, byte[] unblindedSignature)>();
for (int i = 0; i < inputRegistrationUsers.Count; i++)
{
var user = inputRegistrationUsers[i];
var request = aliceClients[i];

var aliceClient = await request;
if (roundId == 0)
{
roundId = aliceClient.RoundId;
}
else
{
Assert.Equal(roundId, aliceClient.RoundId);
}
// Because it's valuetuple.
users.Add((user.blinded, user.activeOutputAddress, user.changeOutputAddress, user.inputProofModels, user.userInputData, aliceClient, blindingKey.PubKey.UnblindSignature(aliceClient.BlindedOutputSignature, user.blinded.blindingFactor)));
}

Assert.Equal(users.Count, roundConfig.AnonymitySet);

confirmationRequests = new List<Task<string>>();

foreach (var user in users)
{
confirmationRequests.Add(user.aliceClient.PostConfirmationAsync());
}

roundHash = null;
foreach (var request in confirmationRequests)
{
if (roundHash is null)
{
roundHash = await request;
}
else
{
Assert.Equal(roundHash, await request);
}
}

using (var satoshiClient = new SatoshiClient(baseUri))
{
IEnumerable<CcjRunningRoundState> states = await satoshiClient.GetAllRoundStatesAsync();
foreach (CcjRoundPhase phase in states.Select(x => x.Phase))
var times = 0;
while (!(await satoshiClient.GetAllRoundStatesAsync()).All(x => x.Phase == CcjRoundPhase.InputRegistration))
{
Assert.Equal(CcjRoundPhase.InputRegistration, phase);
await Task.Delay(100);
if (times > 50) // 5 sec, 3 should be enough
{
throw new TimeoutException("Not all rouns were in InputRegistration.");
}
times++;
}
}

Assert.True(coordinator.UtxoReferee.BannedUtxos.Count >= roundConfig.AnonymitySet);
bannedCount = coordinator.UtxoReferee.CountBanned(false);
Assert.True(bannedCount >= roundConfig.AnonymitySet);

foreach (var aliceClient in aliceClients)
{
@@ -2209,7 +2279,7 @@ public async Task Ccj100ParticipantsTestsAsync()
decimal coordinatorFeePercent = 0.003m;
int anonymitySet = 100;
int connectionConfirmationTimeout = 120;
var roundConfig = new CcjRoundConfig(denomination, 144, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24);
var roundConfig = new CcjRoundConfig(denomination, 144, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24, true);
coordinator.UpdateRoundConfig(roundConfig);
coordinator.AbortAllRoundsInInputRegistration(nameof(RegTests), "");
await rpc.GenerateAsync(100); // So to make sure we have enough money.
@@ -2416,7 +2486,7 @@ public async Task CcjClientTestsAsync()
decimal coordinatorFeePercent = 0.1m;
int anonymitySet = 2;
int connectionConfirmationTimeout = 14;
var roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24);
var roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24, true);
coordinator.UpdateRoundConfig(roundConfig);
coordinator.AbortAllRoundsInInputRegistration(nameof(RegTests), "");
await rpc.GenerateAsync(3); // So to make sure we have enough money.
@@ -2516,7 +2586,7 @@ public async Task CcjClientTestsAsync()

// Make sure if times out, it tries again.
connectionConfirmationTimeout = 1;
roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24);
roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24, true);
coordinator.UpdateRoundConfig(roundConfig);
coordinator.AbortAllRoundsInInputRegistration(nameof(RegTests), "");
Assert.NotEmpty(chaumianClient1.State.GetAllQueuedCoins());
@@ -2561,7 +2631,7 @@ public async Task CcjClientCustomOutputScriptTestsAsync()
decimal coordinatorFeePercent = 0.1m;
int anonymitySet = 2;
int connectionConfirmationTimeout = 14;
var roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24);
var roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24, true);
coordinator.UpdateRoundConfig(roundConfig);
coordinator.AbortAllRoundsInInputRegistration(nameof(RegTests), "");
await rpc.GenerateAsync(3); // So to make sure we have enough money.
@@ -2658,7 +2728,7 @@ public async Task CoinJoinMultipleRoundTestsAsync()
decimal coordinatorFeePercent = 0.1m;
int anonymitySet = 2;
int connectionConfirmationTimeout = 14;
var roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24);
var roundConfig = new CcjRoundConfig(denomination, 140, coordinatorFeePercent, anonymitySet, 240, connectionConfirmationTimeout, 50, 50, 1, 24, true);
coordinator.UpdateRoundConfig(roundConfig);
coordinator.AbortAllRoundsInInputRegistration(nameof(RegTests), "");

@@ -33,7 +33,7 @@ public RegTestFixture()

var config = new Config(rpc.Network, authString[0], authString[1]);

var roundConfig = new CcjRoundConfig(Money.Coins(0.1m), 144, 0.1m, 100, 120, 60, 60, 60, 1, 24);
var roundConfig = new CcjRoundConfig(Money.Coins(0.1m), 144, 0.1m, 100, 120, 60, 60, 60, 1, 24, true);

Global.InitializeAsync(config, roundConfig, rpc).GetAwaiter().GetResult();

@@ -463,7 +463,7 @@ public async Task ExecuteNextPhaseAsync(CcjRoundPhase expectedPhase)

if (inputsToBan.Any())
{
await UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, inputsToBan.ToArray());
await UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, forceNoted: false, RoundId, inputsToBan.ToArray());
}

RemoveAlicesBy(alicesToBan1.Select(x => x.UniqueId).Concat(alicesToBan2.Select(y => y.UniqueId)).Distinct().ToArray());
@@ -506,7 +506,7 @@ public async Task ExecuteNextPhaseAsync(CcjRoundPhase expectedPhase)
}
if (outpointsToBan.Any())
{
await UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, outpointsToBan.ToArray());
await UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, forceNoted: false, RoundId, outpointsToBan.ToArray());
}
Abort(nameof(CcjRound), "Not all Alices signed.");
}
@@ -48,6 +48,9 @@ public class CcjRoundConfig : IConfig
[JsonProperty(PropertyName = "DosDurationHours")]
public long? DosDurationHours { get; internal set; }

[JsonProperty(PropertyName = "DosNoteBeforeBan")]
public bool? DosNoteBeforeBan { get; internal set; }

public CcjRoundConfig()
{
}
@@ -57,7 +60,7 @@ public CcjRoundConfig(string filePath)
SetFilePath(filePath);
}

public CcjRoundConfig(Money denomination, int? confirmationTarget, decimal? coordinatorFeePercent, int? anonymitySet, long? inputRegistrationTimeout, long? connectionConfirmationTimeout, long? outputRegistrationTimeout, long? signingTimeout, int? dosSeverity, long? dosDurationHours)
public CcjRoundConfig(Money denomination, int? confirmationTarget, decimal? coordinatorFeePercent, int? anonymitySet, long? inputRegistrationTimeout, long? connectionConfirmationTimeout, long? outputRegistrationTimeout, long? signingTimeout, int? dosSeverity, long? dosDurationHours, bool dosNoteBeforeBan)
{
FilePath = null;
Denomination = Guard.NotNull(nameof(denomination), denomination);
@@ -70,6 +73,7 @@ public CcjRoundConfig(Money denomination, int? confirmationTarget, decimal? coor
SigningTimeout = Guard.NotNull(nameof(signingTimeout), signingTimeout);
DosSeverity = Guard.NotNull(nameof(dosSeverity), dosSeverity);
DosDurationHours = Guard.NotNull(nameof(dosDurationHours), dosDurationHours);
DosNoteBeforeBan = Guard.NotNull(nameof(dosNoteBeforeBan), dosNoteBeforeBan);
}

/// <inheritdoc />
@@ -98,6 +102,7 @@ public async Task LoadOrCreateDefaultFileAsync()
SigningTimeout = 60;
DosSeverity = 1;
DosDurationHours = 730; // 1 month
DosNoteBeforeBan = true;

if (!File.Exists(FilePath))
{
@@ -126,6 +131,7 @@ public void UpdateOrDefault(CcjRoundConfig config)
SigningTimeout = config.SigningTimeout ?? SigningTimeout;
DosSeverity = config.DosSeverity ?? DosSeverity;
DosDurationHours = config.DosDurationHours ?? DosDurationHours;
DosNoteBeforeBan = config.DosNoteBeforeBan ?? DosNoteBeforeBan;
}

/// <inheritdoc />
@@ -181,6 +187,10 @@ public async Task<bool> CheckFileChangeAsync()
{
return true;
}
if (DosNoteBeforeBan != config.DosNoteBeforeBan)
{
return true;
}

return false;
}
@@ -153,17 +153,18 @@ public async Task ProcessBlockAsync(Block block)
OutPoint prevOut = input.PrevOut;

// if coin is not banned
if (UtxoReferee.BannedUtxos.TryGetValue(prevOut, out (int severity, DateTimeOffset timeOfBan) found))
var foundElem = await UtxoReferee.TryGetBannedAsync(prevOut, notedToo: true);
if (foundElem != null)
{
if (!AnyRunningRoundContainsInput(prevOut, out _))
{
int newSeverity = found.severity + 1;
int newSeverity = foundElem.Value.severity + 1;
await UtxoReferee.UnbanAsync(prevOut); // since it's not an UTXO anymore

if (RoundConfig.DosSeverity >= newSeverity)
{
var txCoins = tx.Outputs.AsIndexedOutputs().Select(x => x.ToCoin().Outpoint);
await UtxoReferee.BanUtxosAsync(newSeverity, found.timeOfBan, txCoins.ToArray());
await UtxoReferee.BanUtxosAsync(newSeverity, foundElem.Value.timeOfBan, forceNoted: foundElem.Value.isNoted, foundElem.Value.bannedForRound, txCoins.ToArray());
}
}
}
@@ -233,7 +234,7 @@ private async void Round_StatusChangedAsync(object sender, CcjRoundStatus status
{
// If its from any coinjoin, then don't ban.
IEnumerable<OutPoint> utxosToBan = alice.Inputs.Select(x => x.Outpoint);
await UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, utxosToBan.ToArray());
await UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, forceNoted: false, round.RoundId, utxosToBan.ToArray());
}
}

0 comments on commit 52fe7c0

Please sign in to comment.
You can’t perform that action at this time.