Skip to content

Commit

Permalink
Merge pull request #940 from longfin/bugfix/serialization-exc-2
Browse files Browse the repository at this point in the history
Serializable InsufficientBalanceException
  • Loading branch information
longfin authored Jul 30, 2020
2 parents 0b2236e + e2e2cfd commit d2a1f60
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ To be released.
`BlockHeader` constructor. [[#931], [#935]]
- Added `HashDigest<SHA256>`-typed `preEvaluationHash` parameter to
`Block<T>()` constructor. [[#931], [#935]]
- Replaced `SerializationInfoExtensions.GetValueOrDefault<T>()` to
`SerializationInfoExtensions.TryGetValue<T>()`. [[#940]]

### Backward-incompatible network protocol changes

Expand Down Expand Up @@ -172,6 +174,7 @@ To be released.
[#933]: https://github.com/planetarium/libplanet/pull/933
[#935]: https://github.com/planetarium/libplanet/pull/935
[#936]: https://github.com/planetarium/libplanet/pull/936
[#940]: https://github.com/planetarium/libplanet/pull/940
[sleep mode]: https://en.wikipedia.org/wiki/Sleep_mode


Expand Down
41 changes: 41 additions & 0 deletions Libplanet.Tests/Action/InsufficientBalanceExceptionTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Libplanet.Action;
using Xunit;

namespace Libplanet.Tests.Action
{
public class InsufficientBalanceExceptionTest
{
[Fact]
public void Serializable()
{
var minter = new Address(new byte[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
});
var account = new Address(new byte[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
});

var currency = new Currency("PLT", minter);
var exc = new InsufficientBalanceException(account, currency, 99, "for testing");

var formatter = new BinaryFormatter();
using (var ms = new MemoryStream())
{
formatter.Serialize(ms, exc);

ms.Seek(0, SeekOrigin.Begin);
var deserialized = (InsufficientBalanceException)formatter.Deserialize(ms);
Assert.Equal("for testing", deserialized.Message);
Assert.Equal(account, deserialized.Address);
Assert.Equal(currency.Hash, deserialized.Currency.Hash);
Assert.Equal(99, deserialized.Balance);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using Libplanet.Action;
using Libplanet.Tests.Common.Action;
using Libplanet.Tx;
using Xunit;

namespace Libplanet.Tests.Action
Expand All @@ -12,8 +15,23 @@ public class UnexpectedlyTerminatedActionExceptionTest
public void Serializable()
{
var innerExc = new Exception("inner");
var blockHash = new HashDigest<SHA256>(
TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)
);
long blockIndex = 100;
var txId = new TxId(TestUtils.GetRandomBytes(TxId.Size));
var action = new Sleep()
{
ZoneId = 1,
};

var exc = new UnexpectedlyTerminatedActionException(
default, default, null, null, "for testing", innerExc
blockHash,
blockIndex,
txId,
action,
"for testing",
innerExc
);

var formatter = new BinaryFormatter();
Expand All @@ -26,6 +44,13 @@ public void Serializable()
Assert.Equal("for testing", deserialized.Message);
Assert.IsType<Exception>(deserialized.InnerException);
Assert.Equal(innerExc.Message, deserialized.InnerException.Message);

Assert.Equal(blockHash, deserialized.BlockHash);
Assert.Equal(blockIndex, deserialized.BlockIndex);
Assert.Equal(txId, deserialized.TxId);

Assert.IsType<Sleep>(deserialized.Action);
Assert.Equal(action.PlainValue, deserialized.Action.PlainValue);
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions Libplanet.Tests/CurrencyTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Immutable;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using Libplanet.Crypto;
using Xunit;
Expand Down Expand Up @@ -107,5 +109,21 @@ public void String()
Currency currency = new Currency(ticker: "GOLD", minter: AddressA);
Assert.Equal("GOLD (2ce0b92ff1c5e5631d73370ad2c45920c1ba9755)", currency.ToString());
}

[Fact]
public void Serializable()
{
var currency = new Currency(ticker: "GOLD", minter: AddressA);

var formatter = new BinaryFormatter();
using (var ms = new MemoryStream())
{
formatter.Serialize(ms, currency);
ms.Seek(0, SeekOrigin.Begin);

var deserialized = (Currency)formatter.Deserialize(ms);
Assert.Equal(currency.Hash, deserialized.Hash);
}
}
}
}
19 changes: 19 additions & 0 deletions Libplanet/Action/InsufficientBalanceException.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#nullable enable
using System;
using System.Numerics;
using System.Runtime.Serialization;
using Libplanet.Serialization;

namespace Libplanet.Action
{
Expand Down Expand Up @@ -36,6 +38,14 @@ public InsufficientBalanceException(
Balance = balance;
}

private InsufficientBalanceException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
Address = info.GetValue<Address>(nameof(Address));
Balance = info.GetValue<BigInteger>(nameof(Balance));
Currency = info.GetValue<Currency>(nameof(Currency));
}

/// <summary>
/// The owner of the insufficient <see cref="Balance"/>.
/// </summary>
Expand All @@ -50,5 +60,14 @@ public InsufficientBalanceException(
/// The account's current balance of the <see cref="Currency"/>.
/// </summary>
public BigInteger Balance { get; }

public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);

info.AddValue(nameof(Address), Address);
info.AddValue(nameof(Balance), Balance);
info.AddValue(nameof(Currency), Currency);
}
}
}
53 changes: 53 additions & 0 deletions Libplanet/Action/UnexpectedlyTerminatedActionException.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using Bencodex;
using Bencodex.Types;
using Libplanet.Blockchain.Policies;
using Libplanet.Blocks;
using Libplanet.Serialization;
using Libplanet.Tx;

namespace Libplanet.Action
Expand Down Expand Up @@ -55,6 +58,30 @@ StreamingContext context
)
: base(info, context)
{
if (info.TryGetValue(nameof(BlockHash), out byte[] blockHash))
{
BlockHash = new HashDigest<SHA256>(blockHash);
}

if (info.TryGetValue(nameof(BlockIndex), out long blockIndex))
{
BlockIndex = blockIndex;
}

if (info.TryGetValue(nameof(TxId), out byte[] txId))
{
TxId = new TxId(txId);
}

if (info.TryGetValue($"{nameof(Action)}_type", out string actionType))
{
var values = (Dictionary)new Codec().Decode(
info.GetValue<byte[]>($"{nameof(Action)}_values")
);

Action = (IAction)Activator.CreateInstance(Type.GetType(actionType, true, true));
Action?.LoadPlainValue(values);
}
}

/// <summary>
Expand All @@ -80,5 +107,31 @@ StreamingContext context
/// The <see cref="IAction"/> object which threw an exception.
/// </summary>
public IAction Action { get; }

public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);

if (BlockHash is HashDigest<SHA256> blockHash)
{
info.AddValue(nameof(BlockHash), blockHash.ToByteArray());
}

if (BlockIndex is long blockIndex)
{
info.AddValue(nameof(BlockIndex), blockIndex);
}

if (TxId is TxId txId)
{
info.AddValue(nameof(TxId), txId.ToByteArray());
}

if (!(Action is null))
{
info.AddValue($"{nameof(Action)}_type", Action.GetType().AssemblyQualifiedName);
info.AddValue($"{nameof(Action)}_values", new Codec().Encode(Action.PlainValue));
}
}
}
}
32 changes: 31 additions & 1 deletion Libplanet/Currency.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using Bencodex;
using Bencodex.Types;
using Libplanet.Action;
using Libplanet.Serialization;

namespace Libplanet
{
Expand All @@ -17,7 +20,8 @@ namespace Libplanet
/// each <see cref="Currency"/> value represents such currencies as USD (US Dollar) or
/// EUR (Euro), <em>not values</em> like $100 or €100.
/// </summary>
public readonly struct Currency
[Serializable]
public readonly struct Currency : ISerializable
{
/// <summary>
/// The ticker symbol, e.g., <c>&quot;USD&quot;</c>.
Expand Down Expand Up @@ -80,6 +84,22 @@ public Currency(string ticker, Address? minter)
{
}

private Currency(SerializationInfo info, StreamingContext context)
{
Ticker = info.GetValue<string>(nameof(Ticker));

if (info.TryGetValue(nameof(Minters), out List<byte[]> minters))
{
Minters = minters.Select(m => new Address(m)).ToImmutableHashSet();
}
else
{
Minters = default;
}

Hash = GetHash();
}

/// <summary>
/// Returns <c>true</c> if and only if the given <paramref name="address"/> is allowed
/// to mint or burn assets of this currency.
Expand All @@ -90,6 +110,16 @@ public Currency(string ticker, Address? minter)
[Pure]
public bool AllowsToMint(Address address) => Minters is null || Minters.Contains(address);

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(nameof(Ticker), Ticker);

if (Minters is IImmutableSet<Address> minters)
{
info.AddValue(nameof(Minters), minters.Select(m => m.ToByteArray()).ToList());
}
}

[Pure]
public override string ToString() =>
$"{Ticker} ({Hash})";
Expand Down
10 changes: 6 additions & 4 deletions Libplanet/Serialization/SerializationInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@ public static T GetValue<T>(this SerializationInfo info, string name)
return (T)info.GetValue(name, typeof(T));
}

public static T GetValueOrDefault<T>(
public static bool TryGetValue<T>(
this SerializationInfo serializationInfo,
string name,
T defaultValue)
out T value)
{
try
{
return serializationInfo.GetValue<T>(name);
value = serializationInfo.GetValue<T>(name);
return true;
}
catch (SerializationException)
{
return defaultValue;
value = default;
return false;
}
}
}
Expand Down

0 comments on commit d2a1f60

Please sign in to comment.