예제 #1
0
 public OnlineNode(ProtocolSettings settings, ExpressChain chain, ExpressConsensusNode node)
 {
     this.ProtocolSettings = settings;
     this.chain            = chain;
     rpcClient             = new RpcClient(new Uri($"http://localhost:{node.RpcPort}"), protocolSettings: settings);
     consensusNodesKeys    = new Lazy <KeyPair[]>(() => chain.GetConsensusNodeKeys());
 }
예제 #2
0
        public static void Preload(uint preloadGasAmount, Store store, ExpressConsensusNode node, TextWriter writer, CancellationToken cancellationToken)
        {
            Debug.Assert(preloadGasAmount > 0);

            var wallet = DevWallet.FromExpressWallet(node.Wallet);

            using var system = new NeoSystem(store);

            var generationAmount = Blockchain.GenerationAmount[0];
            var gas          = preloadGasAmount / generationAmount;
            var preloadCount = preloadGasAmount % generationAmount == 0 ? gas : gas + 1;

            writer.WriteLine($"Creating {preloadCount} empty blocks to preload {preloadGasAmount} GAS");
            Random random = new Random();

            for (int i = 1; i <= preloadCount; i++)
            {
                if (i % 100 == 0)
                {
                    writer.WriteLine($"  Creating Block {i}");
                }
                var block       = CreatePreloadBlock(wallet, random);
                var relayResult = system.Blockchain.Ask <RelayResultReason>(block).Result;

                if (relayResult != RelayResultReason.Succeed)
                {
                    throw new Exception($"Preload block {i} failed {relayResult}");
                }
            }

            ClaimPreloadGas(system, wallet, random);

            writer.WriteLine($"Preload complete. {preloadCount * generationAmount} GAS loaded into genesis account.");
        }
예제 #3
0
        public static string GetMultiSigAddress(this ExpressConsensusNode node)
        {
            var account = DevWalletAccount.FromExpressWalletAccount(node.Wallet.Accounts
                                                                    .Single(a => Neo.SmartContract.Helper.IsMultiSigContract(a.Contract.Script.ToByteArray())));

            return(account.Address);
        }
            static RpcServerSettings GetRpcServerSettings(ExpressChain chain, ExpressConsensusNode node)
            {
                var ipAddress = chain.TryReadSetting <IPAddress>("rpc.BindAddress", IPAddress.TryParse, out var bindAddress)
                    ? bindAddress : IPAddress.Loopback;

                var settings = new Dictionary <string, string>()
                {
                    { "PluginConfiguration:Network", $"{chain.Network}" },
                    { "PluginConfiguration:BindAddress", $"{ipAddress}" },
                    { "PluginConfiguration:Port", $"{node.RpcPort}" }
                };

                if (chain.TryReadSetting <decimal>("rpc.MaxGasInvoke", decimal.TryParse, out var maxGasInvoke))
                {
                    settings.Add("PluginConfiguration:MaxGasInvoke", $"{maxGasInvoke}");
                }

                if (chain.TryReadSetting <decimal>("rpc.MaxFee", decimal.TryParse, out var maxFee))
                {
                    settings.Add("PluginConfiguration:MaxFee", $"{maxFee}");
                }

                if (chain.TryReadSetting <int>("rpc.MaxIteratorResultItems", int.TryParse, out var maxIteratorResultItems) &&
                    maxIteratorResultItems > 0)
                {
                    settings.Add("PluginConfiguration:MaxIteratorResultItems", $"{maxIteratorResultItems}");
                }

                var config = new ConfigurationBuilder().AddInMemoryCollection(settings).Build();

                return(RpcServerSettings.Load(config.GetSection("PluginConfiguration")));
            }
        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);
        static bool IsNodeRunning(ExpressConsensusNode node)
        {
            // Check to see if there's a neo-express blockchain currently running by
            // attempting to open a mutex with the multisig account address for a name

            var account = node.Wallet.Accounts.Single(a => a.IsDefault);

            return(Mutex.TryOpenExisting(GLOBAL_PREFIX + account.ScriptHash, out var _));
        }
