Skip to content

Commit

Permalink
fix: move wallet manager "zero balance" check to transaction handlers (
Browse files Browse the repository at this point in the history
  • Loading branch information
air1one authored and spkjp committed Aug 30, 2019
1 parent e03846d commit 8c773da
Show file tree
Hide file tree
Showing 31 changed files with 841 additions and 121 deletions.
116 changes: 12 additions & 104 deletions __tests__/e2e/lib/utils/test-utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use strict";

const { Managers, Identities } = require("@arkecosystem/crypto");
const { generateMnemonic } = require("bip39");
const axios = require("axios");
axios.defaults.adapter = require("axios/lib/adapters/http");

Expand Down Expand Up @@ -65,119 +67,25 @@ class Helpers {
expect(response.status).toBe(code);
}

expectResource(response) {
expect(response.data.data).toBeObject();
}

expectCollection(response) {
expect(Array.isArray(response.data.data)).toBe(true);
}

expectPaginator(response, firstPage = true) {
expect(response.data.meta).toBeObject();
expect(response.data.meta).toHaveProperty("count");
expect(response.data.meta).toHaveProperty("pageCount");
expect(response.data.meta).toHaveProperty("totalCount");
expect(response.data.meta).toHaveProperty("next");
expect(response.data.meta).toHaveProperty("previous");
expect(response.data.meta).toHaveProperty("self");
expect(response.data.meta).toHaveProperty("first");
expect(response.data.meta).toHaveProperty("last");
}

expectSuccessful(response, statusCode = 200) {
this.expectStatus(response, statusCode);
this.expectJson(response);
}

expectError(response, statusCode = 404) {
this.expectStatus(response, statusCode);
this.expectJson(response);
expect(response.data.statusCode).toBeNumber();
expect(response.data.error).toBeString();
expect(response.data.message).toBeString();
}
generateWallets(walletsNames = []) {
Managers.configManager.setFromPreset("testnet");
const wallets = {};

expectTransaction(transaction) {
expect(transaction).toBeObject();
expect(transaction).toHaveProperty("id");
expect(transaction).toHaveProperty("blockId");
expect(transaction).toHaveProperty("type");
expect(transaction).toHaveProperty("amount");
expect(transaction).toHaveProperty("fee");
expect(transaction).toHaveProperty("sender");

if ([1, 2].indexOf(transaction.type) === -1) {
expect(transaction.recipient).toBeString();
for (const walletName of walletsNames) {
const passphrase = generateMnemonic();
wallets[walletName] = {
passphrase,
address: Identities.Address.fromPassphrase(passphrase)
}
}

expect(transaction.signature).toBeString();
expect(transaction.confirmations).toBeNumber();
return wallets;
}

expectBlock(block) {
expect(block).toBeObject();
expect(block).toHaveProperty("id");
expect(block).toHaveProperty("version");
expect(block).toHaveProperty("height");
expect(block).toHaveProperty("previous");
expect(block).toHaveProperty("forged");
expect(block.forged).toHaveProperty("reward");
expect(block.forged).toHaveProperty("fee");
expect(block).toHaveProperty("payload");
expect(block.payload).toHaveProperty("length");
expect(block.payload).toHaveProperty("hash");
expect(block).toHaveProperty("generator");
expect(block.generator).toHaveProperty("publicKey");
expect(block).toHaveProperty("signature");
expect(block).toHaveProperty("transactions");
}

expectDelegate(delegate, expected) {
expect(delegate).toBeObject();
expect(delegate.username).toBeString();
expect(delegate.address).toBeString();
expect(delegate.publicKey).toBeString();
expect(delegate.votes).toBeNumber();
expect(delegate.rank).toBeNumber();
expect(delegate.blocks).toBeObject();
expect(delegate.blocks.missed).toBeNumber();
expect(delegate.blocks.produced).toBeNumber();
expect(delegate.production).toBeObject();
expect(delegate.production.approval).toBeString();
expect(delegate.production.productivity).toBeString();

Object.keys(expected || {}).forEach(attr => {
expect(delegate[attr]).toBe(expected[attr]);
});
}

expectWallet(wallet) {
expect(wallet).toBeObject();
expect(wallet).toHaveProperty("address");
expect(wallet).toHaveProperty("publicKey");
expect(wallet).toHaveProperty("balance");
expect(wallet).toHaveProperty("isDelegate");
}

async createTransaction(options) {}
/*async createTransaction (options) {
client.setConfig(options.network)
let transaction = transactionBuilder
.transfer()
.amount(options.amount)
.recipientId(options.recipientId)
.vendorField(options.vendorField)
.sign(options.passphrase)
.getStruct()
await axios.post('http://127.0.0.1:4300/api/v2/transactions', {
transactions: [transaction]
})
return transaction
}*/
}

/**
Expand Down
3 changes: 3 additions & 0 deletions __tests__/e2e/tests/scenarios/scenario1/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ module.exports = {
"insufficient-balance",
//'pool-restart',
"transactions-valid",
"htlc-claim",
"htlc-refund",
"multisignature"
],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use strict";

const { Managers, Utils } = require("@arkecosystem/crypto");
const utils = require("./utils");
const testUtils = require("../../../../lib/utils/test-utils");
const { delegates } = require("../../../../lib/utils/testnet");
const { TransactionFactory } = require('../../../../../helpers/transaction-factory');

/**
* Creates a transaction to a new wallet
* @param {Object} options = { }
* @return {void}
*/
module.exports = async options => {
Managers.configManager.setFromPreset("testnet");

const senderWallet = delegates[7]; // better use a different delegate for each scenario initial transfer
let transaction1 = TransactionFactory.transfer(utils.htlcSender.address, 1000 * Math.pow(10, 8), "send coins to htlc sender")
.withFee(0.1 * Math.pow(10, 8))
.withNonce(Utils.BigNumber.make(2))
.withPassphrase(senderWallet.passphrase)
.createOne();

await testUtils.POST("transactions", {
transactions: [transaction1],
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"use strict";

const { Managers, Crypto, Utils } = require("@arkecosystem/crypto");
const utils = require("./utils");
const shared = require("./shared");
const testUtils = require("../../../../lib/utils/test-utils");
const { TransactionFactory } = require('../../../../../helpers/transaction-factory');

/**
* Send lock transactions, we need 4 lock transactions to then test :
* - associated lock tx does not exist
* - secret hash does not match
* - not recipient of lock tx
* - lock expired
* @param {Object} options = { }
* @return {void}
*/
module.exports = async options => {
Managers.configManager.setFromPreset("testnet");

const nodesHeight = await testUtils.getNodesHeight();
const lastHeight = Math.max(...nodesHeight);

// "normal" htlc lock transaction that will allow to claim without issue
shared.lockTransactions.normal = TransactionFactory.htlcLock(
{
secretHash: Crypto.HashAlgorithms.sha256(utils.htlcRecipient1.address.slice(0, 32)).toString("hex"),
expiration: {
type: 2,
value: lastHeight + 12,
},
},
utils.htlcRecipient1.address,
3 * Math.pow(10, 8)
)
.withFee(0.1 * Math.pow(10, 8))
.withPassphrase(utils.htlcSender.passphrase)
.createOne();

// htlc lock transaction that we will claim with a wrong secret hash
shared.lockTransactions.wrongSecret = TransactionFactory.htlcLock(
{
secretHash: Crypto.HashAlgorithms.sha256(utils.htlcRecipient2.address.slice(0, 32)).toString("hex"),
expiration: {
type: 2,
value: lastHeight + 12,
},
},
utils.htlcRecipient2.address,
3 * Math.pow(10, 8)
)
.withFee(0.1 * Math.pow(10, 8))
.withNonce(Utils.BigNumber.make(1))
.withPassphrase(utils.htlcSender.passphrase)
.createOne();

// htlc lock transaction that we will claim with a wallet not recipient of the lock tx
shared.lockTransactions.notRecipient = TransactionFactory.htlcLock(
{
secretHash: Crypto.HashAlgorithms.sha256(utils.htlcRecipient3.address.slice(0, 32)).toString("hex"),
expiration: {
type: 2,
value: lastHeight + 12,
},
},
utils.htlcRecipient3.address,
3 * Math.pow(10, 8)
)
.withFee(0.1 * Math.pow(10, 8))
.withNonce(Utils.BigNumber.make(2))
.withPassphrase(utils.htlcSender.passphrase)
.createOne();

// htlc lock transaction that we will claim after lock expiration
shared.lockTransactions.lockExpired = TransactionFactory.htlcLock(
{
secretHash: Crypto.HashAlgorithms.sha256(utils.htlcRecipient4.address.slice(0, 32)).toString("hex"),
expiration: {
type: 2,
value: lastHeight + 1,
},
},
utils.htlcRecipient4.address,
3 * Math.pow(10, 8)
)
.withFee(0.1 * Math.pow(10, 8))
.withNonce(Utils.BigNumber.make(3))
.withPassphrase(utils.htlcSender.passphrase)
.createOne();

await testUtils.POST("transactions", { transactions: Object.values(shared.lockTransactions) }, 1); // to node 1
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use strict";

const testUtils = require("../../../../lib/utils/test-utils");
const utils = require("./utils");
const shared = require("./shared");

describe("Check confirmed and unconfirmed transactions", () => {
it("should have no unconfirmed transaction", async () => {
const response = await testUtils.GET("transactions/unconfirmed", {}, 1);
testUtils.expectSuccessful(response);
const transactions = response.data.data;

expect(transactions.length).toBe(0);
});

it("should have all lock transactions forged", async () => {
const response = await testUtils.GET("transactions");
testUtils.expectSuccessful(response);
const transactions = response.data.data;

for (const recipientName of ["htlcRecipient1", "htlcRecipient2", "htlcRecipient3", "htlcRecipient4"]) {
expect(transactions.filter(transaction => transaction.recipient === utils[recipientName].address).length).toBe(1);
}
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"use strict";

const { Managers, Utils } = require("@arkecosystem/crypto");
const utils = require("./utils");
const shared = require("./shared");
const testUtils = require("../../../../lib/utils/test-utils");
const { TransactionFactory } = require('../../../../../helpers/transaction-factory');

/**
* Send claim transactions, we need 4 claim transactions to test when :
* - associated lock tx does not exist
* - secret hash does not match
* - not recipient of lock tx
* - lock expired
* @param {Object} options = { }
* @return {void}
*/
module.exports = async options => {
Managers.configManager.setFromPreset("testnet");

// 1st transaction : "normal" htlc lock transaction that we claim without issue
shared.claimTransactions.normal = TransactionFactory.htlcClaim(
{
lockTransactionId: shared.lockTransactions.normal.id,
unlockSecret: shared.lockTransactions.normal.recipientId.slice(0, 32),
}
)
.withPassphrase(utils.htlcRecipient1.passphrase)
.createOne();

// 2nd transaction : htlc lock transaction that we claim with a wrong secret hash
shared.claimTransactions.wrongSecret = TransactionFactory.htlcClaim(
{
lockTransactionId: shared.lockTransactions.wrongSecret.id,
unlockSecret: "thatisasecretthatissooooooowrong",
}
)
.withPassphrase(utils.htlcRecipient2.passphrase)
.createOne();

// 3rd transaction : htlc lock transaction that we claim with a wallet not recipient of the lock tx
shared.claimTransactions.notRecipient = TransactionFactory.htlcClaim(
{
lockTransactionId: shared.lockTransactions.notRecipient.id,
unlockSecret: shared.lockTransactions.notRecipient.recipientId.slice(0, 32),
}
)
.withPassphrase(utils.htlcNotRecipient.passphrase)
.createOne();

// 4th transaction : htlc lock transaction that we will claim after lock expiration
shared.claimTransactions.lockExpired = TransactionFactory.htlcClaim(
{
lockTransactionId: shared.lockTransactions.lockExpired.id,
unlockSecret: shared.lockTransactions.lockExpired.recipientId.slice(0, 32),
}
)
.withPassphrase(utils.htlcRecipient4.passphrase)
.createOne();

await testUtils.POST("transactions", { transactions: Object.values(shared.claimTransactions) }, 1); // to node 1
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"use strict";

const testUtils = require("../../../../lib/utils/test-utils");
const utils = require("./utils");
const shared = require("./shared");

describe("Check confirmed and unconfirmed transactions", () => {
it("should have no unconfirmed transaction", async () => {
const response = await testUtils.GET("transactions/unconfirmed", {}, 1);
testUtils.expectSuccessful(response);
const transactions = response.data.data;

expect(transactions.length).toBe(0);
});

it("should have valid transactions forged and invalid not forged", async () => {
const response = await testUtils.GET("transactions");
testUtils.expectSuccessful(response);
const transactions = response.data.data;

// recipients 1 and htlcNotRecipient sent valid htlc claim transactions
for (const senderName of ["htlcRecipient1", "htlcNotRecipient"]) {
expect(transactions.filter(transaction => transaction.sender === utils[senderName].address).length).toBe(1);
}

// recipients 2 and 4 sent invalid htlc claim transactions
for (const senderName of ["htlcRecipient2", "htlcRecipient4"]) {
expect(transactions.filter(transaction => transaction.sender === utils[senderName].address).length).toBe(0);
}
});
});
Loading

0 comments on commit 8c773da

Please sign in to comment.