Kann ich die Rohtransaktion mit Nethereum erhalten?

Wie erhalte ich eine Rohtransaktion für eine Transaktion auf der Blockchain mit web3/Nethereum?

Ein Beispiel für eine Rohtransaktion ist hier zu sehen: https://etherscan.io/getRawTx?tx=0x3866bd52ab1273b9b014e81f981fb35e6b1ec3254514e09c604921ecc17a6ad6

Antworten (1)

Das Nethereum unterstützt es nicht direkt, aber alle Versionen von Parity Wallet unterstützen es und neuere Versionen von Geth unterstützen es auch, sodass wir einen RPC-Aufruf direkt senden können, ohne einen Nethereum-RPC-Aufruf zu verwenden. Die fragliche RPC-Methode ist eth_getRawTransactionByHash.

Wie so

        /// <summary>
        /// Attempt to get the raw hex directly from the geth node
        /// </summary>
        /// <param name="txid"></param>
        /// <returns></returns>
        internal string GetRawTxHexByGetRawTransactionByHash(string txid)
        {
            // Extract the HttpClient object from the web3 object
            FieldInfo field = typeof(Nethereum.JsonRpc.Client.RpcClient).GetField("_httpClient", BindingFlags.NonPublic | BindingFlags.Instance);
            HttpClient httpClient = (HttpClient)field.GetValue(_web3.Client);

            // Make the post request to our own Geth node and deserialize the result
            RpcRequest rpcRequest = new RpcRequest
            {
                method = "eth_getRawTransactionByHash",
                @params = new string[] { txid },
            };
            HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri("/", UriKind.Relative));
            requestMessage.Content = new StringContent(JsonConvert.SerializeObject(rpcRequest), Encoding.UTF8, "application/json");
            HttpResponseMessage resp = httpClient.SendAsync(requestMessage).Result;
            if (!resp.IsSuccessStatusCode)
            {
                _logger.LogWarning($"Failed to call to eth_getRawTransactionByHash for txid={txid}.");
                return null;
            }

            EthGetRawTransactionByHashResponse txResp =
                JsonConvert.DeserializeObject<EthGetRawTransactionByHashResponse>(resp.Content.ReadAsStringAsync().Result);

            return txResp.result;
        }

wobei die folgenden Hilfsklassen verwendet wurden

        private abstract class Web3RpcBase
        {
            public int id { get; set; } = 67;
            public string jsonrpc { get; set; } = "2.0";
        }

        private class RpcRequest : Web3RpcBase
        {
            public string method { get; set; }
            public string[] @params { get; set; }
        }

        private class EthGetRawTransactionByHashResponse : Web3RpcBase
        {
            public string result { get; set; }
        }

