Skip to content

Commit

Permalink
[VG-3094] Compute operation_id from tezos transactions and update of …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
jcoatelen-ledger authored Feb 7, 2022
1 parent d99308d commit 5263347
Show file tree
Hide file tree
Showing 16 changed files with 258 additions and 88 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ include_what_you_use() # add cmake conf option IWYU=ON to activate
# The project version number.
set(VERSION_MAJOR 4 CACHE STRING "Project major version number.")
set(VERSION_MINOR 1 CACHE STRING "Project minor version number.")
set(VERSION_PATCH 2 CACHE STRING "Project patch version number.")
set(VERSION_PATCH 3 CACHE STRING "Project patch version number.")
mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY build)
Expand Down
28 changes: 17 additions & 11 deletions core/idl/wallet/tezos/tezos_like_wallet.djinni
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ TezosOperationTag = enum {
#Class representing a Tezos transaction
TezosLikeTransaction = interface +c {
# Get type of operation (transaction, reveal ... cf TezosOperationTag)
getType(): TezosOperationTag;
const getType(): TezosOperationTag;
# Get the hash of the transaction.
getHash(): string;
const getHash(): string;
# Get the operation index in the transaction
const getOperationIndexInTransaction(): i64;
# Get the operation type in the transaction
const getOperationTypeInTransaction(): TezosOperationTag;
# Get Fees (in drop)
# It returns the sum of transaction fees and reveal fees (if it exists)
getFees(): Amount;
Expand All @@ -31,9 +35,9 @@ TezosLikeTransaction = interface +c {
getRevealFees(): Amount;

# Get destination XTZ. address
getReceiver(): optional<TezosLikeAddress>;
const getReceiver(): optional<TezosLikeAddress>;
# Get XTZ. sender address
getSender(): TezosLikeAddress;
const getSender(): TezosLikeAddress;
# Get amount of XTZ to send
getValue(): optional<Amount>;
# Serialize the transaction to its raw format.
Expand All @@ -54,10 +58,10 @@ TezosLikeTransaction = interface +c {
getStatus(): i32;
# Get the correlation id
getCorrelationId(): string;
# Set the correlation id which can be used to debug transaction errors
# through the full ledger stack
# @return the OLD Correlation ID, if it was set (empty string if it was unset)
setCorrelationId(correlationId : string) : string;
# Set the correlation id which can be used to debug transaction errors
# through the full ledger stack
# @return the OLD Correlation ID, if it was set (empty string if it was unset)
setCorrelationId(correlationId : string) : string;
}

#Class representing a Tezos Operation
Expand Down Expand Up @@ -158,9 +162,11 @@ TezosLikeAccount = interface +c {
getOriginatedAccounts(): list<TezosLikeOriginatedAccount>;
# Get current delegate
getCurrentDelegate(callback: Callback<string>);
# Get the balance of the account for a given token
# @param tokenAddress Address of the contract
getTokenBalance(tokenAddress: string, callback: Callback<BigInt>);
# Get the balance of the account for a given token
# @param tokenAddress Address of the contract
getTokenBalance(tokenAddress: string, callback: Callback<BigInt>);
# Get the deterministic operation Uid
const computeOperationUid(transaction: TezosLikeTransaction): string;
}

# Class representing originated accounts
Expand Down
3 changes: 3 additions & 0 deletions core/src/api/TezosLikeAccount.hpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions core/src/api/TezosLikeTransaction.hpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions core/src/jni/jni/TezosLikeAccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,14 @@ CJNIEXPORT void JNICALL Java_co_ledger_core_TezosLikeAccount_00024CppProxy_nativ
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
}

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

} // namespace djinni_generated
20 changes: 20 additions & 0 deletions core/src/jni/jni/TezosLikeTransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,26 @@ CJNIEXPORT jstring JNICALL Java_co_ledger_core_TezosLikeTransaction_00024CppProx
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}

