Giter VIP home page Giter VIP logo

Comments (5)

xeniacx avatar xeniacx commented on August 22, 2024

That is correct. The return type in your example should be List<ListTransactionsResponse> and not ListTransactionsResponse, as demonstrated in this test client call.

from bitcoinlib.

NiklasNikolajsen avatar NiklasNikolajsen commented on August 22, 2024

The error I reported WAS FROM running the test client! I then modified the call as part of finding out the root cause, but the error is not a type case error, but as described, a deserialization error - which also occur in the unmodified CoinService code, at least for me.

As mentioned, the error occurs because the JSON response cannot be deserialized - not because I try to capture the returned value in a ListTransactionsResponse .
I do not think you tried to run CoinService.ListTransactions, did you? If so - and if you encountered no error, your JSON.Net version must be different than mine, which cannot deserialize the returned JSON string.
The RPC call and the JSON response is captured fine, but Deserilization using your original CoinService code fails.

I investigated the root cause.

Running against the blockchain.info RPC access at https://rpc.blockchain.info:443.

The JSON text string returned from the RPC in my case was:

{"result":{"lastblock":"00000000000000000ee4d0f4d086b0324e750d19fae10003c55ba875652c1ca4","transactions":[{"amount":0.0008,"blockhash":"00000000000000000020a6a6280401444ab61a9d4f35d436a50567935fcbf495","address":"16NxBNBcrxRgzHRGsJiW9fmg7HLoNvUZ3n","fee":0.0001,"txid":"e649d9333f20f7f5a9549809e2784b254cb8d79d9b6f7c0be1814eea4ad4b282","label":"BTCSFFB0W5DY","time":1424387709,"category":"receive","confirmations":-163,"blockindex":781976,"account":"BTCSFFB0W5DY"},{"amount":-0.0019,"blockhash":"00000000000000000020a6a6280401444ab61a9d4f35d436a50567935fcbf495","address":"16NxBNBcrxRgzHRGsJiW9fmg7HLoNvUZ3n","fee":0.0001,"txid":"e649d9333f20f7f5a9549809e2784b254cb8d79d9b6f7c0be1814eea4ad4b282","label":"BTCSFFB0W5DY","time":1424387709,"category":"send","confirmations":-163,"blockindex":781976,"account":"BTCSFFB0W5DY"},{"amount":0.0019,"blockhash":"00000000000000000014506cec64981fdc49178011a1510b1f00995c9d62a95d","address":"16NxBNBcrxRgzHRGsJiW9fmg7HLoNvUZ3n","fee":0.0001,"txid":"7685a8e832d468f224a7b5414b7ce9037a7955132237983acaf4ee842a5d5741","label":"BTCSFFB0W5DY","time":1424276225,"category":"receive","confirmations":-377,"blockindex":779874,"account":"BTCSFFB0W5DY"},{"amount":-0.003,"blockhash":"00000000000000000014506cec64981fdc49178011a1510b1f00995c9d62a95d","address":"16NxBNBcrxRgzHRGsJiW9fmg7HLoNvUZ3n","fee":0.0001,"txid":"7685a8e832d468f224a7b5414b7ce9037a7955132237983acaf4ee842a5d5741","label":"BTCSFFB0W5DY","time":1424276225,"category":"send","confirmations":-377,"blockindex":779874,"account":"BTCSFFB0W5DY"},{"amount":0.003,"blockhash":"00000000000000000477417305b03d8033a0c9fbf949be5ca60dbf0c6abf5fef","address":"16NxBNBcrxRgzHRGsJiW9fmg7HLoNvUZ3n","fee":0.00001,"txid":"e92bfc63cb15f030b557be38aa59025f23bc1f50e16f1b5a2072249bc8c6a778","label":"BTCSFFB0W5DY","time":1424273720,"category":"receive","confirmations":-383,"blockindex":773756,"account":"BTCSFFB0W5DY"}]},"id":"1","jsonrpc":"2.0","error":null}

