Making transformations on HTTP outcall responses in Motoko to achieve consensus

I’m trying to get bitcoin’s price with an http outcall. I’m using Kyle’s code, the first two functions here:

I’m calling those from the third function, the last one below them, http_call_and_decode_bitcoin_price().

Everything works fine, but I need to make a transformation to reduce the precision of the price so that there is no disagreement between nodes about the correct value, and I don’t know how to adapt transform() or how else to achieve consensus.

Alternatively, or additionally, how does one make a call to the exchange rate canister in Motoko exactly? I don’t understand usage nor exact syntax from the Readme: GitHub - dfinity/exchange-rate-canister: The exchange rate canister (XRC) makes use of the HTTP requests feature to provide exchange rates as a service to the IC.

I managed to make the transformation. I’m basically using the price in 10 dollar increments.

My worry now are the cutoff points. transform() is effectively rounding up or down to the nearest $10, but won’t we have a problem when the price is very close to exactly a multiple of $5, with some nodes getting eg $23884 and some $23885, therefore rounding to $23880 and $23890 respectively and therefore not reaching consensus for the result?

What kind of transform can and should be done for this sort of thing so that the requests never fail due to inability to reach consensus between nodes?

The problem you are (probably) running into is that by calling something that gives the current price your call’s response depends on the time when it is executed. If all replicas perform the call at a slightly different time, you will get slightly different responses and have to round or do some other trickery to get the same response.

The recommended way to fetch any information is to use a request that does not depend on the time at which it is executed. In your case, you should fetch the exchange rate at a specific timestamp, and set the timestamp to the most recent you expect to be available (read: now). This way all replicas should receive the same data and the transform function does not need to round or do any other weird tricks.

1 Like

@THLO made a nice simple Motoko canister that queries the exchange rate canister. Maybe you find it useful: xrc_demo/main.mo at main · THLO/xrc_demo · GitHub

3 Likes

I was looking for something like this. If it consumes 10B cycles per call it’s somewhat unusable though. Not sure if that’s correct or how much gets refunded.

That would be around 1.5 cents per call or ~$8k dollars per year calling once per minute.

For now the maximum charge of the XRC is 5B cycles. So you will be refunded at least 5B. See here for details on how it charges.
The reason this is quite expensive is that the XRC might make several HTTPS outcalls for each call. This is expensive in terms of resources and if too cheap, can be used to DoS the subnet.

1 Like