Skip to content
This repository was archived by the owner on Feb 12, 2025. It is now read-only.

Commit e5df32c

Browse files
VG-4576 Fix tezos reveal operation (#865)
* fix conversion issues in tezos gas price computation This was due to incorrect locale set in the libcore, the fix consists to set the locale in function scope to make sure to use the correct character as decimal separator. * fix: use gas_used instead of gas_limit in gas_price computation * fix: Tezos reveal fee computation * ci: bump patch version
1 parent 38eec6c commit e5df32c

File tree

4 files changed

+97
-25
lines changed

4 files changed

+97
-25
lines changed

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ clang_tidy("-checks=-*,clang-analyzer-*,-clang-analyzer-cplusplus*,cppcoreguidel
4242
include_what_you_use() # add cmake conf option IWYU=ON to activate
4343

4444
# The project version number.
45-
set(VERSION_MAJOR 4 CACHE STRING "Project major version number.")
46-
set(VERSION_MINOR 1 CACHE STRING "Project minor version number.")
47-
set(VERSION_PATCH 9 CACHE STRING "Project patch version number.")
45+
set(VERSION_MAJOR 4 CACHE STRING "Project major version number.")
46+
set(VERSION_MINOR 1 CACHE STRING "Project minor version number.")
47+
set(VERSION_PATCH 10 CACHE STRING "Project patch version number.")
4848
mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH)
4949

5050
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY build)

core/src/wallet/tezos/TezosLikeAccount2.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -454,24 +454,22 @@ namespace ledger {
454454

455455
return gasPriceFut.flatMapPtr<TezosLikeTransactionApi>(self->getMainExecutionContext(), [self, filledTx] (const std::shared_ptr<BigInt>&gasPrice) -> FuturePtr<TezosLikeTransactionApi> {
456456
return self->estimateGasLimit(filledTx).flatMapPtr<TezosLikeTransactionApi>(self->getMainExecutionContext(), [self, filledTx, gasPrice] (const std::shared_ptr<GasLimit> &gas) -> FuturePtr<TezosLikeTransactionApi> {
457-
// 0.000001 comes from the gasPrice->toInt64 being in picoTez
458457
filledTx->setRevealGasLimit(std::make_shared<BigInt>(gas->reveal));
459-
const auto revealFees = std::make_shared<BigInt>(static_cast<int64_t>(1 + static_cast<double>(gas->reveal.toInt64()) * static_cast<double>(gasPrice->toInt64()) * 0.000001));
460-
filledTx->setRevealFees(revealFees);
461-
462458
filledTx->setTransactionGasLimit(std::make_shared<BigInt>(gas->transaction));
463-
459+
464460
auto computeFees = [](const std::size_t& size, const BigInt& gasLimit) -> BigInt {
465461
const BigInt fullSize{static_cast<unsigned long long>(size + signatureSize)}; // Bytes
466462
BigInt truncated = (minimalFees + minimalNanotezPerByte * fullSize + minimalNanotezPerGazUnit * gasLimit) / BigInt(1000); // utz
467-
return ++truncated;
463+
return ++truncated;
468464
};
469-
465+
470466
const std::size_t txSize = filledTx->serialize().size();
471-
BigInt computedFees = computeFees(txSize, gas->transaction);
472-
467+
BigInt computedRevealFees = computeFees(txSize, gas->reveal);
468+
BigInt computedTransactionFees = computeFees(txSize, gas->transaction);
473469

474-
const auto transactionFees = std::make_shared<BigInt>(std::move(computedFees));
470+
const auto revealFees = std::make_shared<BigInt>(std::move(computedRevealFees));
471+
filledTx->setRevealFees(revealFees);
472+
const auto transactionFees = std::make_shared<BigInt>(std::move(computedTransactionFees));
475473
filledTx->setTransactionFees(transactionFees);
476474

477475
self->logger()->info(

core/src/wallet/tezos/api_impl/TezosLikeTransactionApi.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ namespace ledger {
461461
pub_key.c_str(), static_cast<SizeType>(pub_key.length()), allocator);
462462
revealOp.AddMember("public_key", vString, allocator);
463463

464-
static const auto fee = "257000";
464+
static const auto fee = "10000";
465465
vString.SetString(fee, static_cast<SizeType>(std::strlen(fee)), allocator);
466466
revealOp.AddMember("fee", vString, allocator);
467467

core/src/wallet/tezos/explorers/ExternalTezosLikeBlockchainExplorer.cpp

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
#include <api/ErrorCode.hpp>
3434
#include <api/TezosConfiguration.hpp>
3535
#include <api/TezosConfigurationDefaults.hpp>
36+
#include <clocale>
37+
#include <sstream>
38+
3639

3740
namespace ledger {
3841
namespace core {
@@ -132,14 +135,29 @@ namespace ledger {
132135
ExternalTezosLikeBlockchainExplorer::getGasPrice() {
133136
const bool parseNumbersAsString = true;
134137
// 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";
137140
const auto feeField = "fee";
138141
// We still use the legacy field in case we have a rollback
139142
const auto gasPriceField = "gas_price";
140143

141144
return _http->GET("block/head")
142145
.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+
143161
auto &json = *std::get<1>(result);
144162

145163
if (!json.IsObject()) {
@@ -154,31 +172,87 @@ namespace ledger {
154172
// OR
155173
// tzindex v12+ gas_price compute
156174
else {
157-
if (!json.HasMember(gasLimitField) || !json[gasLimitField].IsString()) {
175+
if (!json.HasMember(gasUsedField) || !json[gasUsedField].IsString()) {
158176
throw make_exception(
159177
api::ErrorCode::HTTP_ERROR, fmt::format(
160178
"Failed to compute gas_price from network, no (or malformed) field \"{}\" in response",
161-
gasLimitField));
179+
gasUsedField));
162180
}
163181
if (!json.HasMember(feeField) || !json[feeField].IsString()) {
164182
throw make_exception(
165183
api::ErrorCode::HTTP_ERROR, fmt::format(
166184
"Failed to compute gas_price from network, no (or malformed) field \"{}\" in response",
167185
feeField));
168186
}
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+
{
171202
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+
)
173208
);
174209
}
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();
178226
}
179227

180228
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);
182256
});
183257
}
184258

0 commit comments

Comments
 (0)