Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cache to native contract executions V2 #1766

Merged
merged 11 commits into from
Jul 17, 2020
Merged
61 changes: 49 additions & 12 deletions src/neo/Ledger/StorageItem.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using Neo.IO;
using Neo.SmartContract;
using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;

namespace Neo.Ledger
{
public class StorageItem : ICloneable<StorageItem>, ISerializable
{
private byte[] value;
private IInteroperable interoperable;
private object cache;
public bool IsConstant;

public int Size => Value.GetVarSize() + sizeof(bool);
Expand All @@ -16,33 +19,47 @@ public byte[] Value
{
get
{
if (value is null && interoperable != null)
value = BinarySerializer.Serialize(interoperable.ToStackItem(null), 4096);
return value;
return value ??= cache switch
{
BigInteger bi => bi.ToByteArrayStandard(),
IInteroperable interoperable => BinarySerializer.Serialize(interoperable.ToStackItem(null), 4096),
IReadOnlyCollection<ISerializable> list => list.ToByteArray(),
null => null,
_ => throw new InvalidCastException()
};
}
set
{
interoperable = null;
this.value = value;
cache = null;
}
}

public StorageItem()
{
}
public StorageItem() { }

public StorageItem(byte[] value, bool isConstant = false)
{
this.value = value;
this.IsConstant = isConstant;
}

public StorageItem(BigInteger value, bool isConstant = false)
{
this.cache = value;
this.IsConstant = isConstant;
}

public StorageItem(IInteroperable interoperable, bool isConstant = false)
{
this.interoperable = interoperable;
this.cache = interoperable;
this.IsConstant = isConstant;
}

public void Add(BigInteger integer)
{
Set(this + integer);
}

StorageItem ICloneable<StorageItem>.Clone()
{
return new StorageItem
Expand All @@ -66,19 +83,39 @@ void ICloneable<StorageItem>.FromReplica(StorageItem replica)

public T GetInteroperable<T>() where T : IInteroperable, new()
{
if (interoperable is null)
if (cache is null)
{
interoperable = new T();
var interoperable = new T();
interoperable.FromStackItem(BinarySerializer.Deserialize(value, 16, 34));
cache = interoperable;
}
value = null;
return (T)interoperable;
return (T)cache;
}

public List<T> GetSerializableList<T>() where T : ISerializable, new()
{
cache ??= new List<T>(value.AsSerializableArray<T>());
value = null;
return (List<T>)cache;
}

public void Serialize(BinaryWriter writer)
{
writer.WriteVarBytes(Value);
writer.Write(IsConstant);
}

public void Set(BigInteger integer)
{
cache = integer;
value = null;
}

public static implicit operator BigInteger(StorageItem item)
{
item.cache ??= new BigInteger(item.value);
return (BigInteger)item.cache;
}
}
}
36 changes: 19 additions & 17 deletions src/neo/SmartContract/Native/PolicyContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Neo.SmartContract.Manifest;
using System;
using System.Collections.Generic;
using System.Numerics;

namespace Neo.SmartContract.Native
{
Expand Down Expand Up @@ -58,31 +59,31 @@ internal override void Initialize(ApplicationEngine engine)
[ContractMethod(0_01000000, CallFlags.AllowStates)]
public uint GetMaxTransactionsPerBlock(StoreView snapshot)
{
return BitConverter.ToUInt32(snapshot.Storages[CreateStorageKey(Prefix_MaxTransactionsPerBlock)].Value, 0);
return (uint)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_MaxTransactionsPerBlock)];
}

[ContractMethod(0_01000000, CallFlags.AllowStates)]
public uint GetMaxBlockSize(StoreView snapshot)
{
return BitConverter.ToUInt32(snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSize)].Value, 0);
return (uint)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSize)];
}

[ContractMethod(0_01000000, CallFlags.AllowStates)]
public long GetMaxBlockSystemFee(StoreView snapshot)
{
return BitConverter.ToInt64(snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSystemFee)].Value, 0);
return (long)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSystemFee)];
}

[ContractMethod(0_01000000, CallFlags.AllowStates)]
public long GetFeePerByte(StoreView snapshot)
{
return BitConverter.ToInt64(snapshot.Storages[CreateStorageKey(Prefix_FeePerByte)].Value, 0);
return (long)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_FeePerByte)];
}

[ContractMethod(0_01000000, CallFlags.AllowStates)]
public UInt160[] GetBlockedAccounts(StoreView snapshot)
{
return snapshot.Storages[CreateStorageKey(Prefix_BlockedAccounts)].Value.AsSerializableArray<UInt160>();
return snapshot.Storages[CreateStorageKey(Prefix_BlockedAccounts)].GetSerializableList<UInt160>().ToArray();
}

[ContractMethod(0_03000000, CallFlags.AllowModifyStates)]
Expand All @@ -91,7 +92,7 @@ private bool SetMaxBlockSize(ApplicationEngine engine, uint value)
if (!CheckCommittees(engine)) return false;
if (Network.P2P.Message.PayloadMaxSize <= value) return false;
StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSize));
storage.Value = BitConverter.GetBytes(value);
storage.Set(value);
return true;
}

Expand All @@ -100,7 +101,7 @@ private bool SetMaxTransactionsPerBlock(ApplicationEngine engine, uint value)
{
if (!CheckCommittees(engine)) return false;
StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxTransactionsPerBlock));
storage.Value = BitConverter.GetBytes(value);
storage.Set(value);
return true;
}

Expand All @@ -110,7 +111,7 @@ private bool SetMaxBlockSystemFee(ApplicationEngine engine, long value)
if (!CheckCommittees(engine)) return false;
if (value <= 4007600) return false;
StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSystemFee));
storage.Value = BitConverter.GetBytes(value);
storage.Set(value);
return true;
}

