Skip to content

Commit

Permalink
Merge pull request #441 from minhoryang/issues/172
Browse files Browse the repository at this point in the history
Less stateful RawTransaction
  • Loading branch information
longfin authored Aug 21, 2019
2 parents 3ec8619 + 2e7057f commit aa3b376
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 72 deletions.
34 changes: 17 additions & 17 deletions Libplanet.Tests/Blocks/BlockTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -338,12 +338,12 @@ public void EvaluateInvalidTxSignature()
{
RawTransaction rawTx = new RawTransaction(
0,
_fx.TxFixture.Address1.ToByteArray(),
new byte[][] { },
_fx.TxFixture.PublicKey1.Format(false),
_fx.TxFixture.Address1.ByteArray,
ImmutableArray<ImmutableArray<byte>>.Empty,
_fx.TxFixture.PublicKey1.Format(false).ToImmutableArray(),
DateTimeOffset.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.ffffffZ"),
new IDictionary<string, object>[0],
new byte[10]
new IImmutableDictionary<string, object>[0],
new byte[10].ToImmutableArray()
);
var invalidTx = new Transaction<DumbAction>(rawTx);
Block<DumbAction> invalidBlock = MineNext(
Expand All @@ -360,12 +360,12 @@ public void EvaluateInvalidTxPublicKey()
{
RawTransaction rawTxWithoutSig = new RawTransaction(
0,
new PrivateKey().PublicKey.ToAddress().ToByteArray(),
new byte[][] { },
_fx.TxFixture.PublicKey1.Format(false),
new PrivateKey().PublicKey.ToAddress().ByteArray,
ImmutableArray<ImmutableArray<byte>>.Empty,
_fx.TxFixture.PublicKey1.Format(false).ToImmutableArray(),
DateTimeOffset.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.ffffffZ"),
new IDictionary<string, object>[0],
new byte[0]
new IImmutableDictionary<string, object>[0],
ImmutableArray<byte>.Empty
);
byte[] sig = _fx.TxFixture.PrivateKey1.Sign(
new Transaction<DumbAction>(rawTxWithoutSig).ToBencodex(false)
Expand All @@ -378,7 +378,7 @@ public void EvaluateInvalidTxPublicKey()
rawTxWithoutSig.PublicKey,
rawTxWithoutSig.Timestamp,
rawTxWithoutSig.Actions,
sig
sig.ToImmutableArray()
)
);
Block<DumbAction> invalidBlock = MineNext(
Expand All @@ -393,17 +393,17 @@ public void EvaluateInvalidTxPublicKey()
[Fact]
public void EvaluateInvalidTxUpdatedAddresses()
{
ImmutableArray<IDictionary<string, object>> rawActions =
ImmutableArray<IImmutableDictionary<string, object>> rawActions =
_fx.TxFixture.TxWithActions
.ToRawTransaction(false).Actions.ToImmutableArray();
RawTransaction rawTxWithoutSig = new RawTransaction(
0,
_fx.TxFixture.Address1.ToByteArray(),
new byte[][] { },
_fx.TxFixture.PublicKey1.Format(false),
_fx.TxFixture.Address1.ByteArray,
ImmutableArray<ImmutableArray<byte>>.Empty,
_fx.TxFixture.PublicKey1.Format(false).ToImmutableArray(),
DateTimeOffset.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.ffffffZ"),
rawActions,
new byte[0]
ImmutableArray<byte>.Empty
);
byte[] sig = _fx.TxFixture.PrivateKey1.Sign(
new Transaction<PolymorphicAction<BaseAction>>(
Expand All @@ -418,7 +418,7 @@ public void EvaluateInvalidTxUpdatedAddresses()
rawTxWithoutSig.PublicKey,
rawTxWithoutSig.Timestamp,
rawTxWithoutSig.Actions,
sig
sig.ToImmutableArray()
)
);
Block<PolymorphicAction<BaseAction>> invalidBlock = MineNext(
Expand Down
14 changes: 7 additions & 7 deletions Libplanet.Tests/Tx/TransactionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ public void DetectBadSignature()
rawTx.PublicKey,
rawTx.Timestamp,
rawTx.Actions,
new byte[rawTx.Signature.Length]
new byte[rawTx.Signature.Length].ToImmutableArray()
)
);

Expand Down Expand Up @@ -778,12 +778,12 @@ public void DetectAddressMismatch()
};
var rawTxWithMismatchedAddress = new RawTransaction(
nonce: 0,
signer: mismatchedAddress,
signer: mismatchedAddress.ToImmutableArray(),
updatedAddresses: rawTx.UpdatedAddresses,
publicKey: rawTx.PublicKey,
timestamp: rawTx.Timestamp,
actions: rawTx.Actions,
signature: signature
signature: signature.ToImmutableArray()
);
var tx = new Transaction<DumbAction>(rawTxWithMismatchedAddress);

Expand Down Expand Up @@ -895,8 +895,8 @@ internal RawTransaction GetExpectedRawTransaction(bool includeSingature)
{
0xc2, 0xa8, 0x60, 0x14, 0x07, 0x3d, 0x66, 0x2a, 0x4a, 0x9b,
0xfc, 0xf9, 0xcb, 0x54, 0x26, 0x3d, 0xfa, 0x4f, 0x5c, 0xbc,
},
updatedAddresses: new byte[][] { },
}.ToImmutableArray(),
updatedAddresses: ImmutableArray<ImmutableArray<byte>>.Empty,
publicKey: new byte[]
{
0x04, 0x46, 0x11, 0x5b, 0x01, 0x31, 0xba, 0xcc, 0xf9, 0x4a,
Expand All @@ -906,9 +906,9 @@ internal RawTransaction GetExpectedRawTransaction(bool includeSingature)
0x1f, 0x11, 0x0a, 0x32, 0x6d, 0xa1, 0xbd, 0xb8, 0x1f, 0x5a,
0xe3, 0xba, 0xdf, 0x76, 0xa9, 0x0b, 0x22, 0xc8, 0xc4, 0x91,
0xae, 0xd3, 0xaa, 0xa2, 0x96,
},
}.ToImmutableArray(),
timestamp: "2018-11-21T00:00:00.000000Z",
actions: new List<IDictionary<string, object>>()
actions: new List<IImmutableDictionary<string, object>>()
);
if (!includeSingature)
{
Expand Down
100 changes: 59 additions & 41 deletions Libplanet/Tx/RawTransaction.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
Expand All @@ -16,26 +17,31 @@ internal struct RawTransaction : ISerializable
public RawTransaction(SerializationInfo info, StreamingContext context)
: this(
nonce: info.GetInt64("nonce"),
signer: info.GetValue<byte[]>("signer"),
publicKey: info.GetValue<byte[]>("public_key"),
signer: info.GetValue<byte[]>("signer").ToImmutableArray(),
publicKey: info.GetValue<byte[]>("public_key").ToImmutableArray(),
updatedAddresses: To2dArray(
info.GetValue<byte[]>("updated_addresses"),
Address.Size),
timestamp: info.GetString("timestamp"),
signature: info.GetValue<byte[]>("signature"),
signature: info.GetValue<byte[]>("signature").ToImmutableArray(),
actions: info.GetValue<IEnumerable>(
"actions").OfType<IDictionary<string, object>>()
"actions").OfType<IDictionary<string, object>>().Select(a =>
a.ToImmutableDictionary(
kv => kv.Key,
kv => kv.Value
)
)
)
{
}

