Example #1
0
        public void TestSignMulti()
        {
            txManager = new TransactionManager(rpcClientMock.Object, sender);

            var multiContract = Contract.CreateMultiSigContract(2, keyPair1.PublicKey, keyPair2.PublicKey);

            // Cosigner needs multi signature
            Cosigner[] cosigners = new Cosigner[1]
            {
                new Cosigner
                {
                    Account = multiContract.ScriptHash,
                    Scopes  = WitnessScope.Global
                }
            };

            byte[] script = new byte[1];
            txManager.MakeTransaction(script, null, cosigners, 0_10000000)
            .AddMultiSig(keyPair1, 2, keyPair1.PublicKey, keyPair2.PublicKey)
            .AddMultiSig(keyPair2, 2, keyPair1.PublicKey, keyPair2.PublicKey)
            .AddSignature(keyPair1)
            .Sign();

            var store    = TestBlockchain.GetStore();
            var snapshot = store.GetSnapshot();

            var tx = txManager.Tx;

            Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee));
        }
Example #2
0
        public void TestAddWitness()
        {
            txManager = new TransactionManager(rpcClientMock.Object, sender);

            // Cosigner as contract scripthash
            Cosigner[] cosigners = new Cosigner[1]
            {
                new Cosigner
                {
                    Account = UInt160.Zero,
                    Scopes  = WitnessScope.Global
                }
            };

            byte[] script = new byte[1];
            txManager.MakeTransaction(script, null, cosigners);
            txManager.AddWitness(UInt160.Zero);
            txManager.AddSignature(keyPair1);
            txManager.Sign();

            var tx = txManager.Tx;

            Assert.AreEqual(2, tx.Witnesses.Length);
            Assert.AreEqual(0, tx.Witnesses[0].VerificationScript.Length);
            Assert.AreEqual(0, tx.Witnesses[0].InvocationScript.Length);
        }
Example #3
0
        public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT()
        {
            var wallet   = TestUtils.GenerateTestWallet();
            var snapshot = store.GetSnapshot();

            // no password on this wallet
            using (var unlock = wallet.Unlock(""))
            {
                var acc = wallet.CreateAccount();

                // Fake balance

                var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash);

                var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem
                {
                    Value = new Nep5AccountState().ToByteArray()
                });

                entry.Value = new Nep5AccountState()
                {
                    Balance = 10000 * NativeContract.GAS.Factor
                }
                .ToByteArray();

                // Make transaction
                // Manually creating script

                byte[] script;
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    // self-transfer of 1e-8 GAS
                    System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value;
                    sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value);
                    sb.Emit(OpCode.THROWIFNOT);
                    script = sb.ToArray();
                }

                // trying global scope
                var cosigners = new Cosigner[] { new Cosigner
                                                 {
                                                     Account          = acc.ScriptHash,
                                                     Scopes           = WitnessScope.CustomContracts,
                                                     AllowedContracts = new[] { NativeContract.NEO.Hash }
                                                 } };

                // using this...

                // expects FAULT on execution of 'transfer' Application script
                // due to lack of a valid witness validation
                Transaction tx = null;
                Assert.ThrowsException <InvalidOperationException>(() =>
                                                                   tx = wallet.MakeTransaction(script, acc.ScriptHash, new TransactionAttribute[0], cosigners));
                Assert.IsNull(tx);
            }
        }
Example #4
0
        public void Json_Global()
        {
            var attr = new Cosigner()
            {
                Scopes  = WitnessScope.Global,
                Account = UInt160.Zero
            };

            var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"Global\"}";

            attr.ToJson().ToString().Should().Be(json);
        }
Example #5
0
        public void Json_CustomContracts()
        {
            var attr = new Cosigner()
            {
                Scopes           = WitnessScope.CustomContracts,
                AllowedContracts = new[] { UInt160.Zero },
                Account          = UInt160.Zero
            };

            var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomContracts\",\"allowedContracts\":[\"0x0000000000000000000000000000000000000000\"]}";

            attr.ToJson().ToString().Should().Be(json);
        }
