From 083082602a68a81bd6331497f119c319333c4290 Mon Sep 17 00:00:00 2001 From: Krain Chen Date: Thu, 9 Jan 2020 16:32:03 +0800 Subject: [PATCH] change network fee calculation (#178) * change network fee calculation * update to CI00847 * fix fee issue * add UT for network fee --- src/RpcClient/RpcClient.csproj | 4 +- src/RpcClient/TransactionManager.cs | 70 ++++++++----------- .../UT_TransactionManager.cs | 14 +++- 3 files changed, 42 insertions(+), 46 deletions(-) diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index d2e2e89dc..2f4aed74b 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00825 + 3.0.0-CI00847 netstandard2.1 Neo.Network.RPC The Neo Project @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index d9992ab4c..2f8c27571 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -4,9 +4,9 @@ using Neo.Network.RPC.Models; using Neo.SmartContract; using Neo.SmartContract.Native; -using Neo.VM; using Neo.Wallets; using System; +using System.Linq; namespace Neo.Network.RPC { @@ -62,9 +62,9 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] Script = script, Sender = sender, ValidUntilBlock = height + Transaction.MaxValidUntilBlockIncrement, - Attributes = attributes ?? new TransactionAttribute[0], - Cosigners = cosigners ?? new Cosigner[0], - Witnesses = new Witness[0] + Attributes = attributes ?? Array.Empty(), + Cosigners = cosigners ?? Array.Empty(), + Witnesses = Array.Empty() }; // Add witness hashes parameter to pass CheckWitness @@ -84,7 +84,7 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] context = new ContractParametersContext(Tx); // set networkfee to estimate value when networkFee is 0 - Tx.NetworkFee = networkFee == 0 ? EstimateNetworkFee() : networkFee; + Tx.NetworkFee = networkFee == 0 ? CalculateNetworkFee(true) : networkFee; var gasBalance = nep5API.BalanceOf(NativeContract.GAS.Hash, sender); if (gasBalance >= Tx.SystemFee + Tx.NetworkFee) return this; @@ -92,55 +92,41 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] } /// - /// Estimate NetworkFee, assuming the witnesses are basic Signature Contract + /// Calculate NetworkFee /// - private long EstimateNetworkFee() + /// assuming the witnesses are basic Signature Contract if set to true + /// + private long CalculateNetworkFee(bool isEstimate = false) { long networkFee = 0; UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); - int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); - - // assume the hashes are single Signature - foreach (var hash in hashes) + int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Cosigners.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + foreach (UInt160 hash in hashes) { - size += 166; - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL]; // message - using (ScriptBuilder sb = new ScriptBuilder()) + byte[] witness_script = null; + if (isEstimate) { - networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(64).ToArray()[0]]; // signature - networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(33).ToArray()[0]]; // pubKey - size += sb.ToArray().Length; + // assuming the witnesses are basic Signature Contract + KeyPair one = new KeyPair(new byte[31].Concat(new byte[] { 1 }).ToArray()); + witness_script = Contract.CreateSignatureRedeemScript(one.PublicKey); } - networkFee += InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null); - } - - networkFee += size * policyAPI.GetFeePerByte(); - return networkFee; - } - - /// - /// Calculate NetworkFee with context items - /// - private long CalculateNetworkFee() - { - long networkFee = 0; - UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); - int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); - foreach (UInt160 hash in hashes) - { - byte[] witness_script = context.GetScript(hash); - if (witness_script is null || witness_script.Length == 0) + else { - try + // calculate NetworkFee with context items + witness_script = context.GetScript(hash); + if (witness_script is null || witness_script.Length == 0) { - witness_script = rpcClient.GetContractState(hash.ToString())?.Script; + try + { + witness_script = rpcClient.GetContractState(hash.ToString())?.Script; + } + catch { } } - catch { } - } - if (witness_script is null) continue; + if (witness_script is null) continue; + } - networkFee += Wallet.CalculateNetWorkFee(witness_script, ref size); + networkFee += Wallet.CalculateNetworkFee(witness_script, ref size); } networkFee += size * policyAPI.GetFeePerByte(); return networkFee; diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index 45814d259..56925ff58 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -112,16 +112,26 @@ public void TestSign() } }; + Cosigner[] cosigners = new Cosigner[1] { + new Cosigner{ + Account = sender, + Scopes = WitnessScope.Global + } + }; + byte[] script = new byte[1]; - txManager.MakeTransaction(script, attributes) + txManager.MakeTransaction(script, attributes, cosigners) .AddSignature(keyPair1) .Sign(); // get signature from Witnesses var tx = txManager.Tx; - byte[] signature = tx.Witnesses[0].InvocationScript.Skip(1).ToArray(); + byte[] signature = tx.Witnesses[0].InvocationScript.Skip(2).ToArray(); Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey.EncodePoint(false).Skip(1).ToArray())); + // verify network fee + long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null); + Assert.AreEqual(networkFee, tx.NetworkFee); // duplicate sign should not add new witness txManager.AddSignature(keyPair1).Sign();