Skip to content

Commit

Permalink
Review
Browse files Browse the repository at this point in the history
  • Loading branch information
gagbo committed Sep 3, 2020
1 parent b5cf251 commit 0d85a9b
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 160 deletions.
16 changes: 8 additions & 8 deletions core/src/wallet/tezos/TezosLikeAccount2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,15 +372,15 @@ namespace ledger {
}).flatMapPtr<api::TezosLikeTransaction>(self->getMainExecutionContext(), [self, request] (const std::shared_ptr<TezosLikeTransactionApi> &tx) {
if (request.gasLimit->toInt() == 0) {
auto filledTx = tx;
auto gasPrice_fut = request.fees->toInt() == 0 ?
auto gasPriceFut = request.fees->toInt() == 0 ?
self->getGasPrice()
:
FuturePtr<BigInt>::successful(request.fees);

return gasPrice_fut.flatMapPtr<api::TezosLikeTransaction>(self->getMainExecutionContext(), [self, filledTx] (const std::shared_ptr<BigInt>&gasPrice) -> FuturePtr<api::TezosLikeTransaction> {
return gasPriceFut.flatMapPtr<api::TezosLikeTransaction>(self->getMainExecutionContext(), [self, filledTx] (const std::shared_ptr<BigInt>&gasPrice) -> FuturePtr<api::TezosLikeTransaction> {
return self->estimateGasLimit(filledTx).flatMapPtr<api::TezosLikeTransaction>(self->getMainExecutionContext(), [filledTx, gasPrice] (const std::shared_ptr<BigInt> &gas) -> FuturePtr<api::TezosLikeTransaction> {
// 0.000001 comes from the gasPrice being in picoTez
const auto fees = std::make_shared<BigInt>(static_cast<int64_t>(1 + gas->toInt64() * static_cast<double>(gasPrice->toInt64()) * 0.000001));
// 0.000001 comes from the gasPrice->toInt64 being in picoTez
const auto fees = std::make_shared<BigInt>(static_cast<int64_t>(1 + static_cast<double>(gas->toInt64()) * static_cast<double>(gasPrice->toInt64()) * 0.000001));
filledTx->setGasLimit(gas);
filledTx->setFees(fees);
return FuturePtr<api::TezosLikeTransaction>::successful(filledTx);
Expand Down Expand Up @@ -445,13 +445,13 @@ namespace ledger {
return _explorer->getGasPrice();
}

FuturePtr<BigInt> TezosLikeAccount::estimateGasLimit(const std::shared_ptr<TezosLikeTransactionApi>& tx, double adjustment_factor) {
FuturePtr<BigInt> TezosLikeAccount::estimateGasLimit(const std::shared_ptr<TezosLikeTransactionApi>& tx, double adjustmentFactor) {
return _explorer->getEstimatedGasLimit(tx).flatMapPtr<BigInt>(
getMainExecutionContext(),
[adjustment_factor](const std::shared_ptr<BigInt>& consumedGas){
auto adjusted_gas = static_cast<int64_t>(1 + consumedGas->toInt64() * adjustment_factor);
[adjustmentFactor](const std::shared_ptr<BigInt>& consumedGas){
auto adjustedGas = static_cast<int64_t>(1 + consumedGas->toInt64() * adjustmentFactor);
return Future<std::shared_ptr<BigInt>>::successful(
std::make_shared<BigInt>(adjusted_gas));
std::make_shared<BigInt>(adjustedGas));
});
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/wallet/tezos/api_impl/TezosLikeTransactionApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ namespace ledger {
}
const auto pub_key = _revealedPubKey ;
vString.SetString(
source.c_str(), static_cast<SizeType>(source.length()), allocator);
pub_key.c_str(), static_cast<SizeType>(pub_key.length()), allocator);
revealOp.AddMember("public_key", vString, allocator);

static const auto fee = "257000";
Expand Down
2 changes: 1 addition & 1 deletion core/src/wallet/tezos/api_impl/TezosLikeTransactionApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ namespace ledger {
std::vector<uint8_t> serialize() override;
std::vector<uint8_t> serializeWithType(api::TezosOperationTag type);

/// Serialize the transaction as json for Tezos Node run_operation JSON RPC endpoint
/// Serialize the transaction as binary for Tezos Node run_operation JSON RPC endpoint
std::vector<uint8_t> serializeForDryRun(const std::vector<uint8_t>& chainID);

/// Serialize the transaction as json for Tezos Node run_operation JSON RPC endpoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@
#include "ExternalTezosLikeBlockchainExplorer.h"
#include <api/TezosConfigurationDefaults.hpp>
#include <api/Configuration.hpp>
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <api/BigInt.hpp>
#include <unordered_map>

namespace ledger {
namespace core {
Expand Down Expand Up @@ -113,8 +108,8 @@ namespace ledger {
fees = totalFees->divide(totalTx)->toString(10);
}
// Since nodes are giving some awkward values, we set a threshold to avoid
// having really fees Factor for threshold is inspired from other XTZ
// wallets
// having really fees
// Factor for threshold is inspired from other XTZ wallets
return std::make_shared<BigInt>(std::min(std::stoi(fees), std::stoi(api::TezosConfigurationDefaults::TEZOS_DEFAULT_MAX_FEES)));
});
}
Expand Down Expand Up @@ -318,75 +313,7 @@ namespace ledger {

Future<std::shared_ptr<BigInt>>
ExternalTezosLikeBlockchainExplorer::getEstimatedGasLimit(const std::shared_ptr<TezosLikeTransactionApi> &tx) {
// ChainID is obtained by doing GET RPCNode /chains/main/chain_id
const auto strChainID = "NetXdQprcVkpaWU";
const auto postPath = fmt::format(
"/chains/{}/blocks/head/helpers/scripts/run_operation",
strChainID);
const auto payload = tx->serializeJsonForDryRun(strChainID);

const std::unordered_map<std::string, std::string> postHeaders{
{"Accept", "application/json"}, {"Content-Type", "application/json"}};

const bool parseNumbersAsString = true;
return _http
->POST(
postPath,
std::vector<uint8_t>(payload.cbegin(), payload.cend()),
postHeaders,
getRPCNodeEndpoint())
.json(parseNumbersAsString)
.flatMapPtr<BigInt>(
getContext(), [](const HttpRequest::JsonResult &result) -> FuturePtr<BigInt> {
const auto &json = std::get<1>(result)->GetObject();
if (json.HasMember("kind")) {
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to simulate operation: {}", json["kind"].GetString());
}
if (
!json["contents"].IsArray() || !(json["contents"].Size() > 0) ||
!json["contents"].GetArray()[0].IsObject() ||
!json["contents"].GetArray()[0].GetObject().HasMember("metadata") ||
!json["contents"].GetArray()[0].GetObject()["metadata"].HasMember("operation_result")
) {
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to get operation_result in simulation");
}
auto &operationResult = json["contents"]
.GetArray()[0]
.GetObject()["metadata"]
.GetObject()["operation_result"];

// Fail if operation_result is not .status == "applied"
if (!operationResult.HasMember("status") ||
operationResult["status"].GetString() != std::string("applied")) {
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to simulate the operation on the Node");
}

return FuturePtr<BigInt>::successful(std::make_shared<BigInt>(
BigInt::fromString(operationResult["consumed_gas"].GetString())));
})
.recover(getContext(), [] (const Exception &exception) {
auto ecode = exception.getErrorCode();
// Tezos RPC returns a 500 when the transaction is not valid (bad counter, no balance, etc.)
// so we rethrow the tezos node error for easier debugging
auto body = std::static_pointer_cast<HttpRequest::JsonResult>(exception.getUserData().getValue());
const auto &json = *std::get<1>(*body);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
json.Accept(writer);
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to simulate operation: {}",
buffer.GetString());

// lambda is [noreturn], this is just left so type deduction succeeds and compiles
return std::make_shared<BigInt>("0");
});
return TezosLikeBlockchainExplorer::getEstimatedGasLimit(_http, getContext(), tx);
}

Future<std::shared_ptr<BigInt>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,75 +260,7 @@ namespace ledger {
NodeTezosLikeBlockchainExplorer::getEstimatedGasLimit(
const std::shared_ptr<TezosLikeTransactionApi> &tx)
{
// ChainID is obtained by doing GET RPCNode /chains/main/chain_id
const auto strChainID = "NetXdQprcVkpaWU";
const auto postPath = fmt::format(
"/chains/{}/blocks/head/helpers/scripts/run_operation",
strChainID);
const auto payload = tx->serializeJsonForDryRun(strChainID);

const std::unordered_map<std::string, std::string> postHeaders{
{"Accept", "application/json"}, {"Content-Type", "application/json"}};

const bool parseNumbersAsString = true;
return _http
->POST(
postPath,
std::vector<uint8_t>(payload.cbegin(), payload.cend()),
postHeaders,
getRPCNodeEndpoint())
.json(parseNumbersAsString)
.flatMapPtr<BigInt>(
getContext(), [](const HttpRequest::JsonResult &result) -> FuturePtr<BigInt> {
const auto &json = std::get<1>(result)->GetObject();
if (json.HasMember("kind")) {
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to simulate operation: {}", json["kind"].GetString());
}
if (
!json["contents"].IsArray() || !(json["contents"].Size() > 0) ||
!json["contents"].GetArray()[0].IsObject() ||
!json["contents"].GetArray()[0].GetObject().HasMember("metadata") ||
!json["contents"].GetArray()[0].GetObject()["metadata"].HasMember("operation_result")
) {
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to get operation_result in simulation");
}
auto &operationResult = json["contents"]
.GetArray()[0]
.GetObject()["metadata"]
.GetObject()["operation_result"];

// Fail if operation_result is not .status == "applied"
if (!operationResult.HasMember("status") ||
operationResult["status"].GetString() != std::string("applied")) {
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to simulate the operation on the Node");
}

return FuturePtr<BigInt>::successful(std::make_shared<BigInt>(
BigInt::fromString(operationResult["consumed_gas"].GetString())));
})
.recover(getContext(), [] (const Exception &exception) {
auto ecode = exception.getErrorCode();
// Tezos RPC returns a 500 when the transaction is not valid (bad counter, no balance, etc.)
// so we rethrow the tezos node error for easier debugging
auto body = std::static_pointer_cast<HttpRequest::JsonResult>(exception.getUserData().getValue());
const auto &json = *std::get<1>(*body);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
json.Accept(writer);
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to simulate operation: {}",
buffer.GetString());

// lambda is [noreturn], this is just left so type deduction succeeds and compiles
return std::make_shared<BigInt>("0");
});
return TezosLikeBlockchainExplorer::getEstimatedGasLimit(_http, getContext(), tx);
}

Future<std::shared_ptr<BigInt>> NodeTezosLikeBlockchainExplorer::getStorage(
Expand Down
85 changes: 84 additions & 1 deletion core/src/wallet/tezos/explorers/TezosLikeBlockchainExplorer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
#include <wallet/tezos/api_impl/TezosLikeTransactionApi.h>
#include <api/TezosConfiguration.hpp>
#include <api/TezosConfigurationDefaults.hpp>
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <api/BigInt.hpp>
#include <unordered_map>

namespace ledger {
namespace core {
Expand Down Expand Up @@ -152,5 +157,83 @@ namespace ledger {
return false;
});
}

Future<std::shared_ptr<BigInt>> TezosLikeBlockchainExplorer::getEstimatedGasLimit(
const std::shared_ptr<HttpClient> &_http,
const std::shared_ptr<api::ExecutionContext> &context,
const std::shared_ptr<TezosLikeTransactionApi> &tx)
{
// ChainID is obtained by doing GET RPCNode /chains/main/chain_id
const auto strChainID = "NetXdQprcVkpaWU";
const auto postPath =
fmt::format("/chains/{}/blocks/head/helpers/scripts/run_operation", strChainID);
const auto payload = tx->serializeJsonForDryRun(strChainID);

const std::unordered_map<std::string, std::string> postHeaders{
{"Accept", "application/json"}, {"Content-Type", "application/json"}};

const bool parseNumbersAsString = true;
return _http
->POST(
postPath,
std::vector<uint8_t>(payload.cbegin(), payload.cend()),
postHeaders,
getRPCNodeEndpoint())
.json(parseNumbersAsString)
.flatMapPtr<BigInt>(
context,
[](const HttpRequest::JsonResult &result) -> FuturePtr<BigInt> {
const auto &json = std::get<1>(result)->GetObject();
if (json.HasMember("kind")) {
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to simulate operation: {}",
json["kind"].GetString());
}
if (!json["contents"].IsArray() || !(json["contents"].Size() > 0) ||
!json["contents"].GetArray()[0].IsObject() ||
!json["contents"].GetArray()[0].GetObject().HasMember("metadata") ||
!json["contents"].GetArray()[0].GetObject()["metadata"].HasMember(
"operation_result")) {
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to get operation_result in simulation");
}
auto &operationResult = json["contents"]
.GetArray()[0]
.GetObject()["metadata"]
.GetObject()["operation_result"];

// Fail if operation_result is not .status == "applied"
if (!operationResult.HasMember("status") ||
operationResult["status"].GetString() != std::string("applied")) {
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to simulate the operation on the Node");
}

return FuturePtr<BigInt>::successful(std::make_shared<BigInt>(
BigInt::fromString(operationResult["consumed_gas"].GetString())));
})
.recover(context, [](const Exception &exception) {
auto ecode = exception.getErrorCode();
// Tezos RPC returns a 500 when the transaction is not valid (bad counter, no
// balance, etc.) so we rethrow the tezos node error for easier debugging
auto body = std::static_pointer_cast<HttpRequest::JsonResult>(
exception.getUserData().getValue());
const auto &json = *std::get<1>(*body);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
json.Accept(writer);
throw make_exception(
api::ErrorCode::HTTP_ERROR,
"failed to simulate operation: {}",
buffer.GetString());

// lambda is [noreturn], this is just left so type deduction succeeds and
// compiles
return std::make_shared<BigInt>("0");
});
}
}
}
}
Loading

0 comments on commit 0d85a9b

Please sign in to comment.