Skip to content

Commit

Permalink
Merge pull request #46 from EanCuznaivy/feature-tx-from-to-types
Browse files Browse the repository at this point in the history
Use concurrent data structure and update worldstate.
  • Loading branch information
EanCuznaivy authored Feb 8, 2018
2 parents 2857d69 + 9985c78 commit 5501be1
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 72 deletions.
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.

0 comments on commit 5501be1

Please sign in to comment.