Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: treat mead as state #2665

Draft
wants to merge 1 commit into
base: feature/dpos-sloth
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 37 additions & 15 deletions Lib9c/Action/DPoS/Sys/Mortgage.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Collections.Immutable;
using System;
using System.Linq;
using Bencodex.Types;
using Lib9c;
using Libplanet.Action;
using Libplanet.Action.State;
using Libplanet.Types.Assets;
using Nekoyume.Exceptions;
using Nekoyume.Module;

namespace Nekoyume.Action.DPoS.Sys
Expand Down Expand Up @@ -33,25 +35,45 @@
public override IWorld Execute(IActionContext context)
{
var state = context.PreviousState;
if (context.MaxGasPrice is not { } realGasPrice)
if (!(context.TxId is { } txId &&
context.Txs.Any(tx => tx.Id.Equals(txId))))
{
return state;
}

var balance = state.GetBalance(context.Signer, realGasPrice.Currency);
if (balance < realGasPrice * context.GasLimit())
var tx = context.Txs.First(tx => tx.Id.Equals(context.TxId));
switch ((tx.MaxGasPrice, tx.GasLimit))
{
var msg =
$"The account {context.Signer}'s balance of {realGasPrice.Currency} is " +
"insufficient to pay gas fee: " +
$"{balance} < {realGasPrice * context.GasLimit()}.";
throw new InsufficientBalanceException(msg, context.Signer, balance);
}
case (null, null):
return state.SetTxGasInfo(null, null);
case (not null, null): case (null, not null):
throw new ArgumentException("Pairity of null-ness of price and gas limit must match.");
case ({ Sign: > 0 } realGasPrice, { } gasLimit):
if (gasLimit < 0)
{
throw new GasLimitNegativeException();

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-and-test (Release)

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-and-test (Release)

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-js

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-js

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-js

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-js

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-and-test (Release)

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-and-test (Release)

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'

Check failure on line 54 in Lib9c/Action/DPoS/Sys/Mortgage.cs

View workflow job for this annotation

GitHub Actions / build-for-unity

'GasLimitNegativeException' is an ambiguous reference between 'Nekoyume.Exceptions.GasLimitNegativeException' and 'Libplanet.Action.GasLimitNegativeException'
}
state = state.SetTxGasInfo(realGasPrice, gasLimit);

var balance = state.GetBalance(context.Signer, Currencies.Mead);
if (balance < realGasPrice * gasLimit)
{
var msg =
$"The account {context.Signer}'s balance of {realGasPrice.Currency} is " +
"insufficient to pay gas fee: " +
$"{balance} < {realGasPrice * gasLimit}.";
throw new InsufficientBalanceException(msg, context.Signer, balance);
}

return state.BurnAsset(
context,
context.Signer,
realGasPrice * context.GasLimit());
return state.TransferAsset(
context,
context.Signer,
Addresses.MeadPool,
realGasPrice * gasLimit);
default:
// Gas price is negative.
throw new ArgumentException("Sign of gas price must be positive.");
}
}
}
}
19 changes: 6 additions & 13 deletions Lib9c/Action/DPoS/Sys/Refund.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Immutable;
using Bencodex.Types;
using Bencodex.Types;
using Libplanet.Action;
using Libplanet.Action.State;
using Nekoyume.Module;
Expand Down Expand Up @@ -32,20 +31,14 @@ public override void LoadPlainValue(IValue plainValue)
public override IWorld Execute(IActionContext context)
{
var world = context.PreviousState;
if (context.MaxGasPrice is not { Sign: > 0 } realGasPrice)
{
return world;
}
var remainder = world.RemainingGas();
world = world.CleanUpGasInfo();

if (context.GasLimit() - context.GasUsed() <= 0)
{
return world;
}

return world.MintAsset(
return world.TransferAsset(
context,
Addresses.MeadPool,
context.Signer,
(context.GasLimit() - context.GasUsed()) * realGasPrice);
remainder);
}
}
}
13 changes: 5 additions & 8 deletions Lib9c/Action/DPoS/Sys/Reward.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Libplanet.Action;
using Libplanet.Action.State;
using Nekoyume.Action.DPoS.Misc;
using Nekoyume.Module;

