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

Commit 5263347

Browse files
[VG-3094] Compute operation_id from tezos transactions and update of uid formula (#848)
* fix(Tezos): add operation_id in tezos transactions and update of uid formula Changes: * change tezos operation uid formula to {accountUId + counter + TxOpIndex + TxOpType (+ additional) + OperationType} * add methods to tezos transaction to retreive the non-reveal operation type / index in batch * add method to tezos account to compute an operation_id from an unsigned transaction * a bit of refactoring in Operation * parse tezos operation index in batch and counter * ci: bump patch version
1 parent d99308d commit 5263347

16 files changed

+258
-88
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ include_what_you_use() # add cmake conf option IWYU=ON to activate
4444
# The project version number.
4545
set(VERSION_MAJOR 4 CACHE STRING "Project major version number.")
4646
set(VERSION_MINOR 1 CACHE STRING "Project minor version number.")
47-
set(VERSION_PATCH 2 CACHE STRING "Project patch version number.")
47+
set(VERSION_PATCH 3 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/idl/wallet/tezos/tezos_like_wallet.djinni

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ TezosOperationTag = enum {
1919
#Class representing a Tezos transaction
2020
TezosLikeTransaction = interface +c {
2121
# Get type of operation (transaction, reveal ... cf TezosOperationTag)
22-
getType(): TezosOperationTag;
22+
const getType(): TezosOperationTag;
2323
# Get the hash of the transaction.
24-
getHash(): string;
24+
const getHash(): string;
25+
# Get the operation index in the transaction
26+
const getOperationIndexInTransaction(): i64;
27+
# Get the operation type in the transaction
28+
const getOperationTypeInTransaction(): TezosOperationTag;
2529
# Get Fees (in drop)
2630
# It returns the sum of transaction fees and reveal fees (if it exists)
2731
getFees(): Amount;
@@ -31,9 +35,9 @@ TezosLikeTransaction = interface +c {
3135
getRevealFees(): Amount;
3236

3337
# Get destination XTZ. address
34-
getReceiver(): optional<TezosLikeAddress>;
38+
const getReceiver(): optional<TezosLikeAddress>;
3539
# Get XTZ. sender address
36-
getSender(): TezosLikeAddress;
40+
const getSender(): TezosLikeAddress;
3741
# Get amount of XTZ to send
3842
getValue(): optional<Amount>;
3943
# Serialize the transaction to its raw format.
@@ -54,10 +58,10 @@ TezosLikeTransaction = interface +c {
5458
getStatus(): i32;
5559
# Get the correlation id
5660
getCorrelationId(): string;
57-
# Set the correlation id which can be used to debug transaction errors
58-
# through the full ledger stack
59-
# @return the OLD Correlation ID, if it was set (empty string if it was unset)
60-
setCorrelationId(correlationId : string) : string;
61+
# Set the correlation id which can be used to debug transaction errors
62+
# through the full ledger stack
63+
# @return the OLD Correlation ID, if it was set (empty string if it was unset)
64+
setCorrelationId(correlationId : string) : string;
6165
}
6266

6367
#Class representing a Tezos Operation
@@ -158,9 +162,11 @@ TezosLikeAccount = interface +c {
158162
getOriginatedAccounts(): list<TezosLikeOriginatedAccount>;
159163
# Get current delegate
160164
getCurrentDelegate(callback: Callback<string>);
161-
# Get the balance of the account for a given token
162-
# @param tokenAddress Address of the contract
163-
getTokenBalance(tokenAddress: string, callback: Callback<BigInt>);
165+
# Get the balance of the account for a given token
166+
# @param tokenAddress Address of the contract
167+
getTokenBalance(tokenAddress: string, callback: Callback<BigInt>);
168+
# Get the deterministic operation Uid
169+
const computeOperationUid(transaction: TezosLikeTransaction): string;
164170
}
165171

166172
# Class representing originated accounts

core/src/api/TezosLikeAccount.hpp

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/api/TezosLikeTransaction.hpp

Lines changed: 10 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/jni/jni/TezosLikeAccount.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,14 @@ CJNIEXPORT void JNICALL Java_co_ledger_core_TezosLikeAccount_00024CppProxy_nativ
121121
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
122122
}
123123

124+
CJNIEXPORT jstring JNICALL Java_co_ledger_core_TezosLikeAccount_00024CppProxy_native_1computeOperationUid(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, jobject j_transaction)
125+
{
126+
try {
127+
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
128+
const auto& ref = ::djinni::objectFromHandleAddress<::ledger::core::api::TezosLikeAccount>(nativeRef);
129+
auto r = ref->computeOperationUid(::djinni_generated::TezosLikeTransaction::toCpp(jniEnv, j_transaction));
130+
return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));
131+
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
132+
}
133+
124134
} // namespace djinni_generated

core/src/jni/jni/TezosLikeTransaction.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,26 @@ CJNIEXPORT jstring JNICALL Java_co_ledger_core_TezosLikeTransaction_00024CppProx
4343
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
4444
}
4545

46+
CJNIEXPORT jlong JNICALL Java_co_ledger_core_TezosLikeTransaction_00024CppProxy_native_1getOperationIndexInTransaction(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
47+
{
48+
try {
49+
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
50+
const auto& ref = ::djinni::objectFromHandleAddress<::ledger::core::api::TezosLikeTransaction>(nativeRef);
51+
auto r = ref->getOperationIndexInTransaction();
52+
return ::djinni::release(::djinni::I64::fromCpp(jniEnv, r));
53+
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
54+
}
55+
56+
CJNIEXPORT jobject JNICALL Java_co_ledger_core_TezosLikeTransaction_00024CppProxy_native_1getOperationTypeInTransaction(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
57+
{
58+
try {
59+
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
60+
const auto& ref = ::djinni::objectFromHandleAddress<::ledger::core::api::TezosLikeTransaction>(nativeRef);
61+
auto r = ref->getOperationTypeInTransaction();
62+
return ::djinni::release(::djinni_generated::TezosOperationTag::fromCpp(jniEnv, r));
63+
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
64+
}
65+
4666
CJNIEXPORT jobject JNICALL Java_co_ledger_core_TezosLikeTransaction_00024CppProxy_native_1getFees(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
4767
{
4868
try {

core/src/wallet/common/Operation.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,34 +36,37 @@ namespace ledger {
3636
namespace core {
3737

3838
void Operation::refreshUid(const std::string &additional) {
39+
std::string txId;
3940
if (bitcoinTransaction.nonEmpty()) {
40-
uid = OperationDatabaseHelper::createUid(accountUid, bitcoinTransaction.getValue().hash, type);
41+
txId = computeTransactionId(bitcoinTransaction.getValue().hash);
4142
}
4243
else if (cosmosTransaction.nonEmpty()) {
43-
auto final = cosmosTransaction.getValue().tx.hash;
44-
if (!additional.empty()){
45-
final = fmt::format("{}+{}", final, additional);
46-
}
47-
48-
uid = OperationDatabaseHelper::createUid(accountUid, final, type);
44+
txId = computeTransactionId(cosmosTransaction.getValue().tx.hash, additional);
4945
}
5046
else if (ethereumTransaction.nonEmpty()) {
51-
uid = OperationDatabaseHelper::createUid(accountUid, ethereumTransaction.getValue().hash, type);
47+
txId = computeTransactionId(ethereumTransaction.getValue().hash);
5248
}
5349
else if (rippleTransaction.nonEmpty()) {
54-
uid = OperationDatabaseHelper::createUid(accountUid, rippleTransaction.getValue().hash, type);
50+
txId = computeTransactionId(rippleTransaction.getValue().hash);
5551
}
5652
else if (tezosTransaction.nonEmpty()) {
57-
auto final = fmt::format("{}+{}", tezosTransaction.getValue().hash, api::to_string(tezosTransaction.getValue().type));
58-
if (!additional.empty()){
59-
final = fmt::format("{}+{}", final, additional);
60-
}
61-
uid = OperationDatabaseHelper::createUid(accountUid, final, type);
53+
const auto& tx = tezosTransaction.getValue();
54+
std::string txIdBase = fmt::format("{}+{}",
55+
tx.counter,
56+
tx.index
57+
);
58+
txId = computeTransactionId(txIdBase, tx.type, additional);
6259
} else if (stellarOperation.nonEmpty()) {
63-
uid = OperationDatabaseHelper::createUid(accountUid, stellarOperation.getValue().operation.transactionHash, type);
60+
txId = computeTransactionId(stellarOperation.getValue().operation.transactionHash);
6461
} else {
6562
throw Exception(api::ErrorCode::RUNTIME_ERROR, "Cannot refresh uid of an incomplete operation.");
6663
}
64+
65+
uid = OperationDatabaseHelper::createUid(accountUid, txId, type);
66+
}
67+
68+
std::string Operation::computeTransactionId(const std::string& txHash, const std::string& additional){
69+
return additional.empty() ? txHash : fmt::format("{}+{}", txHash, additional);
6770
}
6871

6972
}

core/src/wallet/common/Operation.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,18 @@ namespace ledger {
8989

9090
Operation& operator=(Operation const&) = default;
9191
Operation& operator=(Operation&&) = default;
92+
93+
template <typename CoinOperationType>
94+
static std::string computeTransactionId(const std::string& txHash, const CoinOperationType& coinOperationType, const std::string& additional = "");
95+
static std::string computeTransactionId(const std::string& txHash, const std::string& additional = "");
96+
9297
};
98+
99+
template <typename CoinOperationType>
100+
std::string Operation::computeTransactionId(const std::string& txHash, const CoinOperationType& coinOperationType, const std::string& additional) {
101+
auto hashAndCoinOpType = fmt::format("{}+{}", txHash, api::to_string(coinOperationType));
102+
return computeTransactionId(hashAndCoinOpType, additional);
103+
}
93104
}
94105
}
95106

core/src/wallet/tezos/TezosLikeAccount.cpp

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -112,33 +112,35 @@ namespace ledger {
112112
// Check if it's an operation related to an originated account
113113
// It can be the case if we are putting transaction operations
114114
// for originated account.
115+
std::string originatedAccountUid;
116+
std::string originatedAccountAddress;
115117
if (!transaction.originatedAccountUid.empty() && !transaction.originatedAccountAddress.empty()) {
116-
operation.amount = transaction.value;
117-
operation.type = transaction.sender == transaction.originatedAccountAddress ? api::OperationType::SEND : api::OperationType::RECEIVE;
118-
operation.refreshUid(transaction.originatedAccountUid);
119-
out.push_back(operation);
120-
result = static_cast<int>(transaction.type);
121-
return addedAddressToKeychain;
118+
originatedAccountUid = transaction.originatedAccountUid;
119+
originatedAccountAddress = transaction.originatedAccountAddress;
122120
}
123121

124-
if (_accountAddress == transaction.sender) {
125-
operation.amount = transaction.value;
126-
operation.type = api::OperationType::SEND;
127-
operation.refreshUid();
128-
if (transaction.type == api::TezosOperationTag::OPERATION_TAG_ORIGINATION && transaction.status == 1) {
129-
addedAddressToKeychain = updateOriginatedAccounts(operation);
130-
}
131-
out.push_back(operation);
132-
result = static_cast<int>(transaction.type);
133-
}
122+
std::string additional;
123+
api::OperationType opType;
124+
std::tie(opType, additional) = getOperationTypeAndUidAdditional(
125+
transaction.sender,
126+
transaction.receiver,
127+
originatedAccountUid,
128+
originatedAccountAddress
129+
);
130+
131+
operation.amount = transaction.value;
132+
operation.type = opType;
133+
operation.refreshUid(additional);
134134

135-
if (_accountAddress == transaction.receiver) {
136-
operation.amount = transaction.value;
137-
operation.type = api::OperationType::RECEIVE;
138-
operation.refreshUid();
139-
out.push_back(operation);
140-
result = static_cast<int>(transaction.type);
135+
if (additional.empty() && _accountAddress == transaction.sender &&
136+
transaction.type == api::TezosOperationTag::OPERATION_TAG_ORIGINATION && transaction.status == 1)
137+
{
138+
addedAddressToKeychain = updateOriginatedAccounts(operation);
141139
}
140+
141+
out.push_back(operation);
142+
result = static_cast<int>(transaction.type);
143+
142144
return addedAddressToKeychain;
143145
}
144146

@@ -346,5 +348,26 @@ namespace ledger {
346348
})
347349
.callback(getMainExecutionContext(), callback);
348350
}
351+
352+
std::pair<api::OperationType, std::string> TezosLikeAccount::getOperationTypeAndUidAdditional(const std::string& sender, const std::string& receiver,
353+
const std::string& originatedAccountId, const std::string& originatedAccountAddress) const {
354+
const std::string& accountAddress = getAccountAddress();
355+
356+
if(!originatedAccountId.empty() && !originatedAccountAddress.empty()) {
357+
if(originatedAccountAddress == sender) {
358+
return std::make_pair(api::OperationType::SEND, originatedAccountId);
359+
}
360+
if(originatedAccountAddress == receiver) {
361+
return std::make_pair(api::OperationType::RECEIVE, originatedAccountId);
362+
}
363+
}
364+
if(accountAddress == sender) {
365+
return std::make_pair(api::OperationType::SEND, "");
366+
}
367+
if(accountAddress == receiver) {
368+
return std::make_pair(api::OperationType::RECEIVE, "");
369+
}
370+
throw make_exception(api::ErrorCode::RUNTIME_ERROR, "Failed to determine the operation type for computing the operation id");
371+
}
349372
}
350373
}

core/src/wallet/tezos/TezosLikeAccount.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,22 @@ namespace ledger {
162162

163163
void getTokenBalance(const std::string& tokenAddress, const std::shared_ptr<api::BigIntCallback>& callback) override;
164164

165+
const std::string& getAccountAddress() const;
166+
165167
/// Return a common trace prefix for logs
166168
/// TODO: Upstream tracePrefix() to AbstractAccount and use that everywhere
167169
std::string tracePrefix() const;
170+
171+
std::string computeOperationUid(const std::shared_ptr<api::TezosLikeTransaction> & transaction) const override;
172+
168173
private:
169174
std::shared_ptr<TezosLikeAccount> getSelf();
170175
void broadcastRawTransaction(const std::vector<uint8_t> &transaction,
171176
const std::shared_ptr<api::StringCallback> &callback,
172177
const std::string& correlationId);
173178

179+
std::pair<api::OperationType, std::string> getOperationTypeAndUidAdditional(const std::string& sender, const std::string& receiver, const std::string& originatedAccountId, const std::string& originatedAccountAddress) const;
180+
174181
std::shared_ptr<TezosLikeKeychain> _keychain;
175182
std::string _accountAddress;
176183
std::shared_ptr<TezosLikeBlockchainExplorer> _explorer;

0 commit comments

Comments
 (0)