Skip to content

Commit

Permalink
fix GetPrice parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
Luchuan committed Mar 11, 2020
1 parent 8acfe41 commit ffad20a
Show file tree
Hide file tree
Showing 9 changed files with 33 additions and 41 deletions.
2 changes: 1 addition & 1 deletion src/neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public override void Dispose()

protected override bool OnSysCall(uint method)
{
if (!AddGas(InteropService.GetPrice(method, this)))
if (!AddGas(InteropService.GetPrice(method, CurrentContext.EvaluationStack, Snapshot)))
return false;
return InteropService.Invoke(this, method);
}
Expand Down
15 changes: 5 additions & 10 deletions src/neo/SmartContract/InteropDescriptor.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Neo.Persistence;
using Neo.VM;
using System;

Expand All @@ -9,7 +10,7 @@ public class InteropDescriptor
public uint Hash { get; }
internal Func<ApplicationEngine, bool> Handler { get; }
public long Price { get; }
public Func<ApplicationEngine, long> PriceCalculator { get; }
public Func<EvaluationStack, StoreView, long> PriceCalculator { get; }
public TriggerType AllowedTriggers { get; }
public CallFlags RequiredCallFlags { get; }

Expand All @@ -19,18 +20,12 @@ internal InteropDescriptor(string method, Func<ApplicationEngine, bool> handler,
this.Price = price;
}

internal InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, Func<ApplicationEngine, long> priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags)
internal InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, Func<EvaluationStack, StoreView, long> priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags)
: this(method, handler, allowedTriggers, requiredCallFlags)
{
this.PriceCalculator = priceCalculator;
}

internal InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, Func<EvaluationStack, long> priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags)
: this(method, handler, allowedTriggers, requiredCallFlags)
{
this.PriceCalculator = (engine) => priceCalculator(engine.CurrentContext.EvaluationStack);
}

private InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, TriggerType allowedTriggers, CallFlags requiredCallFlags)
{
this.Method = method;
Expand All @@ -40,9 +35,9 @@ private InteropDescriptor(string method, Func<ApplicationEngine, bool> handler,
this.RequiredCallFlags = requiredCallFlags;
}

public long GetPrice(ApplicationEngine applicationEngine)
public long GetPrice(EvaluationStack stack, StoreView snapshot)
{
return PriceCalculator is null ? Price : PriceCalculator(applicationEngine);
return PriceCalculator is null ? Price : PriceCalculator(stack, snapshot);
}

public static implicit operator uint(InteropDescriptor descriptor)
Expand Down
3 changes: 2 additions & 1 deletion src/neo/SmartContract/InteropService.Contract.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Neo.IO;
using Neo.Ledger;
using Neo.Persistence;
using Neo.SmartContract.Manifest;
using Neo.VM;
using Neo.VM.Types;
Expand All @@ -19,7 +20,7 @@ public static class Contract
public static readonly InteropDescriptor CallEx = Register("System.Contract.CallEx", Contract_CallEx, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall);
public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All, CallFlags.None);