namespace Nekoyume.Action.DPoS.Sys
{
Expand Down Expand Up @@ -31,19 +32,15 @@ public override void LoadPlainValue(IValue plainValue)
public override IWorld Execute(IActionContext context)
{
var world = context.PreviousState;
if (context.MaxGasPrice is not { Sign: > 0 } realGasPrice)
var gasPriceUsed = world.GasPriceUsed();
if (gasPriceUsed is not { } reward)
{
return world;
}

if (context.GasUsed() <= 0)
{
return world;
}

var reward = realGasPrice * context.GasUsed();
return world.MintAsset(
return world.TransferAsset(
context,
Addresses.MeadPool,
ReservedAddress.RewardPool,
reward);
}
Expand Down
2 changes: 2 additions & 0 deletions Lib9c/Addresses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public static class Addresses
public static readonly Address ActionPoint = new Address("0000000000000000000000000000000000000021");
public static readonly Address RuneState = new Address("0000000000000000000000000000000000000022");

public static readonly Address MeadPool = new Address("0000000000000000000000000000000000100000");

public static Address GetSheetAddress<T>() where T : ISheet => GetSheetAddress(typeof(T).Name);

public static Address GetSheetAddress(string sheetName) => TableSheet.Derive(sheetName);
Expand Down
23 changes: 23 additions & 0 deletions Lib9c/Exceptions/GasLimitExceededException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Globalization;

namespace Nekoyume.Exceptions
{
[Serializable]
public sealed class GasLimitExceededException : Exception
{
public GasLimitExceededException(long limit, long used)
: base($"Gas usage cannot be exceed limit. Gas limit is " +
$"{limit.ToString(CultureInfo.InvariantCulture)} but used gas is " +
$"{used.ToString(CultureInfo.InvariantCulture)}. " +
$"Please ensure that the gas limit is not exceeded.")
{
Limit = limit;
Used = used;
}

public long Limit { get; }

public long Used { get; }
}
}
14 changes: 14 additions & 0 deletions Lib9c/Exceptions/GasLimitNegativeException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace Nekoyume.Exceptions
{
[Serializable]
public class GasLimitNegativeException : Exception
{
public GasLimitNegativeException()
: base($"Gas Limit cannot be negative. " +
$"Please set the Gas Limit to a non-negative value.")
{
}
}
}
14 changes: 14 additions & 0 deletions Lib9c/Exceptions/GasUseNegativeException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace Nekoyume.Exceptions
{
[Serializable]
public class GasUseNegativeException : Exception
{
public GasUseNegativeException()
: base($"Cannot use negative value gas. " +
$"Please use gas with a non-negative value.")
{
}
}
}
93 changes: 93 additions & 0 deletions Lib9c/Module/MeadModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using Bencodex.Types;
using Lib9c;
using Libplanet.Action.State;
using Libplanet.Crypto;
using Libplanet.Types.Assets;
using Nekoyume.Exceptions;

namespace Nekoyume.Module
{
public static class MeadModule
{
private static readonly Address RealGasPriceAddress = new Address("0000000000000000000000000000000000000000");
private static readonly Address GasLimitAddress = new Address("0000000000000000000000000000000000000001");
private static readonly Address GasUsedAddress = new Address("0000000000000000000000000000000000000002");

public static IWorld SetTxGasInfo(this IWorld world, FungibleAssetValue? realGasPrice, long? gasLimit)
{
var account = world.GetAccount(Addresses.MeadPool);
account = account.SetState(RealGasPriceAddress, realGasPrice?.Serialize() ?? Null.Value);
account = account.SetState(GasLimitAddress, gasLimit is null ? Null.Value : (Integer)gasLimit);
account = account.SetState(GasUsedAddress, (Integer)0);
return world.SetAccount(Addresses.MeadPool, account);
}

public static IWorld UseGas(this IWorld world, long gas)
{
if (gas < 0)
{
throw new GasUseNegativeException();
}

var account = world.GetAccount(Addresses.MeadPool);
if (account.GetState(GasLimitAddress) is not Integer gasLimit ||
account.GetState(GasUsedAddress) is not Integer gasUsed)
{
// Bypass if the gas limit is not set.
return world;
}

long newGasUsed = 0;
try
{
newGasUsed = checked(gasUsed + gas);
}
catch (System.OverflowException)
{
throw new GasLimitExceededException(gasLimit, gasUsed + gas);
}

if (newGasUsed > gasLimit)
{
throw new GasLimitExceededException(gasLimit, newGasUsed);
}

gasUsed = newGasUsed;
account = account.SetState(GasUsedAddress, gasUsed);
return world.SetAccount(Addresses.MeadPool, account);
}

public static FungibleAssetValue? GasPriceUsed(this IWorldState worldState)
{
var account = worldState.GetAccountState(Addresses.MeadPool);
if (account.GetState(RealGasPriceAddress) is not List realGasPriceRaw ||
account.GetState(GasUsedAddress) is not Integer gasUsed)
{
// Bypass if the gas limit is not set.
return null;
}

if (gasUsed <= 0)
{
return null;
}

var realGasPrice = new FungibleAssetValue(realGasPriceRaw);
return realGasPrice * gasUsed;
}

public static FungibleAssetValue RemainingGas(this IWorldState worldState)
{
return worldState.GetBalance(Addresses.MeadPool, Currencies.Mead);
}

public static IWorld CleanUpGasInfo(this IWorld world)
{
var account = world.GetAccount(Addresses.MeadPool);
account = account.RemoveState(RealGasPriceAddress);
account = account.RemoveState(GasLimitAddress);
account = account.RemoveState(GasUsedAddress);
return world.SetAccount(Addresses.MeadPool, account);
}
}
}
Loading