Example #6
0
        public void Json_CustomGroups()
        {
            var attr = new Cosigner()
            {
                Scopes        = WitnessScope.CustomGroups,
                AllowedGroups = new[] { ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1) },
                Account       = UInt160.Zero
            };

            var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomGroups\",\"allowedGroups\":[\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\"]}";

            attr.ToJson().ToString().Should().Be(json);
        }
Example #7
0
        public void Serialize_Deserialize_CalledByEntry()
        {
            var attr = new Cosigner()
            {
                Scopes  = WitnessScope.CalledByEntry,
                Account = UInt160.Zero
            };

            var hex = "01000000000000000000000000000000000000000001";

            attr.ToArray().ToHexString().Should().Be(hex);

            var copy = hex.HexToBytes().AsSerializable <Cosigner>();

            Assert.AreEqual(attr.Scopes, copy.Scopes);
            Assert.AreEqual(attr.Account, copy.Account);
        }
Example #8
0
        public void Json_Global()
        {
            var attr = new Cosigner()
            {
                Scopes  = WitnessScope.Global,
                Account = UInt160.Zero
            };

            var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"Global\"}";

            attr.ToJson().ToString().Should().Be(json);

            var copy = Cosigner.FromJson(JObject.Parse(json));

            Assert.AreEqual(attr.Scopes, copy.Scopes);
            Assert.AreEqual(attr.Account, copy.Account);
        }
Example #9
0
        public void Json_CustomContracts()
        {
            var attr = new Cosigner()
            {
                Scopes           = WitnessScope.CustomContracts,
                AllowedContracts = new[] { UInt160.Zero },
                Account          = UInt160.Zero
            };

            var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomContracts\",\"allowedContracts\":[\"0x0000000000000000000000000000000000000000\"]}";

            attr.ToJson().ToString().Should().Be(json);

            var copy = Cosigner.FromJson(JObject.Parse(json));

            Assert.AreEqual(attr.Scopes, copy.Scopes);
            CollectionAssert.AreEqual(attr.AllowedContracts, copy.AllowedContracts);
            Assert.AreEqual(attr.Account, copy.Account);
        }
Example #10
0
        public void Serialize_Deserialize_CustomContracts()
        {
            var attr = new Cosigner()
            {
                Scopes           = WitnessScope.CustomContracts,
                AllowedContracts = new[] { UInt160.Zero },
                Account          = UInt160.Zero
            };

            var hex = "01000000000000000000000000000000000000000010010000000000000000000000000000000000000000";

            attr.ToArray().ToHexString().Should().Be(hex);

            var copy = hex.HexToBytes().AsSerializable <Cosigner>();

            Assert.AreEqual(attr.Scopes, copy.Scopes);
            CollectionAssert.AreEqual(attr.AllowedContracts, copy.AllowedContracts);
            Assert.AreEqual(attr.Account, copy.Account);
        }
Example #11
0
        public void Serialize_Deserialize_CustomGroups()
        {
            var attr = new Cosigner()
            {
                Scopes        = WitnessScope.CustomGroups,
                AllowedGroups = new[] { ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1) },
                Account       = UInt160.Zero
            };

            var hex = "010000000000000000000000000000000000000000200103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c";

            attr.ToArray().ToHexString().Should().Be(hex);

            var copy = hex.HexToBytes().AsSerializable <Cosigner>();

            Assert.AreEqual(attr.Scopes, copy.Scopes);
            CollectionAssert.AreEqual(attr.AllowedGroups, copy.AllowedGroups);
            Assert.AreEqual(attr.Account, copy.Account);
        }
Example #12
0
        public void TestSign()
        {
            txManager = new TransactionManager(rpcClientMock.Object, sender);

            TransactionAttribute[] attributes = new TransactionAttribute[1]
            {
                new TransactionAttribute
                {
                    Usage = TransactionAttributeUsage.Url,
                    Data  = "53616d706c6555726c".HexToBytes() // "SampleUrl"
                }
            };

            Cosigner[] cosigners = new Cosigner[1] {
                new Cosigner {
                    Account = sender,
                    Scopes  = WitnessScope.Global
                }
            };

            byte[] script = new byte[1];
            txManager.MakeTransaction(script, attributes, cosigners)
            .AddSignature(keyPair1)
            .Sign();

            // get signature from Witnesses
            var tx = txManager.Tx;

            byte[] signature = tx.Witnesses[0].InvocationScript.Skip(2).ToArray();

            Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey.EncodePoint(false).Skip(1).ToArray()));
            // verify network fee
            long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null);

            Assert.AreEqual(networkFee, tx.NetworkFee);

            // duplicate sign should not add new witness
            txManager.AddSignature(keyPair1).Sign();
            Assert.AreEqual(1, txManager.Tx.Witnesses.Length);

            // throw exception when the KeyPair is wrong
            Assert.ThrowsException <Exception>(() => txManager.AddSignature(keyPair2).Sign());
        }