This is being attempted deserialized in :

private T MakeRequest(RpcMethods rpcMethod, Int16 timedOutRequestsCount, params object[] parameters)

However - here the error occus at:
JsonRpcResponse rpcResponse = JsonConvert.DeserializeObject<JsonRpcResponse>(json);

My Newtonsoft JSON.Net dll (v. 6.0.0) seems unable to handle the response, due in part to the issue described here: http://michaelcummings.net/mathoms/using-a-custom-jsonconverter-to-fix-bad-json-results/

But likely also because the returned JSON has a "lastblock" element, one level lower than the transactions themselves.

FIX:

First step is to rewrite ListTransactionsResponse, to include the lastblock element, then a list of nested transactions (original code assumed JSON return was just the list of transactions):

public class ListTransactionsResponse
{
public string lastblock;
public List transactions;
}
public class ListTransactionsResponseEx
{

    public String Account { get; set; }
    public String Label { get; set; }
    public String Address { get; set; }
    public String Category { get; set; }
    public Decimal Amount { get; set; }
    public Decimal Fee { get; set; }
    public Int32 Confirmations { get; set; }
    public String BlockHash { get; set; }
    public String BlockIndex { get; set; }
    public Double BlockTime { get; set; }
    public String TxId { get; set; }
    public List<String> WalletConflicts { get; set; }
    public Double Time { get; set; }
    public Double TimeReceived { get; set; }
    public String Comment { get; set; }
    public String OtherAccount { get; set; }

}

However - the Deserialization will still fail,, as Newtonsoft cannot handle the (actually valid) JSON text response. This can be fixed by adding square brackets around the "result" element in the JSON text string:

UGLY FIX:

if (rpcMethod.ToString() == "listtransactions")
{
json = json.Replace("result":{", "result":[{");
json = json.Replace("]},"id":", "]}],"id":");
}
JsonRpcResponse rpcResponse = JsonConvert.DeserializeObject<JsonRpcResponse>(json);

While this creates an array of results in rpcResponse.Result, at least it works. One then has to access rpcResponse.Result[0] to get to the result data.

TRUE FIX:
Extend JSON.Net's deserialization pipeline as described here: http://michaelcummings.net/mathoms/using-a-custom-jsonconverter-to-fix-bad-json-results/

A few of the other functions in the CoinService fail as well when run up against rpc.blockchain.info (using JSON.Net 6.0) - but are also fixable. So -all in all a very useful piece of code, which certainly got me started :-) Thank you!

from bitcoinlib.

xeniacx avatar xeniacx commented on August 22, 2024

Thanks for your input.

OK, mystery solved: you are getting this deserialization error because blockchain.info's listtransactions response is different than the reference client's.

Bitcoin-core's response is:

