예제 #1
0
 public override bool Match(ApplicationEngine engine)
 {
     return(engine.CallingScriptHash is null || engine.CallingScriptHash == engine.EntryScriptHash);
 }
예제 #2
0
        public void System_Runtime_GetInvocationCounter()
        {
            ContractState contractA, contractB, contractC;
            var           snapshot  = TestBlockchain.GetStore().GetSnapshot();
            var           contracts = (TestDataCache <UInt160, ContractState>)snapshot.Contracts;

            // Create dummy contracts

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

                contractA = new ContractState()
                {
                    Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP }.Concat(script.ToArray()).ToArray()
                };
                contractB = new ContractState()
                {
                    Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP, (byte)OpCode.NOP }.Concat(script.ToArray()).ToArray()
                };
                contractC = new ContractState()
                {
                    Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP, (byte)OpCode.NOP, (byte)OpCode.NOP }.Concat(script.ToArray()).ToArray()
                };

                // Init A,B,C contracts
                // First two drops is for drop method and arguments

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

            // Call A,B,B,C

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

                // Execute

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

                // Check the results

                CollectionAssert.AreEqual
                (
                    engine.ResultStack.Select(u => (int)((VM.Types.Integer)u).GetBigInteger()).ToArray(),
                    new int[]
                {
                    1,     /* A */
                    1,     /* B */
                    2,     /* B */
                    1      /* C */
                }
                );
            }
        }
        public Transaction GetTransaction()
        {
            var cOutputs = txOutListBox1.Items.Where(p => p.AssetId is UInt160).GroupBy(p => new
            {
                AssetId = (UInt160)p.AssetId,
                Account = p.ScriptHash
            }, (k, g) => new
            {
                AssetId = k.AssetId,
                Value   = g.Aggregate(BigInteger.Zero, (x, y) => x + y.Value.Value),
                Account = k.Account
            }).ToArray();
            Transaction tx;
            List <TransactionAttribute> attributes = new List <TransactionAttribute>();

            if (cOutputs.Length == 0)
            {
                tx = new ContractTransaction();
            }
            else
            {
                UInt160[]         addresses   = Program.CurrentWallet.GetAccounts().Select(p => p.ScriptHash).ToArray();
                HashSet <UInt160> sAttributes = new HashSet <UInt160>();
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    foreach (var output in cOutputs)
                    {
                        byte[] script;
                        using (ScriptBuilder sb2 = new ScriptBuilder())
                        {
                            foreach (UInt160 address in addresses)
                            {
                                sb2.EmitAppCall(output.AssetId, "balanceOf", address);
                            }
                            sb2.Emit(OpCode.DEPTH, OpCode.PACK);
                            script = sb2.ToArray();
                        }
                        ApplicationEngine engine = ApplicationEngine.Run(script);
                        if (engine.State.HasFlag(VMState.FAULT))
                        {
                            return(null);
                        }
                        var balances = engine.EvaluationStack.Pop().GetArray().Reverse().Zip(addresses, (i, a) => new
                        {
                            Account = a,
                            Value   = i.GetBigInteger()
                        }).ToArray();
                        BigInteger sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value);
                        if (sum < output.Value)
                        {
                            return(null);
                        }
                        if (sum != output.Value)
                        {
                            balances = balances.OrderByDescending(p => p.Value).ToArray();
                            BigInteger amount = output.Value;
                            int        i      = 0;
                            while (balances[i].Value <= amount)
                            {
                                amount -= balances[i++].Value;
                            }
                            if (amount == BigInteger.Zero)
                            {
                                balances = balances.Take(i).ToArray();
                            }
                            else
                            {
                                balances = balances.Take(i).Concat(new[] { balances.Last(p => p.Value >= amount) }).ToArray();
                            }
                            sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value);
                        }
                        sAttributes.UnionWith(balances.Select(p => p.Account));
                        for (int i = 0; i < balances.Length; i++)
                        {
                            BigInteger value = balances[i].Value;
                            if (i == 0)
                            {
                                BigInteger change = sum - output.Value;
                                if (change > 0)
                                {
                                    value -= change;
                                }
                            }
                            sb.EmitAppCall(output.AssetId, "transfer", balances[i].Account, output.Account, value);
                            sb.Emit(OpCode.THROWIFNOT);
                        }
                    }
                    tx = new InvocationTransaction
                    {
                        Version = 1,
                        Script  = sb.ToArray()
                    };
                }
                attributes.AddRange(sAttributes.Select(p => new TransactionAttribute
                {
                    Usage = TransactionAttributeUsage.Script,
                    Data  = p.ToArray()
                }));
            }
            if (!string.IsNullOrEmpty(remark))
            {
                attributes.Add(new TransactionAttribute
                {
                    Usage = TransactionAttributeUsage.Remark,
                    Data  = Encoding.UTF8.GetBytes(remark)
                });
            }
            tx.Attributes = attributes.ToArray();
            tx.Outputs    = txOutListBox1.Items.Where(p => p.AssetId is UInt256).Select(p => p.ToTxOutput()).ToArray();
            if (tx is ContractTransaction ctx)
            {
                tx = Program.CurrentWallet.MakeTransaction(ctx, change_address: ChangeAddress, fee: Fee);
            }
            return(tx);
        }
예제 #4
0
 internal override ContractTask Initialize(ApplicationEngine engine)
 {
     engine.Snapshot.Add(CreateStorageKey(Prefix_MinimumDeploymentFee), new StorageItem(10_00000000));
     engine.Snapshot.Add(CreateStorageKey(Prefix_NextAvailableId), new StorageItem(1));
     return(ContractTask.CompletedTask);
 }
예제 #5
0
 public override bool Match(ApplicationEngine engine)
 {
     return(!Expression.Match(engine));
 }
