-
Notifications
You must be signed in to change notification settings - Fork 1k
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 for recent on chain transaction hashes #1886
Changes from 3 commits
2810274
a6408b5
da3b82a
2bc11bc
4bd87af
bd92363
a037828
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace Neo.IO.Caching | ||
{ | ||
public class HashCache<T> where T : IEquatable<T> | ||
{ | ||
/// <summary> | ||
/// Sets where the Hashes are stored | ||
/// </summary> | ||
private readonly LinkedList<HashSet<T>> sets = new LinkedList<HashSet<T>>(); | ||
|
||
/// <summary> | ||
/// Maximum number of buckets for the LinkedList, meaning its maximum cardinality. | ||
/// </summary> | ||
private readonly int maxBucketCount; | ||
|
||
public int Depth => sets.Count; | ||
|
||
public HashCache(int maxBucketCount = 10) | ||
{ | ||
if (maxBucketCount <= 0) throw new ArgumentOutOfRangeException($"{nameof(maxBucketCount)} should be greater than 0"); | ||
|
||
this.maxBucketCount = maxBucketCount; | ||
sets.AddFirst(new HashSet<T>()); | ||
} | ||
|
||
public bool Add(T item) | ||
{ | ||
//if (Contains(item)) return false; | ||
return sets.First.Value.Add(item); | ||
} | ||
|
||
public bool Contains(T item) | ||
{ | ||
foreach (var set in sets) | ||
{ | ||
if (set.Contains(item)) return true; | ||
} | ||
return false; | ||
} | ||
|
||
public void Refresh() | ||
{ | ||
var newSet = new HashSet<T>(); | ||
sets.AddFirst(newSet); | ||
if (sets.Count > maxBucketCount) | ||
{ | ||
sets.RemoveLast(); | ||
} | ||
} | ||
|
||
public IEnumerator<T> GetEnumerator() | ||
{ | ||
foreach (var set in sets) | ||
{ | ||
foreach (var item in set) | ||
{ | ||
yield return item; | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ public class Transaction : IEquatable<Transaction>, IInventory, IInteroperable | |
private long sysfee; | ||
private long netfee; | ||
private uint validUntilBlock; | ||
private UInt256 lastBlockHash = UInt256.Zero; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If so, why not use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Such value can be forged by sender to make duplicate transactions onchain. |
||
private Signer[] _signers; | ||
private TransactionAttribute[] attributes; | ||
private byte[] script; | ||
|
@@ -40,7 +41,8 @@ public class Transaction : IEquatable<Transaction>, IInventory, IInteroperable | |
sizeof(uint) + //Nonce | ||
sizeof(long) + //SystemFee | ||
sizeof(long) + //NetworkFee | ||
sizeof(uint); //ValidUntilBlock | ||
sizeof(uint) + //ValidUntilBlock | ||
UInt256.Length; //LastBlockHash | ||
|
||
private Dictionary<Type, TransactionAttribute[]> _attributesCache; | ||
public TransactionAttribute[] Attributes | ||
|
@@ -135,6 +137,12 @@ public uint ValidUntilBlock | |
set { validUntilBlock = value; _hash = null; } | ||
} | ||
|
||
public UInt256 LastBlockHash | ||
{ | ||
get => lastBlockHash; | ||
set { lastBlockHash = value; _hash = null; } | ||
} | ||
|
||
public byte Version | ||
{ | ||
get => version; | ||
|
@@ -195,6 +203,7 @@ public void DeserializeUnsigned(BinaryReader reader) | |
if (NetworkFee < 0) throw new FormatException(); | ||
if (SystemFee + NetworkFee < SystemFee) throw new FormatException(); | ||
ValidUntilBlock = reader.ReadUInt32(); | ||
LastBlockHash = reader.ReadSerializable<UInt256>(); | ||
Signers = DeserializeSigners(reader, MaxTransactionAttributes).ToArray(); | ||
Attributes = DeserializeAttributes(reader, MaxTransactionAttributes - Signers.Length).ToArray(); | ||
Script = reader.ReadVarBytes(ushort.MaxValue); | ||
|
@@ -253,6 +262,7 @@ void IVerifiable.SerializeUnsigned(BinaryWriter writer) | |
writer.Write(SystemFee); | ||
writer.Write(NetworkFee); | ||
writer.Write(ValidUntilBlock); | ||
writer.Write(LastBlockHash); | ||
writer.Write(Signers); | ||
writer.Write(Attributes); | ||
writer.WriteVarBytes(Script); | ||
|
@@ -269,6 +279,7 @@ public JObject ToJson() | |
json["sysfee"] = SystemFee.ToString(); | ||
json["netfee"] = NetworkFee.ToString(); | ||
json["validuntilblock"] = ValidUntilBlock; | ||
json["lastblockhash"] = LastBlockHash.ToString(); | ||
json["signers"] = Signers.Select(p => p.ToJson()).ToArray(); | ||
json["attributes"] = Attributes.Select(p => p.ToJson()).ToArray(); | ||
json["script"] = Convert.ToBase64String(Script); | ||
|
@@ -285,6 +296,8 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, Transaction | |
{ | ||
if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) | ||
return VerifyResult.Expired; | ||
if (snapshot.GetBlock(LastBlockHash)?.Index != ValidUntilBlock - MaxValidUntilBlockIncrement) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Qiao-Jin, shouldn't it be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? This |
||
return VerifyResult.Invalid; | ||
UInt160[] hashes = GetScriptHashesForVerifying(snapshot); | ||
if (NativeContract.Policy.IsAnyAccountBlocked(snapshot, hashes)) | ||
return VerifyResult.PolicyFail; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not https://github.com/Qiao-Jin/neo/blob/da3b82a9ae958689f49847cc2a89d4eabc22695e/src/neo/IO/Caching/HashSetCache.cs ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic is somehow different, i.e. don't need a
bucketCapacity
, don't want to checkContains
upon adding as has been checked before inBlockchain.OnTransaction
, etc.