public RawTransaction(
long nonce,
byte[] signer,
byte[][] updatedAddresses,
byte[] publicKey,
ImmutableArray<byte> signer,
ImmutableArray<ImmutableArray<byte>> updatedAddresses,
ImmutableArray<byte> publicKey,
string timestamp,
IEnumerable<IDictionary<string, object>> actions
IEnumerable<IImmutableDictionary<string, object>> actions
)
: this(
nonce,
Expand All @@ -44,19 +50,19 @@ IEnumerable<IDictionary<string, object>> actions
publicKey,
timestamp,
actions,
null
ImmutableArray<byte>.Empty
)
{
}

public RawTransaction(
long nonce,
byte[] signer,
byte[][] updatedAddresses,
byte[] publicKey,
ImmutableArray<byte> signer,
ImmutableArray<ImmutableArray<byte>> updatedAddresses,
ImmutableArray<byte> publicKey,
string timestamp,
IEnumerable<IDictionary<string, object>> actions,
byte[] signature
IEnumerable<IImmutableDictionary<string, object>> actions,
ImmutableArray<byte> signature
)
{
Nonce = nonce;
Expand All @@ -71,68 +77,79 @@ byte[] signature
public RawTransaction(Dictionary<string, object> dict)
{
Nonce = (long)(BigInteger)dict["nonce"];
Signer = (byte[])dict["signer"];
Signer = ((byte[])dict["signer"]).ToImmutableArray();
UpdatedAddresses = To2dArray(
(byte[])dict["updated_addresses"],
Address.Size);
PublicKey = (byte[])dict["public_key"];
PublicKey = ((byte[])dict["public_key"]).ToImmutableArray();
Timestamp = (string)dict["timestamp"];
Actions = ((IEnumerable)dict["actions"])
.Cast<Dictionary<string, object>>()
.Select(a =>
a.ToImmutableDictionary(
kv => kv.Key,
kv => kv.Value
)
)
.ToList();
if (dict.TryGetValue("signature", out object signature))
{
Signature = (byte[])signature;
Signature = ((byte[])signature).ToImmutableArray();
}
else
{
Signature = null;
Signature = ImmutableArray<byte>.Empty;
}
}

public long Nonce { get; }

public byte[] Signer { get; }
public ImmutableArray<byte> Signer { get; }

public byte[] PublicKey { get; }
public ImmutableArray<byte> PublicKey { get; }

public byte[][] UpdatedAddresses { get; }
public ImmutableArray<ImmutableArray<byte>> UpdatedAddresses { get; }

public string Timestamp { get; }

public byte[] Signature { get; }
public ImmutableArray<byte> Signature { get; }

public IEnumerable<IDictionary<string, object>> Actions { get; }
public IEnumerable<IImmutableDictionary<string, object>> Actions { get; }

public void GetObjectData(
SerializationInfo info,
StreamingContext context
)
{
info.AddValue("nonce", Nonce);
info.AddValue("signer", Signer);
info.AddValue("signer", Signer.ToArray());

// SerializationInfo.AddValue() doesn't seem to work well with
// 2d arrays. Concat addresses before encode them (fortunately,
// addresses all have 20 bytes, fixed-length).
var updatedAddresses =
new byte[UpdatedAddresses.Length * Address.Size];
int i = 0;
foreach (byte[] address in UpdatedAddresses)
foreach (ImmutableArray<byte> address in UpdatedAddresses)
{
address.CopyTo(updatedAddresses, i);
i += Address.Size;
}

info.AddValue("updated_addresses", updatedAddresses);

info.AddValue("public_key", PublicKey);
info.AddValue("public_key", PublicKey.ToArray());
info.AddValue("timestamp", Timestamp);
info.AddValue("actions", Actions);

if (Signature != null)
info.AddValue("actions", Actions.Select(a =>
a.ToDictionary(
kv => kv.Key,
kv => kv.Value
)
));

if (Signature != ImmutableArray<byte>.Empty)
{
info.AddValue("signature", Signature);
info.AddValue("signature", Signature.ToArray());
}
}

Expand All @@ -145,31 +162,31 @@ public RawTransaction AddSignature(byte[] signature)
PublicKey,
Timestamp,
Actions,
signature
signature.ToImmutableArray()
);
}

