Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use concurrent data structure and update worldstate. #46

Merged
merged 8 commits into from
Feb 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions AElf.Kernel.Tests/MerkleTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AElf.Kernel.Extensions;
using System;
using AElf.Kernel.Extensions;
using AElf.Kernel.Merkle;
using System.Collections.Generic;
using Xunit;
Expand Down Expand Up @@ -27,10 +28,10 @@ public void VerifyProofListTest()

var hash_l = new Hash<ITransaction>("l".CalculateHash());
var hash_f = new Hash<ITransaction>("f".CalculateHash());
var hash_l_f = new Hash<ITransaction>((hash_l.ToString() + hash_f.ToString()).CalculateHash());
var hash_l_f = new Hash<ITransaction>(hash_l.CalculateHashWith(hash_f));
#endregion

List<Hash<ITransaction>> prooflist = new List<Hash<ITransaction>>
List<IHash<ITransaction>> prooflist = new List<IHash<ITransaction>>
{
hash_a,
hash_e,
Expand Down
30 changes: 0 additions & 30 deletions AElf.Kernel.Tests/MinerTest.cs

This file was deleted.

5 changes: 1 addition & 4 deletions AElf.Kernel/AElf.Kernel.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,4 @@
<Name>AElf.Serialization</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ProjectCapability Include="CSharp;Managed;ClassDesigner" />
</ItemGroup>
</Project>
</Project>
30 changes: 19 additions & 11 deletions AElf.Kernel/DataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,19 @@ public class DataProvider : IDataProvider
private Dictionary<string, IDataProvider> _dataProviders = new Dictionary<string, IDataProvider>();
private Dictionary<IHash, IHash> _mapSerializedValue = new Dictionary<IHash, IHash>();

private IHash keyHash;
private IHash oldValueHash;
private IHash newValueHash;
private IHash _keyHash;
private IHash _newValueHash;

/// <summary>
/// ctor.
/// </summary>
/// <param name="accountAddress"></param>
/// <param name="account"></param>
public DataProvider(IAccount account)
{
_account = account;

keyHash = default(IHash);
oldValueHash = default(IHash);
newValueHash = default(IHash);
_keyHash = default(IHash);
_newValueHash = default(IHash);
}

/// <summary>
Expand Down Expand Up @@ -80,6 +78,16 @@ private IDataProvider AddDataProvider(string name)
_dataProviders[name] = defaultDataProvider;
return defaultDataProvider;
}

/// <summary>
/// Set a data provider.
/// </summary>
/// <param name="name"></param>
/// <param name="dataProvider"></param>
public void SetDataProvider(string name, IDataProvider dataProvider)
{
_dataProviders[name] = dataProvider;
}

/// <summary>
/// Directly add a data to k-v database.
Expand All @@ -100,8 +108,8 @@ public Task SetAsync(IHash key, ISerializable obj)
var finalHash = new Hash<ISerializable>(key.CalculateHashWith(obj));

#region Store the context
keyHash = key;
newValueHash = finalHash;
_keyHash = key;
_newValueHash = finalHash;
#endregion

return new Task(() => Database.Insert(finalHash, obj));
Expand All @@ -125,11 +133,11 @@ public Task SetAsync(string key, ISerializable obj)
/// </summary>
public void Execute()
{
if (keyHash == default(IHash) || newValueHash == default(IHash))
if (_keyHash == default(IHash) || _newValueHash == default(IHash))
{
return;
}
_mapSerializedValue[keyHash] = newValueHash;
_mapSerializedValue[_keyHash] = _newValueHash;
}
}
}
68 changes: 51 additions & 17 deletions AElf.Kernel/Merkle/BinaryMerkleTree.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using AElf.Kernel.Extensions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.ComTypes;

