Skip to content

Commit

Permalink
feat: add dpos related actions
Browse files Browse the repository at this point in the history
  • Loading branch information
limebell committed Mar 15, 2024
1 parent c5e4eb3 commit 12ab1d2
Show file tree
Hide file tree
Showing 55 changed files with 4,213 additions and 0 deletions.
21 changes: 21 additions & 0 deletions Lib9c.DPoS/Action/DPoSModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Bencodex.Types;
using Lib9c.DPoS.Misc;
using Libplanet.Action.State;
using Libplanet.Crypto;

namespace Lib9c.DPoS.Action;

Check failure on line 6 in Lib9c.DPoS/Action/DPoSModule.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

Feature 'file-scoped namespace' is not available in C# 8.0. Please use language version 10.0 or greater.

Check failure on line 6 in Lib9c.DPoS/Action/DPoSModule.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

Feature 'file-scoped namespace' is not available in C# 8.0. Please use language version 10.0 or greater.

public static class DPoSModule
{
public static IValue? GetDPoSState(this IWorld world, Address address)
{
return world.GetAccount(ReservedAddress.DPoSAccountAddress).GetState(address);
}

public static IWorld SetDPoSState(this IWorld world, Address address, IValue value)
{
var account = world.GetAccount(ReservedAddress.DPoSAccountAddress);
account = account.SetState(address, value);
return world.SetAccount(ReservedAddress.DPoSAccountAddress, account);
}
}
45 changes: 45 additions & 0 deletions Lib9c.DPoS/Action/PoSAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Bencodex.Types;
using Lib9c.DPoS.Control;
using Lib9c.DPoS.Model;
using Libplanet.Action;
using Libplanet.Action.State;

namespace Lib9c.DPoS.Action
{
/// <summary>
/// A block action for DPoS that updates <see cref="ValidatorSet"/>.
/// </summary>
public sealed class PoSAction : IAction
{
/// <summary>
/// Creates a new instance of <see cref="PoSAction"/>.
/// </summary>
public PoSAction()
{
}

/// <inheritdoc cref="IAction.PlainValue"/>
public IValue PlainValue => new Bencodex.Types.Boolean(true);

/// <inheritdoc cref="IAction.LoadPlainValue(IValue)"/>
public void LoadPlainValue(IValue plainValue)
{
// Method intentionally left empty.
}

/// <inheritdoc cref="IAction.Execute(IActionContext)"/>
public IWorld Execute(IActionContext context)
{
IActionContext ctx = context;
var state = ctx.PreviousState;

// if (ctx.Rehearsal)
// Rehearsal mode is not implemented
state = ValidatorSetCtrl.Update(state, ctx.BlockIndex);

state = AllocateReward.Execute(
state, ctx, ctx.NativeTokens, ctx.LastCommit?.Votes, ctx.Miner);
return state;
}
}
}
77 changes: 77 additions & 0 deletions Lib9c.DPoS/Action/Sys/CancelUndelegation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using Bencodex.Types;
using Lib9c.DPoS.Control;
using Lib9c.DPoS.Model;
using Lib9c.DPoS.Util;
using Libplanet.Action;
using Libplanet.Action.State;
using Libplanet.Crypto;
using Libplanet.Types.Assets;