private static long GetDeploymentPrice(EvaluationStack stack)
private static long GetDeploymentPrice(EvaluationStack stack, StoreView snapshot)
{
int size = stack.Peek(0).GetByteLength() + stack.Peek(1).GetByteLength();
return Storage.GasPerByte * size;
Expand Down
3 changes: 2 additions & 1 deletion src/neo/SmartContract/InteropService.Crypto.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Neo.Cryptography;
using Neo.Network.P2P;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.VM;
using Neo.VM.Types;
using System;
Expand All @@ -16,7 +17,7 @@ public static class Crypto
public static readonly InteropDescriptor ECDsaVerify = Register("Neo.Crypto.ECDsaVerify", Crypto_ECDsaVerify, 0_01000000, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor ECDsaCheckMultiSig = Register("Neo.Crypto.ECDsaCheckMultiSig", Crypto_ECDsaCheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All, CallFlags.None);

private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack)
private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack, StoreView snapshot)
{
if (stack.Count < 2) return 0;
var item = stack.Peek(1);
Expand Down
8 changes: 4 additions & 4 deletions src/neo/SmartContract/InteropService.Storage.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Neo.Ledger;
using Neo.Persistence;
using Neo.SmartContract.Iterators;
using Neo.VM;
using Neo.VM.Types;
Expand All @@ -24,13 +25,12 @@ public static class Storage
public static readonly InteropDescriptor PutEx = Register("System.Storage.PutEx", Storage_PutEx, GetStoragePrice, TriggerType.Application, CallFlags.AllowModifyStates);
public static readonly InteropDescriptor Delete = Register("System.Storage.Delete", Storage_Delete, 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates);

private static long GetStoragePrice(ApplicationEngine engine)
private static long GetStoragePrice(EvaluationStack stack, StoreView snapshot)
{
var stack = engine.CurrentContext.EvaluationStack;
var key = stack.Peek(1);
var value = stack.Peek(2);
var newDataSize = value.IsNull ? 0 : value.GetByteLength();
if (!(engine.CurrentContext.EvaluationStack.Peek() is InteropInterface _interface))
if (!(stack.Peek() is InteropInterface _interface))
throw new InvalidOperationException();

StorageContext context = _interface.GetInterface<StorageContext>();
Expand All @@ -39,7 +39,7 @@ private static long GetStoragePrice(ApplicationEngine engine)
Id = context.Id,
Key = key.GetSpan().ToArray()
};
var skeyValue = engine.Snapshot.Storages.TryGet(skey);
var skeyValue = snapshot.Storages.TryGet(skey);
if (skeyValue is null || skeyValue.Value is null || skeyValue.Value.Length == 0)
return (key.GetByteLength() + newDataSize) * GasPerByte;

Expand Down
14 changes: 4 additions & 10 deletions src/neo/SmartContract/InteropService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Neo.Persistence;
using Neo.VM;
using System;
using System.Collections.Generic;
Expand All @@ -15,9 +16,9 @@ static InteropService()
t.GetFields()[0].GetValue(null);
}

public static long GetPrice(uint hash, ApplicationEngine applicationEngine)
public static long GetPrice(uint hash, EvaluationStack stack, StoreView snapshot)
{
return methods[hash].GetPrice(applicationEngine);
return methods[hash].GetPrice(stack, snapshot);
}

public static IEnumerable<InteropDescriptor> SupportedMethods()
Expand All @@ -44,14 +45,7 @@ private static InteropDescriptor Register(string method, Func<ApplicationEngine,
return descriptor;
}

private static InteropDescriptor Register(string method, Func<ApplicationEngine, bool> handler, Func<EvaluationStack, long> priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags)
{
InteropDescriptor descriptor = new InteropDescriptor(method, handler, priceCalculator, allowedTriggers, requiredCallFlags);
methods.Add(descriptor.Hash, descriptor);
return descriptor;
}

private static InteropDescriptor Register(string method, Func<ApplicationEngine, bool> handler, Func<ApplicationEngine, long> priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags)
private static InteropDescriptor Register(string method, Func<ApplicationEngine, bool> handler, Func<EvaluationStack, StoreView, long> priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags)
{
InteropDescriptor descriptor = new InteropDescriptor(method, handler, priceCalculator, allowedTriggers, requiredCallFlags);
methods.Add(descriptor.Hash, descriptor);
Expand Down
3 changes: 2 additions & 1 deletion src/neo/SmartContract/Native/NativeContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using Neo.IO;
using Neo.Ledger;
using Neo.Persistence;
using Neo.SmartContract.Manifest;
using Neo.SmartContract.Native.Tokens;
using Neo.VM;
Expand Down Expand Up @@ -101,7 +102,7 @@ internal bool Invoke(ApplicationEngine engine)
return true;
}

internal long GetPrice(EvaluationStack stack)
internal long GetPrice(EvaluationStack stack, StoreView snapshot)
{
return methods.TryGetValue(stack.Peek().GetString(), out ContractMethodMetadata method) ? method.Price : 0;
}
Expand Down
4 changes: 2 additions & 2 deletions src/neo/Wallets/Wallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size)
if (witness_script.IsSignatureContract())
{
size += 67 + witness_script.GetVarSize();
networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null);
networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null);
}
else if (witness_script.IsMultiSigContract(out int m, out int n))
{
Expand All @@ -366,7 +366,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size)
networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * n;
using (ScriptBuilder sb = new ScriptBuilder())
networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(n).ToArray()[0]];
networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null) * n;
networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null) * n;
}
else
{
Expand Down
22 changes: 11 additions & 11 deletions tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,23 @@ public void ApplicationEngineFixedPrices()
using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0))
{
ae.LoadScript(SyscallSystemRuntimeCheckWitnessHash);
InteropService.GetPrice(InteropService.Runtime.CheckWitness, ae).Should().Be(0_00030000L);
InteropService.GetPrice(InteropService.Runtime.CheckWitness, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_00030000L);
}