CJNIEXPORT jlong JNICALL Java_co_ledger_core_TezosLikeTransaction_00024CppProxy_native_1getOperationIndexInTransaction(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
const auto& ref = ::djinni::objectFromHandleAddress<::ledger::core::api::TezosLikeTransaction>(nativeRef);
auto r = ref->getOperationIndexInTransaction();
return ::djinni::release(::djinni::I64::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}

CJNIEXPORT jobject JNICALL Java_co_ledger_core_TezosLikeTransaction_00024CppProxy_native_1getOperationTypeInTransaction(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
const auto& ref = ::djinni::objectFromHandleAddress<::ledger::core::api::TezosLikeTransaction>(nativeRef);
auto r = ref->getOperationTypeInTransaction();
return ::djinni::release(::djinni_generated::TezosOperationTag::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}

CJNIEXPORT jobject JNICALL Java_co_ledger_core_TezosLikeTransaction_00024CppProxy_native_1getFees(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
{
try {
Expand Down
33 changes: 18 additions & 15 deletions core/src/wallet/common/Operation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,37 @@ namespace ledger {
namespace core {

void Operation::refreshUid(const std::string &additional) {
std::string txId;
if (bitcoinTransaction.nonEmpty()) {
uid = OperationDatabaseHelper::createUid(accountUid, bitcoinTransaction.getValue().hash, type);
txId = computeTransactionId(bitcoinTransaction.getValue().hash);
}
else if (cosmosTransaction.nonEmpty()) {
auto final = cosmosTransaction.getValue().tx.hash;
if (!additional.empty()){
final = fmt::format("{}+{}", final, additional);
}

uid = OperationDatabaseHelper::createUid(accountUid, final, type);
txId = computeTransactionId(cosmosTransaction.getValue().tx.hash, additional);
}
else if (ethereumTransaction.nonEmpty()) {
uid = OperationDatabaseHelper::createUid(accountUid, ethereumTransaction.getValue().hash, type);
txId = computeTransactionId(ethereumTransaction.getValue().hash);
}
else if (rippleTransaction.nonEmpty()) {
uid = OperationDatabaseHelper::createUid(accountUid, rippleTransaction.getValue().hash, type);
txId = computeTransactionId(rippleTransaction.getValue().hash);
}
else if (tezosTransaction.nonEmpty()) {
auto final = fmt::format("{}+{}", tezosTransaction.getValue().hash, api::to_string(tezosTransaction.getValue().type));
if (!additional.empty()){
final = fmt::format("{}+{}", final, additional);
}
uid = OperationDatabaseHelper::createUid(accountUid, final, type);
const auto& tx = tezosTransaction.getValue();
std::string txIdBase = fmt::format("{}+{}",
tx.counter,
tx.index
);
txId = computeTransactionId(txIdBase, tx.type, additional);
} else if (stellarOperation.nonEmpty()) {
uid = OperationDatabaseHelper::createUid(accountUid, stellarOperation.getValue().operation.transactionHash, type);
txId = computeTransactionId(stellarOperation.getValue().operation.transactionHash);
} else {
throw Exception(api::ErrorCode::RUNTIME_ERROR, "Cannot refresh uid of an incomplete operation.");
}

uid = OperationDatabaseHelper::createUid(accountUid, txId, type);
}

std::string Operation::computeTransactionId(const std::string& txHash, const std::string& additional){
return additional.empty() ? txHash : fmt::format("{}+{}", txHash, additional);
}

}
Expand Down
11 changes: 11 additions & 0 deletions core/src/wallet/common/Operation.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,18 @@ namespace ledger {

Operation& operator=(Operation const&) = default;
Operation& operator=(Operation&&) = default;

template <typename CoinOperationType>
static std::string computeTransactionId(const std::string& txHash, const CoinOperationType& coinOperationType, const std::string& additional = "");
static std::string computeTransactionId(const std::string& txHash, const std::string& additional = "");

};

template <typename CoinOperationType>
std::string Operation::computeTransactionId(const std::string& txHash, const CoinOperationType& coinOperationType, const std::string& additional) {
auto hashAndCoinOpType = fmt::format("{}+{}", txHash, api::to_string(coinOperationType));
return computeTransactionId(hashAndCoinOpType, additional);
}
}
}

Expand Down
67 changes: 45 additions & 22 deletions core/src/wallet/tezos/TezosLikeAccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,33 +112,35 @@ namespace ledger {
// Check if it's an operation related to an originated account
// It can be the case if we are putting transaction operations
// for originated account.
std::string originatedAccountUid;
std::string originatedAccountAddress;
if (!transaction.originatedAccountUid.empty() && !transaction.originatedAccountAddress.empty()) {
operation.amount = transaction.value;
operation.type = transaction.sender == transaction.originatedAccountAddress ? api::OperationType::SEND : api::OperationType::RECEIVE;
operation.refreshUid(transaction.originatedAccountUid);
out.push_back(operation);
result = static_cast<int>(transaction.type);
return addedAddressToKeychain;
originatedAccountUid = transaction.originatedAccountUid;
originatedAccountAddress = transaction.originatedAccountAddress;
}

if (_accountAddress == transaction.sender) {
operation.amount = transaction.value;
operation.type = api::OperationType::SEND;
operation.refreshUid();
if (transaction.type == api::TezosOperationTag::OPERATION_TAG_ORIGINATION && transaction.status == 1) {
addedAddressToKeychain = updateOriginatedAccounts(operation);
}
out.push_back(operation);
result = static_cast<int>(transaction.type);
}
std::string additional;
api::OperationType opType;
std::tie(opType, additional) = getOperationTypeAndUidAdditional(
transaction.sender,
transaction.receiver,
originatedAccountUid,
originatedAccountAddress
);

operation.amount = transaction.value;
operation.type = opType;
operation.refreshUid(additional);

if (_accountAddress == transaction.receiver) {
operation.amount = transaction.value;
operation.type = api::OperationType::RECEIVE;
operation.refreshUid();
out.push_back(operation);
result = static_cast<int>(transaction.type);
if (additional.empty() && _accountAddress == transaction.sender &&
transaction.type == api::TezosOperationTag::OPERATION_TAG_ORIGINATION && transaction.status == 1)
{
addedAddressToKeychain = updateOriginatedAccounts(operation);
}

out.push_back(operation);
result = static_cast<int>(transaction.type);

return addedAddressToKeychain;
}

Expand Down Expand Up @@ -346,5 +348,26 @@ namespace ledger {
})
.callback(getMainExecutionContext(), callback);
}

std::pair<api::OperationType, std::string> TezosLikeAccount::getOperationTypeAndUidAdditional(const std::string& sender, const std::string& receiver,
const std::string& originatedAccountId, const std::string& originatedAccountAddress) const {
const std::string& accountAddress = getAccountAddress();

if(!originatedAccountId.empty() && !originatedAccountAddress.empty()) {
if(originatedAccountAddress == sender) {
return std::make_pair(api::OperationType::SEND, originatedAccountId);
}
if(originatedAccountAddress == receiver) {
return std::make_pair(api::OperationType::RECEIVE, originatedAccountId);
}
}
if(accountAddress == sender) {
return std::make_pair(api::OperationType::SEND, "");
}
if(accountAddress == receiver) {
return std::make_pair(api::OperationType::RECEIVE, "");
}
throw make_exception(api::ErrorCode::RUNTIME_ERROR, "Failed to determine the operation type for computing the operation id");
}
}
}
7 changes: 7 additions & 0 deletions core/src/wallet/tezos/TezosLikeAccount.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,22 @@ namespace ledger {

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

const std::string& getAccountAddress() const;

/// Return a common trace prefix for logs
/// TODO: Upstream tracePrefix() to AbstractAccount and use that everywhere
std::string tracePrefix() const;

std::string computeOperationUid(const std::shared_ptr<api::TezosLikeTransaction> & transaction) const override;

private:
std::shared_ptr<TezosLikeAccount> getSelf();
void broadcastRawTransaction(const std::vector<uint8_t> &transaction,
const std::shared_ptr<api::StringCallback> &callback,
const std::string& correlationId);

std::pair<api::OperationType, std::string> getOperationTypeAndUidAdditional(const std::string& sender, const std::string& receiver, const std::string& originatedAccountId, const std::string& originatedAccountAddress) const;

std::shared_ptr<TezosLikeKeychain> _keychain;
std::string _accountAddress;
std::shared_ptr<TezosLikeBlockchainExplorer> _explorer;
Expand Down
Loading

0 comments on commit 5263347

Please sign in to comment.