Пример #1
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);
        }
Пример #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();
        }
Пример #3
0
        public Task <UInt256> ExecuteAsync(ExpressWalletAccount account, Neo.VM.Script script, decimal additionalGas = 0)
        {
            if (disposedValue)
            {
                throw new ObjectDisposedException(nameof(OfflineNode));
            }

            var devAccount = DevWalletAccount.FromExpressWalletAccount(account);
            var devWallet  = new DevWallet(string.Empty, devAccount);
            var signer     = new Signer()
            {
                Account = devAccount.ScriptHash, Scopes = WitnessScope.CalledByEntry
            };
            var tx = devWallet.MakeTransaction(script, devAccount.ScriptHash, new[] { signer });

            if (additionalGas > 0.0m)
            {
                tx.SystemFee += (long)additionalGas.ToBigInteger(NativeContract.GAS.Decimals);
            }
            var context = new ContractParametersContext(tx);

            if (devAccount.IsMultiSigContract())
            {
                var wallets = chain.GetMultiSigWallets(account);

                foreach (var wallet in wallets)
                {
                    if (context.Completed)
                    {
                        break;
                    }

                    wallet.Sign(context);
                }
            }
            else
            {
                devWallet.Sign(context);
            }

            if (!context.Completed)
            {
                throw new Exception();
            }

            tx.Witnesses = context.GetWitnesses();

            return(SubmitTransactionAsync(tx));
        }
        public static (byte[] signature, byte[] publicKey) Sign(ExpressWalletAccount account, byte[] data)
        {
            var devAccount = DevWalletAccount.FromExpressWalletAccount(account);

            var key = devAccount.GetKey();

            if (key == null)
            {
                throw new InvalidOperationException();
            }

            var publicKey = key.PublicKey.EncodePoint(false).AsSpan().Slice(1).ToArray();
            var signature = Neo.Cryptography.Crypto.Default.Sign(data, key.PrivateKey, publicKey);

            return(signature, key.PublicKey.EncodePoint(true));
        }
Пример #5
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
            {
        public static void ExportBlockchain(ExpressChain chain, string folder, string password, Action <string> writeConsole)
        {
            void WriteNodeConfigJson(ExpressConsensusNode _node, string walletPath)
            {
                using (var stream = File.Open(Path.Combine(folder, $"{_node.Wallet.Name}.config.json"), FileMode.Create, FileAccess.Write))
                    using (var writer = new JsonTextWriter(new StreamWriter(stream))
                    {
                        Formatting = Formatting.Indented
                    })
                    {
                        writer.WriteStartObject();
                        writer.WritePropertyName("ApplicationConfiguration");
                        writer.WriteStartObject();

                        writer.WritePropertyName("Paths");
                        writer.WriteStartObject();
                        writer.WritePropertyName("Chain");
                        writer.WriteValue("Chain_{0}");
                        writer.WritePropertyName("Index");
                        writer.WriteValue("Index_{0}");
                        writer.WriteEndObject();

                        writer.WritePropertyName("P2P");
                        writer.WriteStartObject();
                        writer.WritePropertyName("Port");
                        writer.WriteValue(_node.TcpPort);
                        writer.WritePropertyName("WsPort");
                        writer.WriteValue(_node.WebSocketPort);
                        writer.WriteEndObject();

                        writer.WritePropertyName("RPC");
                        writer.WriteStartObject();
                        writer.WritePropertyName("BindAddress");
                        writer.WriteValue("127.0.0.1");
                        writer.WritePropertyName("Port");
                        writer.WriteValue(_node.RpcPort);
                        writer.WritePropertyName("SslCert");
                        writer.WriteValue("");
                        writer.WritePropertyName("SslCertPassword");
                        writer.WriteValue("");
                        writer.WriteEndObject();

                        writer.WritePropertyName("UnlockWallet");
                        writer.WriteStartObject();
                        writer.WritePropertyName("Path");
                        writer.WriteValue(walletPath);
                        writer.WritePropertyName("Password");
                        writer.WriteValue(password);
                        writer.WritePropertyName("StartConsensus");
                        writer.WriteValue(true);
                        writer.WritePropertyName("IsActive");
                        writer.WriteValue(true);
                        writer.WriteEndObject();

                        writer.WriteEndObject();
                        writer.WriteEndObject();
                    }
            }

            void WriteProtocolJson()
            {
                using (var stream = File.Open(Path.Combine(folder, "protocol.json"), FileMode.Create, FileAccess.Write))
                    using (var writer = new JsonTextWriter(new StreamWriter(stream))
                    {
                        Formatting = Formatting.Indented
                    })
                    {
                        writer.WriteStartObject();
                        writer.WritePropertyName("ProtocolConfiguration");
                        writer.WriteStartObject();

                        writer.WritePropertyName("Magic");
                        writer.WriteValue(chain.Magic);
                        writer.WritePropertyName("AddressVersion");
                        writer.WriteValue(23);
                        writer.WritePropertyName("SecondsPerBlock");
                        writer.WriteValue(15);

                        writer.WritePropertyName("StandbyValidators");
                        writer.WriteStartArray();
                        for (int i = 0; i < chain.ConsensusNodes.Count; i++)
                        {
                            var account = DevWalletAccount.FromExpressWalletAccount(chain.ConsensusNodes[i].Wallet.DefaultAccount);
                            var key     = account.GetKey();
                            if (key != null)
                            {
                                writer.WriteValue(key.PublicKey.EncodePoint(true).ToHexString());
                            }
                        }
                        writer.WriteEndArray();

                        writer.WritePropertyName("SeedList");
                        writer.WriteStartArray();
                        foreach (var node in chain.ConsensusNodes)
                        {
                            writer.WriteValue($"{IPAddress.Loopback}:{node.TcpPort}");
                        }
                        writer.WriteEndArray();

                        writer.WriteEndObject();
                        writer.WriteEndObject();
                    }
            }

            for (var i = 0; i < chain.ConsensusNodes.Count; i++)
            {
                var node = chain.ConsensusNodes[i];
                writeConsole($"Exporting {node.Wallet.Name} Conensus Node wallet");

                var walletPath = Path.Combine(folder, $"{node.Wallet.Name}.wallet.json");
                if (File.Exists(walletPath))
                {
                    File.Delete(walletPath);
                }

                ExportWallet(node.Wallet, walletPath, password);
                WriteNodeConfigJson(node, walletPath);
            }

            WriteProtocolJson();
        }