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

UntypedBlock & UntypedTransaction #1978

Merged
merged 14 commits into from
May 25, 2022
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
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