Skip to content

Commit

Permalink
Interface to store addresses mask into blocks
Browse files Browse the repository at this point in the history
Note: Although I added an ad-hoc field separated from Block type,
this leads the order of storing multiple blocks to be forced
unless there are information about corresponding addresses masks
for these blocks to put in.  (A mask for a block needs to be
made on top of the mask for its previous block.)

For example, if we want to retrieve a large amount of blocks
out of order, we need to serialize the order of block insertions,
from the genesis block to the topmost block, or retrieve pairs
of block and its mask.  Even if we retrieve blocks along with
their masks, as masks are neither signed nor hashed with nonce,
we implement extra validations for masks.  It doesn't make only
dealing with blocks complex and painful, but also these jobs
bug-prone.

So I suggest to put the mask field into the Block type,
so that it is fully integrated into blockchain and all
things are validated along with, in a consistent way.
  • Loading branch information
dahlia committed Apr 12, 2019
1 parent 8406241 commit e01da78
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 10 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ To be released.
mined by `BlockChain<T>.MineBlock()`.
- Fixed a bug that `TurnClientException` had been thrown by Swarm when a STUN
nonce is stale. [[#193]]
- Added `GetAddressesMask(HashDigest<SHA256>)` method to `IStore` interface
and its all implementations. [[#189]]
- The signature of `IStore.PutBlock<T>(Block<T>)` method was changed to
`PutBlock<T>(Block<T>, Address)`. [[#189]]

[#185]: https://github.com/planetarium/libplanet/pull/185
[#187]: https://github.com/planetarium/libplanet/issues/187
Expand Down
24 changes: 21 additions & 3 deletions Libplanet.Tests/Store/FileStoreTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO;
using System.Security.Cryptography;
using Libplanet.Action;
using Libplanet.Crypto;
using Libplanet.Tests.Common.Action;
using Libplanet.Tx;
using Xunit;
Expand All @@ -26,7 +27,7 @@ public void ListNamespaces()
{
Assert.Empty(_fx.Store.ListNamespaces());

_fx.Store.PutBlock(_fx.Block1);
_fx.Store.PutBlock(_fx.Block1, default);
_fx.Store.AppendIndex(_ns, _fx.Block1.Hash);
Assert.Equal(
new[] { _ns }.ToImmutableHashSet(),
Expand Down Expand Up @@ -92,7 +93,8 @@ public void StoreBlock()
Assert.Null(_fx.Store.GetBlock<DumbAction>(_fx.Block3.Hash));
Assert.False(_fx.Store.DeleteBlock(_fx.Block1.Hash));

_fx.Store.PutBlock(_fx.Block1);
Address arbitraryMask = new PrivateKey().PublicKey.ToAddress();
_fx.Store.PutBlock(_fx.Block1, arbitraryMask);
Assert.Equal(1, _fx.Store.CountBlocks());
Assert.Equal(
new HashSet<HashDigest<SHA256>>
Expand All @@ -103,10 +105,17 @@ public void StoreBlock()
Assert.Equal(
_fx.Block1,
_fx.Store.GetBlock<DumbAction>(_fx.Block1.Hash));
Assert.Equal(
arbitraryMask,
_fx.Store.GetAddressesMask(_fx.Block1.Hash)
);
Assert.Null(_fx.Store.GetBlock<DumbAction>(_fx.Block2.Hash));
Assert.Null(_fx.Store.GetAddressesMask(_fx.Block2.Hash));
Assert.Null(_fx.Store.GetBlock<DumbAction>(_fx.Block3.Hash));
Assert.Null(_fx.Store.GetAddressesMask(_fx.Block3.Hash));

_fx.Store.PutBlock(_fx.Block2);
Address arbitraryMask2 = new PrivateKey().PublicKey.ToAddress();
_fx.Store.PutBlock(_fx.Block2, arbitraryMask2);
Assert.Equal(2, _fx.Store.CountBlocks());
Assert.Equal(
new HashSet<HashDigest<SHA256>>
Expand All @@ -118,10 +127,19 @@ public void StoreBlock()
Assert.Equal(
_fx.Block1,
_fx.Store.GetBlock<DumbAction>(_fx.Block1.Hash));
Assert.Equal(
arbitraryMask,
_fx.Store.GetAddressesMask(_fx.Block1.Hash)
);
Assert.Equal(
_fx.Block2,
_fx.Store.GetBlock<DumbAction>(_fx.Block2.Hash));
Assert.Equal(
arbitraryMask2,
_fx.Store.GetAddressesMask(_fx.Block2.Hash)
);
Assert.Null(_fx.Store.GetBlock<DumbAction>(_fx.Block3.Hash));
Assert.Null(_fx.Store.GetAddressesMask(_fx.Block3.Hash));

Assert.True(_fx.Store.DeleteBlock(_fx.Block1.Hash));
Assert.Equal(1, _fx.Store.CountBlocks());
Expand Down
12 changes: 9 additions & 3 deletions Libplanet.Tests/Store/StoreTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ public Block<T> GetBlock<T>(HashDigest<SHA256> blockHash)
return _store.GetBlock<T>(blockHash);
}

public Address? GetAddressesMask(HashDigest<SHA256> blockHash)
{
_logs.Add((nameof(GetAddressesMask), blockHash, null));
return _store.GetAddressesMask(blockHash);
}

public AddressStateMap GetBlockStates(HashDigest<SHA256> blockHash)
{
_logs.Add((nameof(GetBlockStates), blockHash, null));
Expand Down Expand Up @@ -123,11 +129,11 @@ public IEnumerable<string> ListNamespaces()
return _store.ListNamespaces();
}

public void PutBlock<T>(Block<T> block)
public void PutBlock<T>(Block<T> block, Address addressesMask)
where T : IAction, new()
{
_logs.Add((nameof(PutBlock), block, null));
_store.PutBlock<T>(block);
_logs.Add((nameof(PutBlock), block, addressesMask));
_store.PutBlock<T>(block, addressesMask);
}

public void PutTransaction<T>(Transaction<T> tx)
Expand Down
6 changes: 5 additions & 1 deletion Libplanet/Store/BaseStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ public abstract void PutTransaction<T>(Transaction<T> tx)
public abstract Block<T> GetBlock<T>(HashDigest<SHA256> blockHash)
where T : IAction, new();

public abstract void PutBlock<T>(Block<T> block)
/// <inheritdoc />
public abstract Address? GetAddressesMask(HashDigest<SHA256> blockHash);

/// <inheritdoc />
public abstract void PutBlock<T>(Block<T> block, Address addressesMask)
where T : IAction, new();

public abstract bool DeleteBlock(HashDigest<SHA256> blockHash);
Expand Down
4 changes: 3 additions & 1 deletion Libplanet/Store/BlockSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ public override Block<T> this[HashDigest<SHA256> key]
}

value.Validate(DateTimeOffset.UtcNow);
Store.PutBlock(value);

// FIXME: A proper mask should be passed.
Store.PutBlock(value, default(Address));
}
}

Expand Down
37 changes: 36 additions & 1 deletion Libplanet/Store/FileStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class FileStore : BaseStore
private const string _stagedTransactionsDir = "stage";
private const string _statesDir = "states";
private const string _indicesDir = "indices";
private const string _addressesMaskDir = "masks";

private static readonly string[] BuiltinDirs =
{
Expand Down Expand Up @@ -84,6 +85,16 @@ public string GetBlockPath()
_blocksDir);
}

public string GetAddressesMaskPath(HashDigest<SHA256> blockHash)
{
var keyHex = blockHash.ToString();
return Path.Combine(
_path,
_addressesMaskDir,
keyHex.Substring(0, 4),
keyHex.Substring(4));
}

public string GetStagedTransactionPath(TxId txid)
{
return Path.Combine(
Expand Down Expand Up @@ -260,6 +271,22 @@ public override Block<T> GetBlock<T>(HashDigest<SHA256> blockHash)
}
}

public override Address? GetAddressesMask(HashDigest<SHA256> blockHash)
{
var blockFile = new FileInfo(GetAddressesMaskPath(blockHash));
if (!blockFile.Exists)
{
return null;
}

using (Stream stream = blockFile.OpenRead())
{
var buffer = new byte[Address.Size];
stream.Read(buffer, 0, buffer.Length);
return new Address(buffer);
}
}

public override Transaction<T> GetTransaction<T>(TxId txid)
{
var txFile = new FileInfo(GetTransactionPath(txid));
Expand Down Expand Up @@ -423,7 +450,7 @@ public override IEnumerable<TxId> IterateTransactionIds()
}
}

public override void PutBlock<T>(Block<T> block)
public override void PutBlock<T>(Block<T> block, Address addressesMask)
{
foreach (var tx in block.Transactions)
{
Expand All @@ -441,6 +468,14 @@ public override void PutBlock<T>(Block<T> block)
);
stream.Write(blockBytes, 0, blockBytes.Length);
}

var maskFile = new FileInfo(GetAddressesMaskPath(block.Hash));
maskFile.Directory.Create();
using (Stream stream = maskFile.Open(
FileMode.OpenOrCreate, FileAccess.Write))
{
stream.Write(addressesMask.ToByteArray(), 0, Address.Size);
}
}

public override void PutTransaction<T>(Transaction<T> tx)
Expand Down
30 changes: 29 additions & 1 deletion Libplanet/Store/IStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,35 @@ void PutTransaction<T>(Transaction<T> tx)
Block<T> GetBlock<T>(HashDigest<SHA256> blockHash)
where T : IAction, new();

void PutBlock<T>(Block<T> block)
/// <summary>
/// Gets the bitmask of all addresses ever used until the block
/// of the given <paramref name="blockHash"/>.
/// </summary>
/// <param name="blockHash">The <see cref="Block{T}.Hash"/> of
/// the topmost <see cref="Block{T}"/> of the <see cref="Block{T}"/>
/// sequence that updated the <see cref="Address"/> set to which
/// the bit mask you want to obtain approximates.</param>
/// <returns>A bitmask in the <see cref="Address"/> type
/// (so this is probably not a valid address). It can be
/// <c>null</c> if the given <paramref name="blockHash"/> refers to
/// a <see cref="Block{T}"/> that is not in the store.</returns>
Address? GetAddressesMask(HashDigest<SHA256> blockHash);

/// <summary>
/// Puts the given <paramref name="block"/> in to the store,
/// with a bit mask which approximates the <see cref="Address"/> set
/// updated by the <paramref name="block"/> and its all previous
/// <see cref="Block{T}"/>s.
/// </summary>
/// <param name="block">A <see cref="Block{T}"/> to put into the store.
/// </param>
/// <param name="addressesMask">A bit mask, in the <see cref="Address"/>
/// type (so this is probably not a valid address), which approximates
/// the <see cref="Address"/> set updated by the <paramref name="block"
/// /> and its all previous <see cref="Block{T}"/>s.</param>
/// <typeparam name="T">An <see cref="IAction"/> class used with
/// <paramref name="block"/>.</typeparam>
void PutBlock<T>(Block<T> block, Address addressesMask)
where T : IAction, new();

bool DeleteBlock(HashDigest<SHA256> blockHash);
Expand Down

0 comments on commit e01da78

Please sign in to comment.