public override int GetHashCode()
{
return ByteUtil.CalculateHashCode(Signature);
return ByteUtil.CalculateHashCode(Signature.ToArray());
}

public override string ToString()
{
string updatedAddresses = string.Join(
string.Empty,
UpdatedAddresses.Select(a => "\n " + ByteUtil.Hex(a))
UpdatedAddresses.Select(a => "\n " + ByteUtil.Hex(a.ToArray()))
);
return $@"{nameof(RawTransaction)}
{nameof(Nonce)} = {Nonce.ToString()}
{nameof(Signer)} = {ByteUtil.Hex(Signer)}
{nameof(PublicKey)} = {ByteUtil.Hex(PublicKey)}
{nameof(Signer)} = {ByteUtil.Hex(Signer.ToArray())}
{nameof(PublicKey)} = {ByteUtil.Hex(PublicKey.ToArray())}
{nameof(UpdatedAddresses)} = {updatedAddresses}
{nameof(Timestamp)} = {Timestamp}
{nameof(Signature)} = {ByteUtil.Hex(Signature)}";
{nameof(Signature)} = {ByteUtil.Hex(Signature.ToArray())}";
}

private static T[][] To2dArray<T>(T[] array, int chunk)
private static ImmutableArray<ImmutableArray<T>> To2dArray<T>(T[] array, int chunk)
{
if (array.Length % chunk > 0)
{
Expand All @@ -180,14 +197,15 @@ private static T[][] To2dArray<T>(T[] array, int chunk)
}

int resultLength = array.Length / chunk;
T[][] result = new T[resultLength][];
var result = new ImmutableArray<T>[resultLength];
for (int i = 0; i < resultLength; i++)
{
result[i] = new T[chunk];
Array.Copy(array, i * chunk, result[i], 0, chunk);
var partialResult = new T[chunk];
Array.Copy(array, i * chunk, partialResult, 0, chunk);
result[i] = partialResult.ToImmutableArray();
}

return result;
return result.ToImmutableArray();
}
}
}
14 changes: 7 additions & 7 deletions Libplanet/Tx/Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ internal Transaction(RawTransaction rawTx)
: this(
rawTx.Nonce,
new Address(rawTx.Signer),
new PublicKey(rawTx.PublicKey),
new PublicKey(rawTx.PublicKey.ToArray()),
rawTx.UpdatedAddresses.Select(
a => new Address(a)
).ToImmutableHashSet(),
Expand All @@ -116,7 +116,7 @@ internal Transaction(RawTransaction rawTx)
TimestampFormat,
CultureInfo.InvariantCulture).ToUniversalTime(),
rawTx.Actions.Select(ToAction).ToImmutableList(),
rawTx.Signature,
rawTx.Signature.ToArray(),
false)
{
}
Expand Down Expand Up @@ -663,13 +663,13 @@ internal RawTransaction ToRawTransaction(bool includeSign)
{
var rawTx = new RawTransaction(
nonce: Nonce,
signer: Signer.ToByteArray(),
signer: Signer.ByteArray,
updatedAddresses: UpdatedAddresses.Select(a =>
a.ToByteArray()).ToArray(),
publicKey: PublicKey.Format(false),
a.ByteArray).ToImmutableArray(),
publicKey: PublicKey.Format(false).ToImmutableArray(),
timestamp: Timestamp.ToString(TimestampFormat),
actions: Actions.Select(a =>
a.PlainValue.ToDictionary(
a.PlainValue.ToImmutableDictionary(
kv => kv.Key,
kv => kv.Value
)
Expand All @@ -684,7 +684,7 @@ internal RawTransaction ToRawTransaction(bool includeSign)
return rawTx;
}

private static T ToAction(IDictionary<string, object> arg)
private static T ToAction(IImmutableDictionary<string, object> arg)
{
var action = new T();
action.LoadPlainValue(arg.ToImmutableDictionary());
Expand Down

0 comments on commit aa3b376

Please sign in to comment.