无法通过 JSON-RPC 将 GETBLOCKHASH 发布到比特币核心

Posted

技术标签:

【中文标题】无法通过 JSON-RPC 将 GETBLOCKHASH 发布到比特币核心【英文标题】:Unable to post GETBLOCKHASH to Bitcoin Core via JSON-RPC 【发布时间】:2020-07-25 13:02:35 【问题描述】:

以下代码在大多数情况下都可以正常工作:

public static string RequestServer(string methodName, List<string> parameters)

    // Use the values you specified in the bitcoin server command line
    string ServerIp = "http://localhost.:8332";
    string UserName = "username";
    string Password = "password";

    HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(ServerIp);
    webRequest.Credentials = new NetworkCredential(UserName, Password);

    webRequest.ContentType = "application/json-rpc";
    webRequest.Method = "POST";

    string responseValue = string.Empty;

    // Configure request type
    JObject joe = new JObject();
    joe.Add(new JProperty("jsonrpc", "1.0"));
    joe.Add(new JProperty("id", "1"));
    joe.Add(new JProperty("method", methodName));

    JArray props = new JArray();
    foreach (var parameter in parameters)
    
        props.Add(parameter);
    

    joe.Add(new JProperty("params", props));

    // serialize JSON for request
    string s = JsonConvert.SerializeObject(joe);
    byte[] byteArray = Encoding.UTF8.GetBytes(s);
    webRequest.ContentLength = byteArray.Length;
    Stream dataStream = webRequest.GetRequestStream();
    dataStream.Write(byteArray, 0, byteArray.Length);
    dataStream.Close();

    // deserialze the response
    StreamReader sReader = null;
    WebResponse webResponse = webRequest.GetResponse();
    sReader = new StreamReader(webResponse.GetResponseStream(), true);
    responseValue = sReader.ReadToEnd();

    var data = JsonConvert.DeserializeObject(responseValue).ToString();
    
    return data;

然后我可以使用methodName(例如getnewaddress)从服务器取回数据:

static void Main(string[] args)

    Console.WriteLine(RequestServer("getnewaddress", new List<string>()"","legacy"));

这将返回如下内容:


  "result": "1EWJkGrirdhXpduoNdccxaCx7syqWHuDcK",
  "error": null,
  "id": "1"

上述方法名在使用终端时也可以正常工作:

bitcoin@desktop:~/Downloads/bitcoin-0.20.0-x86_64-linux-gnu/bitcoin-0/bin$ ./bitcoin-cli getnewaddress "" "legacy"
1EWJkGrirdhXpduoNdccxaCx7syqWHuDcK
bitcoin@desktop:~/Downloads/bitcoin-0.20.0-x86_64-linux-gnu/bitcoin-0.20.0/bin$ 

我可以以同样的方式使用一些方法名,它们工作正常。然而,当我使用getblockhash:

static void Main(string[] args)

    Console.WriteLine(RequestServer("getblockhash", new List<string>()"0"));

它给了我以下错误:

bitcoin@desktop:~/Code/blockchain-app$ dotnet run
Unhandled exception. System.Net.WebException: The remote server returned an error: (500) Internal Server Error.
   at System.Net.HttpWebRequest.GetResponse()
   at blockchain-app.Program.RequestServer(String methodName, List`1 parameters) in /home/bitcoin/Code/blockchain-app/Program.cs:line 72
   at blockchain-app.Program.Main(String[] args) in /home/bitcoin/Code/blockchain-app/Program.cs:line 29
bitcoin@desktop:~/Code/blockchain-app$

调试时,错误发生在这一行:

WebResponse webResponse = webRequest.GetResponse();

如果我尝试在终端中使用该 methodName 手动检查输出,如下所示,它可以正常工作:

bitcoin@desktop:~/Downloads/bitcoin-0.20.0-x86_64-linux-gnu/bitcoin-0.20.0/bin$ ./bitcoin-cli getblockhash 0
000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
bitcoin@desktop:~/Downloads/bitcoin-0.20.0-x86_64-linux-gnu/bitcoin-0.20.0/bin$

除了 methodName 和发送的参数之外,请求示例结构在我看来是相同的:

https://bitcoincore.org/en/doc/0.20.0/rpc/wallet/getnewaddress/ https://bitcoincore.org/en/doc/0.20.0/rpc/blockchain/getblockhash/

有人知道为什么会这样吗?

【问题讨论】:

您是否检查了响应正文以查看是否有任何错误详细信息? 不确定如何检查响应正文。 ***.com/questions/11828843/… body 可能有某种错误原因。 @Charleh,这帮助我解决了这个问题。感谢您的帮助。 酷,如果您愿意,可以将您的解决方案作为答案发布,将来可能会对某人有所帮助 【参考方案1】:

认为问题是您在调用getblockhash 时为高度索引传递了错误的参数类型。您链接到的文档说它应该是一个数字(整数)参数,但您传递的是一个字符串。相比之下,getnewaddress 方法使用字符串参数,因此您现有的代码适用于此。

如果您捕获由 RequestServer 方法生成的 JSON,它看起来像这样:

"jsonrpc":"1.0","id":"1","method":"getblockhash","params":["0"]

getblockhash 文档中的示例如下所示:

"jsonrpc":"1.0","id":"curltest","method":"getblockhash","params":[1000]

请注意,params 数组中的值未在示例中引用,而在您的示例中被引用。

要修复,请尝试以下操作:

    从此更改现有RequestServer 方法的方法签名:

    public static string RequestServer(string methodName, List<string> parameters)
    

    到这里:

    public static string RequestServer(string methodName, List<JToken> parameters)
    

    使用旧签名创建RequestServer 方法的新重载,该签名调用您刚刚更改的现有签名。这将允许您已经工作的其他方法调用(例如getnewaddress)继续工作而无需更改。

    public static string RequestServer(string methodName, List<string> parameters)
    
        return RequestServer(methodName, parameters.Select(p => new JValue(p)).ToList<JToken>());
    
    

    从这里更改调用getblockhash的代码:

    Console.WriteLine(RequestServer("getblockhash", new List<string>()  "0" ));
    

    到这里:

    Console.WriteLine(RequestServer("getblockhash", new List<JToken>()  new JValue(0) ));
    

请注意,我在 2018 年为您回答了 similar question,其中我推荐了上面显示的相同步骤 1 和 2,因此您可能已经完成了该部分。如果是这样,您只需执行第 3 步即可。

【讨论】:

以上是关于无法通过 JSON-RPC 将 GETBLOCKHASH 发布到比特币核心的主要内容,如果未能解决你的问题,请参考以下文章

连接到json-rpc接口

我可以使用 JSON-RPC 将文件发布到网络服务吗?

React Native 中的比特币 JSON-RPC Api 请求?

如何通过retrofit2发送Json-rpc?

Yii2通过curl调用json-rpc接口

如何通过retrofit2发送Json-rpc?