Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: almost complete ffi wallet test #3220

Merged
merged 1 commit into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion integration_tests/features/WalletFFI.feature
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,22 @@ Feature: Wallet FFI
Scenario: As a client I want to receive Tari via my Public Key while I am online
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"

@long-running @broken
Scenario: As a client I want to receive Tari via my Public Key sent while I am offline when I come back online
Given I have a base node BASE
And I have wallet SENDER connected to base node BASE
And I have mining node MINER connected to base node BASE and wallet SENDER
And mining node MINER mines 4 blocks
Then I wait for wallet SENDER to have at least 1000000 uT
And I have a ffi wallet FFI_WALLET connected to base node BASE
And I stop wallet FFI_WALLET
And I wait 5 seconds
And I send 2000000 uT from wallet SENDER to wallet FFI_WALLET at fee 100
And I wait 5 seconds
And I start wallet FFI_WALLET
And wallet SENDER detects all transactions are at least Broadcast
And mining node MINER mines 10 blocks
Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT

@long-running
Scenario: As a client I want to retrieve a list of transactions I have made and received
Expand All @@ -24,12 +39,16 @@ Feature: Wallet FFI
And wallet SENDER detects all transactions are at least Broadcast
And mining node MINER mines 10 blocks
Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT
And Check callbacks for finished inbound tx on ffi wallet FFI_WALLET
And I have wallet RECEIVER connected to base node BASE
And I send 1000000 uT from ffi wallet FFI_WALLET to wallet RECEIVER at fee 100
And ffi wallet FFI_WALLET has 1 broadcast transaction
And mining node MINER mines 4 blocks
Then I wait for wallet RECEIVER to have at least 1000000 uT
And Check callbacks for finished outbound tx on ffi wallet FFI_WALLET
And I have 1 received and 1 send transaction in ffi wallet FFI_WALLET
And I start STXO validation on wallet FFI_WALLET
And I start UTXO validation on wallet FFI_WALLET

# 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
Expand All @@ -47,6 +66,15 @@ Feature: Wallet FFI
Then I don't have contact with alias ALIAS in ffi wallet FFI_WALLET

Scenario: As a client I want to set the base node (should be persisted)
Given I have a base node BASE1
Given I have a base node BASE2
And I have a ffi wallet FFI_WALLET connected to base node BASE1
And I set base node BASE2 for ffi wallet FFI_WALLET
Then BASE2 is connected to FFI_WALLET
And I stop wallet FFI_WALLET
And I wait 5 seconds
And I start wallet FFI_WALLET
Then BASE2 is connected to FFI_WALLET

Scenario: As a client I want to see my public_key, emoji ID, address (whoami)
Given I have a base node BASE
Expand All @@ -57,16 +85,45 @@ Feature: Wallet FFI
Scenario: As a client I want to get my balance
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"

@long-running
Scenario: As a client I want to cancel a transaction
Given I have a base node BASE
And I have wallet SENDER connected to base node BASE
And I have mining node MINER connected to base node BASE and wallet SENDER
And mining node MINER mines 4 blocks
Then I wait for wallet SENDER to have at least 1000000 uT
And I have a ffi wallet FFI_WALLET connected to base node BASE
And I send 2000000 uT from wallet SENDER to wallet FFI_WALLET at fee 100
And wallet SENDER detects all transactions are at least Broadcast
And mining node MINER mines 10 blocks
Then I wait for ffi wallet FFI_WALLET to have at least 1000000 uT
And I have wallet RECEIVER connected to base node BASE
And I stop wallet RECEIVER
And I send 1000000 uT from ffi wallet FFI_WALLET to wallet RECEIVER at fee 100
Then I wait for ffi wallet FFI_WALLET to have 1 pending outbound transaction
Then I cancel all transactions on ffi wallet FFI_WALLET and it will cancel 1 transaction

@long-running
Scenario: As a client I want to be able to restore my wallet from seed words
Given I have a base node BASE
And I have wallet WALLET connected to base node BASE
And I have mining node MINER connected to base node BASE and wallet WALLET
And mining node MINER mines 4 blocks
Then I wait for wallet WALLET to have at least 1000000 uT
Then I recover wallet WALLET into ffi wallet FFI_WALLET from seed words on node BASE
And I wait for recovery of wallet FFI_WALLET to finish
And I wait for ffi wallet FFI_WALLET to have at least 1000000 uT

