Skip to content

Commit

Permalink
fix: update cucumber tests for walletffi.feature (#3275)
Browse files Browse the repository at this point in the history
Description
Made types more explicit for ffi interface and easier to maintain going forwards.
Initialized InterfaceFFI in world rather than WalletFFIClient.
Updated steps in WalletFFI.feature
Updated some const variables in wrapper classes to be let.
Better handling of callback function pointer variables in wallet.
Added additional steps to tests.
Downgrade code to be compatible with nodejs v12.

Motivation and Context


How Has This Been Tested?
nvm use v12.22.6 && ./node_modules/.bin/cucumber-js features/WalletFFI.feature

Run log:
[run.log](https://github.com/tari-project/tari/files/7097096/run.log)


NodeJS version downgrade:
tari-labs/docker#16
StriderDM authored Sep 2, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent cedb1d4 commit 38191d3
Showing 24 changed files with 982 additions and 838 deletions.
8 changes: 7 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -127,9 +127,15 @@ 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
- run:
name: Run ffi cucumber scenarios
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
when: always
- run:
name: Generate report (ffi)
command: cd integration_tests && node ./generate_report.js "cucumber_output/tests_ffi.cucumber" "temp/reports/cucumber_ffi_report.html"
2 changes: 1 addition & 1 deletion Cargo.lock

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

32 changes: 21 additions & 11 deletions integration_tests/features/WalletFFI.feature
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
@wallet-ffi
Feature: Wallet FFI
# Increase heap memory available to nodejs if frequent crashing occurs with
# error being be similar to this: `0x1a32cd5 V8_Fatal(char const*, ...)`
# Appears to run in NodeJS v12 consistently on mac (5 crash-less runs in a row).
# Crashes in v14+ intermittently on mac (more frequently than not) and completely broken on Linux.
# See issues:
# 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
@@ -35,11 +38,12 @@ Feature: Wallet FFI
And I stop ffi wallet FFI_WALLET
And I stop node BASE1
And I wait 5 seconds
And I restart ffi wallet FFI_WALLET
# Possibly check SAF messages, no way to get current connected base node peer from the library itself afaik
# Good idea just to add a fn to do this to the library.
# Then I wait for ffi wallet FFI_WALLET to receive 1 SAF message
And I wait 5 seconds
# Broken step with reason base node is not persisted
# See details on:
# Scenario: As a client I want to receive Tari via my Public Key sent while I am offline when I come back online
# And I restart ffi wallet FFI_WALLET
And I restart ffi wallet FFI_WALLET connected to base node BASE2
Then I wait for ffi wallet FFI_WALLET to receive at least 1 SAF message
And I stop ffi wallet FFI_WALLET

Scenario: As a client I want to cancel a transaction
@@ -101,12 +105,18 @@ Feature: Wallet FFI
And I wait 10 seconds
And I send 2000000 uT from wallet SENDER to wallet FFI_WALLET at fee 100
And I wait 5 seconds
And I restart ffi wallet FFI_WALLET
# Broken step with reason base node is not persisted
# Log:
# [wallet::transaction_service::callback_handler] DEBUG Calling Received Finalized Transaction callback function for TxId: 7595706993517535281
# [wallet::transaction_service::service] WARN Error broadcasting completed transaction TxId: 7595706993517535281 to mempool: NoBaseNodeKeysProvided
# And I restart ffi wallet FFI_WALLET
And I restart ffi wallet FFI_WALLET connected to base node BASE
Then I wait for ffi wallet FFI_WALLET to receive 1 transaction
Then I wait for ffi wallet FFI_WALLET to receive 1 finalization
# Assume tx will be mined to reduce time taken for test, balance is tested in later scenarios.
# And mining node MINER mines 10 blocks
# Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT
Then I wait for ffi wallet FFI_WALLET to receive 1 broadcast
And mining node MINER mines 10 blocks
Then I wait for ffi wallet FFI_WALLET to receive 1 mined
Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT
And I stop ffi wallet FFI_WALLET

# Scenario: As a client I want to get my balance
155 changes: 111 additions & 44 deletions integration_tests/features/support/steps.js
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ const {
consoleLogBalance,
consoleLogTransactionDetails,
withTimeout,
waitForIterate,
} = require("../../helpers/util");
const { ConnectivityStatus, PaymentType } = require("../../helpers/types");
const TransactionBuilder = require("../../helpers/transactionBuilder");
@@ -3538,19 +3539,6 @@ When(
}
);

Then(
"I want to get public key of ffi wallet {word}",
{ timeout: 20 * 1000 },
function (name) {
let wallet = this.getWallet(name);
let public_key = wallet.identify();
expect(public_key.length).to.be.equal(
64,
`Public key has wrong length : ${public_key}`
);
}
);

Then(
"I want to get emoji id of ffi wallet {word}",
{ timeout: 20 * 1000 },
@@ -3826,14 +3814,13 @@ Then(
"Waiting for " + wallet_name + " to receive " + amount + " transaction(s)"
);

await waitFor(
async () => {
await waitForIterate(
() => {
return wallet.getCounters().received >= amount;
},
true,
700 * 1000,
5 * 1000,
5
1000,
700
);

if (!(wallet.getCounters().received >= amount)) {
@@ -3860,14 +3847,13 @@ Then(
" transaction finalization(s)"
);

await waitFor(
async () => {
await waitForIterate(
() => {
return wallet.getCounters().finalized >= amount;
},
true,
700 * 1000,
5 * 1000,
5
1000,
700
);

if (!(wallet.getCounters().finalized >= amount)) {
@@ -3880,7 +3866,7 @@ Then(
);

Then(
/I wait for ffi wallet (.*) to receive (.*) SAF message/,
/I wait for ffi wallet (.*) to receive (.*) broadcast/,
{ timeout: 710 * 1000 },
async function (wallet_name, amount) {
let wallet = this.getWallet(wallet_name);
@@ -3891,17 +3877,82 @@ Then(
wallet_name +
" to receive " +
amount +
" transaction broadcast(s)"
);

await waitForIterate(
() => {
return wallet.getCounters().broadcast >= amount;
},
true,
1000,
700
);

if (!(wallet.getCounters().broadcast >= amount)) {
console.log("Counter not adequate!");
} else {
console.log(wallet.getCounters());
}
expect(wallet.getCounters().broadcast >= amount).to.equal(true);
}
);

Then(
/I wait for ffi wallet (.*) to receive (.*) mined/,
{ timeout: 710 * 1000 },
async function (wallet_name, amount) {
let wallet = this.getWallet(wallet_name);

console.log("\n");
console.log(
"Waiting for " +
wallet_name +
" to receive " +
amount +
" transaction mined"
);

await waitForIterate(
() => {
return wallet.getCounters().mined >= amount;
},
true,
1000,
700
);

if (!(wallet.getCounters().mined >= amount)) {
console.log("Counter not adequate!");
} else {
console.log(wallet.getCounters());
}
expect(wallet.getCounters().mined >= amount).to.equal(true);
}
);

Then(
/I wait for ffi wallet (.*) to receive at least (.*) SAF message/,
{ timeout: 710 * 1000 },
async function (wallet_name, amount) {
let wallet = this.getWallet(wallet_name);

console.log("\n");
console.log(
"Waiting for " +
wallet_name +
" to receive at least " +
amount +
" SAF messages(s)"
);

await waitFor(
async () => {
await waitForIterate(
() => {
return wallet.getCounters().saf >= amount;
},
true,
700 * 1000,
5 * 1000,
5
1000,
700
);

if (!(wallet.getCounters().saf >= amount)) {
@@ -3924,23 +3975,21 @@ Then(
"Waiting for " + wallet_name + " balance to be at least " + amount + " uT"
);

let count = 0;

while (!(wallet.getBalance().available >= amount)) {
await sleep(1000);
count++;
if (count > 700) {
break;
}
}
await waitForIterate(
() => {
return wallet.getBalance().available >= amount;
},
true,
1000,
700
);

let balance = wallet.getBalance().available;

if (!(balance >= amount)) {
console.log("Balance not adequate!");
} else {
console.log(wallet.getBalance());
}

expect(balance >= amount).to.equal(true);
}
);
@@ -3961,10 +4010,28 @@ When(/I start ffi wallet (.*)/, async function (walletName) {
await wallet.startNew(null, null);
});

When(/I restart ffi wallet (.*)/, async function (walletName) {
let wallet = this.getWallet(walletName);
await wallet.restart();
});
When(
/I restart ffi wallet (.*) connected to base node (.*)/,
async function (walletName, node) {
let wallet = this.getWallet(walletName);
await wallet.restart();
let peer = this.nodes[node].peerAddress().split("::");
wallet.addBaseNodePeer(peer[0], peer[1]);
}
);

Then(
"I want to get public key of ffi wallet {word}",
{ timeout: 20 * 1000 },
function (name) {
let wallet = this.getWallet(name);
let public_key = wallet.identify();
expect(public_key.length).to.be.equal(
64,
`Public key has wrong length : ${public_key}`
);
}
);

When(/I stop ffi wallet (.*)/, function (walletName) {
let wallet = this.getWallet(walletName);
5 changes: 4 additions & 1 deletion integration_tests/features/support/world.js
Original file line number Diff line number Diff line change
@@ -9,6 +9,8 @@ const TransactionBuilder = require("../../helpers/transactionBuilder");
const glob = require("glob");
const fs = require("fs");
const archiver = require("archiver");
const InterfaceFFI = require("../../helpers/ffi/ffiInterface");

class CustomWorld {
constructor({ attach, parameters }) {
// this.variable = 0;
@@ -381,7 +383,8 @@ BeforeAll({ timeout: 1200000 }, async function () {
await miningNode.compile();

console.log("Compiling wallet FFI...");
await WalletFFIClient.Init();
await InterfaceFFI.compile();
await InterfaceFFI.init();
console.log("Finished compilation.");
});

20 changes: 10 additions & 10 deletions integration_tests/helpers/ffi/byteVector.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
const InterfaceFFI = require("./ffiInterface");

class ByteVector {
#byte_vector_ptr;
ptr;

pointerAssign(ptr) {
// Prevent pointer from being leaked in case of re-assignment
if (this.#byte_vector_ptr) {
if (this.ptr) {
this.destroy();
this.#byte_vector_ptr = ptr;
this.ptr = ptr;
} else {
this.#byte_vector_ptr = ptr;
this.ptr = ptr;
}
}

@@ -30,21 +30,21 @@ class ByteVector {
}

getLength() {
return InterfaceFFI.byteVectorGetLength(this.#byte_vector_ptr);
return InterfaceFFI.byteVectorGetLength(this.ptr);
}

getAt(position) {
return InterfaceFFI.byteVectorGetAt(this.#byte_vector_ptr, position);
return InterfaceFFI.byteVectorGetAt(this.ptr, position);
}

getPtr() {
return this.#byte_vector_ptr;
return this.ptr;
}

destroy() {
if (this.#byte_vector_ptr) {
InterfaceFFI.byteVectorDestroy(this.#byte_vector_ptr);
this.#byte_vector_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.byteVectorDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
12 changes: 6 additions & 6 deletions integration_tests/helpers/ffi/commsConfig.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ const InterfaceFFI = require("./ffiInterface");
const utf8 = require("utf8");

class CommsConfig {
#comms_config_ptr;
ptr;

constructor(
public_address,
@@ -17,7 +17,7 @@ class CommsConfig {
let sanitize_db_name = utf8.encode(database_name);
let sanitize_db_path = utf8.encode(datastore_path);
let sanitize_network = utf8.encode(network);
this.#comms_config_ptr = InterfaceFFI.commsConfigCreate(
this.ptr = InterfaceFFI.commsConfigCreate(
sanitize_address,
transport_ptr,
sanitize_db_name,
@@ -29,13 +29,13 @@ class CommsConfig {
}

getPtr() {
return this.#comms_config_ptr;
return this.ptr;
}

destroy() {
if (this.#comms_config_ptr) {
InterfaceFFI.commsConfigDestroy(this.#comms_config_ptr);
this.#comms_config_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.commsConfigDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
62 changes: 19 additions & 43 deletions integration_tests/helpers/ffi/completedTransaction.js
Original file line number Diff line number Diff line change
@@ -2,101 +2,77 @@ const InterfaceFFI = require("./ffiInterface");
const PublicKey = require("./publicKey");

class CompletedTransaction {
#tari_completed_transaction_ptr;
ptr;

pointerAssign(ptr) {
if (this.#tari_completed_transaction_ptr) {
if (this.ptr) {
this.destroy();
this.#tari_completed_transaction_ptr = ptr;
this.ptr = ptr;
} else {
this.#tari_completed_transaction_ptr = ptr;
this.ptr = ptr;
}
}

getPtr() {
return this.#tari_completed_transaction_ptr;
return this.ptr;
}

isOutbound() {
return InterfaceFFI.completedTransactionIsOutbound(
this.#tari_completed_transaction_ptr
);
return InterfaceFFI.completedTransactionIsOutbound(this.ptr);
}

getDestinationPublicKey() {
let result = new PublicKey();
result.pointerAssign(
InterfaceFFI.completedTransactionGetDestinationPublicKey(
this.#tari_completed_transaction_ptr
)
InterfaceFFI.completedTransactionGetDestinationPublicKey(this.ptr)
);
return result;
}

getSourcePublicKey() {
let result = new PublicKey();
result.pointerAssign(
InterfaceFFI.completedTransactionGetSourcePublicKey(
this.#tari_completed_transaction_ptr
)
InterfaceFFI.completedTransactionGetSourcePublicKey(this.ptr)
);
return result;
}

getAmount() {
return InterfaceFFI.completedTransactionGetAmount(
this.#tari_completed_transaction_ptr
);
return InterfaceFFI.completedTransactionGetAmount(this.ptr);
}

getFee() {
return InterfaceFFI.completedTransactionGetFee(
this.#tari_completed_transaction_ptr
);
return InterfaceFFI.completedTransactionGetFee(this.ptr);
}

getMessage() {
return InterfaceFFI.completedTransactionGetMessage(
this.#tari_completed_transaction_ptr
);
return InterfaceFFI.completedTransactionGetMessage(this.ptr);
}

getStatus() {
return InterfaceFFI.completedTransactionGetStatus(
this.#tari_completed_transaction_ptr
);
return InterfaceFFI.completedTransactionGetStatus(this.ptr);
}

getTransactionID() {
return InterfaceFFI.completedTransactionGetTransactionId(
this.#tari_completed_transaction_ptr
);
return InterfaceFFI.completedTransactionGetTransactionId(this.ptr);
}

getTimestamp() {
return InterfaceFFI.completedTransactionGetTimestamp(
this.#tari_completed_transaction_ptr
);
return InterfaceFFI.completedTransactionGetTimestamp(this.ptr);
}

isValid() {
return InterfaceFFI.completedTransactionIsValid(
this.#tari_completed_transaction_ptr
);
return InterfaceFFI.completedTransactionIsValid(this.ptr);
}

getConfirmations() {
return InterfaceFFI.completedTransactionGetConfirmations(
this.#tari_completed_transaction_ptr
);
return InterfaceFFI.completedTransactionGetConfirmations(this.ptr);
}

destroy() {
if (this.#tari_completed_transaction_ptr) {
InterfaceFFI.completedTransactionDestroy(
this.#tari_completed_transaction_ptr
);
this.#tari_completed_transaction_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.completedTransactionDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
21 changes: 7 additions & 14 deletions integration_tests/helpers/ffi/completedTransactions.js
Original file line number Diff line number Diff line change
@@ -2,35 +2,28 @@ const CompletedTransaction = require("./completedTransaction");
const InterfaceFFI = require("./ffiInterface");

class CompletedTransactions {
#tari_completed_transactions_ptr;
ptr;

constructor(ptr) {
this.#tari_completed_transactions_ptr = ptr;
this.ptr = ptr;
}

getLength() {
return InterfaceFFI.completedTransactionsGetLength(
this.#tari_completed_transactions_ptr
);
return InterfaceFFI.completedTransactionsGetLength(this.ptr);
}

getAt(position) {
let result = new CompletedTransaction();
result.pointerAssign(
InterfaceFFI.completedTransactionsGetAt(
this.#tari_completed_transactions_ptr,
position
)
InterfaceFFI.completedTransactionsGetAt(this.ptr, position)
);
return result;
}

destroy() {
if (this.#tari_completed_transactions_ptr) {
InterfaceFFI.completedTransactionsDestroy(
this.#tari_completed_transactions_ptr
);
this.#tari_completed_transactions_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.completedTransactionsDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
26 changes: 12 additions & 14 deletions integration_tests/helpers/ffi/contact.js
Original file line number Diff line number Diff line change
@@ -2,50 +2,48 @@ const PublicKey = require("./publicKey");
const InterfaceFFI = require("./ffiInterface");

class Contact {
#tari_contact_ptr;
ptr;

pointerAssign(ptr) {
// Prevent pointer from being leaked in case of re-assignment
if (this.#tari_contact_ptr) {
if (this.ptr) {
this.destroy();
this.#tari_contact_ptr = ptr;
this.ptr = ptr;
} else {
this.#tari_contact_ptr = ptr;
this.ptr = ptr;
}
}

getPtr() {
return this.#tari_contact_ptr;
return this.ptr;
}

getAlias() {
const alias = InterfaceFFI.contactGetAlias(this.#tari_contact_ptr);
const result = alias.readCString();
let alias = InterfaceFFI.contactGetAlias(this.ptr);
let result = alias.readCString();
InterfaceFFI.stringDestroy(alias);
return result;
}

getPubkey() {
let result = new PublicKey();
result.pointerAssign(
InterfaceFFI.contactGetPublicKey(this.#tari_contact_ptr)
);
result.pointerAssign(InterfaceFFI.contactGetPublicKey(this.ptr));
return result;
}

getPubkeyHex() {
let result = "";
let pk = new PublicKey();
pk.pointerAssign(InterfaceFFI.contactGetPublicKey(this.#tari_contact_ptr));
pk.pointerAssign(InterfaceFFI.contactGetPublicKey(this.ptr));
result = pk.getHex();
pk.destroy();
return result;
}

destroy() {
if (this.#tari_contact_ptr) {
InterfaceFFI.contactDestroy(this.#tari_contact_ptr);
this.#tari_contact_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.contactDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
16 changes: 7 additions & 9 deletions integration_tests/helpers/ffi/contacts.js
Original file line number Diff line number Diff line change
@@ -2,28 +2,26 @@ const Contact = require("./contact");
const InterfaceFFI = require("./ffiInterface");

class Contacts {
#tari_contacts_ptr;
ptr;

constructor(ptr) {
this.#tari_contacts_ptr = ptr;
this.ptr = ptr;
}

getLength() {
return InterfaceFFI.contactsGetLength(this.#tari_contacts_ptr);
return InterfaceFFI.contactsGetLength(this.ptr);
}

getAt(position) {
let result = new Contact();
result.pointerAssign(
InterfaceFFI.contactsGetAt(this.#tari_contacts_ptr, position)
);
result.pointerAssign(InterfaceFFI.contactsGetAt(this.ptr, position));
return result;
}

destroy() {
if (this.#tari_contacts_ptr) {
InterfaceFFI.contactsDestroy(this.#tari_contacts_ptr);
this.#tari_contacts_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.contactsDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
14 changes: 7 additions & 7 deletions integration_tests/helpers/ffi/emojiSet.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
const InterfaceFFI = require("./ffiInterface");

class EmojiSet {
#emoji_set_ptr;
ptr;

constructor() {
this.#emoji_set_ptr = InterfaceFFI.getEmojiSet();
this.ptr = InterfaceFFI.getEmojiSet();
}

getLength() {
return InterfaceFFI.emojiSetGetLength(this.#emoji_set_ptr);
return InterfaceFFI.emojiSetGetLength(this.ptr);
}

getAt(position) {
return InterfaceFFI.emojiSetGetAt(this.#emoji_set_ptr, position);
return InterfaceFFI.emojiSetGetAt(this.ptr, position);
}

list() {
@@ -26,9 +26,9 @@ class EmojiSet {
}

destroy() {
if (this.#emoji_set_ptr) {
InterfaceFFI.byteVectorDestroy(this.#emoji_set_ptr);
this.#emoji_set_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.byteVectorDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
811 changes: 464 additions & 347 deletions integration_tests/helpers/ffi/ffiInterface.js

Large diffs are not rendered by default.

42 changes: 14 additions & 28 deletions integration_tests/helpers/ffi/pendingInboundTransaction.js
Original file line number Diff line number Diff line change
@@ -2,67 +2,53 @@ const InterfaceFFI = require("./ffiInterface");
const PublicKey = require("./publicKey");

class PendingInboundTransaction {
#tari_pending_inbound_transaction_ptr;
ptr;

pointerAssign(ptr) {
if (this.#tari_pending_inbound_transaction_ptr) {
if (this.ptr) {
this.destroy();
this.#tari_pending_inbound_transaction_ptr = ptr;
this.ptr = ptr;
} else {
this.#tari_pending_inbound_transaction_ptr = ptr;
this.ptr = ptr;
}
}

getPtr() {
return this.#tari_pending_inbound_transaction_ptr;
return this.ptr;
}

getSourcePublicKey() {
let result = new PublicKey();
result.pointerAssign(
InterfaceFFI.pendingInboundTransactionGetSourcePublicKey(
this.#tari_pending_inbound_transaction_ptr
)
InterfaceFFI.pendingInboundTransactionGetSourcePublicKey(this.ptr)
);
return result;
}

getAmount() {
return InterfaceFFI.pendingInboundTransactionGetAmount(
this.#tari_pending_inbound_transaction_ptr
);
return InterfaceFFI.pendingInboundTransactionGetAmount(this.ptr);
}

getMessage() {
return InterfaceFFI.pendingInboundTransactionGetMessage(
this.#tari_pending_inbound_transaction_ptr
);
return InterfaceFFI.pendingInboundTransactionGetMessage(this.ptr);
}

getStatus() {
return InterfaceFFI.pendingInboundTransactionGetStatus(
this.#tari_pending_inbound_transaction_ptr
);
return InterfaceFFI.pendingInboundTransactionGetStatus(this.ptr);
}

getTransactionID() {
return InterfaceFFI.pendingInboundTransactionGetTransactionId(
this.#tari_pending_inbound_transaction_ptr
);
return InterfaceFFI.pendingInboundTransactionGetTransactionId(this.ptr);
}

getTimestamp() {
return InterfaceFFI.pendingInboundTransactionGetTimestamp(
this.#tari_pending_inbound_transaction_ptr
);
return InterfaceFFI.pendingInboundTransactionGetTimestamp(this.ptr);
}

destroy() {
if (this.#tari_pending_inbound_transaction_ptr) {
InterfaceFFI.pendingInboundTransactionDestroy(
this.#tari_pending_inbound_transaction_ptr
);
this.#tari_pending_inbound_transaction_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.pendingInboundTransactionDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
21 changes: 7 additions & 14 deletions integration_tests/helpers/ffi/pendingInboundTransactions.js
Original file line number Diff line number Diff line change
@@ -2,35 +2,28 @@ const PendingInboundTransaction = require("./pendingInboundTransaction");
const InterfaceFFI = require("./ffiInterface");

class PendingInboundTransactions {
#tari_pending_inbound_transactions_ptr;
ptr;

constructor(ptr) {
this.#tari_pending_inbound_transactions_ptr = ptr;
this.ptr = ptr;
}

getLength() {
return InterfaceFFI.pendingInboundTransactionsGetLength(
this.#tari_pending_inbound_transactions_ptr
);
return InterfaceFFI.pendingInboundTransactionsGetLength(this.ptr);
}

getAt(position) {
let result = new PendingInboundTransaction();
result.pointerAssign(
InterfaceFFI.pendingInboundTransactionsGetAt(
this.#tari_pending_inbound_transactions_ptr,
position
)
InterfaceFFI.pendingInboundTransactionsGetAt(this.ptr, position)
);
return result;
}

destroy() {
if (this.#tari_pending_inbound_transactions_ptr) {
InterfaceFFI.pendingInboundTransactionsDestroy(
this.#tari_pending_inbound_transactions_ptr
);
this.#tari_pending_inbound_transactions_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.pendingInboundTransactionsDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
46 changes: 15 additions & 31 deletions integration_tests/helpers/ffi/pendingOutboundTransaction.js
Original file line number Diff line number Diff line change
@@ -2,73 +2,57 @@ const InterfaceFFI = require("./ffiInterface");
const PublicKey = require("./publicKey");

class PendingOutboundTransaction {
#tari_pending_outbound_transaction_ptr;
ptr;

pointerAssign(ptr) {
if (this.#tari_pending_outbound_transaction_ptr) {
this.#tari_pending_outbound_transaction_ptr = ptr;
if (this.ptr) {
this.ptr = ptr;
this.destroy();
} else {
this.#tari_pending_outbound_transaction_ptr = ptr;
this.ptr = ptr;
}
}

getPtr() {
return this.#tari_pending_outbound_transaction_ptr;
return this.ptr;
}

getDestinationPublicKey() {
let result = new PublicKey();
result.pointerAssign(
InterfaceFFI.pendingOutboundTransactionGetDestinationPublicKey(
this.#tari_pending_outbound_transaction_ptr
)
InterfaceFFI.pendingOutboundTransactionGetDestinationPublicKey(this.ptr)
);
return result;
}

getAmount() {
return InterfaceFFI.pendingOutboundTransactionGetAmount(
this.#tari_pending_outbound_transaction_ptr
);
return InterfaceFFI.pendingOutboundTransactionGetAmount(this.ptr);
}

getFee() {
return InterfaceFFI.pendingOutboundTransactionGetFee(
this.#tari_pending_outbound_transaction_ptr
);
return InterfaceFFI.pendingOutboundTransactionGetFee(this.ptr);
}

getMessage() {
return InterfaceFFI.pendingOutboundTransactionGetMessage(
this.#tari_pending_outbound_transaction_ptr
);
return InterfaceFFI.pendingOutboundTransactionGetMessage(this.ptr);
}

getStatus() {
return InterfaceFFI.pendingOutboundTransactionGetStatus(
this.#tari_pending_outbound_transaction_ptr
);
return InterfaceFFI.pendingOutboundTransactionGetStatus(this.ptr);
}

getTransactionID() {
return InterfaceFFI.pendingOutboundTransactionGetTransactionId(
this.#tari_pending_outbound_transaction_ptr
);
return InterfaceFFI.pendingOutboundTransactionGetTransactionId(this.ptr);
}

getTimestamp() {
return InterfaceFFI.pendingOutboundTransactionGetTimestamp(
this.#tari_pending_outbound_transaction_ptr
);
return InterfaceFFI.pendingOutboundTransactionGetTimestamp(this.ptr);
}

destroy() {
if (this.#tari_pending_outbound_transaction_ptr) {
InterfaceFFI.pendingOutboundTransactionDestroy(
this.#tari_pending_outbound_transaction_ptr
);
this.#tari_pending_outbound_transaction_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.pendingOutboundTransactionDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
21 changes: 7 additions & 14 deletions integration_tests/helpers/ffi/pendingOutboundTransactions.js
Original file line number Diff line number Diff line change
@@ -2,35 +2,28 @@ const PendingOutboundTransaction = require("./pendingOutboundTransaction");
const InterfaceFFI = require("./ffiInterface");

class PendingOutboundTransactions {
#tari_pending_outbound_transactions_ptr;
ptr = undefined;

constructor(ptr) {
this.#tari_pending_outbound_transactions_ptr = ptr;
this.ptr = ptr;
}

getLength() {
return InterfaceFFI.pendingOutboundTransactionsGetLength(
this.#tari_pending_outbound_transactions_ptr
);
return InterfaceFFI.pendingOutboundTransactionsGetLength(this.ptr);
}

getAt(position) {
let result = new PendingOutboundTransaction();
result.pointerAssign(
InterfaceFFI.pendingOutboundTransactionsGetAt(
this.#tari_pending_outbound_transactions_ptr,
position
)
InterfaceFFI.pendingOutboundTransactionsGetAt(this.ptr, position)
);
return result;
}

destroy() {
if (this.#tari_pending_outbound_transactions_ptr) {
InterfaceFFI.pendingOutboundTransactionsDestroy(
this.#tari_pending_outbound_transactions_ptr
);
this.#tari_pending_outbound_transactions_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.pendingOutboundTransactionsDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
23 changes: 10 additions & 13 deletions integration_tests/helpers/ffi/privateKey.js
Original file line number Diff line number Diff line change
@@ -3,20 +3,19 @@ const ByteVector = require("./byteVector");
const utf8 = require("utf8");

class PrivateKey {
#tari_private_key_ptr;

ptr;
pointerAssign(ptr) {
// Prevent pointer from being leaked in case of re-assignment
if (this.#tari_private_key_ptr) {
this.#tari_private_key_ptr = ptr;
if (this.ptr) {
this.ptr = ptr;
this.destroy();
} else {
this.#tari_private_key_ptr = ptr;
this.ptr = ptr;
}
}

generate() {
this.#tari_private_key_ptr = InterfaceFFI.privateKeyGenerate();
this.ptr = InterfaceFFI.privateKeyGenerate();
}

fromHexString(hex) {
@@ -33,14 +32,12 @@ class PrivateKey {
}

getPtr() {
return this.#tari_private_key_ptr;
return this.ptr;
}

getBytes() {
let result = new ByteVector();
result.pointerAssign(
InterfaceFFI.privateKeyGetBytes(this.#tari_private_key_ptr)
);
result.pointerAssign(InterfaceFFI.privateKeyGetBytes(this.ptr));
return result;
}

@@ -57,9 +54,9 @@ class PrivateKey {
}

destroy() {
if (this.#tari_private_key_ptr) {
InterfaceFFI.privateKeyDestroy(this.#tari_private_key_ptr);
this.#tari_private_key_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.privateKeyDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
24 changes: 11 additions & 13 deletions integration_tests/helpers/ffi/publicKey.js
Original file line number Diff line number Diff line change
@@ -3,15 +3,15 @@ const ByteVector = require("./byteVector");
const utf8 = require("utf8");

class PublicKey {
#tari_public_key_ptr;
ptr;

pointerAssign(ptr) {
// Prevent pointer from being leaked in case of re-assignment
if (this.#tari_public_key_ptr) {
if (this.ptr) {
this.destroy();
this.#tari_public_key_ptr = ptr;
this.ptr = ptr;
} else {
this.#tari_public_key_ptr = ptr;
this.ptr = ptr;
}
}

@@ -42,14 +42,12 @@ class PublicKey {
}

getPtr() {
return this.#tari_public_key_ptr;
return this.ptr;
}

getBytes() {
let result = new ByteVector();
result.pointerAssign(
InterfaceFFI.publicKeyGetBytes(this.#tari_public_key_ptr)
);
result.pointerAssign(InterfaceFFI.publicKeyGetBytes(this.ptr));
return result;
}

@@ -66,16 +64,16 @@ class PublicKey {
}

getEmojiId() {
const emoji_id = InterfaceFFI.publicKeyToEmojiId(this.#tari_public_key_ptr);
const result = emoji_id.readCString();
let emoji_id = InterfaceFFI.publicKeyToEmojiId(this.ptr);
let result = emoji_id.readCString();
InterfaceFFI.stringDestroy(emoji_id);
return result;
}

destroy() {
if (this.#tari_public_key_ptr) {
InterfaceFFI.publicKeyDestroy(this.#tari_public_key_ptr);
this.#tari_public_key_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.publicKeyDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
25 changes: 11 additions & 14 deletions integration_tests/helpers/ffi/seedWords.js
Original file line number Diff line number Diff line change
@@ -2,15 +2,15 @@ const InterfaceFFI = require("./ffiInterface");
const utf8 = require("utf8");

class SeedWords {
#tari_seed_words_ptr;
ptr;

pointerAssign(ptr) {
// Prevent pointer from being leaked in case of re-assignment
if (this.#tari_seed_words_ptr) {
if (this.ptr) {
this.destroy();
this.#tari_seed_words_ptr = ptr;
this.ptr = ptr;
} else {
this.#tari_seed_words_ptr = ptr;
this.ptr = ptr;
}
}

@@ -28,27 +28,24 @@ class SeedWords {
}

getLength() {
return InterfaceFFI.seedWordsGetLength(this.#tari_seed_words_ptr);
return InterfaceFFI.seedWordsGetLength(this.ptr);
}

getPtr() {
return this.#tari_seed_words_ptr;
return this.ptr;
}

getAt(position) {
const seed_word = InterfaceFFI.seedWordsGetAt(
this.#tari_seed_words_ptr,
position
);
const result = seed_word.readCString();
let seed_word = InterfaceFFI.seedWordsGetAt(this.ptr, position);
let result = seed_word.readCString();
InterfaceFFI.stringDestroy(seed_word);
return result;
}

destroy() {
if (this.#tari_seed_words_ptr) {
InterfaceFFI.seedWordsDestroy(this.#tari_seed_words_ptr);
this.#tari_seed_words_ptr = undefined; //prevent double free segfault
if (this.ptr) {
InterfaceFFI.seedWordsDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
28 changes: 14 additions & 14 deletions integration_tests/helpers/ffi/transportType.js
Original file line number Diff line number Diff line change
@@ -2,27 +2,27 @@ const InterfaceFFI = require("./ffiInterface");
const utf8 = require("utf8");

class TransportType {
#tari_transport_type_ptr;
#type = "None";
ptr;
type = "None";

pointerAssign(ptr, type) {
// Prevent pointer from being leaked in case of re-assignment
if (this.#tari_transport_type_ptr) {
if (this.ptr) {
this.destroy();
this.#tari_transport_type_ptr = ptr;
this.#type = type;
this.ptr = ptr;
this.type = type;
} else {
this.#tari_transport_type_ptr = ptr;
this.#type = type;
this.ptr = ptr;
this.type = type;
}
}

getPtr() {
return this.#tari_transport_type_ptr;
return this.ptr;
}

getType() {
return this.#type;
return this.type;
}

static createMemory() {
@@ -63,7 +63,7 @@ class TransportType {
}

getAddress() {
if (this.#type === "Memory") {
if (this.type === "Memory") {
let c_address = InterfaceFFI.transportMemoryGetAddress(this.getPtr());
let result = c_address.readCString();
InterfaceFFI.stringDestroy(c_address);
@@ -74,10 +74,10 @@ class TransportType {
}

destroy() {
this.#type = "None";
if (this.#tari_transport_type_ptr) {
InterfaceFFI.transportTypeDestroy(this.#tari_transport_type_ptr);
this.#tari_transport_type_ptr = undefined; //prevent double free segfault
this.type = "None";
if (this.ptr) {
InterfaceFFI.transportTypeDestroy(this.ptr);
this.ptr = undefined; //prevent double free segfault
}
}
}
273 changes: 145 additions & 128 deletions integration_tests/helpers/ffi/wallet.js

Large diffs are not rendered by default.

15 changes: 14 additions & 1 deletion integration_tests/helpers/util.js
Original file line number Diff line number Diff line change
@@ -107,6 +107,19 @@ async function waitFor(
}
}

async function waitForIterate(testFn, toBe, sleepMs, maxIterations = 500) {
let count = 0;
let val = testFn();
while (!(val === toBe)) {
val = testFn();
if (count >= maxIterations) {
break;
}
count++;
await sleep(sleepMs);
}
}

async function waitForPredicate(predicate, timeOut, sleep_ms = 500) {
const now = new Date();
while (new Date() - now < timeOut) {
@@ -280,6 +293,6 @@ module.exports = {
combineTwoTariKeys,
byteArrayToHex,
waitForPredicate,

waitForIterate,
NO_CONNECTION,
};
118 changes: 58 additions & 60 deletions integration_tests/helpers/walletFFIClient.js
Original file line number Diff line number Diff line change
@@ -4,183 +4,181 @@ const CommsConfig = require("./ffi/commsConfig");
const Wallet = require("./ffi/wallet");
const { getFreePort } = require("./util");
const dateFormat = require("dateformat");
const InterfaceFFI = require("./ffi/ffiInterface");

class WalletFFIClient {
#name;
#wallet;
#comms_config;
#transport;
#seed_words;
#pass_phrase;
#port;
name;
wallet;
comms_config;
transport;
seed_words;
pass_phrase;
port;
baseDir = "";

constructor(name) {
this.#name = name;
}

static async Init() {
await InterfaceFFI.Init();
this.name = name;
}

async startNew(seed_words_text, pass_phrase) {
this.#port = await getFreePort(19000, 25000);
const name = `WalletFFI${this.#port}-${this.#name}`;
this.port = await getFreePort(19000, 25000);
const name = `WalletFFI${this.port}-${this.name}`;
this.baseDir = `./temp/base_nodes/${dateFormat(
new Date(),
"yyyymmddHHMM"
)}/${name}`;
this.#transport = TransportType.createTCP(`/ip4/0.0.0.0/tcp/${this.#port}`);
this.#comms_config = new CommsConfig(
`/ip4/0.0.0.0/tcp/${this.#port}`,
this.#transport.getPtr(),
this.transport = TransportType.createTCP(`/ip4/0.0.0.0/tcp/${this.port}`);
this.comms_config = new CommsConfig(
`/ip4/0.0.0.0/tcp/${this.port}`,
this.transport.getPtr(),
"wallet.dat",
this.baseDir,
30,
600,
"localnet"
);
this.#start(seed_words_text, pass_phrase);
this.start(seed_words_text, pass_phrase);
}

async restart(seed_words_text, pass_phrase) {
this.#transport = TransportType.createTCP(`/ip4/0.0.0.0/tcp/${this.#port}`);
this.#comms_config = new CommsConfig(
`/ip4/0.0.0.0/tcp/${this.#port}`,
this.#transport.getPtr(),
this.transport = TransportType.createTCP(`/ip4/0.0.0.0/tcp/${this.port}`);
this.comms_config = new CommsConfig(
`/ip4/0.0.0.0/tcp/${this.port}`,
this.transport.getPtr(),
"wallet.dat",
this.baseDir,
30,
600,
"localnet"
);
this.#start(seed_words_text, pass_phrase);
this.start(seed_words_text, pass_phrase);
}

getStxoValidationStatus() {
return this.#wallet.getStxoValidationStatus();
return this.wallet.getStxoValidationStatus();
}

getUtxoValidationStatus() {
return this.#wallet.getUtxoValidationStatus();
return this.wallet.getUtxoValidationStatus();
}
identify() {
return this.#wallet.getPublicKey();
return this.wallet.getPublicKey();
}

identifyEmoji() {
return this.#wallet.getEmojiId();
return this.wallet.getEmojiId();
}

getBalance() {
return this.#wallet.getBalance();
return this.wallet.getBalance();
}

addBaseNodePeer(public_key_hex, address) {
return this.#wallet.addBaseNodePeer(public_key_hex, address);
return this.wallet.addBaseNodePeer(public_key_hex, address);
}

addContact(alias, pubkey_hex) {
return this.#wallet.addContact(alias, pubkey_hex);
return this.wallet.addContact(alias, pubkey_hex);
}

getContactList() {
return this.#wallet.getContacts();
return this.wallet.getContacts();
}

getCompletedTxs() {
return this.#wallet.getCompletedTransactions();
return this.wallet.getCompletedTransactions();
}

getInboundTxs() {
return this.#wallet.getInboundTransactions();
return this.wallet.getInboundTransactions();
}

getOutboundTxs() {
return this.#wallet.getOutboundTransactions();
return this.wallet.getOutboundTransactions();
}

removeContact(contact) {
return this.#wallet.removeContact(contact);
return this.wallet.removeContact(contact);
}

startRecovery(base_node_pubkey) {
this.#wallet.startRecovery(base_node_pubkey);
this.wallet.startRecovery(base_node_pubkey);
}

checkRecoveryInProgress() {
return this.#wallet.recoveryInProgress();
return this.wallet.recoveryInProgress();
}

applyEncryption(passphrase) {
this.#wallet.applyEncryption(passphrase);
this.wallet.applyEncryption(passphrase);
}

startStxoValidation() {
this.#wallet.startStxoValidation();
this.wallet.startStxoValidation();
}

startUtxoValidation() {
this.#wallet.startUtxoValidation();
this.wallet.startUtxoValidation();
}

getCounters() {
return this.#wallet.getCounters();
return this.wallet.getCounters();
}
resetCounters() {
this.#wallet.clearCallbackCounters();
this.wallet.clearCallbackCounters();
}

sendTransaction(destination, amount, fee_per_gram, message) {
return this.#wallet.sendTransaction(
return this.wallet.sendTransaction(
destination,
amount,
fee_per_gram,
message
);
}

#start(
start(
seed_words_text,
pass_phrase,
rolling_log_files = 50,
byte_size_per_log = 102400
) {
this.#pass_phrase = pass_phrase;
this.pass_phrase = pass_phrase;
if (seed_words_text) {
let seed_words = SeedWords.fromText(seed_words_text);
this.#seed_words = seed_words;
this.seed_words = seed_words;
}

let log_path = `${this.baseDir}/log/wallet.log`;
this.#wallet = new Wallet(
this.#comms_config.getPtr(),
this.wallet = new Wallet(
this.comms_config.getPtr(),
log_path,
this.#pass_phrase,
this.#seed_words ? this.#seed_words.getPtr() : null,
this.pass_phrase,
this.seed_words ? this.seed_words.getPtr() : null,
rolling_log_files,
byte_size_per_log
);
}

getOutboundTransactions() {
return this.#wallet.getOutboundTransactions();
return this.wallet.getOutboundTransactions();
}

cancelPendingTransaction(tx_id) {
return this.#wallet.cancelPendingTransaction(tx_id);
return this.wallet.cancelPendingTransaction(tx_id);
}

stop() {
if (this.#wallet) {
this.#wallet.destroy();
if (this.wallet) {
this.wallet.destroy();
}
if (this.comms_config) {
this.comms_config.destroy();
}
if (this.#comms_config) {
this.#comms_config.destroy();
if (this.transport) {
this.transport.destroy();
}
if (this.#seed_words) {
this.#seed_words.destroy();
if (this.seed_words) {
this.seed_words.destroy();
}
}
}

0 comments on commit 38191d3

Please sign in to comment.