예제 #6
0
        private void Persist(Block block)
        {
            using (Snapshot snapshot = GetSnapshot())
            {
                List <ApplicationExecuted> all_application_executed = new List <ApplicationExecuted>();
                snapshot.PersistingBlock = block;
                if (block.Index > 0)
                {
                    NativeContract[] contracts = { NativeContract.GAS, NativeContract.NEO };
                    using (ApplicationEngine engine = new ApplicationEngine(TriggerType.System, null, snapshot, 0, true))
                    {
                        using (ScriptBuilder sb = new ScriptBuilder())
                        {
                            foreach (NativeContract contract in contracts)
                            {
                                sb.EmitAppCall(contract.Hash, "onPersist");
                            }
                            engine.LoadScript(sb.ToArray());
                        }
                        if (engine.Execute() != VMState.HALT)
                        {
                            throw new InvalidOperationException();
                        }
                        ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                snapshot.Blocks.Add(block.Hash, block.Trim());
                foreach (Transaction tx in block.Transactions)
                {
                    snapshot.Transactions.Add(tx.Hash, new TransactionState
                    {
                        BlockIndex  = block.Index,
                        Transaction = tx
                    });
                    using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx, snapshot.Clone(), tx.Gas))
                    {
                        engine.LoadScript(tx.Script);
                        if (!engine.Execute().HasFlag(VMState.FAULT))
                        {
                            engine.Snapshot.Commit();
                        }
                        ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                snapshot.BlockHashIndex.GetAndChange().Hash  = block.Hash;
                snapshot.BlockHashIndex.GetAndChange().Index = block.Index;
                if (block.Index == header_index.Count)
                {
                    header_index.Add(block.Hash);
                    snapshot.HeaderHashIndex.GetAndChange().Hash  = block.Hash;
                    snapshot.HeaderHashIndex.GetAndChange().Index = block.Index;
                }
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    plugin.OnPersist(snapshot, all_application_executed);
                }
                snapshot.Commit();
                List <Exception> commitExceptions = null;
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    try
                    {
                        plugin.OnCommit(snapshot);
                    }
                    catch (Exception ex)
                    {
                        if (plugin.ShouldThrowExceptionFromCommit(ex))
                        {
                            if (commitExceptions == null)
                            {
                                commitExceptions = new List <Exception>();
                            }

                            commitExceptions.Add(ex);
                        }
                    }
                }
                if (commitExceptions != null)
                {
                    throw new AggregateException(commitExceptions);
                }
            }
            UpdateCurrentSnapshot();
            OnPersistCompleted(block);
        }
예제 #7
0
 private ContractTask <ContractState> Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest)
 {
     return(Deploy(engine, nefFile, manifest, StackItem.Null));
 }
예제 #8
0
 public void TestRuntime_Platform()
 {
     ApplicationEngine.GetPlatform().Should().Be("NEO");
 }
예제 #9
0
        public void Runtime_GetNotifications_Test()
        {
            UInt160 scriptHash2;
            var     snapshot = TestBlockchain.GetTestSnapshot();

            using (var script = new ScriptBuilder())
            {
                // Notify method

                script.Emit(OpCode.SWAP, OpCode.NEWARRAY, OpCode.SWAP);
                script.EmitSysCall(ApplicationEngine.System_Runtime_Notify);

                // Add return

                script.EmitPush(true);
                script.Emit(OpCode.RET);

                // Mock contract

                scriptHash2 = script.ToArray().ToScriptHash();

                snapshot.DeleteContract(scriptHash2);
                snapshot.AddContract(scriptHash2, TestUtils.GetContract(script.ToArray(), TestUtils.CreateManifest("test", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer)));
            }

            // Wrong length

            using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot))
                using (var script = new ScriptBuilder())
                {
                    // Retrive

                    script.EmitPush(1);
                    script.EmitSysCall(ApplicationEngine.System_Runtime_GetNotifications);

                    // Execute

                    engine.LoadScript(script.ToArray());

                    Assert.AreEqual(VMState.FAULT, engine.Execute());
                }

            // All test

            using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot))
                using (var script = new ScriptBuilder())
                {
                    // Notification

                    script.EmitPush(0);
                    script.Emit(OpCode.NEWARRAY);
                    script.EmitPush("testEvent1");
                    script.EmitSysCall(ApplicationEngine.System_Runtime_Notify);

                    // Call script

                    script.EmitDynamicCall(scriptHash2, "test", "testEvent2", 1);

                    // Drop return

                    script.Emit(OpCode.DROP);

                    // Receive all notifications

                    script.Emit(OpCode.PUSHNULL);
                    script.EmitSysCall(ApplicationEngine.System_Runtime_GetNotifications);

                    // Execute

                    engine.LoadScript(script.ToArray());
                    engine.CurrentContext.GetState <ExecutionContextState>().Contract = new();
                    var currentScriptHash = engine.EntryScriptHash;

                    Assert.AreEqual(VMState.HALT, engine.Execute());
                    Assert.AreEqual(1, engine.ResultStack.Count);
                    Assert.AreEqual(2, engine.Notifications.Count);

                    Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Array));

                    var array = (VM.Types.Array)engine.ResultStack.Pop();

                    // Check syscall result

                    AssertNotification(array[1], scriptHash2, "testEvent2");
                    AssertNotification(array[0], currentScriptHash, "testEvent1");

                    // Check notifications

                    Assert.AreEqual(scriptHash2, engine.Notifications[1].ScriptHash);
                    Assert.AreEqual("testEvent2", engine.Notifications[1].EventName);

                    Assert.AreEqual(currentScriptHash, engine.Notifications[0].ScriptHash);
                    Assert.AreEqual("testEvent1", engine.Notifications[0].EventName);
                }

            // Script notifications

            using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot))
                using (var script = new ScriptBuilder())
                {
                    // Notification

                    script.EmitPush(0);
                    script.Emit(OpCode.NEWARRAY);
                    script.EmitPush("testEvent1");
                    script.EmitSysCall(ApplicationEngine.System_Runtime_Notify);

                    // Call script

                    script.EmitDynamicCall(scriptHash2, "test", "testEvent2", 1);

                    // Drop return

                    script.Emit(OpCode.DROP);

                    // Receive all notifications

                    script.EmitPush(scriptHash2.ToArray());
                    script.EmitSysCall(ApplicationEngine.System_Runtime_GetNotifications);

                    // Execute

                    engine.LoadScript(script.ToArray());
                    engine.CurrentContext.GetState <ExecutionContextState>().Contract = new();
                    var currentScriptHash = engine.EntryScriptHash;

                    Assert.AreEqual(VMState.HALT, engine.Execute());
                    Assert.AreEqual(1, engine.ResultStack.Count);
                    Assert.AreEqual(2, engine.Notifications.Count);

                    Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Array));

                    var array = (VM.Types.Array)engine.ResultStack.Pop();

                    // Check syscall result

                    AssertNotification(array[0], scriptHash2, "testEvent2");

                    // Check notifications

                    Assert.AreEqual(scriptHash2, engine.Notifications[1].ScriptHash);
                    Assert.AreEqual("testEvent2", engine.Notifications[1].EventName);

                    Assert.AreEqual(currentScriptHash, engine.Notifications[0].ScriptHash);
                    Assert.AreEqual("testEvent1", engine.Notifications[0].EventName);
                }

            // Clean storage

            snapshot.DeleteContract(scriptHash2);
        }
