Skip to content
Permalink
Browse files

Merge pull request #121 from dahlia/advance-tx-recipient

Refactor the interface for actions updating states
  • Loading branch information...
dahlia committed Mar 15, 2019
2 parents 6cb9223 + cca67a1 commit 352a7834aae2c7d1c8b6bb104e4e96a40c55abfa
Showing with 1,932 additions and 774 deletions.
  1. +1 −0 .gitignore
  2. +91 −10 CHANGES.md
  3. +3 −2 Libplanet.Explorer/Controllers/ExplorerController.cs
  4. +3 −3 Libplanet.Explorer/README.md
  5. +2 −2 Libplanet.Explorer/ViewModels/TransactionViewModel.cs
  6. +93 −0 Libplanet.Tests/Action/AccountStateDeltaImplTest.cs
  7. +19 −3 Libplanet.Tests/Action/ActionContextTest.cs
  8. +48 −38 Libplanet.Tests/Blockchain/BlockChainTest.cs
  9. +9 −3 Libplanet.Tests/Blocks/BlockFixture.cs
  10. +294 −75 Libplanet.Tests/Blocks/BlockTest.cs
  11. +16 −12 Libplanet.Tests/Common/Action/Attack.cs
  12. +1 −7 Libplanet.Tests/Common/Action/BaseAction.cs
  13. +68 −6 Libplanet.Tests/Common/Action/BattleResult.cs
  14. +0 −22 Libplanet.Tests/Common/Action/DummyAction.cs
  15. +8 −3 Libplanet.Tests/Common/Action/Sleep.cs
  16. +6 −10 Libplanet.Tests/Net/SwarmTest.cs
  17. +23 −16 Libplanet.Tests/Store/AddressTransactionSetTest.cs
  18. +12 −8 Libplanet.Tests/Store/FileStoreFixture.cs
  19. +377 −274 Libplanet.Tests/Tx/TransactionTest.cs
  20. +37 −23 Libplanet.Tests/Tx/TxFixture.cs
  21. +3 −0 Libplanet.sln.DotSettings
  22. +67 −0 Libplanet/Action/AccountStateDeltaImpl.cs
  23. +16 −0 Libplanet/Action/AccountStateGetter.cs
  24. +5 −9 Libplanet/Action/ActionContext.cs
  25. +97 −0 Libplanet/Action/IAccountStateDelta.cs
  26. +30 −72 Libplanet/Action/IAction.cs
  27. +10 −12 Libplanet/Action/IActionContext.cs
  28. +9 −3 Libplanet/Address.cs
  29. +55 −36 Libplanet/Blockchain/BlockChain.cs
  30. +141 −22 Libplanet/Blocks/Block.cs
  31. +11 −1 Libplanet/Serialization/BencodexFormatterConverter.cs
  32. +3 −2 Libplanet/Store/BlockSet.cs
  33. +2 −1 Libplanet/Store/TransactionSet.cs
  34. +17 −3 Libplanet/Tx/InvalidTxException.cs
  35. +5 −2 Libplanet/Tx/InvalidTxIdException.cs
  36. +6 −3 Libplanet/Tx/InvalidTxPublicKeyException.cs
  37. +5 −2 Libplanet/Tx/InvalidTxSignatureException.cs
  38. +70 −0 Libplanet/Tx/InvalidTxUpdatedAddressesException.cs
  39. +58 −19 Libplanet/Tx/RawTransaction.cs
  40. +210 −69 Libplanet/Tx/Transaction.cs
  41. +1 −1 Libplanet/Tx/TxId.cs
@@ -27,6 +27,7 @@
[Oo]bj/
_UpgradeReport_Files/
[Pp]ackages/
mono_crash.*.json

Thumbs.db
Desktop.ini
@@ -6,10 +6,97 @@ Version 0.2.0

To be released.