Example #13
0
        public void Json_CustomGroups()
        {
            var attr = new Cosigner()
            {
                Scopes        = WitnessScope.CustomGroups,
                AllowedGroups = new[] { ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1) },
                Account       = UInt160.Zero
            };

            var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomGroups\",\"allowedGroups\":[\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\"]}";

            attr.ToJson().ToString().Should().Be(json);

            var copy = Cosigner.FromJson(JObject.Parse(json));

            Assert.AreEqual(attr.Scopes, copy.Scopes);
            CollectionAssert.AreEqual(attr.AllowedGroups, copy.AllowedGroups);
            Assert.AreEqual(attr.Account, copy.Account);
        }
Example #14
0
        public void TestSignMulti()
        {
            txManager = new TransactionManager(rpcClientMock.Object, sender);

            var multiContract = Contract.CreateMultiSigContract(2, keyPair1.PublicKey, keyPair2.PublicKey);

            // Cosigner needs multi signature
            Cosigner[] cosigners = new Cosigner[1]
            {
                new Cosigner
                {
                    Account = multiContract.ScriptHash,
                    Scopes  = WitnessScope.Global
                }
            };

            byte[] script = new byte[1];
            txManager.MakeTransaction(script, null, cosigners)
            .AddMultiSig(keyPair1, 2, keyPair1.PublicKey, keyPair2.PublicKey)
            .AddMultiSig(keyPair2, 2, keyPair1.PublicKey, keyPair2.PublicKey)
            .AddSignature(keyPair1)
            .Sign();
        }
Example #15
0
        public void Transaction_Serialize_Deserialize_MaxSizeCosigners()
        {
            // cosigners must respect count

            int maxCosigners = 16;

            // --------------------------------------
            // this should pass (respecting max size)

            var cosigners1 = new Cosigner[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
                {
                    Account = UInt160.Parse(hex)
                };
            }

            Transaction txCosigners1 = new Transaction
            {
                Version         = 0x00,
                Nonce           = 0x01020304,
                Sender          = UInt160.Zero,
                SystemFee       = (long)BigInteger.Pow(10, 8), // 1 GAS
                NetworkFee      = 0x0000000000000001,
                ValidUntilBlock = 0x01020304,
                Attributes      = new TransactionAttribute[0] {
                },
                Cosigners       = cosigners1, // max + 1 (should fail)
                Script          = new byte[] { (byte)OpCode.PUSH1 },
                Witnesses       = new Witness[0] {
                }
            };

            byte[] sTx1 = txCosigners1.ToArray();

            // back to transaction (should fail, due to non-distinct cosigners)
            Transaction tx1 = Trustlink.IO.Helper.AsSerializable <Transaction>(sTx1);

            Assert.IsNotNull(tx1);

            // ----------------------------
            // this should fail (max + 1)

            var cosigners = new Cosigner[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
                {
                    Account = UInt160.Parse(hex)
                };
            }

            Transaction txCosigners = new Transaction
            {
                Version         = 0x00,
                Nonce           = 0x01020304,
                Sender          = UInt160.Zero,
                SystemFee       = (long)BigInteger.Pow(10, 8), // 1 GAS
                NetworkFee      = 0x0000000000000001,
                ValidUntilBlock = 0x01020304,
                Attributes      = new TransactionAttribute[0] {
                },
                Cosigners       = cosigners, // max + 1 (should fail)
                Script          = new byte[] { (byte)OpCode.PUSH1 },
                Witnesses       = new Witness[0] {
                }
            };

            byte[] sTx2 = txCosigners.ToArray();

            // back to transaction (should fail, due to non-distinct cosigners)
            Transaction tx2 = null;

            Assert.ThrowsException <FormatException>(() =>
                                                     tx2 = Trustlink.IO.Helper.AsSerializable <Transaction>(sTx2)
                                                     );
            Assert.IsNull(tx2);
        }
 public DisbandingTxSignature GetDisbandingTxSignature(Cosigner cosigner, int input)
 {
     return(_disbandingTxSignatureRepo.Get(cosigner, input));
 }