예제 #10
0
 private StackItem GetFeePerByte(ApplicationEngine engine, VMArray args)
 {
     return(GetFeePerByte(engine.Snapshot));
 }
예제 #11
0
 private StackItem GetBlockedAccounts(ApplicationEngine engine, VMArray args)
 {
     return(GetBlockedAccounts(engine.Snapshot).Select(p => (StackItem)p.ToArray()).ToList());
 }
예제 #12
0
 private StackItem GetMaxTransactionsPerBlock(ApplicationEngine engine, VMArray args)
 {
     return(GetMaxTransactionsPerBlock(engine.Snapshot));
 }
예제 #13
0
파일: GasToken.cs 프로젝트: superboyiii/neo
 internal override ContractTask Initialize(ApplicationEngine engine)
 {
     UInt160 account = Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators);
     return Mint(engine, account, 30_000_000 * Factor, false);
 }
예제 #14
0
        public void System_Blockchain_GetBlock()
        {
            var tx = new Transaction()
            {
                Script          = new byte[] { 0x01 },
                Attributes      = Array.Empty <TransactionAttribute>(),
                NetworkFee      = 0x02,
                SystemFee       = 0x03,
                Nonce           = 0x04,
                ValidUntilBlock = 0x05,
                Version         = 0x06,
                Witnesses       = new Witness[] { new Witness()
                                                  {
                                                      VerificationScript = new byte[] { 0x07 }
                                                  } },
                Sender = UInt160.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
            };

            var block = new Block()
            {
                Index     = 0,
                Timestamp = 2,
                Version   = 3,
                Witness   = new Witness()
                {
                    InvocationScript   = new byte[0],
                    VerificationScript = new byte[0]
                },
                PrevHash      = UInt256.Zero,
                MerkleRoot    = UInt256.Zero,
                NextConsensus = UInt160.Zero,
                ConsensusData = new ConsensusData()
                {
                    Nonce = 1, PrimaryIndex = 1
                },
                Transactions = new Transaction[] { tx }
            };

            var snapshot = Blockchain.Singleton.GetSnapshot();

            using (var script = new ScriptBuilder())
            {
                script.EmitPush(block.Hash.ToArray());
                script.EmitSysCall(ApplicationEngine.System_Blockchain_GetBlock);

                // Without block

                var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);
                engine.LoadScript(script.ToArray());

                Assert.AreEqual(engine.Execute(), VMState.HALT);
                Assert.AreEqual(1, engine.ResultStack.Count);
                Assert.IsTrue(engine.ResultStack.Peek().IsNull);

                // Not traceable block

                var height = snapshot.BlockHashIndex.GetAndChange();
                height.Index = block.Index + Transaction.MaxValidUntilBlockIncrement;

                var blocks = snapshot.Blocks;
                var txs    = snapshot.Transactions;
                blocks.Add(block.Hash, block.Trim());
                txs.Add(tx.Hash, new TransactionState()
                {
                    Transaction = tx, BlockIndex = block.Index, VMState = VMState.HALT
                });

                engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);
                engine.LoadScript(script.ToArray());

                Assert.AreEqual(engine.Execute(), VMState.HALT);
                Assert.AreEqual(1, engine.ResultStack.Count);
                Assert.IsTrue(engine.ResultStack.Peek().IsNull);

                // With block

                height.Index = block.Index;

                script.EmitSysCall(ApplicationEngine.System_Json_Serialize);
                engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);
                engine.LoadScript(script.ToArray());

                Assert.AreEqual(engine.Execute(), VMState.HALT);
                Assert.AreEqual(1, engine.ResultStack.Count);
                Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(ByteString));
                Assert.AreEqual(engine.ResultStack.Pop().GetSpan().ToHexString(),
                                "5b2261564e62466b35384f51717547373870747154766561762f48677941566a72634e41434d4e59705c7530303242366f6f3d222c332c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c322c302c224141414141414141414141414141414141414141414141414141413d222c315d");
                Assert.AreEqual(0, engine.ResultStack.Count);

                // Clean

                blocks.Delete(block.Hash);
                txs.Delete(tx.Hash);
            }
        }
예제 #15
0
        private void Persist(Block block)
        {
            using (SnapshotCache snapshot = system.GetSnapshot())
            {
                List <ApplicationExecuted> all_application_executed = new List <ApplicationExecuted>();
                using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot, block))
                {
                    engine.LoadScript(onPersistScript);
                    if (engine.Execute() != VMState.HALT)
                    {
                        throw new InvalidOperationException();
                    }
                    ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                    Context.System.EventStream.Publish(application_executed);
                    all_application_executed.Add(application_executed);
                }
                DataCache clonedSnapshot = snapshot.CreateSnapshot();
                // Warning: Do not write into variable snapshot directly. Write into variable clonedSnapshot and commit instead.
                foreach (Transaction tx in block.Transactions)
                {
                    using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, tx, clonedSnapshot, block, tx.SystemFee))
                    {
                        engine.LoadScript(tx.Script);
                        if (engine.Execute() == VMState.HALT)
                        {
                            clonedSnapshot.Commit();
                        }
                        else
                        {
                            clonedSnapshot = snapshot.CreateSnapshot();
                        }
                        ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.PostPersist, null, snapshot, block))
                {
                    engine.LoadScript(postPersistScript);
                    if (engine.Execute() != VMState.HALT)
                    {
                        throw new InvalidOperationException();
                    }
                    ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                    Context.System.EventStream.Publish(application_executed);
                    all_application_executed.Add(application_executed);
                }
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    plugin.OnPersist(block, snapshot, all_application_executed);
                }
                snapshot.Commit();
                List <Exception> commitExceptions = null;
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    try
                    {
                        plugin.OnCommit(block, snapshot);
                    }
                    catch (Exception ex)
                    {
                        if (plugin.ShouldThrowExceptionFromCommit(ex))
                        {
                            if (commitExceptions == null)
                            {
                                commitExceptions = new List <Exception>();
                            }

                            commitExceptions.Add(ex);
                        }
                    }
                }
                if (commitExceptions != null)
                {
                    throw new AggregateException(commitExceptions);
                }
                system.MemPool.UpdatePoolForBlockPersisted(block, snapshot);
            }
            extensibleWitnessWhiteList = null;
            block_cache.Remove(block.PrevHash);
            Context.System.EventStream.Publish(new PersistCompleted {
                Block = block
            });
            if (system.HeaderCache.TryRemoveFirst(out Header header))
            {
                Debug.Assert(header.Index == block.Index);
            }
        }
