Skip to content

Commit

Permalink
feat: add cw-simulate for fetching data without limitation
Browse files Browse the repository at this point in the history
  • Loading branch information
perfogic committed Nov 26, 2024
1 parent 37b0dee commit 0c4d34a
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 30 deletions.
4 changes: 3 additions & 1 deletion packages/orchestrator/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.env.*
!.env.example
!.env.example
src/services/contract-simulate/data/final/*
src/services/contract-simulate/data/pending/*
47 changes: 35 additions & 12 deletions packages/orchestrator/src/bin/signer.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,46 @@
import { AppBitcoinClient, LightClientBitcoinClient } from '@oraichain/bitcoin-bridge-contracts-sdk';
import env from '../configs/env';
import { OraichainConfig } from '../configs/networks';
import SignerService from '../services/signer';
import { initSignerClient } from '../utils/cosmos';
import { decryptMnemonic } from '../utils/mnemonic';
import {
AppBitcoinClient,
LightClientBitcoinClient,
} from "@oraichain/bitcoin-bridge-contracts-sdk";
import env from "../configs/env";
import { OraichainConfig } from "../configs/networks";
import ContractSimulator from "../services/contract-simulate";
import SignerService from "../services/signer";
import { initSignerClient } from "../utils/cosmos";
import { decryptMnemonic } from "../utils/mnemonic";

const start = async () => {
let mnemonic = env.cosmos.mnemonic;
if (!mnemonic) {
mnemonic = decryptMnemonic('Mnemonic passphrase:', env.cosmos.encryptedMnemonic);
mnemonic = decryptMnemonic(
"Mnemonic passphrase:",
env.cosmos.encryptedMnemonic
);
}

const { prefix, gasPrice } = OraichainConfig;
const { sender, client } = await initSignerClient(
env.cosmos.rpcUrl,
mnemonic,
prefix,
gasPrice
);
const lightClientBitcoinClient = new LightClientBitcoinClient(
client,
sender,
env.cosmos.lightClientBitcoin
);
const appBitcoinClient = new AppBitcoinClient(
client,
sender,
env.cosmos.appBitcoin
);
ContractSimulator.setSender(sender);

const { sender, client } = await initSignerClient(env.cosmos.rpcUrl, mnemonic, prefix, gasPrice);
const lightClientBitcoinClient = new LightClientBitcoinClient(client, sender, env.cosmos.lightClientBitcoin);
const appBitcoinClient = new AppBitcoinClient(client, sender, env.cosmos.appBitcoin);

const signerService = new SignerService(lightClientBitcoinClient, appBitcoinClient);
const signerService = new SignerService(
lightClientBitcoinClient,
appBitcoinClient
);

await signerService.relay();
};
Expand Down
6 changes: 4 additions & 2 deletions packages/orchestrator/src/configs/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ const envVarsSchema = Joi.object()
BTC_RPC_USERNAME: Joi.string().default("satoshi"),
BTC_RPC_PASSWORD: Joi.string().default("nakamoto"),
BTC_NETWORK: Joi.string().default("testnet"),
COSMOS_RPC_URL: Joi.optional(),
COSMOS_RPC_URL: Joi.optional().default("https://rpc.orai.io"),
COSMOS_LCD_URL: Joi.optional().default("https://lcd.orai.io"),
LIGHT_CLIENT_BITCOIN_ADDRESS: Joi.string().error(
new Error("LIGHT_CLIENT_BITCOIN_ADDRESS is required")
),
Expand All @@ -25,7 +26,7 @@ const envVarsSchema = Joi.object()
LEGITIMATE_CHECKPOINT_INTERVAL: Joi.number().default(24 * 60 * 60),
DEPOSIT_BUFFER: Joi.number().error(new Error("DEPOSIT_BUFFER is required")),
STORAGE_DIR_NAME: Joi.string().default(".oraibtc-relayer"),
WEBHOOK_URL: Joi.string().optional(),
WEBHOOK_URL: Joi.string().allow("").optional(),
TRIGGER_BLOCK_INTERVAL: Joi.number().default(5 * 60 * 1000),
})
.unknown();
Expand Down Expand Up @@ -53,6 +54,7 @@ export default {
},
cosmos: {
rpcUrl: envVars.COSMOS_RPC_URL,
lcdUrl: envVars.COSMOS_LCD_URL,
encryptedMnemonic: envVars.ENCRYPTED_MNEMONIC,
mnemonic: envVars.MNEMONIC,
appBitcoin: envVars.APP_BITCOIN_ADDRESS,
Expand Down
1 change: 1 addition & 0 deletions packages/orchestrator/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export const RETRY_DELAY = 100; // 1 second
export const ITERATION_DELAY = {
RELAY_SIGNATURES_INTERVAL: 3000,
TRACK_MEMORY_LEAK: 10000,
SIMULATOR_INTERVAL: 5000,
};
Binary file not shown.
146 changes: 146 additions & 0 deletions packages/orchestrator/src/services/contract-simulate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { AppBitcoinClient } from "@oraichain/bitcoin-bridge-contracts-sdk";
import {
BufferCollection,
compare,
DownloadState,
SimulateCosmWasmClient,
SortedMap,
} from "@oraichain/cw-simulate";
import fs, { readFileSync } from "fs";
import path from "path";
import { setTimeout } from "timers/promises";
import env from "../../configs/env";
import { logger } from "../../configs/logger";
import { ITERATION_DELAY } from "../../constants";

class ContractSimulator {
static simulateAppCwBitcoin: AppBitcoinClient;
static simulateClient: SimulateCosmWasmClient = new SimulateCosmWasmClient({
chainId: "Oraichain",
bech32Prefix: "orai",
});
static finalState = new DownloadState(
env.cosmos.lcdUrl,
`${__dirname}/data/final`
);
static pendingState = new DownloadState(
env.cosmos.lcdUrl,
`${__dirname}/data/pending`
);
static logger = logger("ContractSimulator");
static initialized: boolean = false;
static sender: string = "orai1ehmhqcn8erf3dgavrca69zgp4rtxj5kqgtcnyd";

static stateCrawler = async () => {
this.logger.info("Starting download new state");
const source = `${__dirname}/data/pending`;
const dest = `${__dirname}/data/final`;

if (!fs.existsSync(source)) {
fs.mkdirSync(source, { recursive: true });
}

if (!fs.existsSync(dest)) {
fs.mkdirSync(dest, { recursive: true });
}

// download and copy to final state
await Promise.all([this.pendingState.saveState(env.cosmos.appBitcoin)]);
this.copyFolderContents(source, dest);
this.logger.info("Success update new state!");

// load new state
await Promise.all([
this.finalState.loadState(
this.simulateClient,
this.sender,
env.cosmos.appBitcoin,
"cw-app-bitcoin"
),
]);
this.simulateAppCwBitcoin = new AppBitcoinClient(
this.simulateClient as any,
this.sender,
env.cosmos.appBitcoin
);

this.initialized = true;

await Promise.all([
this.loadStateAndCode("cw-app-bitcoin.wasm", env.cosmos.appBitcoin),
]);
this.logger.info("Finish state crawler!");
};

static async tryInitializeWithOldData() {
try {
await Promise.all([
this.loadStateAndCode("cw-app-bitcoin.wasm", env.cosmos.appBitcoin),
]);
this.simulateAppCwBitcoin = new AppBitcoinClient(
this.simulateClient as any,
this.sender,
env.cosmos.appBitcoin
);
this.initialized = true;
} catch (err) {
this.logger.info(`[tryInitializeWithOldData] ${err}`);
}
}

static async loadStateAndCode(fileName: string, contractAddress: string) {
const code = readFileSync(path.join(__dirname, `data/wasm/${fileName}`));
const state = readFileSync(
path.join(__dirname, `data/final/${contractAddress}.state`)
);
const { codeId } = await this.simulateClient.upload(
this.sender,
code,
"auto"
);
const raw = SortedMap.rawPack(
new BufferCollection(state as any) as any,
compare
);
await this.simulateClient.loadContract(
env.cosmos.appBitcoin,
{
codeId: codeId,
admin: this.sender,
created: new Date().getTime(),
creator: "",
label: "",
},
raw
);
}

static copyFolderContents = (source: string, destination: string) => {
const files = fs.readdirSync(source);

files.forEach((file) => {
const currentFilePath = path.join(source, file);
const destinationFilePath = path.join(destination, file);

if (fs.lstatSync(currentFilePath).isDirectory()) {
this.copyFolderContents(currentFilePath, destinationFilePath);
} else {
fs.copyFileSync(currentFilePath, destinationFilePath);
}
});
};

static setSender(sender: string) {
this.sender = sender;
}

static async sync() {
this.tryInitializeWithOldData();
while (true) {
await this.stateCrawler();
await setTimeout(ITERATION_DELAY.SIMULATOR_INTERVAL);
}
}
}

export default ContractSimulator;
43 changes: 28 additions & 15 deletions packages/orchestrator/src/services/signer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { ITERATION_DELAY } from "../../constants";
import { getCurrentNetwork } from "../../utils/bitcoin";
import { wrappedExecuteTransaction } from "../../utils/cosmos";
import { RelayerInterface } from "../common/relayer.interface";
import ContractSimulator from "../contract-simulate";

class SignerService implements RelayerInterface {
lightClientBitcoinClient: LightClientBitcoinClient;
Expand All @@ -38,7 +39,7 @@ class SignerService implements RelayerInterface {

async relay() {
let { xpriv, xpub } = await this.loadOrGenerateXpriv();

ContractSimulator.sync();
const signatoryKey = await this.appBitcoinClient.signatoryKey({
addr: this.appBitcoinClient.sender,
});
Expand All @@ -51,10 +52,12 @@ class SignerService implements RelayerInterface {
}

this.logger.info(`Signer is running...`);
await this.startRelay({
xpriv,
xpub,
});
await Promise.all([
this.startRelay({
xpriv,
xpub,
}),
]);
}

async startRelay({ xpriv, xpub }: { xpriv: string; xpub: string }) {
Expand All @@ -69,6 +72,10 @@ class SignerService implements RelayerInterface {
const node = bip32.fromBase58(xpriv, getCurrentNetwork(this.network));

while (true) {
if (!ContractSimulator.initialized) {
await setTimeout(ITERATION_DELAY.RELAY_SIGNATURES_INTERVAL);
continue;
}
try {
let btcHeight = await this.lightClientBitcoinClient.headerHeight();
let buildingIndex = await this.appBitcoinClient.buildingIndex();
Expand All @@ -85,12 +92,13 @@ class SignerService implements RelayerInterface {

if (checkpoint.status === "signing") {
await this.checkChangeRate();
let signTxs = await this.appBitcoinClient.signingTxsAtCheckpointIndex(
{
xpub: encodeXpub({ key: xpub }),
checkpointIndex: previousIndex,
}
);
let signTxs =
await ContractSimulator.simulateAppCwBitcoin.signingTxsAtCheckpointIndex(
{
xpub: encodeXpub({ key: xpub }),
checkpointIndex: previousIndex,
}
);

if (signTxs.length > 0) {
// Fetch latest signed checkpoint height
Expand Down Expand Up @@ -154,7 +162,7 @@ class SignerService implements RelayerInterface {

async checkChangeRate() {
const { withdrawal, sigset_change } =
await this.appBitcoinClient.changeRates({
await ContractSimulator.simulateAppCwBitcoin.changeRates({
interval: env.signer.legitimateCheckpointInterval,
});
let sigsetChangeRate = sigset_change / 10000;
Expand All @@ -179,10 +187,15 @@ class SignerService implements RelayerInterface {
const node = bip32.fromBase58(xpriv, getCurrentNetwork(this.network));

while (true) {
if (!ContractSimulator.initialized) {
await setTimeout(ITERATION_DELAY.RELAY_SIGNATURES_INTERVAL);
continue;
}
try {
let signTxs = await this.appBitcoinClient.signingRecoveryTxs({
xpub: encodeXpub({ key: xpub }),
});
let signTxs =
await ContractSimulator.simulateAppCwBitcoin.signingRecoveryTxs({
xpub: encodeXpub({ key: xpub }),
});
let sigs = [];

if (signTxs.length > 0) {
Expand Down

0 comments on commit 0c4d34a

Please sign in to comment.