diff --git a/src/Neo/Persistence/IReadOnlyStore.cs b/src/Neo/Persistence/IReadOnlyStore.cs
index 4b6c3fe0ec..e52ccbb7c3 100644
--- a/src/Neo/Persistence/IReadOnlyStore.cs
+++ b/src/Neo/Persistence/IReadOnlyStore.cs
@@ -9,6 +9,7 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
+using System;
using System.Collections.Generic;
namespace Neo.Persistence
@@ -31,8 +32,17 @@ public interface IReadOnlyStore
///
/// The key of the entry.
/// The data of the entry. Or if it doesn't exist.
+ /// . Obsolete it later for avoiding complier warning.
byte[] TryGet(byte[] key);
+ ///
+ /// Reads a specified entry from the database.
+ ///
+ /// The key of the entry.
+ /// The data of the entry.
+ /// if the entry exists; otherwise, .
+ bool TryGet(byte[] key, out byte[] value);
+
///
/// Determines whether the database contains the specified entry.
///
diff --git a/src/Neo/Persistence/MemorySnapshot.cs b/src/Neo/Persistence/MemorySnapshot.cs
index 096431552c..b3d06798d4 100644
--- a/src/Neo/Persistence/MemorySnapshot.cs
+++ b/src/Neo/Persistence/MemorySnapshot.cs
@@ -69,6 +69,11 @@ public byte[] TryGet(byte[] key)
return value?[..];
}
+ public bool TryGet(byte[] key, out byte[] value)
+ {
+ return immutableData.TryGetValue(key, out value);
+ }
+
public bool Contains(byte[] key)
{
return immutableData.ContainsKey(key);
diff --git a/src/Neo/Persistence/MemoryStore.cs b/src/Neo/Persistence/MemoryStore.cs
index 191b89ea4f..378d5374f1 100644
--- a/src/Neo/Persistence/MemoryStore.cs
+++ b/src/Neo/Persistence/MemoryStore.cs
@@ -66,6 +66,12 @@ public byte[] TryGet(byte[] key)
return value[..];
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool TryGet(byte[] key, out byte[] value)
+ {
+ return _innerData.TryGetValue(key, out value);
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains(byte[] key)
{
diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs b/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs
index 0b0a63b885..f66164285b 100644
--- a/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs
+++ b/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs
@@ -65,5 +65,11 @@ public byte[] TryGet(byte[] key)
{
return db.Get(options, key);
}
+
+ public bool TryGet(byte[] key, out byte[] value)
+ {
+ value = db.Get(options, key);
+ return value != null;
+ }
}
}
diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs
index 27b12a8b64..175b71a8fe 100644
--- a/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs
+++ b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs
@@ -63,5 +63,11 @@ public byte[] TryGet(byte[] key)
{
return db.Get(ReadOptions.Default, key);
}
+
+ public bool TryGet(byte[] key, out byte[] value)
+ {
+ value = db.Get(ReadOptions.Default, key);
+ return value != null;
+ }
}
}
diff --git a/src/Plugins/RocksDBStore/Plugins/Storage/Snapshot.cs b/src/Plugins/RocksDBStore/Plugins/Storage/Snapshot.cs
index 7423f6ae4a..4da29e41fe 100644
--- a/src/Plugins/RocksDBStore/Plugins/Storage/Snapshot.cs
+++ b/src/Plugins/RocksDBStore/Plugins/Storage/Snapshot.cs
@@ -73,6 +73,12 @@ public byte[] TryGet(byte[] key)
return db.Get(key, readOptions: options);
}
+ public bool TryGet(byte[] key, out byte[] value)
+ {
+ value = db.Get(key, readOptions: options);
+ return value != null;
+ }
+
public void Dispose()
{
snapshot.Dispose();
diff --git a/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs b/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs
index ebf160dab0..3f8121ca07 100644
--- a/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs
+++ b/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs
@@ -59,6 +59,12 @@ public byte[] TryGet(byte[] key)
return db.Get(key);
}
+ public bool TryGet(byte[] key, out byte[] value)
+ {
+ value = db.Get(key);
+ return value != null;
+ }
+
public void Delete(byte[] key)
{
db.Remove(key);
diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs
index 2e53456545..d7fcb92775 100644
--- a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs
+++ b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs
@@ -52,6 +52,11 @@ public byte[] TryGet(byte[] key)
return null;
}
+ public bool TryGet(byte[] key, out byte[] value)
+ {
+ return store.TryGetValue(StoreKey(key), out value);
+ }
+
public void Dispose() { throw new System.NotImplementedException(); }
public int Size => store.Count;
diff --git a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs
index 189e212bc2..ed44faab53 100644
--- a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs
+++ b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs
@@ -85,6 +85,8 @@ public void TestLevelDbSnapshot()
snapshot.Put(testKey, testValue);
// Data saved to the leveldb snapshot shall not be visible to the store
Assert.IsNull(snapshot.TryGet(testKey));
+ Assert.IsFalse(snapshot.TryGet(testKey, out var got));
+ Assert.IsNull(got);
// Value is in the write batch, not visible to the store and snapshot
Assert.AreEqual(false, snapshot.Contains(testKey));
@@ -94,7 +96,13 @@ public void TestLevelDbSnapshot()
// After commit, the data shall be visible to the store but not to the snapshot
Assert.IsNull(snapshot.TryGet(testKey));
+ Assert.IsFalse(snapshot.TryGet(testKey, out got));
+ Assert.IsNull(got);
+
CollectionAssert.AreEqual(testValue, store.TryGet(testKey));
+ Assert.IsTrue(store.TryGet(testKey, out got));
+ CollectionAssert.AreEqual(testValue, got);
+
Assert.AreEqual(false, snapshot.Contains(testKey));
Assert.AreEqual(true, store.Contains(testKey));
@@ -154,7 +162,12 @@ public void TestRocksDbSnapshot()
snapshot.Put(testKey, testValue);
// Data saved to the leveldb snapshot shall not be visible
Assert.IsNull(snapshot.TryGet(testKey));
+ Assert.IsFalse(snapshot.TryGet(testKey, out var got));
+ Assert.IsNull(got);
+
Assert.IsNull(store.TryGet(testKey));
+ Assert.IsFalse(store.TryGet(testKey, out got));
+ Assert.IsNull(got);
// Value is in the write batch, not visible to the store and snapshot
Assert.AreEqual(false, snapshot.Contains(testKey));
@@ -164,7 +177,13 @@ public void TestRocksDbSnapshot()
// After commit, the data shall be visible to the store but not to the snapshot
Assert.IsNull(snapshot.TryGet(testKey));
+ Assert.IsFalse(snapshot.TryGet(testKey, out got));
+ Assert.IsNull(got);
+
CollectionAssert.AreEqual(testValue, store.TryGet(testKey));
+ Assert.IsTrue(store.TryGet(testKey, out got));
+ CollectionAssert.AreEqual(testValue, got);
+
Assert.AreEqual(false, snapshot.Contains(testKey));
Assert.AreEqual(true, store.Contains(testKey));
diff --git a/tests/Neo.UnitTests/Persistence/UT_MemorySnapshot.cs b/tests/Neo.UnitTests/Persistence/UT_MemorySnapshot.cs
index 629e2bc374..8eea33c9a7 100644
--- a/tests/Neo.UnitTests/Persistence/UT_MemorySnapshot.cs
+++ b/tests/Neo.UnitTests/Persistence/UT_MemorySnapshot.cs
@@ -97,6 +97,14 @@ public void MultiSnapshotTest()
Assert.IsNull(_snapshot.TryGet(key1));
CollectionAssert.AreEqual(value1, snapshot2.TryGet(key1));
+ Assert.IsFalse(_snapshot.TryGet(key1, out var value2));
+
+ Assert.IsTrue(snapshot2.TryGet(key1, out value2));
+ CollectionAssert.AreEqual(value1, value2);
+
+ Assert.IsTrue(_memoryStore.TryGet(key1, out value2));
+ CollectionAssert.AreEqual(value1, value2);
+
_snapshot.Delete(key1);
// Deleted value can not being found from the snapshot but can still get from the store and snapshot2
diff --git a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs
index 133d9eb66c..4473ae63a8 100644
--- a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs
+++ b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs
@@ -51,6 +51,9 @@ public void StoreTest()
store.Delete([1]);
Assert.AreEqual(null, store.TryGet([1]));
+ Assert.IsFalse(store.TryGet([1], out var got));
+ Assert.AreEqual(null, got);
+
store.Put([1], [1, 2, 3]);
CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, store.TryGet([1]));
@@ -79,13 +82,18 @@ public void NeoSystemStoreViewTest()
var store = _neoSystem.StoreView;
var key = new StorageKey(Encoding.UTF8.GetBytes("testKey"));
var value = new StorageItem(Encoding.UTF8.GetBytes("testValue"));
+
store.Add(key, value);
store.Commit();
+
var result = store.TryGet(key);
// The StoreView is a readonly view of the store, here it will have value in the cache
Assert.AreEqual("testValue", Encoding.UTF8.GetString(result.Value.ToArray()));
- // But the value will not be written to the underlying store even its committed.
+
+ // But the value will not be written to the underlying store even its committed.
Assert.IsNull(_memoryStore.TryGet(key.ToArray()));
+ Assert.IsFalse(_memoryStore.TryGet(key.ToArray(), out var got));
+ Assert.AreEqual(null, got);
}
[TestMethod]