mirror of
https://github.com/EvernodeXRPL/sashimono.git
synced 2026-04-29 15:38:00 +00:00
Implemented initial steps for contract deployment
This commit is contained in:
@@ -78,7 +78,7 @@ async function main() {
|
||||
console.log('Data dir: ' + appenv.DATA_DIR);
|
||||
console.log('Using message board config: ' + appenv.MB_XRPL_CONFIG_PATH);
|
||||
|
||||
const rep = new ReputationD(appenv.CONFIG_PATH, appenv.SECRET_CONFIG_PATH, appenv.MB_XRPL_CONFIG_PATH);
|
||||
const rep = new ReputationD(appenv.CONFIG_PATH, appenv.SECRET_CONFIG_PATH, appenv.MB_XRPL_CONFIG_PATH, appenv.INSTANCE_IMAGE);
|
||||
await rep.init();
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
@@ -5,7 +5,8 @@ let appenv = {
|
||||
IS_DEV_MODE: process.env.REPUTATIOND_DEV === "1",
|
||||
FILE_LOG_ENABLED: process.env.REPUTATIOND_FILE_LOG === "1",
|
||||
DATA_DIR: process.env.REPUTATIOND_DATA_DIR || __dirname,
|
||||
DATA_DIR: process.env.REPUTATIOND_DATA_DIR || __dirname
|
||||
DATA_DIR: process.env.REPUTATIOND_DATA_DIR || __dirname,
|
||||
INSTANCE_IMAGE: 'evernode/sashimono:hp.0.6.4-ubt.20.04-njs.20',
|
||||
}
|
||||
|
||||
appenv = {
|
||||
|
||||
26
reputationd/lib/cli-handler.js
Normal file
26
reputationd/lib/cli-handler.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const { Buffer } = require('buffer');
|
||||
const { exec } = require("child_process");
|
||||
|
||||
class CliHelper {
|
||||
static async listInstances() {
|
||||
return await this.execCommand('evernode list');
|
||||
}
|
||||
|
||||
static execCommand(command) {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(command, { stdio: 'pipe' }, (err, stdout, stderr) => {
|
||||
if (err || stderr) {
|
||||
reject(err || stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
let message = Buffer.from(stdout).toString();
|
||||
resolve(JSON.parse(message.substring(0, message.length - 1))); // Skipping the \n from the result.
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
CliHelper
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
const fs = require('fs');
|
||||
const evernode = require('evernode-js-client');
|
||||
const crypto = require('crypto');
|
||||
const uuid = require('uuid');
|
||||
const { appenv } = require('./appenv');
|
||||
const { ConfigHelper } = require('./config-helper');
|
||||
const { CliHelper } = require('./cli-handler');
|
||||
|
||||
class ReputationD {
|
||||
#concurrencyQueue = {
|
||||
@@ -13,15 +17,22 @@ class ReputationD {
|
||||
#feeUpliftment = 0;
|
||||
#reportTimeQuota = 0.65; // Percentage of moment size.
|
||||
#contractInitTimeQuota = 0.1; // Percentage of moment size.
|
||||
#scoreFilePath = `/home/#USER#/#INSTANCE#/contract_fs/mnt/opinion.txt`
|
||||
|
||||
constructor(configPath, secretConfigPath, mbXrplConfigPath) {
|
||||
this.configPath = configPath;
|
||||
this.secretConfigPath = secretConfigPath;
|
||||
this.mbXrplConfigPath = mbXrplConfigPath;
|
||||
#configPath;
|
||||
#secretConfigPath;
|
||||
#mbXrplConfigPath;
|
||||
#instanceImage;
|
||||
|
||||
constructor(configPath, secretConfigPath, mbXrplConfigPath, instanceImage) {
|
||||
this.#configPath = configPath;
|
||||
this.#secretConfigPath = secretConfigPath;
|
||||
this.#mbXrplConfigPath = mbXrplConfigPath;
|
||||
this.#instanceImage = instanceImage;
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.readConfig();
|
||||
this.#readConfig();
|
||||
if (!this.cfg.version || !this.cfg.xrpl.address || !this.cfg.xrpl.secret)
|
||||
throw "Required cfg fields cannot be empty.";
|
||||
|
||||
@@ -279,16 +290,122 @@ class ReputationD {
|
||||
}, startTimeout);
|
||||
}
|
||||
|
||||
async #getUniverseInfo() {
|
||||
// TODO: Collect the universe info.
|
||||
return {
|
||||
id: '',
|
||||
hosts: ''
|
||||
};
|
||||
}
|
||||
|
||||
async #getInstancesInUniverse(universeId) {
|
||||
// TODO: Collect the universe info.
|
||||
return [];
|
||||
}
|
||||
|
||||
// Find the universe id and generate contract id.
|
||||
async #generateContractId(universeId) {
|
||||
// Generate a hash from the seed
|
||||
const hash = crypto.createHash('sha1').update(universeId).digest('hex');
|
||||
// Use a portion of the hash to generate a random UUID
|
||||
const id = uuid.v4({
|
||||
random: Buffer.from(hash.substring(0, 16), 'hex')
|
||||
});
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// Create and setup reputation contract.
|
||||
async #createReputationContract() {
|
||||
// TODO: Acquire instance from self host and deploy reputation contract.
|
||||
await this.#queueAction(async (submissionRefs) => {
|
||||
submissionRefs.refs ??= [{}];
|
||||
// Check again wether the transaction is validated before retry.
|
||||
const txHash = submissionRefs?.refs[0]?.submissionResult?.result?.tx_json?.hash;
|
||||
if (txHash) {
|
||||
const txResponse = await tenantClient.xrplApi.getTransactionValidatedResults(txHash);
|
||||
if (txResponse && txResponse.code === "tesSUCCESS") {
|
||||
console.log('Transaction is validated and success, Retry skipped!')
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const tenantClient = new evernode.TenantClient(this.hostClient.reputationAcc.address, this.hostClient.reputationAcc.secret);
|
||||
await tenantClient.connect();
|
||||
await tenantClient.prepareAccount();
|
||||
|
||||
const universeInfo = await this.#getUniverseInfo();
|
||||
const requirement = {
|
||||
owner_pubkey: ownerPubkey,
|
||||
contract_id: await this.#generateContractId(universeInfo.id),
|
||||
image: this.#instanceImage,
|
||||
config: {
|
||||
contract: {
|
||||
consensus: {
|
||||
roundtime: 5000
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Update the registry with the active instance count.
|
||||
const result = await tenantClient.acquireLease(this.hostClient.xrplAcc.address, requirement, {});
|
||||
|
||||
await tenantClient.disconnect();
|
||||
|
||||
const acquiredTimestamp = Date.now();
|
||||
|
||||
// Assign ip to domain and outbound_ip for instance created from old sashimono version.
|
||||
if ('ip' in result.instance) {
|
||||
result.instance.domain = result.instance.ip;
|
||||
delete result.instance.ip;
|
||||
}
|
||||
|
||||
this.cfg.contractInstance = { ...result.instance, created_timestamp: acquiredTimestamp };
|
||||
this.#persistConfig();
|
||||
|
||||
const instances = this.#getInstancesInUniverse(universeInfo.id);
|
||||
const overrideConfig = {
|
||||
unl: instances.map(p => `${p.pubkey}`),
|
||||
contract: {
|
||||
consensus: {
|
||||
roundtime: 2000
|
||||
}
|
||||
},
|
||||
mesh: {
|
||||
known_peers: instances.map(p => `${p.domain}:${p.port}`)
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Deploy the contract.
|
||||
});
|
||||
}
|
||||
|
||||
async #getScores() {
|
||||
const instanceName = this.cfg.contractInstance.name;
|
||||
if (!instanceName)
|
||||
throw 'No available reputation contract running.';
|
||||
|
||||
const instances = await CliHelper.listInstances();
|
||||
|
||||
const instance = instances.find(i => i.name === instanceName);
|
||||
|
||||
if (!instance) {
|
||||
this.cfg.contractInstance = {};
|
||||
this.#persistConfig();
|
||||
|
||||
throw 'No contract instance matching with the configuration.';
|
||||
}
|
||||
|
||||
const path = this.#scoreFilePath.replace('#USER#', instance.user).replace('#INSTANCE#', instance.name);
|
||||
|
||||
if (!fs.existsSync(path))
|
||||
throw 'Scores file does not exist.';
|
||||
|
||||
return JSON.parse(path);
|
||||
}
|
||||
|
||||
// Reputation sender.
|
||||
async #sendReputations() {
|
||||
// TODO: Get reputation scores from the contract.
|
||||
const scores = {};
|
||||
|
||||
await this.#queueAction(async (submissionRefs) => {
|
||||
submissionRefs.refs ??= [{}];
|
||||
// Check again wether the transaction is validated before retry.
|
||||
@@ -301,6 +418,9 @@ class ReputationD {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Get reputation scores from the contract.
|
||||
const scores = await this.#getScores();
|
||||
|
||||
let ongoingReputation = false;
|
||||
const currentMoment = await this.hostClient.getMoment();
|
||||
|
||||
@@ -329,12 +449,12 @@ class ReputationD {
|
||||
}, this.#reputationRetryCount, this.#reputationRetryDelay);
|
||||
}
|
||||
|
||||
readConfig() {
|
||||
this.cfg = ConfigHelper.readConfig(this.configPath, this.secretConfigPath, this.mbXrplConfigPath);
|
||||
#readConfig() {
|
||||
this.cfg = ConfigHelper.readConfig(this.#configPath, this.#secretConfigPath, this.#mbXrplConfigPath);
|
||||
}
|
||||
|
||||
persistConfig() {
|
||||
ConfigHelper.writeConfig(this.cfg, this.configPath);
|
||||
#persistConfig() {
|
||||
ConfigHelper.writeConfig(this.cfg, this.#configPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ class Setup {
|
||||
xrpl: {
|
||||
address: address,
|
||||
secretPath: secretPath
|
||||
}
|
||||
},
|
||||
contractInstance: {}
|
||||
};
|
||||
|
||||
this.#saveConfig(baseConfig);
|
||||
|
||||
15
reputationd/package-lock.json
generated
15
reputationd/package-lock.json
generated
@@ -6,7 +6,8 @@
|
||||
"": {
|
||||
"name": "reputationd",
|
||||
"dependencies": {
|
||||
"evernode-js-client": "0.6.42"
|
||||
"evernode-js-client": "0.6.42",
|
||||
"uuid": "9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "8.3.0"
|
||||
@@ -1934,6 +1935,18 @@
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-compile-cache": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz",
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"build": "npm run lint && ncc build app.js --minify -o dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"evernode-js-client": "0.6.42"
|
||||
"evernode-js-client": "0.6.42",
|
||||
"uuid": "9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "8.3.0"
|
||||
|
||||
Reference in New Issue
Block a user