diff --git a/src/Neo/Network/P2P/Payloads/NotValidBefore.cs b/src/Neo/Network/P2P/Payloads/NotValidBefore.cs new file mode 100644 index 0000000000..e77693813b --- /dev/null +++ b/src/Neo/Network/P2P/Payloads/NotValidBefore.cs @@ -0,0 +1,46 @@ +using Neo.IO; +using Neo.Json; +using Neo.Persistence; +using Neo.SmartContract.Native; +using System.IO; + +namespace Neo.Network.P2P.Payloads +{ + public class NotValidBefore : TransactionAttribute + { + /// + /// Indicates that the transaction is not valid before this height. + /// + public uint Height; + + public override TransactionAttributeType Type => TransactionAttributeType.NotValidBefore; + + public override bool AllowMultiple => false; + + public override int Size => base.Size + + sizeof(uint); // Height. + + protected override void DeserializeWithoutType(ref MemoryReader reader) + { + Height = reader.ReadUInt32(); + } + + protected override void SerializeWithoutType(BinaryWriter writer) + { + writer.Write(Height); + } + + public override JObject ToJson() + { + JObject json = base.ToJson(); + json["height"] = Height; + return json; + } + + public override bool Verify(DataCache snapshot, Transaction tx) + { + var block_height = NativeContract.Ledger.CurrentIndex(snapshot); + return block_height >= Height; + } + } +} diff --git a/src/Neo/Network/P2P/Payloads/TransactionAttributeType.cs b/src/Neo/Network/P2P/Payloads/TransactionAttributeType.cs index bfda3f34ba..41c69b507d 100644 --- a/src/Neo/Network/P2P/Payloads/TransactionAttributeType.cs +++ b/src/Neo/Network/P2P/Payloads/TransactionAttributeType.cs @@ -27,6 +27,12 @@ public enum TransactionAttributeType : byte /// Indicates that the transaction is an oracle response. /// [ReflectionCache(typeof(OracleResponse))] - OracleResponse = 0x11 + OracleResponse = 0x11, + + /// + /// Indicates that the transaction is not valid before . + /// + [ReflectionCache(typeof(NotValidBefore))] + NotValidBefore = 0x20 } } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs new file mode 100644 index 0000000000..e47159d9ff --- /dev/null +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs @@ -0,0 +1,75 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract.Native; +using System; + +namespace Neo.UnitTests.Network.P2P.Payloads +{ + [TestClass] + public class UT_NotValidBefore + { + [TestMethod] + public void Size_Get() + { + var test = new NotValidBefore(); + test.Size.Should().Be(5); + } + + [TestMethod] + public void ToJson() + { + var test = new NotValidBefore(); + test.Height = 42; + var json = test.ToJson().ToString(); + Assert.AreEqual(@"{""type"":""NotValidBefore"",""height"":42}", json); + } + + [TestMethod] + public void DeserializeAndSerialize() + { + var test = new NotValidBefore(); + + var clone = test.ToArray().AsSerializable(); + Assert.AreEqual(clone.Type, test.Type); + + // As transactionAttribute + + byte[] buffer = test.ToArray(); + var reader = new MemoryReader(buffer); + clone = TransactionAttribute.DeserializeFrom(ref reader) as NotValidBefore; + Assert.AreEqual(clone.Type, test.Type); + + // Wrong type + + buffer[0] = 0xff; + reader = new MemoryReader(buffer); + try + { + TransactionAttribute.DeserializeFrom(ref reader); + Assert.Fail(); + } + catch (FormatException) { } + reader = new MemoryReader(buffer); + try + { + new NotValidBefore().Deserialize(ref reader); + Assert.Fail(); + } + catch (FormatException) { } + } + + [TestMethod] + public void Verify() + { + var test = new NotValidBefore(); + var snapshot = TestBlockchain.GetTestSnapshot(); + test.Height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; + + Assert.IsFalse(test.Verify(snapshot, new Transaction())); + test.Height--; + Assert.IsTrue(test.Verify(snapshot, new Transaction())); + } + } +}