Skip to content

Commit

Permalink
Simplifying access to Transactions and Blocks in syscalls (neo-projec…
Browse files Browse the repository at this point in the history
…t#1081)

* Add Transaction.Sender and Transaction.Script

* Allow to get the current Transaction

* Update unit test, refactor transactions methods

* UT

* Summary TX object inside VM

* Revert some changes

* Refactor to new model and UT

* Fix

* Reduce conditional

* Fix ut

* Fix ut

* Change order

* Block

* Some fixes

* Fix comment

* Fix comments

* Move hash to the top

* Remove GetHeader

* Remove GetHeader

* Block with transactions count

* Migrate ContractState

* Format

* Close neo-project#1096

Close neo-project#1096

* Update nulls

* Remove Neo.Account.IsStandard

* Revert last change

* Fix Unit tests

* Remove unused var

* TrimmedBlock

* Change fee

* Neo.VM v3.0.0-CI00041

* Neo.VM v3.0.0-CI00042

* Rename

* ContractNullParameter

* Clean using

* Revert Null in ContractParameterType
  • Loading branch information
shargon authored and Luchuan committed Jan 10, 2020
1 parent 62da9d3 commit 9f02f02
Show file tree
Hide file tree
Showing 15 changed files with 319 additions and 330 deletions.
2 changes: 1 addition & 1 deletion neo.UnitTests/SmartContract/UT_InteropService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public void Runtime_GetNotifications_Test()

// Receive all notifications

script.EmitPush(new byte[0]);
script.Emit(OpCode.PUSHNULL);
script.EmitSysCall(InteropService.System_Runtime_GetNotifications);

// Execute
Expand Down
198 changes: 163 additions & 35 deletions neo.UnitTests/SmartContract/UT_Syscalls.cs
Original file line number Diff line number Diff line change
@@ -1,66 +1,194 @@
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_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 = TestBlockchain.GetStore().GetSnapshot();

using (var script = new ScriptBuilder())
{
script.EmitPush(block.Hash.ToArray());
script.EmitSysCall(InteropService.System_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 = (TestDataCache<UInt256, TrimmedBlock>)snapshot.Blocks;
var txs = (TestDataCache<UInt256, TransactionState>)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.Neo_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().GetByteArray().ToHexString(),
"5b22515c7546464644795c75464646445c75464646445c75303030335c75464646445c75464646445c754646464475465c7530303046715c75303132415c625b595c75303434335c75464646445c75464646447d5d767b385c7546464644785c75303032375c75464646445c7546464644222c332c225c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c7530303030222c225c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c7530303030222c322c312c225c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c75303030305c7530303030222c315d");
Assert.AreEqual(0, engine.ResultStack.Count);

// Clean
blocks.Delete(block.Hash);
txs.Delete(tx.Hash);
}
}

[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.IsTrue(engine.ResultStack.Peek().IsNull);

// 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());

Assert.AreEqual(engine.Execute(), VMState.HALT);
Assert.AreEqual(1, engine.ResultStack.Count);
Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(ByteArray));
Assert.AreEqual(engine.ResultStack.Pop().GetByteArray().ToHexString(),
@"5b225c7546464644445c7546464644615c7546464644732c5c75464646445c7546464644665c75303030375d5c75303030305c75464646445c75303632325c7546464644545c7546464644375c7530303133335c75303031385c7530303033655c75464646445c75464646445c75303032375a5c75464646445c2f5c7546464644222c362c342c225c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c75464646445c7546464644222c332c322c352c225c7530303031225d");
Assert.AreEqual(0, engine.ResultStack.Count);
}
}

[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
// Create dummy contracts

var script = new ScriptBuilder();
script.EmitSysCall(InteropService.System_Runtime_GetInvocationCounter);
using (var script = new ScriptBuilder())
{
script.EmitSysCall(InteropService.System_Runtime_GetInvocationCounter);

// Init A,B,C contracts
// First two drops is for drop method and arguments
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() };

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 */
}
);
}
}
}
}
17 changes: 16 additions & 1 deletion neo/Ledger/ContractState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
using Neo.IO.Json;
using Neo.SmartContract;
using Neo.SmartContract.Manifest;
using Neo.VM;
using Neo.VM.Types;
using System.IO;

