ledger-core
AbstractLedgerApiBlockchainExplorer.h
1 /*
2  *
3  * AbstractLedgerApiBlockchainExplorer
4  *
5  * Created by El Khalil Bellakrid on 29/07/2018.
6  *
7  * The MIT License (MIT)
8  *
9  * Copyright (c) 2018 Ledger
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in all
19  * copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  *
29  */
30 
31 
32 #ifndef LEDGER_CORE_ABSTRACTLEDGERAPIBLOCKCHAINEXPLORER_H
33 #define LEDGER_CORE_ABSTRACTLEDGERAPIBLOCKCHAINEXPLORER_H
34 
35 #include <fmt/format.h>
36 #include <rapidjson/stringbuffer.h>
37 #include <rapidjson/writer.h>
38 #include <api/Configuration.hpp>
39 #include <utils/hex.h>
40 #include <net/HttpClient.hpp>
41 #include <wallet/common/explorers/LedgerApiParser.hpp>
42 #include <wallet/common/Block.h>
43 #include <utils/JSONUtils.h>
44 #include <sstream>
45 
46 namespace ledger {
47  namespace core {
48 
49  //TODO: remove TransactionsParser and TransactionsBulkParser from template when refactoring them (common interface)
50  template <typename BlockchainExplorerTransaction, typename TransactionsBulk, typename TransactionsParser, typename TransactionsBulkParser, typename BlockParser, typename NetworkParameters>
52  public:
54  getLedgerApiTransactions(const std::vector<std::string> &addresses,
55  Option<std::string> fromBlockHash,
56  Option<void *> session,
57  bool isSnakeCase = false) {
58  auto joinedAddresses = Array<std::string>(addresses).join(strings::mkString(",")).getValueOr("");
59  std::string params;
60  std::unordered_map<std::string, std::string> headers;
61 
62  if (session.isEmpty()) {
63  params = isSnakeCase ? "?no_token=true" : "?noToken=true";
64  } else {
65  headers["X-LedgerWallet-SyncToken"] = *((std::string *)session.getValue());
66  }
67  if (!fromBlockHash.isEmpty()) {
68  if (params.size() > 0) {
69  params = params + "&";
70  } else {
71  params = params + "?";
72  }
73  auto blockHash = isSnakeCase ? "block_hash=" : "blockHash=";
74  params = params + blockHash + fromBlockHash.getValue();
75  }
76  return _http->GET(fmt::format("/blockchain/{}/{}/addresses/{}/transactions{}", getExplorerVersion(), getNetworkParameters().Identifier, joinedAddresses, params), headers)
78  .template mapPtr<TransactionsBulk>(getExplorerContext(), [fromBlockHash] (const Either<Exception, std::shared_ptr<TransactionsBulk>>& result) {
79  if (result.isLeft()) {
80  if (fromBlockHash.isEmpty()) {
81  throw result.getLeft();
82  } else {
83  throw make_exception(api::ErrorCode::BLOCK_NOT_FOUND, "Unable to find block with hash {}", fromBlockHash.getValue());
84  }
85  } else {
86  return result.getRight();
87  }
88  });
89  };
90 
92  getLedgerApiCurrentBlock() const {
93  return _http->GET(fmt::format("/blockchain/{}/{}/blocks/current", getExplorerVersion(), getNetworkParameters().Identifier))
95  .template mapPtr<Block>(getExplorerContext(), [] (const Either<Exception, std::shared_ptr<Block>>& result) {
96  if (result.isLeft()) {
97  throw result.getLeft();
98  } else {
99  return result.getRight();
100  }
101  });
102  };
103 
105  getLedgerApiTransactionByHash(const String &transactionHash) const {
106  return _http->GET(fmt::format("/blockchain/{}/{}/transactions/{}", getExplorerVersion(), getNetworkParameters().Identifier, transactionHash.str()))
108  .template mapPtr<BlockchainExplorerTransaction>(getExplorerContext(), [transactionHash] (const Either<Exception, std::shared_ptr<std::vector<BlockchainExplorerTransaction>>>& result) {
109  if (result.isLeft()) {
110  throw result.getLeft();
111  } else if (result.getRight()->size() == 0) {
112  throw make_exception(api::ErrorCode::TRANSACTION_NOT_FOUND, "Transaction '{}' not found", transactionHash.str());
113  } else {
114  auto tx = (*result.getRight())[0];
115  auto transaction = std::make_shared<BlockchainExplorerTransaction>(tx);
116  return transaction;
117  }
118  });
119  };
120 
121  Future<void *> startLedgerApiSession() const {
122  return _http->GET(fmt::format("/blockchain/{}/{}/syncToken", getExplorerVersion(), getNetworkParameters().Identifier))
123  .json().template map<void *>(getExplorerContext(), [] (const HttpRequest::JsonResult& result) {
124  auto& json = *std::get<1>(result);
125  return new std::string(json["token"].GetString(), json["token"].GetStringLength());
126  });
127  };
128 
129  Future<Unit> killLedgerApiSession(void *session) const {
130  return _http->addHeader("X-LedgerWallet-SyncToken", *((std::string *)session))
131  .DEL(fmt::format("/blockchain/{}/{}/syncToken", getExplorerVersion(), getNetworkParameters().Identifier))
132  .json().template map<Unit>(getExplorerContext(), [] (const HttpRequest::JsonResult& result) {
133  return unit;
134  });
135  };
136 
137 
138  Future<Bytes> getLedgerApiRawTransaction(const String& transactionHash) const {
139  return _http->GET(fmt::format("/blockchain/{}/{}/transactions/{}/hex", getExplorerVersion(), getNetworkParameters().Identifier, transactionHash.str()))
140  .json().template map<Bytes>(getExplorerContext(), [transactionHash] (const HttpRequest::JsonResult& result) {
141  auto& json = *std::get<1>(result);
142  if (json.GetArray().Size() == 0) {
143  throw make_exception(api::ErrorCode::RAW_TRANSACTION_NOT_FOUND, "Unable to retrieve {}", transactionHash.str());
144  } else {
145  auto& hex = json[0].GetObject()["hex"];
146  return Bytes(ledger::core::hex::toByteArray(std::string(hex.GetString(), hex.GetStringLength())));
147  }
148  });
149  }
150 
151  Future<int64_t > getLedgerApiTimestamp() const {
152  auto delay = 60*getNetworkParameters().TimestampDelay;
153  return _http->GET(fmt::format("/timestamp"))
154  .json().template map<int64_t>(getExplorerContext(), [delay] (const HttpRequest::JsonResult& result) {
155  auto& json = *std::get<1>(result);
156  return json["timestamp"].GetInt64() - delay;
157  });
158  }
159 
160  virtual Future<String> pushLedgerApiTransaction(const std::vector<uint8_t> &transaction) = 0 ;
161  protected:
162  virtual std::shared_ptr<api::ExecutionContext> getExplorerContext() const = 0;
163  virtual NetworkParameters getNetworkParameters() const = 0;
164  virtual std::string getExplorerVersion() const = 0;
165  std::shared_ptr<HttpClient> _http;
166  };
167  }
168 }
169 
170 
171 #endif //LEDGER_CORE_ABSTRACTLEDGERAPIBLOCKCHAINEXPLORER_H
Definition: Either.hpp:43
a class to store JSON values
Definition: json.hpp:231
Definition: TransactionsParser.hpp:40
Definition: Deffered.hpp:49
Definition: AbstractLedgerApiBlockchainExplorer.h:51
Definition: Bytes.hpp:41
Definition: Account.cpp:8
std::vector< uint8_t > toByteArray(const std::string &str)
Definition: hex.cpp:39
Definition: LedgerApiParser.hpp:42
Definition: Sequence.hpp:42
Definition: Exception.hpp:45