namespace AElf.Kernel.Merkle
{
Expand All @@ -10,15 +12,17 @@ public class BinaryMerkleTree<T> : IMerkleTree<T>
/// <summary>
/// Merkle nodes
/// </summary>
private List<IHash<T>> Nodes { get; set; } = new List<IHash<T>>();
private ConcurrentStack<IHash<T>> Nodes { get; set; } = new ConcurrentStack<IHash<T>>();

private ConcurrentDictionary<string, IHash<T>> _cache = new ConcurrentDictionary<string, IHash<T>>();

/// <summary>
/// Add a leaf node and compute root hash.
/// </summary>
/// <param name="hash"></param>
public void AddNode(IHash<T> hash)
{
Nodes.Add(hash);
Nodes.Push(hash);
ComputeRootHash();
}

Expand All @@ -37,15 +41,20 @@ public void AddNode(IHash<T> newHash, IHash<T> oldHash)

public BinaryMerkleTree<T> AddNodes(List<IHash<T>> hashes)
{
hashes.ForEach(hash => Nodes.Add(hash));
hashes.ForEach(hash => Nodes.Push(hash));

return this;
}

public IHash<IMerkleTree<T>> ComputeRootHash() => ComputeRootHash(Nodes);

public IHash<IMerkleTree<T>> ComputeRootHash(List<IHash<T>> hashes)
private IHash<IMerkleTree<T>> ComputeRootHash(ConcurrentStack<IHash<T>> hashesbag)
{
//Just work around to use a list in this method.
var hashArray = new IHash<T>[hashesbag.Count];
hashesbag.CopyTo(hashArray, 0);
var hashes = hashArray.Reverse().ToList();

if (hashes.Count < 1)
{
throw new InvalidOperationException("Cannot generate merkle tree without any nodes.");
Expand All @@ -58,14 +67,14 @@ public IHash<IMerkleTree<T>> ComputeRootHash(List<IHash<T>> hashes)
else
{
//Every time goes to a higher level.
List<IHash<T>> parents = new List<IHash<T>>();
ConcurrentStack<IHash<T>> parents = new ConcurrentStack<IHash<T>>();

for (int i = 0; i < hashes.Count; i += 2)
{
IHash<T> right = (i + 1 < hashes.Count) ? new Hash<T>(hashes[i + 1].Value) : null;
IHash<T> parent = new Hash<T>((hashes[i].ToString() + right?.ToString()).CalculateHash());
IHash<T> parent = FindCache(hashes[i], right);

parents.Add(parent);
parents.Push(parent);
}

return ComputeRootHash(parents);
Expand All @@ -86,28 +95,29 @@ public int FindLeaf(IHash<T> leaf)
}
for (int i = 0; i < Nodes.Count; i++)
{
if (Nodes[i] == leaf)
Nodes.TryPeek(out var node);
if (node == leaf)
{
return i;
}
}
return -1;
}

public bool VerifyProofList(List<Hash<ITransaction>> hashlist)
public bool VerifyProofList(List<IHash<T>> hashlist)
{
List<Hash<ITransaction>> list = ComputeProofHash(hashlist);
List<IHash<T>> list = ComputeProofHash(hashlist);
return ComputeRootHash().ToString() == list[0].ToString();
}

private List<Hash<ITransaction>> ComputeProofHash(List<Hash<ITransaction>> hashlist)
{
private List<IHash<T>> ComputeProofHash(List<IHash<T>> hashlist)
{
if (hashlist.Count < 2)
return hashlist;

List<Hash<ITransaction>> list = new List<Hash<ITransaction>>()
List<IHash<T>> list = new List<IHash<T>>()
{
new Hash<ITransaction>((hashlist[0].ToString() + hashlist[1].ToString()).CalculateHash())
new Hash<T>(hashlist[0].CalculateHashWith(hashlist[1]))
};

if (hashlist.Count > 2)
Expand All @@ -128,10 +138,34 @@ public void UpdateNode(IHash<T> oldLeaf, IHash<T> newLeaf)

public void UpdateNode(int oldLeafOrder, IHash<T> newLeaf)
{
Nodes[oldLeafOrder] = newLeaf;
// TODO:
// Make it quicker to compute root hash value.
Queue<IHash<T>> temp = new Queue<IHash<T>>();
for (var i = 0; i < Nodes.Count - oldLeafOrder + 1; i++)
{
if (Nodes.TryPop(out var element))
{
temp.Enqueue(element);
}
}
Nodes.Push(newLeaf);
for (int i = 0; i < temp.Count; i++)
{
Nodes.Push(temp.Dequeue());
}
ComputeRootHash();
}

private IHash<T> FindCache(IHash<T> hash1, IHash<T> hash2)
{
var combineHash = hash1.Value.ToHex() + hash2.Value.ToHex();
return _cache.TryGetValue(combineHash, out var resultHash)
? resultHash
: AddCache(combineHash, new Hash<T>(hash1.CalculateHashWith(hash2)));
}

private IHash<T> AddCache(string keyHash, IHash<T> valueHash)
{
_cache[keyHash] = valueHash;
return valueHash;
}
}
}
15 changes: 8 additions & 7 deletions AElf.Kernel/WorldState.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using AElf.Kernel.Extensions;
Expand All @@ -9,7 +10,7 @@ namespace AElf.Kernel
{
public class WorldState : IWorldState
{
private Dictionary<byte[], IAccountDataProvider> _accountDataProviders;
private ConcurrentDictionary<IAccount, IAccountDataProvider> _accountDataProviders;

// TODO:
// Figure out how to update the merkle tree node automatically.
Expand All @@ -19,19 +20,19 @@ public class WorldState : IWorldState

public WorldState()
{
_accountDataProviders = new Dictionary<byte[], IAccountDataProvider>();
_accountDataProviders = new ConcurrentDictionary<IAccount, IAccountDataProvider>();
_merkleTree = new BinaryMerkleTree<IHash>();
}

/// <summary>
/// If the given account address included in the world state, return the instance,
/// otherwise create a new account data provider and return.
/// </summary>
/// <param name="accountAddress"></param>
/// <param name="account"></param>
/// <returns></returns>
public IAccountDataProvider GetAccountDataProviderByAccount(IAccount account)
{
return _accountDataProviders.TryGetValue(account.GetAddress().Value, out var accountDataProvider)
return _accountDataProviders.TryGetValue(account, out var accountDataProvider)
? accountDataProvider
: AddAccountDataProvider(account);
}
Expand All @@ -45,11 +46,11 @@ private IAccountDataProvider AddAccountDataProvider(IAccount account)
{
var accountDataProvider = new AccountDataProvider(account);
//Add the address to dict.
_accountDataProviders[account.GetAddress().Value] = accountDataProvider;
_accountDataProviders[account] = accountDataProvider;
//Add the hash of account data provider to merkle tree as a node.
_merkleTree.AddNode(new Hash<IHash>(accountDataProvider.CalculateHash()));
_merkleTree.AddNode(new Hash<IHash>(accountDataProvider.GetDataProvider().CalculateHash()));

return accountDataProvider;
}
}
}
}
Empty file removed Address.txt
Empty file.