Skip to content

Commit

Permalink
Add decimals to BigDecimal constructor (neo-project#2255)
Browse files Browse the repository at this point in the history
* Add decimals

* Optimize

Co-authored-by: Erik Zhang <erik@neo.org>
  • Loading branch information
2 people authored and cloud8little committed Jan 24, 2021
1 parent 1cc57ea commit e22fc4b
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 32 deletions.
29 changes: 26 additions & 3 deletions src/neo/BigDecimal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,39 @@ public struct BigDecimal
public byte Decimals => decimals;
public int Sign => value.Sign;

/// <summary>
/// Create BigDecimal from BigInteger
/// </summary>
/// <param name="value">Value</param>
/// <param name="decimals">Decimals</param>
public BigDecimal(BigInteger value, byte decimals)
{
this.value = value;
this.decimals = decimals;
}

public BigDecimal(decimal value)
/// <summary>
/// Create BigDecimal from decimal
/// </summary>
/// <param name="value">Value</param>
public unsafe BigDecimal(decimal value)
{
this.decimals = BitConverter.GetBytes(decimal.GetBits(value)[3])[2];
this.value = new BigInteger(decimal.Multiply((Decimal)Math.Pow(10, this.decimals), value));
ReadOnlySpan<byte> buffer = new ReadOnlySpan<byte>(&value, sizeof(decimal));
this.decimals = buffer[14];
this.value = new BigInteger(decimal.Multiply((decimal)Math.Pow(10, decimals), value));
}

/// <summary>
/// Create BigDecimal from decimal
/// </summary>
/// <param name="value">Value</param>
/// <param name="decimals">Decimals</param>
public unsafe BigDecimal(decimal value, byte decimals)
{
ReadOnlySpan<byte> buffer = new ReadOnlySpan<byte>(&value, sizeof(decimal));
if (buffer[14] > decimals) throw new ArgumentException(null, nameof(value));
this.value = new BigInteger(decimal.Multiply((decimal)Math.Pow(10, decimals), value));
this.decimals = decimals;
}

public BigDecimal ChangeDecimals(byte decimals)
Expand Down
2 changes: 1 addition & 1 deletion src/neo/Wallets/Wallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public BigDecimal GetBalance(UInt160 asset_id, params UInt160[] accounts)
}
using ApplicationEngine engine = ApplicationEngine.Run(script, gas: 20000000L * accounts.Length);
if (engine.State.HasFlag(VMState.FAULT))
return new BigDecimal(0, 0);
return new BigDecimal(BigInteger.Zero, 0);
byte decimals = (byte)engine.ResultStack.Pop().GetInteger();
BigInteger amount = engine.ResultStack.Pop().GetInteger();
return new BigDecimal(amount, decimals);
Expand Down
3 changes: 2 additions & 1 deletion tests/neo.UnitTests/Ledger/UT_Blockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Neo.Wallets.NEP6;
using System;
using System.Linq;
using System.Numerics;
using System.Reflection;

namespace Neo.UnitTests.Ledger
Expand Down Expand Up @@ -119,7 +120,7 @@ private Transaction CreateValidTx(NEP6Wallet wallet, UInt160 account, uint nonce
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = account,
Value = new BigDecimal(1,8)
Value = new BigDecimal(BigInteger.One,8)
}
},
account);
Expand Down
24 changes: 12 additions & 12 deletions tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public void FeeIsMultiSigContract()
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = acc.ScriptHash,
Value = new BigDecimal(1,8)
Value = new BigDecimal(BigInteger.One,8)
}
}, acc.ScriptHash);

Expand Down Expand Up @@ -210,7 +210,7 @@ public void FeeIsSignatureContractDetailed()
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = acc.ScriptHash,
Value = new BigDecimal(1,8)
Value = new BigDecimal(BigInteger.One,8)
}
}, acc.ScriptHash);

