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

refactor(core-magistrate): make bridgechain genesis hash only unique per wallet #3523

Merged
merged 12 commits into from
Feb 25, 2020
14 changes: 0 additions & 14 deletions __tests__/integration/core-api/handlers/bridgechains.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,6 @@ describe("API 2.0 - Bridgechains", () => {
});
});

describe("GET /bridgechains/:id", () => {
it("should GET bridgechains by id (genesisHash)", async () => {
const response = await utils.request("GET", `bridgechains/${bridgechainAsset.genesisHash}`);
expect(response).toBeSuccessfulResponse();
expect(response.data.data).toBeObject();
expect(response.data.data.publicKey).toEqual(publicKey);
expect(response.data.data.name).toEqual(bridgechainAsset.name);
expect(response.data.data.seedNodes).toEqual(bridgechainAsset.seedNodes);
expect(response.data.data.genesisHash).toEqual(bridgechainAsset.genesisHash);
expect(response.data.data.bridgechainRepository).toEqual(bridgechainAsset.bridgechainRepository);
expect(response.data.data.ports).toEqual(bridgechainAsset.ports);
});
});

describe("POST /bridgechains/search", () => {
it("should POST a search for bridgechains by name", async () => {
const response = await utils.request("POST", "bridgechains/search", {
Expand Down
13 changes: 13 additions & 0 deletions __tests__/integration/core-api/handlers/businesses.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ describe("API 2.0 - Businesses", () => {
});
});

describe("GET /businesses/:businessId/bridgechains/:bridgechainId", () => {
it.each(Object.entries(validIdentifiers))("should GET a business bridgechains by %s : %s", async (_, value) => {
const response = await utils.request(
"GET",
`businesses/${value}/bridgechains/${bridgechainAsset.genesisHash}`,
);
expect(response).toBeSuccessfulResponse();
expect(response.data.data).toBeObject();

expect(response.data.data.bridgechainAsset.genesisHash).toEqual(bridgechainAsset.genesisHash);
});
});

describe("POST /businesses/search", () => {
it("should POST a search for businesses by name", async () => {
const response = await utils.request("POST", "businesses/search", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { State } from "@arkecosystem/core-interfaces";
import { Builders as MagistrateBuilders } from "@arkecosystem/core-magistrate-crypto";
import { Wallets } from "@arkecosystem/core-state";
import { Handlers } from "@arkecosystem/core-transactions";
import { Managers, Utils } from "@arkecosystem/crypto";
import { Identities, Managers, Utils } from "@arkecosystem/crypto";
import {
BridgechainAlreadyRegisteredError,
PortKeyMustBeValidPackageNameError,
Expand All @@ -18,11 +18,7 @@ import {
IBridgechainWalletAttributes,
IBusinessWalletAttributes,
} from "../../../../packages/core-magistrate-transactions/src/interfaces";
import {
bridgechainIndexer,
businessIndexer,
MagistrateIndex,
} from "../../../../packages/core-magistrate-transactions/src/wallet-manager";
import { businessIndexer, MagistrateIndex } from "../../../../packages/core-magistrate-transactions/src/wallet-manager";
import { bridgechainRegistrationAsset1, bridgechainRegistrationAsset2, businessRegistrationAsset1 } from "../helper";

jest.mock("@arkecosystem/core-container", () => {
Expand All @@ -49,6 +45,8 @@ let businessRegistrationBuilder: MagistrateBuilders.BusinessRegistrationBuilder;
let bridgechainRegistrationBuilder: MagistrateBuilders.BridgechainRegistrationBuilder;

let senderWallet: Wallets.Wallet;
const otherPassphrase = "other wallet passphrase";
let otherWallet: Wallets.Wallet;
let walletManager: State.IWalletManager;

Managers.configManager.setHeight(2); // aip11 (v2 transactions) is true from height 2 on testnet
Expand All @@ -68,12 +66,16 @@ describe("should test marketplace transaction handlers", () => {

walletManager = new Wallets.WalletManager();
walletManager.registerIndex(MagistrateIndex.Businesses, businessIndexer);
walletManager.registerIndex(MagistrateIndex.Bridgechains, bridgechainIndexer);

senderWallet = new Wallets.Wallet("ANBkoGqWeTSiaEVgVzSKZd3jS7UWzv9PSo");
senderWallet.balance = Utils.BigNumber.make("500000000000000");
senderWallet.publicKey = "03287bfebba4c7881a0509717e71b34b63f31e40021c321f89ae04f84be6d6ac37";
walletManager.reindex(senderWallet);

otherWallet = new Wallets.Wallet(Identities.Address.fromPassphrase(otherPassphrase));
otherWallet.balance = Utils.BigNumber.make("500000000000000");
otherWallet.publicKey = Identities.PublicKey.fromPassphrase(otherPassphrase);
walletManager.reindex(otherWallet);
});

describe("Bridgechain registration handler", () => {
Expand All @@ -98,6 +100,16 @@ describe("should test marketplace transaction handlers", () => {
.nonce("1")
.sign("clay harbor enemy utility margin pretty hub comic piece aerobic umbrella acquire");
await businessRegistrationHandler.applyToSender(businessRegistration.build(), walletManager);

const businessRegistration2 = businessRegistrationBuilder
.businessRegistrationAsset({
name: "business2",
website: "http://www.website2.com",
})
.nonce("1")
.sign(otherPassphrase);

await businessRegistrationHandler.applyToSender(businessRegistration2.build(), walletManager);
});

it("should pass because business is registered", async () => {
Expand All @@ -111,7 +123,7 @@ describe("should test marketplace transaction handlers", () => {
).toResolve();
});

it("should throw because bridgechain is already registered", async () => {
it("should throw because bridgechain is already registered by same wallet", async () => {
const actual = bridgechainRegistrationBuilder
.bridgechainRegistrationAsset(bridgechainRegistrationAsset1)
.nonce("2")
Expand All @@ -123,6 +135,23 @@ describe("should test marketplace transaction handlers", () => {
).rejects.toThrowError(BridgechainAlreadyRegisteredError);
});

it("should not throw when bridgechain is registered by another wallet", async () => {
const otherBridgechainRegistration = bridgechainRegistrationBuilder
.bridgechainRegistrationAsset(bridgechainRegistrationAsset1)
.nonce("2")
.sign(otherPassphrase);
await bridgechainRegistrationHandler.applyToSender(otherBridgechainRegistration.build(), walletManager);

const actual = bridgechainRegistrationBuilder
.bridgechainRegistrationAsset(bridgechainRegistrationAsset1)
.nonce("2")
.sign("clay harbor enemy utility margin pretty hub comic piece aerobic umbrella acquire");

await expect(
bridgechainRegistrationHandler.throwIfCannotBeApplied(actual.build(), senderWallet, walletManager),
).toResolve();
});

it.each([["@invalid/UPPERCASE"], ["@invalid/char)"]])(
"should throw because ports contains invalid package name",
async invalidName => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ import {
BusinessRegistrationTransactionHandler,
} from "../../../../packages/core-magistrate-transactions/src/handlers";
import { IBusinessWalletAttributes } from "../../../../packages/core-magistrate-transactions/src/interfaces";
import {
bridgechainIndexer,
businessIndexer,
MagistrateIndex,
} from "../../../../packages/core-magistrate-transactions/src/wallet-manager";
import { businessIndexer, MagistrateIndex } from "../../../../packages/core-magistrate-transactions/src/wallet-manager";
import { bridgechainRegistrationAsset1 } from "../helper";

jest.mock("@arkecosystem/core-container", () => {
Expand Down Expand Up @@ -71,7 +67,6 @@ describe("Bridgechain resignation handler", () => {

walletManager = new Wallets.WalletManager();
walletManager.registerIndex(MagistrateIndex.Businesses, businessIndexer);
walletManager.registerIndex(MagistrateIndex.Bridgechains, bridgechainIndexer);

senderWallet = new Wallets.Wallet("ANBkoGqWeTSiaEVgVzSKZd3jS7UWzv9PSo");
senderWallet.balance = Utils.BigNumber.make("500000000000000");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ import {
BridgechainUpdateTransactionHandler,
BusinessRegistrationTransactionHandler,
} from "../../../../packages/core-magistrate-transactions/src/handlers";
import {
bridgechainIndexer,
businessIndexer,
MagistrateIndex,
} from "../../../../packages/core-magistrate-transactions/src/wallet-manager";
import { businessIndexer, MagistrateIndex } from "../../../../packages/core-magistrate-transactions/src/wallet-manager";
import {
bridgechainRegistrationAsset1,
bridgechainRegistrationAsset2,
Expand Down Expand Up @@ -76,7 +72,6 @@ describe("Bridgechain update handler", () => {

walletManager = new Wallets.WalletManager();
walletManager.registerIndex(MagistrateIndex.Businesses, businessIndexer);
walletManager.registerIndex(MagistrateIndex.Bridgechains, bridgechainIndexer);

senderWallet = new Wallets.Wallet("ANBkoGqWeTSiaEVgVzSKZd3jS7UWzv9PSo");
senderWallet.balance = Utils.BigNumber.make("500000000000000");
Expand Down
11 changes: 0 additions & 11 deletions packages/core-api/src/handlers/bridgechains/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,6 @@ export class BridgechainController extends Controller {
}
}

public async show(request: Hapi.Request, h: Hapi.ResponseToolkit) {
try {
// @ts-ignore
const data = await request.server.methods.v2.bridgechains.show(request);

return super.respondWithCache(data, h);
} catch (error) {
return Boom.badImplementation(error);
}
}

public async search(request: Hapi.Request, h: Hapi.ResponseToolkit) {
try {
// @ts-ignore
Expand Down
16 changes: 1 addition & 15 deletions packages/core-api/src/handlers/bridgechains/methods.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { app } from "@arkecosystem/core-container";
import { Database } from "@arkecosystem/core-interfaces";
import Boom from "@hapi/boom";
import { ServerCache } from "../../services";
import { paginate, respondWithResource, toPagination } from "../utils";
import { paginate, toPagination } from "../utils";

const databaseService = app.resolvePlugin<Database.IDatabaseService>("database");

Expand All @@ -15,18 +14,6 @@ const index = async request => {
return toPagination(bridgechains, "bridgechain");
};

const show = async request => {
const bridgechain = databaseService.wallets.search(Database.SearchScope.Bridgechains, {
genesisHash: request.params.id,
}).rows[0];

if (!bridgechain) {
return Boom.notFound("Bridgechain not found");
}

return respondWithResource(bridgechain, "bridgechain");
};

const search = async request => {
const bridgechains = databaseService.wallets.search(Database.SearchScope.Bridgechains, {
...request.payload,
Expand All @@ -43,7 +30,6 @@ export const registerMethods = server => {
...request.query,
...paginate(request),
}))
.method("v2.bridgechains.show", show, 8, request => ({ id: request.params.id }))
.method("v2.bridgechains.search", search, 30, request => ({
...request.payload,
...request.query,
Expand Down
9 changes: 0 additions & 9 deletions packages/core-api/src/handlers/bridgechains/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@ export const registerRoutes = (server: Hapi.Server): void => {
},
});

server.route({
method: "GET",
path: "/bridgechains/{id}",
handler: controller.show,
options: {
validate: Schema.show,
},
});

server.route({
method: "POST",
path: "/bridgechains/search",
Expand Down
8 changes: 0 additions & 8 deletions packages/core-api/src/handlers/bridgechains/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,6 @@ export const index: object = {
},
};

export const show: object = {
params: {
id: Joi.string()
.hex()
.length(64), // id is genesisHash
},
};

export const search: object = {
query: {
...pagination,
Expand Down
11 changes: 11 additions & 0 deletions packages/core-api/src/handlers/businesses/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ export class BusinessController extends Controller {
}
}

public async bridgechain(request: Hapi.Request, h: Hapi.ResponseToolkit) {
try {
// @ts-ignore
const data = await request.server.methods.v2.businesses.bridgechain(request);

return super.respondWithCache(data, h);
} catch (error) {
return Boom.badImplementation(error);
}
}

public async search(request: Hapi.Request, h: Hapi.ResponseToolkit) {
try {
// @ts-ignore
Expand Down
19 changes: 19 additions & 0 deletions packages/core-api/src/handlers/businesses/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@ const bridgechains = async request => {
return toPagination(bridgechains, "bridgechain");
};

const bridgechain = async request => {
const wallet = databaseService.wallets.findById(Database.SearchScope.Wallets, request.params.businessId);

if (!wallet || !wallet.hasAttribute("business")) {
return Boom.notFound("Business not found");
}

const bridgechains = wallet.getAttribute("business.bridgechains");
if (!bridgechains || !bridgechains[request.params.bridgechainId]) {
return Boom.notFound("Bridgechain not found");
}

return respondWithResource(bridgechains[request.params.bridgechainId], "bridgechain");
};

const search = async request => {
const businesses = databaseService.wallets.search(Database.SearchScope.Businesses, {
...request.payload,
Expand All @@ -78,6 +93,10 @@ export const registerMethods = server => {
...request.query,
...paginate(request),
}))
.method("v2.businesses.bridgechain", bridgechain, 8, request => ({
businessId: request.params.businessId,
bridgechainId: request.params.bridgechainId,
}))
.method("v2.businesses.search", search, 30, request => ({
...request.payload,
...request.query,
Expand Down
9 changes: 9 additions & 0 deletions packages/core-api/src/handlers/businesses/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ export const registerRoutes = (server: Hapi.Server): void => {
},
});

server.route({
method: "GET",
path: "/businesses/{businessId}/bridgechains/{bridgechainId}",
handler: controller.bridgechain,
options: {
validate: Schema.bridgechain,
},
});

server.route({
method: "POST",
path: "/businesses/search",
Expand Down
11 changes: 10 additions & 1 deletion packages/core-api/src/handlers/businesses/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const show: object = {
},
query: {
transform: Joi.bool().default(true),
}
},
};

export const bridgechains: object = {
Expand All @@ -36,6 +36,15 @@ export const bridgechains: object = {
},
};

export const bridgechain: object = {
params: {
businessId: walletId,
bridgechainId: Joi.string()
.hex()
.length(64), // genesisHash
},
};

export const search: object = {
query: {
...pagination,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,22 +263,25 @@ export class WalletsBusinessRepository implements Database.IWalletsBusinessRepos
};

const entries: any[] = this.databaseServiceProvider()
.walletManager.getIndex("bridgechains")
.entries()
.reduce((acc, [genesisHash, wallet]) => {
const bridgechains: any[] = wallet.getAttribute("business.bridgechains");
if (bridgechains && bridgechains[genesisHash]) {
const bridgechain: any = bridgechains[genesisHash];
.walletManager.getIndex("businesses")
.values()
.reduce((acc, wallet) => {
const bridgechains: Record<
string,
{
bridgechainAsset: object;
resigned?: boolean;
}
> = wallet.getAttribute("business.bridgechains") || {};

const bridgechainData = {
acc.push(
...Object.values(bridgechains).map(bridgechain => ({
publicKey: wallet.publicKey,
address: wallet.address,
...bridgechain.bridgechainAsset,
isResigned: !!bridgechain.resigned,
};

acc.push(bridgechainData);
}
})),
);

return acc;
}, []);
Expand Down
Loading