From 84cf52093ffc631c6ce89effc4d4dc78dc33412b Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 21 Jan 2021 09:31:10 +0100 Subject: [PATCH 1/2] Add decimals --- src/neo/BigDecimal.cs | 14 ++++++++++- src/neo/Wallets/Wallet.cs | 2 +- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 3 ++- .../Network/P2P/Payloads/UT_Transaction.cs | 24 +++++++++---------- tests/neo.UnitTests/UT_BigDecimal.cs | 14 +++++------ tests/neo.UnitTests/Wallets/UT_Wallet.cs | 17 ++++++------- 6 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/neo/BigDecimal.cs b/src/neo/BigDecimal.cs index ad1948f6bc..1aeb1b586d 100644 --- a/src/neo/BigDecimal.cs +++ b/src/neo/BigDecimal.cs @@ -12,16 +12,28 @@ public struct BigDecimal public byte Decimals => decimals; public int Sign => value.Sign; + /// + /// Create BigDecimal from BigInteger + /// + /// Value + /// Decimals public BigDecimal(BigInteger value, byte decimals) { this.value = value; this.decimals = decimals; } - public BigDecimal(decimal value) + /// + /// Create BigDecimal from decimal + /// + /// Value + /// Change decimals to + public BigDecimal(decimal value, byte changeDecimals) { this.decimals = BitConverter.GetBytes(decimal.GetBits(value)[3])[2]; this.value = new BigInteger(decimal.Multiply((Decimal)Math.Pow(10, this.decimals), value)); + this.value = this.ChangeDecimals(changeDecimals).value; + this.decimals = changeDecimals; } public BigDecimal ChangeDecimals(byte decimals) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index d5c9ef0a13..a0dc5c4945 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -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); diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index c2051f40d4..40ba38c868 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -11,6 +11,7 @@ using Neo.Wallets.NEP6; using System; using System.Linq; +using System.Numerics; using System.Reflection; namespace Neo.UnitTests.Ledger @@ -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); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index bd949063d3..77d4d5f750 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -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); @@ -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); @@ -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(); @@ -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(); @@ -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(); @@ -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(); @@ -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(); @@ -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(); @@ -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(); @@ -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); @@ -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); @@ -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); diff --git a/tests/neo.UnitTests/UT_BigDecimal.cs b/tests/neo.UnitTests/UT_BigDecimal.cs index ccd147427a..8ea5f05054 100644 --- a/tests/neo.UnitTests/UT_BigDecimal.cs +++ b/tests/neo.UnitTests/UT_BigDecimal.cs @@ -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); } diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index 219bd62d25..75d38c25a1 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -9,6 +9,7 @@ using Neo.Wallets; using System; using System.Collections.Generic; +using System.Numerics; namespace Neo.UnitTests.Wallets { @@ -206,7 +207,7 @@ public void TestGetAvailable() entry.GetInteroperable().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().Balance = 0; @@ -228,8 +229,8 @@ public void TestGetBalance() entry.GetInteroperable().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().Balance = 0; @@ -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); @@ -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); @@ -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); @@ -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(); @@ -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" } }); From 1b59b604270e5b7bff4ea7a6e87bc27a2cc367ea Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 21 Jan 2021 18:14:22 +0800 Subject: [PATCH 2/2] Optimize --- src/neo/BigDecimal.cs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/neo/BigDecimal.cs b/src/neo/BigDecimal.cs index 1aeb1b586d..45e2ae770c 100644 --- a/src/neo/BigDecimal.cs +++ b/src/neo/BigDecimal.cs @@ -27,13 +27,24 @@ public BigDecimal(BigInteger value, byte decimals) /// Create BigDecimal from decimal /// /// Value - /// Change decimals to - public BigDecimal(decimal value, byte changeDecimals) + 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)); - this.value = this.ChangeDecimals(changeDecimals).value; - this.decimals = changeDecimals; + ReadOnlySpan buffer = new ReadOnlySpan(&value, sizeof(decimal)); + this.decimals = buffer[14]; + this.value = new BigInteger(decimal.Multiply((decimal)Math.Pow(10, decimals), value)); + } + + /// + /// Create BigDecimal from decimal + /// + /// Value + /// Decimals + public unsafe BigDecimal(decimal value, byte decimals) + { + ReadOnlySpan buffer = new ReadOnlySpan(&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)