public async Task RunAsync(IStorageProvider store, ExpressConsensusNode node, bool enableTrace, TextWriter writer, CancellationToken token)
        {
            if (IsNodeRunning(node))
            {
                throw new Exception("Node already running");
            }

            var tcs = new TaskCompletionSource <bool>();

            _ = Task.Run(() =>
            {
                try
                {
                    var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(token);

                    var defaultAccount = node.Wallet.Accounts.Single(a => a.IsDefault);
                    using var mutex    = new Mutex(true, GLOBAL_PREFIX + defaultAccount.ScriptHash);

                    var wallet          = DevWallet.FromExpressWallet(ProtocolSettings, node.Wallet);
                    var multiSigAccount = wallet.GetMultiSigAccounts().Single();

                    var logPlugin             = new Node.LogPlugin(writer);
                    var storageProviderPlugin = new Node.StorageProviderPlugin(store);
                    var appEngineProvider     = enableTrace ? new Node.ApplicationEngineProvider() : null;
                    var dbftPlugin            = new Neo.Consensus.DBFTPlugin(GetConsensusSettings(chain));
                    var persistencePlugin     = new Node.PersistencePlugin(store);

                    using var neoSystem = new Neo.NeoSystem(ProtocolSettings, storageProviderPlugin.Name);
                    _ = neoSystem.ActorSystem.ActorOf(EventWrapper <Blockchain.ApplicationExecuted> .Props(OnApplicationExecuted));
                    var rpcSettings       = GetRpcServerSettings(chain, node);
                    var rpcServer         = new Neo.Plugins.RpcServer(neoSystem, rpcSettings);
                    var expressRpcMethods = new ExpressRpcMethods(neoSystem, store, multiSigAccount.ScriptHash, linkedToken);
                    rpcServer.RegisterMethods(expressRpcMethods);
                    rpcServer.RegisterMethods(persistencePlugin);
                    rpcServer.StartRpcServer();

                    neoSystem.StartNode(new Neo.Network.P2P.ChannelsConfig
                    {
                        Tcp       = new IPEndPoint(IPAddress.Loopback, node.TcpPort),
                        WebSocket = new IPEndPoint(IPAddress.Loopback, node.WebSocketPort),
                    });
                    dbftPlugin.Start(wallet);

                    // DevTracker looks for a string that starts with "Neo express is running" to confirm that the instance has started
                    // Do not remove or re-word this console output:
                    writer.WriteLine($"Neo express is running ({store.GetType().Name})");

                    linkedToken.Token.WaitHandle.WaitOne();
                }
                catch (Exception ex)
                {
                    tcs.SetException(ex);
                }
                finally
                {
                    tcs.TrySetResult(true);
                }
            });
            await tcs.Task.ConfigureAwait(false);
예제 #2
0
        public JObject ExpressEnumNotifications(JArray @params)
        {
            var contracts = ((JArray)@params[0]).Select(j => UInt160.Parse(j.AsString())).ToHashSet();
            var events    = ((JArray)@params[1]).Select(j => j.AsString()).ToHashSet(StringComparer.OrdinalIgnoreCase);
            int skip      = @params.Count >= 3 ? (int)@params[2].AsNumber() : 0;
            int take      = @params.Count >= 4 ? (int)@params[3].AsNumber() : MAX_NOTIFICATIONS;

            if (take > MAX_NOTIFICATIONS)
            {
                take = MAX_NOTIFICATIONS;
            }

            var notifications = PersistencePlugin
                                .GetNotifications(
                storageProvider,
                SeekDirection.Backward,
                contracts.Count > 0 ? contracts : null,
                events.Count > 0 ? events : null)
                                .Skip(skip);

            var count             = 0;
            var jsonNotifications = new JArray();
            var truncated         = false;

            foreach (var(blockIndex, _, notification) in notifications)
            {
                if (count++ > take)
                {
                    truncated = true;
                    break;
                }

                var jNotification = new JObject
                {
                    ["block-index"]    = blockIndex,
                    ["script-hash"]    = notification.ScriptHash.ToString(),
                    ["event-name"]     = notification.EventName,
                    ["inventory-type"] = (byte)notification.InventoryType,
                    ["inventory-hash"] = notification.InventoryHash.ToString(),
                    ["state"]          = Neo.VM.Helper.ToJson(notification.State),
                };
                jsonNotifications.Add(jNotification);
            }

            return(new JObject
            {
                ["truncated"] = truncated,
                ["notifications"] = jsonNotifications,
            });
        }
예제 #3
0
        public OfflineNode(ProtocolSettings settings, RocksDbStorageProvider rocksDbStorageProvider, Wallet nodeWallet, ExpressChain chain, bool enableTrace)
        {
            this.nodeWallet             = nodeWallet;
            this.chain                  = chain;
            this.rocksDbStorageProvider = rocksDbStorageProvider;
            applicationEngineProvider   = enableTrace ? new ApplicationEngineProvider() : null;
            consensusNodesKeys          = new Lazy <KeyPair[]>(() => chain.GetConsensusNodeKeys());

            var storageProviderPlugin = new StorageProviderPlugin(rocksDbStorageProvider);

            _         = new PersistencePlugin(rocksDbStorageProvider);
            neoSystem = new NeoSystem(settings, storageProviderPlugin.Name);

            ApplicationEngine.Log += OnLog !;
        }
예제 #4
0
        public JObject GetNep17Balances(JArray @params)
        {
            var address = AsScriptHash(@params[0]);

            using var snapshot = neoSystem.GetSnapshot();

            // collect the non-zero balances of all the deployed Nep17 contracts for the specified account
            var addressBalances = TokenContract.Enumerate(snapshot)
                                  .Where(c => c.standard == TokenStandard.Nep17)
                                  .Select(c => (
                                              scriptHash: c.scriptHash,
                                              balance: snapshot.GetNep17Balance(c.scriptHash, address, neoSystem.Settings)))
                                  .Where(t => !t.balance.IsZero)
                                  .ToList();

            // collect the last block index a transfer occurred for all account balances
            var updateIndexes = new Dictionary <UInt160, uint>();

            if (addressBalances.Count > 0)
            {
                var notifications = PersistencePlugin.GetNotifications(
                    storageProvider,
                    SeekDirection.Backward,
                    addressBalances.Select(b => b.scriptHash).ToHashSet(),
                    TRANSFER);

                foreach (var(blockIndex, _, notification) in notifications)
                {
                    // iterate backwards thru the notifications looking for all the Transfer events from a contract
                    // in assets where a Transfer event hasn't already been recorded
                    if (!updateIndexes.ContainsKey(notification.ScriptHash))
                    {
                        var transfer = TransferNotificationRecord.Create(notification);
                        if (transfer is not null &&
                            (transfer.From == address || transfer.To == address))
                        {
                            // if the specified account was the sender or receiver of the current transfer,
                            // record the update index. Stop the iteration if indexes for all the assets are
                            // have been recorded
                            updateIndexes.Add(notification.ScriptHash, blockIndex);
                            if (updateIndexes.Count == addressBalances.Count)
                            {
                                break;
                            }
                        }
                    }
                }
            }

            var balances = new JArray();

            for (int i = 0; i < addressBalances.Count; i++)
            {
                var(scriptHash, balance) = addressBalances[i];
                var lastUpdatedBlock = updateIndexes.TryGetValue(scriptHash, out var _index) ? _index : 0;

                balances.Add(new JObject
                {
                    ["assethash"]        = scriptHash.ToString(),
                    ["amount"]           = balance.ToString(),
                    ["lastupdatedblock"] = lastUpdatedBlock,
                });
            }

            return(new JObject
            {
                ["address"] = address.ToAddress(neoSystem.Settings.AddressVersion),
                ["balance"] = balances,
            });
        }
예제 #5
0
        public JObject GetApplicationLog(JArray _params)
        {
            UInt256 hash = UInt256.Parse(_params[0].AsString());

            return(PersistencePlugin.GetAppLog(storageProvider, hash) ?? throw new RpcException(-100, "Unknown transaction"));
        }