namespace Neo.Ledger
{
public class ContractState : ICloneable<ContractState>, ISerializable
public class ContractState : ICloneable<ContractState>, ISerializable, IInteroperable
{
public byte[] Script;
public ContractManifest Manifest;
Expand Down Expand Up @@ -72,5 +74,18 @@ public static ContractState FromJson(JObject json)
contractState.Manifest = ContractManifest.FromJson(json["manifest"]);
return contractState;
}

public StackItem ToStackItem()
{
return new VM.Types.Array
(
new StackItem[]
{
new ByteArray(Script),
new Boolean(HasStorage),
new Boolean(Payable),
}
);
}
}
}
31 changes: 30 additions & 1 deletion neo/Network/P2P/Payloads/Block.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
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;

namespace Neo.Network.P2P.Payloads
{
public class Block : BlockBase, IInventory, IEquatable<Block>
public class Block : BlockBase, IInventory, IEquatable<Block>, IInteroperable
{
public const int MaxContentsPerBlock = ushort.MaxValue;
public const int MaxTransactionsPerBlock = MaxContentsPerBlock - 1;
Expand Down Expand Up @@ -131,5 +134,31 @@ public TrimmedBlock Trim()
ConsensusData = ConsensusData
};
}

public StackItem ToStackItem()
{
return new VM.Types.Array
(
new StackItem[]
{
// Computed properties
new ByteArray(Hash.ToArray()),

// BlockBase properties
new Integer(Version),
new ByteArray(PrevHash.ToArray()),
new ByteArray(MerkleRoot.ToArray()),
new Integer(Timestamp),
new Integer(Index),
new ByteArray(NextConsensus.ToArray()),
// Witness

// Block properties
// Count
// ConsensusData
new Integer(Transactions.Length)
}
);
}
}
}
30 changes: 28 additions & 2 deletions 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 @@ -68,7 +70,7 @@ public UInt256 Hash
sizeof(byte) + //Version
sizeof(uint) + //Nonce
20 + //Sender
sizeof(long) + //Gas
sizeof(long) + //SystemFee
sizeof(long) + //NetworkFee
sizeof(uint); //ValidUntilBlock

Expand Down Expand Up @@ -216,5 +218,29 @@ 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[]
{
// Computed properties
new ByteArray(Hash.ToArray()),

// Transaction properties
new Integer(Version),
new Integer(Nonce),
new ByteArray(Sender.ToArray()),
new Integer(SystemFee),
new Integer(NetworkFee),
new Integer(ValidUntilBlock),
// Attributes
// Cosigners
new ByteArray(Script),
// Witnesses
}
);
}
}
}
2 changes: 2 additions & 0 deletions neo/SmartContract/ApplicationEngine.OpCodePrices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ partial class ApplicationEngine
[OpCode.PUSHDATA2] = 13000,
[OpCode.PUSHDATA4] = 110000,
[OpCode.PUSHM1] = 30,
[OpCode.PUSHNULL] = 30,
[OpCode.PUSH1] = 30,
[OpCode.PUSH2] = 30,
[OpCode.PUSH3] = 30,
Expand Down Expand Up @@ -114,6 +115,7 @@ partial class ApplicationEngine
[OpCode.DUPFROMALTSTACK] = 60,
[OpCode.TOALTSTACK] = 60,
[OpCode.FROMALTSTACK] = 60,
[OpCode.ISNULL] = 60,
[OpCode.XDROP] = 400,
[OpCode.XSWAP] = 60,
[OpCode.XTUCK] = 400,
Expand Down
Loading

0 comments on commit 9f02f02

Please sign in to comment.