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 ID to ContractState #1400

Merged
merged 17 commits into from
Jan 27, 2020
Merged
37 changes: 37 additions & 0 deletions src/neo/Ledger/ContractIdState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Neo.IO;
using System;
using System.IO;

namespace Neo.Ledger
{
public class ContractIdState : ICloneable<ContractIdState>, ISerializable
{
public int NextId;

int ISerializable.Size => sizeof(int);

ContractIdState ICloneable<ContractIdState>.Clone()
{
return new ContractIdState
{
NextId = NextId
};
}

void ISerializable.Deserialize(BinaryReader reader)
{
NextId = reader.ReadInt32();
if (NextId < 0) throw new FormatException();
}

void ICloneable<ContractIdState>.FromReplica(ContractIdState replica)
{
NextId = replica.NextId;
}

void ISerializable.Serialize(BinaryWriter writer)
{
writer.Write(NextId);
}
}
}
16 changes: 7 additions & 9 deletions src/neo/Ledger/ContractState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace Neo.Ledger
{
public class ContractState : ICloneable<ContractState>, ISerializable, IInteroperable
{
public int Id;
public byte[] Script;
public ContractManifest Manifest;

Expand All @@ -31,52 +32,49 @@ public UInt160 ScriptHash
}
}

int ISerializable.Size => Script.GetVarSize() + Manifest.ToJson().ToString().GetVarSize();
int ISerializable.Size => sizeof(int) + Script.GetVarSize() + Manifest.ToJson().ToString().GetVarSize();

ContractState ICloneable<ContractState>.Clone()
{
return new ContractState
{
Id = Id,
Script = Script,
Manifest = Manifest.Clone()
};
}

void ISerializable.Deserialize(BinaryReader reader)
{
Id = reader.ReadInt32();
Script = reader.ReadVarBytes();
Manifest = reader.ReadSerializable<ContractManifest>();
}

void ICloneable<ContractState>.FromReplica(ContractState replica)
{
Id = replica.Id;
Script = replica.Script;
Manifest = replica.Manifest.Clone();
}

void ISerializable.Serialize(BinaryWriter writer)
{
writer.Write(Id);
writer.WriteVarBytes(Script);
writer.Write(Manifest);
}

public JObject ToJson()
{
shargon marked this conversation as resolved.
Show resolved Hide resolved
JObject json = new JObject();
json["id"] = Id;
json["hash"] = ScriptHash.ToString();
json["script"] = Convert.ToBase64String(Script);
json["manifest"] = Manifest.ToJson();
return json;
}

public static ContractState FromJson(JObject json)
{
ContractState contractState = new ContractState();
contractState.Script = Convert.FromBase64String(json["script"].AsString());
contractState.Manifest = ContractManifest.FromJson(json["manifest"]);
return contractState;
}

