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

Simplifying access to Transactions and Blocks in syscalls #1081

Merged
merged 46 commits into from
Oct 16, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
fad0a2d
Add Transaction.Sender and Transaction.Script
shargon Sep 1, 2019
d842daf
Allow to get the current Transaction
shargon Sep 1, 2019
4e5765f
Update unit test, refactor transactions methods
shargon Sep 2, 2019
1418b6b
UT
shargon Sep 2, 2019
008fb11
Summary TX object inside VM
shargon Sep 4, 2019
ff77103
Merge branch 'master' into add-tx-properties
shargon Sep 4, 2019
6002ce1
Revert some changes
shargon Sep 4, 2019
2886542
Merge remote-tracking branch 'shargon/add-tx-properties' into add-tx-…
shargon Sep 4, 2019
af6ccff
Refactor to new model and UT
shargon Sep 4, 2019
f094d53
Fix
shargon Sep 4, 2019
e7c31dd
Reduce conditional
shargon Sep 4, 2019
194bb99
Fix ut
shargon Sep 5, 2019
c3eb5f5
Fix ut
shargon Sep 5, 2019
e40c9fe
Change order
shargon Sep 10, 2019
32c1668
Block
shargon Sep 10, 2019
4ddf863
Some fixes
shargon Sep 11, 2019
c1da9f0
Merge branch 'master' into add-tx-properties
shargon Sep 11, 2019
2da33ac
Fix comment
shargon Sep 11, 2019
aeaf768
Merge remote-tracking branch 'shargon/add-tx-properties' into add-tx-…
shargon Sep 11, 2019
0210333
Fix comments
shargon Sep 11, 2019
de35932
Move hash to the top
shargon Sep 11, 2019
5a4ee76
Remove GetHeader
shargon Sep 11, 2019
661b80e
Remove GetHeader
shargon Sep 11, 2019
7fb7b91
Block with transactions count
shargon Sep 11, 2019
d9645f3
Migrate ContractState
shargon Sep 11, 2019
17ee593
Format
shargon Sep 11, 2019
442e901
Close https://github.com/neo-project/neo/issues/1096
shargon Sep 11, 2019
7aecf36
Update nulls
shargon Sep 12, 2019
d9d4cc2
Remove Neo.Account.IsStandard
shargon Sep 12, 2019
1836c98
Revert last change
shargon Sep 12, 2019
5bb58ca
Merge branch 'master' into add-tx-properties
shargon Sep 16, 2019
238bc06
Fix Unit tests
shargon Sep 19, 2019
d199914
Remove unused var
shargon Sep 19, 2019
ece0081
Merge branch 'master' into add-tx-properties
shargon Sep 23, 2019
944484f
TrimmedBlock
shargon Sep 26, 2019
3a9f0bf
Change fee
shargon Sep 26, 2019
c08dd55
Merge branch 'master' into add-tx-properties
shargon Oct 1, 2019
4320dac
Merge branch 'master' into add-tx-properties
erikzhang Oct 3, 2019
ec00054
Neo.VM v3.0.0-CI00041
erikzhang Oct 3, 2019
a7ab656
Neo.VM v3.0.0-CI00042
erikzhang Oct 14, 2019
6dc2893
Rename
erikzhang Oct 14, 2019
97d2bda
ContractNullParameter
shargon Oct 15, 2019
3c3cbdf
Clean using
shargon Oct 15, 2019
6e35d8a
Revert Null in ContractParameterType
shargon Oct 15, 2019
55ef8ef
Merge branch 'master' into add-tx-properties
shargon Oct 15, 2019
3175c32
Merge branch 'master' into add-tx-properties
shargon Oct 15, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 88 additions & 34 deletions neo.UnitTests/SmartContract/UT_Syscalls.cs
Original file line number Diff line number Diff line change
@@ -1,66 +1,120 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Ledger;
using Neo.Network.P2P.Payloads;
using Neo.SmartContract;
using Neo.VM;
using Neo.VM.Types;
using System.Linq;

namespace Neo.UnitTests.SmartContract
{
[TestClass]
public class UT_Syscalls
{
[TestMethod]
public void System_ExecutionEngine_GetScriptContainer()
{
var snapshot = TestBlockchain.GetStore().GetSnapshot();
using (var script = new ScriptBuilder())
{
script.EmitSysCall(InteropService.System_ExecutionEngine_GetScriptContainer);

// Without tx

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.IsNull(((InteropInterface<IVerifiable>)engine.ResultStack.Pop()).GetInterface<IVerifiable>());

// With tx

script.EmitSysCall(InteropService.Neo_Json_Serialize);

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"),
};

engine = new ApplicationEngine(TriggerType.Application, tx, snapshot, 0, true);
engine.LoadScript(script.ToArray());
engine.CurrentContext.EvaluationStack.Push(InteropInterface.FromInterface(tx));

Assert.AreEqual(engine.Execute(), VMState.HALT);
Assert.AreEqual(2, engine.ResultStack.Count);
Assert.AreEqual(engine.ResultStack.Pop().GetString(),
@"[""\uFFFDD\uFFFDa\uFFFDs,\uFFFD\uFFFDf\u0007]\u0000\uFFFD\u0622\uFFFDT\uFFFD7\u00133\u0018\u0003e\uFFFD\uFFFD\u0027Z\uFFFD\/\uFFFD"",""\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD"",""\u0001"",[""\u0007""],4,2,3,5,6]");
Assert.AreEqual(1, engine.ResultStack.Count);
shargon marked this conversation as resolved.
Show resolved Hide resolved
}
}

[TestMethod]
public void System_Runtime_GetInvocationCounter()
{
ContractState contractA, contractB, contractC;
var snapshot = TestBlockchain.GetStore().GetSnapshot();
var contracts = (TestDataCache<UInt160, ContractState>)snapshot.Contracts;

// Call System.Runtime.GetInvocationCounter syscall

var script = new ScriptBuilder();
script.EmitSysCall(InteropService.System_Runtime_GetInvocationCounter);
using (var script = new ScriptBuilder())
{
contractA = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP }.Concat(script.ToArray()).ToArray() };
contractB = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP, (byte)OpCode.NOP }.Concat(script.ToArray()).ToArray() };
contractC = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP, (byte)OpCode.NOP, (byte)OpCode.NOP }.Concat(script.ToArray()).ToArray() };

// Init A,B,C contracts
// First two drops is for drop method and arguments
script.EmitSysCall(InteropService.System_Runtime_GetInvocationCounter);

var contractA = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP }.Concat(script.ToArray()).ToArray() };
var contractB = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP, (byte)OpCode.NOP }.Concat(script.ToArray()).ToArray() };
var contractC = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP, (byte)OpCode.NOP, (byte)OpCode.NOP }.Concat(script.ToArray()).ToArray() };
// Init A,B,C contracts
// First two drops is for drop method and arguments

contracts.DeleteWhere((a, b) => a.ToArray().SequenceEqual(contractA.ScriptHash.ToArray()));
contracts.DeleteWhere((a, b) => a.ToArray().SequenceEqual(contractB.ScriptHash.ToArray()));
contracts.DeleteWhere((a, b) => a.ToArray().SequenceEqual(contractC.ScriptHash.ToArray()));
contracts.Add(contractA.ScriptHash, contractA);
contracts.Add(contractB.ScriptHash, contractB);
contracts.Add(contractC.ScriptHash, contractC);
contracts.DeleteWhere((a, b) => a.ToArray().SequenceEqual(contractA.ScriptHash.ToArray()));
contracts.DeleteWhere((a, b) => a.ToArray().SequenceEqual(contractB.ScriptHash.ToArray()));
contracts.DeleteWhere((a, b) => a.ToArray().SequenceEqual(contractC.ScriptHash.ToArray()));
contracts.Add(contractA.ScriptHash, contractA);
contracts.Add(contractB.ScriptHash, contractB);
contracts.Add(contractC.ScriptHash, contractC);
}

// Call A,B,B,C

script = new ScriptBuilder();
script.EmitSysCall(InteropService.System_Contract_Call, contractA.ScriptHash.ToArray(), "dummyMain", 0);
script.EmitSysCall(InteropService.System_Contract_Call, contractB.ScriptHash.ToArray(), "dummyMain", 0);
script.EmitSysCall(InteropService.System_Contract_Call, contractB.ScriptHash.ToArray(), "dummyMain", 0);
script.EmitSysCall(InteropService.System_Contract_Call, contractC.ScriptHash.ToArray(), "dummyMain", 0);
using (var script = new ScriptBuilder())
{
script.EmitSysCall(InteropService.System_Contract_Call, contractA.ScriptHash.ToArray(), "dummyMain", 0);
script.EmitSysCall(InteropService.System_Contract_Call, contractB.ScriptHash.ToArray(), "dummyMain", 0);
script.EmitSysCall(InteropService.System_Contract_Call, contractB.ScriptHash.ToArray(), "dummyMain", 0);
script.EmitSysCall(InteropService.System_Contract_Call, contractC.ScriptHash.ToArray(), "dummyMain", 0);

// Execute
// Execute

var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);
engine.LoadScript(script.ToArray());
Assert.AreEqual(engine.Execute(), VMState.HALT);
var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);
engine.LoadScript(script.ToArray());
Assert.AreEqual(engine.Execute(), VMState.HALT);

// Check the results
// Check the results

CollectionAssert.AreEqual
(
engine.ResultStack.Select(u => (int)((VM.Types.Integer)u).GetBigInteger()).ToArray(),
new int[]
{
1, /* A */
1, /* B */
2, /* B */
1 /* C */
}
);
CollectionAssert.AreEqual
(
engine.ResultStack.Select(u => (int)((VM.Types.Integer)u).GetBigInteger()).ToArray(),
new int[]
{
1, /* A */
1, /* B */
2, /* B */
1 /* C */
}
);
}
}
}
}
23 changes: 22 additions & 1 deletion neo/Network/P2P/Payloads/Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.VM;
using Neo.VM.Types;
using Neo.Wallets;
using System;
using System.Collections.Generic;
Expand All @@ -13,7 +15,7 @@

namespace Neo.Network.P2P.Payloads
{
public class Transaction : IEquatable<Transaction>, IInventory
public class Transaction : IEquatable<Transaction>, IInventory, IInteroperable
{
public const int MaxTransactionSize = 102400;
public const uint MaxValidUntilBlockIncrement = 2102400;
Expand Down Expand Up @@ -215,5 +217,24 @@ public virtual bool Verify(Snapshot snapshot, IEnumerable<Transaction> mempool)
if (net_fee < 0) return false;
return this.VerifyWitnesses(snapshot, net_fee);
}

public StackItem ToStackItem()
{
return new VM.Types.Array
(
new StackItem[]
{
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
new ByteArray(Hash.ToArray()),
new ByteArray(Sender.ToArray()),
new ByteArray(Script),
new VM.Types.Array(Witnesses.Select(u=>new ByteArray(u.VerificationScript))),
shargon marked this conversation as resolved.
Show resolved Hide resolved
new Integer(Nonce),
new Integer(NetworkFee),
new Integer(SystemFee),
new Integer(ValidUntilBlock),
new Integer(Version)
}
);
}
}
}
9 changes: 9 additions & 0 deletions neo/SmartContract/IInteroperable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Neo.VM;

namespace Neo.SmartContract
{
public interface IInteroperable
{
StackItem ToStackItem();
}
}
28 changes: 0 additions & 28 deletions neo/SmartContract/InteropService.NEO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ static partial class InteropService
public static readonly uint Neo_Header_GetVersion = Register("Neo.Header.GetVersion", Header_GetVersion, 0_00000400, TriggerType.Application);
public static readonly uint Neo_Header_GetMerkleRoot = Register("Neo.Header.GetMerkleRoot", Header_GetMerkleRoot, 0_00000400, TriggerType.Application);
public static readonly uint Neo_Header_GetNextConsensus = Register("Neo.Header.GetNextConsensus", Header_GetNextConsensus, 0_00000400, TriggerType.Application);
public static readonly uint Neo_Transaction_GetScript = Register("Neo.Transaction.GetScript", Transaction_GetScript, 0_00000400, TriggerType.All);
public static readonly uint Neo_Transaction_GetWitnesses = Register("Neo.Transaction.GetWitnesses", Transaction_GetWitnesses, 0_00010000, TriggerType.All);
public static readonly uint Neo_Witness_GetVerificationScript = Register("Neo.Witness.GetVerificationScript", Witness_GetVerificationScript, 0_00000400, TriggerType.All);
public static readonly uint Neo_Account_IsStandard = Register("Neo.Account.IsStandard", Account_IsStandard, 0_00030000, TriggerType.All);
shargon marked this conversation as resolved.
Show resolved Hide resolved
public static readonly uint Neo_Contract_Create = Register("Neo.Contract.Create", Contract_Create, GetDeploymentPrice, TriggerType.Application);
Expand Down Expand Up @@ -193,32 +191,6 @@ private static bool Header_GetNextConsensus(ApplicationEngine engine)
return false;
}

private static bool Transaction_GetScript(ApplicationEngine engine)
{
if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)
{
Transaction tx = _interface.GetInterface<Transaction>();
if (tx == null) return false;
engine.CurrentContext.EvaluationStack.Push(tx.Script);
return true;
}
return false;
}

private static bool Transaction_GetWitnesses(ApplicationEngine engine)
{
if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)
{
Transaction tx = _interface.GetInterface<Transaction>();
if (tx == null) return false;
if (tx.Witnesses.Length > engine.MaxArraySize)
return false;
engine.CurrentContext.EvaluationStack.Push(WitnessWrapper.Create(tx, engine.Snapshot).Select(p => StackItem.FromInterface(p)).ToArray());
return true;
}
return false;
}

private static bool Witness_GetVerificationScript(ApplicationEngine engine)
{
if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)
Expand Down
24 changes: 7 additions & 17 deletions neo/SmartContract/InteropService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public static partial class InteropService
public static readonly uint System_Block_GetTransactionCount = Register("System.Block.GetTransactionCount", Block_GetTransactionCount, 0_00000400, TriggerType.Application);
public static readonly uint System_Block_GetTransactions = Register("System.Block.GetTransactions", Block_GetTransactions, 0_00010000, TriggerType.Application);
public static readonly uint System_Block_GetTransaction = Register("System.Block.GetTransaction", Block_GetTransaction, 0_00000400, TriggerType.Application);
shargon marked this conversation as resolved.
Show resolved Hide resolved
public static readonly uint System_Transaction_GetHash = Register("System.Transaction.GetHash", Transaction_GetHash, 0_00000400, TriggerType.All);
public static readonly uint System_Contract_Call = Register("System.Contract.Call", Contract_Call, 0_01000000, TriggerType.System | TriggerType.Application);
public static readonly uint System_Contract_Destroy = Register("System.Contract.Destroy", Contract_Destroy, 0_01000000, TriggerType.Application);
public static readonly uint System_Storage_GetContext = Register("System.Storage.GetContext", Storage_GetContext, 0_00000400, TriggerType.Application);
Expand Down Expand Up @@ -112,7 +111,9 @@ private static uint Register(string method, Func<ApplicationEngine, bool> handle

private static bool ExecutionEngine_GetScriptContainer(ApplicationEngine engine)
{
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(engine.ScriptContainer));
engine.CurrentContext.EvaluationStack.Push(
engine.ScriptContainer is IInteroperable value ? value.ToStackItem() :
StackItem.FromInterface(engine.ScriptContainer));
return true;
}

Expand Down Expand Up @@ -352,7 +353,8 @@ private static bool Blockchain_GetTransaction(ApplicationEngine engine)
{
byte[] hash = engine.CurrentContext.EvaluationStack.Pop().GetByteArray();
Transaction tx = engine.Snapshot.GetTransaction(new UInt256(hash));
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(tx));
if (tx == null) return false;
engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem());
return true;
}

Expand Down Expand Up @@ -443,7 +445,7 @@ private static bool Block_GetTransactions(ApplicationEngine engine)
if (block == null) return false;
if (block.Transactions.Length > engine.MaxArraySize)
return false;
engine.CurrentContext.EvaluationStack.Push(block.Transactions.Select(p => StackItem.FromInterface(p)).ToArray());
engine.CurrentContext.EvaluationStack.Push(new VM.Types.Array(block.Transactions.Select(tx => tx.ToStackItem())));
return true;
}
return false;
Expand All @@ -458,19 +460,7 @@ private static bool Block_GetTransaction(ApplicationEngine engine)
if (block == null) return false;
if (index < 0 || index >= block.Transactions.Length) return false;
Transaction tx = block.Transactions[index];
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(tx));
return true;
}
return false;
}

private static bool Transaction_GetHash(ApplicationEngine engine)
{
if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)
{
Transaction tx = _interface.GetInterface<Transaction>();
if (tx == null) return false;
engine.CurrentContext.EvaluationStack.Push(tx.Hash.ToArray());
engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem());
return true;
}
return false;
Expand Down