From 975fe9a90f476ac245b326b326f7aee528194304 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 20 May 2019 03:15:59 +0800 Subject: [PATCH] Update dependency: Neo v3.0.0-CI00044 (#98) --- ApplicationLogs/ApplicationLogs.csproj | 2 +- ApplicationLogs/LogReader.cs | 40 +- ApplicationLogs/Settings.cs | 3 +- CoreMetrics/CoreMetrics.csproj | 2 +- ImportBlocks/ImportBlocks.csproj | 2 +- RpcNep5Tracker/Nep5Balance.cs | 15 +- RpcNep5Tracker/Nep5Transfer.cs | 15 +- RpcNep5Tracker/RpcNep5Tracker.cs | 19 +- RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- RpcSecurity/RpcSecurity.csproj | 2 +- .../RpcSystemAssetTracker.csproj | 17 - .../RpcSystemAssetTracker/config.json | 7 - .../RpcSystemAssetTrackerPlugin.cs | 426 ------------------ .../UserSystemAssetCoinOutputs.cs | 79 ---- .../UserSystemAssetCoinOutputsKey.cs | 81 ---- RpcWallet/RpcWallet.cs | 193 ++------ RpcWallet/RpcWallet.csproj | 2 +- RpcWallet/Settings.cs | 5 +- SimplePolicy.UnitTests/UT_SimplePolicy.cs | 241 ++-------- SimplePolicy/Settings.cs | 21 +- SimplePolicy/SimplePolicy.csproj | 2 +- SimplePolicy/SimplePolicy/config.json | 4 - SimplePolicy/SimplePolicyPlugin.cs | 16 +- StatesDumper/StatesDumper.csproj | 2 +- neo-plugins.sln | 7 +- 25 files changed, 135 insertions(+), 1070 deletions(-) delete mode 100644 RpcSystemAssetTracker/RpcSystemAssetTracker.csproj delete mode 100644 RpcSystemAssetTracker/RpcSystemAssetTracker/config.json delete mode 100644 RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs delete mode 100644 RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs delete mode 100644 RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index c2b8d3673..ca2946f4e 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -14,7 +14,7 @@ - + diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index 0ee121c5e..c316659d3 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -53,36 +53,30 @@ public void OnPersist(Snapshot snapshot, IReadOnlyList + json["trigger"] = appExec.Trigger; + json["vmstate"] = appExec.VMState; + json["gas_consumed"] = appExec.GasConsumed.ToString(); + try { - JObject execution = new JObject(); - execution["trigger"] = p.Trigger; - execution["contract"] = p.ScriptHash.ToString(); - execution["vmstate"] = p.VMState; - execution["gas_consumed"] = p.GasConsumed.ToString(); + json["stack"] = appExec.Stack.Select(q => q.ToParameter().ToJson()).ToArray(); + } + catch (InvalidOperationException) + { + json["stack"] = "error: recursive reference"; + } + json["notifications"] = appExec.Notifications.Select(q => + { + JObject notification = new JObject(); + notification["contract"] = q.ScriptHash.ToString(); try { - execution["stack"] = p.Stack.Select(q => q.ToParameter().ToJson()).ToArray(); + notification["state"] = q.State.ToParameter().ToJson(); } catch (InvalidOperationException) { - execution["stack"] = "error: recursive reference"; + notification["state"] = "error: recursive reference"; } - execution["notifications"] = p.Notifications.Select(q => - { - JObject notification = new JObject(); - notification["contract"] = q.ScriptHash.ToString(); - try - { - notification["state"] = q.State.ToParameter().ToJson(); - } - catch (InvalidOperationException) - { - notification["state"] = "error: recursive reference"; - } - return notification; - }).ToArray(); - return execution; + return notification; }).ToArray(); writeBatch.Put(appExec.Transaction.Hash.ToArray(), json.ToString()); } diff --git a/ApplicationLogs/Settings.cs b/ApplicationLogs/Settings.cs index 234972e7c..82a501e90 100644 --- a/ApplicationLogs/Settings.cs +++ b/ApplicationLogs/Settings.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Configuration; -using Neo.Network.P2P; namespace Neo.Plugins { @@ -11,7 +10,7 @@ internal class Settings private Settings(IConfigurationSection section) { - this.Path = string.Format(section.GetSection("Path").Value, Message.Magic.ToString("X8")); + this.Path = string.Format(section.GetSection("Path").Value, ProtocolSettings.Default.Magic.ToString("X8")); } public static void Load(IConfigurationSection section) diff --git a/CoreMetrics/CoreMetrics.csproj b/CoreMetrics/CoreMetrics.csproj index 01e53fe4e..91bb46e49 100644 --- a/CoreMetrics/CoreMetrics.csproj +++ b/CoreMetrics/CoreMetrics.csproj @@ -7,7 +7,7 @@ - + diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 6584133f0..56a2d5578 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -14,7 +14,7 @@ - + diff --git a/RpcNep5Tracker/Nep5Balance.cs b/RpcNep5Tracker/Nep5Balance.cs index 304028d08..c848879f5 100644 --- a/RpcNep5Tracker/Nep5Balance.cs +++ b/RpcNep5Tracker/Nep5Balance.cs @@ -1,32 +1,29 @@ using System.IO; using System.Numerics; using Neo.IO; -using Neo.Ledger; namespace Neo.Plugins { - public class Nep5Balance : StateBase, ICloneable + public class Nep5Balance : ICloneable, ISerializable { public BigInteger Balance; public uint LastUpdatedBlock; - public override int Size => base.Size + Balance.ToByteArray().GetVarSize() + sizeof(uint); + int ISerializable.Size => Balance.ToByteArray().GetVarSize() + sizeof(uint); - public override void Serialize(BinaryWriter writer) + void ISerializable.Serialize(BinaryWriter writer) { - base.Serialize(writer); writer.WriteVarBytes(Balance.ToByteArray()); writer.Write(LastUpdatedBlock); } - public override void Deserialize(BinaryReader reader) + void ISerializable.Deserialize(BinaryReader reader) { - base.Deserialize(reader); Balance = new BigInteger(reader.ReadVarBytes(512)); LastUpdatedBlock = reader.ReadUInt32(); } - public Nep5Balance Clone() + Nep5Balance ICloneable.Clone() { return new Nep5Balance { @@ -41,4 +38,4 @@ public void FromReplica(Nep5Balance replica) LastUpdatedBlock = replica.LastUpdatedBlock; } } -} \ No newline at end of file +} diff --git a/RpcNep5Tracker/Nep5Transfer.cs b/RpcNep5Tracker/Nep5Transfer.cs index 7ddf8c54a..9c4b2307b 100644 --- a/RpcNep5Tracker/Nep5Transfer.cs +++ b/RpcNep5Tracker/Nep5Transfer.cs @@ -1,38 +1,35 @@ using System.IO; using System.Numerics; using Neo.IO; -using Neo.Ledger; namespace Neo.Plugins { - public class Nep5Transfer : StateBase, ICloneable + public class Nep5Transfer : ICloneable, ISerializable { public UInt160 UserScriptHash; public uint BlockIndex; public UInt256 TxHash; public BigInteger Amount; - public override int Size => base.Size + 20 + sizeof(uint) + 32 + Amount.ToByteArray().GetVarSize(); + int ISerializable.Size => 20 + sizeof(uint) + 32 + Amount.ToByteArray().GetVarSize(); - public override void Serialize(BinaryWriter writer) + void ISerializable.Serialize(BinaryWriter writer) { - base.Serialize(writer); writer.Write(UserScriptHash); writer.Write(BlockIndex); writer.Write(TxHash); writer.WriteVarBytes(Amount.ToByteArray()); } - public override void Deserialize(BinaryReader reader) + void ISerializable.Deserialize(BinaryReader reader) { - base.Deserialize(reader); UserScriptHash = reader.ReadSerializable(); BlockIndex = reader.ReadUInt32(); TxHash = reader.ReadSerializable(); Amount = new BigInteger(reader.ReadVarBytes(512)); } - public Nep5Transfer Clone() + Nep5Transfer ICloneable.Clone() { return new Nep5Transfer { @@ -43,7 +40,7 @@ public Nep5Transfer Clone() }; } - public void FromReplica(Nep5Transfer replica) + void ICloneable.FromReplica(Nep5Transfer replica) { UserScriptHash = replica.UserScriptHash; BlockIndex = replica.BlockIndex; diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index 517849de1..60599c160 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -165,18 +165,15 @@ public void OnPersist(Snapshot snapshot, IReadOnlyList - + diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 8878830f9..77998bf66 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -14,7 +14,7 @@ - + diff --git a/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj b/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj deleted file mode 100644 index 44eab88a4..000000000 --- a/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - 2.10.2 - netstandard2.0 - Neo.Plugins - latest - - - - PreserveNewest - PreserveNewest - - - - - - diff --git a/RpcSystemAssetTracker/RpcSystemAssetTracker/config.json b/RpcSystemAssetTracker/RpcSystemAssetTracker/config.json deleted file mode 100644 index 214c08939..000000000 --- a/RpcSystemAssetTracker/RpcSystemAssetTracker/config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "PluginConfiguration": { - "DBPath": "SystemAssetBalanceData", - "MaxReturnedUnspents": 1000, - "TrackUnclaimed": true - } -} diff --git a/RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs b/RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs deleted file mode 100644 index 076bb4f6a..000000000 --- a/RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs +++ /dev/null @@ -1,426 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Neo.IO.Caching; -using Neo.IO.Data.LevelDB; -using Neo.IO.Json; -using Neo.Network.P2P.Payloads; -using Neo.Persistence.LevelDB; -using Neo.Wallets; -using System; -using System.Collections.Generic; -using System.Linq; -using Neo.Ledger; -using Neo.Persistence; -using Snapshot = Neo.Persistence.Snapshot; - -namespace Neo.Plugins -{ - public class RpcSystemAssetTrackerPlugin : Plugin, IPersistencePlugin, IRpcPlugin - { - private const byte SystemAssetUnspentCoinsPrefix = 0xfb; - private const byte SystemAssetSpentUnclaimedCoinsPrefix = 0xfc; - private DB _db; - private DataCache _userUnspentCoins; - private bool _shouldTrackUnclaimed; - private DataCache _userSpentUnclaimedCoins; - private WriteBatch _writeBatch; - private int _rpcMaxUnspents; - private uint _lastPersistedBlock; - private bool _shouldPersistBlock; - private Neo.IO.Data.LevelDB.Snapshot _levelDbSnapshot; - - public override void Configure() - { - if (_db == null) - { - var dbPath = GetConfiguration().GetSection("DBPath").Value ?? "SystemAssetBalanceData"; - _db = DB.Open(dbPath, new Options { CreateIfMissing = true }); - _shouldTrackUnclaimed = (GetConfiguration().GetSection("TrackUnclaimed").Value ?? true.ToString()) != false.ToString(); - try - { - _lastPersistedBlock = _db.Get(ReadOptions.Default, SystemAssetUnspentCoinsPrefix).ToUInt32(); - } - catch (LevelDBException ex) - { - if (!ex.Message.Contains("not found")) - throw; - _lastPersistedBlock = 0; - } - } - _rpcMaxUnspents = int.Parse(GetConfiguration().GetSection("MaxReturnedUnspents").Value ?? "0"); - } - - private void ResetBatch() - { - _writeBatch = new WriteBatch(); - _levelDbSnapshot?.Dispose(); - _levelDbSnapshot = _db.GetSnapshot(); - var dbOptions = new ReadOptions { FillCache = false, Snapshot = _levelDbSnapshot }; - _userUnspentCoins = new DbCache(_db, dbOptions, - _writeBatch, SystemAssetUnspentCoinsPrefix); - if (!_shouldTrackUnclaimed) return; - _userSpentUnclaimedCoins = new DbCache(_db, dbOptions, - _writeBatch, SystemAssetSpentUnclaimedCoinsPrefix); - } - - private bool ProcessBlock(Snapshot snapshot, Block block) - { - if (block.Transactions.Length <= 1) - { - _lastPersistedBlock = block.Index; - return false; - } - - ResetBatch(); - - var transactionsCache = snapshot.Transactions; - foreach (Transaction tx in block.Transactions) - { - ushort outputIndex = 0; - foreach (TransactionOutput output in tx.Outputs) - { - bool isGoverningToken = output.AssetId.Equals(Blockchain.GoverningToken.Hash); - if (isGoverningToken || output.AssetId.Equals(Blockchain.UtilityToken.Hash)) - { - // Add new unspent UTXOs by account script hash. - UserSystemAssetCoinOutputs outputs = _userUnspentCoins.GetAndChange( - new UserSystemAssetCoinOutputsKey(isGoverningToken, output.ScriptHash, tx.Hash), - () => new UserSystemAssetCoinOutputs()); - outputs.AddTxIndex(outputIndex, output.Value); - } - outputIndex++; - } - - // Iterate all input Transactions by grouping by common input hashes. - foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash)) - { - TransactionState txPrev = transactionsCache[group.Key]; - // For each input being spent by this transaction. - foreach (CoinReference input in group) - { - // Get the output from the the previous transaction that is now being spent. - var outPrev = txPrev.Transaction.Outputs[input.PrevIndex]; - - bool isGoverningToken = outPrev.AssetId.Equals(Blockchain.GoverningToken.Hash); - if (isGoverningToken || outPrev.AssetId.Equals(Blockchain.UtilityToken.Hash)) - { - // Remove spent UTXOs for unspent outputs by account script hash. - var userCoinOutputsKey = - new UserSystemAssetCoinOutputsKey(isGoverningToken, outPrev.ScriptHash, input.PrevHash); - UserSystemAssetCoinOutputs outputs = _userUnspentCoins.GetAndChange( - userCoinOutputsKey, () => new UserSystemAssetCoinOutputs()); - outputs.RemoveTxIndex(input.PrevIndex); - if (outputs.AmountByTxIndex.Count == 0) - _userUnspentCoins.Delete(userCoinOutputsKey); - - if (_shouldTrackUnclaimed && isGoverningToken) - { - UserSystemAssetCoinOutputs spentUnclaimedOutputs = _userSpentUnclaimedCoins.GetAndChange( - userCoinOutputsKey, () => new UserSystemAssetCoinOutputs()); - spentUnclaimedOutputs.AddTxIndex(input.PrevIndex, outPrev.Value); - } - } - } - } - - if (_shouldTrackUnclaimed && tx is ClaimTransaction claimTransaction) - { - foreach (CoinReference input in claimTransaction.Claims) - { - TransactionState txPrev = transactionsCache[input.PrevHash]; - var outPrev = txPrev.Transaction.Outputs[input.PrevIndex]; - - var claimedCoinKey = - new UserSystemAssetCoinOutputsKey(true, outPrev.ScriptHash, input.PrevHash); - UserSystemAssetCoinOutputs spentUnclaimedOutputs = _userSpentUnclaimedCoins.GetAndChange( - claimedCoinKey, () => new UserSystemAssetCoinOutputs()); - spentUnclaimedOutputs.RemoveTxIndex(input.PrevIndex); - if (spentUnclaimedOutputs.AmountByTxIndex.Count == 0) - _userSpentUnclaimedCoins.Delete(claimedCoinKey); - - if (snapshot.SpentCoins.TryGet(input.PrevHash)?.Items.Remove(input.PrevIndex) == true) - snapshot.SpentCoins.GetAndChange(input.PrevHash); - } - } - } - - // Write the current height into the key of the prefix itself - _writeBatch.Put(SystemAssetUnspentCoinsPrefix, block.Index); - _lastPersistedBlock = block.Index; - return true; - } - - - private void ProcessSkippedBlocks(Snapshot snapshot) - { - for (uint blockIndex = _lastPersistedBlock + 1; blockIndex < snapshot.PersistingBlock.Index; blockIndex++) - { - var skippedBlock = Blockchain.Singleton.Store.GetBlock(blockIndex); - if (skippedBlock.Transactions.Length <= 1) - { - _lastPersistedBlock = skippedBlock.Index; - continue; - } - - _shouldPersistBlock = ProcessBlock(snapshot, skippedBlock); - OnCommit(snapshot); - } - } - - public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) - { - if (snapshot.PersistingBlock.Index > _lastPersistedBlock + 1) - ProcessSkippedBlocks(snapshot); - - _shouldPersistBlock = ProcessBlock(snapshot, snapshot.PersistingBlock); - } - - public void OnCommit(Snapshot snapshot) - { - if (!_shouldPersistBlock) return; - _userUnspentCoins.Commit(); - if (_shouldTrackUnclaimed) _userSpentUnclaimedCoins.Commit(); - _db.Write(WriteOptions.Default, _writeBatch); - } - - public bool ShouldThrowExceptionFromCommit(Exception ex) - { - return true; - } - - public void PreProcess(HttpContext context, string method, JArray _params) - { - } - - private UInt160 GetScriptHashFromParam(string addressOrScriptHash) - { - return addressOrScriptHash.Length < 40 ? - addressOrScriptHash.ToScriptHash() : UInt160.Parse(addressOrScriptHash); - } - - - private long GetSysFeeAmountForHeight(DataCache blocks, uint height) - { - return blocks.TryGet(Blockchain.Singleton.GetBlockHash(height)).SystemFeeAmount; - } - - private void CalculateClaimable(Snapshot snapshot, Fixed8 value, uint startHeight, uint endHeight, out Fixed8 generated, out Fixed8 sysFee) - { - uint amount = 0; - uint ustart = startHeight / Blockchain.DecrementInterval; - if (ustart < Blockchain.GenerationAmount.Length) - { - uint istart = startHeight % Blockchain.DecrementInterval; - uint uend = endHeight / Blockchain.DecrementInterval; - uint iend = endHeight % Blockchain.DecrementInterval; - if (uend >= Blockchain.GenerationAmount.Length) - { - uend = (uint)Blockchain.GenerationAmount.Length; - iend = 0; - } - if (iend == 0) - { - uend--; - iend = Blockchain.DecrementInterval; - } - while (ustart < uend) - { - amount += (Blockchain.DecrementInterval - istart) * Blockchain.GenerationAmount[ustart]; - ustart++; - istart = 0; - } - amount += (iend - istart) * Blockchain.GenerationAmount[ustart]; - } - - Fixed8 fractionalShare = value / 100000000; - generated = fractionalShare * amount; - sysFee = fractionalShare * (GetSysFeeAmountForHeight(snapshot.Blocks, endHeight - 1) - - (startHeight == 0 ? 0 : GetSysFeeAmountForHeight(snapshot.Blocks, startHeight - 1))); - } - - private bool AddClaims(JArray claimableOutput, ref Fixed8 runningTotal, int maxClaims, - Snapshot snapshot, DataCache storeSpentCoins, - KeyValuePair claimableInTx) - { - foreach (var claimTransaction in claimableInTx.Value.AmountByTxIndex) - { - var utxo = new JObject(); - var txId = claimableInTx.Key.TxHash.ToString().Substring(2); - utxo["txid"] = txId; - utxo["n"] = claimTransaction.Key; - var spentCoinState = storeSpentCoins.TryGet(claimableInTx.Key.TxHash); - var startHeight = spentCoinState.TransactionHeight; - var endHeight = spentCoinState.Items[claimTransaction.Key]; - CalculateClaimable(snapshot, claimTransaction.Value, startHeight, endHeight, out var generated, - out var sysFee); - var unclaimed = generated + sysFee; - utxo["value"] = (double) (decimal) claimTransaction.Value; - utxo["start_height"] = startHeight; - utxo["end_height"] = endHeight; - utxo["generated"] = (double) (decimal) generated; - utxo["sys_fee"] = (double) (decimal) sysFee; - utxo["unclaimed"] = (double) (decimal) unclaimed; - runningTotal += unclaimed; - claimableOutput.Add(utxo); - if (claimableOutput.Count > maxClaims) - return false; - } - - return true; - } - - private JObject ProcessGetClaimableSpents(JArray parameters) - { - UInt160 scriptHash = GetScriptHashFromParam(parameters[0].AsString()); - var dbCache = new DbCache( - _db, null, null, SystemAssetSpentUnclaimedCoinsPrefix); - - JObject json = new JObject(); - JArray claimable = new JArray(); - json["claimable"] = claimable; - json["address"] = scriptHash.ToAddress(); - - Fixed8 totalUnclaimed = Fixed8.Zero; - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - { - var storeSpentCoins = snapshot.SpentCoins; - byte[] prefix = new [] { (byte) 1 }.Concat(scriptHash.ToArray()).ToArray(); - foreach (var claimableInTx in dbCache.Find(prefix)) - if (!AddClaims(claimable, ref totalUnclaimed, _rpcMaxUnspents, snapshot, storeSpentCoins, - claimableInTx)) - break; - } - json["unclaimed"] = (double) (decimal) totalUnclaimed; - return json; - } - - private JObject ProcessGetUnclaimed(JArray parameters) - { - UInt160 scriptHash = GetScriptHashFromParam(parameters[0].AsString()); - JObject json = new JObject(); - - Fixed8 available = Fixed8.Zero; - Fixed8 unavailable = Fixed8.Zero; - var spentsCache = new DbCache( - _db, null, null, SystemAssetSpentUnclaimedCoinsPrefix); - var unspentsCache = new DbCache( - _db, null, null, SystemAssetUnspentCoinsPrefix); - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - { - var storeSpentCoins = snapshot.SpentCoins; - byte[] prefix = new [] { (byte) 1 }.Concat(scriptHash.ToArray()).ToArray(); - foreach (var claimableInTx in spentsCache.Find(prefix)) - { - var spentCoinState = storeSpentCoins.TryGet(claimableInTx.Key.TxHash); - foreach (var claimTxIndex in claimableInTx.Value.AmountByTxIndex) - { - var startHeight = spentCoinState.TransactionHeight; - var endHeight = spentCoinState.Items[claimTxIndex.Key]; - CalculateClaimable(snapshot, claimTxIndex.Value, startHeight, endHeight, out var generated, - out var sysFee); - available += generated + sysFee; - } - } - - var transactionsCache = snapshot.Transactions; - foreach (var claimableInTx in unspentsCache.Find(prefix)) - { - var transaction = transactionsCache.TryGet(claimableInTx.Key.TxHash); - - foreach (var claimTxIndex in claimableInTx.Value.AmountByTxIndex) - { - var startHeight = transaction.BlockIndex; - var endHeight = Blockchain.Singleton.Height; - CalculateClaimable(snapshot, claimTxIndex.Value, startHeight, endHeight, - out var generated, - out var sysFee); - unavailable += generated + sysFee; - } - } - } - - json["available"] = (double) (decimal) available; - json["unavailable"] = (double) (decimal) unavailable; - json["unclaimed"] = (double) (decimal) (available + unavailable); - return json; - } - - private bool AddUnspents(JArray unspents, ref Fixed8 runningTotal, - KeyValuePair unspentInTx) - { - var txId = unspentInTx.Key.TxHash.ToString().Substring(2); - foreach (var unspent in unspentInTx.Value.AmountByTxIndex) - { - var utxo = new JObject(); - utxo["txid"] = txId; - utxo["n"] = unspent.Key; - utxo["value"] = (double) (decimal) unspent.Value; - runningTotal += unspent.Value; - - unspents.Add(utxo); - if (unspents.Count > _rpcMaxUnspents) - return false; - } - return true; - } - - private JObject ProcessGetUnspents(JArray _params) - { - UInt160 scriptHash = GetScriptHashFromParam(_params[0].AsString()); - byte startingToken = 0; // 0 = Utility Token (GAS), 1 = Governing Token (NEO) - int maxIterations = 2; - - if (_params.Count > 1) - { - maxIterations = 1; - bool isGoverningToken = _params[1].AsBoolean(); - if (isGoverningToken) startingToken = 1; - } - - var unspentsCache = new DbCache( - _db, null, null, SystemAssetUnspentCoinsPrefix); - - string[] nativeAssetNames = {"GAS", "NEO"}; - UInt256[] nativeAssetIds = {Blockchain.UtilityToken.Hash, Blockchain.GoverningToken.Hash}; - - JObject json = new JObject(); - JArray balances = new JArray(); - json["balance"] = balances; - json["address"] = scriptHash.ToAddress(); - for (byte tokenIndex = startingToken; maxIterations-- > 0; tokenIndex++) - { - byte[] prefix = new [] { tokenIndex }.Concat(scriptHash.ToArray()).ToArray(); - - var unspents = new JArray(); - Fixed8 total = new Fixed8(0); - - foreach (var unspentInTx in unspentsCache.Find(prefix)) - if (!AddUnspents(unspents, ref total, unspentInTx)) break; - - if (unspents.Count <= 0) continue; - - var balance = new JObject(); - balance["unspent"] = unspents; - balance["asset_hash"] = nativeAssetIds[tokenIndex].ToString().Substring(2); - balance["asset_symbol"] = balance["asset"] = nativeAssetNames[tokenIndex]; - balance["amount"] = new JNumber((double) (decimal) total); ; - balances.Add(balance); - } - - return json; - } - - public JObject OnProcess(HttpContext context, string method, JArray parameters) - { - if (_shouldTrackUnclaimed) - { - if (method == "getclaimable") return ProcessGetClaimableSpents(parameters); - if (method == "getunclaimed") return ProcessGetUnclaimed(parameters); - } - return method != "getunspents" ? null : ProcessGetUnspents(parameters); - } - - public void PostProcess(HttpContext context, string method, JArray _params, JObject result) - { - } - } -} diff --git a/RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs b/RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs deleted file mode 100644 index 9d6251ea6..000000000 --- a/RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using Neo.IO; -using Neo.Ledger; - -namespace Neo.Plugins -{ - public class UserSystemAssetCoinOutputs : StateBase, ICloneable - { - public Fixed8 TotalAmount; - public Dictionary AmountByTxIndex; - - public override int Size => base.Size + TotalAmount.Size + sizeof(ushort) + - (AmountByTxIndex.Count * (sizeof(ushort) + sizeof(ulong))); - - public UserSystemAssetCoinOutputs() - { - TotalAmount = new Fixed8(0); - AmountByTxIndex = new Dictionary(); - } - - public void AddTxIndex(ushort index, Fixed8 amount) - { - TotalAmount += amount; - AmountByTxIndex.Add(index, amount); - } - - public bool RemoveTxIndex(ushort index) - { - if(AmountByTxIndex.TryGetValue(index, out Fixed8 amount)) - { - AmountByTxIndex.Remove(index); - TotalAmount -= amount; - return true; - } - - return false; - } - public UserSystemAssetCoinOutputs Clone() - { - return new UserSystemAssetCoinOutputs() - { - TotalAmount = TotalAmount, - AmountByTxIndex = new Dictionary(AmountByTxIndex) - }; - } - - public void FromReplica(UserSystemAssetCoinOutputs replica) - { - TotalAmount = replica.TotalAmount; - AmountByTxIndex = replica.AmountByTxIndex; - } - - public override void Serialize(BinaryWriter writer) - { - base.Serialize(writer); - writer.Write(TotalAmount); - writer.Write((ushort)AmountByTxIndex.Count); - foreach (KeyValuePair txIndex in AmountByTxIndex) - { - writer.Write(txIndex.Key); - writer.Write(txIndex.Value); - } - } - - public override void Deserialize(BinaryReader reader) - { - base.Deserialize(reader); - ((ISerializable)TotalAmount).Deserialize(reader); - ushort count = reader.ReadUInt16(); - for (int i = 0; i < count; i++) - { - ushort txIndex = reader.ReadUInt16(); - Fixed8 amount = reader.ReadSerializable(); - AmountByTxIndex.Add(txIndex, amount); - } - } - } -} \ No newline at end of file diff --git a/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs b/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs deleted file mode 100644 index 3e4439b50..000000000 --- a/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Neo.IO; - -namespace Neo.Plugins -{ - public class UserSystemAssetCoinOutputsKey : IComparable, IEquatable, - ISerializable - { - public bool IsGoverningToken; // It's either the governing token or the utility token - public readonly UInt160 UserAddress; - public readonly UInt256 TxHash; - - public int Size => 1 + UserAddress.Size + TxHash.Size; - - public bool Equals(UserSystemAssetCoinOutputsKey other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return IsGoverningToken == other.IsGoverningToken && Equals(UserAddress, other.UserAddress) && Equals(TxHash, other.TxHash); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (!(obj is UserSystemAssetCoinOutputsKey b)) return false; - return Equals(b); - } - - public int CompareTo(UserSystemAssetCoinOutputsKey other) - { - if (ReferenceEquals(this, other)) return 0; - if (ReferenceEquals(null, other)) return 1; - var isGoverningTokenComparison = IsGoverningToken.CompareTo(other.IsGoverningToken); - if (isGoverningTokenComparison != 0) return isGoverningTokenComparison; - var userAddressComparison = Comparer.Default.Compare(UserAddress, other.UserAddress); - if (userAddressComparison != 0) return userAddressComparison; - return Comparer.Default.Compare(TxHash, other.TxHash); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = IsGoverningToken.GetHashCode(); - hashCode = (hashCode * 397) ^ (UserAddress != null ? UserAddress.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (TxHash != null ? TxHash.GetHashCode() : 0); - return hashCode; - } - } - - public UserSystemAssetCoinOutputsKey() - { - UserAddress = new UInt160(); - TxHash = new UInt256(); - } - - public UserSystemAssetCoinOutputsKey(bool isGoverningToken, UInt160 userAddress, UInt256 txHash) - { - IsGoverningToken = isGoverningToken; - UserAddress = userAddress; - TxHash = txHash; - } - - public void Serialize(BinaryWriter writer) - { - writer.Write(IsGoverningToken); - writer.Write(UserAddress.ToArray()); - writer.Write(TxHash.ToArray()); - } - - public void Deserialize(BinaryReader reader) - { - IsGoverningToken = reader.ReadBoolean(); - ((ISerializable) UserAddress).Deserialize(reader); - ((ISerializable) TxHash).Deserialize(reader); - } - } -} \ No newline at end of file diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index 3d934b8b8..04e8759d3 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -8,10 +8,11 @@ using Neo.Network.RPC; using Neo.Persistence; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.Wallets; using Neo.Wallets.NEP6; -using System.Collections.Generic; using System.Linq; +using System.Numerics; namespace Neo.Plugins { @@ -32,11 +33,6 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) { switch (method) { - case "claimgas": - { - UInt160 to = _params.Count >= 1 ? _params[0].AsString().ToScriptHash() : null; - return ClaimGas(to); - } case "dumpprivkey": { UInt160 scriptHash = _params[0].AsString().ToScriptHash(); @@ -44,7 +40,7 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) } case "getbalance": { - UIntBase asset_id = UIntBase.Parse(_params[0].AsString()); + UInt160 asset_id = UInt160.Parse(_params[0].AsString()); return GetBalance(asset_id); } case "getnewaddress": @@ -70,13 +66,12 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) } case "sendfrom": { - UIntBase assetId = UIntBase.Parse(_params[0].AsString()); + UInt160 assetId = UInt160.Parse(_params[0].AsString()); UInt160 from = _params[1].AsString().ToScriptHash(); UInt160 to = _params[2].AsString().ToScriptHash(); string value = _params[3].AsString(); - Fixed8 fee = _params.Count >= 5 ? Fixed8.Parse(_params[4].AsString()) : Fixed8.Zero; - UInt160 change_address = _params.Count >= 6 ? _params[5].AsString().ToScriptHash() : null; - return SendFrom(assetId, from, to, value, fee, change_address); + long fee = _params.Count >= 5 ? long.Parse(_params[4].AsString()) : 0; + return SendFrom(assetId, from, to, value, fee); } case "sendmany": { @@ -88,18 +83,16 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) to_start = 1; } JArray to = (JArray)_params[to_start + 0]; - Fixed8 fee = _params.Count >= to_start + 2 ? Fixed8.Parse(_params[to_start + 1].AsString()) : Fixed8.Zero; - UInt160 change_address = _params.Count >= to_start + 3 ? _params[to_start + 2].AsString().ToScriptHash() : null; - return SendMany(from, to, fee, change_address); + long fee = _params.Count >= to_start + 2 ? long.Parse(_params[to_start + 1].AsString()) : 0; + return SendMany(from, to, fee); } case "sendtoaddress": { - UIntBase assetId = UIntBase.Parse(_params[0].AsString()); + UInt160 assetId = UInt160.Parse(_params[0].AsString()); UInt160 scriptHash = _params[1].AsString().ToScriptHash(); string value = _params[2].AsString(); - Fixed8 fee = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero; - UInt160 change_address = _params.Count >= 5 ? _params[4].AsString().ToScriptHash() : null; - return SendToAddress(assetId, scriptHash, value, fee, change_address); + long fee = _params.Count >= 4 ? long.Parse(_params[3].AsString()) : 0; + return SendToAddress(assetId, scriptHash, value, fee); } default: return null; @@ -122,25 +115,17 @@ private void ProcessInvoke(JObject result) { if (Wallet != null) { - InvocationTransaction tx = new InvocationTransaction + Transaction tx = new Transaction { - Version = 1, - Script = result["script"].AsString().HexToBytes(), - Gas = Fixed8.Parse(result["gas_consumed"].AsString()) + Script = result["script"].AsString().HexToBytes() }; - tx.Gas -= Fixed8.FromDecimal(10); - if (tx.Gas < Fixed8.Zero) tx.Gas = Fixed8.Zero; - tx.Gas = tx.Gas.Ceiling(); - tx = Wallet.MakeTransaction(tx); - if (tx != null) - { - ContractParametersContext context = new ContractParametersContext(tx); - Wallet.Sign(context); - if (context.Completed) - tx.Witnesses = context.GetWitnesses(); - else - tx = null; - } + Wallet.FillTransaction(tx); + ContractParametersContext context = new ContractParametersContext(tx); + Wallet.Sign(context); + if (context.Completed) + tx.Witnesses = context.GetWitnesses(); + else + tx = null; result["tx"] = tx?.ToArray().ToHexString(); } } @@ -168,36 +153,6 @@ private JObject SignAndRelay(Transaction tx) } } - private JObject ClaimGas(UInt160 to) - { - CheckWallet(); - const int MAX_CLAIMS_AMOUNT = 50; - CoinReference[] claims = Wallet.GetUnclaimedCoins().Select(p => p.Reference).ToArray(); - if (claims.Length == 0) - throw new RpcException(-300, "No gas to claim"); - ClaimTransaction tx; - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - { - tx = new ClaimTransaction - { - Claims = claims.Take(MAX_CLAIMS_AMOUNT).ToArray(), - Attributes = new TransactionAttribute[0], - Inputs = new CoinReference[0], - Outputs = new[] - { - new TransactionOutput - { - AssetId = Blockchain.UtilityToken.Hash, - Value = snapshot.CalculateBonus(claims.Take(MAX_CLAIMS_AMOUNT)), - ScriptHash = to ?? Wallet.GetChangeAddress() - } - } - - }; - } - return SignAndRelay(tx); - } - private JObject DumpPrivKey(UInt160 scriptHash) { CheckWallet(); @@ -205,21 +160,11 @@ private JObject DumpPrivKey(UInt160 scriptHash) return account.GetKey().Export(); } - private JObject GetBalance(UIntBase asset_id) + private JObject GetBalance(UInt160 asset_id) { CheckWallet(); JObject json = new JObject(); - switch (asset_id) - { - case UInt160 asset_id_160: //NEP-5 balance - json["balance"] = Wallet.GetAvailable(asset_id_160).ToString(); - break; - case UInt256 asset_id_256: //Global Assets balance - IEnumerable coins = Wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(asset_id_256)); - json["balance"] = coins.Sum(p => p.Output.Value).ToString(); - json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString(); - break; - } + json["balance"] = Wallet.GetAvailable(asset_id).ToString(); return json; } @@ -235,24 +180,13 @@ private JObject GetNewAddress() private JObject GetUnclaimedGas() { CheckWallet(); + BigInteger gas = BigInteger.Zero; using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - { - uint height = snapshot.Height + 1; - Fixed8 unavailable; - try - { - unavailable = snapshot.CalculateBonus(Wallet.FindUnspentCoins().Where(p => p.Output.AssetId.Equals(Blockchain.GoverningToken.Hash)).Select(p => p.Reference), height); - } - catch + foreach (UInt160 account in Wallet.GetAccounts().Select(p => p.ScriptHash)) { - unavailable = Fixed8.Zero; + gas += NativeContract.NEO.UnclaimedGas(snapshot, account, snapshot.Height + 1); } - return new JObject - { - ["available"] = snapshot.CalculateBonus(Wallet.GetUnclaimedCoins().Select(p => p.Reference)).ToString(), - ["unavailable"] = unavailable.ToString() - }; - } + return gas.ToString(); } private JObject GetWalletHeight() @@ -290,14 +224,14 @@ private JObject ListAddress() }).ToArray(); } - private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string value, Fixed8 fee, UInt160 change_address) + private JObject SendFrom(UInt160 assetId, UInt160 from, UInt160 to, string value, long fee) { CheckWallet(); AssetDescriptor descriptor = new AssetDescriptor(assetId); BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); if (amount.Sign <= 0) throw new RpcException(-32602, "Invalid params"); - if (fee < Fixed8.Zero) + if (fee < 0) throw new RpcException(-32602, "Invalid params"); Transaction tx = Wallet.MakeTransaction(null, new[] { @@ -307,7 +241,7 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu Value = amount, ScriptHash = to } - }, from: from, change_address: change_address, fee: fee); + }, from: from, net_fee: fee); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -318,29 +252,16 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { - Fixed8 calFee = Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); - if (fee < calFee) - { - fee = calFee; - tx = Wallet.MakeTransaction(null, new[] - { - new TransferOutput - { - AssetId = assetId, - Value = amount, - ScriptHash = to - } - }, from: from, change_address: change_address, fee: fee); - if (tx == null) - throw new RpcException(-300, "Insufficient funds"); - } + long calFee = tx.Size * 1000 + 100000; + if (tx.NetworkFee < calFee) + tx.NetworkFee = calFee; } - if (fee > Settings.Default.MaxFee) + if (tx.NetworkFee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } - private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_address) + private JObject SendMany(UInt160 from, JArray to, long fee) { CheckWallet(); if (to.Count == 0) @@ -348,7 +269,7 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add TransferOutput[] outputs = new TransferOutput[to.Count]; for (int i = 0; i < to.Count; i++) { - UIntBase asset_id = UIntBase.Parse(to[i]["asset"].AsString()); + UInt160 asset_id = UInt160.Parse(to[i]["asset"].AsString()); AssetDescriptor descriptor = new AssetDescriptor(asset_id); outputs[i] = new TransferOutput { @@ -359,9 +280,9 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add if (outputs[i].Value.Sign <= 0) throw new RpcException(-32602, "Invalid params"); } - if (fee < Fixed8.Zero) + if (fee < 0) throw new RpcException(-32602, "Invalid params"); - Transaction tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); + Transaction tx = Wallet.MakeTransaction(null, outputs, from: from, net_fee: fee); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -372,28 +293,23 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { - Fixed8 calFee = Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); - if (fee < calFee) - { - fee = calFee; - tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); - if (tx == null) - throw new RpcException(-300, "Insufficient funds"); - } + long calFee = tx.Size * 1000 + 100000; + if (tx.NetworkFee < calFee) + tx.NetworkFee = calFee; } - if (fee > Settings.Default.MaxFee) + if (tx.NetworkFee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } - private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value, Fixed8 fee, UInt160 change_address) + private JObject SendToAddress(UInt160 assetId, UInt160 scriptHash, string value, long fee) { CheckWallet(); AssetDescriptor descriptor = new AssetDescriptor(assetId); BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); if (amount.Sign <= 0) throw new RpcException(-32602, "Invalid params"); - if (fee < Fixed8.Zero) + if (fee < 0) throw new RpcException(-32602, "Invalid params"); Transaction tx = Wallet.MakeTransaction(null, new[] { @@ -403,7 +319,7 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value Value = amount, ScriptHash = scriptHash } - }, change_address: change_address, fee: fee); + }, net_fee: fee); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -414,24 +330,11 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { - Fixed8 calFee = Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); - if (fee < calFee) - { - fee = calFee; - tx = Wallet.MakeTransaction(null, new[] - { - new TransferOutput - { - AssetId = assetId, - Value = amount, - ScriptHash = scriptHash - } - }, change_address: change_address, fee: fee); - if (tx == null) - throw new RpcException(-300, "Insufficient funds"); - } + long calFee = tx.Size * 1000 + 100000; + if (tx.NetworkFee < calFee) + tx.NetworkFee = calFee; } - if (fee > Settings.Default.MaxFee) + if (tx.NetworkFee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj index a8e7f0e76..04ee59222 100644 --- a/RpcWallet/RpcWallet.csproj +++ b/RpcWallet/RpcWallet.csproj @@ -14,7 +14,7 @@ - + diff --git a/RpcWallet/Settings.cs b/RpcWallet/Settings.cs index 1e94b2224..371032b5c 100644 --- a/RpcWallet/Settings.cs +++ b/RpcWallet/Settings.cs @@ -1,16 +1,17 @@ using Microsoft.Extensions.Configuration; +using Neo.SmartContract.Native; namespace Neo.Plugins { internal class Settings { - public Fixed8 MaxFee { get; } + public long MaxFee { get; } public static Settings Default { get; private set; } private Settings(IConfigurationSection section) { - this.MaxFee = Fixed8.Parse(section.GetValue("MaxFee", "0.1")); + this.MaxFee = (long)BigDecimal.Parse(section.GetValue("MaxFee", "0.1"), NativeContract.GAS.Decimals).Value; } public static void Load(IConfigurationSection section) diff --git a/SimplePolicy.UnitTests/UT_SimplePolicy.cs b/SimplePolicy.UnitTests/UT_SimplePolicy.cs index f22d6aff9..00d1dc794 100644 --- a/SimplePolicy.UnitTests/UT_SimplePolicy.cs +++ b/SimplePolicy.UnitTests/UT_SimplePolicy.cs @@ -6,9 +6,6 @@ using Neo.Persistence; using Settings = Neo.Plugins.Settings; using System.Collections.Generic; -using Neo.Cryptography; -using System.Numerics; -using System.Collections; using System.Linq; using System; using Moq; @@ -35,132 +32,16 @@ public void TestMaxTransactionsPerBlock() Settings.Default.MaxFreeTransactionsPerBlock.Should().Be(20); } - - [TestMethod] - public void TestFilterForBlock_ClaimHasPriority() - { - // Should contain "ClaimTransaction" in "HighPriorityTxType" - Settings.Default.HighPriorityTxType.Contains(TransactionType.ClaimTransaction).Should().Be(true); - - ClaimTransaction claimTxZero1 = GetClaimTransaction(0); - claimTxZero1.Size.Should().Be(7 + 21); // 7 + 21 (random script) - claimTxZero1.Hash.ToString().Should().Be("0x60037520be0fd903703c2b67973296f22cac8932db07a2723addf79478aea75f"); - ClaimTransaction claimTxZero2 = GetClaimTransaction(0); - claimTxZero2.Size.Should().Be(7 + 21); // 7 + 21 (random script) - claimTxZero2.Hash.ToString().Should().Be("0xb29426673b3ef5c226bd35d53c2cb2242e09c06f0efe9c0d5be2034f41cb85ba"); - ClaimTransaction claimTxZero3 = GetClaimTransaction(0); - claimTxZero3.Size.Should().Be(7 + 21); // 7 + 21 (random script) - claimTxZero3.Hash.ToString().Should().Be("0x01027faead9a0538048db7ac5657172f6e2240bff3f7d902e490bb1bd75c2df7"); - - //ClaimTransaction claimTxTwo = GetClaimTransaction(2); - //claimTxTwo.Size.Should().Be(75 + 21); // 2*34 + 7 + 21 - - ClaimTransaction claimTx30 = GetClaimTransaction(30); - claimTx30.Size.Should().Be(1027 + 21); // 30*34 + 7 + 21 - claimTx30.NetworkFee.Should().Be(Fixed8.Zero); - claimTx30.IsLowPriority.Should().Be(true); // by default is Low Priority, but plugin makes it High Priority - //uut.IsLowPriority -> cannot inspect because it's private... no problem! - - List TxList = new List(); - TxList.Insert(0, claimTxZero1); - TxList.Insert(0, claimTxZero2); - TxList.Insert(0, claimTxZero3); - TxList.Insert(0, claimTx30); - - //Console.WriteLine("Tx List Claim"); - //foreach(var tx in TxList) - // Console.WriteLine($"Claim TX fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.FeePerByte} hash: {tx.Hash}" ); - - - // ======================== BEGIN TESTS ============================ - - // insert 100 paid invocation transactions - for (var i = 0; i < 100; i++) - { - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.One, 50).Object); - } - - // insert 100 low priority invocation transactions (18 satoshi + 82 zero) - for (var i = 0; i < 100; i++) - { - if (i < 18) - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.Satoshi, 50).Object); - else - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.Zero, 50).Object); - } - - TxList.Count().Should().Be(204); // 100 free + 100 paid + 4 claims - TxList.Where(tx => tx.NetworkFee == Fixed8.Zero).Count().Should().Be(100-18+4); // 82 fully free + 4 claims - - IEnumerable filteredTxList = uut.FilterForBlock(TxList); - //filteredTxList.Count().Should().Be(124); // 20 free + 100 paid + 4 claims - filteredTxList.Count().Should().Be(120); // 20 free (including 2 claims) + 100 paid - filteredTxList.Where(tx => tx.NetworkFee == Fixed8.Zero).Count().Should().Be(2); // 2 fully free (2 claims) - - // will select 20 low priority (including Claims) - var vx = filteredTxList.Where(tx => tx.IsLowPriority == true); - vx.Count().Should().Be(20); - - // two Claim Transaction will survive - vx = filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction); - vx.Count().Should().Be(2); - - // ================================================================= - - // insert more paid invocation transactions (400 of each) - for (var i = 0; i < 400; i++) - { - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.One, 50).Object); - } - - // insert more free invocation transactions (400 of each) - for (var i = 0; i < 400; i++) - { - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.Zero, 50).Object); - } - - TxList.Count().Should().Be(1004); // 500 free + 500 paid + 4 claims - TxList.Where(tx => tx.NetworkFee == Fixed8.Zero).Count().Should().Be(400+100-18+4); // 500-18 fully free + 4 claims - - filteredTxList = uut.FilterForBlock(TxList); - filteredTxList.Count().Should().Be(499); // full block - - // will select 20 low priority (including Claims) - vx = filteredTxList.Where(tx => tx.IsLowPriority == true); - vx.Count().Should().Be(20); - - // will still select Claim Transactions - vx = filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction); - vx.Count().Should().Be(2); - - // there are 3 tied Claim tx, will solve it based on smaller hash (0x01, 0x60) => 0xb2 is excluded - // 0x01027faead9a0538048db7ac5657172f6e2240bff3f7d902e490bb1bd75c2df7 - // 0x60037520be0fd903703c2b67973296f22cac8932db07a2723addf79478aea75f - // 0xb29426673b3ef5c226bd35d53c2cb2242e09c06f0efe9c0d5be2034f41cb85ba - vx = filteredTxList.Where(tx => tx.Hash.ToString() == "0x01027faead9a0538048db7ac5657172f6e2240bff3f7d902e490bb1bd75c2df7"); - vx.Count().Should().Be(1); - vx = filteredTxList.Where(tx => tx.Hash.ToString() == "0x60037520be0fd903703c2b67973296f22cac8932db07a2723addf79478aea75f"); - vx.Count().Should().Be(1); - vx = filteredTxList.Where(tx => tx.Hash.ToString() == "0xb29426673b3ef5c226bd35d53c2cb2242e09c06f0efe9c0d5be2034f41cb85ba"); - vx.Count().Should().Be(0); - - //Console.WriteLine("filtered"); - //foreach(var tx in filteredTxList) - // Console.WriteLine($"TX fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.FeePerByte} hash: {tx.Hash}" ); - - } - - [TestMethod] public void FreeTxVerifySort_NoHighPriority() { List txList = new List(); // three different sizes, but it doesn't matter - for (var size = 10; size <= 20; size += 5) + for (var size = 100; size <= 200; size += 50) { for (var netFeeSatoshi = 0; netFeeSatoshi <= 90000; netFeeSatoshi += 10000) { - var testTx = MockGenerateInvocationTransaction(new Fixed8(netFeeSatoshi), size).Object; + var testTx = MockGenerateTransaction(netFeeSatoshi, size).Object; testTx.IsLowPriority.Should().Be(true); // "LowPriorityThreshold": 0.001 txList.Insert(0, testTx); } @@ -234,119 +115,57 @@ public void FreeTxVerifySort_NoHighPriority() */ // part A - filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) >= new Fixed8(2500)).Count().Should().Be(18); // 18 enter in part A - txList.Where(tx => (tx.NetworkFee / tx.Size) >= new Fixed8(2500)).Count().Should().Be(18); // they also exist in main list - txList.Where(tx => (tx.NetworkFee / tx.Size) < new Fixed8(2500)).Count().Should().Be(30 - 18); // 12 not selected transactions in part A + filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) >= 250).Count().Should().Be(18); // 18 enter in part A + txList.Where(tx => (tx.NetworkFee / tx.Size) >= 250).Count().Should().Be(18); // they also exist in main list + txList.Where(tx => (tx.NetworkFee / tx.Size) < 250).Count().Should().Be(30 - 18); // 12 not selected transactions in part A // part B - filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) < new Fixed8(2500)).Count().Should().Be(2); // only two enter in part B - filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) == new Fixed8(2000)).Count().Should().Be(2); // only two enter in part B with ratio 0.00002 - txList.Where(tx => (tx.NetworkFee / tx.Size) == new Fixed8(2000)).Count().Should().Be(3); // 3 in tie (ratio 0.00002) - txList.Where(tx => (tx.NetworkFee / tx.Size) == new Fixed8(2000) && (tx.NetworkFee > new Fixed8(20000))).Count().Should().Be(2); // only 2 survive (fee > 0.0002) + filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) < 250).Count().Should().Be(2); // only two enter in part B + filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) == 200).Count().Should().Be(2); // only two enter in part B with ratio 0.00002 + txList.Where(tx => (tx.NetworkFee / tx.Size) == 200).Count().Should().Be(3); // 3 in tie (ratio 0.00002) + txList.Where(tx => (tx.NetworkFee / tx.Size) == 200 && (tx.NetworkFee > 20000)).Count().Should().Be(2); // only 2 survive (fee > 0.0002) } - [TestMethod] - public void FreeTxVerifySortWithPriority() + public void TestMock_GenerateTransaction() { - List txList = new List(); - // three different sizes, but it doesn't matter - for (var size = 10; size <= 15; size += 5) - { - for (var netFeeSatoshi = 0; netFeeSatoshi <= 90000; netFeeSatoshi += 10000) - { - var testTx = MockGenerateInvocationTransaction(new Fixed8(netFeeSatoshi), size).Object; - testTx.IsLowPriority.Should().Be(true); // "LowPriorityThreshold": 0.001 - txList.Insert(0, testTx); - } - } - - txList.Insert(0, GetClaimTransaction(1)); - txList.Insert(0, GetClaimTransaction(10)); - txList.Insert(0, GetClaimTransaction(20)); - txList.Insert(0, GetClaimTransaction(30)); - - txList.Count.Should().Be(24); // 20 free + 4 claims - - IEnumerable filteredTxList = uut.FilterForBlock(txList); - filteredTxList.Count().Should().Be(20); - - filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction).Count().Should().Be(2); // 2 claims will be selected - } - - - [TestMethod] - public void TestMock_GenerateInvocationTransaction() - { - var txHighPriority = MockGenerateInvocationTransaction(Fixed8.One, 50); + var txHighPriority = MockGenerateTransaction(100000000, 50); // testing default values - Fixed8 txHighPriority_ratio = txHighPriority.Object.NetworkFee / txHighPriority.Object.Size; - txHighPriority_ratio.Should().Be(new Fixed8(2000000)); // 0.02 + long txHighPriority_ratio = txHighPriority.Object.NetworkFee / txHighPriority.Object.Size; + txHighPriority_ratio.Should().Be(2000000); // 0.02 txHighPriority.Object.IsLowPriority.Should().Be(false); - var txLowPriority = MockGenerateInvocationTransaction(Fixed8.One / 10000, 50); // 0.00001 + var txLowPriority = MockGenerateTransaction(100000000 / 10000, 50); // 0.00001 // testing default values - Fixed8 txLowPriority_ratio = txLowPriority.Object.NetworkFee / txLowPriority.Object.Size; - txLowPriority_ratio.Should().Be(new Fixed8(200)); // 0.000002 -> 200 satoshi / Byte + long txLowPriority_ratio = txLowPriority.Object.NetworkFee / txLowPriority.Object.Size; + txLowPriority_ratio.Should().Be(200); // 0.000002 -> 200 satoshi / Byte txLowPriority.Object.IsLowPriority.Should().Be(true); } // Generate Mock InvocationTransaction with different sizes and prices - public static Mock MockGenerateInvocationTransaction(Fixed8 networkFee, int size) + public static Mock MockGenerateTransaction(long networkFee, int size) { - var mockTx = new Mock(); - mockTx.SetupGet(mr => mr.NetworkFee).Returns(networkFee); - mockTx.SetupGet(mr => mr.Size).Returns(size); + var mockTx = new Mock + { + CallBase = true + }; - //============================== - //=== Generating random Hash === - mockTx.CallBase = true; mockTx.Setup(p => p.Verify(It.IsAny(), It.IsAny>())).Returns(true); var tx = mockTx.Object; - var randomBytes = new byte[16]; - _random.NextBytes(randomBytes); - tx.Script = randomBytes; + tx.Script = new byte[0]; + tx.Sender = UInt160.Zero; + tx.NetworkFee = networkFee; tx.Attributes = new TransactionAttribute[0]; - tx.Inputs = new CoinReference[0]; - tx.Outputs = new TransactionOutput[0]; tx.Witnesses = new Witness[0]; - //============================== - - return mockTx; - } - - // Create ClaimTransaction with 'countRefs' CoinReferences - public static ClaimTransaction GetClaimTransaction(int countRefs) - { - CoinReference[] refs = new CoinReference[countRefs]; - for (var i = 0; i < countRefs; i++) + int diff = size - tx.Size; + if (diff < 0) throw new InvalidOperationException(); + if (diff > 0) { - refs[i] = GetCoinReference(new UInt256(Crypto.Default.Hash256(new BigInteger(i).ToByteArray()))); + tx.Script = new byte[diff]; + _random.NextBytes(tx.Script); } - //============================== - //=== Generating random Hash === - var randomBytes = new byte[20]; - _random.NextBytes(randomBytes); - //============================== - return new ClaimTransaction - { - Claims = refs, - Attributes = new TransactionAttribute[]{new TransactionAttribute{Usage = TransactionAttributeUsage.Script, Data = randomBytes} }, - Inputs = new CoinReference[0], - Outputs = new TransactionOutput[0], - Witnesses = new Witness[0] - }; - } - - public static CoinReference GetCoinReference(UInt256 prevHash) - { - if (prevHash == null) prevHash = UInt256.Zero; - return new CoinReference - { - PrevHash = prevHash, - PrevIndex = 0 - }; + return mockTx; } } } diff --git a/SimplePolicy/Settings.cs b/SimplePolicy/Settings.cs index 146047788..36c4756a5 100644 --- a/SimplePolicy/Settings.cs +++ b/SimplePolicy/Settings.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.Configuration; -using Neo.Network.P2P.Payloads; +using Neo.SmartContract.Native; using Neo.Wallets; using System; using System.Collections.Generic; @@ -12,8 +12,7 @@ internal class Settings public int MaxTransactionsPerBlock { get; } public int MaxFreeTransactionsPerBlock { get; } public int MaxFreeTransactionSize { get; } - public Fixed8 FeePerExtraByte { get; } - public EnumSet HighPriorityTxType { get; } + public long FeePerExtraByte { get; } public BlockedAccounts BlockedAccounts { get; } public static Settings Default { get; private set; } @@ -23,8 +22,7 @@ private Settings(IConfigurationSection section) this.MaxTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxTransactionsPerBlock"), 500, p => int.Parse(p)); this.MaxFreeTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxFreeTransactionsPerBlock"), 20, p => int.Parse(p)); this.MaxFreeTransactionSize = GetValueOrDefault(section.GetSection("MaxFreeTransactionSize"), 1024, p => int.Parse(p)); - this.FeePerExtraByte = GetValueOrDefault(section.GetSection("FeePerExtraByte"), Fixed8.FromDecimal(0.00001M), p => Fixed8.Parse(p)); - this.HighPriorityTxType = new EnumSet(section.GetSection("HighPriorityTxType"), TransactionType.ClaimTransaction); + this.FeePerExtraByte = GetValueOrDefault(section.GetSection("FeePerExtraByte"), 1000L, p => (long)BigDecimal.Parse(p, NativeContract.GAS.Decimals).Value); this.BlockedAccounts = new BlockedAccounts(section.GetSection("BlockedAccounts")); } @@ -40,19 +38,6 @@ public static void Load(IConfigurationSection section) } } - internal class EnumSet : HashSet - where T : Enum - { - public EnumSet(IConfigurationSection section, params T[] defaultValues) - { - if (section.Exists()) - foreach (IConfigurationSection child in section.GetChildren()) - Add((T)Enum.Parse(typeof(T), child.Value)); - else - UnionWith(defaultValues); - } - } - internal enum PolicyType : byte { AllowAll, diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index b2001eac2..3f01397be 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -15,7 +15,7 @@ - + diff --git a/SimplePolicy/SimplePolicy/config.json b/SimplePolicy/SimplePolicy/config.json index bb49ca3d2..c17821e5e 100644 --- a/SimplePolicy/SimplePolicy/config.json +++ b/SimplePolicy/SimplePolicy/config.json @@ -4,10 +4,6 @@ "MaxFreeTransactionsPerBlock": 20, "MaxFreeTransactionSize": 1024, "FeePerExtraByte": 0.00001, - "HighPriorityTxType": - [ - "ClaimTransaction" - ], "BlockedAccounts": { "Type": "AllowAll", "List": [] diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index f6cfc487a..e28876589 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -29,11 +29,9 @@ public bool FilterForMemoryPool(Transaction tx) case PolicyType.AllowAll: return true; case PolicyType.AllowList: - return tx.Witnesses.All(p => Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) || - tx.Outputs.All(p => Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); + return tx.Witnesses.All(p => Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())); case PolicyType.DenyList: - return tx.Witnesses.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) && - tx.Outputs.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); + return tx.Witnesses.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())); default: return false; } @@ -50,7 +48,7 @@ public IEnumerable FilterForBlock(IEnumerable transact private static IEnumerable FilterForBlock_Policy1(IEnumerable transactions) { int count = 0, count_free = 0; - foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee).ThenByDescending(p => InHigherLowPriorityList(p))) + foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee)) { if (count++ >= Settings.Default.MaxTransactionsPerBlock - 1) break; if (!tx.IsLowPriority || count_free++ < Settings.Default.MaxFreeTransactionsPerBlock) @@ -66,7 +64,6 @@ private static IEnumerable FilterForBlock_Policy2(IEnumerable p.IsLowPriority) .OrderByDescending(p => p.NetworkFee / p.Size) .ThenByDescending(p => p.NetworkFee) - .ThenByDescending(p => InHigherLowPriorityList(p)) .ThenBy(p => p.Hash) .Take(Settings.Default.MaxFreeTransactionsPerBlock) .ToArray(); @@ -98,22 +95,17 @@ void ILogPlugin.Log(string source, LogLevel level, string message) private bool VerifySizeLimits(Transaction tx) { - if (InHigherLowPriorityList(tx)) return true; - // Not Allow free TX bigger than MaxFreeTransactionSize if (tx.IsLowPriority && tx.Size > Settings.Default.MaxFreeTransactionSize) return false; // Require proportional fee for TX bigger than MaxFreeTransactionSize if (tx.Size > Settings.Default.MaxFreeTransactionSize) { - Fixed8 fee = Settings.Default.FeePerExtraByte * (tx.Size - Settings.Default.MaxFreeTransactionSize); + long fee = Settings.Default.FeePerExtraByte * (tx.Size - Settings.Default.MaxFreeTransactionSize); if (tx.NetworkFee < fee) return false; } return true; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool InHigherLowPriorityList(Transaction tx) => Settings.Default.HighPriorityTxType.Contains(tx.Type); } } diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 0f848c148..532688d67 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + diff --git a/neo-plugins.sln b/neo-plugins.sln index 4c1f919f6..9df0cbc46 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -21,8 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreMetrics", "CoreMetrics\CoreMetrics.csproj", "{AEFFF003-3500-416B-AD9B-8C838C33C1F4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSystemAssetTracker", "RpcSystemAssetTracker\RpcSystemAssetTracker.csproj", "{D3C183C1-8C23-4566-8909-EBF468DAD67A}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -52,6 +50,7 @@ Global {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.Build.0 = Debug|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.Build.0 = Release|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -64,10 +63,6 @@ Global {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.Build.0 = Release|Any CPU - {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE