From 3702164ddf66f4640a184262e08a6d047a9dd5f4 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 7 Jul 2020 10:39:51 +0200 Subject: [PATCH 01/27] Sender from signers --- src/neo/Ledger/Blockchain.cs | 9 +++- .../P2P/Payloads/{Cosigner.cs => Signer.cs} | 4 +- src/neo/Network/P2P/Payloads/Transaction.cs | 20 +++------ .../P2P/Payloads/TransactionAttributeType.cs | 4 +- .../ApplicationEngine.Runtime.cs | 2 +- src/neo/Wallets/Wallet.cs | 28 ++++++++++-- .../Consensus/UT_ConsensusContext.cs | 2 - .../Cryptography/UT_Cryptography_Helper.cs | 1 - .../neo.UnitTests/IO/Caching/UT_RelayCache.cs | 2 - tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 1 - tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 6 +-- tests/neo.UnitTests/Ledger/UT_PoolItem.cs | 3 +- .../Ledger/UT_SendersFeeMonitor.cs | 1 - tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 14 +++--- .../Network/P2P/Payloads/UT_Block.cs | 8 ++-- .../Network/P2P/Payloads/UT_Cosigner.cs | 24 +++++----- .../Network/P2P/Payloads/UT_Transaction.cs | 45 ++++++++----------- .../Network/P2P/Payloads/UT_Witness.cs | 10 ++++- .../UT_ContractParameterContext.cs | 24 ++++------ .../SmartContract/UT_InteropService.cs | 4 +- .../SmartContract/UT_Syscalls.cs | 2 - tests/neo.UnitTests/TestUtils.cs | 15 ++++--- 22 files changed, 117 insertions(+), 112 deletions(-) rename src/neo/Network/P2P/Payloads/{Cosigner.cs => Signer.cs} (96%) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 50cee9509d..c09b08cd8a 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -166,9 +166,14 @@ private static Transaction DeployNativeContracts() { Version = 0, Script = script, - Sender = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash(), SystemFee = 0, - Attributes = Array.Empty(), + Attributes = new TransactionAttribute[] + { + new Signer() + { + Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash() + } + }, Witnesses = new[] { new Witness diff --git a/src/neo/Network/P2P/Payloads/Cosigner.cs b/src/neo/Network/P2P/Payloads/Signer.cs similarity index 96% rename from src/neo/Network/P2P/Payloads/Cosigner.cs rename to src/neo/Network/P2P/Payloads/Signer.cs index ba8a6fa3dd..0cd2118515 100644 --- a/src/neo/Network/P2P/Payloads/Cosigner.cs +++ b/src/neo/Network/P2P/Payloads/Signer.cs @@ -6,7 +6,7 @@ namespace Neo.Network.P2P.Payloads { - public class Cosigner : TransactionAttribute + public class Signer : TransactionAttribute { // This limits maximum number of AllowedContracts or AllowedGroups here private const int MaxSubitems = 16; @@ -16,7 +16,7 @@ public class Cosigner : TransactionAttribute public UInt160[] AllowedContracts; public ECPoint[] AllowedGroups; - public override TransactionAttributeType Type => TransactionAttributeType.Cosigner; + public override TransactionAttributeType Type => TransactionAttributeType.Signer; public override bool AllowMultiple => true; public override int Size => base.Size + diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 127f56cb17..8fd6f998d2 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -28,7 +28,6 @@ public class Transaction : IEquatable, IInventory, IInteroperable private byte version; private uint nonce; - private UInt160 sender; private long sysfee; private long netfee; private uint validUntilBlock; @@ -47,11 +46,12 @@ public class Transaction : IEquatable, IInventory, IInteroperable public TransactionAttribute[] Attributes { get => attributes; - set { attributes = value; _cosigners = null; _hash = null; _size = 0; } + set { attributes = value; _signers = null; _hash = null; _size = 0; } } - private Dictionary _cosigners; - public IReadOnlyDictionary Cosigners => _cosigners ??= attributes.OfType().ToDictionary(p => p.Account); + private Dictionary _signers; + public IReadOnlyDictionary Signers => _signers ??= attributes.OfType().ToDictionary(p => p.Account); + public UInt160 Sender => attributes.OfType().Select(p => p.Account).First(); /// /// The NetworkFee for the transaction divided by its Size. @@ -95,12 +95,6 @@ public byte[] Script set { script = value; _hash = null; _size = 0; } } - public UInt160 Sender - { - get => sender; - set { sender = value; _hash = null; } - } - private int _size; public int Size { @@ -173,7 +167,6 @@ public void DeserializeUnsigned(BinaryReader reader) Version = reader.ReadByte(); if (Version > 0) throw new FormatException(); Nonce = reader.ReadUInt32(); - Sender = reader.ReadSerializable(); SystemFee = reader.ReadInt64(); if (SystemFee < 0) throw new FormatException(); NetworkFee = reader.ReadInt64(); @@ -183,7 +176,7 @@ public void DeserializeUnsigned(BinaryReader reader) Attributes = DeserializeAttributes(reader).ToArray(); try { - _ = Cosigners; + _ = Signers; } catch (ArgumentException) { @@ -217,8 +210,7 @@ public override int GetHashCode() public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { - var hashes = new HashSet(Cosigners.Keys) { Sender }; - return hashes.OrderBy(p => p).ToArray(); + return Signers.Keys.OrderBy(p => p).ToArray(); } void ISerializable.Serialize(BinaryWriter writer) diff --git a/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs b/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs index f1e2d704da..fc9bceab89 100644 --- a/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs +++ b/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs @@ -4,7 +4,7 @@ namespace Neo.Network.P2P.Payloads { public enum TransactionAttributeType : byte { - [ReflectionCache(typeof(Cosigner))] - Cosigner = 0x01 + [ReflectionCache(typeof(Signer))] + Signer = 0x01 } } diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index a000f06e34..eb38ee51af 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -104,7 +104,7 @@ internal bool CheckWitnessInternal(UInt160 hash) { if (ScriptContainer is Transaction tx) { - if (!tx.Cosigners.TryGetValue(hash, out Cosigner cosigner)) return false; + if (!tx.Signers.TryGetValue(hash, out Signer cosigner)) return false; if (cosigner.Scopes == WitnessScope.Global) return true; if (cosigner.Scopes.HasFlag(WitnessScope.CalledByEntry)) { diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index d70fa23f8b..d105a5d7d5 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -12,6 +12,7 @@ using System.Numerics; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; +using System.Security.Policy; using System.Text; using static Neo.Wallets.Helper; using ECPoint = Neo.Cryptography.ECC.ECPoint; @@ -278,7 +279,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); var cosigners = cosignerList.Select(p => - new Cosigner() + new Signer() { // default access for transfers should be valid only for first invocation Scopes = WitnessScope.CalledByEntry, @@ -314,14 +315,35 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Transacti Random rand = new Random(); foreach (var (account, value) in balances_gas) { + var attr = new List(); + + if (!attributes.OfType().Any(u => u.Account == account)) + { + // Add a new signer + + attr.Add(new Signer() + { + Account = account, + Scopes = WitnessScope.CalledByEntry + }); + attr.AddRange(attributes); + } + else + { + // Use the first signer of this account + + var ac = attributes.OfType().First(u => u.Account == account); + attr.Add(ac); + attr.AddRange(attributes.Where(u => u != ac)); + } + Transaction tx = new Transaction { Version = 0, Nonce = (uint)rand.Next(), Script = script, - Sender = account, ValidUntilBlock = snapshot.Height + Transaction.MaxValidUntilBlockIncrement, - Attributes = attributes, + Attributes = attr.ToArray(), }; // will try to execute 'transfer' script to check if it works diff --git a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs index 2f32b4b7ff..ea7ce9c6e0 100644 --- a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs +++ b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs @@ -128,7 +128,6 @@ private Transaction CreateTransactionWithSize(int v) NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[0], - Sender = UInt160.Zero, SystemFee = 0, ValidUntilBlock = (uint)r.Next(), Version = 0, @@ -148,7 +147,6 @@ private Transaction CreateTransactionWithSytemFee(long fee) NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[0], - Sender = UInt160.Zero, SystemFee = fee, ValidUntilBlock = int.MaxValue, Version = 0, diff --git a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index b2c5775903..f6e94e9fb6 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -152,7 +152,6 @@ public void TestTest() Transaction tx = new Transaction { Script = TestUtils.GetByteArray(32, 0x42), - Sender = UInt160.Zero, SystemFee = 4200000000, Attributes = Array.Empty(), Witnesses = new[] diff --git a/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs b/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs index d442a018e9..79a817ab95 100644 --- a/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs +++ b/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs @@ -24,7 +24,6 @@ public void TestGetKeyForItem() { Version = 0, Nonce = 1, - Sender = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), SystemFee = 0, NetworkFee = 0, ValidUntilBlock = 100, @@ -33,7 +32,6 @@ public void TestGetKeyForItem() Witnesses = new Witness[0] }; relayCache.Add(tx); - relayCache.Contains(tx).Should().BeTrue(); relayCache.TryGet(tx.Hash, out IInventory tmp).Should().BeTrue(); (tmp is Transaction).Should().BeTrue(); diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index 7e04dfe229..f68f1eeab7 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -148,7 +148,6 @@ public void TestInvalidTransactionInPersist() NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[] { 1 }, - Sender = UInt160.Zero, SystemFee = 0, ValidUntilBlock = Blockchain.GenesisBlock.Index + 1, Version = 0, diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 4e96605b7b..dd103cc674 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -77,7 +77,6 @@ private Transaction CreateTransactionWithFee(long fee) mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; - mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); mock.Object.Witnesses = new[] @@ -97,11 +96,10 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - UInt160 sender = UInt160.Zero; - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => + NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; - mock.Object.Sender = sender; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); mock.Object.Witnesses = new[] diff --git a/tests/neo.UnitTests/Ledger/UT_PoolItem.cs b/tests/neo.UnitTests/Ledger/UT_PoolItem.cs index 09b6e71fba..6ed25e74b7 100644 --- a/tests/neo.UnitTests/Ledger/UT_PoolItem.cs +++ b/tests/neo.UnitTests/Ledger/UT_PoolItem.cs @@ -118,7 +118,6 @@ public static Transaction GenerateTx(long networkFee, int size, byte[] overrideS { Nonce = (uint)TestRandom.Next(), Script = overrideScriptBytes ?? new byte[0], - Sender = UInt160.Zero, NetworkFee = networkFee, Attributes = Array.Empty(), Witnesses = new[] @@ -132,7 +131,7 @@ public static Transaction GenerateTx(long networkFee, int size, byte[] overrideS }; tx.Attributes.Length.Should().Be(0); - tx.Cosigners.Count.Should().Be(0); + tx.Signers.Count.Should().Be(0); int diff = size - tx.Size; if (diff < 0) throw new ArgumentException(); diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs index cd8a5af463..923ef206cc 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -21,7 +21,6 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; - mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = networkFee; mock.Object.SystemFee = systemFee; mock.Object.Attributes = Array.Empty(); diff --git a/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs index b74a0b2a9e..c8b0e30fb8 100644 --- a/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -35,7 +35,7 @@ public static TrimmedBlock GetTrimmedBlockWithNoTransaction() public void TestGetIsBlock() { TrimmedBlock block = GetTrimmedBlockWithNoTransaction(); - block.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + block.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; block.IsBlock.Should().BeTrue(); } @@ -43,7 +43,7 @@ public void TestGetIsBlock() public void TestGetBlock() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var tx1 = TestUtils.GetTransaction(); + var tx1 = TestUtils.GetTransaction(UInt160.Zero); tx1.Script = new byte[] { 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, @@ -53,7 +53,7 @@ public void TestGetBlock() Transaction = tx1, BlockIndex = 1 }; - var tx2 = TestUtils.GetTransaction(); + var tx2 = TestUtils.GetTransaction(UInt160.Zero); tx2.Script = new byte[] { 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, @@ -89,7 +89,7 @@ public void TestGetHeader() public void TestGetSize() { TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); - tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; tblock.Size.Should().Be(146); } @@ -97,7 +97,7 @@ public void TestGetSize() public void TestDeserialize() { TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); - tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; var newBlock = new TrimmedBlock(); using (MemoryStream ms = new MemoryStream(1024)) using (BinaryWriter writer = new BinaryWriter(ms)) @@ -119,7 +119,7 @@ public void TestDeserialize() public void TestClone() { TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); - tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; ICloneable cloneable = tblock; var clonedBlock = cloneable.Clone(); clonedBlock.ToJson().ToString().Should().Be(tblock.ToJson().ToString()); @@ -129,7 +129,7 @@ public void TestClone() public void TestFromReplica() { TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); - tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; ICloneable cloneable = new TrimmedBlock(); cloneable.FromReplica(tblock); ((TrimmedBlock)cloneable).ToJson().ToString().Should().Be(tblock.ToJson().ToString()); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 1efd90a3a8..b4f222127d 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -56,7 +56,7 @@ public void Size_Get_1_Transaction() uut.Transactions = new[] { - TestUtils.GetTransaction() + TestUtils.GetTransaction(UInt160.Zero) }; uut.Size.Should().Be(165); @@ -70,9 +70,9 @@ public void Size_Get_3_Transaction() uut.Transactions = new[] { - TestUtils.GetTransaction(), - TestUtils.GetTransaction(), - TestUtils.GetTransaction() + TestUtils.GetTransaction(UInt160.Zero), + TestUtils.GetTransaction(UInt160.Zero), + TestUtils.GetTransaction(UInt160.Zero) }; uut.Size.Should().Be(267); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs index 22ca14cb82..a487fea297 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs @@ -12,7 +12,7 @@ public class UT_Cosigner [TestMethod] public void Serialize_Deserialize_Global() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.Global, Account = UInt160.Zero @@ -21,7 +21,7 @@ public void Serialize_Deserialize_Global() var hex = "01000000000000000000000000000000000000000000"; attr.ToArray().ToHexString().Should().Be(hex); - var copy = hex.HexToBytes().AsSerializable(); + var copy = hex.HexToBytes().AsSerializable(); Assert.AreEqual(attr.Scopes, copy.Scopes); Assert.AreEqual(attr.Account, copy.Account); @@ -30,7 +30,7 @@ public void Serialize_Deserialize_Global() [TestMethod] public void Serialize_Deserialize_CalledByEntry() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CalledByEntry, Account = UInt160.Zero @@ -39,7 +39,7 @@ public void Serialize_Deserialize_CalledByEntry() var hex = "01000000000000000000000000000000000000000001"; attr.ToArray().ToHexString().Should().Be(hex); - var copy = hex.HexToBytes().AsSerializable(); + var copy = hex.HexToBytes().AsSerializable(); Assert.AreEqual(attr.Scopes, copy.Scopes); Assert.AreEqual(attr.Account, copy.Account); @@ -48,7 +48,7 @@ public void Serialize_Deserialize_CalledByEntry() [TestMethod] public void Serialize_Deserialize_CustomContracts() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CustomContracts, AllowedContracts = new[] { UInt160.Zero }, @@ -58,7 +58,7 @@ public void Serialize_Deserialize_CustomContracts() var hex = "01000000000000000000000000000000000000000010010000000000000000000000000000000000000000"; attr.ToArray().ToHexString().Should().Be(hex); - var copy = hex.HexToBytes().AsSerializable(); + var copy = hex.HexToBytes().AsSerializable(); Assert.AreEqual(attr.Scopes, copy.Scopes); CollectionAssert.AreEqual(attr.AllowedContracts, copy.AllowedContracts); @@ -68,7 +68,7 @@ public void Serialize_Deserialize_CustomContracts() [TestMethod] public void Serialize_Deserialize_CustomGroups() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CustomGroups, AllowedGroups = new[] { ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1) }, @@ -78,7 +78,7 @@ public void Serialize_Deserialize_CustomGroups() var hex = "010000000000000000000000000000000000000000200103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"; attr.ToArray().ToHexString().Should().Be(hex); - var copy = hex.HexToBytes().AsSerializable(); + var copy = hex.HexToBytes().AsSerializable(); Assert.AreEqual(attr.Scopes, copy.Scopes); CollectionAssert.AreEqual(attr.AllowedGroups, copy.AllowedGroups); @@ -88,7 +88,7 @@ public void Serialize_Deserialize_CustomGroups() [TestMethod] public void Json_Global() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.Global, Account = UInt160.Zero @@ -101,7 +101,7 @@ public void Json_Global() [TestMethod] public void Json_CalledByEntry() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CalledByEntry, Account = UInt160.Zero @@ -114,7 +114,7 @@ public void Json_CalledByEntry() [TestMethod] public void Json_CustomContracts() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CustomContracts, AllowedContracts = new[] { UInt160.Zero }, @@ -128,7 +128,7 @@ public void Json_CustomContracts() [TestMethod] public void Json_CustomGroups() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CustomGroups, AllowedGroups = new[] { ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1) }, diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 61ea913867..204e68e829 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -64,7 +64,6 @@ public void Gas_Set() public void Size_Get() { uut.Script = TestUtils.GetByteArray(32, 0x42); - uut.Sender = UInt160.Zero; uut.Attributes = Array.Empty(); uut.Witnesses = new[] { @@ -251,10 +250,10 @@ public void FeeIsSignatureContractDetailed() // Part II Assert.AreEqual(23, tx.Attributes.GetVarSize()); Assert.AreEqual(1, tx.Attributes.Length); - Assert.AreEqual(1, tx.Cosigners.Count); - Assert.AreEqual(23, tx.Cosigners.Values.ToArray().GetVarSize()); + Assert.AreEqual(1, tx.Signers.Count); + Assert.AreEqual(23, tx.Signers.Values.ToArray().GetVarSize()); // Note that Data size and Usage size are different (because of first byte on GetVarSize()) - Assert.AreEqual(22, tx.Cosigners.Values.First().Size); + Assert.AreEqual(22, tx.Signers.Values.First().Size); // Part III Assert.AreEqual(86, tx.Script.GetVarSize()); // Part IV @@ -308,7 +307,7 @@ public void FeeIsSignatureContract_TestScope_Global() } // trying global scope - var cosigners = new Cosigner[]{ new Cosigner + var cosigners = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.Global @@ -394,7 +393,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() } // trying global scope - var cosigners = new Cosigner[]{ new Cosigner + var cosigners = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, @@ -481,7 +480,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() } // trying CalledByEntry together with GAS - var cosigners = new Cosigner[]{ new Cosigner + var cosigners = new Signer[]{ new Signer { Account = acc.ScriptHash, // This combination is supposed to actually be an OR, @@ -569,7 +568,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() } // trying global scope - var cosigners = new Cosigner[]{ new Cosigner + var cosigners = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, @@ -621,7 +620,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() } // trying two custom hashes, for same target account - var cosigners = new Cosigner[]{ new Cosigner + var cosigners = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, @@ -650,7 +649,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // no attributes must exist tx.Attributes.Length.Should().Be(1); // one cosigner must exist - tx.Cosigners.Count.Should().Be(1); + tx.Signers.Count.Should().Be(1); // Fast check Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee)); @@ -731,13 +730,12 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = new[] { - new Cosigner + new Signer { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), Scopes = WitnessScope.Global @@ -759,7 +757,6 @@ public void Transaction_Serialize_Deserialize_Simple() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, @@ -791,7 +788,7 @@ public void Transaction_Serialize_Deserialize_Simple() tx2.NetworkFee.Should().Be(0x0000000000000001); tx2.ValidUntilBlock.Should().Be(0x01020304); tx2.Attributes.Should().BeEquivalentTo(new TransactionAttribute[0] { }); - tx2.Cosigners.Should().BeEquivalentTo(new Cosigner[0] { }); + tx2.Signers.Should().BeEquivalentTo(new Signer[0] { }); tx2.Script.Should().BeEquivalentTo(new byte[] { (byte)OpCode.PUSH1 }); tx2.Witnesses.Should().BeEquivalentTo(new Witness[0] { }); } @@ -805,18 +802,17 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = new[] { - new Cosigner + new Signer { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), Scopes = WitnessScope.Global }, - new Cosigner + new Signer { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), // same account as above Scopes = WitnessScope.CalledByEntry // different scope, but still, same account (cannot do that) @@ -850,13 +846,13 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() // -------------------------------------- // this should pass (respecting max size) - var cosigners1 = new Cosigner[maxCosigners]; + var cosigners1 = new Signer[maxCosigners]; for (int i = 0; i < cosigners1.Length; i++) { string hex = i.ToString("X4"); while (hex.Length < 40) hex = hex.Insert(0, "0"); - cosigners1[i] = new Cosigner + cosigners1[i] = new Signer { Account = UInt160.Parse(hex) }; @@ -866,7 +862,6 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, @@ -884,13 +879,13 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() // ---------------------------- // this should fail (max + 1) - var cosigners = new Cosigner[maxCosigners + 1]; + var cosigners = new Signer[maxCosigners + 1]; for (var i = 0; i < maxCosigners + 1; i++) { string hex = i.ToString("X4"); while (hex.Length < 40) hex = hex.Insert(0, "0"); - cosigners[i] = new Cosigner + cosigners[i] = new Signer { Account = UInt160.Parse(hex) }; @@ -900,7 +895,6 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, @@ -924,7 +918,7 @@ public void FeeIsSignatureContract_TestScope_Global_Default() { // Global is supposed to be default - Cosigner cosigner = new Cosigner(); + Signer cosigner = new Signer(); cosigner.Scopes.Should().Be(WitnessScope.Global); var wallet = TestUtils.GenerateTestWallet(); @@ -959,7 +953,7 @@ public void FeeIsSignatureContract_TestScope_Global_Default() } // default to global scope - var cosigners = new Cosigner[]{ new Cosigner + var cosigners = new Signer[]{ new Signer { Account = acc.ScriptHash } }; @@ -1013,7 +1007,6 @@ public void FeeIsSignatureContract_TestScope_Global_Default() public void ToJson() { uut.Script = TestUtils.GetByteArray(32, 0x42); - uut.Sender = UInt160.Zero; uut.SystemFee = 4200000000; uut.Attributes = Array.Empty(); uut.Witnesses = new[] diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs index a6cc76682f..279921bb35 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs @@ -54,8 +54,14 @@ private Witness PrepareDummyWitness(int maxAccounts) var data = new ContractParametersContext(new Transaction() { - Sender = multiSignContract.ScriptHash, - Attributes = Array.Empty(), + Attributes = new TransactionAttribute[] + { + new Signer() + { + Account = multiSignContract.ScriptHash, + Scopes = WitnessScope.CalledByEntry + } + }, NetworkFee = 0, Nonce = 0, Script = new byte[0], diff --git a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index 23e474e4b8..e56b0a5d6e 100644 --- a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -33,8 +33,7 @@ public static void ClassSetUp(TestContext context) [TestMethod] public void TestGetComplete() { - Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); + Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); var context = new ContractParametersContext(tx); context.Completed.Should().BeFalse(); } @@ -42,8 +41,7 @@ public void TestGetComplete() [TestMethod] public void TestToString() { - Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); + Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); var context = new ContractParametersContext(tx); context.Add(contract, 0, new byte[] { 0x01 }); string str = context.ToString(); @@ -68,11 +66,10 @@ public void TestFromJson() [TestMethod] public void TestAdd() { - Transaction tx = TestUtils.GetTransaction(); + Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0")); var context1 = new ContractParametersContext(tx); context1.Add(contract, 0, new byte[] { 0x01 }).Should().BeFalse(); - tx.Sender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); var context2 = new ContractParametersContext(tx); context2.Add(contract, 0, new byte[] { 0x01 }).Should().BeTrue(); //test repeatlly createItem @@ -82,8 +79,7 @@ public void TestAdd() [TestMethod] public void TestGetParameter() { - Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); + Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0")); var context = new ContractParametersContext(tx); context.GetParameter(tx.Sender, 0).Should().BeNull(); @@ -95,8 +91,7 @@ public void TestGetParameter() [TestMethod] public void TestGetWitnesses() { - Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); + Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0")); var context = new ContractParametersContext(tx); context.Add(contract, 0, new byte[] { 0x01 }); Witness[] witnesses = context.GetWitnesses(); @@ -108,9 +103,8 @@ public void TestGetWitnesses() [TestMethod] public void TestAddSignature() { - Transaction tx = TestUtils.GetTransaction(); var singleSender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); - tx.Sender = singleSender; + Transaction tx = TestUtils.GetTransaction(singleSender); //singleSign @@ -140,16 +134,16 @@ public void TestAddSignature() key2.PublicKey }); var multiSender = UInt160.Parse("0x3593816cc1085a6328fea2b899c24d78cd0ba372"); - tx.Sender = multiSender; + tx = TestUtils.GetTransaction(multiSender); context = new ContractParametersContext(tx); context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); context.AddSignature(multiSignContract, key2.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); - tx.Sender = singleSender; + tx = TestUtils.GetTransaction(singleSender); context = new ContractParametersContext(tx); context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeFalse(); - tx.Sender = multiSender; + tx = TestUtils.GetTransaction(multiSender); context = new ContractParametersContext(tx); byte[] privateKey3 = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 670c2530a5..75b31dffa6 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -250,7 +250,7 @@ public void TestRuntime_CheckWitness() ECPoint pubkey = keyPair.PublicKey; var engine = GetEngine(true); - ((Transaction)engine.ScriptContainer).Sender = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); + (((Transaction)engine.ScriptContainer).Attributes[0] as Signer).Account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); engine.CheckWitness(((Transaction)engine.ScriptContainer).Sender.ToArray()).Should().BeFalse(); @@ -698,7 +698,7 @@ public static void LogEvent(object sender, LogEventArgs args) private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false, bool addScript = true) { - var tx = TestUtils.GetTransaction(); + var tx = TestUtils.GetTransaction(UInt160.Zero); var snapshot = Blockchain.Singleton.GetSnapshot(); ApplicationEngine engine; if (hasContainer && hasSnapshot) diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 192e7292ff..c37b6c5779 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -32,7 +32,6 @@ public void System_Blockchain_GetBlock() ValidUntilBlock = 0x05, Version = 0x06, Witnesses = new Witness[] { new Witness() { VerificationScript = new byte[] { 0x07 } } }, - Sender = UInt160.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), }; var block = new Block() @@ -246,7 +245,6 @@ public void System_ExecutionEngine_GetScriptContainer() 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); diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index adaf205ea1..e4e1601dec 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -88,13 +88,19 @@ public static NEP6Wallet GenerateTestWallet() return new NEP6Wallet(wallet); } - public static Transaction GetTransaction() + public static Transaction GetTransaction(UInt160 sender) { return new Transaction { Script = new byte[1], - Sender = UInt160.Zero, - Attributes = Array.Empty(), + Attributes = new TransactionAttribute[] + { + new Signer() + { + Account = sender, + Scopes = WitnessScope.CalledByEntry + } + }, Witnesses = new Witness[]{ new Witness { InvocationScript = new byte[0], @@ -154,7 +160,7 @@ public static void SetupBlockWithValues(Block block, UInt256 val256, out UInt256 { for (int i = 0; i < numberOfTransactions; i++) { - transactionsVal[i] = TestUtils.GetTransaction(); + transactionsVal[i] = TestUtils.GetTransaction(UInt160.Zero); } } @@ -189,7 +195,6 @@ public static Transaction CreateRandomHashTransaction() return new Transaction { Script = randomBytes, - Sender = UInt160.Zero, Attributes = Array.Empty(), Witnesses = new[] { From 576973bb9cc270333b3c5bb862ad7802e34e488b Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 7 Jul 2020 10:41:41 +0200 Subject: [PATCH 02/27] Remove co- --- src/neo/SmartContract/ApplicationEngine.Runtime.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index eb38ee51af..0e49ccb078 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -104,23 +104,23 @@ internal bool CheckWitnessInternal(UInt160 hash) { if (ScriptContainer is Transaction tx) { - if (!tx.Signers.TryGetValue(hash, out Signer cosigner)) return false; - if (cosigner.Scopes == WitnessScope.Global) return true; - if (cosigner.Scopes.HasFlag(WitnessScope.CalledByEntry)) + if (!tx.Signers.TryGetValue(hash, out Signer signer)) return false; + if (signer.Scopes == WitnessScope.Global) return true; + if (signer.Scopes.HasFlag(WitnessScope.CalledByEntry)) { if (CallingScriptHash == EntryScriptHash) return true; } - if (cosigner.Scopes.HasFlag(WitnessScope.CustomContracts)) + if (signer.Scopes.HasFlag(WitnessScope.CustomContracts)) { - if (cosigner.AllowedContracts.Contains(CurrentScriptHash)) + if (signer.AllowedContracts.Contains(CurrentScriptHash)) return true; } - if (cosigner.Scopes.HasFlag(WitnessScope.CustomGroups)) + if (signer.Scopes.HasFlag(WitnessScope.CustomGroups)) { var contract = Snapshot.Contracts[CallingScriptHash]; // check if current group is the required one - if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(cosigner.AllowedGroups).Any()) + if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(signer.AllowedGroups).Any()) return true; } return false; From 4d70d15aaa7abe3bc48a7bf473a68ba9b9c5c174 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 8 Jul 2020 17:02:50 +0200 Subject: [PATCH 03/27] Move signers outside attributes --- src/neo/Ledger/Blockchain.cs | 8 +- src/neo/Network/P2P/Payloads/Signer.cs | 15 +-- src/neo/Network/P2P/Payloads/Signers.cs | 108 ++++++++++++++++++ src/neo/Network/P2P/Payloads/Transaction.cs | 25 ++-- .../P2P/Payloads/TransactionAttributeType.cs | 4 +- src/neo/Wallets/Wallet.cs | 52 +++------ .../{UT_Cosigner.cs => UT_Signers.cs} | 2 +- .../Network/P2P/Payloads/UT_Transaction.cs | 60 ++++++---- .../Network/P2P/Payloads/UT_Witness.cs | 12 +- .../SmartContract/UT_InteropService.cs | 2 +- tests/neo.UnitTests/TestUtils.cs | 10 +- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 9 +- 12 files changed, 200 insertions(+), 107 deletions(-) create mode 100644 src/neo/Network/P2P/Payloads/Signers.cs rename tests/neo.UnitTests/Network/P2P/Payloads/{UT_Cosigner.cs => UT_Signers.cs} (99%) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index c09b08cd8a..af83cf5227 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -167,13 +167,7 @@ private static Transaction DeployNativeContracts() Version = 0, Script = script, SystemFee = 0, - Attributes = new TransactionAttribute[] - { - new Signer() - { - Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash() - } - }, + Signers = new Signer() { Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash() }, Witnesses = new[] { new Witness diff --git a/src/neo/Network/P2P/Payloads/Signer.cs b/src/neo/Network/P2P/Payloads/Signer.cs index 0cd2118515..72a623fb2e 100644 --- a/src/neo/Network/P2P/Payloads/Signer.cs +++ b/src/neo/Network/P2P/Payloads/Signer.cs @@ -6,7 +6,7 @@ namespace Neo.Network.P2P.Payloads { - public class Signer : TransactionAttribute + public class Signer : ISerializable { // This limits maximum number of AllowedContracts or AllowedGroups here private const int MaxSubitems = 16; @@ -16,16 +16,13 @@ public class Signer : TransactionAttribute public UInt160[] AllowedContracts; public ECPoint[] AllowedGroups; - public override TransactionAttributeType Type => TransactionAttributeType.Signer; - public override bool AllowMultiple => true; - - public override int Size => base.Size + + public int Size => /*Account*/ UInt160.Length + /*Scopes*/ sizeof(WitnessScope) + /*AllowedContracts*/ (Scopes.HasFlag(WitnessScope.CustomContracts) ? AllowedContracts.GetVarSize() : 0) + /*AllowedGroups*/ (Scopes.HasFlag(WitnessScope.CustomGroups) ? AllowedGroups.GetVarSize() : 0); - protected override void DeserializeWithoutType(BinaryReader reader) + public void Deserialize(BinaryReader reader) { Account = reader.ReadSerializable(); Scopes = (WitnessScope)reader.ReadByte(); @@ -37,7 +34,7 @@ protected override void DeserializeWithoutType(BinaryReader reader) : new ECPoint[0]; } - protected override void SerializeWithoutType(BinaryWriter writer) + public void Serialize(BinaryWriter writer) { writer.Write(Account); writer.Write((byte)Scopes); @@ -47,9 +44,9 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(AllowedGroups); } - public override JObject ToJson() + public JObject ToJson() { - JObject json = base.ToJson(); + var json = new JObject(); json["account"] = Account.ToString(); json["scopes"] = Scopes; if (Scopes.HasFlag(WitnessScope.CustomContracts)) diff --git a/src/neo/Network/P2P/Payloads/Signers.cs b/src/neo/Network/P2P/Payloads/Signers.cs new file mode 100644 index 0000000000..d13ff28fc1 --- /dev/null +++ b/src/neo/Network/P2P/Payloads/Signers.cs @@ -0,0 +1,108 @@ +using Neo.IO; +using Neo.IO.Json; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Neo.Network.P2P.Payloads +{ + public class Signers : ISerializable, IEnumerable + { + private Signer[] _signers; + private Dictionary _cache; + + public int Size => Entries.GetVarSize(); + + public Signer[] Entries + { + get => _signers; + set + { + var cache = value.ToDictionary(u => u.Account); + if (cache.Count != value.Length) + throw new FormatException(); + + _cache = cache; + _signers = value; + Sender = value.Length > 0 ? value[0].Account : UInt160.Zero; + } + } + + public Signer this[UInt160 hash] + { + get + { + if (_cache.TryGetValue(hash, out var value)) return value; + return null; + } + } + + /// + /// Correspond with the first entry of Signers + /// + public UInt160 Sender { get; private set; } = UInt160.Zero; + + /// + /// Keys + /// + public IEnumerable Keys => _cache.Keys; + + /// + /// Count + /// + public int Count => _signers.Length; + + public void Deserialize(BinaryReader reader) + { + Entries = reader.ReadSerializableArray(byte.MaxValue); + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(Entries); + } + + public Signers() { } + + /// + /// Constructor with values + /// + /// Entries + public Signers(params Signer[] entries) + { + Entries = entries; + } + + public JObject ToJson() + { + return Entries.Select(p => p.ToJson()).ToArray(); + } + + /// + /// Try get value + /// + /// Hash + /// Signer + /// + public bool TryGetValue(UInt160 hash, out Signer signer) + { + if (_cache.TryGetValue(hash, out signer)) return true; + return false; + } + + public IEnumerator GetEnumerator() + { + return (IEnumerator)_signers.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _signers.GetEnumerator(); + } + + public static implicit operator Signers(Signer signer) => new Signers(signer); + public static implicit operator Signers(Signer[] signers) => new Signers(signers); + } +} diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 8fd6f998d2..995eb31510 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -34,6 +34,7 @@ public class Transaction : IEquatable, IInventory, IInteroperable private TransactionAttribute[] attributes; private byte[] script; private Witness[] witnesses; + private Signers _signers; public const int HeaderSize = sizeof(byte) + //Version @@ -49,9 +50,16 @@ public TransactionAttribute[] Attributes set { attributes = value; _signers = null; _hash = null; _size = 0; } } - private Dictionary _signers; - public IReadOnlyDictionary Signers => _signers ??= attributes.OfType().ToDictionary(p => p.Account); - public UInt160 Sender => attributes.OfType().Select(p => p.Account).First(); + public Signers Signers + { + get => _signers; + set { Signers = value; _hash = null; _size = 0; } + } + + /// + /// Correspond with the first entry of Signers + /// + public UInt160 Sender => _signers.Sender; /// /// The NetworkFee for the transaction divided by its Size. @@ -174,14 +182,7 @@ public void DeserializeUnsigned(BinaryReader reader) if (SystemFee + NetworkFee < SystemFee) throw new FormatException(); ValidUntilBlock = reader.ReadUInt32(); Attributes = DeserializeAttributes(reader).ToArray(); - try - { - _ = Signers; - } - catch (ArgumentException) - { - throw new FormatException(); - } + Signers = reader.ReadSerializable(); Script = reader.ReadVarBytes(ushort.MaxValue); if (Script.Length == 0) throw new FormatException(); } @@ -228,6 +229,7 @@ void IVerifiable.SerializeUnsigned(BinaryWriter writer) writer.Write(NetworkFee); writer.Write(ValidUntilBlock); writer.Write(Attributes); + writer.Write(Signers); writer.WriteVarBytes(Script); } @@ -243,6 +245,7 @@ public JObject ToJson() json["netfee"] = NetworkFee.ToString(); json["validuntilblock"] = ValidUntilBlock; json["attributes"] = Attributes.Select(p => p.ToJson()).ToArray(); + json["signers"] = Signers.ToJson(); json["script"] = Convert.ToBase64String(Script); json["witnesses"] = Witnesses.Select(p => p.ToJson()).ToArray(); return json; diff --git a/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs b/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs index fc9bceab89..d6224db0b2 100644 --- a/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs +++ b/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs @@ -4,7 +4,7 @@ namespace Neo.Network.P2P.Payloads { public enum TransactionAttributeType : byte { - [ReflectionCache(typeof(Signer))] - Signer = 0x01 + //[ReflectionCache(typeof(Signer))] + //Signer = 0x01 } } diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index d105a5d7d5..949feefd87 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -236,7 +236,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null } using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { - HashSet cosignerList = new HashSet(); + HashSet signersList = new HashSet(); byte[] script; List<(UInt160 Account, BigInteger Value)> balances_gas = null; using (ScriptBuilder sb = new ScriptBuilder()) @@ -263,7 +263,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null { balances = balances.OrderBy(p => p.Value).ToList(); var balances_used = FindPayingAccounts(balances, output.Value.Value); - cosignerList.UnionWith(balances_used.Select(p => p.Account)); + signersList.UnionWith(balances_used.Select(p => p.Account)); foreach (var (account, value) in balances_used) { sb.EmitAppCall(output.AssetId, "transfer", account, output.ScriptHash, value); @@ -278,20 +278,21 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null if (balances_gas is null) balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - var cosigners = cosignerList.Select(p => - new Signer() - { - // default access for transfers should be valid only for first invocation - Scopes = WitnessScope.CalledByEntry, - Account = new UInt160(p.ToArray()) - }).ToArray(); + var signers = new Signers(signersList.Select(p => + new Signer() + { + // default access for transfers should be valid only for first invocation + Scopes = WitnessScope.CalledByEntry, + Account = new UInt160(p.ToArray()) + }).ToArray()); - return MakeTransaction(snapshot, script, cosigners, balances_gas); + return MakeTransaction(snapshot, script, signers, null, balances_gas); } } - public Transaction MakeTransaction(byte[] script, UInt160 sender = null, TransactionAttribute[] attributes = null) + public Transaction MakeTransaction(byte[] script, Signers signers = null, TransactionAttribute[] attributes = null) { + var sender = signers?.Sender; UInt160[] accounts; if (sender is null) { @@ -306,44 +307,23 @@ public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Transac using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { var balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - return MakeTransaction(snapshot, script, attributes ?? new TransactionAttribute[0], balances_gas); + return MakeTransaction(snapshot, script, signers, attributes ?? Array.Empty(), balances_gas); } } - private Transaction MakeTransaction(StoreView snapshot, byte[] script, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) + private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signers signers, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) { Random rand = new Random(); foreach (var (account, value) in balances_gas) { - var attr = new List(); - - if (!attributes.OfType().Any(u => u.Account == account)) - { - // Add a new signer - - attr.Add(new Signer() - { - Account = account, - Scopes = WitnessScope.CalledByEntry - }); - attr.AddRange(attributes); - } - else - { - // Use the first signer of this account - - var ac = attributes.OfType().First(u => u.Account == account); - attr.Add(ac); - attr.AddRange(attributes.Where(u => u != ac)); - } - Transaction tx = new Transaction { Version = 0, Nonce = (uint)rand.Next(), Script = script, ValidUntilBlock = snapshot.Height + Transaction.MaxValidUntilBlockIncrement, - Attributes = attr.ToArray(), + Signers = signers, + Attributes = attributes ?? Array.Empty(), }; // will try to execute 'transfer' script to check if it works diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs similarity index 99% rename from tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs rename to tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs index a487fea297..ca834b7c65 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs @@ -7,7 +7,7 @@ namespace Neo.UnitTests.Network.P2P.Payloads { [TestClass] - public class UT_Cosigner + public class UT_Signers { [TestMethod] public void Serialize_Deserialize_Global() diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 204e68e829..19e4ab5226 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -251,9 +251,9 @@ public void FeeIsSignatureContractDetailed() Assert.AreEqual(23, tx.Attributes.GetVarSize()); Assert.AreEqual(1, tx.Attributes.Length); Assert.AreEqual(1, tx.Signers.Count); - Assert.AreEqual(23, tx.Signers.Values.ToArray().GetVarSize()); + Assert.AreEqual(23, tx.Signers.Size); // Note that Data size and Usage size are different (because of first byte on GetVarSize()) - Assert.AreEqual(22, tx.Signers.Values.First().Size); + Assert.AreEqual(22, tx.Signers.First().Size); // Part III Assert.AreEqual(86, tx.Script.GetVarSize()); // Part IV @@ -307,7 +307,7 @@ public void FeeIsSignatureContract_TestScope_Global() } // trying global scope - var cosigners = new Signer[]{ new Signer + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.Global @@ -315,7 +315,7 @@ public void FeeIsSignatureContract_TestScope_Global() // using this... - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, new Signers(signers)); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -393,7 +393,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() } // trying global scope - var cosigners = new Signer[]{ new Signer + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, @@ -402,7 +402,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() // using this... - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, new Signers(signers)); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -480,7 +480,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() } // trying CalledByEntry together with GAS - var cosigners = new Signer[]{ new Signer + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, // This combination is supposed to actually be an OR, @@ -492,7 +492,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() // using this... - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, new Signers(signers)); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -568,7 +568,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() } // trying global scope - var cosigners = new Signer[]{ new Signer + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, @@ -580,7 +580,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners)); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, new Signers(signers))); Assert.IsNull(tx); } } @@ -620,7 +620,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() } // trying two custom hashes, for same target account - var cosigners = new Signer[]{ new Signer + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, @@ -629,7 +629,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // using this... - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, new Signers(signers)); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -703,7 +703,7 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); @@ -712,12 +712,19 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() // trying with no scope var attributes = new TransactionAttribute[] { }; + var signers = new Signer[]{ new Signer + { + Account = acc.ScriptHash, + Scopes = (WitnessScope) 0xFF, + AllowedContracts = new[] { NativeContract.NEO.Hash, NativeContract.GAS.Hash } + } }; + // using this... // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, acc.ScriptHash, attributes)); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, new Signers(signers), attributes)); Assert.IsNull(tx); } } @@ -733,14 +740,14 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = new[] - { + Attributes = Array.Empty(), + Signers = new Signers( new Signer { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), Scopes = WitnessScope.Global } - }, + ), Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } }; @@ -805,19 +812,20 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = new[] + Attributes = Array.Empty(), + Signers = new Signers(new Signer[] { - new Signer + new Signer() { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), Scopes = WitnessScope.Global }, - new Signer + new Signer() { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), // same account as above Scopes = WitnessScope.CalledByEntry // different scope, but still, same account (cannot do that) } - }, + }), Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } }; @@ -865,7 +873,8 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = cosigners1, // max + 1 (should fail) + Attributes = Array.Empty(), + Signers = new Signers(cosigners1), // max + 1 (should fail) Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } }; @@ -898,7 +907,8 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = cosigners, // max + 1 (should fail) + Attributes = Array.Empty(), + Signers = new Signers(cosigners1), // max + 1 (should fail) Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } }; @@ -953,14 +963,14 @@ public void FeeIsSignatureContract_TestScope_Global_Default() } // default to global scope - var cosigners = new Signer[]{ new Signer + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash } }; // using this... - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, new Signers(signers)); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs index 279921bb35..436b5cf723 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs @@ -54,14 +54,12 @@ private Witness PrepareDummyWitness(int maxAccounts) var data = new ContractParametersContext(new Transaction() { - Attributes = new TransactionAttribute[] + Attributes = Array.Empty(), + Signers = new Signers(new Signer() { - new Signer() - { - Account = multiSignContract.ScriptHash, - Scopes = WitnessScope.CalledByEntry - } - }, + Account = multiSignContract.ScriptHash, + Scopes = WitnessScope.CalledByEntry + }), NetworkFee = 0, Nonce = 0, Script = new byte[0], diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 75b31dffa6..17b73fadf6 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -250,7 +250,7 @@ public void TestRuntime_CheckWitness() ECPoint pubkey = keyPair.PublicKey; var engine = GetEngine(true); - (((Transaction)engine.ScriptContainer).Attributes[0] as Signer).Account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); + (((Transaction)engine.ScriptContainer).Signers.Entries[0]).Account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); engine.CheckWitness(((Transaction)engine.ScriptContainer).Sender.ToArray()).Should().BeFalse(); diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index e4e1601dec..79096781e0 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -93,13 +93,11 @@ public static Transaction GetTransaction(UInt160 sender) return new Transaction { Script = new byte[1], - Attributes = new TransactionAttribute[] + Attributes = Array.Empty(), + Signers = new Signer() { - new Signer() - { - Account = sender, - Scopes = WitnessScope.CalledByEntry - } + Account = sender, + Scopes = WitnessScope.CalledByEntry }, Witnesses = new Witness[]{ new Witness { diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index e63145ff5d..ba0b007f21 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -367,7 +367,7 @@ public void TestMakeTransaction1() public void TestMakeTransaction2() { MyWallet wallet = new MyWallet(); - Action action = () => wallet.MakeTransaction(new byte[] { }, UInt160.Zero, new TransactionAttribute[] { }); + Action action = () => wallet.MakeTransaction(new byte[] { }, null, new TransactionAttribute[] { }); action.Should().Throw(); Contract contract = Contract.Create(new ContractParameterType[] { ContractParameterType.Boolean }, new byte[] { 1 }); @@ -381,7 +381,12 @@ public void TestMakeTransaction2() entry.GetInteroperable().Balance = 1000000 * NativeContract.GAS.Factor; snapshot.Commit(); - var tx = wallet.MakeTransaction(new byte[] { }, account.ScriptHash, new TransactionAttribute[] { }); + var tx = wallet.MakeTransaction(new byte[] { }, new Signers(new Signer() + { + Account = account.ScriptHash, + Scopes = WitnessScope.Global + }), new TransactionAttribute[] { }); + tx.Should().NotBeNull(); tx = wallet.MakeTransaction(new byte[] { }, null, new TransactionAttribute[] { }); From d7754927eb2944bffec3a39232cf09ae4d8b962d Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 9 Jul 2020 10:46:32 +0200 Subject: [PATCH 04/27] Fix UT and remove Signers class --- src/neo/Ledger/Blockchain.cs | 3 +- src/neo/Network/P2P/Payloads/Signers.cs | 108 ---------------- src/neo/Network/P2P/Payloads/Transaction.cs | 35 ++++-- .../ApplicationEngine.Runtime.cs | 2 +- src/neo/Wallets/Wallet.cs | 18 +-- .../Consensus/UT_ConsensusContext.cs | 2 + .../Cryptography/UT_Cryptography_Helper.cs | 1 + .../neo.UnitTests/IO/Caching/UT_RelayCache.cs | 3 +- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 50 ++++---- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 2 + tests/neo.UnitTests/Ledger/UT_PoolItem.cs | 3 +- .../Ledger/UT_SendersFeeMonitor.cs | 1 + .../Ledger/UT_TransactionState.cs | 2 +- .../Network/P2P/Payloads/UT_Block.cs | 18 +-- .../Network/P2P/Payloads/UT_Signers.cs | 16 +-- .../Network/P2P/Payloads/UT_Transaction.cs | 118 +++++++++--------- .../Network/P2P/Payloads/UT_Witness.cs | 4 +- .../UT_ContractParameterContext.cs | 7 +- .../SmartContract/UT_InteropService.cs | 2 +- .../SmartContract/UT_Syscalls.cs | 2 + tests/neo.UnitTests/TestUtils.cs | 7 +- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 6 +- 22 files changed, 165 insertions(+), 245 deletions(-) delete mode 100644 src/neo/Network/P2P/Payloads/Signers.cs diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index af83cf5227..81951209cb 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -167,7 +167,8 @@ private static Transaction DeployNativeContracts() Version = 0, Script = script, SystemFee = 0, - Signers = new Signer() { Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash() }, + Signers = new[] { new Signer() { Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash() } }, + Attributes = Array.Empty(), Witnesses = new[] { new Witness diff --git a/src/neo/Network/P2P/Payloads/Signers.cs b/src/neo/Network/P2P/Payloads/Signers.cs deleted file mode 100644 index d13ff28fc1..0000000000 --- a/src/neo/Network/P2P/Payloads/Signers.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Neo.IO; -using Neo.IO.Json; -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace Neo.Network.P2P.Payloads -{ - public class Signers : ISerializable, IEnumerable - { - private Signer[] _signers; - private Dictionary _cache; - - public int Size => Entries.GetVarSize(); - - public Signer[] Entries - { - get => _signers; - set - { - var cache = value.ToDictionary(u => u.Account); - if (cache.Count != value.Length) - throw new FormatException(); - - _cache = cache; - _signers = value; - Sender = value.Length > 0 ? value[0].Account : UInt160.Zero; - } - } - - public Signer this[UInt160 hash] - { - get - { - if (_cache.TryGetValue(hash, out var value)) return value; - return null; - } - } - - /// - /// Correspond with the first entry of Signers - /// - public UInt160 Sender { get; private set; } = UInt160.Zero; - - /// - /// Keys - /// - public IEnumerable Keys => _cache.Keys; - - /// - /// Count - /// - public int Count => _signers.Length; - - public void Deserialize(BinaryReader reader) - { - Entries = reader.ReadSerializableArray(byte.MaxValue); - } - - public void Serialize(BinaryWriter writer) - { - writer.Write(Entries); - } - - public Signers() { } - - /// - /// Constructor with values - /// - /// Entries - public Signers(params Signer[] entries) - { - Entries = entries; - } - - public JObject ToJson() - { - return Entries.Select(p => p.ToJson()).ToArray(); - } - - /// - /// Try get value - /// - /// Hash - /// Signer - /// - public bool TryGetValue(UInt160 hash, out Signer signer) - { - if (_cache.TryGetValue(hash, out signer)) return true; - return false; - } - - public IEnumerator GetEnumerator() - { - return (IEnumerator)_signers.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _signers.GetEnumerator(); - } - - public static implicit operator Signers(Signer signer) => new Signers(signer); - public static implicit operator Signers(Signer[] signers) => new Signers(signers); - } -} diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 995eb31510..1564db9b42 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -34,12 +34,12 @@ public class Transaction : IEquatable, IInventory, IInteroperable private TransactionAttribute[] attributes; private byte[] script; private Witness[] witnesses; - private Signers _signers; + private Signer[] _signers; + private Dictionary _signersCache; public const int HeaderSize = sizeof(byte) + //Version sizeof(uint) + //Nonce - 20 + //Sender sizeof(long) + //SystemFee sizeof(long) + //NetworkFee sizeof(uint); //ValidUntilBlock @@ -47,19 +47,29 @@ public class Transaction : IEquatable, IInventory, IInteroperable public TransactionAttribute[] Attributes { get => attributes; - set { attributes = value; _signers = null; _hash = null; _size = 0; } + set { attributes = value; _hash = null; _size = 0; } } - public Signers Signers + public Signer[] Signers { get => _signers; - set { Signers = value; _hash = null; _size = 0; } + set + { + var cache = value.ToDictionary(u => u.Account); + if (cache.Count != value.Length) + throw new FormatException("Signers accounts must be unique"); + + _signersCache = cache; + _signers = value; + _hash = null; + _size = 0; + } } /// /// Correspond with the first entry of Signers /// - public UInt160 Sender => _signers.Sender; + public UInt160 Sender => _signers.Length > 0 ? _signers[0].Account : UInt160.Zero; /// /// The NetworkFee for the transaction divided by its Size. @@ -112,6 +122,7 @@ public int Size { _size = HeaderSize + Attributes.GetVarSize() + // Attributes + Signers.GetVarSize() + // Signers Script.GetVarSize() + // Script Witnesses.GetVarSize(); // Witnesses } @@ -170,6 +181,11 @@ private static IEnumerable DeserializeAttributes(BinaryRea } } + public bool TryGetSigner(UInt160 hash, out Signer signer) + { + return _signersCache.TryGetValue(hash, out signer); + } + public void DeserializeUnsigned(BinaryReader reader) { Version = reader.ReadByte(); @@ -182,7 +198,7 @@ public void DeserializeUnsigned(BinaryReader reader) if (SystemFee + NetworkFee < SystemFee) throw new FormatException(); ValidUntilBlock = reader.ReadUInt32(); Attributes = DeserializeAttributes(reader).ToArray(); - Signers = reader.ReadSerializable(); + Signers = reader.ReadSerializableArray(MaxTransactionAttributes); Script = reader.ReadVarBytes(ushort.MaxValue); if (Script.Length == 0) throw new FormatException(); } @@ -211,7 +227,7 @@ public override int GetHashCode() public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { - return Signers.Keys.OrderBy(p => p).ToArray(); + return _signersCache.Keys.OrderBy(p => p).ToArray(); } void ISerializable.Serialize(BinaryWriter writer) @@ -224,7 +240,6 @@ void IVerifiable.SerializeUnsigned(BinaryWriter writer) { writer.Write(Version); writer.Write(Nonce); - writer.Write(Sender); writer.Write(SystemFee); writer.Write(NetworkFee); writer.Write(ValidUntilBlock); @@ -245,7 +260,7 @@ public JObject ToJson() json["netfee"] = NetworkFee.ToString(); json["validuntilblock"] = ValidUntilBlock; json["attributes"] = Attributes.Select(p => p.ToJson()).ToArray(); - json["signers"] = Signers.ToJson(); + json["signers"] = Signers.Select(p => p.ToJson()).ToArray(); json["script"] = Convert.ToBase64String(Script); json["witnesses"] = Witnesses.Select(p => p.ToJson()).ToArray(); return json; diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index 0e49ccb078..607bc077ff 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -104,7 +104,7 @@ internal bool CheckWitnessInternal(UInt160 hash) { if (ScriptContainer is Transaction tx) { - if (!tx.Signers.TryGetValue(hash, out Signer signer)) return false; + if (!tx.TryGetSigner(hash, out Signer signer)) return false; if (signer.Scopes == WitnessScope.Global) return true; if (signer.Scopes.HasFlag(WitnessScope.CalledByEntry)) { diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 949feefd87..f1c2a49566 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -278,30 +278,30 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null if (balances_gas is null) balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - var signers = new Signers(signersList.Select(p => + var signers = signersList.Select(p => new Signer() { // default access for transfers should be valid only for first invocation Scopes = WitnessScope.CalledByEntry, Account = new UInt160(p.ToArray()) - }).ToArray()); + }).ToArray(); return MakeTransaction(snapshot, script, signers, null, balances_gas); } } - public Transaction MakeTransaction(byte[] script, Signers signers = null, TransactionAttribute[] attributes = null) + public Transaction MakeTransaction(byte[] script, Signer[] signers = null, TransactionAttribute[] attributes = null) { - var sender = signers?.Sender; + var sender = signers?.Length > 0 ? signers[0].Account : UInt160.Zero; UInt160[] accounts; - if (sender is null) + if (sender == UInt160.Zero) { accounts = GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray(); } else { if (!Contains(sender)) - throw new ArgumentException($"The address {sender.ToString()} was not found in the wallet"); + throw new ArgumentException($"The address {sender} was not found in the wallet"); accounts = new[] { sender }; } using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) @@ -311,7 +311,7 @@ public Transaction MakeTransaction(byte[] script, Signers signers = null, Transa } } - private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signers signers, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) + private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] signers, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) { Random rand = new Random(); foreach (var (account, value) in balances_gas) @@ -322,7 +322,7 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signers s Nonce = (uint)rand.Next(), Script = script, ValidUntilBlock = snapshot.Height + Transaction.MaxValidUntilBlockIncrement, - Signers = signers, + Signers = signers ?? Array.Empty(), Attributes = attributes ?? Array.Empty(), }; @@ -337,7 +337,7 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signers s UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); // base size for transaction: includes const_header + attributes + script + hashes - int size = Transaction.HeaderSize + tx.Attributes.GetVarSize() + script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + int size = Transaction.HeaderSize + tx.Attributes.GetVarSize() + tx.Signers.GetVarSize() + script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); foreach (UInt160 hash in hashes) { diff --git a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs index ea7ce9c6e0..358e8b1776 100644 --- a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs +++ b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs @@ -125,6 +125,7 @@ private Transaction CreateTransactionWithSize(int v) var tx = new Transaction() { Attributes = System.Array.Empty(), + Signers = System.Array.Empty(), NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[0], @@ -144,6 +145,7 @@ private Transaction CreateTransactionWithSytemFee(long fee) var tx = new Transaction() { Attributes = System.Array.Empty(), + Signers = System.Array.Empty(), NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[0], diff --git a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index f6e94e9fb6..65aa81e0c0 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -153,6 +153,7 @@ public void TestTest() { Script = TestUtils.GetByteArray(32, 0x42), SystemFee = 4200000000, + Signers = Array.Empty(), Attributes = Array.Empty(), Witnesses = new[] { diff --git a/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs b/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs index 79a817ab95..659b7f5797 100644 --- a/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs +++ b/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs @@ -28,8 +28,9 @@ public void TestGetKeyForItem() NetworkFee = 0, ValidUntilBlock = 100, Attributes = Array.Empty(), + Signers = Array.Empty(), Script = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04 }, - Witnesses = new Witness[0] + Witnesses = Array.Empty() }; relayCache.Add(tx); relayCache.Contains(tx).Should().BeTrue(); diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index f68f1eeab7..38f39fd374 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -73,13 +73,13 @@ public void TestContainsTransaction() [TestMethod] public void TestGetCurrentBlockHash() { - Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0x3843c6d0dd2082a801cf3da0fe0e847ba8d5571e0606c5018f9a35ce49c55e18")); + Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0xc5e3965587c58ff2a38e3f152e054e5cbc6f114ac3d83c7189eb4bb73294679d")); } [TestMethod] public void TestGetCurrentHeaderHash() { - Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0x3843c6d0dd2082a801cf3da0fe0e847ba8d5571e0606c5018f9a35ce49c55e18")); + Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0xc5e3965587c58ff2a38e3f152e054e5cbc6f114ac3d83c7189eb4bb73294679d")); } [TestMethod] @@ -91,7 +91,7 @@ public void TestGetBlock() [TestMethod] public void TestGetBlockHash() { - Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0x3843c6d0dd2082a801cf3da0fe0e847ba8d5571e0606c5018f9a35ce49c55e18")); + Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0xc5e3965587c58ff2a38e3f152e054e5cbc6f114ac3d83c7189eb4bb73294679d")); Blockchain.Singleton.GetBlockHash(10).Should().BeNull(); } @@ -109,33 +109,29 @@ public void TestValidTransaction() var snapshot = Blockchain.Singleton.GetSnapshot(); var walletA = TestUtils.GenerateTestWallet(); - using (var unlockA = walletA.Unlock("123")) - { - var acc = walletA.CreateAccount(); - - // Fake balance + using var unlockA = walletA.Unlock("123"); + var acc = walletA.CreateAccount(); - var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + // Fake balance - entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; + var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(acc.ScriptHash); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; + snapshot.Commit(); - snapshot.Commit(); + typeof(Blockchain) + .GetMethod("UpdateCurrentSnapshot", BindingFlags.Instance | BindingFlags.NonPublic) + .Invoke(Blockchain.Singleton, null); - typeof(Blockchain) - .GetMethod("UpdateCurrentSnapshot", BindingFlags.Instance | BindingFlags.NonPublic) - .Invoke(Blockchain.Singleton, null); + // Make transaction - // Make transaction + var tx = CreateValidTx(walletA, acc.ScriptHash, 0); - var tx = CreateValidTx(walletA, acc.ScriptHash, 0); + senderProbe.Send(system.Blockchain, tx); + senderProbe.ExpectMsg(p => p.Result == VerifyResult.Succeed); - senderProbe.Send(system.Blockchain, tx); - senderProbe.ExpectMsg(p => p.Result == VerifyResult.Succeed); - - senderProbe.Send(system.Blockchain, tx); - senderProbe.ExpectMsg(p => p.Result == VerifyResult.AlreadyExists); - } + senderProbe.Send(system.Blockchain, tx); + senderProbe.ExpectMsg(p => p.Result == VerifyResult.AlreadyExists); } [TestMethod] @@ -145,6 +141,7 @@ public void TestInvalidTransactionInPersist() var tx = new Transaction() { Attributes = Array.Empty(), + Signers = Array.Empty(), NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[] { 1 }, @@ -183,9 +180,9 @@ private Transaction CreateValidTx(NEP6Wallet wallet, UInt160 account, uint nonce { new TransferOutput() { - AssetId = NativeContract.GAS.Hash, - ScriptHash = account, - Value = new BigDecimal(1,8) + AssetId = NativeContract.GAS.Hash, + ScriptHash = account, + Value = new BigDecimal(1,8) } }, account); @@ -197,7 +194,6 @@ private Transaction CreateValidTx(NEP6Wallet wallet, UInt160 account, uint nonce Assert.IsTrue(data.Completed); tx.Witnesses = data.GetWitnesses(); - return tx; } } diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index dd103cc674..d1cd5b482b 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -79,6 +79,7 @@ private Transaction CreateTransactionWithFee(long fee) mock.Object.Script = randomBytes; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); + mock.Object.Signers = Array.Empty(); mock.Object.Witnesses = new[] { new Witness @@ -102,6 +103,7 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) mock.Object.Script = randomBytes; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); + mock.Object.Signers = Array.Empty(); mock.Object.Witnesses = new[] { new Witness diff --git a/tests/neo.UnitTests/Ledger/UT_PoolItem.cs b/tests/neo.UnitTests/Ledger/UT_PoolItem.cs index 6ed25e74b7..4c4c406c62 100644 --- a/tests/neo.UnitTests/Ledger/UT_PoolItem.cs +++ b/tests/neo.UnitTests/Ledger/UT_PoolItem.cs @@ -120,6 +120,7 @@ public static Transaction GenerateTx(long networkFee, int size, byte[] overrideS Script = overrideScriptBytes ?? new byte[0], NetworkFee = networkFee, Attributes = Array.Empty(), + Signers = Array.Empty(), Witnesses = new[] { new Witness @@ -131,7 +132,7 @@ public static Transaction GenerateTx(long networkFee, int size, byte[] overrideS }; tx.Attributes.Length.Should().Be(0); - tx.Signers.Count.Should().Be(0); + tx.Signers.Length.Should().Be(0); int diff = size - tx.Size; if (diff < 0) throw new ArgumentException(); diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs index 923ef206cc..d10a70eaeb 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -24,6 +24,7 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) mock.Object.NetworkFee = networkFee; mock.Object.SystemFee = systemFee; mock.Object.Attributes = Array.Empty(); + mock.Object.Signers = Array.Empty(); mock.Object.Witnesses = new[] { new Witness diff --git a/tests/neo.UnitTests/Ledger/UT_TransactionState.cs b/tests/neo.UnitTests/Ledger/UT_TransactionState.cs index 9446b954d2..e30416a136 100644 --- a/tests/neo.UnitTests/Ledger/UT_TransactionState.cs +++ b/tests/neo.UnitTests/Ledger/UT_TransactionState.cs @@ -61,7 +61,7 @@ public void TestDeserialize() [TestMethod] public void TestGetSize() { - ((ISerializable)origin).Size.Should().Be(61); + ((ISerializable)origin).Size.Should().Be(63); } } } diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index b4f222127d..8449dc219e 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -59,7 +59,7 @@ public void Size_Get_1_Transaction() TestUtils.GetTransaction(UInt160.Zero) }; - uut.Size.Should().Be(165); + uut.Size.Should().Be(167); } [TestMethod] @@ -75,7 +75,7 @@ public void Size_Get_3_Transaction() TestUtils.GetTransaction(UInt160.Zero) }; - uut.Size.Should().Be(267); + uut.Size.Should().Be(273); } [TestMethod] @@ -84,7 +84,7 @@ public void Serialize() UInt256 val256 = UInt256.Zero; TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, 1); - var hex = "000000000000000000000000000000000000000000000000000000000000000000000000bc72014eb4f1fcdd27831b79c42ffa71e1b949086a97c87654a644585dd616f6e913ff854c0000000000000000000000000000000000000000000000000000000100011102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000"; + var hex = "000000000000000000000000000000000000000000000000000000000000000000000000ecba43e27d4cff6e139ae5c1424151aa41f8bcf1c89132d1a98a915740d271d9e913ff854c00000000000000000000000000000000000000000000000000000001000111020000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010100010000"; uut.ToArray().ToHexString().Should().Be(hex); } @@ -94,7 +94,7 @@ public void Deserialize() UInt256 val256 = UInt256.Zero; TestUtils.SetupBlockWithValues(new Block(), val256, out var merkRoot, out var val160, out var timestampVal, out var indexVal, out var scriptVal, out var transactionsVal, 1); - var hex = "000000000000000000000000000000000000000000000000000000000000000000000000bc72014eb4f1fcdd27831b79c42ffa71e1b949086a97c87654a644585dd616f6e913ff854c0000000000000000000000000000000000000000000000000000000100011102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000"; + var hex = "000000000000000000000000000000000000000000000000000000000000000000000000ecba43e27d4cff6e139ae5c1424151aa41f8bcf1c89132d1a98a915740d271d9e913ff854c00000000000000000000000000000000000000000000000000000001000111020000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010100010000"; using (MemoryStream ms = new MemoryStream(hex.HexToBytes(), false)) using (BinaryReader reader = new BinaryReader(ms)) @@ -199,11 +199,11 @@ public void ToJson() JObject jObj = uut.ToJson(); jObj.Should().NotBeNull(); - jObj["hash"].AsString().Should().Be("0xac84cebc5825cbe78941b301789bc43e8906bb9d86edd80cc94591088a26d9cc"); - jObj["size"].AsNumber().Should().Be(165); + jObj["hash"].AsString().Should().Be("0xbc31c72acd2f3af6a1bc8454c0956a5e7aa6301c755e70cc1bd9263c1d7cfcba"); + jObj["size"].AsNumber().Should().Be(167); jObj["version"].AsNumber().Should().Be(0); jObj["previousblockhash"].AsString().Should().Be("0x0000000000000000000000000000000000000000000000000000000000000000"); - jObj["merkleroot"].AsString().Should().Be("0xf616d65d5844a65476c8976a0849b9e171fa2fc4791b8327ddfcf1b44e0172bc"); + jObj["merkleroot"].AsString().Should().Be("0xd971d24057918aa9d13291c8f1bcf841aa514142c1e59a136eff4c7de243baec"); jObj["time"].AsNumber().Should().Be(328665601001); jObj["index"].AsNumber().Should().Be(0); jObj["nextconsensus"].AsString().Should().Be("NKuyBkoGdZZSLyPbJEetheRhMjeznFZszf"); @@ -214,8 +214,8 @@ public void ToJson() jObj["tx"].Should().NotBeNull(); JArray txObj = (JArray)jObj["tx"]; - txObj[0]["hash"].AsString().Should().Be("0x5f9b7409b6cf21fb0bf63c3890f62cccfe5fb9c3277ea33935e0a09f4255407c"); - txObj[0]["size"].AsNumber().Should().Be(51); + txObj[0]["hash"].AsString().Should().Be("0x85110746f54b4dc72502443c1bb1368ab256bbf3ea9f759b98a3f7861523e6e3"); + txObj[0]["size"].AsNumber().Should().Be(53); txObj[0]["version"].AsNumber().Should().Be(0); ((JArray)txObj[0]["attributes"]).Count.Should().Be(0); txObj[0]["netfee"].AsString().Should().Be("0"); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs index ca834b7c65..3d24c14509 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs @@ -18,7 +18,7 @@ public void Serialize_Deserialize_Global() Account = UInt160.Zero }; - var hex = "01000000000000000000000000000000000000000000"; + var hex = "000000000000000000000000000000000000000000"; attr.ToArray().ToHexString().Should().Be(hex); var copy = hex.HexToBytes().AsSerializable(); @@ -36,7 +36,7 @@ public void Serialize_Deserialize_CalledByEntry() Account = UInt160.Zero }; - var hex = "01000000000000000000000000000000000000000001"; + var hex = "000000000000000000000000000000000000000001"; attr.ToArray().ToHexString().Should().Be(hex); var copy = hex.HexToBytes().AsSerializable(); @@ -55,7 +55,7 @@ public void Serialize_Deserialize_CustomContracts() Account = UInt160.Zero }; - var hex = "01000000000000000000000000000000000000000010010000000000000000000000000000000000000000"; + var hex = "000000000000000000000000000000000000000010010000000000000000000000000000000000000000"; attr.ToArray().ToHexString().Should().Be(hex); var copy = hex.HexToBytes().AsSerializable(); @@ -75,7 +75,7 @@ public void Serialize_Deserialize_CustomGroups() Account = UInt160.Zero }; - var hex = "010000000000000000000000000000000000000000200103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"; + var hex = "0000000000000000000000000000000000000000200103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"; attr.ToArray().ToHexString().Should().Be(hex); var copy = hex.HexToBytes().AsSerializable(); @@ -94,7 +94,7 @@ public void Json_Global() Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"Global\"}"; + var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"Global\"}"; attr.ToJson().ToString().Should().Be(json); } @@ -107,7 +107,7 @@ public void Json_CalledByEntry() Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CalledByEntry\"}"; + var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CalledByEntry\"}"; attr.ToJson().ToString().Should().Be(json); } @@ -121,7 +121,7 @@ public void Json_CustomContracts() Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomContracts\",\"allowedcontracts\":[\"0x0000000000000000000000000000000000000000\"]}"; + var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomContracts\",\"allowedcontracts\":[\"0x0000000000000000000000000000000000000000\"]}"; attr.ToJson().ToString().Should().Be(json); } @@ -135,7 +135,7 @@ public void Json_CustomGroups() Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomGroups\",\"allowedgroups\":[\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\"]}"; + var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomGroups\",\"allowedgroups\":[\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\"]}"; attr.ToJson().ToString().Should().Be(json); } } diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 19e4ab5226..2436b2cb7b 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -64,6 +64,7 @@ public void Gas_Set() public void Size_Get() { uut.Script = TestUtils.GetByteArray(32, 0x42); + uut.Signers = Array.Empty(); uut.Attributes = Array.Empty(); uut.Witnesses = new[] { @@ -77,7 +78,7 @@ public void Size_Get() uut.Version.Should().Be(0); uut.Script.Length.Should().Be(32); uut.Script.GetVarSize().Should().Be(33); - uut.Size.Should().Be(82); + uut.Size.Should().Be(63); } [TestMethod] @@ -157,8 +158,8 @@ public void FeeIsMultiSigContract() var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); Assert.AreEqual(2000810, verificationGas); - Assert.AreEqual(367000, sizeGas); - Assert.AreEqual(2367810, tx.NetworkFee); + Assert.AreEqual(347000, sizeGas); + Assert.AreEqual(2347810, tx.NetworkFee); } } @@ -199,7 +200,7 @@ public void FeeIsSignatureContractDetailed() Assert.IsNull(tx.Witnesses); // check pre-computed network fee (already guessing signature sizes) - tx.NetworkFee.Should().Be(1264390); + tx.NetworkFee.Should().Be(1244390L); // ---- // Sign @@ -241,32 +242,32 @@ public void FeeIsSignatureContractDetailed() // ------------------ // check tx_size cost // ------------------ - Assert.AreEqual(264, tx.Size); + Assert.AreEqual(244, tx.Size); // will verify tx size, step by step // Part I - Assert.AreEqual(45, Transaction.HeaderSize); + Assert.AreEqual(25, Transaction.HeaderSize); // Part II - Assert.AreEqual(23, tx.Attributes.GetVarSize()); - Assert.AreEqual(1, tx.Attributes.Length); - Assert.AreEqual(1, tx.Signers.Count); - Assert.AreEqual(23, tx.Signers.Size); + Assert.AreEqual(1, tx.Attributes.GetVarSize()); + Assert.AreEqual(0, tx.Attributes.Length); + Assert.AreEqual(1, tx.Signers.Length); // Note that Data size and Usage size are different (because of first byte on GetVarSize()) - Assert.AreEqual(22, tx.Signers.First().Size); + Assert.AreEqual(22, tx.Signers.GetVarSize()); // Part III Assert.AreEqual(86, tx.Script.GetVarSize()); // Part IV Assert.AreEqual(110, tx.Witnesses.GetVarSize()); // I + II + III + IV - Assert.AreEqual(45 + 23 + 86 + 110, tx.Size); + Assert.AreEqual(25 + 22 + 1 + 86 + 110, tx.Size); Assert.AreEqual(1000, NativeContract.Policy.GetFeePerByte(snapshot)); var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); - Assert.AreEqual(264000, sizeGas); - // final check on sum: verification_cost + tx_size - Assert.AreEqual(1264390, verificationGas + sizeGas); + // final check: verification_cost and tx_size + Assert.AreEqual(244000, sizeGas); + Assert.AreEqual(1000390, verificationGas); + // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -300,7 +301,7 @@ public void FeeIsSignatureContract_TestScope_Global() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); @@ -315,7 +316,7 @@ public void FeeIsSignatureContract_TestScope_Global() // using this... - var tx = wallet.MakeTransaction(script, new Signers(signers)); + var tx = wallet.MakeTransaction(script, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -352,7 +353,7 @@ public void FeeIsSignatureContract_TestScope_Global() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1264390, verificationGas + sizeGas); + Assert.AreEqual(1244390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -386,7 +387,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); @@ -402,7 +403,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() // using this... - var tx = wallet.MakeTransaction(script, new Signers(signers)); + var tx = wallet.MakeTransaction(script, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -439,7 +440,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1285390, verificationGas + sizeGas); + Assert.AreEqual(1265390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -492,7 +493,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() // using this... - var tx = wallet.MakeTransaction(script, new Signers(signers)); + var tx = wallet.MakeTransaction(script, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -529,7 +530,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1285390, verificationGas + sizeGas); + Assert.AreEqual(1265390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -580,7 +581,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, new Signers(signers))); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, signers)); Assert.IsNull(tx); } } @@ -613,7 +614,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); @@ -629,7 +630,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // using this... - var tx = wallet.MakeTransaction(script, new Signers(signers)); + var tx = wallet.MakeTransaction(script, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -647,9 +648,9 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // only a single witness should exist tx.Witnesses.Length.Should().Be(1); // no attributes must exist - tx.Attributes.Length.Should().Be(1); + tx.Attributes.Length.Should().Be(0); // one cosigner must exist - tx.Signers.Count.Should().Be(1); + tx.Signers.Length.Should().Be(1); // Fast check Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee)); @@ -671,7 +672,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1305390, verificationGas + sizeGas); + Assert.AreEqual(1285390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -724,7 +725,7 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, new Signers(signers), attributes)); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, signers, attributes)); Assert.IsNull(tx); } } @@ -741,18 +742,18 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = Array.Empty(), - Signers = new Signers( + Signers = new[]{ new Signer { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), Scopes = WitnessScope.Global } - ), + }, Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } }; UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshot); - Assert.AreEqual(2, hashes.Length); + Assert.AreEqual(1, hashes.Length); Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot, BigInteger.Zero)); } @@ -767,6 +768,7 @@ public void Transaction_Serialize_Deserialize_Simple() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, + Signers = Array.Empty(), Attributes = Array.Empty(), Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } @@ -777,11 +779,11 @@ public void Transaction_Serialize_Deserialize_Simple() // detailed hexstring info (basic checking) sTx.ToHexString().Should().Be("00" + // version "04030201" + // nonce - "0000000000000000000000000000000000000000" + // sender "00e1f50500000000" + // system fee (1 GAS) "0100000000000000" + // network fee (1 satoshi) "04030201" + // timelimit "00" + // no attributes + "00" + // no signer "0111" + // push1 script "00"); // no witnesses @@ -813,7 +815,21 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = Array.Empty(), - Signers = new Signers(new Signer[] + Signers = Array.Empty(), + Script = new byte[] { (byte)OpCode.PUSH1 }, + Witnesses = new Witness[0] { } + }; + + byte[] sTx = txDoubleCosigners.ToArray(); + + // no need for detailed hexstring here (see basic tests for it) + sTx.ToHexString().Should().Be("000403020100e1f505000000000100000000000000040302010000011100"); + + // back to transaction (should fail, due to non-distinct cosigners) + Transaction tx2 = null; + Assert.ThrowsException(() => + { + txDoubleCosigners.Signers = new Signer[] { new Signer() { @@ -825,21 +841,8 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), // same account as above Scopes = WitnessScope.CalledByEntry // different scope, but still, same account (cannot do that) } - }), - Script = new byte[] { (byte)OpCode.PUSH1 }, - Witnesses = new Witness[0] { } - }; - - byte[] sTx = txDoubleCosigners.ToArray(); - - // no need for detailed hexstring here (see basic tests for it) - sTx.ToHexString().Should().Be("0004030201000000000000000000000000000000000000000000e1f50500000000010000000000000004030201020109080706050403020100090807060504030201000001090807060504030201000908070605040302010001011100"); - - // back to transaction (should fail, due to non-distinct cosigners) - Transaction tx2 = null; - Assert.ThrowsException(() => - tx2 = Neo.IO.Helper.AsSerializable(sTx) - ); + }; + }); Assert.IsNull(tx2); } @@ -874,7 +877,7 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = Array.Empty(), - Signers = new Signers(cosigners1), // max + 1 (should fail) + Signers = cosigners1, // max + 1 (should fail) Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } }; @@ -908,7 +911,7 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = Array.Empty(), - Signers = new Signers(cosigners1), // max + 1 (should fail) + Signers = cosigners, // max + 1 (should fail) Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } }; @@ -956,7 +959,7 @@ public void FeeIsSignatureContract_TestScope_Global_Default() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); @@ -970,7 +973,7 @@ public void FeeIsSignatureContract_TestScope_Global_Default() // using this... - var tx = wallet.MakeTransaction(script, new Signers(signers)); + var tx = wallet.MakeTransaction(script, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -1007,7 +1010,7 @@ public void FeeIsSignatureContract_TestScope_Global_Default() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1264390, verificationGas + sizeGas); + Assert.AreEqual(1244390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -1018,6 +1021,7 @@ public void ToJson() { uut.Script = TestUtils.GetByteArray(32, 0x42); uut.SystemFee = 4200000000; + uut.Signers = Array.Empty(); uut.Attributes = Array.Empty(); uut.Witnesses = new[] { @@ -1030,8 +1034,8 @@ public void ToJson() JObject jObj = uut.ToJson(); jObj.Should().NotBeNull(); - jObj["hash"].AsString().Should().Be("0xfe08a23db645733a95914622ead5e738b03918680e927e00928116395e571758"); - jObj["size"].AsNumber().Should().Be(82); + jObj["hash"].AsString().Should().Be("0xb1fa52d0778d1e31d0c419e6006d522c5a0e006f7fd83489e7360f7847a6edfe"); + jObj["size"].AsNumber().Should().Be(63); jObj["version"].AsNumber().Should().Be(0); ((JArray)jObj["attributes"]).Count.Should().Be(0); jObj["netfee"].AsString().Should().Be("0"); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs index 436b5cf723..ff47beef29 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs @@ -55,11 +55,11 @@ private Witness PrepareDummyWitness(int maxAccounts) var data = new ContractParametersContext(new Transaction() { Attributes = Array.Empty(), - Signers = new Signers(new Signer() + Signers = new[] {new Signer() { Account = multiSignContract.ScriptHash, Scopes = WitnessScope.CalledByEntry - }), + }}, NetworkFee = 0, Nonce = 0, Script = new byte[0], diff --git a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index e56b0a5d6e..6e1b05cf35 100644 --- a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -45,13 +45,13 @@ public void TestToString() var context = new ContractParametersContext(tx); context.Add(contract, 0, new byte[] { 0x01 }); string str = context.ToString(); - str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hex"":""AAAAAABmUJDLobcPtqo9vZKIdjXsd8fVGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA"",""items"":{}}"); + str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hex"":""AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZlCQy6G3D7aqPb2SiHY17HfH1RsBAQA="",""items"":{}}"); } [TestMethod] public void TestParse() { - var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"hex\":\"AAAAAABmUJDLobcPtqo9vZKIdjXsd8fVGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"IQJv8DuUkkHOHa3UNRnmlg4KhbQaaaBcMoEDqivOFZTKFmh0dHaq\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"AQ==\"}]}}}"); + var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"hex\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZlCQy6G3D7aqPb2SiHY17HfH1RsBAQA=\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"IQJv8DuUkkHOHa3UNRnmlg4KhbQaaaBcMoEDqivOFZTKFmh0dHaq\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"AQ==\"}]}}}"); ret.ScriptHashes[0].ToString().Should().Be("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); ((Transaction)ret.Verifiable).Script.ToHexString().Should().Be(new byte[1].ToHexString()); } @@ -66,10 +66,11 @@ public void TestFromJson() [TestMethod] public void TestAdd() { - Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0")); + Transaction tx = TestUtils.GetTransaction(UInt160.Zero); var context1 = new ContractParametersContext(tx); context1.Add(contract, 0, new byte[] { 0x01 }).Should().BeFalse(); + tx = TestUtils.GetTransaction(UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0")); var context2 = new ContractParametersContext(tx); context2.Add(contract, 0, new byte[] { 0x01 }).Should().BeTrue(); //test repeatlly createItem diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 17b73fadf6..174aace8f1 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -250,7 +250,7 @@ public void TestRuntime_CheckWitness() ECPoint pubkey = keyPair.PublicKey; var engine = GetEngine(true); - (((Transaction)engine.ScriptContainer).Signers.Entries[0]).Account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); + ((Transaction)engine.ScriptContainer).Signers[0].Account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); engine.CheckWitness(((Transaction)engine.ScriptContainer).Sender.ToArray()).Should().BeFalse(); diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index c37b6c5779..a7dca5b434 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -26,6 +26,7 @@ public void System_Blockchain_GetBlock() { Script = new byte[] { 0x01 }, Attributes = Array.Empty(), + Signers = Array.Empty(), NetworkFee = 0x02, SystemFee = 0x03, Nonce = 0x04, @@ -238,6 +239,7 @@ public void System_ExecutionEngine_GetScriptContainer() var tx = new Transaction() { Script = new byte[] { 0x01 }, + Signers = Array.Empty(), Attributes = Array.Empty(), NetworkFee = 0x02, SystemFee = 0x03, diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index 79096781e0..996cba6fdd 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -80,7 +80,7 @@ public static NEP6Wallet GenerateTestWallet() { JObject wallet = new JObject(); wallet["name"] = "noname"; - wallet["version"] = new System.Version("3.0").ToString(); + wallet["version"] = new Version("3.0").ToString(); wallet["scrypt"] = new ScryptParameters(0, 0, 0).ToJson(); wallet["accounts"] = new JArray(); wallet["extra"] = null; @@ -94,11 +94,11 @@ public static Transaction GetTransaction(UInt160 sender) { Script = new byte[1], Attributes = Array.Empty(), - Signers = new Signer() + Signers = new[]{ new Signer() { Account = sender, Scopes = WitnessScope.CalledByEntry - }, + } }, Witnesses = new Witness[]{ new Witness { InvocationScript = new byte[0], @@ -194,6 +194,7 @@ public static Transaction CreateRandomHashTransaction() { Script = randomBytes, Attributes = Array.Empty(), + Signers = Array.Empty(), Witnesses = new[] { new Witness diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index ba0b007f21..449de4a134 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -381,11 +381,11 @@ public void TestMakeTransaction2() entry.GetInteroperable().Balance = 1000000 * NativeContract.GAS.Factor; snapshot.Commit(); - var tx = wallet.MakeTransaction(new byte[] { }, new Signers(new Signer() + var tx = wallet.MakeTransaction(new byte[] { }, new[]{ new Signer() { Account = account.ScriptHash, - Scopes = WitnessScope.Global - }), new TransactionAttribute[] { }); + Scopes = WitnessScope.CalledByEntry + }}, new TransactionAttribute[] { }); tx.Should().NotBeNull(); From fc6a3fa18983379e2e7f6edf6b3cae89c3cc349c Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 9 Jul 2020 11:09:56 +0200 Subject: [PATCH 05/27] Fix UT --- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index 449de4a134..5b8183257d 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -368,7 +368,7 @@ public void TestMakeTransaction2() { MyWallet wallet = new MyWallet(); Action action = () => wallet.MakeTransaction(new byte[] { }, null, new TransactionAttribute[] { }); - action.Should().Throw(); + action.Should().Throw(); Contract contract = Contract.Create(new ContractParameterType[] { ContractParameterType.Boolean }, new byte[] { 1 }); WalletAccount account = wallet.CreateAccount(contract, glkey.PrivateKey); From ec0262e5666d4c7d63025747dc1845c9fcc529cd Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 9 Jul 2020 16:55:21 +0200 Subject: [PATCH 06/27] Add FeeOnly scope --- src/neo/Network/P2P/Payloads/WitnessScope.cs | 13 +++++++++---- src/neo/SmartContract/ApplicationEngine.Runtime.cs | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/WitnessScope.cs b/src/neo/Network/P2P/Payloads/WitnessScope.cs index f35e550a34..ab9e371a8c 100644 --- a/src/neo/Network/P2P/Payloads/WitnessScope.cs +++ b/src/neo/Network/P2P/Payloads/WitnessScope.cs @@ -5,27 +5,32 @@ namespace Neo.Network.P2P.Payloads [Flags] public enum WitnessScope : byte { + /// + /// It's only valid for be a sender, it can't be used during the execution + /// + FeeOnly = 0x00, + /// /// Global allows this witness in all contexts (default Neo2 behavior) /// This cannot be combined with other flags /// - Global = 0x00, + Global = 0x01, /// /// CalledByEntry means that this condition must hold: EntryScriptHash == CallingScriptHash /// No params is needed, as the witness/permission/signature given on first invocation will automatically expire if entering deeper internal invokes /// This can be default safe choice for native NEO/GAS (previously used on Neo 2 as "attach" mode) /// - CalledByEntry = 0x01, + CalledByEntry = 0x10, /// /// Custom hash for contract-specific /// - CustomContracts = 0x10, + CustomContracts = 0x20, /// /// Custom pubkey for group members /// - CustomGroups = 0x20 + CustomGroups = 0x30 } } diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index 607bc077ff..c60dcf4116 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -106,6 +106,7 @@ internal bool CheckWitnessInternal(UInt160 hash) { if (!tx.TryGetSigner(hash, out Signer signer)) return false; if (signer.Scopes == WitnessScope.Global) return true; + if (signer.Scopes.HasFlag(WitnessScope.FeeOnly)) return false; if (signer.Scopes.HasFlag(WitnessScope.CalledByEntry)) { if (CallingScriptHash == EntryScriptHash) From 09860a40da6060007120243b076f894b11d1f2e8 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 9 Jul 2020 16:56:54 +0200 Subject: [PATCH 07/27] Remove orderBy --- src/neo/Network/P2P/Payloads/Transaction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 1564db9b42..eaa79722eb 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -227,7 +227,7 @@ public override int GetHashCode() public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { - return _signersCache.Keys.OrderBy(p => p).ToArray(); + return _signersCache.Keys.ToArray(); } void ISerializable.Serialize(BinaryWriter writer) From a7266994ef4d295cd6d0b95568710b9525fff999 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 14:08:53 +0800 Subject: [PATCH 08/27] Remove _signersCache --- src/neo/Network/P2P/Payloads/Transaction.cs | 30 +++++-------------- .../ApplicationEngine.Runtime.cs | 3 +- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index eaa79722eb..840f9ee1d7 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -35,7 +35,6 @@ public class Transaction : IEquatable, IInventory, IInteroperable private byte[] script; private Witness[] witnesses; private Signer[] _signers; - private Dictionary _signersCache; public const int HeaderSize = sizeof(byte) + //Version @@ -50,22 +49,6 @@ public TransactionAttribute[] Attributes set { attributes = value; _hash = null; _size = 0; } } - public Signer[] Signers - { - get => _signers; - set - { - var cache = value.ToDictionary(u => u.Account); - if (cache.Count != value.Length) - throw new FormatException("Signers accounts must be unique"); - - _signersCache = cache; - _signers = value; - _hash = null; - _size = 0; - } - } - /// /// Correspond with the first entry of Signers /// @@ -113,6 +96,12 @@ public byte[] Script set { script = value; _hash = null; _size = 0; } } + public Signer[] Signers + { + get => _signers; + set { _signers = value; _hash = null; _size = 0; } + } + private int _size; public int Size { @@ -181,11 +170,6 @@ private static IEnumerable DeserializeAttributes(BinaryRea } } - public bool TryGetSigner(UInt160 hash, out Signer signer) - { - return _signersCache.TryGetValue(hash, out signer); - } - public void DeserializeUnsigned(BinaryReader reader) { Version = reader.ReadByte(); @@ -227,7 +211,7 @@ public override int GetHashCode() public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { - return _signersCache.Keys.ToArray(); + return Signers.Select(p => p.Account).ToArray(); } void ISerializable.Serialize(BinaryWriter writer) diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index c60dcf4116..547352bb2b 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -104,7 +104,8 @@ internal bool CheckWitnessInternal(UInt160 hash) { if (ScriptContainer is Transaction tx) { - if (!tx.TryGetSigner(hash, out Signer signer)) return false; + Signer signer = tx.Signers.FirstOrDefault(p => p.Account.Equals(hash)); + if (signer is null) return false; if (signer.Scopes == WitnessScope.Global) return true; if (signer.Scopes.HasFlag(WitnessScope.FeeOnly)) return false; if (signer.Scopes.HasFlag(WitnessScope.CalledByEntry)) From 67dc7e3913b11f21f995f7d40236825529423adc Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 14:21:15 +0800 Subject: [PATCH 09/27] Fix Signers --- src/neo/Network/P2P/Payloads/Transaction.cs | 28 +++++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 840f9ee1d7..b56368da84 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -31,10 +31,10 @@ public class Transaction : IEquatable, IInventory, IInteroperable private long sysfee; private long netfee; private uint validUntilBlock; + private Signer[] _signers; private TransactionAttribute[] attributes; private byte[] script; private Witness[] witnesses; - private Signer[] _signers; public const int HeaderSize = sizeof(byte) + //Version @@ -110,8 +110,8 @@ public int Size if (_size == 0) { _size = HeaderSize + - Attributes.GetVarSize() + // Attributes Signers.GetVarSize() + // Signers + Attributes.GetVarSize() + // Attributes Script.GetVarSize() + // Script Witnesses.GetVarSize(); // Witnesses } @@ -157,9 +157,9 @@ void ISerializable.Deserialize(BinaryReader reader) _size = (int)reader.BaseStream.Position - startPosition; } - private static IEnumerable DeserializeAttributes(BinaryReader reader) + private static IEnumerable DeserializeAttributes(BinaryReader reader, int maxCount) { - int count = (int)reader.ReadVarInt(MaxTransactionAttributes); + int count = (int)reader.ReadVarInt((ulong)maxCount); HashSet hashset = new HashSet(); while (count-- > 0) { @@ -170,6 +170,18 @@ private static IEnumerable DeserializeAttributes(BinaryRea } } + private static IEnumerable DeserializeSigners(BinaryReader reader, int maxCount) + { + int count = (int)reader.ReadVarInt((ulong)maxCount); + HashSet hashset = new HashSet(); + while (count-- > 0) + { + Signer signer = reader.ReadSerializable(); + if (!hashset.Add(signer.Account)) throw new FormatException(); + yield return signer; + } + } + public void DeserializeUnsigned(BinaryReader reader) { Version = reader.ReadByte(); @@ -181,8 +193,8 @@ public void DeserializeUnsigned(BinaryReader reader) if (NetworkFee < 0) throw new FormatException(); if (SystemFee + NetworkFee < SystemFee) throw new FormatException(); ValidUntilBlock = reader.ReadUInt32(); - Attributes = DeserializeAttributes(reader).ToArray(); - Signers = reader.ReadSerializableArray(MaxTransactionAttributes); + Signers = DeserializeSigners(reader, MaxTransactionAttributes).ToArray(); + Attributes = DeserializeAttributes(reader, MaxTransactionAttributes - Signers.Length).ToArray(); Script = reader.ReadVarBytes(ushort.MaxValue); if (Script.Length == 0) throw new FormatException(); } @@ -227,8 +239,8 @@ void IVerifiable.SerializeUnsigned(BinaryWriter writer) writer.Write(SystemFee); writer.Write(NetworkFee); writer.Write(ValidUntilBlock); - writer.Write(Attributes); writer.Write(Signers); + writer.Write(Attributes); writer.WriteVarBytes(Script); } @@ -243,8 +255,8 @@ public JObject ToJson() json["sysfee"] = SystemFee.ToString(); json["netfee"] = NetworkFee.ToString(); json["validuntilblock"] = ValidUntilBlock; - json["attributes"] = Attributes.Select(p => p.ToJson()).ToArray(); json["signers"] = Signers.Select(p => p.ToJson()).ToArray(); + json["attributes"] = Attributes.Select(p => p.ToJson()).ToArray(); json["script"] = Convert.ToBase64String(Script); json["witnesses"] = Witnesses.Select(p => p.ToJson()).ToArray(); return json; From 881fb8817d6173dca260662738c81f5143b668e7 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 14:37:02 +0800 Subject: [PATCH 10/27] Fix WitnessScope --- src/neo/Network/P2P/Payloads/Signer.cs | 5 +++++ src/neo/Network/P2P/Payloads/Transaction.cs | 7 +++++-- src/neo/Network/P2P/Payloads/WitnessScope.cs | 20 +++++++++---------- .../ApplicationEngine.Runtime.cs | 1 - 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Signer.cs b/src/neo/Network/P2P/Payloads/Signer.cs index 72a623fb2e..4be59a349f 100644 --- a/src/neo/Network/P2P/Payloads/Signer.cs +++ b/src/neo/Network/P2P/Payloads/Signer.cs @@ -1,6 +1,7 @@ using Neo.Cryptography.ECC; using Neo.IO; using Neo.IO.Json; +using System; using System.IO; using System.Linq; @@ -26,6 +27,10 @@ public void Deserialize(BinaryReader reader) { Account = reader.ReadSerializable(); Scopes = (WitnessScope)reader.ReadByte(); + if ((Scopes & ~(WitnessScope.CalledByEntry | WitnessScope.CustomContracts | WitnessScope.CustomGroups | WitnessScope.Global)) != 0) + throw new FormatException(); + if (Scopes.HasFlag(WitnessScope.Global) && Scopes != WitnessScope.Global) + throw new FormatException(); AllowedContracts = Scopes.HasFlag(WitnessScope.CustomContracts) ? reader.ReadSerializableArray(MaxSubitems) : new UInt160[0]; diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index b56368da84..11351c825b 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -174,10 +174,13 @@ private static IEnumerable DeserializeSigners(BinaryReader reader, int m { int count = (int)reader.ReadVarInt((ulong)maxCount); HashSet hashset = new HashSet(); - while (count-- > 0) + for (int i = 0; i < count; i++) { Signer signer = reader.ReadSerializable(); - if (!hashset.Add(signer.Account)) throw new FormatException(); + if (i == 0 ^ signer.Scopes == WitnessScope.FeeOnly) + throw new FormatException(); + if (!hashset.Add(signer.Account)) + throw new FormatException(); yield return signer; } } diff --git a/src/neo/Network/P2P/Payloads/WitnessScope.cs b/src/neo/Network/P2P/Payloads/WitnessScope.cs index ab9e371a8c..9cc3cd99fd 100644 --- a/src/neo/Network/P2P/Payloads/WitnessScope.cs +++ b/src/neo/Network/P2P/Payloads/WitnessScope.cs @@ -8,29 +8,29 @@ public enum WitnessScope : byte /// /// It's only valid for be a sender, it can't be used during the execution /// - FeeOnly = 0x00, - - /// - /// Global allows this witness in all contexts (default Neo2 behavior) - /// This cannot be combined with other flags - /// - Global = 0x01, + FeeOnly = 0, /// /// CalledByEntry means that this condition must hold: EntryScriptHash == CallingScriptHash /// No params is needed, as the witness/permission/signature given on first invocation will automatically expire if entering deeper internal invokes /// This can be default safe choice for native NEO/GAS (previously used on Neo 2 as "attach" mode) /// - CalledByEntry = 0x10, + CalledByEntry = 0x01, /// /// Custom hash for contract-specific /// - CustomContracts = 0x20, + CustomContracts = 0x10, /// /// Custom pubkey for group members /// - CustomGroups = 0x30 + CustomGroups = 0x20, + + /// + /// Global allows this witness in all contexts (default Neo2 behavior) + /// This cannot be combined with other flags + /// + Global = 0x80 } } diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index 547352bb2b..c670971937 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -107,7 +107,6 @@ internal bool CheckWitnessInternal(UInt160 hash) Signer signer = tx.Signers.FirstOrDefault(p => p.Account.Equals(hash)); if (signer is null) return false; if (signer.Scopes == WitnessScope.Global) return true; - if (signer.Scopes.HasFlag(WitnessScope.FeeOnly)) return false; if (signer.Scopes.HasFlag(WitnessScope.CalledByEntry)) { if (CallingScriptHash == EntryScriptHash) From e55dfeef83ec9880d77025c5b7303f15e2fb0849 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 14:42:09 +0800 Subject: [PATCH 11/27] Fix Sender --- src/neo/Network/P2P/Payloads/Transaction.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 11351c825b..332a6021d2 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -49,11 +49,6 @@ public TransactionAttribute[] Attributes set { attributes = value; _hash = null; _size = 0; } } - /// - /// Correspond with the first entry of Signers - /// - public UInt160 Sender => _signers.Length > 0 ? _signers[0].Account : UInt160.Zero; - /// /// The NetworkFee for the transaction divided by its Size. /// Note that this property must be used with care. Getting the value of this property multiple times will return the same result. The value of this property can only be obtained after the transaction has been completely built (no longer modified). @@ -96,6 +91,11 @@ public byte[] Script set { script = value; _hash = null; _size = 0; } } + /// + /// Correspond with the first entry of Signers + /// + public UInt160 Sender => _signers[0].Account; + public Signer[] Signers { get => _signers; @@ -173,6 +173,7 @@ private static IEnumerable DeserializeAttributes(BinaryRea private static IEnumerable DeserializeSigners(BinaryReader reader, int maxCount) { int count = (int)reader.ReadVarInt((ulong)maxCount); + if (count == 0) throw new FormatException(); HashSet hashset = new HashSet(); for (int i = 0; i < count; i++) { From e28cd1dfad8315b2c2424cd5aeaba9ea55357de1 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 14:48:19 +0800 Subject: [PATCH 12/27] Update TransactionAttributeType.cs --- src/neo/Network/P2P/Payloads/TransactionAttributeType.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs b/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs index d6224db0b2..c3f32ddecf 100644 --- a/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs +++ b/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs @@ -1,10 +1,6 @@ -using Neo.IO.Caching; - namespace Neo.Network.P2P.Payloads { public enum TransactionAttributeType : byte { - //[ReflectionCache(typeof(Signer))] - //Signer = 0x01 } } From eb7e302e1d16159376343dfeeb1f059a765dd408 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 15:01:26 +0800 Subject: [PATCH 13/27] Update Wallet.cs --- src/neo/Wallets/Wallet.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index f1c2a49566..b393e78fcd 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -12,7 +12,6 @@ using System.Numerics; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using System.Security.Policy; using System.Text; using static Neo.Wallets.Helper; using ECPoint = Neo.Cryptography.ECC.ECPoint; @@ -292,14 +291,14 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null public Transaction MakeTransaction(byte[] script, Signer[] signers = null, TransactionAttribute[] attributes = null) { - var sender = signers?.Length > 0 ? signers[0].Account : UInt160.Zero; UInt160[] accounts; - if (sender == UInt160.Zero) + if (signers is null) { accounts = GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray(); } else { + UInt160 sender = signers[0].Account; if (!Contains(sender)) throw new ArgumentException($"The address {sender} was not found in the wallet"); accounts = new[] { sender }; From c536c308f7bef16fe21483ac0ea526eaca8942bf Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 15:22:05 +0800 Subject: [PATCH 14/27] Fix Wallet --- src/neo/Wallets/Wallet.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index b393e78fcd..f3db2def4f 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -285,20 +285,19 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null Account = new UInt160(p.ToArray()) }).ToArray(); - return MakeTransaction(snapshot, script, signers, null, balances_gas); + return MakeTransaction(snapshot, script, signers, Array.Empty(), balances_gas); } } - public Transaction MakeTransaction(byte[] script, Signer[] signers = null, TransactionAttribute[] attributes = null) + public Transaction MakeTransaction(byte[] script, UInt160 sender, Signer[] cosigners = null, TransactionAttribute[] attributes = null) { UInt160[] accounts; - if (signers is null) + if (sender is null) { accounts = GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray(); } else { - UInt160 sender = signers[0].Account; if (!Contains(sender)) throw new ArgumentException($"The address {sender} was not found in the wallet"); accounts = new[] { sender }; @@ -306,11 +305,11 @@ public Transaction MakeTransaction(byte[] script, Signer[] signers = null, Trans using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { var balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - return MakeTransaction(snapshot, script, signers, attributes ?? Array.Empty(), balances_gas); + return MakeTransaction(snapshot, script, cosigners ?? Array.Empty(), attributes ?? Array.Empty(), balances_gas); } } - private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] signers, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) + private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] cosigners, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) { Random rand = new Random(); foreach (var (account, value) in balances_gas) @@ -321,8 +320,8 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] Nonce = (uint)rand.Next(), Script = script, ValidUntilBlock = snapshot.Height + Transaction.MaxValidUntilBlockIncrement, - Signers = signers ?? Array.Empty(), - Attributes = attributes ?? Array.Empty(), + Signers = cosigners.Prepend(new Signer { Account = account }).ToArray(), + Attributes = attributes, }; // will try to execute 'transfer' script to check if it works From 0f5db32a98730c431bcc023edfff9e8efb67d6e6 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 15:24:23 +0800 Subject: [PATCH 15/27] Rename --- src/neo/Wallets/Wallet.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index f3db2def4f..19df817204 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -235,7 +235,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null } using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { - HashSet signersList = new HashSet(); + HashSet cosignerList = new HashSet(); byte[] script; List<(UInt160 Account, BigInteger Value)> balances_gas = null; using (ScriptBuilder sb = new ScriptBuilder()) @@ -262,7 +262,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null { balances = balances.OrderBy(p => p.Value).ToList(); var balances_used = FindPayingAccounts(balances, output.Value.Value); - signersList.UnionWith(balances_used.Select(p => p.Account)); + cosignerList.UnionWith(balances_used.Select(p => p.Account)); foreach (var (account, value) in balances_used) { sb.EmitAppCall(output.AssetId, "transfer", account, output.ScriptHash, value); @@ -277,7 +277,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null if (balances_gas is null) balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - var signers = signersList.Select(p => + var cosigners = cosignerList.Select(p => new Signer() { // default access for transfers should be valid only for first invocation @@ -285,7 +285,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null Account = new UInt160(p.ToArray()) }).ToArray(); - return MakeTransaction(snapshot, script, signers, Array.Empty(), balances_gas); + return MakeTransaction(snapshot, script, cosigners, Array.Empty(), balances_gas); } } From 8a8b837b60f4b8df58f0690c98170fb5f0ed44f5 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 15:26:26 +0800 Subject: [PATCH 16/27] Update Wallet.cs --- src/neo/Wallets/Wallet.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 19df817204..6d22263d92 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -277,13 +277,12 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null if (balances_gas is null) balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - var cosigners = cosignerList.Select(p => - new Signer() - { - // default access for transfers should be valid only for first invocation - Scopes = WitnessScope.CalledByEntry, - Account = new UInt160(p.ToArray()) - }).ToArray(); + var cosigners = cosignerList.Select(p => new Signer() + { + // default access for transfers should be valid only for first invocation + Scopes = WitnessScope.CalledByEntry, + Account = p + }).ToArray(); return MakeTransaction(snapshot, script, cosigners, Array.Empty(), balances_gas); } From ffc55fe6921eb15e57a8bf24f058352f15f6c373 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 15:27:41 +0800 Subject: [PATCH 17/27] Update Wallet.cs --- src/neo/Wallets/Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 6d22263d92..1cd20a72c6 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -288,7 +288,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null } } - public Transaction MakeTransaction(byte[] script, UInt160 sender, Signer[] cosigners = null, TransactionAttribute[] attributes = null) + public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Signer[] cosigners = null, TransactionAttribute[] attributes = null) { UInt160[] accounts; if (sender is null) From e018eb64bd8d2ae83cc38f94368b6736c1e83cdb Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Jul 2020 10:16:19 +0200 Subject: [PATCH 18/27] Partial UT fix --- src/neo/Wallets/Wallet.cs | 11 ++++++----- tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs | 4 ++-- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 6 +++--- tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs | 10 +++++----- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 1cd20a72c6..6f9aa9a3da 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -288,15 +288,16 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null } } - public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Signer[] cosigners = null, TransactionAttribute[] attributes = null) + public Transaction MakeTransaction(byte[] script, Signer[] signers = null, TransactionAttribute[] attributes = null) { UInt160[] accounts; - if (sender is null) + if (signers is null || signers.Length > 0) { accounts = GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray(); } else { + var sender = signers[0].Account; if (!Contains(sender)) throw new ArgumentException($"The address {sender} was not found in the wallet"); accounts = new[] { sender }; @@ -304,11 +305,11 @@ public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Signer[ using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { var balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - return MakeTransaction(snapshot, script, cosigners ?? Array.Empty(), attributes ?? Array.Empty(), balances_gas); + return MakeTransaction(snapshot, script, signers ?? Array.Empty(), attributes ?? Array.Empty(), balances_gas); } } - private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] cosigners, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) + private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] signers, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) { Random rand = new Random(); foreach (var (account, value) in balances_gas) @@ -319,7 +320,7 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] Nonce = (uint)rand.Next(), Script = script, ValidUntilBlock = snapshot.Height + Transaction.MaxValidUntilBlockIncrement, - Signers = cosigners.Prepend(new Signer { Account = account }).ToArray(), + Signers = signers.Prepend(new Signer { Account = account }).ToArray(), Attributes = attributes, }; diff --git a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs index 358e8b1776..ca12f676a0 100644 --- a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs +++ b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs @@ -125,7 +125,7 @@ private Transaction CreateTransactionWithSize(int v) var tx = new Transaction() { Attributes = System.Array.Empty(), - Signers = System.Array.Empty(), + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[0], @@ -145,7 +145,7 @@ private Transaction CreateTransactionWithSytemFee(long fee) var tx = new Transaction() { Attributes = System.Array.Empty(), - Signers = System.Array.Empty(), + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[0], diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index 38f39fd374..a94bd98984 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -73,13 +73,13 @@ public void TestContainsTransaction() [TestMethod] public void TestGetCurrentBlockHash() { - Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0xc5e3965587c58ff2a38e3f152e054e5cbc6f114ac3d83c7189eb4bb73294679d")); + Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0xecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8")); } [TestMethod] public void TestGetCurrentHeaderHash() { - Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0xc5e3965587c58ff2a38e3f152e054e5cbc6f114ac3d83c7189eb4bb73294679d")); + Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0xecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8")); } [TestMethod] @@ -91,7 +91,7 @@ public void TestGetBlock() [TestMethod] public void TestGetBlockHash() { - Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0xc5e3965587c58ff2a38e3f152e054e5cbc6f114ac3d83c7189eb4bb73294679d")); + Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0xecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8")); Blockchain.Singleton.GetBlockHash(10).Should().BeNull(); } diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 8449dc219e..0d5208de5a 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -84,7 +84,7 @@ public void Serialize() UInt256 val256 = UInt256.Zero; TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, 1); - var hex = "000000000000000000000000000000000000000000000000000000000000000000000000ecba43e27d4cff6e139ae5c1424151aa41f8bcf1c89132d1a98a915740d271d9e913ff854c00000000000000000000000000000000000000000000000000000001000111020000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010100010000"; + var hex = "000000000000000000000000000000000000000000000000000000000000000000000000add6632f6f3d29cdf94555bb191fb5296683e5446f9937c56bb94c8608023044e913ff854c00000000000000000000000000000000000000000000000000000001000111020000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000100010000"; uut.ToArray().ToHexString().Should().Be(hex); } @@ -94,7 +94,7 @@ public void Deserialize() UInt256 val256 = UInt256.Zero; TestUtils.SetupBlockWithValues(new Block(), val256, out var merkRoot, out var val160, out var timestampVal, out var indexVal, out var scriptVal, out var transactionsVal, 1); - var hex = "000000000000000000000000000000000000000000000000000000000000000000000000ecba43e27d4cff6e139ae5c1424151aa41f8bcf1c89132d1a98a915740d271d9e913ff854c00000000000000000000000000000000000000000000000000000001000111020000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010100010000"; + var hex = "000000000000000000000000000000000000000000000000000000000000000000000000add6632f6f3d29cdf94555bb191fb5296683e5446f9937c56bb94c8608023044e913ff854c00000000000000000000000000000000000000000000000000000001000111020000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000100010000"; using (MemoryStream ms = new MemoryStream(hex.HexToBytes(), false)) using (BinaryReader reader = new BinaryReader(ms)) @@ -199,11 +199,11 @@ public void ToJson() JObject jObj = uut.ToJson(); jObj.Should().NotBeNull(); - jObj["hash"].AsString().Should().Be("0xbc31c72acd2f3af6a1bc8454c0956a5e7aa6301c755e70cc1bd9263c1d7cfcba"); + jObj["hash"].AsString().Should().Be("0x9a164d5b9a1ab8745c97dbaaaef8eb30b0d80a00205acdc82daf502bee69bc20"); jObj["size"].AsNumber().Should().Be(167); jObj["version"].AsNumber().Should().Be(0); jObj["previousblockhash"].AsString().Should().Be("0x0000000000000000000000000000000000000000000000000000000000000000"); - jObj["merkleroot"].AsString().Should().Be("0xd971d24057918aa9d13291c8f1bcf841aa514142c1e59a136eff4c7de243baec"); + jObj["merkleroot"].AsString().Should().Be("0x44300208864cb96bc537996f44e5836629b51f19bb5545f9cd293d6f2f63d6ad"); jObj["time"].AsNumber().Should().Be(328665601001); jObj["index"].AsNumber().Should().Be(0); jObj["nextconsensus"].AsString().Should().Be("NKuyBkoGdZZSLyPbJEetheRhMjeznFZszf"); @@ -214,7 +214,7 @@ public void ToJson() jObj["tx"].Should().NotBeNull(); JArray txObj = (JArray)jObj["tx"]; - txObj[0]["hash"].AsString().Should().Be("0x85110746f54b4dc72502443c1bb1368ab256bbf3ea9f759b98a3f7861523e6e3"); + txObj[0]["hash"].AsString().Should().Be("0x995ce8ff19c30f6b0d6b03e5ed8bd30b08027c92177923782d3a64f573421931"); txObj[0]["size"].AsNumber().Should().Be(53); txObj[0]["version"].AsNumber().Should().Be(0); ((JArray)txObj[0]["attributes"]).Count.Should().Be(0); From 59f934db84981679da568942fb0389edf6ffa802 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Jul 2020 10:24:46 +0200 Subject: [PATCH 19/27] More UT fixes --- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 4 ++-- tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs | 2 +- tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs | 2 +- tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs | 4 ++-- .../SmartContract/UT_ContractParameterContext.cs | 4 ++-- tests/neo.UnitTests/SmartContract/UT_Syscalls.cs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index d1cd5b482b..4fd9617e63 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -79,7 +79,7 @@ private Transaction CreateTransactionWithFee(long fee) mock.Object.Script = randomBytes; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); - mock.Object.Signers = Array.Empty(); + mock.Object.Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }; mock.Object.Witnesses = new[] { new Witness @@ -103,7 +103,7 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) mock.Object.Script = randomBytes; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); - mock.Object.Signers = Array.Empty(); + mock.Object.Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }; mock.Object.Witnesses = new[] { new Witness diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs index d10a70eaeb..4c9e2fa333 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -24,7 +24,7 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) mock.Object.NetworkFee = networkFee; mock.Object.SystemFee = systemFee; mock.Object.Attributes = Array.Empty(); - mock.Object.Signers = Array.Empty(); + mock.Object.Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }; mock.Object.Witnesses = new[] { new Witness diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs index 3d24c14509..82799f233f 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs @@ -18,7 +18,7 @@ public void Serialize_Deserialize_Global() Account = UInt160.Zero }; - var hex = "000000000000000000000000000000000000000000"; + var hex = "000000000000000000000000000000000000000080"; attr.ToArray().ToHexString().Should().Be(hex); var copy = hex.HexToBytes().AsSerializable(); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 2436b2cb7b..9af2a124c8 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -927,12 +927,12 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() } [TestMethod] - public void FeeIsSignatureContract_TestScope_Global_Default() + public void FeeIsSignatureContract_TestScope_FeeOnly_Default() { // Global is supposed to be default Signer cosigner = new Signer(); - cosigner.Scopes.Should().Be(WitnessScope.Global); + cosigner.Scopes.Should().Be(WitnessScope.FeeOnly); var wallet = TestUtils.GenerateTestWallet(); var snapshot = Blockchain.Singleton.GetSnapshot(); diff --git a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index 6e1b05cf35..b96c06ae3c 100644 --- a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -45,13 +45,13 @@ public void TestToString() var context = new ContractParametersContext(tx); context.Add(contract, 0, new byte[] { 0x01 }); string str = context.ToString(); - str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hex"":""AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZlCQy6G3D7aqPb2SiHY17HfH1RsBAQA="",""items"":{}}"); + str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hex"":""AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmUJDLobcPtqo9vZKIdjXsd8fVGwEAAQA="",""items"":{}}"); } [TestMethod] public void TestParse() { - var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"hex\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZlCQy6G3D7aqPb2SiHY17HfH1RsBAQA=\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"IQJv8DuUkkHOHa3UNRnmlg4KhbQaaaBcMoEDqivOFZTKFmh0dHaq\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"AQ==\"}]}}}"); + var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"hex\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmUJDLobcPtqo9vZKIdjXsd8fVGwEAAQA=\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"IQJv8DuUkkHOHa3UNRnmlg4KhbQaaaBcMoEDqivOFZTKFmh0dHaq\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"AQ==\"}]}}}"); ret.ScriptHashes[0].ToString().Should().Be("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); ((Transaction)ret.Verifiable).Script.ToHexString().Should().Be(new byte[1].ToHexString()); } diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index a7dca5b434..b32e808f4d 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -239,7 +239,7 @@ public void System_ExecutionEngine_GetScriptContainer() var tx = new Transaction() { Script = new byte[] { 0x01 }, - Signers = Array.Empty(), + Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }, Attributes = Array.Empty(), NetworkFee = 0x02, SystemFee = 0x03, From eea80a2a4fe80929d13ef7ce8c7c1fab38ea8402 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 16:47:02 +0800 Subject: [PATCH 20/27] Fix Sender's WitnessScope --- src/neo/Network/P2P/Payloads/Transaction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 332a6021d2..5aab07af65 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -178,7 +178,7 @@ private static IEnumerable DeserializeSigners(BinaryReader reader, int m for (int i = 0; i < count; i++) { Signer signer = reader.ReadSerializable(); - if (i == 0 ^ signer.Scopes == WitnessScope.FeeOnly) + if (i > 0 && signer.Scopes == WitnessScope.FeeOnly) throw new FormatException(); if (!hashset.Add(signer.Account)) throw new FormatException(); From cf8ffba186b1b7fe5f20cec277777566a707ea7e Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 17:48:18 +0800 Subject: [PATCH 21/27] Fix Wallet --- src/neo/Wallets/Wallet.cs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 6f9aa9a3da..4410629fa9 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -192,6 +192,26 @@ public static byte[] GetPrivateKeyFromWIF(string wif) return privateKey; } + private static Signer[] GetSigners(UInt160 sender, Signer[] cosigners) + { + for (int i = 0; i < cosigners.Length; i++) + { + if (cosigners[i].Account.Equals(sender)) + { + if (i == 0) return cosigners; + List list = new List(cosigners); + list.RemoveAt(i); + list.Insert(0, cosigners[i]); + return list.ToArray(); + } + } + return cosigners.Prepend(new Signer + { + Account = sender, + Scopes = WitnessScope.FeeOnly + }).ToArray(); + } + public virtual WalletAccount Import(X509Certificate2 cert) { byte[] privateKey; @@ -288,16 +308,15 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null } } - public Transaction MakeTransaction(byte[] script, Signer[] signers = null, TransactionAttribute[] attributes = null) + public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Signer[] cosigners = null, TransactionAttribute[] attributes = null) { UInt160[] accounts; - if (signers is null || signers.Length > 0) + if (sender is null) { accounts = GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray(); } else { - var sender = signers[0].Account; if (!Contains(sender)) throw new ArgumentException($"The address {sender} was not found in the wallet"); accounts = new[] { sender }; @@ -305,11 +324,11 @@ public Transaction MakeTransaction(byte[] script, Signer[] signers = null, Trans using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { var balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - return MakeTransaction(snapshot, script, signers ?? Array.Empty(), attributes ?? Array.Empty(), balances_gas); + return MakeTransaction(snapshot, script, cosigners ?? Array.Empty(), attributes ?? Array.Empty(), balances_gas); } } - private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] signers, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) + private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] cosigners, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) { Random rand = new Random(); foreach (var (account, value) in balances_gas) @@ -320,7 +339,7 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] Nonce = (uint)rand.Next(), Script = script, ValidUntilBlock = snapshot.Height + Transaction.MaxValidUntilBlockIncrement, - Signers = signers.Prepend(new Signer { Account = account }).ToArray(), + Signers = GetSigners(account, cosigners), Attributes = attributes, }; From 6b4a56b49e12e374a20208c8a7fa916ae898950a Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Jul 2020 13:41:49 +0200 Subject: [PATCH 22/27] Fix UT --- .../Network/P2P/Payloads/UT_Transaction.cs | 89 ++++++++++--------- tests/neo.UnitTests/TestUtils.cs | 2 +- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 6 +- 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 9af2a124c8..354c143043 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -316,7 +316,7 @@ public void FeeIsSignatureContract_TestScope_Global() // using this... - var tx = wallet.MakeTransaction(script, signers); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -403,7 +403,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() // using this... - var tx = wallet.MakeTransaction(script, signers); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -493,7 +493,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() // using this... - var tx = wallet.MakeTransaction(script, signers); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -581,7 +581,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, signers)); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, acc.ScriptHash, signers)); Assert.IsNull(tx); } } @@ -630,7 +630,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // using this... - var tx = wallet.MakeTransaction(script, signers); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -725,7 +725,7 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, signers, attributes)); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, acc.ScriptHash, signers, attributes)); Assert.IsNull(tx); } } @@ -768,7 +768,7 @@ public void Transaction_Serialize_Deserialize_Simple() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Signers = Array.Empty(), + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, Attributes = Array.Empty(), Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } @@ -777,15 +777,16 @@ public void Transaction_Serialize_Deserialize_Simple() byte[] sTx = txSimple.ToArray(); // detailed hexstring info (basic checking) - sTx.ToHexString().Should().Be("00" + // version - "04030201" + // nonce - "00e1f50500000000" + // system fee (1 GAS) - "0100000000000000" + // network fee (1 satoshi) - "04030201" + // timelimit - "00" + // no attributes - "00" + // no signer - "0111" + // push1 script - "00"); // no witnesses + sTx.ToHexString().Should().Be( + "00" + // version + "04030201" + // nonce + "00e1f50500000000" + // system fee (1 GAS) + "0100000000000000" + // network fee (1 satoshi) + "04030201" + // timelimit + "01000000000000000000000000000000000000000000" + // empty signer + "00" + // no attributes + "0111" + // push1 script + "00"); // no witnesses // try to deserialize Transaction tx2 = Neo.IO.Helper.AsSerializable(sTx); @@ -797,7 +798,14 @@ public void Transaction_Serialize_Deserialize_Simple() tx2.NetworkFee.Should().Be(0x0000000000000001); tx2.ValidUntilBlock.Should().Be(0x01020304); tx2.Attributes.Should().BeEquivalentTo(new TransactionAttribute[0] { }); - tx2.Signers.Should().BeEquivalentTo(new Signer[0] { }); + tx2.Signers.Should().BeEquivalentTo(new Signer[] { + new Signer() + { + Account = UInt160.Zero, + AllowedContracts = Array.Empty(), + AllowedGroups = Array.Empty() } + } + ); tx2.Script.Should().BeEquivalentTo(new byte[] { (byte)OpCode.PUSH1 }); tx2.Witnesses.Should().BeEquivalentTo(new Witness[0] { }); } @@ -815,21 +823,7 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = Array.Empty(), - Signers = Array.Empty(), - Script = new byte[] { (byte)OpCode.PUSH1 }, - Witnesses = new Witness[0] { } - }; - - byte[] sTx = txDoubleCosigners.ToArray(); - - // no need for detailed hexstring here (see basic tests for it) - sTx.ToHexString().Should().Be("000403020100e1f505000000000100000000000000040302010000011100"); - - // back to transaction (should fail, due to non-distinct cosigners) - Transaction tx2 = null; - Assert.ThrowsException(() => - { - txDoubleCosigners.Signers = new Signer[] + Signers = new Signer[] { new Signer() { @@ -841,8 +835,21 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), // same account as above Scopes = WitnessScope.CalledByEntry // different scope, but still, same account (cannot do that) } - }; - }); + }, + Script = new byte[] { (byte)OpCode.PUSH1 }, + Witnesses = new Witness[0] { } + }; + + byte[] sTx = txDoubleCosigners.ToArray(); + + // no need for detailed hexstring here (see basic tests for it) + sTx.ToHexString().Should().Be("000403020100e1f505000000000100000000000000040302010209080706050403020100090807060504030201008009080706050403020100090807060504030201000100011100"); + + // back to transaction (should fail, due to non-distinct cosigners) + Transaction tx2 = null; + Assert.ThrowsException(() => + tx2 = Neo.IO.Helper.AsSerializable(sTx) + ); Assert.IsNull(tx2); } @@ -865,7 +872,8 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() hex = hex.Insert(0, "0"); cosigners1[i] = new Signer { - Account = UInt160.Parse(hex) + Account = UInt160.Parse(hex), + Scopes = WitnessScope.CalledByEntry }; } @@ -968,12 +976,13 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() // default to global scope var signers = new Signer[]{ new Signer { - Account = acc.ScriptHash + Account = acc.ScriptHash, + Scopes = WitnessScope.CalledByEntry } }; // using this... - var tx = wallet.MakeTransaction(script, signers); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -1021,7 +1030,7 @@ public void ToJson() { uut.Script = TestUtils.GetByteArray(32, 0x42); uut.SystemFee = 4200000000; - uut.Signers = Array.Empty(); + uut.Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }; uut.Attributes = Array.Empty(); uut.Witnesses = new[] { @@ -1034,8 +1043,8 @@ public void ToJson() JObject jObj = uut.ToJson(); jObj.Should().NotBeNull(); - jObj["hash"].AsString().Should().Be("0xb1fa52d0778d1e31d0c419e6006d522c5a0e006f7fd83489e7360f7847a6edfe"); - jObj["size"].AsNumber().Should().Be(63); + jObj["hash"].AsString().Should().Be("0xe17382d26702bde77b00a9f23ea156b77c418764cbc45b2692088b5fde0336e3"); + jObj["size"].AsNumber().Should().Be(84); jObj["version"].AsNumber().Should().Be(0); ((JArray)jObj["attributes"]).Count.Should().Be(0); jObj["netfee"].AsString().Should().Be("0"); diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index 702c67e051..a97869c8b5 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -195,7 +195,7 @@ public static Transaction CreateRandomHashTransaction() { Script = randomBytes, Attributes = Array.Empty(), - Signers = Array.Empty(), + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, Witnesses = new[] { new Witness diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index 5b8183257d..7f4ad69332 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -367,7 +367,7 @@ public void TestMakeTransaction1() public void TestMakeTransaction2() { MyWallet wallet = new MyWallet(); - Action action = () => wallet.MakeTransaction(new byte[] { }, null, new TransactionAttribute[] { }); + Action action = () => wallet.MakeTransaction(new byte[] { }, null, null, Array.Empty()); action.Should().Throw(); Contract contract = Contract.Create(new ContractParameterType[] { ContractParameterType.Boolean }, new byte[] { 1 }); @@ -381,7 +381,7 @@ public void TestMakeTransaction2() entry.GetInteroperable().Balance = 1000000 * NativeContract.GAS.Factor; snapshot.Commit(); - var tx = wallet.MakeTransaction(new byte[] { }, new[]{ new Signer() + var tx = wallet.MakeTransaction(new byte[] { }, account.ScriptHash, new[]{ new Signer() { Account = account.ScriptHash, Scopes = WitnessScope.CalledByEntry @@ -389,7 +389,7 @@ public void TestMakeTransaction2() tx.Should().NotBeNull(); - tx = wallet.MakeTransaction(new byte[] { }, null, new TransactionAttribute[] { }); + tx = wallet.MakeTransaction(new byte[] { }, null, null, Array.Empty()); tx.Should().NotBeNull(); entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); From a2ae4a256e75a168d3d14610a9aca96529e627e3 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Jul 2020 13:44:19 +0200 Subject: [PATCH 23/27] Explicit FeeOnly for DeployNativeContracts --- src/neo/Ledger/Blockchain.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 81951209cb..866c2ad8d1 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -167,7 +167,12 @@ private static Transaction DeployNativeContracts() Version = 0, Script = script, SystemFee = 0, - Signers = new[] { new Signer() { Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash() } }, + Signers = new[] { new Signer() + { + Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash(), + Scopes = WitnessScope.FeeOnly + } + }, Attributes = Array.Empty(), Witnesses = new[] { From f09a8a51128b8451ebf10a127b32933f59153de6 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Jul 2020 13:48:04 +0200 Subject: [PATCH 24/27] Same order as serialization --- src/neo/Wallets/Wallet.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 4410629fa9..55170ec476 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -353,8 +353,8 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); - // base size for transaction: includes const_header + attributes + script + hashes - int size = Transaction.HeaderSize + tx.Attributes.GetVarSize() + tx.Signers.GetVarSize() + script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + // base size for transaction: includes const_header + signers + attributes + script + hashes + int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Attributes.GetVarSize()+ script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); foreach (UInt160 hash in hashes) { From 4870875072d9e3213ccf69df62db5ac4659ab402 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Jul 2020 13:57:14 +0200 Subject: [PATCH 25/27] Test FeeOnly --- .../neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 354c143043..bf11da269f 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -973,14 +973,17 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() script = sb.ToArray(); } - // default to global scope + // try to use fee only inside the smart contract var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, - Scopes = WitnessScope.CalledByEntry + Scopes = WitnessScope.FeeOnly } }; - // using this... + Assert.ThrowsException(() => wallet.MakeTransaction(script, acc.ScriptHash, signers)); + + // change to global scope + signers[0].Scopes = WitnessScope.Global; var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); From cb8f9789cdad8b02b7d05c1e71bc3f03a9f3ca4c Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Jul 2020 15:42:47 +0200 Subject: [PATCH 26/27] dotnet format --- src/neo/Wallets/Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 4784e73d0a..d77532abb9 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -356,7 +356,7 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); // base size for transaction: includes const_header + signers + attributes + script + hashes - int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Attributes.GetVarSize()+ script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Attributes.GetVarSize() + script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); foreach (UInt160 hash in hashes) { From be47d0d9e06f59a7a291a59780a215908bfcef68 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 10 Jul 2020 22:26:19 +0800 Subject: [PATCH 27/27] format --- src/neo/Ledger/Blockchain.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 866c2ad8d1..092309a5a7 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -167,10 +167,12 @@ private static Transaction DeployNativeContracts() Version = 0, Script = script, SystemFee = 0, - Signers = new[] { new Signer() + Signers = new[] + { + new Signer { - Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash(), - Scopes = WitnessScope.FeeOnly + Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash(), + Scopes = WitnessScope.FeeOnly } }, Attributes = Array.Empty(),