예제 #16
0
 public override bool Match(ApplicationEngine engine)
 {
     return(Expressions.Any(p => p.Match(engine)));
 }
예제 #17
0
 public new StackItem TotalSupply(ApplicationEngine engine, VM.Types.Array args)
 {
     return(base.TotalSupply(engine, args));
 }
예제 #18
0
        private void Persist(Block block)
        {
            WriteBatch batch = new WriteBatch();
            DbCache <UInt160, AccountState>        accounts         = new DbCache <UInt160, AccountState>(db, DataEntryPrefix.ST_Account, batch);
            DbCache <UInt256, UnspentCoinState>    unspentcoins     = new DbCache <UInt256, UnspentCoinState>(db, DataEntryPrefix.ST_Coin, batch);
            DbCache <UInt256, SpentCoinState>      spentcoins       = new DbCache <UInt256, SpentCoinState>(db, DataEntryPrefix.ST_SpentCoin, batch);
            DbCache <ECPoint, ValidatorState>      validators       = new DbCache <ECPoint, ValidatorState>(db, DataEntryPrefix.ST_Validator, batch);
            DbCache <UInt256, AssetState>          assets           = new DbCache <UInt256, AssetState>(db, DataEntryPrefix.ST_Asset, batch);
            DbCache <UInt160, ContractState>       contracts        = new DbCache <UInt160, ContractState>(db, DataEntryPrefix.ST_Contract, batch);
            DbCache <StorageKey, StorageItem>      storages         = new DbCache <StorageKey, StorageItem>(db, DataEntryPrefix.ST_Storage, batch);
            DbMetaDataCache <ValidatorsCountState> validators_count = new DbMetaDataCache <ValidatorsCountState>(db, DataEntryPrefix.IX_ValidatorsCount);
            long amount_sysfee = GetSysFeeAmount(block.PrevHash) + (long)block.Transactions.Sum(p => p.SystemFee);

            batch.Put(SliceBuilder.Begin(DataEntryPrefix.DATA_Block).Add(block.Hash), SliceBuilder.Begin().Add(amount_sysfee).Add(block.Trim()));
            foreach (Transaction tx in block.Transactions)
            {
                batch.Put(SliceBuilder.Begin(DataEntryPrefix.DATA_Transaction).Add(tx.Hash), SliceBuilder.Begin().Add(block.Index).Add(tx.ToArray()));
                unspentcoins.Add(tx.Hash, new UnspentCoinState
                {
                    Items = Enumerable.Repeat(CoinState.Confirmed, tx.Outputs.Length).ToArray()
                });
                foreach (TransactionOutput output in tx.Outputs)
                {
                    AccountState account = accounts.GetAndChange(output.ScriptHash, () => new AccountState(output.ScriptHash));
                    if (account.Balances.ContainsKey(output.AssetId))
                    {
                        account.Balances[output.AssetId] += output.Value;
                    }
                    else
                    {
                        account.Balances[output.AssetId] = output.Value;
                    }
                    if (output.AssetId.Equals(GoverningToken.Hash) && account.Votes.Length > 0)
                    {
                        foreach (ECPoint pubkey in account.Votes)
                        {
                            validators.GetAndChange(pubkey, () => new ValidatorState(pubkey)).Votes += output.Value;
                        }
                        validators_count.GetAndChange().Votes[account.Votes.Length - 1] += output.Value;
                    }
                }
                foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash))
                {
                    Transaction tx_prev = GetTransaction(ReadOptions.Default, group.Key, out int height);
                    foreach (CoinReference input in group)
                    {
                        unspentcoins.GetAndChange(input.PrevHash).Items[input.PrevIndex] |= CoinState.Spent;
                        TransactionOutput out_prev = tx_prev.Outputs[input.PrevIndex];
                        AccountState      account  = accounts.GetAndChange(out_prev.ScriptHash);
                        if (out_prev.AssetId.Equals(GoverningToken.Hash))
                        {
                            spentcoins.GetAndChange(input.PrevHash, () => new SpentCoinState
                            {
                                TransactionHash   = input.PrevHash,
                                TransactionHeight = (uint)height,
                                Items             = new Dictionary <ushort, uint>()
                            }).Items.Add(input.PrevIndex, block.Index);
                            if (account.Votes.Length > 0)
                            {
                                foreach (ECPoint pubkey in account.Votes)
                                {
                                    ValidatorState validator = validators.GetAndChange(pubkey);
                                    validator.Votes -= out_prev.Value;
                                    if (!validator.Registered && validator.Votes.Equals(Fixed8.Zero))
                                    {
                                        validators.Delete(pubkey);
                                    }
                                }
                                validators_count.GetAndChange().Votes[account.Votes.Length - 1] -= out_prev.Value;
                            }
                        }
                        account.Balances[out_prev.AssetId] -= out_prev.Value;
                    }
                }
                switch (tx)
                {
#pragma warning disable CS0612
                case RegisterTransaction tx_register:
                    assets.Add(tx.Hash, new AssetState
                    {
                        AssetId    = tx_register.Hash,
                        AssetType  = tx_register.AssetType,
                        Name       = tx_register.Name,
                        Amount     = tx_register.Amount,
                        Available  = Fixed8.Zero,
                        Precision  = tx_register.Precision,
                        Fee        = Fixed8.Zero,
                        FeeAddress = new UInt160(),
                        Owner      = tx_register.Owner,
                        Admin      = tx_register.Admin,
                        Issuer     = tx_register.Admin,
                        Expiration = block.Index + 2 * 2000000,
                        IsFrozen   = false
                    });
                    break;

#pragma warning restore CS0612
                case IssueTransaction _:
                    foreach (TransactionResult result in tx.GetTransactionResults().Where(p => p.Amount < Fixed8.Zero))
                    {
                        assets.GetAndChange(result.AssetId).Available -= result.Amount;
                    }
                    break;

                case ClaimTransaction _:
                    foreach (CoinReference input in ((ClaimTransaction)tx).Claims)
                    {
                        if (spentcoins.TryGet(input.PrevHash)?.Items.Remove(input.PrevIndex) == true)
                        {
                            spentcoins.GetAndChange(input.PrevHash);
                        }
                    }
                    break;

#pragma warning disable CS0612
                case EnrollmentTransaction tx_enrollment:
                    validators.GetAndChange(tx_enrollment.PublicKey, () => new ValidatorState(tx_enrollment.PublicKey)).Registered = true;
                    break;

#pragma warning restore CS0612
                case StateTransaction tx_state:
                    foreach (StateDescriptor descriptor in tx_state.Descriptors)
                    {
                        switch (descriptor.Type)
                        {
                        case StateType.Account:
                            ProcessAccountStateDescriptor(descriptor, accounts, validators, validators_count);
                            break;

                        case StateType.Validator:
                            ProcessValidatorStateDescriptor(descriptor, validators);
                            break;
                        }
                    }
                    break;

#pragma warning disable CS0612
                case PublishTransaction tx_publish:
                    contracts.GetOrAdd(tx_publish.ScriptHash, () => new ContractState
                    {
                        Script             = tx_publish.Script,
                        ParameterList      = tx_publish.ParameterList,
                        ReturnType         = tx_publish.ReturnType,
                        ContractProperties = (ContractPropertyState)Convert.ToByte(tx_publish.NeedStorage),
                        Name        = tx_publish.Name,
                        CodeVersion = tx_publish.CodeVersion,
                        Author      = tx_publish.Author,
                        Email       = tx_publish.Email,
                        Description = tx_publish.Description
                    });
                    break;

#pragma warning restore CS0612
                case InvocationTransaction tx_invocation:
                    CachedScriptTable script_table = new CachedScriptTable(contracts);
                    using (StateMachine service = new StateMachine(block, accounts, assets, contracts, storages))
                    {
                        ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx_invocation, script_table, service, tx_invocation.Gas);
                        engine.LoadScript(tx_invocation.Script, false);
                        if (engine.Execute())
                        {
                            service.Commit();
                        }
                        ApplicationExecuted?.Invoke(this, new ApplicationExecutedEventArgs(tx_invocation, service.Notifications.ToArray(), engine));
                    }
                    break;
                }
            }
            accounts.DeleteWhere((k, v) => !v.IsFrozen && v.Votes.Length == 0 && v.Balances.All(p => p.Value <= Fixed8.Zero));
            accounts.Commit();
            unspentcoins.DeleteWhere((k, v) => v.Items.All(p => p.HasFlag(CoinState.Spent)));
            unspentcoins.Commit();
            spentcoins.DeleteWhere((k, v) => v.Items.Count == 0);
            spentcoins.Commit();
            validators.Commit();
            assets.Commit();
            contracts.Commit();
            storages.Commit();
            validators_count.Commit(batch);
            batch.Put(SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentBlock), SliceBuilder.Begin().Add(block.Hash).Add(block.Index));
            db.Write(WriteOptions.Default, batch);
            current_block_height = block.Index;
        }