Scenario: AS a client I want to be able to initiate TXO and TX validation with the specifed base node.
Scenario: As a client I want to be able to initiate TXO and TX validation with the specifed base node.
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"

Scenario: As a client I want async feedback about the progress of sending and receiving a transaction
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"

Scenario: As a client I want async feedback about my connection status to the specifed Base Node

Scenario: As a client I want async feedback about the wallet restoration process
# As a client I want to be able to restore my wallet from seed words

Scenario: As a client I want async feedback about TXO and TX validation processes
# It's a subtest of "As a client I want to retrieve a list of transactions I have made and received"
118 changes: 113 additions & 5 deletions integration_tests/features/support/steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -3365,17 +3365,19 @@ Then(
"I wait for ffi wallet {word} to have at least {int} uT",
{ timeout: 60 * 1000 },
async function (name, amount) {
let success = false;
let wallet = this.getWallet(name);
let retries = 1;
let balance = 0;
const retries_limit = 12;
while (!success && retries <= retries_limit) {
if ((await this.getWallet(name).getBalance()) >= amount) {
success = true;
while (retries <= retries_limit) {
balance = await wallet.getBalance();
if (balance >= amount) {
break;
}
await sleep(5000);
++retries;
}
expect(success).to.be.true;
expect(balance, "Balance is not enough").to.be.greaterThanOrEqual(amount);
}
);

Expand Down Expand Up @@ -3501,3 +3503,109 @@ Then(
}
}
);

When(
"I set base node {word} for ffi wallet {word}",
async function (node, wallet_name) {
let wallet = this.getWallet(wallet_name);
let peer = this.nodes[node].peerAddress().split("::");
await wallet.addBaseNodePeer(peer[0], peer[1]);
}
);

Then(
"I wait for ffi wallet {word} to have {int} pending outbound transaction(s)",
{ timeout: 120 * 1000 },
async function (wallet_name, count) {
let wallet = this.getWallet(wallet_name);
let broadcast = await wallet.getOutboundTransactionsCount();
let retries = 1;
const retries_limit = 24;
while (broadcast != count && retries <= retries_limit) {
await sleep(5000);
broadcast = await wallet.getOutboundTransactionsCount();
++retries;
}
expect(broadcast, "Number of pending messages mismatch").to.be.equal(count);
}
);

Then(
"I cancel all transactions on ffi wallet {word} and it will cancel {int} transaction",
async function (wallet_name, count) {
const wallet = this.getWallet(wallet_name);
expect(
await wallet.cancelAllOutboundTransactions(),
"Number of cancelled transactions"
).to.be.equal(count);
}
);

Then(
"I recover wallet {word} into ffi wallet {word} from seed words on node {word}",
{ timeout: 20 * 1000 },
async function (wallet_name, ffi_wallet_name, node) {
let wallet = this.getWallet(wallet_name);
const seed_words_text = wallet.getSeedWords();
await wallet.stop();
await sleep(1000);
let ffi_wallet = await this.createAndAddFFIWallet(
ffi_wallet_name,
seed_words_text
);
let peer = this.nodes[node].peerAddress().split("::");
await ffi_wallet.addBaseNodePeer(peer[0], peer[1]);
await ffi_wallet.startRecovery(peer[0]);
}
);

Then(
"I wait for recovery of wallet {word} to finish",
{ timeout: 600 * 1000 },
async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
while (wallet.recoveryInProgress) {
await sleep(1000);
}
expect(wallet.recoveryProgress[1]).to.be.greaterThan(0);
expect(wallet.recoveryProgress[0]).to.be.equal(wallet.recoveryProgress[1]);
}
);

Then("I start STXO validation on wallet {word}", async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
await wallet.startStxoValidation();
while (!wallet.stxo_validation_complete) {
await sleep(1000);
}
expect(wallet.stxo_validation_result).to.be.equal(0);
});

