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); }
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(); }
static byte[] Sign(byte[] hashData, DevWalletAccount account) { var key = account.GetKey(); if (key == null) { throw new Exception("DevWalletAccount missing key"); } var publicKey = key.PublicKey.EncodePoint(false).AsSpan().Slice(1).ToArray(); return(Neo.Cryptography.Crypto.Default.Sign(hashData, key.PrivateKey, publicKey)); }
static byte[] CreateSignatureRedeemScript(DevWalletAccount account) { var key = account.GetKey(); if (key == null) { throw new Exception("DevWalletAccount missing key"); } using var sb = new Neo.VM.ScriptBuilder(); sb.EmitPush(key.PublicKey.EncodePoint(true)); sb.Emit(Neo.VM.OpCode.CHECKSIG); return(sb.ToArray()); }
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)); }
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(); }