예제 #19
0
 public StackItem TestOnPersist(ApplicationEngine engine, VMArray args)
 {
     return(OnPersist(engine, args));
 }
예제 #20
0
 protected virtual bool OnPersist(ApplicationEngine engine)
 {
     return(true);
 }
예제 #21
0
 private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest)
 {
     return(Update(engine, nefFile, manifest, StackItem.Null));
 }
예제 #22
0
 protected StackItem SupportedStandardsMethod(ApplicationEngine engine, VMArray args)
 {
     return(SupportedStandards.Select(p => (StackItem)p).ToList());
 }
예제 #23
0
 public async Task Run()
 {
     _logger.LogInfo <KeepAliveTask>(null, "Starting a keep alive request");
     await _requestProvider.GetStringAsync(ApplicationEngine.RouteUrl(RouteNames.KeepAlive, null, true));
 }
예제 #24
0
 protected void SetBreadcrumbToRoute(string displayText, string routeName, object routeParams = null, string description = null, bool localize = true)
 {
     SetBreadcrumbToUrl(displayText, ApplicationEngine.RouteUrl(routeName, routeParams, true), description, localize);
 }
예제 #25
0
        public void System_Blockchain_GetBlock()
        {
            var tx = new Transaction()
            {
                Script          = new byte[] { 0x01 },
                Attributes      = new TransactionAttribute[0],
                Cosigners       = new Cosigner[0],
                NetworkFee      = 0x02,
                SystemFee       = 0x03,
                Nonce           = 0x04,
                ValidUntilBlock = 0x05,
                Version         = 0x06,
                Witnesses       = new Witness[] { new Witness()
                                                  {
                                                      VerificationScript = new byte[] { 0x07 }
                                                  } },
                Sender = UInt160.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
            };

            var block = new Block()
            {
                Index     = 1,
                Timestamp = 2,
                Version   = 3,
                Witness   = new Witness()
                {
                    InvocationScript   = new byte[0],
                    VerificationScript = new byte[0]
                },
                PrevHash      = UInt256.Zero,
                MerkleRoot    = UInt256.Zero,
                NextConsensus = UInt160.Zero,
                ConsensusData = new ConsensusData()
                {
                    Nonce = 1, PrimaryIndex = 1
                },
                Transactions = new Transaction[] { tx }
            };

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

            using (var script = new ScriptBuilder())
            {
                script.EmitPush(block.Hash.ToArray());
                script.EmitSysCall(InteropService.System_Blockchain_GetBlock);

                // Without block

                var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);
                engine.LoadScript(script.ToArray());

                Assert.AreEqual(engine.Execute(), VMState.HALT);
                Assert.AreEqual(1, engine.ResultStack.Count);
                Assert.IsTrue(engine.ResultStack.Peek().IsNull);

                // With block

                var blocks = (TestDataCache <UInt256, TrimmedBlock>)snapshot.Blocks;
                var txs    = (TestDataCache <UInt256, TransactionState>)snapshot.Transactions;
                blocks.Add(block.Hash, block.Trim());
                txs.Add(tx.Hash, new TransactionState()
                {
                    Transaction = tx, BlockIndex = block.Index, VMState = VMState.HALT
                });

                script.EmitSysCall(InteropService.Neo_Json_Serialize);
                engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);
                engine.LoadScript(script.ToArray());

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

                // Clean
                blocks.Delete(block.Hash);
                txs.Delete(tx.Hash);
            }
        }