namespace Lib9c.DPoS.Action.Sys
{
/// <summary>
/// A system action for DPoS that cancel <see cref="Undelegate"/> specified
/// <see cref="Amount"/> of tokens to a given <see cref="Validator"/>.
/// </summary>
public sealed class CancelUndelegation : IAction
{
/// <summary>
/// Creates a new instance of <see cref="CancelUndelegation"/> action.
/// </summary>
/// <param name="validator">The <see cref="amount"/> of the validator
/// to delegate tokens.</param>
/// <param name="amount">The amount of the asset to be delegated.</param>
public CancelUndelegation(Address validator, FungibleAssetValue amount)
{
Validator = validator;
Amount = amount;
}

internal CancelUndelegation()
{
// Used only for deserialization. See also class Libplanet.Action.Sys.Registry.
}

/// <summary>
/// The <see cref="Address"/> of the validator
/// to cancel the <see cref="Undelegate"/> and <see cref="Delegate"/>.
/// </summary>
public Address Validator { get; set; }

/// <summary>
/// The amount of the asset to be delegated.
/// </summary>
public FungibleAssetValue Amount { get; set; }

/// <inheritdoc cref="IAction.PlainValue"/>
public IValue PlainValue => Bencodex.Types.Dictionary.Empty
.Add("validator", Validator.Serialize())
.Add("amount", Amount.Serialize());

/// <inheritdoc cref="IAction.LoadPlainValue(IValue)"/>
public void LoadPlainValue(IValue plainValue)
{
var dict = (Bencodex.Types.Dictionary)plainValue;
Validator = dict["validator"].ToAddress();
Amount = dict["amount"].ToFungibleAssetValue();
}

/// <inheritdoc cref="IAction.Execute(IActionContext)"/>
public IWorld Execute(IActionContext context)
{
IActionContext ctx = context;
var states = ctx.PreviousState;

// if (ctx.Rehearsal)
// Rehearsal mode is not implemented
states = UndelegateCtrl.Cancel(
states,
ctx,
Undelegation.DeriveAddress(ctx.Signer, Validator),
Amount,
ctx.NativeTokens);

return states;
}
}
}
68 changes: 68 additions & 0 deletions Lib9c.DPoS/Action/Sys/Delegate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Bencodex.Types;
using Lib9c.DPoS.Control;
using Lib9c.DPoS.Util;
using Libplanet.Action;
using Libplanet.Action.State;
using Libplanet.Crypto;
using Libplanet.Types.Assets;

namespace Lib9c.DPoS.Action.Sys
{
/// <summary>
/// A system action for DPoS that <see cref="Delegate"/> specified <see cref="Amount"/>
/// of tokens to a given <see cref="Validator"/>.
/// </summary>
public sealed class Delegate : IAction
{
/// <summary>
/// Creates a new instance of <see cref="Delegate"/> action.
/// </summary>
/// <param name="validator">The <see cref="Address"/> of the validator
/// to delegate tokens.</param>
/// <param name="amount">The amount of the asset to be delegated.</param>
public Delegate(Address validator, FungibleAssetValue amount)
{
Validator = validator;
Amount = amount;
}

internal Delegate()
{
// Used only for deserialization. See also class Libplanet.Action.Sys.Registry.
}

/// <summary>
/// The <see cref="Address"/> of the validator to <see cref="Delegate"/>.
/// </summary>
public Address Validator { get; set; }

public FungibleAssetValue Amount { get; set; }

/// <inheritdoc cref="IAction.PlainValue"/>
public IValue PlainValue => Bencodex.Types.Dictionary.Empty
.Add("validator", Validator.Serialize())
.Add("amount", Amount.Serialize());

/// <inheritdoc cref="IAction.LoadPlainValue(IValue)"/>
public void LoadPlainValue(IValue plainValue)
{
var dict = (Bencodex.Types.Dictionary)plainValue;
Validator = dict["validator"].ToAddress();
Amount = dict["amount"].ToFungibleAssetValue();
}

/// <inheritdoc cref="IAction.Execute(IActionContext)"/>
public IWorld Execute(IActionContext context)
{
IActionContext ctx = context;
var states = ctx.PreviousState;

// if (ctx.Rehearsal)
// Rehearsal mode is not implemented
states = DelegateCtrl.Execute(
states, ctx, ctx.Signer, Validator, Amount, ctx.NativeTokens);

return states;
}
}
}
77 changes: 77 additions & 0 deletions Lib9c.DPoS/Action/Sys/PromoteValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using Bencodex.Types;
using Lib9c.DPoS.Control;
using Lib9c.DPoS.Exception;
using Lib9c.DPoS.Util;
using Libplanet.Action;
using Libplanet.Action.State;
using Libplanet.Crypto;
using Libplanet.Types.Assets;

