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 44 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
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"),
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
};

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);
shargon marked this conversation as resolved.
Show resolved Hide resolved
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[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very good place to apply the proposed ABI serialization I've been discussing... if we adopt such byte serialization format, its conversion to interop could be done automatically like this.

{
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[]
{
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
// 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