From 0e11137281ecd9380eaf05e6b3ee4c3b89a5b973 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sat, 21 Mar 2020 21:08:48 +0800 Subject: [PATCH 1/6] Remove some SYSCALLs --- src/neo/Network/P2P/Payloads/Block.cs | 26 +------ .../InteropService.Blockchain.cs | 75 ------------------- .../SmartContract/UT_InteropService.cs | 48 ------------ .../SmartContract/UT_Syscalls.cs | 74 ------------------ 4 files changed, 1 insertion(+), 222 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Block.cs b/src/neo/Network/P2P/Payloads/Block.cs index a3623a4c94..c4ae1b191d 100644 --- a/src/neo/Network/P2P/Payloads/Block.cs +++ b/src/neo/Network/P2P/Payloads/Block.cs @@ -2,18 +2,14 @@ using Neo.IO; using Neo.IO.Json; using Neo.Ledger; -using Neo.SmartContract; -using Neo.VM; -using Neo.VM.Types; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using Array = Neo.VM.Types.Array; namespace Neo.Network.P2P.Payloads { - public class Block : BlockBase, IInventory, IEquatable, IInteroperable + public class Block : BlockBase, IInventory, IEquatable { public const int MaxContentsPerBlock = ushort.MaxValue; public const int MaxTransactionsPerBlock = MaxContentsPerBlock - 1; @@ -133,25 +129,5 @@ public TrimmedBlock Trim() ConsensusData = ConsensusData }; } - - public StackItem ToStackItem(ReferenceCounter referenceCounter) - { - return new Array(referenceCounter, new StackItem[] - { - // Computed properties - Hash.ToArray(), - - // BlockBase properties - Version, - PrevHash.ToArray(), - MerkleRoot.ToArray(), - Timestamp, - Index, - NextConsensus.ToArray(), - - // Block properties - Transactions.Length - }); - } } } diff --git a/src/neo/SmartContract/InteropService.Blockchain.cs b/src/neo/SmartContract/InteropService.Blockchain.cs index b31aba4a32..ed1bd183b3 100644 --- a/src/neo/SmartContract/InteropService.Blockchain.cs +++ b/src/neo/SmartContract/InteropService.Blockchain.cs @@ -1,9 +1,6 @@ using Neo.Ledger; -using Neo.Network.P2P.Payloads; using Neo.VM; using Neo.VM.Types; -using System; -using System.Numerics; namespace Neo.SmartContract { @@ -12,10 +9,6 @@ partial class InteropService public static class Blockchain { public static readonly InteropDescriptor GetHeight = Register("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application, CallFlags.None); - public static readonly InteropDescriptor GetBlock = Register("System.Blockchain.GetBlock", Blockchain_GetBlock, 0_02500000, TriggerType.Application, CallFlags.None); - public static readonly InteropDescriptor GetTransaction = Register("System.Blockchain.GetTransaction", Blockchain_GetTransaction, 0_01000000, TriggerType.Application, CallFlags.None); - public static readonly InteropDescriptor GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", Blockchain_GetTransactionHeight, 0_01000000, TriggerType.Application, CallFlags.None); - public static readonly InteropDescriptor GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", Blockchain_GetTransactionFromBlock, 0_01000000, TriggerType.Application, CallFlags.None); public static readonly InteropDescriptor GetContract = Register("System.Blockchain.GetContract", Blockchain_GetContract, 0_01000000, TriggerType.Application, CallFlags.None); private static bool Blockchain_GetHeight(ApplicationEngine engine) @@ -24,74 +17,6 @@ private static bool Blockchain_GetHeight(ApplicationEngine engine) return true; } - private static bool Blockchain_GetBlock(ApplicationEngine engine) - { - ReadOnlySpan data = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - UInt256 hash; - if (data.Length <= 5) - hash = Ledger.Blockchain.Singleton.GetBlockHash((uint)new BigInteger(data)); - else if (data.Length == 32) - hash = new UInt256(data); - else - return false; - - Block block = hash != null ? engine.Snapshot.GetBlock(hash) : null; - if (block == null) - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - else - engine.CurrentContext.EvaluationStack.Push(block.ToStackItem(engine.ReferenceCounter)); - return true; - } - - private static bool Blockchain_GetTransaction(ApplicationEngine engine) - { - ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - Transaction tx = engine.Snapshot.GetTransaction(new UInt256(hash)); - if (tx == null) - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - else - engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem(engine.ReferenceCounter)); - return true; - } - - private static bool Blockchain_GetTransactionHeight(ApplicationEngine engine) - { - ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - var tx = engine.Snapshot.Transactions.TryGet(new UInt256(hash)); - engine.CurrentContext.EvaluationStack.Push(tx != null ? new BigInteger(tx.BlockIndex) : BigInteger.MinusOne); - return true; - } - - private static bool Blockchain_GetTransactionFromBlock(ApplicationEngine engine) - { - ReadOnlySpan data = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - UInt256 hash; - if (data.Length <= 5) - hash = Ledger.Blockchain.Singleton.GetBlockHash((uint)new BigInteger(data)); - else if (data.Length == 32) - hash = new UInt256(data); - else - return false; - - TrimmedBlock block = hash != null ? engine.Snapshot.Blocks.TryGet(hash) : null; - if (block == null) - { - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - } - else - { - int index = (int)engine.CurrentContext.EvaluationStack.Pop().GetBigInteger(); - if (index < 0 || index >= block.Hashes.Length - 1) return false; - - Transaction tx = engine.Snapshot.GetTransaction(block.Hashes[index + 1]); - if (tx == null) - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - else - engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem(engine.ReferenceCounter)); - } - return true; - } - private static bool Blockchain_GetContract(ApplicationEngine engine) { UInt160 hash = new UInt160(engine.CurrentContext.EvaluationStack.Pop().GetSpan()); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index fb8d668c10..0e35b702f6 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -402,54 +402,6 @@ public void TestBlockchain_GetHeight() engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(0); } - [TestMethod] - public void TestBlockchain_GetBlock() - { - var engine = GetEngine(true, true); - - engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); - InteropService.Invoke(engine, InteropService.Blockchain.GetBlock).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().Should().Be(StackItem.Null); - - byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; - engine.CurrentContext.EvaluationStack.Push(data1); - InteropService.Invoke(engine, InteropService.Blockchain.GetBlock).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); - - byte[] data2 = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; - engine.CurrentContext.EvaluationStack.Push(data2); - InteropService.Invoke(engine, InteropService.Blockchain.GetBlock).Should().BeFalse(); - } - - [TestMethod] - public void TestBlockchain_GetTransaction() - { - var engine = GetEngine(true, true); - byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; - engine.CurrentContext.EvaluationStack.Push(data1); - InteropService.Invoke(engine, InteropService.Blockchain.GetTransaction).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); - } - - [TestMethod] - public void TestBlockchain_GetTransactionHeight() - { - var engine = GetEngine(true, true); - byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; - engine.CurrentContext.EvaluationStack.Push(data1); - InteropService.Invoke(engine, InteropService.Blockchain.GetTransactionHeight).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(-1); - } - [TestMethod] public void TestBlockchain_GetContract() { diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 04f60db7ff..486847a601 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -18,80 +18,6 @@ public void TestSetup() TestBlockchain.InitializeMockNeoSystem(); } - [TestMethod] - public void System_Blockchain_GetBlock() - { - var tx = new Transaction() - { - Script = new byte[] { 0x01 }, - Attributes = new TransactionAttribute[0], - Cosigners = new Cosigner[0], - NetworkFee = 0x02, - SystemFee = 0x03, - Nonce = 0x04, - ValidUntilBlock = 0x05, - Version = 0x06, - Witnesses = new Witness[] { new Witness() { VerificationScript = new byte[] { 0x07 } } }, - Sender = UInt160.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), - }; - - var block = new Block() - { - Index = 1, - Timestamp = 2, - Version = 3, - Witness = new Witness() - { - InvocationScript = new byte[0], - VerificationScript = new byte[0] - }, - PrevHash = UInt256.Zero, - MerkleRoot = UInt256.Zero, - NextConsensus = UInt160.Zero, - ConsensusData = new ConsensusData() { Nonce = 1, PrimaryIndex = 1 }, - Transactions = new Transaction[] { tx } - }; - - var snapshot = Blockchain.Singleton.GetSnapshot(); - - using (var script = new ScriptBuilder()) - { - script.EmitPush(block.Hash.ToArray()); - script.EmitSysCall(InteropService.Blockchain.GetBlock); - - // Without block - - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); - engine.LoadScript(script.ToArray()); - - Assert.AreEqual(engine.Execute(), VMState.HALT); - Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsTrue(engine.ResultStack.Peek().IsNull); - - // With block - - var blocks = snapshot.Blocks; - var txs = snapshot.Transactions; - blocks.Add(block.Hash, block.Trim()); - txs.Add(tx.Hash, new TransactionState() { Transaction = tx, BlockIndex = block.Index, VMState = VMState.HALT }); - - script.EmitSysCall(InteropService.Json.Serialize); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); - engine.LoadScript(script.ToArray()); - - Assert.AreEqual(engine.Execute(), VMState.HALT); - Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(ByteArray)); - Assert.AreEqual(engine.ResultStack.Pop().GetSpan().ToHexString(), - "5b22556168352f4b6f446d39723064555950636353714346745a30594f726b583164646e7334366e676e3962383d222c332c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c322c312c224141414141414141414141414141414141414141414141414141413d222c315d"); - Assert.AreEqual(0, engine.ResultStack.Count); - - // Clean - blocks.Delete(block.Hash); - txs.Delete(tx.Hash); - } - } - [TestMethod] public void Json_Deserialize() { From 904741d6950166299920c0458b897f9f550ca1f2 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sun, 22 Mar 2020 12:10:04 +0800 Subject: [PATCH 2/6] Revert "Remove some SYSCALLs" This reverts commit 0e11137281ecd9380eaf05e6b3ee4c3b89a5b973. --- src/neo/Network/P2P/Payloads/Block.cs | 26 ++++++- .../InteropService.Blockchain.cs | 75 +++++++++++++++++++ .../SmartContract/UT_InteropService.cs | 48 ++++++++++++ .../SmartContract/UT_Syscalls.cs | 74 ++++++++++++++++++ 4 files changed, 222 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Block.cs b/src/neo/Network/P2P/Payloads/Block.cs index c4ae1b191d..a3623a4c94 100644 --- a/src/neo/Network/P2P/Payloads/Block.cs +++ b/src/neo/Network/P2P/Payloads/Block.cs @@ -2,14 +2,18 @@ using Neo.IO; using Neo.IO.Json; using Neo.Ledger; +using Neo.SmartContract; +using Neo.VM; +using Neo.VM.Types; using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Array = Neo.VM.Types.Array; namespace Neo.Network.P2P.Payloads { - public class Block : BlockBase, IInventory, IEquatable + public class Block : BlockBase, IInventory, IEquatable, IInteroperable { public const int MaxContentsPerBlock = ushort.MaxValue; public const int MaxTransactionsPerBlock = MaxContentsPerBlock - 1; @@ -129,5 +133,25 @@ public TrimmedBlock Trim() ConsensusData = ConsensusData }; } + + public StackItem ToStackItem(ReferenceCounter referenceCounter) + { + return new Array(referenceCounter, new StackItem[] + { + // Computed properties + Hash.ToArray(), + + // BlockBase properties + Version, + PrevHash.ToArray(), + MerkleRoot.ToArray(), + Timestamp, + Index, + NextConsensus.ToArray(), + + // Block properties + Transactions.Length + }); + } } } diff --git a/src/neo/SmartContract/InteropService.Blockchain.cs b/src/neo/SmartContract/InteropService.Blockchain.cs index ed1bd183b3..b31aba4a32 100644 --- a/src/neo/SmartContract/InteropService.Blockchain.cs +++ b/src/neo/SmartContract/InteropService.Blockchain.cs @@ -1,6 +1,9 @@ using Neo.Ledger; +using Neo.Network.P2P.Payloads; using Neo.VM; using Neo.VM.Types; +using System; +using System.Numerics; namespace Neo.SmartContract { @@ -9,6 +12,10 @@ partial class InteropService public static class Blockchain { public static readonly InteropDescriptor GetHeight = Register("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application, CallFlags.None); + public static readonly InteropDescriptor GetBlock = Register("System.Blockchain.GetBlock", Blockchain_GetBlock, 0_02500000, TriggerType.Application, CallFlags.None); + public static readonly InteropDescriptor GetTransaction = Register("System.Blockchain.GetTransaction", Blockchain_GetTransaction, 0_01000000, TriggerType.Application, CallFlags.None); + public static readonly InteropDescriptor GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", Blockchain_GetTransactionHeight, 0_01000000, TriggerType.Application, CallFlags.None); + public static readonly InteropDescriptor GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", Blockchain_GetTransactionFromBlock, 0_01000000, TriggerType.Application, CallFlags.None); public static readonly InteropDescriptor GetContract = Register("System.Blockchain.GetContract", Blockchain_GetContract, 0_01000000, TriggerType.Application, CallFlags.None); private static bool Blockchain_GetHeight(ApplicationEngine engine) @@ -17,6 +24,74 @@ private static bool Blockchain_GetHeight(ApplicationEngine engine) return true; } + private static bool Blockchain_GetBlock(ApplicationEngine engine) + { + ReadOnlySpan data = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); + UInt256 hash; + if (data.Length <= 5) + hash = Ledger.Blockchain.Singleton.GetBlockHash((uint)new BigInteger(data)); + else if (data.Length == 32) + hash = new UInt256(data); + else + return false; + + Block block = hash != null ? engine.Snapshot.GetBlock(hash) : null; + if (block == null) + engine.CurrentContext.EvaluationStack.Push(StackItem.Null); + else + engine.CurrentContext.EvaluationStack.Push(block.ToStackItem(engine.ReferenceCounter)); + return true; + } + + private static bool Blockchain_GetTransaction(ApplicationEngine engine) + { + ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); + Transaction tx = engine.Snapshot.GetTransaction(new UInt256(hash)); + if (tx == null) + engine.CurrentContext.EvaluationStack.Push(StackItem.Null); + else + engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem(engine.ReferenceCounter)); + return true; + } + + private static bool Blockchain_GetTransactionHeight(ApplicationEngine engine) + { + ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); + var tx = engine.Snapshot.Transactions.TryGet(new UInt256(hash)); + engine.CurrentContext.EvaluationStack.Push(tx != null ? new BigInteger(tx.BlockIndex) : BigInteger.MinusOne); + return true; + } + + private static bool Blockchain_GetTransactionFromBlock(ApplicationEngine engine) + { + ReadOnlySpan data = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); + UInt256 hash; + if (data.Length <= 5) + hash = Ledger.Blockchain.Singleton.GetBlockHash((uint)new BigInteger(data)); + else if (data.Length == 32) + hash = new UInt256(data); + else + return false; + + TrimmedBlock block = hash != null ? engine.Snapshot.Blocks.TryGet(hash) : null; + if (block == null) + { + engine.CurrentContext.EvaluationStack.Push(StackItem.Null); + } + else + { + int index = (int)engine.CurrentContext.EvaluationStack.Pop().GetBigInteger(); + if (index < 0 || index >= block.Hashes.Length - 1) return false; + + Transaction tx = engine.Snapshot.GetTransaction(block.Hashes[index + 1]); + if (tx == null) + engine.CurrentContext.EvaluationStack.Push(StackItem.Null); + else + engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem(engine.ReferenceCounter)); + } + return true; + } + private static bool Blockchain_GetContract(ApplicationEngine engine) { UInt160 hash = new UInt160(engine.CurrentContext.EvaluationStack.Pop().GetSpan()); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 0e35b702f6..fb8d668c10 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -402,6 +402,54 @@ public void TestBlockchain_GetHeight() engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(0); } + [TestMethod] + public void TestBlockchain_GetBlock() + { + var engine = GetEngine(true, true); + + engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); + InteropService.Invoke(engine, InteropService.Blockchain.GetBlock).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().Should().Be(StackItem.Null); + + byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + engine.CurrentContext.EvaluationStack.Push(data1); + InteropService.Invoke(engine, InteropService.Blockchain.GetBlock).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); + + byte[] data2 = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; + engine.CurrentContext.EvaluationStack.Push(data2); + InteropService.Invoke(engine, InteropService.Blockchain.GetBlock).Should().BeFalse(); + } + + [TestMethod] + public void TestBlockchain_GetTransaction() + { + var engine = GetEngine(true, true); + byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + engine.CurrentContext.EvaluationStack.Push(data1); + InteropService.Invoke(engine, InteropService.Blockchain.GetTransaction).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); + } + + [TestMethod] + public void TestBlockchain_GetTransactionHeight() + { + var engine = GetEngine(true, true); + byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + engine.CurrentContext.EvaluationStack.Push(data1); + InteropService.Invoke(engine, InteropService.Blockchain.GetTransactionHeight).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(-1); + } + [TestMethod] public void TestBlockchain_GetContract() { diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 486847a601..04f60db7ff 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -18,6 +18,80 @@ public void TestSetup() TestBlockchain.InitializeMockNeoSystem(); } + [TestMethod] + public void System_Blockchain_GetBlock() + { + var tx = new Transaction() + { + Script = new byte[] { 0x01 }, + Attributes = new TransactionAttribute[0], + Cosigners = new Cosigner[0], + NetworkFee = 0x02, + SystemFee = 0x03, + Nonce = 0x04, + ValidUntilBlock = 0x05, + Version = 0x06, + Witnesses = new Witness[] { new Witness() { VerificationScript = new byte[] { 0x07 } } }, + Sender = UInt160.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + }; + + var block = new Block() + { + Index = 1, + Timestamp = 2, + Version = 3, + Witness = new Witness() + { + InvocationScript = new byte[0], + VerificationScript = new byte[0] + }, + PrevHash = UInt256.Zero, + MerkleRoot = UInt256.Zero, + NextConsensus = UInt160.Zero, + ConsensusData = new ConsensusData() { Nonce = 1, PrimaryIndex = 1 }, + Transactions = new Transaction[] { tx } + }; + + var snapshot = Blockchain.Singleton.GetSnapshot(); + + using (var script = new ScriptBuilder()) + { + script.EmitPush(block.Hash.ToArray()); + script.EmitSysCall(InteropService.Blockchain.GetBlock); + + // Without block + + var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine.LoadScript(script.ToArray()); + + Assert.AreEqual(engine.Execute(), VMState.HALT); + Assert.AreEqual(1, engine.ResultStack.Count); + Assert.IsTrue(engine.ResultStack.Peek().IsNull); + + // With block + + var blocks = snapshot.Blocks; + var txs = snapshot.Transactions; + blocks.Add(block.Hash, block.Trim()); + txs.Add(tx.Hash, new TransactionState() { Transaction = tx, BlockIndex = block.Index, VMState = VMState.HALT }); + + script.EmitSysCall(InteropService.Json.Serialize); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine.LoadScript(script.ToArray()); + + Assert.AreEqual(engine.Execute(), VMState.HALT); + Assert.AreEqual(1, engine.ResultStack.Count); + Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(ByteArray)); + Assert.AreEqual(engine.ResultStack.Pop().GetSpan().ToHexString(), + "5b22556168352f4b6f446d39723064555950636353714346745a30594f726b583164646e7334366e676e3962383d222c332c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c322c312c224141414141414141414141414141414141414141414141414141413d222c315d"); + Assert.AreEqual(0, engine.ResultStack.Count); + + // Clean + blocks.Delete(block.Hash); + txs.Delete(tx.Hash); + } + } + [TestMethod] public void Json_Deserialize() { From 7b2e1299b393e6312ac2b8c24ef269e93cf8998c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sun, 22 Mar 2020 20:50:28 +0800 Subject: [PATCH 3/6] Limit the max height for SYSCALLs --- .../InteropService.Blockchain.cs | 68 ++++++++++--------- src/neo/neo.csproj | 2 +- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/neo/SmartContract/InteropService.Blockchain.cs b/src/neo/SmartContract/InteropService.Blockchain.cs index b31aba4a32..4eb4e24f1b 100644 --- a/src/neo/SmartContract/InteropService.Blockchain.cs +++ b/src/neo/SmartContract/InteropService.Blockchain.cs @@ -11,6 +11,8 @@ partial class InteropService { public static class Blockchain { + private const uint MaxTraceableBlocks = Transaction.MaxValidUntilBlockIncrement; + public static readonly InteropDescriptor GetHeight = Register("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application, CallFlags.None); public static readonly InteropDescriptor GetBlock = Register("System.Blockchain.GetBlock", Blockchain_GetBlock, 0_02500000, TriggerType.Application, CallFlags.None); public static readonly InteropDescriptor GetTransaction = Register("System.Blockchain.GetTransaction", Blockchain_GetTransaction, 0_01000000, TriggerType.Application, CallFlags.None); @@ -26,68 +28,72 @@ private static bool Blockchain_GetHeight(ApplicationEngine engine) private static bool Blockchain_GetBlock(ApplicationEngine engine) { - ReadOnlySpan data = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); UInt256 hash; - if (data.Length <= 5) - hash = Ledger.Blockchain.Singleton.GetBlockHash((uint)new BigInteger(data)); - else if (data.Length == 32) + if (engine.TryPop(out uint height)) + { + hash = Ledger.Blockchain.Singleton.GetBlockHash(height); + } + else if (engine.TryPop(out ReadOnlySpan data)) + { + if (data.Length != 32) return false; hash = new UInt256(data); + } else + { return false; - + } Block block = hash != null ? engine.Snapshot.GetBlock(hash) : null; - if (block == null) - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - else - engine.CurrentContext.EvaluationStack.Push(block.ToStackItem(engine.ReferenceCounter)); + if (block?.Index <= engine.Snapshot.Height - MaxTraceableBlocks) block = null; + engine.Push(block?.ToStackItem(engine.ReferenceCounter) ?? StackItem.Null); return true; } private static bool Blockchain_GetTransaction(ApplicationEngine engine) { - ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - Transaction tx = engine.Snapshot.GetTransaction(new UInt256(hash)); - if (tx == null) - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - else - engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem(engine.ReferenceCounter)); + if (!engine.TryPop(out ReadOnlySpan hash)) return false; + TransactionState state = engine.Snapshot.Transactions.TryGet(new UInt256(hash)); + if (state?.BlockIndex <= engine.Snapshot.Height - MaxTraceableBlocks) state = null; + engine.Push(state?.Transaction.ToStackItem(engine.ReferenceCounter) ?? StackItem.Null); return true; } private static bool Blockchain_GetTransactionHeight(ApplicationEngine engine) { - ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - var tx = engine.Snapshot.Transactions.TryGet(new UInt256(hash)); - engine.CurrentContext.EvaluationStack.Push(tx != null ? new BigInteger(tx.BlockIndex) : BigInteger.MinusOne); + if (!engine.TryPop(out ReadOnlySpan hash)) return false; + TransactionState state = engine.Snapshot.Transactions.TryGet(new UInt256(hash)); + if (state?.BlockIndex <= engine.Snapshot.Height - MaxTraceableBlocks) state = null; + engine.Push(state?.BlockIndex ?? BigInteger.MinusOne); return true; } private static bool Blockchain_GetTransactionFromBlock(ApplicationEngine engine) { - ReadOnlySpan data = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); UInt256 hash; - if (data.Length <= 5) - hash = Ledger.Blockchain.Singleton.GetBlockHash((uint)new BigInteger(data)); - else if (data.Length == 32) + if (engine.TryPop(out uint height)) + { + hash = Ledger.Blockchain.Singleton.GetBlockHash(height); + } + else if (engine.TryPop(out ReadOnlySpan data)) + { + if (data.Length != 32) return false; hash = new UInt256(data); + } else + { return false; - + } TrimmedBlock block = hash != null ? engine.Snapshot.Blocks.TryGet(hash) : null; - if (block == null) + if (block?.Index <= engine.Snapshot.Height - MaxTraceableBlocks) block = null; + if (block is null) { - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); + engine.Push(StackItem.Null); } else { - int index = (int)engine.CurrentContext.EvaluationStack.Pop().GetBigInteger(); + if (!engine.TryPop(out int index)) return false; if (index < 0 || index >= block.Hashes.Length - 1) return false; - Transaction tx = engine.Snapshot.GetTransaction(block.Hashes[index + 1]); - if (tx == null) - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - else - engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem(engine.ReferenceCounter)); + engine.Push(tx?.ToStackItem(engine.ReferenceCounter) ?? StackItem.Null); } return true; } diff --git a/src/neo/neo.csproj b/src/neo/neo.csproj index 6b06ca6960..2b146e992e 100644 --- a/src/neo/neo.csproj +++ b/src/neo/neo.csproj @@ -27,7 +27,7 @@ - + From ca56b6df6049e5e3fae1c7e3fe8883b3b40434e1 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sun, 22 Mar 2020 21:12:13 +0800 Subject: [PATCH 4/6] Fix UT --- .../SmartContract/InteropService.Blockchain.cs | 15 +++++++++++---- tests/neo.UnitTests/SmartContract/UT_Syscalls.cs | 4 ++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/neo/SmartContract/InteropService.Blockchain.cs b/src/neo/SmartContract/InteropService.Blockchain.cs index 4eb4e24f1b..65876bd5a0 100644 --- a/src/neo/SmartContract/InteropService.Blockchain.cs +++ b/src/neo/SmartContract/InteropService.Blockchain.cs @@ -1,5 +1,6 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.VM; using Neo.VM.Types; using System; @@ -43,7 +44,7 @@ private static bool Blockchain_GetBlock(ApplicationEngine engine) return false; } Block block = hash != null ? engine.Snapshot.GetBlock(hash) : null; - if (block?.Index <= engine.Snapshot.Height - MaxTraceableBlocks) block = null; + if (block != null && !IsTraceableBlock(engine.Snapshot, block.Index)) block = null; engine.Push(block?.ToStackItem(engine.ReferenceCounter) ?? StackItem.Null); return true; } @@ -52,7 +53,7 @@ private static bool Blockchain_GetTransaction(ApplicationEngine engine) { if (!engine.TryPop(out ReadOnlySpan hash)) return false; TransactionState state = engine.Snapshot.Transactions.TryGet(new UInt256(hash)); - if (state?.BlockIndex <= engine.Snapshot.Height - MaxTraceableBlocks) state = null; + if (state != null && !IsTraceableBlock(engine.Snapshot, state.BlockIndex)) state = null; engine.Push(state?.Transaction.ToStackItem(engine.ReferenceCounter) ?? StackItem.Null); return true; } @@ -61,7 +62,7 @@ private static bool Blockchain_GetTransactionHeight(ApplicationEngine engine) { if (!engine.TryPop(out ReadOnlySpan hash)) return false; TransactionState state = engine.Snapshot.Transactions.TryGet(new UInt256(hash)); - if (state?.BlockIndex <= engine.Snapshot.Height - MaxTraceableBlocks) state = null; + if (state != null && !IsTraceableBlock(engine.Snapshot, state.BlockIndex)) state = null; engine.Push(state?.BlockIndex ?? BigInteger.MinusOne); return true; } @@ -83,7 +84,7 @@ private static bool Blockchain_GetTransactionFromBlock(ApplicationEngine engine) return false; } TrimmedBlock block = hash != null ? engine.Snapshot.Blocks.TryGet(hash) : null; - if (block?.Index <= engine.Snapshot.Height - MaxTraceableBlocks) block = null; + if (block != null && !IsTraceableBlock(engine.Snapshot, block.Index)) block = null; if (block is null) { engine.Push(StackItem.Null); @@ -108,6 +109,12 @@ private static bool Blockchain_GetContract(ApplicationEngine engine) engine.CurrentContext.EvaluationStack.Push(contract.ToStackItem(engine.ReferenceCounter)); return true; } + + private static bool IsTraceableBlock(StoreView snapshot, uint index) + { + if (index > snapshot.Height) return false; + return index + MaxTraceableBlocks > snapshot.Height; + } } } } diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 04f60db7ff..58052a441b 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -37,7 +37,7 @@ public void System_Blockchain_GetBlock() var block = new Block() { - Index = 1, + Index = 0, Timestamp = 2, Version = 3, Witness = new Witness() @@ -83,7 +83,7 @@ public void System_Blockchain_GetBlock() Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(ByteArray)); Assert.AreEqual(engine.ResultStack.Pop().GetSpan().ToHexString(), - "5b22556168352f4b6f446d39723064555950636353714346745a30594f726b583164646e7334366e676e3962383d222c332c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c322c312c224141414141414141414141414141414141414141414141414141413d222c315d"); + "5b22366b4139757552614430373634585358466c706674686b436b5954702f6e34623878715057476c6a6659303d222c332c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c322c302c224141414141414141414141414141414141414141414141414141413d222c315d"); Assert.AreEqual(0, engine.ResultStack.Count); // Clean From b0c8f0e55a9a36908bca985c961fc418cbcd7942 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 23 Mar 2020 12:45:00 +0100 Subject: [PATCH 5/6] Add UT --- .../neo.UnitTests/SmartContract/UT_Syscalls.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 58052a441b..8044d8ae95 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -68,13 +68,27 @@ public void System_Blockchain_GetBlock() Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Peek().IsNull); - // With block + // Not traceable block + + var height = snapshot.BlockHashIndex.GetAndChange(); + height.Index = block.Index + Transaction.MaxValidUntilBlockIncrement; var blocks = snapshot.Blocks; var txs = snapshot.Transactions; blocks.Add(block.Hash, block.Trim()); txs.Add(tx.Hash, new TransactionState() { Transaction = tx, BlockIndex = block.Index, VMState = VMState.HALT }); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine.LoadScript(script.ToArray()); + + Assert.AreEqual(engine.Execute(), VMState.HALT); + Assert.AreEqual(1, engine.ResultStack.Count); + Assert.IsTrue(engine.ResultStack.Peek().IsNull); + + // With block + + height.Index = block.Index; + script.EmitSysCall(InteropService.Json.Serialize); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(script.ToArray()); @@ -87,6 +101,7 @@ public void System_Blockchain_GetBlock() Assert.AreEqual(0, engine.ResultStack.Count); // Clean + blocks.Delete(block.Hash); txs.Delete(tx.Hash); } From c7bb8e232b4f3ef1715837558e8cac4c9c2b8b01 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 23 Mar 2020 20:22:51 +0800 Subject: [PATCH 6/6] Update src/neo/SmartContract/InteropService.Blockchain.cs Co-Authored-By: Shargon --- src/neo/SmartContract/InteropService.Blockchain.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/SmartContract/InteropService.Blockchain.cs b/src/neo/SmartContract/InteropService.Blockchain.cs index 65876bd5a0..1183c5e462 100644 --- a/src/neo/SmartContract/InteropService.Blockchain.cs +++ b/src/neo/SmartContract/InteropService.Blockchain.cs @@ -12,7 +12,7 @@ partial class InteropService { public static class Blockchain { - private const uint MaxTraceableBlocks = Transaction.MaxValidUntilBlockIncrement; + public const uint MaxTraceableBlocks = Transaction.MaxValidUntilBlockIncrement; public static readonly InteropDescriptor GetHeight = Register("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application, CallFlags.None); public static readonly InteropDescriptor GetBlock = Register("System.Blockchain.GetBlock", Blockchain_GetBlock, 0_02500000, TriggerType.Application, CallFlags.None);