public StackItem ToStackItem(ReferenceCounter referenceCounter)
{
return new Array(referenceCounter, new StackItem[] { Script, HasStorage, Payable });
Expand Down
16 changes: 8 additions & 8 deletions src/neo/Ledger/StorageKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ namespace Neo.Ledger
{
public class StorageKey : IEquatable<StorageKey>, ISerializable
{
public UInt160 ScriptHash;
public int Id;
public byte[] Key;

int ISerializable.Size => ScriptHash.Size + (Key.Length / 16 + 1) * 17;
int ISerializable.Size => sizeof(int) + (Key.Length / 16 + 1) * 17;

internal static byte[] CreateSearchPrefix(UInt160 hash, byte[] prefix)
internal static byte[] CreateSearchPrefix(int id, byte[] prefix)
{
using (MemoryStream ms = new MemoryStream())
{
Expand All @@ -27,13 +27,13 @@ internal static byte[] CreateSearchPrefix(UInt160 hash, byte[] prefix)
}
if (remain > 0)
ms.Write(prefix, index, remain);
return Helper.Concat(hash.ToArray(), ms.ToArray());
return Helper.Concat(BitConverter.GetBytes(id), ms.ToArray());
}
}

void ISerializable.Deserialize(BinaryReader reader)
{
ScriptHash = reader.ReadSerializable<UInt160>();
Id = reader.ReadInt32();
Key = reader.ReadBytesWithGrouping();
}

Expand All @@ -43,7 +43,7 @@ public bool Equals(StorageKey other)
return false;
if (ReferenceEquals(this, other))
return true;
return ScriptHash.Equals(other.ScriptHash) && MemoryExtensions.SequenceEqual<byte>(Key, other.Key);
return Id == other.Id && MemoryExtensions.SequenceEqual<byte>(Key, other.Key);
}

public override bool Equals(object obj)
Expand All @@ -54,12 +54,12 @@ public override bool Equals(object obj)

public override int GetHashCode()
{
return ScriptHash.GetHashCode() + (int)Key.Murmur32(0);
return Id.GetHashCode() + (int)Key.Murmur32(0);
}

void ISerializable.Serialize(BinaryWriter writer)
{
writer.Write(ScriptHash);
writer.Write(Id);
writer.WriteBytesWithGrouping(Key);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/neo/Persistence/ClonedView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ internal class ClonedView : StoreView
public override DataCache<SerializableWrapper<uint>, HeaderHashList> HeaderHashList { get; }
public override MetaDataCache<HashIndexState> BlockHashIndex { get; }
public override MetaDataCache<HashIndexState> HeaderHashIndex { get; }
public override MetaDataCache<ContractIdState> ContractId { get; }

public ClonedView(StoreView view)
{
Expand All @@ -24,6 +25,7 @@ public ClonedView(StoreView view)
this.HeaderHashList = view.HeaderHashList.CreateSnapshot();
this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot();
this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot();
this.ContractId = view.ContractId.CreateSnapshot();
}
}
}
1 change: 1 addition & 0 deletions src/neo/Persistence/Prefixes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ internal static class Prefixes
public const byte IX_HeaderHashList = 0x80;
public const byte IX_CurrentBlock = 0xc0;
public const byte IX_CurrentHeader = 0xc1;
public const byte IX_ContractId = 0xc2;