예제 #26
0
        public void MemorySearch()
        {
            var snapshot = TestBlockchain.GetTestSnapshot();

            using (var script = new ScriptBuilder())
            {
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 0);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 1);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 2);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 3);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "d", 0);

                using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheVauthSystem.Settings);
                engine.LoadScript(script.ToArray());

                Assert.AreEqual(engine.Execute(), VMState.HALT);
                Assert.AreEqual(5, engine.ResultStack.Count);

                Assert.AreEqual(-1, engine.ResultStack.Pop <Integer>().GetInteger());
                Assert.AreEqual(-1, engine.ResultStack.Pop <Integer>().GetInteger());
                Assert.AreEqual(2, engine.ResultStack.Pop <Integer>().GetInteger());
                Assert.AreEqual(2, engine.ResultStack.Pop <Integer>().GetInteger());
            }

            using (var script = new ScriptBuilder())
            {
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 0, false);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 1, false);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 2, false);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 3, false);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "d", 0, false);

                using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheVauthSystem.Settings);
                engine.LoadScript(script.ToArray());

                Assert.AreEqual(engine.Execute(), VMState.HALT);
                Assert.AreEqual(5, engine.ResultStack.Count);

                Assert.AreEqual(-1, engine.ResultStack.Pop <Integer>().GetInteger());
                Assert.AreEqual(-1, engine.ResultStack.Pop <Integer>().GetInteger());
                Assert.AreEqual(2, engine.ResultStack.Pop <Integer>().GetInteger());
                Assert.AreEqual(2, engine.ResultStack.Pop <Integer>().GetInteger());
            }

            using (var script = new ScriptBuilder())
            {
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 0, true);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 1, true);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 2, true);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 3, true);
                script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "d", 0, true);

                using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheVauthSystem.Settings);
                engine.LoadScript(script.ToArray());

                Assert.AreEqual(engine.Execute(), VMState.HALT);
                Assert.AreEqual(5, engine.ResultStack.Count);

                Assert.AreEqual(-1, engine.ResultStack.Pop <Integer>().GetInteger());
                Assert.AreEqual(2, engine.ResultStack.Pop <Integer>().GetInteger());
                Assert.AreEqual(-1, engine.ResultStack.Pop <Integer>().GetInteger());
                Assert.AreEqual(-1, engine.ResultStack.Pop <Integer>().GetInteger());
            }
        }
예제 #27
0
파일: Wallet.cs 프로젝트: RALEx147/NEOSx
        public Transaction MakeTransaction(List <TransactionAttribute> attributes, IEnumerable <TransferOutput> outputs, UInt160 from = null, UInt160 change_address = null, Fixed8 fee = default(Fixed8))
        {
            var cOutputs = outputs.Where(p => !p.IsGlobalAsset).GroupBy(p => new
            {
                AssetId = (UInt160)p.AssetId,
                Account = p.ScriptHash
            }, (k, g) => new
            {
                k.AssetId,
                Value = g.Aggregate(BigInteger.Zero, (x, y) => x + y.Value.Value),
                k.Account
            }).ToArray();
            Transaction tx;

            if (attributes == null)
            {
                attributes = new List <TransactionAttribute>();
            }
            if (cOutputs.Length == 0)
            {
                tx = new ContractTransaction();
            }
            else
            {
                UInt160[]         accounts    = from == null?GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray() : new[] { from };
                HashSet <UInt160> sAttributes = new HashSet <UInt160>();
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    foreach (var output in cOutputs)
                    {
                        byte[] script;
                        using (ScriptBuilder sb2 = new ScriptBuilder())
                        {
                            foreach (UInt160 account in accounts)
                            {
                                sb2.EmitAppCall(output.AssetId, "balanceOf", account);
                            }
                            sb2.Emit(OpCode.DEPTH, OpCode.PACK);
                            script = sb2.ToArray();
                        }
                        ApplicationEngine engine = ApplicationEngine.Run(script);
                        if (engine.State.HasFlag(VMState.FAULT))
                        {
                            return(null);
                        }
                        var balances = ((IEnumerable <StackItem>)(VMArray) engine.EvaluationStack.Pop()).Reverse().Zip(accounts, (i, a) => new
                        {
                            Account = a,
                            Value   = i.GetBigInteger()
                        }).ToArray();
                        BigInteger sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value);
                        if (sum < output.Value)
                        {
                            return(null);
                        }
                        if (sum != output.Value)
                        {
                            balances = balances.OrderByDescending(p => p.Value).ToArray();
                            BigInteger amount = output.Value;
                            int        i      = 0;
                            while (balances[i].Value <= amount)
                            {
                                amount -= balances[i++].Value;
                            }
                            if (amount == BigInteger.Zero)
                            {
                                balances = balances.Take(i).ToArray();
                            }
                            else
                            {
                                balances = balances.Take(i).Concat(new[] { balances.Last(p => p.Value >= amount) }).ToArray();
                            }
                            sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value);
                        }
                        sAttributes.UnionWith(balances.Select(p => p.Account));
                        for (int i = 0; i < balances.Length; i++)
                        {
                            BigInteger value = balances[i].Value;
                            if (i == 0)
                            {
                                BigInteger change = sum - output.Value;
                                if (change > 0)
                                {
                                    value -= change;
                                }
                            }
                            sb.EmitAppCall(output.AssetId, "transfer", balances[i].Account, output.Account, value);
                            sb.Emit(OpCode.THROWIFNOT);
                        }
                    }
                    byte[] nonce = new byte[8];
                    rand.NextBytes(nonce);
                    sb.Emit(OpCode.RET, nonce);
                    tx = new InvocationTransaction
                    {
                        Version = 1,
                        Script  = sb.ToArray()
                    };
                }
                attributes.AddRange(sAttributes.Select(p => new TransactionAttribute
                {
                    Usage = TransactionAttributeUsage.Script,
                    Data  = p.ToArray()
                }));
            }
            tx.Attributes = attributes.ToArray();
            tx.Inputs     = new CoinReference[0];
            tx.Outputs    = outputs.Where(p => p.IsGlobalAsset).Select(p => p.ToTxOutput()).ToArray();
            tx.Scripts    = new Witness[0];
            if (tx is InvocationTransaction itx)
            {
                ApplicationEngine engine = ApplicationEngine.Run(itx.Script, itx);
                if (engine.State.HasFlag(VMState.FAULT))
                {
                    return(null);
                }
                tx = new InvocationTransaction
                {
                    Version    = itx.Version,
                    Script     = itx.Script,
                    Gas        = InvocationTransaction.GetGas(engine.GasConsumed),
                    Attributes = itx.Attributes,
                    Inputs     = itx.Inputs,
                    Outputs    = itx.Outputs
                };
            }
            tx = MakeTransaction(tx, from, change_address, fee);
            return(tx);
        }
