无法通过 JSON-RPC post GETBLOCKHASH 到比特币核心

Unable to post GETBLOCKHASH to Bitcoin Core via JSON-RPC

以下代码大部分工作正常:

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"}));
}

那将 return 像这样:

{
  "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/

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

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

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

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

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

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

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

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

  1. 更改现有 RequestServer 方法的方法签名:

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

    对此:

    public static string RequestServer(string methodName, List<JToken> parameters)
    
  2. 使用旧签名创建 RequestServer 方法的新重载,调用您刚刚更改的现有签名。这将允许您已经工作的其他方法调用(例如 getnewaddress)继续工作而无需更改。

    public static string RequestServer(string methodName, List<string> parameters)
    {
        return RequestServer(methodName, parameters.Select(p => new JValue(p)).ToList<JToken>());
    }
    
  3. 将调用getblockhash的代码改成:

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

    对此:

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

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