From 662cf8d24d22efa725298e866ab03b9dc9be0120 Mon Sep 17 00:00:00 2001 From: striderDM <51991544+StriderDM@users.noreply.github.com> Date: Thu, 2 Sep 2021 17:13:38 +0200 Subject: [PATCH] fix: resolved design flaw in wallet_ffi library Exposed TariTransactionKernel instead of TariExcess, TariExcessSignature and TariExcessPublicNonce. This was done as they are all referring to fields from the same object and also to reduce the amount of wrapper classes needs on the other side of the FFI boundary. Added accessor methods to retrieve data from the opaque pointer for TariTransactionKernel and return the data as a type (in this instance a cstring) which can safely cross the FFI boundary. Updated library header. Updated rust tests. Updated cucumber tests. Updated comments. Incremented library version. Fix typo --- .circleci/config.yml | 6 +- Cargo.lock | 2 +- base_layer/wallet_ffi/Cargo.toml | 2 +- base_layer/wallet_ffi/src/lib.rs | 299 ++++++++---------- base_layer/wallet_ffi/wallet.h | 31 +- integration_tests/features/WalletFFI.feature | 3 +- integration_tests/features/support/steps.js | 26 +- integration_tests/features/support/world.js | 6 +- .../helpers/ffi/completedTransaction.js | 7 + integration_tests/helpers/ffi/ffiInterface.js | 120 +++---- .../helpers/ffi/transactionKernel.js | 57 ++++ 11 files changed, 295 insertions(+), 264 deletions(-) create mode 100644 integration_tests/helpers/ffi/transactionKernel.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 7437a00cfd..72841f0fd4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -127,11 +127,7 @@ commands: name: Generate report command: cd integration_tests && node ./generate_report.js when: always - #- run: - # name: Set the correct Node version for wallet FFI tests - # shell: bash -l {0} - # command: nvm install v12.22.6 && nvm use v12.22.6 && cd integration_tests && npm install - # when: always + # Below step requires NodeJS v12 to run correctly, see explanation in WalletFFI.feature - run: name: Run FFI wallet library cucumber scenarios command: cd integration_tests && mkdir -p cucumber_output && node_modules/.bin/cucumber-js --tags "not @long-running and not @broken and not @flaky and @wallet-ffi" --format json:cucumber_output/tests_ffi.cucumber --exit diff --git a/Cargo.lock b/Cargo.lock index 9e3fb4ab6c..d5a2386024 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5049,7 +5049,7 @@ dependencies = [ [[package]] name = "tari_wallet_ffi" -version = "0.17.5" +version = "0.17.6" dependencies = [ "chrono", "env_logger 0.7.1", diff --git a/base_layer/wallet_ffi/Cargo.toml b/base_layer/wallet_ffi/Cargo.toml index ee284c158f..a49a3e923c 100644 --- a/base_layer/wallet_ffi/Cargo.toml +++ b/base_layer/wallet_ffi/Cargo.toml @@ -3,7 +3,7 @@ name = "tari_wallet_ffi" authors = ["The Tari Development Community"] description = "Tari cryptocurrency wallet C FFI bindings" license = "BSD-3-Clause" -version = "0.17.5" +version = "0.17.6" edition = "2018" [dependencies] diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index 1f85e33d06..56b403311a 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -211,9 +211,7 @@ pub type TariTransportType = tari_p2p::transport::TransportType; pub type TariPublicKey = tari_comms::types::CommsPublicKey; pub type TariPrivateKey = tari_comms::types::CommsSecretKey; pub type TariCommsConfig = tari_p2p::initialization::CommsConfig; -pub type TariExcess = tari_common_types::types::Commitment; -pub type TariExcessPublicNonce = tari_crypto::ristretto::RistrettoPublicKey; -pub type TariExcessSignature = tari_crypto::ristretto::RistrettoSecretKey; +pub type TariTransactionKernel = tari_core::transactions::transaction::TransactionKernel; pub struct TariContacts(Vec); @@ -265,6 +263,115 @@ pub unsafe extern "C" fn string_destroy(ptr: *mut c_char) { /// -------------------------------------------------------------------------------------------- /// +/// ----------------------------------- Transaction Kernel ------------------------------------- /// + +/// Gets the excess for a TariTransactionKernel +/// +/// ## Arguments +/// `x` - The pointer to a TariTransactionKernel +/// +/// ## Returns +/// `*mut c_char` - Returns a pointer to a char array. Note that it returns empty if there +/// was an error +/// +/// # Safety +/// The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak +#[no_mangle] +pub unsafe extern "C" fn transaction_kernel_get_excess_hex( + kernel: *mut TariTransactionKernel, + error_out: *mut c_int, +) -> *mut c_char { + let mut error = 0; + let mut result = CString::new("").unwrap(); + ptr::swap(error_out, &mut error as *mut c_int); + if kernel.is_null() { + error = LibWalletError::from(InterfaceError::NullError("kernel".to_string())).code; + ptr::swap(error_out, &mut error as *mut c_int); + return CString::into_raw(result); + } + let excess = (*kernel).excess.clone().to_hex(); + result = CString::new(excess).unwrap(); + result.into_raw() +} + +/// Gets the public nonce for a TariTransactionKernel +/// +/// ## Arguments +/// `x` - The pointer to a TariTransactionKernel +/// +/// ## Returns +/// `*mut c_char` - Returns a pointer to a char array. Note that it returns empty if there +/// was an error +/// +/// # Safety +/// The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak +#[no_mangle] +pub unsafe extern "C" fn transaction_kernel_get_excess_public_nonce_hex( + kernel: *mut TariTransactionKernel, + error_out: *mut c_int, +) -> *mut c_char { + let mut error = 0; + let mut result = CString::new("").unwrap(); + ptr::swap(error_out, &mut error as *mut c_int); + if kernel.is_null() { + error = LibWalletError::from(InterfaceError::NullError("kernel".to_string())).code; + ptr::swap(error_out, &mut error as *mut c_int); + return CString::into_raw(result); + } + let nonce = (*kernel).excess_sig.get_public_nonce().to_hex(); + result = CString::new(nonce).unwrap(); + result.into_raw() +} + +/// Gets the signature for a TariTransactionKernel +/// +/// ## Arguments +/// `x` - The pointer to a TariTransactionKernel +/// +/// ## Returns +/// `*mut c_char` - Returns a pointer to a char array. Note that it returns empty if there +/// was an error +/// +/// # Safety +/// The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak +#[no_mangle] +pub unsafe extern "C" fn transaction_kernel_get_excess_signature_hex( + kernel: *mut TariTransactionKernel, + error_out: *mut c_int, +) -> *mut c_char { + let mut error = 0; + ptr::swap(error_out, &mut error as *mut c_int); + let mut result = CString::new("").unwrap(); + ptr::swap(error_out, &mut error as *mut c_int); + if kernel.is_null() { + error = LibWalletError::from(InterfaceError::NullError("kernel".to_string())).code; + ptr::swap(error_out, &mut error as *mut c_int); + return CString::into_raw(result); + } + let signature = (*kernel).excess_sig.get_signature().to_hex(); + result = CString::new(signature).unwrap(); + result.into_raw() +} + +/// Frees memory for a TariTransactionKernel +/// +/// ## Arguments +/// `x` - The pointer to a TariTransactionKernel +/// +/// ## Returns +/// `()` - Does not return a value, equivalent to void in C +/// +/// # Safety +/// None +#[no_mangle] +pub unsafe extern "C" fn transaction_kernel_destroy(x: *mut TariTransactionKernel) { + if !x.is_null() { + Box::from_raw(x); + } +} + +/// -------------------------------------------------------------------------------------------- /// + /// -------------------------------- ByteVector ------------------------------------------------ /// /// Creates a ByteVector @@ -438,57 +545,6 @@ pub unsafe extern "C" fn public_key_destroy(pk: *mut TariPublicKey) { } } -/// Frees memory for a TariExcess -/// -/// ## Arguments -/// `x` - The pointer to a TariExcess -/// -/// ## Returns -/// `()` - Does not return a value, equivalent to void in C -/// -/// # Safety -/// None -#[no_mangle] -pub unsafe extern "C" fn excess_destroy(x: *mut TariExcess) { - if !x.is_null() { - Box::from_raw(x); - } -} - -/// Frees memory for a TariExcessPublicNonce -/// -/// ## Arguments -/// `r` - The pointer to a TariExcessPublicNonce -/// -/// ## Returns -/// `()` - Does not return a value, equivalent to void in C -/// -/// # Safety -/// None -#[no_mangle] -pub unsafe extern "C" fn nonce_destroy(r: *mut TariExcessPublicNonce) { - if !r.is_null() { - Box::from_raw(r); - } -} - -/// Frees memory for a TariExcessSignature -/// -/// ## Arguments -/// `s` - The pointer to a TariExcessSignature -/// -/// ## Returns -/// `()` - Does not return a value, equivalent to void in C -/// -/// # Safety -/// None -#[no_mangle] -pub unsafe extern "C" fn signature_destroy(s: *mut TariExcessSignature) { - if !s.is_null() { - Box::from_raw(s); - } -} - /// Gets a ByteVector from a TariPublicKey /// /// ## Arguments @@ -1473,7 +1529,7 @@ pub unsafe extern "C" fn completed_transaction_get_destination_public_key( Box::into_raw(Box::new(m)) } -/// Gets the TariExcess of a TariCompletedTransaction +/// Gets the TariTransactionKernel of a TariCompletedTransaction /// /// ## Arguments /// `transaction` - The pointer to a TariCompletedTransaction @@ -1481,17 +1537,18 @@ pub unsafe extern "C" fn completed_transaction_get_destination_public_key( /// as an out parameter. /// /// ## Returns -/// `*mut TariExcess` - Returns the transaction excess, note that it will be +/// `*mut TariTransactionKernel` - Returns the transaction kernel, note that it will be /// ptr::null_mut() if transaction is null, if the transaction status is Pending, or if the number of kernels is not /// exactly one. /// /// # Safety -/// The ```excess_destroy``` method must be called when finished with a TariExcess to prevent a memory leak +/// The ```transaction_kernel_destroy``` method must be called when finished with a TariTransactionKernel to prevent a +/// memory leak #[no_mangle] -pub unsafe extern "C" fn completed_transaction_get_excess( +pub unsafe extern "C" fn completed_transaction_get_transaction_kernel( transaction: *mut TariCompletedTransaction, error_out: *mut c_int, -) -> *mut TariExcess { +) -> *mut TariTransactionKernel { let mut error = 0; ptr::swap(error_out, &mut error as *mut c_int); if transaction.is_null() { @@ -1522,116 +1579,10 @@ pub unsafe extern "C" fn completed_transaction_get_excess( return ptr::null_mut(); } - let x = kernels[0].excess.clone(); + let x = kernels[0].clone(); Box::into_raw(Box::new(x)) } -/// Gets the TariExcessPublicNonce of a TariCompletedTransaction -/// -/// ## Arguments -/// `transaction` - The pointer to a TariCompletedTransaction -/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions -/// as an out parameter. -/// -/// ## Returns -/// `*mut TariExcessPublicNonce` - Returns the transaction excess public nonce, note that it will be -/// ptr::null_mut() if transaction is null, if the transaction status is Pending, or if the number of kernels is not -/// exactly one. -/// -/// # Safety -/// The ```nonce_destroy``` method must be called when finished with a TariExcessPublicNonce to prevent a memory leak -#[no_mangle] -pub unsafe extern "C" fn completed_transaction_get_public_nonce( - transaction: *mut TariCompletedTransaction, - error_out: *mut c_int, -) -> *mut TariExcessPublicNonce { - let mut error = 0; - ptr::swap(error_out, &mut error as *mut c_int); - if transaction.is_null() { - error = LibWalletError::from(InterfaceError::NullError("transaction".to_string())).code; - ptr::swap(error_out, &mut error as *mut c_int); - return ptr::null_mut(); - } - - // check the tx is not in pending state - if matches!( - (*transaction).status, - TransactionStatus::Pending | TransactionStatus::Imported - ) { - let msg = format!("Incorrect transaction status: {}", (*transaction).status); - error = LibWalletError::from(TransactionError::StatusError(msg)).code; - ptr::swap(error_out, &mut error as *mut c_int); - return ptr::null_mut(); - } - - let kernels = (*transaction).transaction.get_body().kernels(); - - // currently we presume that each CompletedTransaction only has 1 kernel - // if that changes this will need to be accounted for - if kernels.len() != 1 { - let msg = format!("Expected 1 kernel, got {}", kernels.len()); - error = LibWalletError::from(TransactionError::KernelError(msg)).code; - ptr::swap(error_out, &mut error as *mut c_int); - return ptr::null_mut(); - } - - let r = kernels[0].excess_sig.get_public_nonce().clone(); - Box::into_raw(Box::new(r)) -} - -/// Gets the TariExcessSignature of a TariCompletedTransaction -/// -/// ## Arguments -/// `transaction` - The pointer to a TariCompletedTransaction -/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions -/// as an out parameter. -/// -/// ## Returns -/// `*mut TariExcessSignature` - Returns the transaction excess signature, note that it will be -/// ptr::null_mut() if transaction is null, if the transaction status is Pending, or if the number of kernels is not -/// exactly one. -/// -/// # Safety -/// The ```signature_destroy``` method must be called when finished with a TariExcessSignature to prevent a memory leak -#[no_mangle] -pub unsafe extern "C" fn completed_transaction_get_signature( - transaction: *mut TariCompletedTransaction, - error_out: *mut c_int, -) -> *mut TariExcessSignature { - let mut error = 0; - ptr::swap(error_out, &mut error as *mut c_int); - if transaction.is_null() { - error = LibWalletError::from(InterfaceError::NullError("transaction".to_string())).code; - ptr::swap(error_out, &mut error as *mut c_int); - return ptr::null_mut(); - } - - // check the tx is not in pending state - if matches!( - (*transaction).status, - TransactionStatus::Pending | TransactionStatus::Imported - ) { - let msg = format!("Incorrect transaction status: {}", (*transaction).status); - error = LibWalletError::from(TransactionError::StatusError(msg)).code; - ptr::swap(error_out, &mut error as *mut c_int); - return ptr::null_mut(); - } - - let kernels = (*transaction).transaction.get_body().kernels(); - - // currently we presume that each CompletedTransaction only has 1 kernel - // if that changes this will need to be accounted for - if kernels.len() != 1 { - let msg = format!("Expected 1 kernel, got {}", kernels.len()); - error = LibWalletError::from(TransactionError::KernelError(msg)).code; - ptr::swap(error_out, &mut error as *mut c_int); - return ptr::null_mut(); - } - - let s = kernels[0].excess_sig.get_signature().clone(); - Box::into_raw(Box::new(s)) -} - /// Gets the source TariPublicKey of a TariCompletedTransaction /// /// ## Arguments @@ -5443,6 +5394,22 @@ mod test { assert_eq!((*tx).status, TransactionStatus::MinedUnconfirmed); let mut lock = CALLBACK_STATE_FFI.lock().unwrap(); lock.mined_tx_unconfirmed_callback_called = true; + let mut error = 0; + let error_ptr = &mut error as *mut c_int; + let kernel = completed_transaction_get_transaction_kernel(tx, error_ptr); + let excess_hex_ptr = transaction_kernel_get_excess_hex(kernel, error_ptr); + let excess_hex = CString::from_raw(excess_hex_ptr).to_str().unwrap().to_owned(); + assert!(!excess_hex.is_empty()); + let nonce_hex_ptr = transaction_kernel_get_excess_public_nonce_hex(kernel, error_ptr); + let nonce_hex = CString::from_raw(nonce_hex_ptr).to_str().unwrap().to_owned(); + assert!(!nonce_hex.is_empty()); + let sig_hex_ptr = transaction_kernel_get_excess_signature_hex(kernel, error_ptr); + let sig_hex = CString::from_raw(sig_hex_ptr).to_str().unwrap().to_owned(); + assert!(!sig_hex.is_empty()); + string_destroy(excess_hex_ptr as *mut c_char); + string_destroy(sig_hex_ptr as *mut c_char); + string_destroy(nonce_hex_ptr); + transaction_kernel_destroy(kernel); drop(lock); completed_transaction_destroy(tx); } diff --git a/base_layer/wallet_ffi/wallet.h b/base_layer/wallet_ffi/wallet.h index bd17dd613e..0dfd400482 100644 --- a/base_layer/wallet_ffi/wallet.h +++ b/base_layer/wallet_ffi/wallet.h @@ -73,11 +73,7 @@ struct TariSeedWords; struct EmojiSet; -struct TariExcess; - -struct TariExcessPublicNonce; - -struct TariExcessSignature; +struct TariTransactionKernel; /// -------------------------------- Transport Types ----------------------------------------------- /// @@ -262,26 +258,25 @@ bool completed_transaction_is_outbound(struct TariCompletedTransaction *tx, int /// Gets the number of confirmations of a TariCompletedTransaction unsigned long long completed_transaction_get_confirmations(struct TariCompletedTransaction *transaction, int *error_out); +// Gets the TariTransactionKernel of a TariCompletedTransaction +struct TariTransactionKernel *completed_transaction_get_transaction_kernel(struct TariCompletedTransaction *transaction, int *error_out); + // Frees memory for a TariCompletedTransaction void completed_transaction_destroy(struct TariCompletedTransaction *transaction); -// Gets the TariExcess of a TariCompletedTransaction -struct TariExcess *completed_transaction_get_excess(struct TariCompletedTransaction *transaction, int *error_out); - -// Gets the TariExcessPublicNonce of a TariCompletedTransaction -struct TariExcessPublicNonce *completed_transaction_get_public_nonce(struct TariCompletedTransaction *transaction, int *error_out); +/// --------------------------------------- TransactionKernel ------------------------------------------------------ /// -// Gets the TariExcessSignature of a TariCompletedTransaction -struct TariExcessSignature *completed_transaction_get_signature(struct TariCompletedTransaction *transaction, int *error_out); +// Gets the excess for a TariTransactionKernel +const char *transaction_kernel_get_excess_hex(struct TariTransactionKernel *kernel, int *error_out); -// Frees memory for a TariExcess -void excess_destroy(struct TariExcess *excess); +// Gets the public nonce for a TariTransactionKernel +const char *transaction_kernel_get_excess_public_nonce_hex(struct TariTransactionKernel *kernel, int *error_out); -// Frees memory for a TariExcessPublicNonce -void nonce_destroy(struct TariExcessPublicNonce *nonce); +// Gets the signature for a TariTransactionKernel +const char *transaction_kernel_get_excess_signature_hex(struct TariTransactionKernel *kernel, int *error_out); -// Frees memory for a TariExcessSignature -void signature_destroy(struct TariExcessSignature *signature); +// Frees memory for a TariTransactionKernel +void transaction_kernel_destroy(struct TariTransactionKernel *kernel); /// -------------------------------- CompletedTransactions ------------------------------------------------------ /// diff --git a/integration_tests/features/WalletFFI.feature b/integration_tests/features/WalletFFI.feature index 729c7480c5..524789a87b 100644 --- a/integration_tests/features/WalletFFI.feature +++ b/integration_tests/features/WalletFFI.feature @@ -6,10 +6,10 @@ Feature: Wallet FFI # https://github.com/nodejs/node/issues/32463 # https://github.com/node-ffi-napi/node-ffi-napi/issues/97 - # It's just calling the encrypt function, we don't test if it's actually encrypted Scenario: As a client I want to be able to protect my wallet with a passphrase Given I have a base node BASE And I have a ffi wallet FFI_WALLET connected to base node BASE + # It's just calling the encrypt function, we don't test if it's actually encrypted And I set passphrase PASSPHRASE of ffi wallet FFI_WALLET And I stop ffi wallet FFI_WALLET @@ -90,6 +90,7 @@ Feature: Wallet FFI And mining node MINER mines 10 blocks Then I wait for wallet RECEIVER to have at least 1000000 uT And I have 1 received and 1 send transaction in ffi wallet FFI_WALLET + Then I want to view the transaction kernels for completed transactions in ffi wallet FFI_WALLET And I start STXO validation on ffi wallet FFI_WALLET And I start UTXO validation on ffi wallet FFI_WALLET And I stop ffi wallet FFI_WALLET diff --git a/integration_tests/features/support/steps.js b/integration_tests/features/support/steps.js index f5208193c1..413d5f6092 100644 --- a/integration_tests/features/support/steps.js +++ b/integration_tests/features/support/steps.js @@ -4033,7 +4033,31 @@ Then( } ); -When(/I stop ffi wallet (.*)/, function (walletName) { +Then( + "I want to view the transaction kernels for completed transactions in ffi wallet {word}", + { timeout: 20 * 1000 }, + function (name) { + let ffi_wallet = this.getWallet(name); + let transactions = ffi_wallet.getCompletedTxs(); + let length = transactions.getLength(); + expect(length > 0).to.equal(true); + for (let i = 0; i < length; i++) { + let tx = transactions.getAt(i); + let kernel = tx.getKernel(); + let data = kernel.asObject(); + console.log("Transaction kernel info:"); + console.log(data); + expect(data.excess.length > 0).to.equal(true); + expect(data.nonce.length > 0).to.equal(true); + expect(data.sig.length > 0).to.equal(true); + kernel.destroy(); + tx.destroy(); + } + transactions.destroy(); + } +); + +When("I stop ffi wallet {word}", function (walletName) { let wallet = this.getWallet(walletName); wallet.stop(); wallet.resetCounters(); diff --git a/integration_tests/features/support/world.js b/integration_tests/features/support/world.js index 44c7dddd44..833b681138 100644 --- a/integration_tests/features/support/world.js +++ b/integration_tests/features/support/world.js @@ -384,8 +384,12 @@ BeforeAll({ timeout: 1200000 }, async function () { console.log("Compiling wallet FFI..."); await InterfaceFFI.compile(); - await InterfaceFFI.init(); console.log("Finished compilation."); + console.log("Loading FFI interface.."); + await InterfaceFFI.init(); + console.log("FFI interface loaded."); + + console.log("World ready, now lets run some tests! :)"); }); After(async function (testCase) { diff --git a/integration_tests/helpers/ffi/completedTransaction.js b/integration_tests/helpers/ffi/completedTransaction.js index 6e0605bcbe..8d0defdeb3 100644 --- a/integration_tests/helpers/ffi/completedTransaction.js +++ b/integration_tests/helpers/ffi/completedTransaction.js @@ -1,5 +1,6 @@ const InterfaceFFI = require("./ffiInterface"); const PublicKey = require("./publicKey"); +const TransactionKernel = require("./transactionKernel"); class CompletedTransaction { ptr; @@ -69,6 +70,12 @@ class CompletedTransaction { return InterfaceFFI.completedTransactionGetConfirmations(this.ptr); } + getKernel() { + let result = new TransactionKernel(); + result.pointerAssign(InterfaceFFI.completedTransactionGetKernel(this.ptr)); + return result; + } + destroy() { if (this.ptr) { InterfaceFFI.completedTransactionDestroy(this.ptr); diff --git a/integration_tests/helpers/ffi/ffiInterface.js b/integration_tests/helpers/ffi/ffiInterface.js index fd724cb55d..e2f19f69ee 100644 --- a/integration_tests/helpers/ffi/ffiInterface.js +++ b/integration_tests/helpers/ffi/ffiInterface.js @@ -155,27 +155,29 @@ class InterfaceFFI { [this.ptr, this.intPtr], ], completed_transaction_destroy: [this.void, [this.ptr]], - //completed_transaction_get_excess: [ - //this.tari_excess_ptr, - // [this.tari_completed_transaction_ptr, this.intPtr], - //], - //completed_transaction_get_public_nonce: [ - // this.tari_excess_public_nonce_ptr, - // [this.tari_completed_transaction_ptr, this.intPtr], - //], - //completed_transaction_get_signature: [ - // this.tari_excess_signature_ptr, - // [this.tari_completed_transaction_ptr, this.intPtr], - //], - // excess_destroy: [this.void, [this.tari_excess_ptr]], - // nonce_destroy: [this.void, [this.tari_excess_public_nonce_ptr]], - // signature_destroy: [this.void, [this.tari_excess_signature_ptr]], + completed_transaction_get_transaction_kernel: [ + this.ptr, + [this.ptr, this.intPtr], + ], completed_transactions_get_length: [this.uint, [this.ptr, this.intPtr]], completed_transactions_get_at: [ this.ptr, [this.ptr, this.uint, this.intPtr], ], completed_transactions_destroy: [this.void, [this.ptr]], + transaction_kernel_get_excess_hex: [ + this.stringPtr, + [this.ptr, this.intPtr], + ], + transaction_kernel_get_excess_public_nonce_hex: [ + this.stringPtr, + [this.ptr, this.intPtr], + ], + transaction_kernel_get_excess_signature_hex: [ + this.stringPtr, + [this.ptr, this.intPtr], + ], + transaction_kernel_destroy: [this.void, [this.ptr]], pending_outbound_transaction_get_transaction_id: [ this.ulonglong, [this.ptr, this.intPtr], @@ -847,76 +849,54 @@ class InterfaceFFI { return result; } + static completedTransactionGetKernel(ptr) { + let error = this.initError(); + let result = this.fn.completed_transaction_get_transaction_kernel( + ptr, + error + ); + this.checkErrorResult(error, `completedTransactionGetConfirmations`); + return result; + } + static completedTransactionDestroy(ptr) { this.fn.completed_transaction_destroy(ptr); } //endregion - /* - //Flagged as design flaw in the FFI lib - - static completedTransactionGetExcess(transaction) { - return new Promise((resolve, reject) => - this.fn.completed_transaction_get_excess.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionGetExcess") - ) - ); - } - - static completedTransactionGetPublicNonce(transaction) { - return new Promise((resolve, reject) => - this.fn.completed_transaction_get_public_nonce.async( - transaction, - this.error, - this.checkAsyncRes( - resolve, - reject, - "completedTransactionGetPublicNonce" - ) - ) - ); - } - - static completedTransactionGetSignature(transaction) { - return new Promise((resolve, reject) => - this.fn.completed_transaction_get_signature.async( - transaction, - this.error, - this.checkAsyncRes(resolve, reject, "completedTransactionGetSignature") - ) - ); + //region TransactionKernel + static transactionKernelGetExcess(ptr) { + let error = this.initError(); + let result = this.fn.transaction_kernel_get_excess_hex(ptr, error); + this.checkErrorResult(error, `completedTransactionGetConfirmations`); + return result; } - static excessDestroy(excess) { - return new Promise((resolve, reject) => - this.fn.excess_destroy.async( - excess, - this.checkAsyncRes(resolve, reject, "excessDestroy") - ) + static transactionKernelGetExcessPublicNonce(ptr) { + let error = this.initError(); + let result = this.fn.transaction_kernel_get_excess_public_nonce_hex( + ptr, + error ); + this.checkErrorResult(error, `completedTransactionGetConfirmations`); + return result; } - static nonceDestroy(nonce) { - return new Promise((resolve, reject) => - this.fn.nonce_destroy.async( - nonce, - this.checkAsyncRes(resolve, reject, "nonceDestroy") - ) + static transactionKernelGetExcessSigntature(ptr) { + let error = this.initError(); + let result = this.fn.transaction_kernel_get_excess_signature_hex( + ptr, + error ); + this.checkErrorResult(error, `completedTransactionGetConfirmations`); + return result; } - static signatureDestroy(signature) { - return new Promise((resolve, reject) => - this.fn.signature_destroy.async( - signature, - this.checkAsyncRes(resolve, reject, "signatureDestroy") - ) - ); + static transactionKernelDestroy(ptr) { + this.fn.transaction_kernel_destroy(ptr); } - */ + //endRegion //region CompletedTransactions (List) static completedTransactionsGetLength(ptr) { diff --git a/integration_tests/helpers/ffi/transactionKernel.js b/integration_tests/helpers/ffi/transactionKernel.js new file mode 100644 index 0000000000..47c68f42e4 --- /dev/null +++ b/integration_tests/helpers/ffi/transactionKernel.js @@ -0,0 +1,57 @@ +const InterfaceFFI = require("./ffiInterface"); + +class CompletedTransactionKernel { + ptr; + + pointerAssign(ptr) { + // Prevent pointer from being leaked in case of re-assignment + if (this.ptr) { + this.destroy(); + this.ptr = ptr; + } else { + this.ptr = ptr; + } + } + + getPtr() { + return this.ptr; + } + + getExcess() { + let strPtr = InterfaceFFI.transactionKernelGetExcess(this.ptr); + let result = strPtr.readCString(); + InterfaceFFI.stringDestroy(strPtr); + return result; + } + + getNonce() { + let strPtr = InterfaceFFI.transactionKernelGetExcessPublicNonce(this.ptr); + let result = strPtr.readCString(); + InterfaceFFI.stringDestroy(strPtr); + return result; + } + + getSignature() { + let strPtr = InterfaceFFI.transactionKernelGetExcessSigntature(this.ptr); + let result = strPtr.readCString(); + InterfaceFFI.stringDestroy(strPtr); + return result; + } + + asObject() { + return { + excess: this.getExcess(), + nonce: this.getNonce(), + sig: this.getSignature(), + }; + } + + destroy() { + if (this.ptr) { + InterfaceFFI.transactionKernelDestroy(this.ptr); + this.ptr = undefined; //prevent double free segfault + } + } +} + +module.exports = CompletedTransactionKernel;