Then("I start UTXO validation on wallet {word}", async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
await wallet.startUtxoValidation();
while (!wallet.utxo_validation_complete) {
await sleep(1000);
}
expect(wallet.utxo_validation_result).to.be.equal(0);
});

Then(
"Check callbacks for finished inbound tx on ffi wallet {word}",
async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
expect(wallet.receivedTransaction).to.be.greaterThanOrEqual(1);
expect(wallet.transactionBroadcast).to.be.greaterThanOrEqual(1);
wallet.clearCallbackCounters();
}
);

Then(
"Check callbacks for finished outbound tx on ffi wallet {word}",
async function (wallet_name) {
const wallet = this.getWallet(wallet_name);
expect(wallet.receivedTransactionReply).to.be.greaterThanOrEqual(1);
expect(wallet.transactionBroadcast).to.be.greaterThanOrEqual(1);
wallet.clearCallbackCounters();
}
);
8 changes: 6 additions & 2 deletions integration_tests/features/support/world.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ class CustomWorld {
this.walletPubkeys[name] = walletInfo.public_key;
}

async createAndAddFFIWallet(name) {
async createAndAddFFIWallet(name, seed_words) {
const wallet = new WalletFFIClient(name);
await wallet.startNew();
await wallet.startNew(seed_words);
this.walletsFFI[name] = wallet;
this.walletPubkeys[name] = await wallet.getPublicKey();
return wallet;
Expand Down Expand Up @@ -230,6 +230,10 @@ class CustomWorld {
client.isWallet = true;
return client;
}
let ffi_wallet = this.walletsFFI[name.trim()];
if (ffi_wallet) {
return ffi_wallet;
}
return null;
}

Expand Down
29 changes: 29 additions & 0 deletions integration_tests/helpers/ffi/byteVector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const WalletFFI = require("./walletFFI");

class ByteVector {
#byte_vector_ptr;

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

static async fromBuffer(buffer) {
let buf = Buffer.from(buffer, "utf-8"); // get the bytes
let len = buf.length; // get the length
return new ByteVector(await WalletFFI.byteVectorCreate(buf, len));
}

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

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

destroy() {
return WalletFFI.byteVectorDestroy(this.#byte_vector_ptr);
}
}

module.exports = ByteVector;
23 changes: 23 additions & 0 deletions integration_tests/helpers/ffi/completedTransaction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const WalletFFI = require("./walletFFI");

class CompletedTransaction {
#tari_completed_transaction_ptr;

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

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

destroy() {
return WalletFFI.completedTransactionDestroy(
this.#tari_completed_transaction_ptr
);
}
}

module.exports = CompletedTransaction;
39 changes: 39 additions & 0 deletions integration_tests/helpers/ffi/completedTransactions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const CompletedTransaction = require("./completedTransaction");
const WalletFFI = require("./walletFFI");

class CompletedTransactions {
#tari_completed_transactions_ptr;

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

static async fromWallet(wallet) {
return new CompletedTransactions(
await WalletFFI.walletGetCompletedTransactions(wallet)
);
}

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

async getAt(position) {
return new CompletedTransaction(
await WalletFFI.completedTransactionsGetAt(
this.#tari_completed_transactions_ptr,
position
)
);
}

destroy() {
return WalletFFI.completedTransactionsDestroy(
this.#tari_completed_transactions_ptr
);
}
}

module.exports = CompletedTransactions;
33 changes: 33 additions & 0 deletions integration_tests/helpers/ffi/contact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const PublicKey = require("./publicKey");
const WalletFFI = require("./walletFFI");

class Contact {
#tari_contact_ptr;

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

getPtr() {
return this.#tari_contact_ptr;
}

async getAlias() {
const alias = await WalletFFI.contactGetAlias(this.#tari_contact_ptr);
const result = alias.readCString();
await WalletFFI.stringDestroy(alias);
return result;
}

async getPubkey() {
return new PublicKey(
await WalletFFI.contactGetPublicKey(this.#tari_contact_ptr)
);
}

destroy() {
return WalletFFI.contactDestroy(this.#tari_contact_ptr);
}
}

module.exports = Contact;
Loading