Skip to content

Commit

Permalink
Merge pull request #1978 from dahlia/untyped-block
Browse files Browse the repository at this point in the history
`UntypedBlock` & `UntypedTransaction`
  • Loading branch information
dahlia authored May 25, 2022
2 parents 9ae10a5 + 912d858 commit 37c7598
Show file tree
Hide file tree
Showing 35 changed files with 1,487 additions and 580 deletions.
1 change: 1 addition & 0 deletions .github/bin/constants.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ projects=(
"Libplanet"
"Libplanet.Stun"
"Libplanet.Net"
"Libplanet.Node"
"Libplanet.RocksDBStore"
"Libplanet.Analyzers"
"Libplanet.Tools"
Expand Down
31 changes: 31 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ To be released.

### Backward-incompatible API changes

- Removed `InvalidTxPublicKeyException` class. [[#1164], [#1978]]
- (Libplanet.Net) Property `SwarmOptions.BlockDownloadTimeout` removed.
[[#1981], [#1982]]
- (Libplanet.Net) `Swarm<T>.BootstrapAsync(IEnumerable<Peer>, TimeSpan?,
Expand All @@ -29,14 +30,44 @@ To be released.

### Added APIs

- Introduced *Libplanet.Node* package. [[#1974], [#1978]]
- Added `ITxMetadata` interface. [[#1164], [#1974], [#1978]]
- Added `TxMetadata` class. [[#1164], [#1974], [#1978]]
- Added `ITxExcerpt` interface. [[#1164], [#1974], [#1978]]
- Added `TxExcerptExtensions` static class. [[#1164], [#1974], [#1978]]
- `Transaction<T>` now implements `ITxExcerpt` interface.
[[#1164], [#1974], [#1978]]
- Added `Transaction<T>(ITxMetadata, IEnumerable<T>, byte[])` constructor.
[[#1164], [#1978]]
- Added `TxId.FromString()` static method. [[#1978]]
- (Libplanet.Node) Added `UntypedTransaction` class. [[#1974], [#1978]]
- (Libplanet.Node) Added `UntypedBlock` class. [[#1974], [#1978]]

### Behavioral changes

- `Transaction<T>(long, Address, PublicKey, BlockHash?,
IImmutableSet<Address>, DateTimeOffset, IEnumerable<T>, byte[])` constructor
became to ignore its second parameter `Address signer`. Instead,
`Transaction<T>.Signer` property is now automatically derived from its
`PublicKey`. [[#1164], [#1978]]

### Bug fixes

- Fixed `InvalidOperationException` thrown by `PublicKey.Verify()` method
if `signature` is a `default(ImmutableArray<byte>)`. Instead, it silently
returns `false` now. [[#1978]]
- Fixed `NullReferenceException` thrown by `ByteUtil.Hex(in
ImmutabelArray<byte>)` method if a `default(ImmutableArray<byte>)` is
present. Instead, it silently returns an empty string now. [[#1978]]
- Fixed a `TxId(byte[])` constructor's bug where `ParamName` and `Message` of
`ArgumentOutOfRangeException` it had thrown had been reversed. [[#1978]]

### Dependencies

### CLI tools

[#1974]: https://github.com/planetarium/libplanet/issues/1974
[#1978]: https://github.com/planetarium/libplanet/pull/1978
[#1981]: https://github.com/planetarium/libplanet/issues/1981
[#1982]: https://github.com/planetarium/libplanet/pull/1982
[#1990]: https://github.com/planetarium/libplanet/pull/1990
Expand Down
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ on GitHub consists of several projects:
*Libplanet*. This is distributed as a distinct NuGet package:
*[Libplanet.Net]*.

- *Libplanet.Node*: User-friendly façade API for building your own
peer-to-peer network. This is distributed as a distinct NuGet package:
*[Libplanet.Node]*.

- *Libplanet.Stun*: The project dedicated to implement [TURN & STUN].
This is distributed as a distinct NuGet package: *[Libplanet.Stun]*.

Expand Down Expand Up @@ -119,6 +123,8 @@ on GitHub consists of several projects:

- *Libplanet.Net.Tests*: Unit tests of the *Libplanet.Net* project.

- *Libplanet.Node.Tests*: Unit tests of the *Libplanet.Node* project.

- *Libplanet.Stun.Tests*: Unit tests of the *Libplanet.Stun* project.

- *Libplanet.RocksDBStore.Tests*: Unit tests of the *Libplanet.RocksDBStore*
Expand All @@ -136,6 +142,7 @@ on GitHub consists of several projects:

[NuGet package]: https://www.nuget.org/packages/Libplanet/
[Libplanet.Net]: https://www.nuget.org/packages/Libplanet.Net/
[Libplanet.Node]: https://www.nuget.org/packages/Libplanet.Node/
[TURN & STUN]: https://snack.planetarium.dev/eng/2019/06/nat_traversal_2/
[RocksDB]: https://rocksdb.org/
[Libplanet.Stun]: https://www.nuget.org/packages/Libplanet.Stun/
Expand Down
1 change: 1 addition & 0 deletions Docs/docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"files": [
"Libplanet/Libplanet.csproj",
"Libplanet.Net/Libplanet.Net.csproj",
"Libplanet.Node/Libplanet.Node.csproj",
"Libplanet.RocksDBStore/Libplanet.RocksDBStore.csproj",
"Libplanet.Extensions.Cocona/Libplanet.Extensions.Cocona.csproj",
"Libplanet.Stun/Libplanet.Stun.csproj"
Expand Down
81 changes: 81 additions & 0 deletions Libplanet.Node.Tests/Libplanet.Node.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsTestProject>true</IsTestProject>
<LangVersion>8.0</LangVersion>
<CodeAnalysisRuleSet>..\Libplanet.Tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

<ItemGroup>
<AdditionalFiles Include="..\Libplanet.Tests\Menees.Analyzers.Settings.xml">
<Link>Menees.Analyzers.Settings.xml</Link>
</AdditionalFiles>
<AdditionalFiles Include="..\stylecop.json" />
</ItemGroup>

<PropertyGroup Condition="
'$([System.Runtime.InteropServices.RuntimeInformation]::
OSArchitecture.ToString())' == 'Arm64' ">
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition=" '$(TestsTargetFramework)'!='' ">
<TargetFramework>$(TestsTargetFramework)</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="JunitXml.TestLogger" Version="3.0.98" />
<PackageReference Include="Menees.Analyzers.2017" Version="2.0.3">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.0.0" />
<PackageReference Include="Serilog.Sinks.TestCorrelator" Version="3.2.0" />
<PackageReference Include="Serilog.Sinks.XUnit" Version="1.0.7" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.205">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>
runtime; build; native; contentfiles; analyzers
</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Collections.Immutable" Version="1.7.*" />
<PackageReference Include="xRetry" Version="1.5.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="Xunit.SkippableFact" Version="1.3.12" />
</ItemGroup>

<ItemGroup Condition="'$(SkipSonar)' != 'true'">
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.12.0.21095">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net47' ">
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Libplanet.Node\Libplanet.Node.csproj" />
</ItemGroup>

<ItemGroup Condition=" '$(MSBuildRuntimeType)'=='Mono' ">
<!--
As Mono has no proper AppDomain, we prevent it on Mono.
This works around Xunit's fatal error on Mono.
-->
<Content Include="xunit.runner.mono.json">
<Link>xunit.runner.json</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
120 changes: 120 additions & 0 deletions Libplanet.Node.Tests/UntypedBlockTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Security.Cryptography;
using Bencodex;
using Libplanet.Action;
using Libplanet.Blocks;
using Libplanet.Crypto;
using Libplanet.Store;
using Libplanet.Store.Trie;
using Libplanet.Tx;
using Xunit;

namespace Libplanet.Node.Tests
{
public class UntypedBlockTest
{
private static readonly HashAlgorithmType Sha256 = HashAlgorithmType.Of<SHA256>();
private static readonly Codec Codec = new Codec();
private readonly PrivateKey _signerKey;
private readonly Transaction<NullAction>[] _txs;
private readonly PrivateKey _minerKey;
private readonly BlockContent<NullAction> _content;
private readonly PreEvaluationBlock<NullAction> _preEval;
private readonly Block<NullAction> _block;

public UntypedBlockTest()
{
_signerKey = new PrivateKey(new byte[]
{
0xfc, 0xf3, 0x0b, 0x33, 0x3d, 0x04, 0xcc, 0xfe, 0xb5, 0x62, 0xf0,
0x00, 0xa3, 0x2d, 0xf4, 0x88, 0xe7, 0x15, 0x49, 0x49, 0xd3, 0x1d,
0xdc, 0xac, 0x3c, 0xf9, 0x27, 0x8a, 0xcb, 0x57, 0x86, 0xc7,
});
var txA = Transaction<NullAction>.Create(
nonce: 0L,
privateKey: _signerKey,
genesisHash: null,
actions: Enumerable.Empty<NullAction>(),
timestamp: new DateTimeOffset(2022, 5, 24, 0, 0, 0, TimeSpan.Zero)
);
var txB = Transaction<NullAction>.Create(
nonce: 1L,
privateKey: _signerKey,
genesisHash: null,
actions: new[]
{
new NullAction(),
new NullAction(),
},
timestamp: new DateTimeOffset(2022, 5, 24, 0, 0, 1, TimeSpan.Zero)
);
_txs = new[] { txA, txB };
_minerKey = new PrivateKey(new byte[]
{
0x9b, 0xf4, 0x66, 0x4b, 0xa0, 0x9a, 0x89, 0xfa, 0xeb, 0x68, 0x4b,
0x94, 0xe6, 0x9f, 0xfd, 0xe0, 0x1d, 0x26, 0xae, 0x14, 0xb5, 0x56,
0x20, 0x4d, 0x3f, 0x6a, 0xb5, 0x8f, 0x61, 0xf7, 0x84, 0x18,
});
_content = new BlockContent<NullAction>
{
Index = 0L,
Timestamp = new DateTimeOffset(2022, 5, 24, 1, 2, 3, 456, TimeSpan.Zero),
PublicKey = _minerKey.PublicKey,
Difficulty = 0L,
PreviousHash = null,
Transactions = _txs,
};
var nonce = default(Nonce);
byte[] blockBytes = Codec.Encode(_content.MakeCandidateData(nonce));
ImmutableArray<byte> preEvalHash = Sha256.Digest(blockBytes).ToImmutableArray();
var proof = (nonce, preEvalHash);
_preEval = new PreEvaluationBlock<NullAction>(_content, Sha256, proof);
_block = _preEval.Evaluate(
_minerKey,
null,
new TrieStateStore(new MemoryKeyValueStore())
);
}

[Fact]
public void Deserialize()
{
Bencodex.Types.Dictionary dict = _block.MarshalBlock();
var untyped = new UntypedBlock(_ => Sha256, dict);
Assert.Equal(_block.ProtocolVersion, untyped.ProtocolVersion);
Assert.Equal(_block.HashAlgorithm, untyped.HashAlgorithm);
Assert.Equal(_block.Index, untyped.Index);
Assert.Equal(_block.Timestamp, untyped.Timestamp);
Assert.Equal(_block.Nonce, untyped.Nonce);
Assert.Equal(_block.Miner, untyped.Miner);
Assert.Equal(_block.PublicKey, untyped.PublicKey);
Assert.Equal(_block.Difficulty, untyped.Difficulty);
Assert.Equal(_block.TotalDifficulty, untyped.TotalDifficulty);
Assert.Equal(_block.PreviousHash, untyped.PreviousHash);
Assert.Equal(_block.TxHash, untyped.TxHash);
Assert.Equal(_block.Signature, untyped.Signature);
Assert.Equal(_block.PreEvaluationHash, untyped.PreEvaluationHash);
Assert.Equal(_block.StateRootHash, untyped.StateRootHash);
Assert.Equal(_block.Hash, untyped.Hash);
Assert.Equal(_block.Transactions.Count, untyped.UntypedTransactions.Count);
Assert.All(
_block.Transactions.Zip(untyped.UntypedTransactions, (t, u) => (t, u)),
pair => pair.Item1.Id.Equals(pair.Item2.Id)
);
}

[Fact]
public void ToBencodex()
{
var untypedTxs = _txs.Select(tx =>
new UntypedTransaction(
tx,
tx.Actions.Select(a => a.PlainValue),
tx.Signature.ToImmutableArray()));
var untyped = new UntypedBlock(_block, untypedTxs);
Assert.Equal(_block.MarshalBlock(), untyped.ToBencodex());
}
}
}
Loading

0 comments on commit 37c7598

Please sign in to comment.