33
33
#include < api/ErrorCode.hpp>
34
34
#include < api/TezosConfiguration.hpp>
35
35
#include < api/TezosConfigurationDefaults.hpp>
36
+ #include < clocale>
37
+ #include < sstream>
38
+
36
39
37
40
namespace ledger {
38
41
namespace core {
@@ -132,14 +135,29 @@ namespace ledger {
132
135
ExternalTezosLikeBlockchainExplorer::getGasPrice () {
133
136
const bool parseNumbersAsString = true ;
134
137
// Since tzindex 12.01, we don't have gas_price field anymore
135
- // We have to calculate it instead from gas_limit and fee
136
- const auto gasLimitField = " gas_limit " ;
138
+ // We have to calculate it instead from gas_used and fee
139
+ const auto gasUsedField = " gas_used " ;
137
140
const auto feeField = " fee" ;
138
141
// We still use the legacy field in case we have a rollback
139
142
const auto gasPriceField = " gas_price" ;
140
143
141
144
return _http->GET (" block/head" )
142
145
.json (parseNumbersAsString).mapPtr <BigInt>(getContext (), [=](const HttpRequest::JsonResult &result) {
146
+
147
+ // Fix locale issue in conversion string from/to double
148
+ struct ScopedLocale {
149
+ ScopedLocale () {
150
+ _locale = std::setlocale (LC_NUMERIC, nullptr );
151
+ std::setlocale (LC_NUMERIC, " C" );
152
+ }
153
+ ~ScopedLocale () {
154
+ std::setlocale (LC_NUMERIC, _locale.c_str ());
155
+ }
156
+ private:
157
+ std::string _locale;
158
+ } _;
159
+
160
+
143
161
auto &json = *std::get<1 >(result);
144
162
145
163
if (!json.IsObject ()) {
@@ -154,31 +172,87 @@ namespace ledger {
154
172
// OR
155
173
// tzindex v12+ gas_price compute
156
174
else {
157
- if (!json.HasMember (gasLimitField ) || !json[gasLimitField ].IsString ()) {
175
+ if (!json.HasMember (gasUsedField ) || !json[gasUsedField ].IsString ()) {
158
176
throw make_exception (
159
177
api::ErrorCode::HTTP_ERROR, fmt::format (
160
178
" Failed to compute gas_price from network, no (or malformed) field \" {}\" in response" ,
161
- gasLimitField ));
179
+ gasUsedField ));
162
180
}
163
181
if (!json.HasMember (feeField) || !json[feeField].IsString ()) {
164
182
throw make_exception (
165
183
api::ErrorCode::HTTP_ERROR, fmt::format (
166
184
" Failed to compute gas_price from network, no (or malformed) field \" {}\" in response" ,
167
185
feeField));
168
186
}
169
- const uint64_t apiGasLimit = std::stoull (json[gasLimitField].GetString ());
170
- if (apiGasLimit == 0 ) {
187
+ const uint64_t apiGasUsed = std::stoull (json[gasUsedField].GetString ());
188
+ if (apiGasUsed == 0 ) {
189
+ throw make_exception (
190
+ api::ErrorCode::HTTP_ERROR, " Failed to compute gas_price from network, gas_used of HEAD block is 0"
191
+ );
192
+ }
193
+
194
+ const auto & feeFieldStringValue = json[feeField].GetString ();
195
+ double apiFee = 0 .;
196
+ try
197
+ {
198
+ apiFee = std::stod (feeFieldStringValue);
199
+ }
200
+ catch (const std::invalid_argument& e)
201
+ {
171
202
throw make_exception (
172
- api::ErrorCode::HTTP_ERROR, " Failed to compute gas_price from network, gas_limit of HEAD block is 0"
203
+ api::ErrorCode::INVALID_ARGUMENT, fmt::format (
204
+ " Failed to compute gas_price from network, issue converting from string with fee of HEAD block equal to \" {}\" : {}" ,
205
+ feeFieldStringValue,
206
+ e.what ()
207
+ )
173
208
);
174
209
}
175
- const double apiFee = std::stod (json[feeField].GetString ());
176
- const double numericGasPrice = apiFee / static_cast <double >(apiGasLimit);
177
- gasPrice = std::to_string (numericGasPrice);
210
+ catch (const std::out_of_range& e)
211
+ {
212
+ throw make_exception (
213
+ api::ErrorCode::OUT_OF_RANGE, fmt::format (
214
+ " Failed to compute gas_price from network, issue casting to double with fee of HEAD block equal to \" {}\" : {}" ,
215
+ feeFieldStringValue,
216
+ e.what ()
217
+ )
218
+ );
219
+ }
220
+
221
+ const double numericGasPrice = apiFee / static_cast <double >(apiGasUsed);
222
+ std::ostringstream ss;
223
+ ss.precision (std::numeric_limits<double >::digits10);
224
+ ss << std::fixed << numericGasPrice;
225
+ gasPrice = ss.str ();
178
226
}
179
227
180
228
const std::string picoTezGasPrice = api::BigInt::fromDecimalString (gasPrice, 6 , " ." )->toString (10 );
181
- return std::make_shared<BigInt>(std::stoi (picoTezGasPrice));
229
+ int intPicoTezGasPrice = 0 ;
230
+ try
231
+ {
232
+ intPicoTezGasPrice = std::stoi (picoTezGasPrice);
233
+ }
234
+ catch (const std::invalid_argument& e)
235
+ {
236
+ throw make_exception (
237
+ api::ErrorCode::INVALID_ARGUMENT, fmt::format (
238
+ " Failed to compute gas_price from network, issue converting from string with picoTezGasPrice equal to \" {}\" : {}" ,
239
+ picoTezGasPrice,
240
+ e.what ()
241
+ )
242
+ );
243
+ }
244
+ catch (const std::out_of_range& e)
245
+ {
246
+ throw make_exception (
247
+ api::ErrorCode::OUT_OF_RANGE, fmt::format (
248
+ " Failed to compute gas_price from network, issue casting to int with picoTezGasPrice equal to \" {}\" : {}" ,
249
+ picoTezGasPrice,
250
+ e.what ()
251
+ )
252
+ );
253
+ }
254
+
255
+ return std::make_shared<BigInt>(intPicoTezGasPrice);
182
256
});
183
257
}
184
258
0 commit comments