Example #17
0
 public Cosigner Add(Cosigner cosigner)
 {
     return(Add <Cosigner>(cosigner));
 }
 public DisbandingTxSignature Get(Cosigner cosigner, int utxoPos)
 {
     return(_context.DisbandingTxSignature.FirstOrDefault(x => x.AddressId == cosigner.AddressId && x.KeyOrder == cosigner.KeyOrder && x.UtxoPos == utxoPos));
 }
Example #19
0
        public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS()
        {
            var wallet   = TestUtils.GenerateTestWallet();
            var snapshot = Blockchain.Singleton.GetSnapshot();

            // no password on this wallet
            using (var unlock = wallet.Unlock(""))
            {
                var acc = wallet.CreateAccount();

                // Fake balance

                var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash);

                var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new Nep5AccountState()));

                entry.GetInteroperable <Nep5AccountState>().Balance = 10000 * NativeContract.GAS.Factor;

                snapshot.Commit();

                // Make transaction
                // Manually creating script

                byte[] script;
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    // self-transfer of 1e-8 GAS
                    System.Numerics.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();
                }

                // trying two custom hashes, for same target account
                var cosigners = new Cosigner[] { new Cosigner
                                                 {
                                                     Account          = acc.ScriptHash,
                                                     Scopes           = WitnessScope.CustomContracts,
                                                     AllowedContracts = new[] { NativeContract.NEO.Hash, NativeContract.GAS.Hash }
                                                 } };

                // using this...

                var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners);

                Assert.IsNotNull(tx);
                Assert.IsNull(tx.Witnesses);

                // ----
                // Sign
                // ----

                var  data   = new ContractParametersContext(tx);
                bool signed = wallet.Sign(data);
                Assert.IsTrue(signed);

                // get witnesses from signed 'data'
                tx.Witnesses = data.GetWitnesses();
                // only a single witness should exist
                tx.Witnesses.Length.Should().Be(1);
                // no attributes must exist
                tx.Attributes.Length.Should().Be(1);
                // one cosigner must exist
                tx.Cosigners.Length.Should().Be(1);

                // Fast check
                Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee));

                // Check
                long verificationGas = 0;
                foreach (var witness in tx.Witnesses)
                {
                    using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false))
                    {
                        engine.LoadScript(witness.VerificationScript);
                        engine.LoadScript(witness.InvocationScript);
                        Assert.AreEqual(VMState.HALT, engine.Execute());
                        Assert.AreEqual(1, engine.ResultStack.Count);
                        Assert.IsTrue(engine.ResultStack.Pop().ToBoolean());
                        verificationGas += engine.GasConsumed;
                    }
                }
                // get sizeGas
                var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot);
                // final check on sum: verification_cost + tx_size
                Assert.AreEqual(1305390, verificationGas + sizeGas);
                // final assert
                Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas);
            }
        }
