-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'release/1.5.0.0' into getbalance2
- Loading branch information
Showing
27 changed files
with
447 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 101 additions & 31 deletions
132
src/Stratis.Bitcoin.Features.PoA/Voting/WhitelistedHashesRepository.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,163 @@ | ||
using System.Collections.Generic; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Microsoft.Extensions.Logging; | ||
using NBitcoin; | ||
using Stratis.Bitcoin.Persistence; | ||
using Stratis.Bitcoin.Utilities; | ||
|
||
namespace Stratis.Bitcoin.Features.PoA.Voting | ||
{ | ||
public class WhitelistedHashesRepository : IWhitelistedHashesRepository | ||
{ | ||
private const string dbKey = "hashesList"; | ||
|
||
private readonly IKeyValueRepository kvRepository; | ||
|
||
/// <summary>Protects access to <see cref="whitelistedHashes"/>.</summary> | ||
private readonly object locker; | ||
|
||
private readonly ILogger logger; | ||
|
||
private List<uint256> whitelistedHashes; | ||
private readonly PoAConsensusOptions poaConsensusOptions; | ||
|
||
public WhitelistedHashesRepository(ILoggerFactory loggerFactory, IKeyValueRepository kvRepository) | ||
// Dictionary of hash histories. Even list entries are additions and odd entries are removals. | ||
private Dictionary<uint256, int[]> whitelistedHashes; | ||
|
||
public WhitelistedHashesRepository(ILoggerFactory loggerFactory, Network network) | ||
{ | ||
this.kvRepository = kvRepository; | ||
this.locker = new object(); | ||
|
||
this.logger = loggerFactory.CreateLogger(this.GetType().FullName); | ||
this.poaConsensusOptions = network.Consensus.Options as PoAConsensusOptions; | ||
} | ||
|
||
// Load this before initialize to ensure its available to when the Mempool feature initializes. | ||
lock (this.locker) | ||
public class PollComparer : IComparer<(int height, int id)> | ||
{ | ||
public int Compare((int height, int id) poll1, (int height, int id) poll2) | ||
{ | ||
this.whitelistedHashes = this.kvRepository.LoadValueJson<List<uint256>>(dbKey) ?? new List<uint256>(); | ||
int cmp = poll1.height.CompareTo(poll2.height); | ||
if (cmp != 0) | ||
return cmp; | ||
|
||
return poll1.id.CompareTo(poll2.id); | ||
} | ||
} | ||
|
||
public void Initialize() | ||
static PollComparer pollComparer = new PollComparer(); | ||
|
||
private void GetWhitelistedHashesFromExecutedPolls(VotingManager votingManager) | ||
{ | ||
lock (this.locker) | ||
{ | ||
var federation = new List<IFederationMember>(this.poaConsensusOptions.GenesisFederationMembers); | ||
|
||
IEnumerable<Poll> executedPolls = votingManager.GetExecutedPolls().WhitelistPolls(); | ||
foreach (Poll poll in executedPolls.OrderBy(a => (a.PollExecutedBlockData.Height, a.Id), pollComparer)) | ||
{ | ||
var hash = new uint256(poll.VotingData.Data); | ||
|
||
if (poll.VotingData.Key == VoteKey.WhitelistHash) | ||
{ | ||
this.AddHash(hash, poll.PollExecutedBlockData.Height); | ||
} | ||
else if (poll.VotingData.Key == VoteKey.RemoveHash) | ||
{ | ||
this.RemoveHash(hash, poll.PollExecutedBlockData.Height); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void SaveHashes() | ||
public void Initialize(VotingManager votingManager) | ||
{ | ||
// TODO: Must call Initialize before the Mempool rules try to use this class. | ||
lock (this.locker) | ||
{ | ||
this.kvRepository.SaveValueJson(dbKey, this.whitelistedHashes); | ||
this.whitelistedHashes = new Dictionary<uint256, int[]>(); | ||
this.GetWhitelistedHashesFromExecutedPolls(votingManager); | ||
} | ||
} | ||
|
||
public void AddHash(uint256 hash) | ||
public void AddHash(uint256 hash, int executionHeight) | ||
{ | ||
lock (this.locker) | ||
{ | ||
if (this.whitelistedHashes.Contains(hash)) | ||
// Retrieve the whitelist history for this hash. | ||
if (!this.whitelistedHashes.TryGetValue(hash, out int[] history)) | ||
{ | ||
this.logger.LogTrace("(-)[ALREADY_EXISTS]"); | ||
this.whitelistedHashes[hash] = new int[] { executionHeight }; | ||
return; | ||
} | ||
|
||
this.whitelistedHashes.Add(hash); | ||
// Keep all history up to and including the executionHeight. | ||
int keep = BinarySearch.BinaryFindFirst((k) => k == history.Length || history[k] > executionHeight, 0, history.Length + 1); | ||
Array.Resize(ref history, keep | 1); | ||
this.whitelistedHashes[hash] = history; | ||
|
||
// If the history is an even length then add the addition height to signify addition. | ||
if ((keep % 2) == 0) | ||
{ | ||
// Add an even indexed entry to signify an addition. | ||
history[keep] = executionHeight; | ||
return; | ||
} | ||
|
||
this.logger.LogTrace("(-)[HASH_ALREADY_EXISTS]"); | ||
return; | ||
} | ||
} | ||
|
||
public void RemoveHash(uint256 hash, int executionHeight) | ||
{ | ||
lock (this.locker) | ||
{ | ||
// Retrieve the whitelist history for this hash. | ||
if (this.whitelistedHashes.TryGetValue(hash, out int[] history)) | ||
{ | ||
// Keep all history up to and including the executionHeight. | ||
int keep = BinarySearch.BinaryFindFirst((k) => k == history.Length || history[k] >= executionHeight, 0, history.Length + 1); | ||
Array.Resize(ref history, (keep + 1) & ~1); | ||
this.whitelistedHashes[hash] = history; | ||
|
||
// If the history is an odd length then add the removal height to signify removal. | ||
if ((keep % 2) != 0) | ||
{ | ||
history[keep] = executionHeight; | ||
return; | ||
} | ||
} | ||
|
||
this.SaveHashes(); | ||
this.logger.LogTrace("(-)[HASH_DOESNT_EXIST]"); | ||
return; | ||
} | ||
} | ||
|
||
public void RemoveHash(uint256 hash) | ||
private bool ExistsHash(uint256 hash, int blockHeight) | ||
{ | ||
lock (this.locker) | ||
{ | ||
bool removed = this.whitelistedHashes.Remove(hash); | ||
// Retrieve the whitelist history for this hash. | ||
if (!this.whitelistedHashes.TryGetValue(hash, out int[] history)) | ||
return false; | ||
|
||
if (removed) | ||
this.SaveHashes(); | ||
int keep = BinarySearch.BinaryFindFirst((k) => k == history.Length || history[k] > blockHeight, 0, history.Length + 1); | ||
return (keep % 2) != 0; | ||
} | ||
} | ||
|
||
public List<uint256> GetHashes() | ||
public List<uint256> GetHashes(int blockHeight = int.MaxValue) | ||
{ | ||
lock (this.locker) | ||
{ | ||
return new List<uint256>(this.whitelistedHashes); | ||
return this.whitelistedHashes.Where(k => ExistsHash(k.Key, blockHeight)).Select(k => k.Key).ToList(); | ||
} | ||
} | ||
} | ||
|
||
public interface IWhitelistedHashesRepository | ||
{ | ||
void AddHash(uint256 hash); | ||
void AddHash(uint256 hash, int executionHeight); | ||
|
||
void RemoveHash(uint256 hash); | ||
void RemoveHash(uint256 hash, int executionHeight); | ||
|
||
List<uint256> GetHashes(); | ||
List<uint256> GetHashes(int blockHeight = int.MaxValue); | ||
|
||
void Initialize(); | ||
void Initialize(VotingManager votingManager); | ||
} | ||
} | ||
} |
Oops, something went wrong.