/* Prefixes 0xf0 to 0xff are reserved for external use.
*
Expand Down
1 change: 1 addition & 0 deletions src/neo/Persistence/ReadOnlyView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class ReadOnlyView : StoreView
public override DataCache<SerializableWrapper<uint>, HeaderHashList> HeaderHashList => new StoreDataCache<SerializableWrapper<uint>, HeaderHashList>(store, Prefixes.IX_HeaderHashList);
public override MetaDataCache<HashIndexState> BlockHashIndex => new StoreMetaDataCache<HashIndexState>(store, Prefixes.IX_CurrentBlock);
public override MetaDataCache<HashIndexState> HeaderHashIndex => new StoreMetaDataCache<HashIndexState>(store, Prefixes.IX_CurrentHeader);
public override MetaDataCache<ContractIdState> ContractId => new StoreMetaDataCache<ContractIdState>(store, Prefixes.IX_ContractId);

public ReadOnlyView(IReadOnlyStore store)
{
Expand Down
2 changes: 2 additions & 0 deletions src/neo/Persistence/SnapshotView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class SnapshotView : StoreView, IDisposable
public override DataCache<SerializableWrapper<uint>, HeaderHashList> HeaderHashList { get; }
public override MetaDataCache<HashIndexState> BlockHashIndex { get; }
public override MetaDataCache<HashIndexState> HeaderHashIndex { get; }
public override MetaDataCache<ContractIdState> ContractId { get; }

public SnapshotView(IStore store)
{
Expand All @@ -30,6 +31,7 @@ public SnapshotView(IStore store)
HeaderHashList = new StoreDataCache<SerializableWrapper<uint>, HeaderHashList>(snapshot, Prefixes.IX_HeaderHashList);
BlockHashIndex = new StoreMetaDataCache<HashIndexState>(snapshot, Prefixes.IX_CurrentBlock);
HeaderHashIndex = new StoreMetaDataCache<HashIndexState>(snapshot, Prefixes.IX_CurrentHeader);
ContractId = new StoreMetaDataCache<ContractIdState>(snapshot, Prefixes.IX_ContractId);
}

public override void Commit()
Expand Down
2 changes: 2 additions & 0 deletions src/neo/Persistence/StoreView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public abstract class StoreView
public abstract DataCache<SerializableWrapper<uint>, HeaderHashList> HeaderHashList { get; }
public abstract MetaDataCache<HashIndexState> BlockHashIndex { get; }
public abstract MetaDataCache<HashIndexState> HeaderHashIndex { get; }
public abstract MetaDataCache<ContractIdState> ContractId { get; }

public uint Height => BlockHashIndex.Get().Index;
public uint HeaderHeight => HeaderHashIndex.Get().Index;
Expand All @@ -38,6 +39,7 @@ public virtual void Commit()
HeaderHashList.Commit();
BlockHashIndex.Commit();
HeaderHashIndex.Commit();
ContractId.Commit();
}

public bool ContainsBlock(UInt256 hash)
Expand Down
19 changes: 3 additions & 16 deletions src/neo/SmartContract/InteropService.Contract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ private static bool Contract_Create(ApplicationEngine engine)
if (contract != null) return false;
contract = new ContractState
{
Id = engine.Snapshot.ContractId.GetAndChange().NextId++,
Script = script,
Manifest = ContractManifest.Parse(manifest)
};
Expand Down Expand Up @@ -66,27 +67,13 @@ private static bool Contract_Update(ApplicationEngine engine)
if (engine.Snapshot.Contracts.TryGet(hash_new) != null) return false;
contract = new ContractState
{
Id = contract.Id,
Script = script,
Manifest = contract.Manifest
};
contract.Manifest.Abi.Hash = hash_new;
engine.Snapshot.Contracts.Add(hash_new, contract);
if (contract.HasStorage)
{
foreach (var (key, value) in engine.Snapshot.Storages.Find(engine.CurrentScriptHash.ToArray()).ToArray())
{
engine.Snapshot.Storages.Add(new StorageKey
{
ScriptHash = hash_new,
Key = key.Key
}, new StorageItem
{
Value = value.Value,
IsConstant = false
});
}
}
Contract_Destroy(engine);
engine.Snapshot.Contracts.Delete(engine.CurrentScriptHash);
shargon marked this conversation as resolved.
Show resolved Hide resolved
}
if (manifest.Length > 0)
{
Expand Down
1 change: 1 addition & 0 deletions src/neo/SmartContract/InteropService.Native.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ private static bool Native_Deploy(ApplicationEngine engine)
{
engine.Snapshot.Contracts.Add(contract.Hash, new ContractState
{
Id = contract.Id,
Script = contract.Script,
Manifest = contract.Manifest
});
Expand Down
32 changes: 13 additions & 19 deletions src/neo/SmartContract/InteropService.Storage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@ 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 bool CheckStorageContext(ApplicationEngine engine, StorageContext context)
{
ContractState contract = engine.Snapshot.Contracts.TryGet(context.ScriptHash);
if (contract == null) return false;
if (!contract.HasStorage) return false;
return true;
}

private static long GetStoragePrice(EvaluationStack stack)
{
return (stack.Peek(1).GetByteLength() + stack.Peek(2).GetByteLength()) * GasPerByte;
Expand All @@ -42,11 +34,10 @@ private static bool PutExInternal(ApplicationEngine engine, StorageContext conte
if (key.Length > MaxKeySize) return false;
if (value.Length > MaxValueSize) return false;
if (context.IsReadOnly) return false;
if (!CheckStorageContext(engine, context)) return false;

StorageKey skey = new StorageKey
{
ScriptHash = context.ScriptHash,
Id = context.Id,
Key = key
};

Expand All @@ -68,19 +59,25 @@ private static bool PutExInternal(ApplicationEngine engine, StorageContext conte

private static bool Storage_GetContext(ApplicationEngine engine)
{
ContractState contract = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash);
if (contract == null) return false;
if (!contract.HasStorage) return false;
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new StorageContext
{
ScriptHash = engine.CurrentScriptHash,
Id = contract.Id,
IsReadOnly = false
}));
return true;
}

private static bool Storage_GetReadOnlyContext(ApplicationEngine engine)
{
ContractState contract = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash);
if (contract == null) return false;
if (!contract.HasStorage) return false;
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new StorageContext
{
ScriptHash = engine.CurrentScriptHash,
Id = contract.Id,
IsReadOnly = true
}));
return true;
Expand All @@ -94,7 +91,7 @@ private static bool Storage_AsReadOnly(ApplicationEngine engine)
if (!context.IsReadOnly)
context = new StorageContext
{
ScriptHash = context.ScriptHash,
Id = context.Id,
IsReadOnly = true
};
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(context));
Expand All @@ -108,11 +105,10 @@ private static bool Storage_Get(ApplicationEngine engine)
if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)
{
StorageContext context = _interface.GetInterface<StorageContext>();
if (!CheckStorageContext(engine, context)) return false;
byte[] key = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray();
StorageItem item = engine.Snapshot.Storages.TryGet(new StorageKey
{
ScriptHash = context.ScriptHash,
Id = context.Id,
Key = key
});
engine.CurrentContext.EvaluationStack.Push(item?.Value ?? StackItem.Null);
Expand All @@ -126,9 +122,8 @@ private static bool Storage_Find(ApplicationEngine engine)
if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)
{
StorageContext context = _interface.GetInterface<StorageContext>();
if (!CheckStorageContext(engine, context)) return false;
byte[] prefix = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray();
byte[] prefix_key = StorageKey.CreateSearchPrefix(context.ScriptHash, prefix);
byte[] prefix_key = StorageKey.CreateSearchPrefix(context.Id, prefix);
StorageIterator iterator = engine.AddDisposable(new StorageIterator(engine.Snapshot.Storages.Find(prefix_key).Where(p => p.Key.Key.AsSpan().StartsWith(prefix)).GetEnumerator()));
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(iterator));
return true;
Expand Down Expand Up @@ -163,10 +158,9 @@ private static bool Storage_Delete(ApplicationEngine engine)
{
StorageContext context = _interface.GetInterface<StorageContext>();
if (context.IsReadOnly) return false;
if (!CheckStorageContext(engine, context)) return false;
StorageKey key = new StorageKey
{
ScriptHash = context.ScriptHash,
Id = context.Id,
Key = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray()
};
if (engine.Snapshot.Storages.TryGet(key)?.IsConstant == true) return false;
Expand Down
4 changes: 3 additions & 1 deletion src/neo/SmartContract/Native/NativeContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public abstract class NativeContract
{
private static readonly List<NativeContract> contracts = new List<NativeContract>();
private readonly Dictionary<string, ContractMethodMetadata> methods = new Dictionary<string, ContractMethodMetadata>();
private static int nextId = -1;

public static IReadOnlyCollection<NativeContract> Contracts { get; } = contracts;
public static NeoToken NEO { get; } = new NeoToken();
Expand All @@ -28,6 +29,7 @@ public abstract class NativeContract
public uint ServiceHash { get; }
public byte[] Script { get; }
public UInt160 Hash { get; }
public int Id { get; } = nextId--;
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
public ContractManifest Manifest { get; }
public virtual string[] SupportedStandards { get; } = { "NEP-10" };

Expand Down Expand Up @@ -71,7 +73,7 @@ protected StorageKey CreateStorageKey(byte prefix, byte[] key = null)
{
StorageKey storageKey = new StorageKey
{
ScriptHash = Hash,
Id = Id,
Key = new byte[sizeof(byte) + (key?.Length ?? 0)]
};
storageKey.Key[0] = prefix;
Expand Down
Loading