예제 #7
0
        public async Task RunAsync(IExpressStore store, ExpressConsensusNode node, uint secondsPerBlock, bool enableTrace, TextWriter writer, CancellationToken token)
        {
            if (IsRunning(node))
            {
                throw new Exception("Node already running");
            }

            chain.InitalizeProtocolSettings(secondsPerBlock);

            await writer.WriteLineAsync(store.GetType().Name).ConfigureAwait(false);

            var tcs = new TaskCompletionSource <bool>();

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

                    var wallet          = DevWallet.FromExpressWallet(node.Wallet);
                    var multiSigAccount = node.Wallet.Accounts.Single(a => a.IsMultiSigContract());

                    var dbftPlugin        = new Neo.Consensus.DBFTPlugin();
                    var logPlugin         = new Node.LogPlugin(writer);
                    var storageProvider   = new Node.ExpressStorageProvider((IStore)store);
                    var appEngineProvider = enableTrace ? new Node.ExpressApplicationEngineProvider() : null;
                    var appLogsPlugin     = new Node.ExpressAppLogsPlugin(store);

                    using var system     = new Neo.NeoSystem(storageProvider.Name);
                    var rpcSettings      = new Neo.Plugins.RpcServerSettings(port: node.RpcPort);
                    var rpcServer        = new Neo.Plugins.RpcServer(system, rpcSettings);
                    var expressRpcServer = new ExpressRpcServer(store, multiSigAccount);
                    rpcServer.RegisterMethods(expressRpcServer);
                    rpcServer.RegisterMethods(appLogsPlugin);
                    rpcServer.StartRpcServer();

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

                    token.WaitHandle.WaitOne();
                }
                catch (Exception ex)
                {
                    tcs.SetException(ex);
                }
                finally
                {
                    tcs.TrySetResult(true);
                }
            });
            await tcs.Task.ConfigureAwait(false);
        }
예제 #8
0
        public static string GetBlockchainPath(this ExpressConsensusNode node)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            return(node.Wallet.GetBlockchainPath());
        }
            static bool NodeRunning(ExpressConsensusNode node)
            {
                // Check to see if there's a neo-express blockchain currently running
                // by attempting to open a mutex with the multisig account address for
                // a name. If so, do an online checkpoint instead of offline.

                if (Mutex.TryOpenExisting(node.GetMultiSigAddress(), out var _))
                {
                    return(true);
                }

                return(false);
            }
예제 #10
0
        public async Task <bool> StopNodeAsync(ExpressConsensusNode node)
        {
            if (!IsNodeRunning(node))
            {
                return(false);
            }

            var rpcClient = new Neo.Network.RPC.RpcClient(new Uri($"http://localhost:{node.RpcPort}"), protocolSettings: ProtocolSettings);
            var json      = await rpcClient.RpcSendAsync("expressshutdown").ConfigureAwait(false);

            var processId = int.Parse(json["process-id"].AsString());
            var process   = System.Diagnostics.Process.GetProcessById(processId);
            await process.WaitForExitAsync().ConfigureAwait(false);

            return(true);
        }
예제 #11
0
        public static Task RunAsync(Store store, ExpressConsensusNode node, TextWriter writer, CancellationToken cancellationToken)
        {
            var tcs = new TaskCompletionSource <bool>();

            Task.Run(() =>
            {
                try
                {
                    var wallet = DevWallet.FromExpressWallet(node.Wallet);
                    using (var system = new NeoSystem(store))
                    {
                        var logPlugin = new LogPlugin(writer);
                        var rpcPlugin = new ExpressNodeRpcPlugin(store);

                        system.StartNode(node.TcpPort, node.WebSocketPort);

                        system.StartConsensus(wallet);
                        system.StartRpc(IPAddress.Loopback, node.RpcPort, wallet);

                        {
                            using var snapshot = Blockchain.Singleton.GetSnapshot();
                            var validators     = snapshot.GetValidators();

                            ;
                        }

                        cancellationToken.WaitHandle.WaitOne();
                    }
                }
                catch (Exception ex)
                {
                    tcs.SetException(ex);
                }
                finally
                {
                    if (store is IDisposable disposable)
                    {
                        disposable.Dispose();
                    }
                    tcs.TrySetResult(true);
                }
            });

            return(tcs.Task);
        }