예제 #28
0
        public void Runtime_GetNotifications_Test()
        {
            UInt160 scriptHash2;
            var     snapshot = TestBlockchain.GetStore().GetSnapshot();

            using (var script = new ScriptBuilder())
            {
                // Drop arguments

                script.Emit(VM.OpCode.TOALTSTACK);
                script.Emit(VM.OpCode.DROP);
                script.Emit(VM.OpCode.FROMALTSTACK);

                // Notify method

                script.EmitSysCall(InteropService.System_Runtime_Notify);

                // Add return

                script.EmitPush(true);

                // Mock contract

                scriptHash2 = script.ToArray().ToScriptHash();

                snapshot.Contracts.Delete(scriptHash2);
                snapshot.Contracts.Add(scriptHash2, new Neo.Ledger.ContractState()
                {
                    Script   = script.ToArray(),
                    Manifest = ContractManifest.CreateDefault(scriptHash2),
                });
            }

            // Wrong length

            using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true))
                using (var script = new ScriptBuilder())
                {
                    // Retrive

                    script.EmitPush(1);
                    script.EmitSysCall(InteropService.System_Runtime_GetNotifications);

                    // Execute

                    engine.LoadScript(script.ToArray());

                    Assert.AreEqual(VMState.FAULT, engine.Execute());
                }

            // All test

            using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true))
                using (var script = new ScriptBuilder())
                {
                    // Notification 1 -> 13

                    script.EmitPush(13);
                    script.EmitSysCall(InteropService.System_Runtime_Notify);

                    // Call script

                    script.EmitAppCall(scriptHash2, "test");

                    // Drop return

                    script.Emit(OpCode.DROP);

                    // Receive all notifications

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

                    // Execute

                    engine.LoadScript(script.ToArray());
                    var currentScriptHash = engine.EntryScriptHash;

                    Assert.AreEqual(VMState.HALT, engine.Execute());
                    Assert.AreEqual(1, engine.ResultStack.Count);
                    Assert.AreEqual(2, engine.Notifications.Count);

                    Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Array));

                    var array = (VM.Types.Array)engine.ResultStack.Pop();

                    // Check syscall result

                    AssertNotification(array[1], scriptHash2, "test");
                    AssertNotification(array[0], currentScriptHash, 13);

                    // Check notifications

                    Assert.AreEqual(scriptHash2, engine.Notifications[1].ScriptHash);
                    Assert.AreEqual("test", engine.Notifications[1].State.GetString());

                    Assert.AreEqual(currentScriptHash, engine.Notifications[0].ScriptHash);
                    Assert.AreEqual(13, engine.Notifications[0].State.GetBigInteger());
                }

            // Script notifications

            using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true))
                using (var script = new ScriptBuilder())
                {
                    // Notification 1 -> 13

                    script.EmitPush(13);
                    script.EmitSysCall(InteropService.System_Runtime_Notify);

                    // Call script

                    script.EmitAppCall(scriptHash2, "test");

                    // Drop return

                    script.Emit(OpCode.DROP);

                    // Receive all notifications

                    script.EmitPush(scriptHash2.ToArray());
                    script.EmitSysCall(InteropService.System_Runtime_GetNotifications);

                    // Execute

                    engine.LoadScript(script.ToArray());
                    var currentScriptHash = engine.EntryScriptHash;

                    Assert.AreEqual(VMState.HALT, engine.Execute());
                    Assert.AreEqual(1, engine.ResultStack.Count);
                    Assert.AreEqual(2, engine.Notifications.Count);

                    Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Array));

                    var array = (VM.Types.Array)engine.ResultStack.Pop();

                    // Check syscall result

                    AssertNotification(array[0], scriptHash2, "test");

                    // Check notifications

                    Assert.AreEqual(scriptHash2, engine.Notifications[1].ScriptHash);
                    Assert.AreEqual("test", engine.Notifications[1].State.GetString());

                    Assert.AreEqual(currentScriptHash, engine.Notifications[0].ScriptHash);
                    Assert.AreEqual(13, engine.Notifications[0].State.GetBigInteger());
                }

            // Clean storage

            snapshot.Contracts.Delete(scriptHash2);
        }
예제 #29
0
        protected virtual bool Transfer(ApplicationEngine engine, UInt160 from, UInt160 to, BigInteger amount)
        {
            if (engine.Service.Trigger != TriggerType.Application)
            {
                throw new InvalidOperationException();
            }
            if (amount.Sign < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(amount));
            }
            if (!from.Equals(new UInt160(engine.CurrentContext.CallingScriptHash)) && !engine.Service.CheckWitness(engine, from))
            {
                return(false);
            }
            ContractState contract_to = engine.Service.Snapshot.Contracts.TryGet(to);

            if (contract_to?.Payable == false)
            {
                return(false);
            }
            StorageKey  key_from     = CreateAccountKey(from);
            StorageItem storage_from = engine.Service.Snapshot.Storages.TryGet(key_from);

            if (amount.IsZero)
            {
                if (storage_from != null)
                {
                    TState state_from = new TState();
                    state_from.FromByteArray(storage_from.Value);
                    OnBalanceChanging(engine, from, state_from, amount);
                }
            }
            else
            {
                if (storage_from is null)
                {
                    return(false);
                }
                TState state_from = new TState();
                state_from.FromByteArray(storage_from.Value);
                if (state_from.Balance < amount)
                {
                    return(false);
                }
                if (from.Equals(to))
                {
                    OnBalanceChanging(engine, from, state_from, BigInteger.Zero);
                }
                else
                {
                    OnBalanceChanging(engine, from, state_from, -amount);
                    if (state_from.Balance == amount)
                    {
                        engine.Service.Snapshot.Storages.Delete(key_from);
                    }
                    else
                    {
                        state_from.Balance -= amount;
                        storage_from        = engine.Service.Snapshot.Storages.GetAndChange(key_from);
                        storage_from.Value  = state_from.ToByteArray();
                    }
                    StorageKey  key_to     = CreateAccountKey(to);
                    StorageItem storage_to = engine.Service.Snapshot.Storages.GetAndChange(key_to, () => new StorageItem
                    {
                        Value = new TState().ToByteArray()
                    });
                    TState state_to = new TState();
                    state_to.FromByteArray(storage_to.Value);
                    OnBalanceChanging(engine, to, state_to, amount);
                    state_to.Balance += amount;
                    storage_to.Value  = state_to.ToByteArray();
                }
            }
            engine.Service.SendNotification(engine, ScriptHash, new StackItem[] { "Transfer", from.ToArray(), to.ToArray(), amount });
            return(true);
        }
