Skip to content

Commit

Permalink
Add cache to native contract executions V2 (neo-project#1766)
Browse files Browse the repository at this point in the history
* cache v2

* More optimizations

* Policy contract optimization

* Remove interporable variable

* Two more

* Add Set

* Optimizations

* Optimize

Co-authored-by: erikzhang <erik@neo.org>
  • Loading branch information
shargon and erikzhang authored Jul 17, 2020
1 parent 6c01017 commit da6be43
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 49 deletions.
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

0 comments on commit da6be43

Please sign in to comment.