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")));
            }
Example #2
0
        public static void SignOracleResponseTransaction(ProtocolSettings settings, ExpressChain chain, Transaction tx, IReadOnlyList <ECPoint> oracleNodes)
        {
            var signatures = new Dictionary <ECPoint, byte[]>();

            for (int i = 0; i < chain.ConsensusNodes.Count; i++)
            {
                var account = chain.ConsensusNodes[i].Wallet.DefaultAccount ?? throw new Exception("Invalid DefaultAccount");
                var key     = DevWalletAccount.FromExpressWalletAccount(settings, account).GetKey() ?? throw new Exception("Invalid KeyPair");
                if (oracleNodes.Contains(key.PublicKey))
                {
                    signatures.Add(key.PublicKey, tx.Sign(key, chain.Network));
                }
            }

            int m = oracleNodes.Count - (oracleNodes.Count - 1) / 3;

            if (signatures.Count < m)
            {
                throw new Exception("Insufficient oracle response signatures");
            }

            var contract = Contract.CreateMultiSigContract(m, oracleNodes);
            var sb       = new ScriptBuilder();

            foreach (var kvp in signatures.OrderBy(p => p.Key).Take(m))
            {
                sb.EmitPush(kvp.Value);
            }
            var index = tx.GetScriptHashesForVerifying(null)[0] == contract.ScriptHash ? 0 : 1;

            tx.Witnesses[index].InvocationScript = sb.ToArray();
        }
Example #3
0
        public static string ResolvePassword(this ExpressChain chain, string name, string password)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentException($"{nameof(name)} parameter can't be null or empty", nameof(name));
            }

            // if the user specified a password, use it
            if (!string.IsNullOrEmpty(password))
            {
                return(password);
            }

            // if the name is a valid Neo Express account name, no password is needed
            if (chain.IsReservedName(name))
            {
                return(password);
            }
            if (chain.Wallets.Any(w => name.Equals(w.Name, StringComparison.OrdinalIgnoreCase)))
            {
                return(password);
            }

            // if a password is needed but not provided, prompt the user
            return(McMaster.Extensions.CommandLineUtils.Prompt.GetPassword($"enter password for {name}"));
        }
Example #4
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());
 }
Example #5
0
        public static ExpressWalletAccount?GetAccount(this ExpressChain chain, string name)
        {
            if (chain.Wallets != null)
            {
                var wallet = chain.Wallets.SingleOrDefault(w => w.NameEquals(name));
                if (wallet != null)
                {
                    return(wallet.DefaultAccount);
                }
            }

            var node = chain.ConsensusNodes.SingleOrDefault(n => n.Wallet.NameEquals(name));

            if (node != null)
            {
                return(node.Wallet.DefaultAccount);
            }

            if ("genesis".Equals(name, StringComparison.InvariantCultureIgnoreCase))
            {
                return(chain.ConsensusNodes
                       .Select(n => n.Wallet.Accounts.Single(a => a.Label == "MultiSigContract"))
                       .FirstOrDefault());
            }

            return(null);
        }
Example #6
0
 public static IEnumerable <DevWalletAccount> GetMultiSigAccounts(this ExpressChain chain, ExpressWalletAccount account)
 => chain.ConsensusNodes
 .Select(n => n.Wallet)
 .Concat(chain.Wallets)
 .Select(w => w.Accounts.Find(a => a.ScriptHash == account.ScriptHash))
 .Where(a => a != null)
 .Select(DevWalletAccount.FromExpressWalletAccount !);