Result:
[
  {
    "account":"accountname",       (string) The account name associated with the transaction.
                                                It will be "" for the default account.
    "address":"bitcoinaddress",    (string) The bitcoin address of the transaction. Not present for
                                                move transactions (category = move).
    "category":"send|receive|move", (string) The transaction category. 'move' is a local (off blockchain)
                                                transaction between accounts, and not associated with an address,
                                                transaction id or block. 'send' and 'receive' transactions are
                                                associated with an address, transaction id and block details
    "amount": x.xxx,          (numeric) The amount in btc. This is negative for the 'send' category, and for the
                                         'move' category for moves outbound. It is positive for the 'receive' category,
                                         and for the 'move' category for inbound funds.
    "vout" : n,               (numeric) the vout value
    "fee": x.xxx,             (numeric) The amount of the fee in btc. This is negative and only available for the
                                         'send' category of transactions.
    "confirmations": n,       (numeric) The number of confirmations for the transaction. Available for 'send' and
                                         'receive' category of transactions.
    "blockhash": "hashvalue", (string) The block hash containing the transaction. Available for 'send' and 'receive'
                                          category of transactions.
    "blockindex": n,          (numeric) The block index containing the transaction. Available for 'send' and 'receive'
                                          category of transactions.
    "txid": "transactionid", (string) The transaction id. Available for 'send' and 'receive' category of transactions.
    "time": xxx,              (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).
    "timereceived": xxx,      (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available
                                          for 'send' and 'receive' category of transactions.
    "comment": "...",       (string) If a comment is associated with the transaction.
    "otheraccount": "accountname",  (string) For the 'move' category of transactions, the account the funds came
                                          from (for receiving funds, positive amounts), or went to (for sending funds,
                                          negative amounts).
  }
]

while blockchain.info's response is:

{
    "lastblock" : "00000000000009133d70c6282279bfc5fadfea07e27543445a199fe6ef84b51b",
    "transactions" : [
        {
            "fee" : 0.01000000,
            "amount" : 1,
            "blockindex" : 171984,
            "category" : "receive",
            "confirmations" : 0,
            "address" : "1A8JiWcwvpY7tAopUkSnGuEYHmzGYfZPiq",
            "txid" : "90992bc8ebff9774cfc91738863602010dab9ab2f5b0841cc4922786a2029725",
            "block" : 1323486876,
            "blockhash" : "00000000000003438e8c67500f34dd32bb1bf0d251a5c230c407641961c85b41",
            "account" : "My Wallet"
        }
    ]
}

The assumption that this library is blockchain.info-compatible was based upon the feedback from this issue, however based on your feedback it turns that it isn't and since blockchain.info decided to diverge from bitcoin-core's RPC API responses we have to think of other ways to extend this library against blockchain.info's implementation, which should not however interfere with the default (bitcoin-core) implementation. Thoughts?

from bitcoinlib.

NiklasNikolajsen avatar NiklasNikolajsen commented on August 22, 2024

Damn - it is extremely inconvinient that Blockchain does not stay true to the Core's implementation. Because it does allow for lightweight applications, not to have to download and maintain the blockchain - and run the core client.
Reading through the previous thread, I have some feedback:

We have also not received an API-key from Blockchain.info, although we actually do have a website (https://www.bitcoinsuisse.ch/en/index/). Actually, we didnt get as much as a reply from them. However, the RCP does not require an API key (nowhere to put it in the calls), only the webservices do.

The Blockchain RPC is however extremely responsive and fast, one does not need a core client + blockchain etc. so it is highly recommendable for ligltweight apps.

The responses are indeed somewhat different as you discovered. I think the only workaround for this is to generate entirely seperate response classes for when using blockchain.info - and to implement a "blockchain.info mode" to set when creating the CoinService instance. As 80 % of the responses are the same, this would not be too big a task. And it would certainly add value to the CoinService library

One annoying thing is that the listtransactions-response from blockchain does not contain the "OtherAccount" field, and one thus miss this information in the transactions. I made a workaround where I call GetTransaction on new transactions before storing in DB, then loop through the response to find the "otheraddress".

var txDetails = CoinService.GetTransaction(transaction.TxId);
foreach (var detailline in txDetails.Details)
{
if(detailline.Address != transaction.Address)
transaction.OtherAccount = detailline.Address;
}
return transaction;

Unlike mentioned in the previous thread, I had no issue with the 2nd password functions (send) or similar. All there seem to work smooth.

A rework of CoinService against blockchain.info would certainly trigger a BTC-donation from my side, because then I do not have to do it, and the feature would then be available to the whole community through github. If you would consider such an undertaking, let me know (niklas.nikolajsen(at)bitcoinsuisse.ch).

from bitcoinlib.

xeniacx avatar xeniacx commented on August 22, 2024

There is no obvious way to get this library working with Blockchain.info's RPC API from the moment they decided to diverge from bitcoin-core's RPC API specification and their developer support is for from satisfactory.

from bitcoinlib.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.