// System.Storage.GetContext: 9bf667ce (price is 1)
byte[] SyscallSystemStorageGetContextHash = new byte[] { 0x68, 0x9b, 0xf6, 0x67, 0xce };
using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0))
{
ae.LoadScript(SyscallSystemStorageGetContextHash);
InteropService.GetPrice(InteropService.Storage.GetContext, ae).Should().Be(0_00000400L);
InteropService.GetPrice(InteropService.Storage.GetContext, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_00000400L);
}

// System.Storage.Get: 925de831 (price is 100)
byte[] SyscallSystemStorageGetHash = new byte[] { 0x68, 0x92, 0x5d, 0xe8, 0x31 };
using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0))
{
ae.LoadScript(SyscallSystemStorageGetHash);
InteropService.GetPrice(InteropService.Storage.Get, ae).Should().Be(0_01000000L);
InteropService.GetPrice(InteropService.Storage.Get, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_01000000L);
}
}

Expand All @@ -56,7 +56,7 @@ public void ApplicationEngineVariablePrices()
ae.LoadScript(SyscallContractCreateHash00);
debugger.StepInto(); // PUSHDATA1
debugger.StepInto(); // PUSHDATA1
InteropService.GetPrice(InteropService.Contract.Create, ae).Should().Be(0_00300000L);
InteropService.GetPrice(InteropService.Contract.Create, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_00300000L);
}

// System.Storage.Put: e63f1884 (requires push key and value)
Expand All @@ -68,7 +68,7 @@ public void ApplicationEngineVariablePrices()
debugger.StepInto(); // push 03 (length 1)
debugger.StepInto(); // push 03 (length 1)
debugger.StepInto(); // push 00
Action act = () => InteropService.GetPrice(InteropService.Storage.Put, ae);
Action act = () => InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot);
act.Should().Throw<InvalidOperationException>();
}

Expand All @@ -81,7 +81,7 @@ public void ApplicationEngineVariablePrices()
debugger.StepInto(); // push 03 (length 1)
debugger.StepInto(); // push 03 (length 1)
debugger.StepInto(); // push 00
Action act = () => InteropService.GetPrice(InteropService.Storage.Put, ae);
Action act = () => InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot);
act.Should().Throw<InvalidOperationException>();
}
}
Expand Down Expand Up @@ -115,7 +115,7 @@ public void ApplicationEngineRegularPut()
debugger.StepInto();
debugger.StepInto();
var setupPrice = ae.GasConsumed;
var defaultDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae);
var defaultDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot);
defaultDataPrice.Should().Be(InteropService.Storage.GasPerByte * (key.Length + value.Length));
var expectedCost = defaultDataPrice + setupPrice;
debugger.Execute();
Expand Down Expand Up @@ -152,7 +152,7 @@ public void ApplicationEngineReusedStorage_FullReuse()
debugger.StepInto();
debugger.StepInto();
var setupPrice = applicationEngine.GasConsumed;
var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, applicationEngine);
var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, applicationEngine.CurrentContext.EvaluationStack, applicationEngine.Snapshot);
reusedDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte);
debugger.Execute();
var expectedCost = reusedDataPrice + setupPrice;
Expand Down Expand Up @@ -191,7 +191,7 @@ public void ApplicationEngineReusedStorage_PartialReuse()
debugger.StepInto();
debugger.StepInto();
var setupPrice = ae.GasConsumed;
var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae);
var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot);
reusedDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte);
debugger.StepInto();
var expectedCost = reusedDataPrice + setupPrice;
Expand Down Expand Up @@ -231,15 +231,15 @@ public void ApplicationEngineReusedStorage_PartialReuseTwice()
debugger.StepInto(); //push value
debugger.StepInto(); //syscall Storage.GetContext
var setupPrice = ae.GasConsumed;
var incrementDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae);
var incrementDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot);
incrementDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte);
debugger.StepInto(); // syscall Storage.Put

debugger.StepInto(); //push key
debugger.StepInto(); //push value
debugger.StepInto();
setupPrice = ae.GasConsumed;
var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae);
var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot);
reusedDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte); // = PUT basic fee
}
}
Expand Down

0 comments on commit ffad20a

Please sign in to comment.