예제 #30
0
        public Transaction GetTransaction()
        {
            var cOutputs = txOutListBox1.Items.Where(p => p.AssetId is UInt160).GroupBy(p => new
            {
                AssetId = (UInt160)p.AssetId,
                Account = p.ScriptHash
            }, (k, g) => new
            {
                k.AssetId,
                Value = g.Aggregate(BigInteger.Zero, (x, y) => x + y.Value.Value),
                k.Account
            }).ToArray();
            Transaction tx;
            List <TransactionAttribute> attributes = new List <TransactionAttribute>();

            if (comboBoxFrom.SelectedItem == null)
            {
                FromAddress = null;
            }
            else
            {
                FromAddress = ((string)comboBoxFrom.SelectedItem).ToScriptHash();
            }

            if (cOutputs.Length == 0)
            {
                tx = new ContractTransaction();
            }
            else
            {
                var       addyFrom  = comboBoxFrom.SelectedItem.ToString();
                UInt160[] addresses =
                    !string.IsNullOrEmpty(addyFrom)? new UInt160[] { addyFrom.ToScriptHash() } :
                Program.CurrentWallet.GetAccounts().Select(p => p.ScriptHash).ToArray();
                HashSet <UInt160> sAttributes = new HashSet <UInt160>();
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    foreach (var output in cOutputs)
                    {
                        byte[] script;
                        using (ScriptBuilder sb2 = new ScriptBuilder())
                        {
                            foreach (UInt160 address in addresses)
                            {
                                sb2.EmitAppCall(output.AssetId, "balanceOf", address);
                            }

                            sb2.Emit(OpCode.DEPTH, OpCode.PACK);
                            script = sb2.ToArray();
                        }
                        using (ApplicationEngine engine = ApplicationEngine.Run(script))
                        {
                            if (engine.State.HasFlag(VMState.FAULT))
                            {
                                return(null);
                            }
                            var balances = ((VMArray)engine.ResultStack.Pop()).AsEnumerable().Reverse().Zip(addresses, (i, a) => new
                            {
                                Account = a,
                                Value   = i.GetBigInteger()
                            }).Where(p => p.Value != 0).ToArray();

                            BigInteger sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value);
                            if (sum < output.Value)
                            {
                                return(null);
                            }
                            if (sum != output.Value)
                            {
                                balances = balances.OrderByDescending(p => p.Value).ToArray();
                                BigInteger amount = output.Value;
                                int        i      = 0;
                                while (balances[i].Value <= amount)
                                {
                                    amount -= balances[i++].Value;
                                }
                                if (amount == BigInteger.Zero)
                                {
                                    balances = balances.Take(i).ToArray();
                                }
                                else
                                {
                                    balances = balances.Take(i).Concat(new[] { balances.Last(p => p.Value >= amount) }).ToArray();
                                }
                                sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value);
                            }
                            sAttributes.UnionWith(balances.Select(p => p.Account));
                            for (int i = 0; i < balances.Length; i++)
                            {
                                BigInteger value = balances[i].Value;
                                if (i == 0)
                                {
                                    BigInteger change = sum - output.Value;
                                    if (change > 0)
                                    {
                                        value -= change;
                                    }
                                }
                                sb.EmitAppCall(output.AssetId, "transfer", balances[i].Account, output.Account, value);
                                sb.Emit(OpCode.THROWIFNOT);
                            }
                        }
                    }
                    tx = new InvocationTransaction
                    {
                        Version = 1,
                        Script  = sb.ToArray()
                    };
                }
                attributes.AddRange(sAttributes.Select(p => new TransactionAttribute
                {
                    Usage = TransactionAttributeUsage.Script,
                    Data  = p.ToArray()
                }));
            }
            if (!string.IsNullOrEmpty(remark))
            {
                attributes.Add(new TransactionAttribute
                {
                    Usage = TransactionAttributeUsage.Remark,
                    Data  = Encoding.UTF8.GetBytes(remark)
                });
            }
            tx.Attributes = attributes.ToArray();
            tx.Outputs    = txOutListBox1.Items.Where(p => p.AssetId is UInt256).Select(p => p.ToTxOutput()).ToArray();
            var tempOuts = tx.Outputs;

            if (tx is ContractTransaction copyTx)
            {
                copyTx.Witnesses = new Witness[0];
                copyTx           = Program.CurrentWallet.MakeTransaction(copyTx, FromAddress, change_address: ChangeAddress, fee: Fee);
                if (copyTx == null)
                {
                    return(null);
                }
                ContractParametersContext transContext = new ContractParametersContext(copyTx);
                Program.CurrentWallet.Sign(transContext);
                if (transContext.Completed)
                {
                    copyTx.Witnesses = transContext.GetWitnesses();
                }
                if (copyTx.Size > 1024)
                {
                    Fixed8 PriorityFee = Fixed8.FromDecimal(0.001m) + Fixed8.FromDecimal(copyTx.Size * 0.00001m);
                    if (Fee > PriorityFee)
                    {
                        PriorityFee = Fee;
                    }
                    if (!Helper.CostRemind(Fixed8.Zero, PriorityFee))
                    {
                        return(null);
                    }
                    tx = Program.CurrentWallet.MakeTransaction(new ContractTransaction
                    {
                        Outputs    = tempOuts,
                        Attributes = tx.Attributes
                    }, FromAddress, change_address: ChangeAddress, fee: PriorityFee);
                }
            }
            return(tx);
        }