Wenn Sie so unglücklich sind, einen Knoten zu verwenden, der eth_getRawTransactionByHash(alte Geth-Versionen) nicht unterstützt, können Sie immer noch das Roh-Hex erhalten, indem Sie die folgenden Funktionen verwenden, um das Roh-Hex aus verfügbaren Daten zu erstellen.

        private abstract class Web3RpcBase
        {
            public int id { get; set; } = 67;
            public string jsonrpc { get; set; } = "2.0";
        }

        private class RpcRequest : Web3RpcBase
        {
            public string method { get; set; }
            public string[] @params { get; set; }
        }


        private class EthGetTransactionByHashResponseResult

        {
            public string blockHash { get; set; }
            public string blockNumber { get; set; }
            public string from { get; set; }

            // This is what we usually call gas limit
            public string gas { get; set; }
            public string gasPrice { get; set; }
            public string hash { get; set; }

            // This is what we usually call data
            public string input { get; set; }
            public string nonce { get; set; }
            public string to { get; set; }
            public string transactionIndex { get; set; }
            public string value { get; set; }
            public string v { get; set; }
            public string r { get; set; }
            public string s { get; set; }
        }


        private class EthGetTransactionByHashResponse : Web3RpcBase

        {
            public EthGetTransactionByHashResponseResult result { get; set; }
        }

        private class EthGetRawTransactionByHashResponse : Web3RpcBase
        {
            public string result { get; set; }
        }


        /// <summary>
        /// Should only be used for Ethereum, not BTC.
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] HexToByteArrayWrapper(string hexString)
        {
            // Prevent "0" from becoming "00" represented by[0]. "0" should be[], and 1 should be [0x01]
            if (string.IsNullOrEmpty(hexString) || hexString == "0" || hexString == "0x0")
            {
                return Array.Empty<byte>();
            }

            return hexString.HexToByteArray();
        }

        /// <summary>
        /// Attempt to get the raw hex directly from the geth node
        /// </summary>
        /// <param name="txid"></param>
        /// <returns></returns>
        internal string GetRawTxHexByGetRawTransactionByHash(string txid)
        {
            // Extract the HttpClient object from the web3 object
            FieldInfo field = typeof(Nethereum.JsonRpc.Client.RpcClient).GetField("_httpClient", BindingFlags.NonPublic | BindingFlags.Instance);
            HttpClient httpClient = (HttpClient)field.GetValue(_web3.Client);

            // Make the post request to our own Geth node and deserialize the result
            RpcRequest rpcRequest = new RpcRequest
            {
                method = "eth_getRawTransactionByHash",
                @params = new string[] { txid },
            };
            HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri("/", UriKind.Relative));
            requestMessage.Content = new StringContent(JsonConvert.SerializeObject(rpcRequest), Encoding.UTF8, "application/json");
            HttpResponseMessage resp = httpClient.SendAsync(requestMessage).Result;
            if (!resp.IsSuccessStatusCode)
            {
                _logger.LogWarning($"Failed to call to eth_getRawTransactionByHash for txid={txid}.");
                return null;
            }

            EthGetRawTransactionByHashResponse txResp =
                JsonConvert.DeserializeObject<EthGetRawTransactionByHashResponse>(resp.Content.ReadAsStringAsync().Result);

            return txResp.result;
        }

        /// <summary>
        /// Attempt to reconstruct the raw hex by getting the transaction info from the geth node
        /// </summary>
        /// <param name="txid"></param>
        /// <returns></returns>
        internal string GetRawTxHexByGetTransactionByHash(string txid)
        {
            // Extract the HttpClient object from the web3 object
            FieldInfo field = typeof(Nethereum.JsonRpc.Client.RpcClient).GetField("_httpClient", BindingFlags.NonPublic | BindingFlags.Instance);
            HttpClient httpClient = (HttpClient)field.GetValue(_web3.Client);

            // Make the post request to our own Geth node and deserialize the result
            RpcRequest rpcRequest = new RpcRequest
            {
                method = "eth_getTransactionByHash",
                @params = new string[] { txid },
            };
            HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri("/", UriKind.Relative));
            requestMessage.Content = new StringContent(JsonConvert.SerializeObject(rpcRequest), Encoding.UTF8, "application/json");
            HttpResponseMessage resp = httpClient.SendAsync(requestMessage).Result;
            if (!resp.IsSuccessStatusCode)
            {
                _logger.LogWarning($"Failed to call to eth_getTransactionByHash for txid={txid}.");
                return null;
            }

            EthGetTransactionByHashResponse txResp = JsonConvert.DeserializeObject<EthGetTransactionByHashResponse>(resp.Content.ReadAsStringAsync().Result);

            // Create the signature object to insert in the transaction (needed to support chain IDs above 0xff)
            Org.BouncyCastle.Math.BigInteger r = new Org.BouncyCastle.Math.BigInteger(txResp.result.r.Substring(2), 0x10);
            Org.BouncyCastle.Math.BigInteger s = new Org.BouncyCastle.Math.BigInteger(txResp.result.s.Substring(2), 0x10);
            byte[] v = new byte[] { byte.Parse(txResp.result.v.Substring(2), System.Globalization.NumberStyles.HexNumber, CultureInfo.GetCultureInfo("en-US")) };
            EthECDSASignature signature = new Nethereum.Signer.EthECDSASignature(r, s, v);

            // Create unsigned transaction object
            Nethereum.Signer.Transaction transaction = new Nethereum.Signer.Transaction(
                HexToByteArrayWrapper(txResp.result.nonce),
                HexToByteArrayWrapper(txResp.result.gasPrice),
                HexToByteArrayWrapper(txResp.result.gas),
                HexToByteArrayWrapper(txResp.result.to),
                HexToByteArrayWrapper(txResp.result.value),
                HexToByteArrayWrapper(txResp.result.input),
                Array.Empty<byte>(),
                Array.Empty<byte>(),
                0);
            transaction.SetSignature(signature);

            // Get the hex format of the RLP-encoded transaction, the rawtx
            string rawTxHex = "0x" + transaction.GetRLPEncoded().Select(x => x.ToString("x2", NumberFormatInfo.InvariantInfo)).Aggregate((acc, elem) => acc + elem);
            return rawTxHex;
        }

        /// <summary>
        /// Given a txid return the RLP-encoded raw hex that represents the transcation on the blockchain.
        /// </summary>
        /// <param name="txid"></param>
        /// <returns></returns>
        internal string GetRawHex(string txid)
        {
            // First try to get the raw hex directly from the node
            string res = GetRawTxHexByGetRawTransactionByHash(txid);
            if (!String.IsNullOrWhiteSpace(res) && res != "0x")
            {
                return res;
            }

            // If that did not work, attempt to construct it from tx details
            _logger.LogInformation("Failed to get raw hex from node, calculating it locally instead.");
            return GetRawTxHexByGetTransactionByHash(txid);
        }