- Since we decided to depend on TURN ([RFC 5766]) and STUN ([RFC 5389]) to work around NAT so that `Peer`'s endpoints don't have to be multiple,
`Peer.Urls` was renamed to `Peer.EndPoint` and its type also was changed from `IImmutableList<Uri>` to `IPEndPoint`. (See also [#120], [#126])
- `Address` and `TxId` are now serializable.
- `Swarm.AddPeersAsync()` was fixed to ignore unreachable peers.
- `Transaction<T>`'s `Sender``Recipient` model was replaced by
`Signer``UpdatedAddresses` model. Unlike cryptocurrencies,
transactions in games are not necessarily a transfer of assets,
so it is difficult to determine what type of assert is transferred
or who will receives the asset. A more useful perspective is,
like what kind of transformation is performed, or what states
are changed. To be close to this perspective, we decided to
get rid of `Transaction<T>.Recipient` (which is singular) and
have `Transaction<T>.UpdatedAddresses` (which is plural) instead.
As there is no more asset to transfer, the term `Sender` was also
renamed to `Signer`, which fits more to the new perspective.

- Renamed `Transaction<T>.Sender`, `RawTransaction.Signer`, and
`IActionContext.From` properties to `Signer`.
The corresponding parameter names on constructors and
methods were also renamed too.
- Old `Transaction<T>.Make()` factory method is replaced by
new `Transaction<T>.Create()` factory method. The `timestamp` parameter
became optional, and the new optional `updatedAddresses` parameter was
added.
- Removed `IActionContext.To` property.
- `Transaction<T>.Recipient` and `RawTransaction.Recipient` properties
were replaced by `Transaction<T>.UpdatedAddresses` and
`RawTransaction.UpdatedAddresses` properties.
The corresponding parameter names on constructors and methods were
replaced too.
- Since the schema of `RawTransaction` class was changed,
the serialization format of transactions and blocks were also changed.
It affects to the way to generate `Transaction<T>.Signature`,
`Transaction<T>.Id`, and `Block.Hash` values as well.
- Added `InvalidTxUpdatedAddressesException` exception class.
- A nullary overload of `Block<T>.Validate()` method was gone
so that the block validation API is always time-wise.
Instead, `Block<T>.Validate()` method now has only one overload:
`Validate(DateTimeOffset, AccountStateGetter)` returning
`IAccountStateDelta`.
- `Block<T>.Validate()` and `BlockChain<T>.Validate()` methods now can
throw an `InvalidTxUpdateAddressesException`.

- The `Address`es `IAction` tries to update no more need to be manually
coded using `IAction.RequestStates()` method. That method was
removed at all, and updated `Address`es became automatically scanned
using dirty-tracking for the most cases.

- Added `AccountStateGetter` delegate to provide a read-only view to
account states.
- Added `IAccountStateDelta` interface to replace `AddressStateMap`.
The interface purposes to provide a read-write view to account states
with maintaining `UpdatedAddresses` (so-called "dirty").
- The type of `IActionContext.PreviousStates` property was changed from
`AddressStateMap` to `IAccountStateDelta`.
- The return type of `IAction.Execute()` method was changed from
`AddressStateMap` to `IAccountStateDelta`.
- Removed `IAction.RequestStates()` method because there is no need for it
and thus it is not used anymore.
- Added `Transaction<T>.EvaluateActions()` method.
- Added `Block<T>.EvaluateActions()` generator method.

- Fixed a bug that mutating a collection of `IAction`s passed to
constructors or factory methods of `Transaction<T>` had affected
made instances as well.
The type of `Transaction<T>.Actions` property was changed from
`IList<T>` to `IImmutableList<T>`. The corresponding parameters on
constructors and factory methods also were changed to take
`IEnumerable<T>` instead of `IList<T>`.
- The type of `Peer.Urls` property was changed from `Uri` to `IPEndPoint`.
- Since we decided to depend on TURN ([RFC 5766]) and STUN ([RFC 5389]) to
work around NAT so that `Peer`'s endpoints don't have to be multiple,
`Peer.Urls` was renamed to `Peer.EndPoint` and its type also was changed
from `IImmutableList<Uri>` to `IPEndPoint`.
[[#120], [#123] by Yang Chun Ung, [#126], [#127]]
- `Address` and `TxId` are now serializable.
[[#99], [#124] by Qria]
- `InvalidTxException` and its subclasses became to have `TxId` property
and the corresponding constructor parameter. This can be useful when
multiple `Transaction<T>` objects are validated at once.
- Added `Address.Size` constant, which is fixed to the `Int32` 20.
- Fixed a bug that `Block<T>.Validate()` had not thrown `InvalidTxException`
even if there is any integrity error on its `Transactions`.
- `Swarm.AddPeersAsync()` was fixed so that unreachable `Peer`s are ignored.
[[#128]]

[#99]: https://github.com/planetarium/libplanet/issues/99
[#120]: https://github.com/planetarium/libplanet/issues/120
[#123]: https://github.com/planetarium/libplanet/pull/123
[#124]: https://github.com/planetarium/libplanet/pull/124
[#126]: https://github.com/planetarium/libplanet/issues/126
[#127]: https://github.com/planetarium/libplanet/pull/127
[#128]: https://github.com/planetarium/libplanet/pull/128
[RFC 5389]: https://tools.ietf.org/html/rfc5389
[RFC 5766]: https://tools.ietf.org/html/rfc5766


Version 0.1.1
@@ -24,9 +111,3 @@ Version 0.1.0
-------------

Initial release. Released on February 26, 2019.


[#120]: https://github.com/planetarium/libplanet/issues/120
[#126]: https://github.com/planetarium/libplanet/issues/126
[RFC 5389]: https://tools.ietf.org/html/rfc5389
[RFC 5766]: https://tools.ietf.org/html/rfc5766
@@ -135,8 +135,9 @@ public IActionResult getTransaction(string txIdString)
Id = tx.Id.ToString(),
Signature = tx.Signature,
Timestamp = tx.Timestamp,
Sender = tx.Sender.ToHex(),
Recipient = tx.Recipient.ToHex(),
Signer = tx.Signer.ToHex(),
UpdatedAddresses = tx.UpdatedAddresses
.Select(a => a.ToHex()).ToArray(),
Actions = tx.Actions
.Select(act => new Dictionary<string, object>
{
@@ -1,7 +1,7 @@
Libplanet.Explorer
==================

Explore your block, transaction, and address with Libplanet.Explorer.
Explore your block, transaction, and address with Libplanet.Explorer.

The goal of this project is to give you the UI of the web or
native application. But we **only provide JSON API** for the present.
@@ -40,7 +40,7 @@ the latter is the store getter class which is added on step 1.
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<ExplorerStartup<DummyAction, MyStore>>()
@@ -58,6 +58,6 @@ the creation timestamp.
difficulty, nonce, the hash of the previous block, reward beneficiary,
creation timestamp, and transaction ids. `{hashString}` is
- `/tx/{txIdString}/`: Show the details of the transaction that includes id,
signature, creation timestamp, sender address, recipient address, and actions.
signature, creation timestamp, signer address, recipient address, and actions.
- `/address/{addressIdString}/`: Show the details of address. The list of
transactions sent/received and state of it.
@@ -10,8 +10,8 @@ public class TransactionViewModel
public string Id { get; set; }
public byte[] Signature { get; set; }
public DateTimeOffset Timestamp { get; set; }
public string Sender { get; set; }
public string Recipient { get; set; }
public string Signer { get; set; }
public string[] UpdatedAddresses { get; set; }
public IEnumerable<Dictionary<string, object>> Actions { get; set; }
}
}
@@ -0,0 +1,93 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using Libplanet.Action;
using Libplanet.Crypto;
using Uno.Extensions;
using Xunit;

namespace Libplanet.Tests.Action
{
public class AccountStateDeltaImplTest
{
private readonly Address[] _addr;
private readonly IImmutableDictionary<Address, object> _states;

public AccountStateDeltaImplTest()
{
Address Addr() => new PrivateKey().PublicKey.ToAddress();

_addr = new[]
{
Addr(),
Addr(),
Addr(),
};

_states = new Dictionary<Address, object>()
{
[_addr[0]] = "a",
[_addr[1]] = "b",
}.ToImmutableDictionary();
}

[Fact]
public void CreateNullDelta()
{
IAccountStateDelta delta = new AccountStateDeltaImpl(GetState);
Assert.Empty(delta.UpdatedAddresses);
Assert.Equal("a", delta.GetState(_addr[0]));
Assert.Equal("b", delta.GetState(_addr[1]));
Assert.Null(delta.GetState(_addr[2]));
}

[Fact]
public void GetSetState()
{
IAccountStateDelta init = new AccountStateDeltaImpl(GetState);
IAccountStateDelta a = init.SetState(_addr[0], "A");
Assert.Equal("A", a.GetState(_addr[0]));
Assert.Equal("a", init.GetState(_addr[0]));
Assert.Equal("b", a.GetState(_addr[1]));
Assert.Equal("b", init.GetState(_addr[1]));
Assert.Null(a.GetState(_addr[2]));
Assert.Null(init.GetState(_addr[2]));
Assert.Equal(
new[] { _addr[0] }.ToImmutableHashSet(),
a.UpdatedAddresses
);
Assert.Empty(init.UpdatedAddresses);

IAccountStateDelta b = a.SetState(_addr[0], "z");
Assert.Equal("z", b.GetState(_addr[0]));
Assert.Equal("A", a.GetState(_addr[0]));
Assert.Equal("a", init.GetState(_addr[0]));
Assert.Equal("b", b.GetState(_addr[1]));
Assert.Equal("b", a.GetState(_addr[1]));
Assert.Null(b.GetState(_addr[2]));
Assert.Null(a.GetState(_addr[2]));
Assert.Equal(
new[] { _addr[0] }.ToImmutableHashSet(),
a.UpdatedAddresses
);
Assert.Empty(init.UpdatedAddresses);

IAccountStateDelta c = b.SetState(_addr[0], "a");
Assert.Equal("a", c.GetState(_addr[0]));
Assert.Equal("z", b.GetState(_addr[0]));
Assert.Empty(c.UpdatedAddresses);
Assert.Empty(init.UpdatedAddresses);
}

private object GetState(Address address)
{
try
{
return _states[address];
}
catch (KeyNotFoundException)
{
return null;
}
}
}
}
@@ -1,3 +1,4 @@
using System.Collections.Immutable;
using Libplanet.Action;
using Xunit;

@@ -16,15 +17,30 @@ public void RandomShouldBeDeterministic()
foreach (var (seed, expected) in testCases)
{
var context = new ActionContext(
from: new Address("21744f4f08db23e044178dafb8273aeb5ebe6644"),
to: new Address("21744f4f08db23e044178dafb8273aeb5ebe6644"),
signer: new Address("21744f4f08db23e044178dafb8273aeb5ebe6644"),
blockIndex: 1,
previousStates: new AddressStateMap(),
previousStates: new DumbAccountStateDelta(),
randomSeed: seed
);
IRandom random = context.Random;
Assert.Equal(expected, random.Next());
}
}

private class DumbAccountStateDelta : IAccountStateDelta
{
public IImmutableSet<Address> UpdatedAddresses =>
ImmutableHashSet<Address>.Empty;

public object GetState(Address address)
{
return null;
}

public IAccountStateDelta SetState(Address address, object state)
{
return this;
}
}
}
}
Oops, something went wrong.

0 comments on commit 352a783

Please sign in to comment.
You can’t perform that action at this time.