namespace Lib9c.DPoS.Action.Sys
{
/// <summary>
/// A system action for DPoS that promotes non-validator node to a validator.
/// </summary>
public sealed class PromoteValidator : IAction
{
/// <summary>
/// Create a new instance of <see cref="PromoteValidator"/> action.
/// </summary>
/// <param name="validator">The <see cref="PublicKey"/> of the target
/// to promote validator.</param>
/// <param name="amount">The amount of the asset to be initialize delegation.</param>
public PromoteValidator(PublicKey validator, FungibleAssetValue amount)
{
Validator = validator;
Amount = amount;
}

internal PromoteValidator()
{
// Used only for deserialization. See also class Libplanet.Action.Sys.Registry.
// FIXME: do not fill ambiguous validator field.
// Suggestion: https://gist.github.com/riemannulus/7405e0d361364c6afa0ab433905ae81c
Validator = new PrivateKey().PublicKey;
}

/// <summary>
/// The <see cref="PublicKey"/> of the target promoting to a validator.
/// </summary>
public PublicKey Validator { get; set; }

/// <summary>
/// The amount of the asset to be initially delegated.
/// </summary>
public FungibleAssetValue Amount { get; set; }

/// <inheritdoc cref="IAction.PlainValue"/>
public IValue PlainValue => Bencodex.Types.Dictionary.Empty
.Add("validator", Validator.Serialize())
.Add("amount", Amount.Serialize());

/// <inheritdoc cref="IAction.LoadPlainValue(IValue)"/>
public void LoadPlainValue(IValue plainValue)
{
var dict = (Bencodex.Types.Dictionary)plainValue;
Validator = dict["validator"].ToPublicKey();
Amount = dict["amount"].ToFungibleAssetValue();
}

/// <inheritdoc cref="IAction.Execute(IActionContext)"/>
public IWorld Execute(IActionContext context)
{
IActionContext ctx = context;
if (!ctx.Signer.Equals(Validator.Address))
{
throw new PublicKeyAddressMatchingException(ctx.Signer, Validator);
}

var states = ctx.PreviousState;

states = ValidatorCtrl.Create(
states, ctx.Signer, Validator, Amount, ctx.NativeTokens, ctx.BlockIndex);

return states;
}
}
}
86 changes: 86 additions & 0 deletions Lib9c.DPoS/Action/Sys/Redelegate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using Bencodex.Types;
using Lib9c.DPoS.Control;
using Lib9c.DPoS.Util;
using Libplanet.Action;
using Libplanet.Action.State;
using Libplanet.Crypto;
using Libplanet.Types.Assets;

namespace Lib9c.DPoS.Action.Sys
{
/// <summary>
/// A system action for DPoS that <see cref="Redelegate"/> specified <see cref="ShareAmount"/>
/// of shared tokens to <see cref="DstValidator"/> from <see cref="SrcValidator"/>.
/// </summary>
public sealed class Redelegate : IAction
{
/// <summary>
/// Creates a new instance of <see cref="Redelegate"/> action.
/// </summary>
/// <param name="src">The <see cref="dst"/> of the validator that
/// delegated previously.</param>
/// <param name="dst">The <see cref="amount"/> of the validator
/// to be newly delegated.</param>
/// <param name="amount">The amount of the shared asset to be re-delegated.</param>
public Redelegate(Address src, Address dst, FungibleAssetValue amount)
{
SrcValidator = src;
DstValidator = dst;
ShareAmount = amount;
}

internal Redelegate()
{
// Used only for deserialization. See also class Libplanet.Action.Sys.Registry.
}

/// <summary>
/// The <see cref="Address"/> of the validator that was previously delegated to.
/// </summary>
public Address SrcValidator { get; set; }

/// <summary>
/// The <see cref="Address"/> of the validator as a destination of moved voting power.
/// </summary>
public Address DstValidator { get; set; }

/// <summary>
/// The amount of the shared token to move delegation.
/// </summary>
public FungibleAssetValue ShareAmount { get; set; }

/// <inheritdoc cref="IAction.PlainValue"/>
public IValue PlainValue => Bencodex.Types.Dictionary.Empty
.Add("src", SrcValidator.Serialize())
.Add("dst", DstValidator.Serialize())
.Add("amount", ShareAmount.Serialize());

/// <inheritdoc cref="IAction.LoadPlainValue(IValue)"/>
public void LoadPlainValue(IValue plainValue)
{
var dict = (Bencodex.Types.Dictionary)plainValue;
SrcValidator = dict["src"].ToAddress();
DstValidator = dict["dst"].ToAddress();
ShareAmount = dict["amount"].ToFungibleAssetValue();
}

/// <inheritdoc cref="IAction.Execute(IActionContext)"/>
public IWorld Execute(IActionContext context)
{
IActionContext ctx = context;
var states = ctx.PreviousState;

states = RedelegateCtrl.Execute(
states,
ctx,
ctx.Signer,
SrcValidator,
DstValidator,
ShareAmount,
ctx.NativeTokens,
ctx.BlockIndex);

return states;
}
}
}
Loading

0 comments on commit 12ab1d2

Please sign in to comment.