void UpdateTransaction(bool loadNonce) { m_paragraphTransaction.Inlines.Clear(); // Password / Private key BigInteger privateKey; if (EllipticCurve.HexToPrivateKey(m_passwordBoxPP.Password, out privateKey)) { m_passwordBoxPP.Background = Brushes.LightSkyBlue; } else { m_passwordBoxPP.Background = Brushes.White; if (Password.GetKeySpace(m_passwordBoxPP.Password) < BigInteger.Pow(2, m_passwordStrengthBit)) { return; } privateKey = Password.PasswordToPrivateKey(m_passwordBoxPP.Password); } BigInteger publicKeyX; BigInteger publicKeyY; BouncyCastle.ECPrivateKeyToPublicKey(privateKey, out publicKeyX, out publicKeyY); byte[] publicKey = EllipticCurve.PublicKeyToBytes(publicKeyX, publicKeyY); byte[] address = ETHAddress.PublicKeyToETHAddress(publicKey); PrintAddressAndBlockExplorer("From", address); // Nonce if (loadNonce) { string text = ""; if (m_dAddressNonce.ContainsKey(Encode.BytesToHex(address))) { text = m_dAddressNonce[Encode.BytesToHex(address)]; } Dispatcher.BeginInvoke(new Action(() => m_comboBoxNonce.Text = text)); } if (!BigInteger.TryParse(m_comboBoxNonce.Text, out m_tx.m_nonce)) { m_paragraphTransaction.Inlines.Add("Nonce: <Invalid>\n"); return; } if (m_tx.m_nonce < 0) { m_paragraphTransaction.Inlines.Add("Nonce: <Invalid>\n"); return; } m_paragraphTransaction.Inlines.Add("Nonce: " + m_tx.m_nonce + "\n"); // To string to = m_comboBoxTo.Text.Trim(); int index = to.IndexOf(" "); if (index != -1) { to = to.Substring(0, index); } m_tx.m_to = Encode.HexToBytes(to); if (m_tx.m_to == null) { m_paragraphTransaction.Inlines.Add("To: <Invalid>\n"); return; } else if (m_tx.m_to.Length == 0) { m_paragraphTransaction.Inlines.Add("To: Empty\n"); } else if (m_tx.m_to.Length == 20) { PrintAddressAndBlockExplorer("To", m_tx.m_to); } else { m_paragraphTransaction.Inlines.Add("To: <Invalid>\n"); return; } // Value if (Encode.DecimalToBigInteger(m_comboBoxValue.Text, 18, out m_tx.m_value)) { m_paragraphTransaction.Inlines.Add("Value: " + Encode.BigIntegerToDecimal(m_tx.m_value, 18) + " " + GetCurrency() + "\n"); } else { m_paragraphTransaction.Inlines.Add("Value: <Invalid>\n"); return; } // Init / Data if (m_tx.m_initOrData.Length > 0) { m_paragraphTransaction.Inlines.Add("Init / Data: " + m_tx.m_initOrData.Length + " bytes\n"); } // Gas price if (!Encode.DecimalToBigInteger(m_comboBoxGasPrice.Text, 18, out m_tx.m_gasPrice)) { m_paragraphTransaction.Inlines.Add("Gas price: <Invalid>\n"); return; } // m_paragraphTransaction.Inlines.Add("Gas price: " + Encode.BigIntegerToDecimal(m_tx.m_gasPrice, 18) + " " + GetCurrency() + "\n"); // Gas limit if (!BigInteger.TryParse(m_comboBoxGasLimit.Text, out m_tx.m_gasLimit)) { m_paragraphTransaction.Inlines.Add("Gas limit: <Invalid>\n"); return; } if (m_tx.m_gasLimit < 0) { m_paragraphTransaction.Inlines.Add("Gas limit: <Invalid>\n"); return; } // m_paragraphTransaction.Inlines.Add("Gas limit: " + m_tx.m_gasLimit + "\n"); BigInteger gasLimitMin = m_tx.GetGasLimitMin(); if (m_tx.m_gasLimit < gasLimitMin) { m_paragraphTransaction.Inlines.Add(new Run("Minimal gas limit is " + gasLimitMin + ".\n") { Foreground = Brushes.Red }); } // calculation m_paragraphTransaction.Inlines.Add(new Run("Fee: " + Encode.BigIntegerToDecimal(m_tx.m_gasPrice * m_tx.m_gasLimit, 18) + " " + GetCurrency() + "\n") { ToolTip = "Fee = Gas price * Gas limit" }); m_paragraphTransaction.Inlines.Add(new Run("Value + Fee: " + Encode.BigIntegerToDecimal(m_tx.m_value + m_tx.m_gasPrice * m_tx.m_gasLimit, 18) + " " + GetCurrency() + "\n") { ToolTip = "Fee = Gas price * Gas limit" }); // additional check if (m_tx.m_to.Length == 0 && m_tx.m_initOrData.Length == 0) { return; } // tx m_tx.ECDsaSign(GetCurrency(), privateKey); byte[] tx = m_tx.EncodeRLP(); byte[] hash = BouncyCastle.Keccak(tx); // button foreach (string node in m_lNode) { Button buttonSend = new Button() { Margin = new Thickness(2), Content = "Send to " + node, ToolTip = "Send raw transaction to " + node }; buttonSend.Click += (sender, e) => { // save string file = GetCurrency() + "_tx_" + DateTime.Now.ToString("yyMMdd_HHmmss") + "_0x" + Encode.BytesToHex(hash); File.WriteAllBytes(file, tx); // nonce read m_dAddressNonce.Clear(); foreach (var entry in ConfigFile.ReadAddressInfo(GetCurrency() + "_nonce")) { m_dAddressNonce[entry.Item1] = entry.Item2; } // nonce update m_dAddressNonce[Encode.BytesToHex(address)] = m_tx.m_nonce.ToString(); // nonce write List <string> lLine = new List <string>(); foreach (var entry in m_dAddressNonce) { lLine.Add("0x" + entry.Key + " " + entry.Value); } File.WriteAllLines(GetCurrency() + "_nonce", lLine); // send System.Diagnostics.Process.Start("send_transaction.exe", file + " " + node + " -pause"); }; m_paragraphTransaction.Inlines.Add(buttonSend); } Button buttonCopy = new Button() { Margin = new Thickness(2), Content = "Copy", ToolTip = "Copy raw transaction to clipboard" }; Button buttonSave = new Button() { Margin = new Thickness(2), Content = "Save", ToolTip = "Save raw transaction to file" }; buttonCopy.Click += (sender, e) => Clipboard.SetText(Encode.BytesToHex(tx)); buttonSave.Click += (sender, e) => { var dlg = new Microsoft.Win32.SaveFileDialog(); dlg.FileName = GetCurrency() + "_tx_0x" + Encode.BytesToHex(hash); if (dlg.ShowDialog() == true) { File.WriteAllBytes(dlg.FileName, tx); } }; m_paragraphTransaction.Inlines.Add(buttonCopy); m_paragraphTransaction.Inlines.Add(buttonSave); }