Expand All @@ -119,7 +120,7 @@ private bool SetFeePerByte(ApplicationEngine engine, long value)
{
if (!CheckCommittees(engine)) return false;
StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_FeePerByte));
storage.Value = BitConverter.GetBytes(value);
storage.Set(value);
return true;
}

Expand All @@ -129,10 +130,10 @@ private bool BlockAccount(ApplicationEngine engine, UInt160 account)
if (!CheckCommittees(engine)) return false;
StorageKey key = CreateStorageKey(Prefix_BlockedAccounts);
StorageItem storage = engine.Snapshot.Storages[key];
SortedSet<UInt160> accounts = new SortedSet<UInt160>(storage.Value.AsSerializableArray<UInt160>());
if (!accounts.Add(account)) return false;
storage = engine.Snapshot.Storages.GetAndChange(key);
storage.Value = accounts.ToByteArray();
List<UInt160> accounts = storage.GetSerializableList<UInt160>();
if (accounts.Contains(account)) return false;
engine.Snapshot.Storages.GetAndChange(key);
accounts.Add(account);
return true;
}

Expand All @@ -142,10 +143,11 @@ private bool UnblockAccount(ApplicationEngine engine, UInt160 account)
if (!CheckCommittees(engine)) return false;
StorageKey key = CreateStorageKey(Prefix_BlockedAccounts);
StorageItem storage = engine.Snapshot.Storages[key];
SortedSet<UInt160> accounts = new SortedSet<UInt160>(storage.Value.AsSerializableArray<UInt160>());
if (!accounts.Remove(account)) return false;
storage = engine.Snapshot.Storages.GetAndChange(key);
storage.Value = accounts.ToByteArray();
List<UInt160> accounts = storage.GetSerializableList<UInt160>();
int index = accounts.IndexOf(account);
if (index < 0) return false;
engine.Snapshot.Storages.GetAndChange(key);
accounts.RemoveAt(index);
return true;
}
}
Expand Down
14 changes: 5 additions & 9 deletions src/neo/SmartContract/Native/Tokens/NeoToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ protected override void OnBalanceChanging(ApplicationEngine engine, UInt160 acco
if (state.VoteTo != null)
{
engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Candidate).Add(state.VoteTo)).GetInteroperable<CandidateState>().Votes += amount;
StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount));
BigInteger votersCount = new BigInteger(item.Value) + amount;
item.Value = votersCount.ToByteArray();
engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount)).Add(amount);
}
}

Expand Down Expand Up @@ -150,12 +148,10 @@ private bool Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo)
if (state_account.VoteTo is null ^ voteTo is null)
{
StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount));
BigInteger votersCount = new BigInteger(item.Value);
if (state_account.VoteTo is null)
votersCount += state_account.Balance;
item.Add(state_account.Balance);
else
votersCount -= state_account.Balance;
item.Value = votersCount.ToByteArray();
item.Add(-state_account.Balance);
}
if (state_account.VoteTo != null)
{
Expand Down Expand Up @@ -210,7 +206,7 @@ public UInt160 GetCommitteeAddress(StoreView snapshot)

private IEnumerable<ECPoint> GetCommitteeMembers(StoreView snapshot)
{
decimal votersCount = (decimal)new BigInteger(snapshot.Storages[CreateStorageKey(Prefix_VotersCount)].Value);
decimal votersCount = (decimal)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_VotersCount)];
decimal VoterTurnout = votersCount / (decimal)TotalAmount;
if (VoterTurnout < EffectiveVoterTurnout)
return Blockchain.StandbyCommittee;
Expand All @@ -225,7 +221,7 @@ public ECPoint[] GetNextBlockValidators(StoreView snapshot)
{
StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_NextValidators));
if (storage is null) return Blockchain.StandbyValidators;
return storage.Value.AsSerializableArray<ECPoint>();
return storage.GetSerializableList<ECPoint>().ToArray();
}

public class NeoAccountState : AccountState
Expand Down
15 changes: 4 additions & 11 deletions src/neo/SmartContract/Native/Tokens/Nep5Token.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,8 @@ internal protected virtual void Mint(ApplicationEngine engine, UInt160 account,
TState state = storage.GetInteroperable<TState>();
OnBalanceChanging(engine, account, state, amount);
state.Balance += amount;
storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply), () => new StorageItem
{
Value = BigInteger.Zero.ToByteArrayStandard()
});
BigInteger totalSupply = new BigInteger(storage.Value);
totalSupply += amount;
storage.Value = totalSupply.ToByteArrayStandard();
storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply), () => new StorageItem(BigInteger.Zero));
storage.Add(amount);
engine.SendNotification(Hash, "Transfer", new Array { StackItem.Null, account.ToArray(), amount });
}

Expand All @@ -90,9 +85,7 @@ internal protected virtual void Burn(ApplicationEngine engine, UInt160 account,
else
state.Balance -= amount;
storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply));
BigInteger totalSupply = new BigInteger(storage.Value);
totalSupply -= amount;
storage.Value = totalSupply.ToByteArrayStandard();
storage.Add(-amount);
engine.SendNotification(Hash, "Transfer", new Array { account.ToArray(), StackItem.Null, amount });
}

Expand All @@ -101,7 +94,7 @@ public virtual BigInteger TotalSupply(StoreView snapshot)
{
StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_TotalSupply));
if (storage is null) return BigInteger.Zero;
return new BigInteger(storage.Value);
return storage;
}

[ContractMethod(0_01000000, CallFlags.AllowStates)]
Expand Down