Example #20
0
        public void FeeIsSignatureContract_TestScope_Global_Default()
        {
            // Global is supposed to be default

            Cosigner cosigner = new Cosigner();

            cosigner.Scopes.Should().Be(WitnessScope.Global);

            var wallet   = TestUtils.GenerateTestWallet();
            var snapshot = store.GetSnapshot();

            // no password on this wallet
            using (var unlock = wallet.Unlock(""))
            {
                var acc = wallet.CreateAccount();

                // Fake balance

                var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash);

                var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem
                {
                    Value = new Nep5AccountState().ToByteArray()
                });

                entry.Value = new Nep5AccountState()
                {
                    Balance = 10000 * NativeContract.GAS.Factor
                }
                .ToByteArray();

                // Make transaction
                // Manually creating script

                byte[] script;
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    // self-transfer of 1e-8 GAS
                    System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value;
                    sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value);
                    sb.Emit(OpCode.THROWIFNOT);
                    script = sb.ToArray();
                }

                // default to global scope
                var cosigners = new Cosigner[] { new Cosigner
                                                 {
                                                     Account = acc.ScriptHash
                                                 } };

                // using this...

                var tx = wallet.MakeTransaction(script, acc.ScriptHash, new TransactionAttribute[0], cosigners);

                Assert.IsNotNull(tx);
                Assert.IsNull(tx.Witnesses);

                // ----
                // Sign
                // ----

                var  data   = new ContractParametersContext(tx);
                bool signed = wallet.Sign(data);
                Assert.IsTrue(signed);

                // get witnesses from signed 'data'
                tx.Witnesses = data.GetWitnesses();
                tx.Witnesses.Length.Should().Be(1);

                // Fast check
                Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee));

                // Check
                long verificationGas = 0;
                foreach (var witness in tx.Witnesses)
                {
                    using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false))
                    {
                        engine.LoadScript(witness.VerificationScript);
                        engine.LoadScript(witness.InvocationScript);
                        Assert.AreEqual(VMState.HALT, engine.Execute());
                        Assert.AreEqual(1, engine.ResultStack.Count);
                        Assert.IsTrue(engine.ResultStack.Pop().GetBoolean());
                        verificationGas += engine.GasConsumed;
                    }
                }
                // get sizeGas
                var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot);
                // final check on sum: verification_cost + tx_size
                Assert.AreEqual(verificationGas + sizeGas, 1257240);
                // final assert
                Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas);
            }
        }
Example #21
0
        public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS()
        {
            var wallet   = TestUtils.GenerateTestWallet();
            var snapshot = store.GetSnapshot();

            // no password on this wallet
            using (var unlock = wallet.Unlock(""))
            {
                var acc = wallet.CreateAccount();

                // Fake balance

                var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash);

                var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem
                {
                    Value = new Nep5AccountState().ToByteArray()
                });

                entry.Value = new Nep5AccountState()
                {
                    Balance = 10000 * NativeContract.GAS.Factor
                }
                .ToByteArray();

                // Make transaction
                // Manually creating script

                byte[] script;
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    // self-transfer of 1e-8 GAS
                    System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value;
                    sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value);
                    sb.Emit(OpCode.THROWIFNOT);
                    script = sb.ToArray();
                }

                // trying CalledByEntry together with GAS
                var cosigners = new Cosigner[] { new Cosigner
                                                 {
                                                     Account = acc.ScriptHash,
                                                     // This combination is supposed to actually be an OR,
                                                     // where it's valid in both Entry and also for Custom hash provided (in any execution level)
                                                     // it would be better to test this in the future including situations where a deeper call level uses this custom witness successfully
                                                     Scopes           = WitnessScope.CustomContracts | WitnessScope.CalledByEntry,
                                                     AllowedContracts = new[] { NativeContract.GAS.Hash }
                                                 } };

                // using this...

                var tx = wallet.MakeTransaction(script, acc.ScriptHash, new TransactionAttribute[0], cosigners);

                Assert.IsNotNull(tx);
                Assert.IsNull(tx.Witnesses);

                // ----
                // Sign
                // ----

                var  data   = new ContractParametersContext(tx);
                bool signed = wallet.Sign(data);
                Assert.IsTrue(signed);

                // get witnesses from signed 'data'
                tx.Witnesses = data.GetWitnesses();
                tx.Witnesses.Length.Should().Be(1);

                // Fast check
                Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee));

                // Check
                long verificationGas = 0;
                foreach (var witness in tx.Witnesses)
                {
                    using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false))
                    {
                        engine.LoadScript(witness.VerificationScript);
                        engine.LoadScript(witness.InvocationScript);
                        Assert.AreEqual(VMState.HALT, engine.Execute());
                        Assert.AreEqual(1, engine.ResultStack.Count);
                        Assert.IsTrue(engine.ResultStack.Pop().GetBoolean());
                        verificationGas += engine.GasConsumed;
                    }
                }
                // get sizeGas
                var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot);
                // final check on sum: verification_cost + tx_size
                Assert.AreEqual(verificationGas + sizeGas, 1278240);
                // final assert
                Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas);
            }
        }