Expand Down Expand Up @@ -318,7 +318,7 @@ public void FeeIsSignatureContract_TestScope_Global()
using (ScriptBuilder sb = new ScriptBuilder())
{
// self-transfer of 1e-8 GAS
BigInteger value = (new BigDecimal(1, 8)).Value;
BigInteger value = (new BigDecimal(BigInteger.One, 8)).Value;
sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null);
sb.Emit(OpCode.ASSERT);
script = sb.ToArray();
Expand Down Expand Up @@ -404,7 +404,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS()
using (ScriptBuilder sb = new ScriptBuilder())
{
// self-transfer of 1e-8 GAS
BigInteger value = (new BigDecimal(1, 8)).Value;
BigInteger value = (new BigDecimal(BigInteger.One, 8)).Value;
sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null);
sb.Emit(OpCode.ASSERT);
script = sb.ToArray();
Expand Down Expand Up @@ -491,7 +491,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS()
using (ScriptBuilder sb = new ScriptBuilder())
{
// self-transfer of 1e-8 GAS
System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value;
System.Numerics.BigInteger value = (new BigDecimal(BigInteger.One, 8)).Value;
sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null);
sb.Emit(OpCode.ASSERT);
script = sb.ToArray();
Expand Down Expand Up @@ -579,7 +579,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT()
using (ScriptBuilder sb = new ScriptBuilder())
{
// self-transfer of 1e-8 GAS
System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value;
System.Numerics.BigInteger value = (new BigDecimal(BigInteger.One, 8)).Value;
sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value);
sb.Emit(OpCode.ASSERT);
script = sb.ToArray();
Expand Down Expand Up @@ -631,7 +631,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS()
using (ScriptBuilder sb = new ScriptBuilder())
{
// self-transfer of 1e-8 GAS
BigInteger value = (new BigDecimal(1, 8)).Value;
BigInteger value = (new BigDecimal(BigInteger.One, 8)).Value;
sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null);
sb.Emit(OpCode.ASSERT);
script = sb.ToArray();
Expand Down Expand Up @@ -721,7 +721,7 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT()
using (ScriptBuilder sb = new ScriptBuilder())
{
// self-transfer of 1e-8 GAS
BigInteger value = (new BigDecimal(1, 8)).Value;
BigInteger value = (new BigDecimal(BigInteger.One, 8)).Value;
sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value);
sb.Emit(OpCode.ASSERT);
script = sb.ToArray();
Expand Down Expand Up @@ -984,7 +984,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default()
using (ScriptBuilder sb = new ScriptBuilder())
{
// self-transfer of 1e-8 GAS
BigInteger value = (new BigDecimal(1, 8)).Value;
BigInteger value = (new BigDecimal(BigInteger.One, 8)).Value;
sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null);
sb.Emit(OpCode.ASSERT);
script = sb.ToArray();
Expand Down Expand Up @@ -1128,7 +1128,7 @@ public void Test_VerifyStateIndependent()
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = acc.ScriptHash,
Value = new BigDecimal(1,8)
Value = new BigDecimal(BigInteger.One,8)
}
}, acc.ScriptHash);

Expand Down Expand Up @@ -1201,7 +1201,7 @@ public void Test_VerifyStateDependent()
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = acc.ScriptHash,
Value = new BigDecimal(1,8)
Value = new BigDecimal(BigInteger.One,8)
}
}, acc.ScriptHash);

Expand Down Expand Up @@ -1271,7 +1271,7 @@ public void Test_Verify()
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = acc.ScriptHash,
Value = new BigDecimal(1,8)
Value = new BigDecimal(BigInteger.One,8)
}
}, acc.ScriptHash);

Expand Down
14 changes: 7 additions & 7 deletions tests/neo.UnitTests/UT_BigDecimal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,23 @@ public void TestBigDecimalConstructor()
value.Value.Should().Be(new BigInteger(-10));
value.Decimals.Should().Be(0);

value = new BigDecimal(123.456789M);
value = new BigDecimal(123.456789M, 6);
value.Value.Should().Be(new BigInteger(123456789));
value.Decimals.Should().Be(6);

