Skip to content

Commit

Permalink
Merge pull request #178 from Chia-Network/dev/michael.taylor/fix-reti…
Browse files Browse the repository at this point in the history
…rement-filter

fix: dont push metadata to cadt if it already exists
  • Loading branch information
MichaelTaylor3D authored Oct 20, 2023
2 parents 2e2d7a2 + 9058709 commit 2c4077c
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 57 deletions.
74 changes: 35 additions & 39 deletions src/api/registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,61 +374,53 @@ const confirmTokenRegistrationOnWarehouse = async (retry = 0) => {
};

/**
* Registers token creation on the registry.
*
* @async
* @function
* @param {Object} token - The token to register.
* @param {string} warehouseUnitId - The warehouse unit ID.
* @returns {Promise<Object|null>} Returns a Promise that resolves to the response body if successful, or null if an error occurs.
* @throws {Error} Throws an error if the Registry API key is invalid.
* Registers a token creation on the registry.
*
* @param {Object} token - The token to be registered.
* @param {string} warehouseUnitId - The ID of the warehouse unit.
* @returns {Promise<boolean|null>} Returns true if successful, null otherwise.
*/
const registerTokenCreationOnRegistry = async (token, warehouseUnitId) => {
try {
await waitForRegistryDataSync();

if (CONFIG().GENERAL.CORE_REGISTRY_MODE) {
const coreRegistryMode = CONFIG().GENERAL.CORE_REGISTRY_MODE;
const metadataUrl = `${registryUri}/v1/organizations/metadata`;
const apiKeyHeaders = maybeAppendRegistryApiKey({ "Content-Type": "application/json" });

if (coreRegistryMode) {
token.detokenization = { mod_hash: "", public_key: "", signature: "" };
}

const response = await superagent
.post(`${registryUri}/v1/organizations/metadata`)
.send({ [token.asset_id]: JSON.stringify(token) })
.set(maybeAppendRegistryApiKey({ "Content-Type": "application/json" }));
const metaDataResponse = await superagent.get(metadataUrl).set(apiKeyHeaders);
const metaData = metaDataResponse.body;

if (response.status === 403) {
throw new Error(
"Registry API key is invalid, please check your config.yaml."
);
if (metaDataResponse.status === 403) {
throw new Error("Registry API key is invalid, please check your config.yaml.");
}

if (
response.body.message ===
"Home org currently being updated, will be completed soon."
) {
if (
CONFIG().GENERAL.CORE_REGISTRY_MODE &&
(await confirmTokenRegistrationOnWarehouse())
) {
await updateUnitMarketplaceIdentifierWithAssetId(
warehouseUnitId,
token.asset_id
);
if (!metaData[`meta_${token.asset_id}`]) {
const response = await superagent.post(metadataUrl)
.send({ [token.asset_id]: JSON.stringify(token) })
.set(apiKeyHeaders);

if (response.status === 403) {
throw new Error("Registry API key is invalid, please check your config.yaml.");
}
} else {
logger.error("Could not register token creation in registry.");
}

return response.body;
if (coreRegistryMode && await confirmTokenRegistrationOnWarehouse()) {
await updateUnitMarketplaceIdentifierWithAssetId(warehouseUnitId, token.asset_id);
}

return true;
} catch (error) {
logger.error(
`Could not register token creation in registry: ${error.message}`
);
logger.error(`Could not register token creation in registry: ${error.message}`);

if (error.response?.body) {
logger.error(
`Additional error details: ${JSON.stringify(error.response.body)}`
);
logger.error(`Additional error details: ${JSON.stringify(error.response.body)}`);
}

return null;
}
};
Expand Down Expand Up @@ -538,6 +530,10 @@ const getOrgMetaData = async (orgUid) => {
* @returns {Promise<void>}
*/
const waitForRegistryDataSync = async (options = {}) => {
if (process.env.NODE_ENV === "test") {
return;
}

await mutex.waitForUnlock();

let isFirstSyncAfterFailure = false;
Expand Down Expand Up @@ -719,7 +715,7 @@ const splitUnit = async ({
beneficiaryName,
beneficiaryAddress,
}) => {
logger.info(`Splitting unit ${unit.warehouseUnitId} by ${amount}`)
logger.info(`Splitting unit ${unit.warehouseUnitId} by ${amount}`);

// Parse the serialNumberBlock
const { unitBlockStart, unitBlockEnd } = utils.parseSerialNumber(
Expand Down
4 changes: 4 additions & 0 deletions src/chia/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const walletIsAvailable = async () => {
};

const waitForAllTransactionsToConfirm = async () => {
if (process.env.NODE_ENV === "test") {
return true;
}

await new Promise((resolve) => setTimeout(() => resolve(), 5000));
const unconfirmedTransactions = await hasUnconfirmedTransactions();

Expand Down
2 changes: 1 addition & 1 deletion src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ app.post("/confirm-detokanization", confirmDetokanization);
*
* @returns {Object} An object containing a message and timestamp.
*/
app.get("/health", (req, res) => {
app.get("/healthz", (req, res) => {
res.status(200).json({
message: "OK",
timestamp: new Date().toISOString(),
Expand Down
3 changes: 3 additions & 0 deletions src/tasks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ const addJobToScheduler = (job) => {
* Start the scheduler and add default jobs
*/
const start = () => {
if (process.env.NODE_ENV === "test") {
return;
}
// Define default jobs
const defaultJobs = [syncRetirements];

Expand Down
39 changes: 23 additions & 16 deletions tests/create-token.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,26 @@ const TokenCreatedResponseMock = require("./data/TokenCreateResponseMock");
const UnitMock = require("./data/UnitMock");
const OrganizationsMock = require("./data/OrganizationsMock");
const { CONFIG, setConfig } = require("../src/config");
const { generateUriForHostAndPort } = require("../src/utils");

// Create a nock interceptor for the registry API
const registryMock = nock(
`${CONFIG().CADT.PROTOCOL}://${CONFIG().CADT.HOST}:${CONFIG().CADT.PORT}`
const registryUri = generateUriForHostAndPort(
CONFIG().CADT.PROTOCOL,
CONFIG().CADT.HOST,
CONFIG().CADT.PORT
);
const tokenDriverMock = nock(
`${CONFIG().CHIA_CLIMATE_TOKENIZATION.PROTOCOL}://${
CONFIG().CHIA_CLIMATE_TOKENIZATION.HOST
}:${CONFIG().CHIA_CLIMATE_TOKENIZATION.PORT}`

const tokenDriverUri = generateUriForHostAndPort(
CONFIG().CHIA_CLIMATE_TOKENIZATION.PROTOCOL,
CONFIG().CHIA_CLIMATE_TOKENIZATION.HOST,
CONFIG().CHIA_CLIMATE_TOKENIZATION.PORT
);

describe("Create Token Process", () => {
let walletHasUnconfirmedTransactionsStub;
let createTokenPayload;

beforeEach(() => {
registryMock.get("/v1/organizations").reply(200, OrganizationsMock);
nock(registryUri).get("/v1/organizations").reply(200, OrganizationsMock);

createTokenPayload = {
org_uid: "org-123",
Expand All @@ -52,7 +55,7 @@ describe("Create Token Process", () => {
afterEach(async () => {
sinon.restore();
nock.cleanAll();
await new Promise(resolve => setTimeout(() => resolve(), 1000));
await new Promise((resolve) => setTimeout(() => resolve(), 1000));
});

afterAll(async () => {
Expand All @@ -61,7 +64,7 @@ describe("Create Token Process", () => {
});

it("health check", async () => {
const response = await request(app).get("/health");
const response = await request(app).get("/healthz");
expect(response.status).to.equal(200);
});

Expand All @@ -87,7 +90,7 @@ describe("Create Token Process", () => {
// 2. Call the registry to register the token creation
// 3. Call the registry to update the unit block with the asset id

const tokenDriverInterceptor = tokenDriverMock
const tokenDriverInterceptor = nock(tokenDriverUri)
.post("/v1/tokens", (body) => {
expect(body).to.deep.equal({
token: {
Expand All @@ -105,8 +108,10 @@ describe("Create Token Process", () => {
})
.reply(200, TokenCreatedResponseMock);

nock(registryUri).get("/v1/organizations/metadata").reply(200, {});

// Nock Registry Add Metadata Response
const updateRegistryMetadataInterceptor = registryMock
const updateRegistryMetadataInterceptor = nock(registryUri)
.post("/v1/organizations/metadata", (body) => {
const bodyValue = JSON.parse(
body[TokenCreatedResponseMock.token.asset_id]
Expand All @@ -126,13 +131,13 @@ describe("Create Token Process", () => {
});

// Nock Registry Update Unit Response (1)
const getUnitInterceptor = registryMock
const getUnitInterceptor = nock(registryUri)
.get("/v1/units")
.query({ warehouseUnitId: createTokenPayload.warehouseUnitId })
.reply(200, UnitMock);

// Nock Registry Update Unit Response (2)
const updateUnitInterceptor = registryMock
const updateUnitInterceptor = nock(registryUri)
.put("/v1/units", (body) => {
expect(body).to.deep.equal({
...registry.sanitizeUnitForUpdate(UnitMock),
Expand Down Expand Up @@ -172,7 +177,7 @@ describe("Create Token Process", () => {
// 2. Call the registry to register the token creation
// 3. Call the registry to update the unit block with the asset id

const tokenDriverInterceptor = tokenDriverMock
const tokenDriverInterceptor = nock(tokenDriverUri)
.post("/v1/tokens", (body) => {
expect(body).to.deep.equal({
token: {
Expand All @@ -190,8 +195,10 @@ describe("Create Token Process", () => {
})
.reply(200, TokenCreatedResponseMock);

nock(registryUri).get("/v1/organizations/metadata").reply(200, {});

// Nock Registry Add Metadata Response
const updateRegistryMetadataInterceptor = registryMock
const updateRegistryMetadataInterceptor = nock(registryUri)
.post("/v1/organizations/metadata", (body) => {
const bodyValue = JSON.parse(
body[TokenCreatedResponseMock.token.asset_id]
Expand Down
118 changes: 118 additions & 0 deletions tests/registry.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
const nock = require("nock");
const sinon = require("sinon");
const { expect } = require("chai");
const registry = require("../src/api/registry");
const { CONFIG, setConfig } = require("../src/config");
const { generateUriForHostAndPort } = require("../src/utils");
const OrganizationsMock = require("./data/OrganizationsMock");
const wallet = require("../src/chia/wallet");

const registryUri = generateUriForHostAndPort(
CONFIG().CADT.PROTOCOL,
CONFIG().CADT.HOST,
CONFIG().CADT.PORT
);

describe("registerTokenCreationOnRegistry", () => {
beforeEach(() => {
nock(registryUri).get("/v1/organizations").reply(200, OrganizationsMock);
sinon.stub(wallet, "hasUnconfirmedTransactions").resolves(false);
});

afterEach(() => {
sinon.restore();
nock.cleanAll();
});

it("should successfully register a token when metadata does not exist", async () => {
const config = CONFIG();
config.GENERAL.CORE_REGISTRY_MODE = true;
setConfig(config);

const tokenMock = {
asset_id: "0x123TEST",
};

const warehouseUnitId = "unit-123";

const metadataInterceptor = nock(registryUri)
.get("/v1/organizations/metadata")
.reply(200, {});

const postMetadataInterceptor = nock(registryUri)
.post("/v1/organizations/metadata")
.reply(200);

nock(registryUri)
.get("/v1/units")
.query({ warehouseUnitId })
.reply(200, { warehouseUnitId });

nock(registryUri)
.put("/v1/units", (body) => {
return (
JSON.stringify(body) ===
JSON.stringify({
warehouseUnitId,
marketplaceIdentifier: tokenMock.asset_id,
marketplace: "Tokenized on Chia",
})
);
})
.reply(200);

nock(registryUri).post("/v1/staging/commit").reply(200);

await registry.registerTokenCreationOnRegistry(tokenMock, warehouseUnitId);

expect(metadataInterceptor.isDone()).to.be.true;
expect(postMetadataInterceptor.isDone()).to.be.true;
}, 50000);

it("should not submit metadata again if it already exists", async () => {
const config = CONFIG();
config.GENERAL.CORE_REGISTRY_MODE = true;
setConfig(config);

const tokenMock = {
asset_id: "0x123TEST",
};

const warehouseUnitId = "unit-123";

const metadataInterceptor = nock(registryUri)
.get("/v1/organizations/metadata")
.reply(200, {
[`meta_${tokenMock.asset_id}`]: {},
});

const postMetadataInterceptor = nock(registryUri)
.post("/v1/organizations/metadata")
.reply(200);

nock(registryUri)
.get("/v1/units")
.query({ warehouseUnitId })
.reply(200, { warehouseUnitId });

nock(registryUri)
.put("/v1/units", (body) => {
return (
JSON.stringify(body) ===
JSON.stringify({
warehouseUnitId,
marketplaceIdentifier: tokenMock.asset_id,
marketplace: "Tokenized on Chia",
})
);
})
.reply(200);

nock(registryUri).post("/v1/staging/commit").reply(200);

await registry.registerTokenCreationOnRegistry(tokenMock, warehouseUnitId);

expect(metadataInterceptor.isDone()).to.be.true;
expect(postMetadataInterceptor.isDone()).to.be.false;
}, 50000);
});
3 changes: 2 additions & 1 deletion tests/retirement-explorer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ describe("getRetirementActivities", () => {

beforeEach(() => {
nock(apiEndpoint)
.get("/v1/activities?page=1&limit=10&minHeight=1&sort=asc")
.get("/v1/activities")
.query({ page: 1, limit: 10, minHeight: 1, sort: "asc" })
.reply(200, mockResponse);
});

Expand Down
Loading

0 comments on commit 2c4077c

Please sign in to comment.