Example #7
0
        public static (Wallet wallet, UInt160 accountHash) GetGenesisAccount(this ExpressChain chain, ProtocolSettings settings)
        {
            Debug.Assert(chain.ConsensusNodes != null && chain.ConsensusNodes.Count > 0);

            var wallet  = DevWallet.FromExpressWallet(settings, chain.ConsensusNodes[0].Wallet);
            var account = wallet.GetMultiSigAccounts().Single();

            return(wallet, account.ScriptHash);
        }
        public static ExpressChain CreateBlockchain(int count)
        {
            var wallets = new List <(DevWallet wallet, Neo.Wallets.WalletAccount account)>(count);

            ushort GetPortNumber(int index, ushort portNumber) => (ushort)((49000 + (index * 1000)) + portNumber);

            try
            {
                for (var i = 1; i <= count; i++)
                {
                    var wallet  = new DevWallet($"node{i}");
                    var account = wallet.CreateAccount();
                    account.IsDefault = true;
                    wallets.Add((wallet, account));
                }

                var keys = wallets.Select(t => t.account.GetKey().PublicKey).ToArray();

                var contract = Neo.SmartContract.Contract.CreateMultiSigContract((keys.Length * 2 / 3) + 1, keys);

                foreach (var(wallet, account) in wallets)
                {
                    var multiSigContractAccount = wallet.CreateAccount(contract, account.GetKey());
                    multiSigContractAccount.Label = "MultiSigContract";
                }

                // 49152 is the first port in the "Dynamic and/or Private" range as specified by IANA
                // http://www.iana.org/assignments/port-numbers
                var nodes = new List <ExpressConsensusNode>(count);
                for (var i = 0; i < count; i++)
                {
                    nodes.Add(new ExpressConsensusNode()
                    {
                        TcpPort       = GetPortNumber(i, 333),
                        WebSocketPort = GetPortNumber(i, 334),
                        RpcPort       = GetPortNumber(i, 332),
                        Wallet        = wallets[i].wallet.ToExpressWallet()
                    });
                }

                return(new ExpressChain()
                {
                    Magic = ExpressChain.GenerateMagicValue(),
                    ConsensusNodes = nodes,
                });
            }
            finally
            {
                foreach (var(wallet, _) in wallets)
                {
                    wallet.Dispose();
                }
            }
        }
            static Neo.Consensus.Settings GetConsensusSettings(ExpressChain chain)
            {
                var settings = new Dictionary <string, string>()
                {
                    { "PluginConfiguration:Network", $"{chain.Network}" }
                };

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

                return(new Neo.Consensus.Settings(config.GetSection("PluginConfiguration")));
            }
Example #10
0
        public static void SaveChain(this IFileSystem fileSystem, ExpressChain chain, string path)
        {
            var serializer = new JsonSerializer();

            using var stream       = fileSystem.File.Open(path, System.IO.FileMode.Create, System.IO.FileAccess.Write);
            using var streamWriter = new System.IO.StreamWriter(stream);
            using var writer       = new JsonTextWriter(streamWriter)
                  {
                      Formatting = Formatting.Indented
                  };
            serializer.Serialize(writer, chain);
        }
Example #11
0
        public OfflineNode(IExpressStore store, Wallet nodeWallet, ExpressChain chain, bool enableTrace)
        {
            this.nodeWallet           = nodeWallet;
            this.chain                = chain;
            this.store                = store;
            applicationEngineProvider = enableTrace ? new ExpressApplicationEngineProvider() : null;
            storageProvider           = new ExpressStorageProvider((IStore)store);
            _         = new ExpressAppLogsPlugin(store);
            neoSystem = new NeoSystem(storageProvider.Name);

            ApplicationEngine.Log += OnLog !;
        }
Example #12
0
        public static bool TryReadSetting <T>(this ExpressChain chain, string setting, TryParse <T> tryParse, [MaybeNullWhen(false)] out T value)
        {
            if (chain.Settings.TryGetValue(setting, out var stringValue) &&
                tryParse(stringValue, out var result))
            {
                value = result;
                return(true);
            }

            value = default;
            return(false);
        }
Example #13
0
        public static void Save(this ExpressChain chain, string fileName)
        {
            var serializer = new JsonSerializer();

            using (var stream = File.Open(fileName, FileMode.Create, FileAccess.Write))
                using (var writer = new JsonTextWriter(new StreamWriter(stream))
                {
                    Formatting = Formatting.Indented
                })
                {
                    serializer.Serialize(writer, chain);
                }
        }
        public void empty_settings_save_correctly()
        {
            var fileSystem = new MockFileSystem();
            var fileName   = fileSystem.Path.Combine(fileSystem.AllDirectories.First(), FILENAME);
            var chain      = new ExpressChain();

            fileSystem.SaveChain(chain, fileName);

            using var json = JsonDocument.Parse(fileSystem.GetFile(fileName).Contents);
            var settings = json.RootElement.GetProperty("settings");

            settings.EnumerateObject().Should().BeEmpty();
        }
        public ExpressChainManager(IFileSystem fileSystem, ExpressChain chain, uint?secondsPerBlock = null)
        {
            this.fileSystem = fileSystem;
            this.chain      = chain;

            uint secondsPerBlockResult = secondsPerBlock.HasValue
                ? secondsPerBlock.Value
                : chain.TryReadSetting <uint>("chain.SecondsPerBlock", uint.TryParse, out var secondsPerBlockSetting)
                    ? secondsPerBlockSetting
                    : 0;

            this.ProtocolSettings = chain.GetProtocolSettings(secondsPerBlockResult);
        }