value = new BigDecimal(-123.45M);
value.Value.Should().Be(new BigInteger(-12345));
value.Decimals.Should().Be(2);
value = new BigDecimal(-123.45M, 3);
value.Value.Should().Be(new BigInteger(-123450));
value.Decimals.Should().Be(3);

value = new BigDecimal(123.45M);
value = new BigDecimal(123.45M, 2);
value.Value.Should().Be(new BigInteger(12345));
value.Decimals.Should().Be(2);

value = new BigDecimal(123M);
value = new BigDecimal(123M, 0);
value.Value.Should().Be(new BigInteger(123));
value.Decimals.Should().Be(0);

value = new BigDecimal(0M);
value = new BigDecimal(0M, 0);
value.Value.Should().Be(new BigInteger(0));
value.Decimals.Should().Be(0);
}
Expand Down
17 changes: 9 additions & 8 deletions tests/neo.UnitTests/Wallets/UT_Wallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Neo.Wallets;
using System;
using System.Collections.Generic;
using System.Numerics;

namespace Neo.UnitTests.Wallets
{
Expand Down Expand Up @@ -206,7 +207,7 @@ public void TestGetAvailable()
entry.GetInteroperable<AccountState>().Balance = 10000 * NativeContract.GAS.Factor;
snapshot.Commit();

wallet.GetAvailable(NativeContract.GAS.Hash).Should().Be(new BigDecimal(1000000000000, 8));
wallet.GetAvailable(NativeContract.GAS.Hash).Should().Be(new BigDecimal(new BigInteger(1000000000000M), 8));

entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState()));
entry.GetInteroperable<AccountState>().Balance = 0;
Expand All @@ -228,8 +229,8 @@ public void TestGetBalance()
entry.GetInteroperable<AccountState>().Balance = 10000 * NativeContract.GAS.Factor;
snapshot.Commit();

wallet.GetBalance(UInt160.Zero, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(0, 0));
wallet.GetBalance(NativeContract.GAS.Hash, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(1000000000000, 8));
wallet.GetBalance(UInt160.Zero, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(BigInteger.Zero, 0));
wallet.GetBalance(NativeContract.GAS.Hash, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(new BigInteger(1000000000000M), 8));

entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState()));
entry.GetInteroperable<AccountState>().Balance = 0;
Expand Down Expand Up @@ -294,7 +295,7 @@ public void TestMakeTransaction1()
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = account.ScriptHash,
Value = new BigDecimal(1,8),
Value = new BigDecimal(BigInteger.One,8),
Data = "Dec 12th"
}
}, UInt160.Zero);
Expand All @@ -306,7 +307,7 @@ public void TestMakeTransaction1()
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = account.ScriptHash,
Value = new BigDecimal(1,8),
Value = new BigDecimal(BigInteger.One,8),
Data = "Dec 12th"
}
}, account.ScriptHash);
Expand All @@ -318,7 +319,7 @@ public void TestMakeTransaction1()
{
AssetId = UInt160.Zero,
ScriptHash = account.ScriptHash,
Value = new BigDecimal(1,8),
Value = new BigDecimal(BigInteger.One,8),
Data = "Dec 12th"
}
}, account.ScriptHash);
Expand All @@ -342,7 +343,7 @@ public void TestMakeTransaction1()
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = account.ScriptHash,
Value = new BigDecimal(1,8)
Value = new BigDecimal(BigInteger.One,8)
}
});
tx.Should().NotBeNull();
Expand All @@ -353,7 +354,7 @@ public void TestMakeTransaction1()
{
AssetId = NativeContract.NEO.Hash,
ScriptHash = account.ScriptHash,
Value = new BigDecimal(1,8),
Value = new BigDecimal(BigInteger.One,8),
Data = "Dec 12th"
}
});
Expand Down

0 comments on commit e22fc4b

Please sign in to comment.