Skip to content

Commit

Permalink
Adjust the Charge for Storage Writting (#1441)
Browse files Browse the repository at this point in the history
  • Loading branch information
eryeer authored Mar 13, 2020
1 parent 154ef25 commit be8ff99
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 22 deletions.
3 changes: 2 additions & 1 deletion src/neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public partial class ApplicationEngine : ExecutionEngine
public IVerifiable ScriptContainer { get; }
public StoreView Snapshot { get; }
public long GasConsumed { get; private set; } = 0;

public UInt160 CurrentScriptHash => CurrentContext?.GetState<ExecutionContextState>().ScriptHash;
public UInt160 CallingScriptHash => CurrentContext?.GetState<ExecutionContextState>().CallingScriptHash;
public UInt160 EntryScriptHash => EntryContext?.GetState<ExecutionContextState>().ScriptHash;
Expand Down Expand Up @@ -78,7 +79,7 @@ public override void Dispose()

protected override bool OnSysCall(uint method)
{
if (!AddGas(InteropService.GetPrice(method, CurrentContext.EvaluationStack)))
if (!AddGas(InteropService.GetPrice(method, CurrentContext.EvaluationStack, Snapshot)))
return false;
return InteropService.Invoke(this, method);
}
Expand Down
9 changes: 5 additions & 4 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<EvaluationStack, long> PriceCalculator { get; }
public Func<EvaluationStack, StoreView, long> PriceCalculator { get; }
public TriggerType AllowedTriggers { get; }
public CallFlags RequiredCallFlags { get; }

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

internal InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, Func<EvaluationStack, 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;
Expand All @@ -34,9 +35,9 @@ private InteropDescriptor(string method, Func<ApplicationEngine, bool> handler,
this.RequiredCallFlags = requiredCallFlags;
}

public long GetPrice(EvaluationStack stack)
public long GetPrice(EvaluationStack stack, StoreView snapshot)
{
return PriceCalculator is null ? Price : PriceCalculator(stack);
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
26 changes: 23 additions & 3 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 @@ -22,11 +23,30 @@ public static class Storage
public static readonly InteropDescriptor Find = Register("System.Storage.Find", Storage_Find, 0_01000000, TriggerType.Application, CallFlags.None);
public static readonly InteropDescriptor Put = Register("System.Storage.Put", Storage_Put, GetStoragePrice, TriggerType.Application, CallFlags.AllowModifyStates);
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);
public static readonly InteropDescriptor Delete = Register("System.Storage.Delete", Storage_Delete, 1 * GasPerByte, TriggerType.Application, CallFlags.AllowModifyStates);

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

StorageContext context = _interface.GetInterface<StorageContext>();
StorageKey skey = new StorageKey
{
Id = context.Id,
Key = key.GetSpan().ToArray()
};
var skeyValue = snapshot.Storages.TryGet(skey);
if (skeyValue is null)
newDataSize += key.GetByteLength();
else if (newDataSize <= skeyValue.Value.Length)
newDataSize = 1;
else
newDataSize -= skeyValue.Value.Length;
return newDataSize * GasPerByte;
}

private static bool PutExInternal(ApplicationEngine engine, StorageContext context, byte[] key, byte[] value, StorageFlags flags)
Expand Down
7 changes: 4 additions & 3 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, EvaluationStack stack)
public static long GetPrice(uint hash, EvaluationStack stack, StoreView snapshot)
{
return methods[hash].GetPrice(stack);
return methods[hash].GetPrice(stack, snapshot);
}

public static IEnumerable<InteropDescriptor> SupportedMethods()
Expand All @@ -44,7 +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)
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
Loading

0 comments on commit be8ff99

Please sign in to comment.