Skip to content

Commit

Permalink
Resolve #172, Less stateful RawTransaction
Browse files Browse the repository at this point in the history
  • Loading branch information
minhoryang committed Aug 16, 2019
1 parent bb6dc57 commit 37100b8
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 61 deletions.
9 changes: 9 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ To be released.
- Added `IActionContext.NewGuId()` method. [[#371], [#439]]
- `Address(byte[])` became to throw `ArgumentNullException`
instead of `NullReferenceException`. [[#443]]
- `RawTransaction.Signer` became to `ImmutableArray<byte>` type. [[#172], [#441]]
- `RawTransaction.PublicKey` became to `ImmutableArray<byte>` type. [[#172], [#441]]
- `RawTransaction.Signature` became to `ImmutableArray<byte>` type. [[#172], [#441]]
- `RawTransaction.UpdatedAddresses` became to
`ImmutableArray<ImmutableArray<byte>>` type. [[#172], [#441]]
- `RawTransaction.Actions` became to
`IEnumerable<IImmutableDictionary<string, object>>` type. [[#172], [#441]]

### Added interfaces

Expand Down Expand Up @@ -114,6 +121,7 @@ To be released.
- Fixed a bug that TURN relay connection had disconnected when preloading
took a long time. [[#424]]

[#172]: https://github.com/planetarium/libplanet/issues/172
[#319]: https://github.com/planetarium/libplanet/issues/319
[#343]: https://github.com/planetarium/libplanet/pull/343
[#350]: https://github.com/planetarium/libplanet/pull/350
Expand Down Expand Up @@ -152,6 +160,7 @@ To be released.
[#434]: https://github.com/planetarium/libplanet/pull/434
[#438]: https://github.com/planetarium/libplanet/pull/438
[#439]: https://github.com/planetarium/libplanet/pull/439
[#441]: https://github.com/planetarium/libplanet/pull/441
[#442]: https://github.com/planetarium/libplanet/issues/442
[#443]: https://github.com/planetarium/libplanet/pull/443
[LiteDB #1268]: https://github.com/mbdavid/LiteDB/issues/1268
Expand Down
28 changes: 14 additions & 14 deletions Libplanet.Tests/Blocks/BlockTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,11 @@ public void EvaluateInvalidTxSignature()
RawTransaction rawTx = new RawTransaction(
0,
_fx.TxFixture.Address1.ByteArray,
new byte[][] { },
_fx.TxFixture.PublicKey1.Format(false),
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 @@ -361,11 +361,11 @@ public void EvaluateInvalidTxPublicKey()
RawTransaction rawTxWithoutSig = new RawTransaction(
0,
new PrivateKey().PublicKey.ToAddress().ByteArray,
new byte[][] { },
_fx.TxFixture.PublicKey1.Format(false),
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.ByteArray,
new byte[][] { },
_fx.TxFixture.PublicKey1.Format(false),
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
10 changes: 5 additions & 5 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 @@ -783,7 +783,7 @@ public void DetectAddressMismatch()
publicKey: rawTx.PublicKey,
timestamp: rawTx.Timestamp,
actions: rawTx.Actions,
signature: signature
signature: signature.ToImmutableArray()
);
var tx = new Transaction<DumbAction>(rawTxWithMismatchedAddress);

Expand Down Expand Up @@ -896,7 +896,7 @@ 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,
}.ToImmutableArray(),
updatedAddresses: new byte[][] { },
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
87 changes: 52 additions & 35 deletions Libplanet/Tx/RawTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,30 @@ public RawTransaction(SerializationInfo info, StreamingContext context)
: this(
nonce: info.GetInt64("nonce"),
signer: info.GetValue<byte[]>("signer").ToImmutableArray(),
publicKey: info.GetValue<byte[]>("public_key"),
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,
ImmutableArray<byte> signer,
byte[][] updatedAddresses,
byte[] publicKey,
ImmutableArray<ImmutableArray<byte>> updatedAddresses,
ImmutableArray<byte> publicKey,
string timestamp,
IEnumerable<IDictionary<string, object>> actions
IEnumerable<IImmutableDictionary<string, object>> actions
)
: this(
nonce,
Expand All @@ -45,19 +50,19 @@ IEnumerable<IDictionary<string, object>> actions
publicKey,
timestamp,
actions,
null
ImmutableArray<byte>.Empty
)
{
}

public RawTransaction(
long nonce,
ImmutableArray<byte> signer,
byte[][] updatedAddresses,
byte[] publicKey,
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 @@ -76,64 +81,75 @@ public RawTransaction(Dictionary<string, object> dict)
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 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 @@ -146,31 +162,31 @@ public RawTransaction AddSignature(byte[] signature)
PublicKey,
Timestamp,
Actions,
signature
signature.ToImmutableArray() // FIXME: New API?
);
}

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.ToArray())}
{nameof(PublicKey)} = {ByteUtil.Hex(PublicKey)}
{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 @@ -181,14 +197,15 @@ private static T[][] To2dArray<T>(T[] array, int chunk)
}

int resultLength = array.Length / chunk;
T[][] result = new T[resultLength][];
ImmutableArray<T>[] 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);
T[] 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 @@ -106,8 +106,8 @@ public Transaction(
internal Transaction(RawTransaction rawTx)
: this(
rawTx.Nonce,
new Address(rawTx.Signer.ToArray()), // FIXME(minhoryang): Propagate?
new PublicKey(rawTx.PublicKey),
new Address(rawTx.Signer),
new PublicKey(rawTx.PublicKey.ToArray()), // FIXME: propagate?
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(), // FIXME: propagate?
false)
{
}
Expand Down Expand Up @@ -665,11 +665,11 @@ internal RawTransaction ToRawTransaction(bool includeSign)
nonce: Nonce,
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 37100b8

Please sign in to comment.