Example #16
0
 public static bool TryParseScriptHash(this ExpressChain chain, string name, [MaybeNullWhen(false)] out UInt160 hash)
 {
     try
     {
         hash = name.ToScriptHash(chain.AddressVersion);
         return(true);
     }
     catch
     {
         hash = null;
         return(false);
     }
 }
Example #17
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 !;
        }
Example #18
0
        internal static ExpressChain CreateChain(int nodeCount)
        {
            if (nodeCount != 1 && nodeCount != 4 && nodeCount != 7)
            {
                throw new ArgumentException("invalid blockchain node count", nameof(nodeCount));
            }

            var wallets = new List <(DevWallet wallet, Neo.Wallets.WalletAccount account)>(nodeCount);

            for (var i = 1; i <= nodeCount; i++)
            {
                var wallet  = new DevWallet($"node{i}");
                var account = wallet.CreateAccount();
                account.IsDefault = true;
                wallets.Add((wallet, account));
            }

            var keys = wallets.Select(t => t.account.GetKey().PublicKey).ToArray();

            var contract = Neo.SmartContract.Contract.CreateMultiSigContract((keys.Length * 2 / 3) + 1, keys);

            foreach (var(wallet, account) in wallets)
            {
                var multiSigContractAccount = wallet.CreateAccount(contract, account.GetKey());
                multiSigContractAccount.Label = "MultiSigContract";
            }

            // 49152 is the first port in the "Dynamic and/or Private" range as specified by IANA
            // http://www.iana.org/assignments/port-numbers
            var nodes = new List <ExpressConsensusNode>(nodeCount);

            for (var i = 0; i < nodeCount; i++)
            {
                nodes.Add(new ExpressConsensusNode()
                {
                    TcpPort       = GetPortNumber(i, 3),
                    WebSocketPort = GetPortNumber(i, 4),
                    RpcPort       = GetPortNumber(i, 2),
                    Wallet        = wallets[i].wallet.ToExpressWallet()
                });
            }

            return(new ExpressChain()
            {
                Magic = ExpressChain.GenerateMagicValue(),
                ConsensusNodes = nodes,
            });
Example #19
0
        public static bool IsReservedName(this ExpressChain chain, string name)
        {
            if ("genesis".Equals(name, StringComparison.InvariantCultureIgnoreCase))
            {
                return(true);
            }

            foreach (var node in chain.ConsensusNodes)
            {
                if (string.Equals(name, node.Wallet.Name, StringComparison.InvariantCultureIgnoreCase))
                {
                    return(true);
                }
            }

            return(false);
        }
Example #20
0
        public static bool IsReservedName(this ExpressChain chain, string name)
        {
            if (string.Equals(GENESIS, name, StringComparison.OrdinalIgnoreCase))
            {
                return(true);
            }

            for (int i = 0; i < chain.ConsensusNodes.Count; i++)
            {
                if (string.Equals(chain.ConsensusNodes[i].Wallet.Name, name, StringComparison.OrdinalIgnoreCase))
                {
                    return(true);
                }
            }

            return(false);
        }
Example #21
0
        internal static ExpressChain CreateChain(int nodeCount, byte?addressVersion)
        {
            if (nodeCount != 1 && nodeCount != 4 && nodeCount != 7)
            {
                throw new ArgumentException("invalid blockchain node count", nameof(nodeCount));
            }

            var settings = ProtocolSettings.Default with
            {
                Network        = ExpressChain.GenerateNetworkValue(),
                AddressVersion = addressVersion ?? ProtocolSettings.Default.AddressVersion
            };

            var wallets = new List <(DevWallet wallet, WalletAccount account)>(nodeCount);

            for (var i = 1; i <= nodeCount; i++)
            {
                var wallet  = new DevWallet(settings, $"node{i}");
                var account = wallet.CreateAccount();
                account.IsDefault = true;
                wallets.Add((wallet, account));
            }

            var keys     = wallets.Select(t => t.account.GetKey().PublicKey).ToArray();
            var contract = Contract.CreateMultiSigContract((keys.Length * 2 / 3) + 1, keys);

            foreach (var(wallet, account) in wallets)
            {
                var multiSigContractAccount = wallet.CreateAccount(contract, account.GetKey());
                multiSigContractAccount.Label = "Consensus MultiSigContract";
            }

            var nodes = wallets.Select((w, i) => new ExpressConsensusNode
            {
                TcpPort       = GetPortNumber(i, 3),
                WebSocketPort = GetPortNumber(i, 4),
                RpcPort       = GetPortNumber(i, 2),
                Wallet        = w.wallet.ToExpressWallet()
            });

            return(new ExpressChain()
            {
                Network = settings.Network,
                AddressVersion = settings.AddressVersion,
                ConsensusNodes = nodes.ToList(),
            });
        public static bool TryGetAccountHash(this ExpressChain chain, string name, [MaybeNullWhen(false)] out UInt160 accountHash, ProtocolSettings?settings = null)
        {
            settings ??= chain.GetProtocolSettings();

            if (chain.Wallets != null && chain.Wallets.Count > 0)
            {
                for (int i = 0; i < chain.Wallets.Count; i++)
                {
                    if (string.Equals(name, chain.Wallets[i].Name, StringComparison.OrdinalIgnoreCase))
                    {
                        var wallet  = DevWallet.FromExpressWallet(settings, chain.Wallets[i]);
                        var account = wallet.GetAccounts().Single(a => a.IsDefault);
                        accountHash = account.ScriptHash;
                        return(true);
                    }
                }
            }

            Debug.Assert(chain.ConsensusNodes != null && chain.ConsensusNodes.Count > 0);

            for (int i = 0; i < chain.ConsensusNodes.Count; i++)
            {
                var nodeWallet = chain.ConsensusNodes[i].Wallet;
                if (string.Equals(name, nodeWallet.Name, StringComparison.OrdinalIgnoreCase))
                {
                    var wallet  = DevWallet.FromExpressWallet(settings, nodeWallet);
                    var account = wallet.GetAccounts().Single(a => a.IsDefault);
                    accountHash = account.ScriptHash;
                    return(true);
                }
            }

            if (GENESIS.Equals(name, StringComparison.OrdinalIgnoreCase))
            {
                (_, accountHash) = chain.GetGenesisAccount(settings);
                return(true);
            }

            if (TryToScriptHash(name, settings.AddressVersion, out accountHash))
            {
                return(true);
            }

            accountHash = default;
            return(false);
Example #23
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 ExpressApplicationEngineProvider() : null;
            consensusNodesKeys          = new Lazy <KeyPair[]>(() => chain.ConsensusNodes
                                                               .Select(n => n.Wallet.DefaultAccount ?? throw new Exception())
                                                               .Select(a => new KeyPair(a.PrivateKey.HexToBytes()))
                                                               .ToArray());

            var storageProviderPlugin = new StorageProviderPlugin(rocksDbStorageProvider);

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

            ApplicationEngine.Log += OnLog !;
        }
Example #24
0
        public static bool TryFindChain(this IFileSystem fileSystem, [MaybeNullWhen(false)] out ExpressChain chain, string fileName = Constants.DEFAULT_EXPRESS_FILENAME, string?searchFolder = null)
        {
            searchFolder ??= fileSystem.Directory.GetCurrentDirectory();
            while (searchFolder != null)
            {
                var filePath = fileSystem.Path.Combine(searchFolder, fileName);
                if (fileSystem.File.Exists(filePath))
                {
                    chain = fileSystem.LoadChain(filePath);
                    return(true);
                }

                searchFolder = fileSystem.Path.GetDirectoryName(searchFolder);
            }

            chain = null;
            return(false);
        }
Example #25
0
        public static bool TryGetAccountHash(this ExpressChain chain, string name, [MaybeNullWhen(false)] out UInt160 accountHash)
        {
            if (chain.Wallets != null && chain.Wallets.Count > 0)
            {
                for (int i = 0; i < chain.Wallets.Count; i++)
                {
                    if (string.Equals(name, chain.Wallets[i].Name, StringComparison.OrdinalIgnoreCase))
                    {
                        accountHash = chain.Wallets[i].DefaultAccount.GetScriptHash();
                        return(true);
                    }
                }
            }

            Debug.Assert(chain.ConsensusNodes != null && chain.ConsensusNodes.Count > 0);

            for (int i = 0; i < chain.ConsensusNodes.Count; i++)
            {
                var nodeWallet = chain.ConsensusNodes[i].Wallet;
                if (string.Equals(name, nodeWallet.Name, StringComparison.OrdinalIgnoreCase))
                {
                    accountHash = nodeWallet.DefaultAccount.GetScriptHash();
                    return(true);
                }
            }

            if (GENESIS.Equals(name, StringComparison.OrdinalIgnoreCase))
            {
                var keys = chain.ConsensusNodes
                           .Select(n => n.Wallet.DefaultAccount ?? throw new Exception())
                           .Select(a => new KeyPair(a.PrivateKey.HexToBytes()).PublicKey)
                           .ToArray();
                var contract = Neo.SmartContract.Contract.CreateMultiSigContract((keys.Length * 2 / 3) + 1, keys);
                accountHash = contract.ScriptHash;
                return(true);
            }

            return(chain.TryParseScriptHash(name, out accountHash));
        }
Example #26
0
        public static TransactionManager AddSignatures(this TransactionManager tm, ExpressChain chain, ExpressWalletAccount account)
        {
            if (account.IsMultiSigContract())
            {
                var signers = chain.GetMultiSigAccounts(account);

                var publicKeys = signers.Select(s => s.GetKey() !.PublicKey).ToArray();
                var sigCount   = account.Contract.Parameters.Count;

                foreach (var signer in signers.Take(sigCount))
                {
                    var keyPair = signer.GetKey() ?? throw new Exception();
                    tm = tm.AddMultiSig(keyPair, sigCount, publicKeys);
                }

                return(tm);
            }
            else
            {
                return(tm.AddSignature(account.GetKey() !));
            }
        }
Example #27
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")));
            }
Example #28
0
        public static bool InitializeProtocolSettings(this ExpressChain chain, uint secondsPerBlock = 0)
        {
            secondsPerBlock = secondsPerBlock == 0 ? 15 : secondsPerBlock;

            IEnumerable <KeyValuePair <string, string> > settings()
            {
                yield return(new KeyValuePair <string, string>(
                                 "ProtocolConfiguration:Magic", $"{chain.Magic}"));

                yield return(new KeyValuePair <string, string>(
                                 "ProtocolConfiguration:AddressVersion", $"{ExpressChain.AddressVersion}"));

                yield return(new KeyValuePair <string, string>(
                                 "ProtocolConfiguration:SecondsPerBlock", $"{secondsPerBlock}"));

                foreach (var(node, index) in chain.ConsensusNodes.Select((n, i) => (n, i)))
                {
                    var privateKey = node.Wallet.Accounts
                                     .Select(a => a.PrivateKey)
                                     .Distinct().Single().HexToBytes();
                    var encodedPublicKey = new KeyPair(privateKey).PublicKey
                                           .EncodePoint(true).ToHexString();
                    yield return(new KeyValuePair <string, string>(
                                     $"ProtocolConfiguration:StandbyValidators:{index}", encodedPublicKey));

                    yield return(new KeyValuePair <string, string>(
                                     $"ProtocolConfiguration:SeedList:{index}", $"{IPAddress.Loopback}:{node.TcpPort}"));
                }
            }

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

            return(ProtocolSettings.Initialize(config));
        }
Example #29
0
        // this method only used in Online/OfflineNode ExecuteAsync
        public static IReadOnlyList <Wallet> GetMultiSigWallets(this ExpressChain chain, ProtocolSettings settings, UInt160 accountHash)
        {
            var builder = ImmutableList.CreateBuilder <Wallet>();

            for (int i = 0; i < chain.ConsensusNodes.Count; i++)
            {
                var wallet = DevWallet.FromExpressWallet(settings, chain.ConsensusNodes[i].Wallet);
                if (wallet.GetAccount(accountHash) != null)
                {
                    builder.Add(wallet);
                }
            }

            for (int i = 0; i < chain.Wallets.Count; i++)
            {
                var wallet = DevWallet.FromExpressWallet(settings, chain.Wallets[i]);
                if (wallet.GetAccount(accountHash) != null)
                {
                    builder.Add(wallet);
                }
            }

            return(builder.ToImmutable());
        }
Example #30
0
        public static Witness GetWitness(Transaction tx, ExpressChain chain, ExpressWalletAccount account)
        {
            var txHashData = Neo.Network.P2P.Helper.GetHashData(tx);
            var devAccount = DevWalletAccount.FromExpressWalletAccount(account);

            if (IsMultiSigContract(account))
            {
                // neo-express only uses multi sig contracts for consensus nodes
                var verification   = devAccount.Contract.Script;
                var signatureCount = devAccount.Contract.ParameterList.Length;

                var signatures = chain.ConsensusNodes
                                 .Select(node => DevWalletAccount.FromExpressWalletAccount(node.Wallet.DefaultAccount))
                                 .OrderBy(account => (account.GetKey() ?? throw new Exception("DevWalletAccount missing key")).PublicKey)
                                 .Select(account => Sign(txHashData, account))
                                 .Take(signatureCount)
                                 .ToList();

                var invocation = new byte[signatures.Aggregate(0, (a, sig) => a + sig.Length + 1)];

                var curPos = 0;
                for (int i = 0; i < signatures.Count; i++)
                {
                    invocation[curPos] = 0x40;
                    signatures[i].AsSpan().CopyTo(invocation.AsSpan().Slice(curPos + 1, signatures[i].Length));
                    curPos += 1 + signatures[i].Length;
                }

                return(new Witness()
                {
                    InvocationScript = invocation,
                    VerificationScript = verification,
                });
            }
            else
            {