예제 #12
0
        public static string GetNodePath(this IFileSystem fileSystem, ExpressConsensusNode node)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }
            if (node.Wallet == null)
            {
                throw new ArgumentNullException(nameof(node.Wallet));
            }
            var account = node.Wallet.Accounts.Single(a => a.IsDefault);

            var rootPath = fileSystem.Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.DoNotVerify),
                "Neo-Express",
                "blockchain-nodes");

            return(fileSystem.Path.Combine(rootPath, account.ScriptHash));
        }
예제 #13
0
        public void ResetNode(ExpressConsensusNode node, bool force)
        {
            if (IsNodeRunning(node))
            {
                var scriptHash = node.Wallet.DefaultAccount?.ScriptHash ?? "<unknown>";
                throw new InvalidOperationException($"node {scriptHash} currently running");
            }

            var nodePath = fileSystem.GetNodePath(node);

            if (fileSystem.Directory.Exists(nodePath))
            {
                if (!force)
                {
                    throw new InvalidOperationException("--force must be specified when resetting a node");
                }

                fileSystem.Directory.Delete(nodePath, true);
            }
        }
예제 #14
0
        public IExpressStore GetNodeStore(ExpressConsensusNode node, bool discard)
        {
            var folder = fileSystem.GetNodePath(node);

            if (discard)
            {
                try
                {
                    var rocksDbStore = RocksDbStore.OpenReadOnly(folder);
                    return(new CheckpointStore(rocksDbStore));
                }
                catch
                {
                    return(new CheckpointStore(NullReadOnlyStore.Instance));
                }
            }
            else
            {
                return(RocksDbStore.Open(folder));
            }
        }
예제 #15
0
            static RpcServerSettings GetRpcServerSettings(ExpressChain chain, ExpressConsensusNode node)
            {
                var settings = new Dictionary <string, string>()
                {
                    { "PluginConfiguration:Network", $"{chain.Network}" },
                    { "PluginConfiguration:BindAddress", $"{IPAddress.Loopback}" },
                    { "PluginConfiguration:Port", $"{node.RpcPort}" }
                };

                if (chain.TryReadSetting <long>("rpc.MaxGasInvoke", long.TryParse, out var maxGasInvoke))
                {
                    settings.Add("PluginConfiguration:MaxGasInvoke", $"{maxGasInvoke}");
                }

                if (chain.TryReadSetting <long>("rpc.MaxFee", long.TryParse, out var maxFee))
                {
                    settings.Add("PluginConfiguration:MaxFee", $"{maxFee}");
                }

                var config = new ConfigurationBuilder().AddInMemoryCollection(settings).Build();

                return(RpcServerSettings.Load(config.GetSection("PluginConfiguration")));
            }
예제 #16
0
 public static Uri GetUri(this ExpressConsensusNode node)
 => new Uri($"http://localhost:{node.RpcPort}");
예제 #17
0
 public OnlineNode(ProtocolSettings settings, ExpressChain chain, ExpressConsensusNode node)
 {
     this.ProtocolSettings = settings;
     this.chain            = chain;
     rpcClient             = new RpcClient(new Uri($"http://localhost:{node.RpcPort}"), protocolSettings: settings);
 }
예제 #18
0
 public OnlineNode(ExpressChain chain, ExpressConsensusNode node)
 {
     this.chain = chain;
     rpcClient  = new RpcClient(node.GetUri());
 }