@instadapp/interop-x 0.0.0-dev.9b1fcb8 → 0.0.0-dev.a846f65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +5 -5
- package/dist/src/api/index.js +3 -3
- package/dist/src/config/index.js +1 -0
- package/dist/src/index.js +44 -5
- package/dist/src/net/peer/index.js +2 -1
- package/dist/src/net/pool/index.js +18 -2
- package/dist/src/net/protocol/dial/SignatureDialProtocol.1.js +28 -0
- package/dist/src/net/protocol/index.js +41 -1
- package/dist/src/tasks/AutoUpdateTask.js +67 -0
- package/dist/src/tasks/BaseTask.js +7 -3
- package/dist/src/tasks/InteropBridge/ProcessWithdrawEvents.js +146 -0
- package/dist/src/tasks/InteropBridge/SyncWithdrawEvents.js +2 -1
- package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +3 -1
- package/dist/src/tasks/InteropXGateway/SyncDepositEvents.js +0 -1
- package/dist/src/tasks/Transactions/SyncTransactionStatusTask.js +53 -0
- package/dist/src/tasks/index.js +8 -0
- package/dist/src/utils/index.js +68 -8
- package/package.json +5 -5
- package/src/api/index.ts +2 -2
- package/src/config/index.ts +2 -0
- package/src/index.ts +56 -7
- package/src/net/peer/index.ts +2 -1
- package/src/net/pool/index.ts +25 -5
- package/src/net/protocol/dial/SignatureDialProtocol.1.ts +31 -0
- package/src/net/protocol/index.ts +57 -1
- package/src/tasks/AutoUpdateTask.ts +81 -0
- package/src/tasks/BaseTask.ts +8 -3
- package/src/tasks/InteropBridge/ProcessWithdrawEvents.ts +231 -0
- package/src/tasks/InteropBridge/SyncWithdrawEvents.ts +3 -3
- package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +4 -2
- package/src/tasks/InteropXGateway/SyncDepositEvents.ts +0 -2
- package/src/tasks/Transactions/SyncTransactionStatusTask.ts +65 -0
- package/src/tasks/index.ts +11 -0
- package/src/utils/index.ts +88 -7
@@ -0,0 +1,53 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const BaseTask_1 = require("../BaseTask");
|
7
|
+
const logger_1 = __importDefault(require("@/logger"));
|
8
|
+
const net_1 = require("@/net");
|
9
|
+
const db_1 = require("@/db");
|
10
|
+
const sequelize_1 = require("sequelize");
|
11
|
+
class SyncTransactionStatusTask extends BaseTask_1.BaseTask {
|
12
|
+
constructor() {
|
13
|
+
super({
|
14
|
+
logger: new logger_1.default("SyncTransactionStatusTask"),
|
15
|
+
});
|
16
|
+
this.pollIntervalMs = 60 * 1000;
|
17
|
+
this.exceptLeadNode = true;
|
18
|
+
}
|
19
|
+
async pollHandler() {
|
20
|
+
// if transaction is pending for more than 1 hour, check lead node for status
|
21
|
+
const leadNode = net_1.peerPool.getLeadPeer();
|
22
|
+
if (!leadNode) {
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
const transaction = await db_1.Transaction.findOne({
|
26
|
+
where: {
|
27
|
+
status: 'pending',
|
28
|
+
sourceCreatedAt: {
|
29
|
+
[sequelize_1.Op.gte]: new Date(Date.now() - 60 * 60 * 1000),
|
30
|
+
},
|
31
|
+
}
|
32
|
+
});
|
33
|
+
if (!transaction) {
|
34
|
+
return;
|
35
|
+
}
|
36
|
+
this.logger.info(`Requesting transaction status for ${transaction.transactionHash}`);
|
37
|
+
const transactionStatus = await net_1.protocol.requestTransactionStatus(transaction.transactionHash, leadNode.id);
|
38
|
+
if (!transactionStatus) {
|
39
|
+
return;
|
40
|
+
}
|
41
|
+
this.logger.info(`Received transaction status for ${transaction.transactionHash}`);
|
42
|
+
transaction.sourceStatus = transactionStatus.sourceStatus;
|
43
|
+
transaction.sourceTransactionHash = transactionStatus.sourceTransactionHash;
|
44
|
+
transaction.sourceErrors = transactionStatus.sourceErrors;
|
45
|
+
transaction.targetStatus = transactionStatus.targetStatus;
|
46
|
+
transaction.targetTransactionHash = transactionStatus.targetTransactionHash;
|
47
|
+
transaction.targetErrors = transactionStatus.targetErrors;
|
48
|
+
transaction.status = transactionStatus.status;
|
49
|
+
await transaction.save();
|
50
|
+
this.logger.info(`Updated transaction status for ${transaction.transactionHash}`);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
exports.default = SyncTransactionStatusTask;
|
package/dist/src/tasks/index.js
CHANGED
@@ -7,9 +7,14 @@ exports.Tasks = void 0;
|
|
7
7
|
const ProcessDepositEvents_1 = __importDefault(require("./InteropXGateway/ProcessDepositEvents"));
|
8
8
|
const SyncDepositEvents_1 = __importDefault(require("./InteropXGateway/SyncDepositEvents"));
|
9
9
|
const SyncWithdrawEvents_1 = __importDefault(require("./InteropBridge/SyncWithdrawEvents"));
|
10
|
+
const ProcessWithdrawEvents_1 = __importDefault(require("./InteropBridge/ProcessWithdrawEvents"));
|
11
|
+
const AutoUpdateTask_1 = __importDefault(require("./AutoUpdateTask"));
|
12
|
+
const SyncTransactionStatusTask_1 = __importDefault(require("./Transactions/SyncTransactionStatusTask"));
|
10
13
|
class Tasks {
|
11
14
|
constructor() {
|
12
15
|
this.tasks = [
|
16
|
+
new SyncTransactionStatusTask_1.default(),
|
17
|
+
new AutoUpdateTask_1.default(),
|
13
18
|
new SyncDepositEvents_1.default({
|
14
19
|
chainId: 43114
|
15
20
|
}),
|
@@ -19,6 +24,9 @@ class Tasks {
|
|
19
24
|
new SyncWithdrawEvents_1.default({
|
20
25
|
chainId: 137,
|
21
26
|
itokenAddress: '0xEab02fe1F016eE3e4106c1C6aad35FeEe657268E',
|
27
|
+
}),
|
28
|
+
new ProcessWithdrawEvents_1.default({
|
29
|
+
chainId: 137,
|
22
30
|
})
|
23
31
|
];
|
24
32
|
}
|
package/dist/src/utils/index.js
CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.getContract = exports.buildDataForTransaction = exports.generateInteropTransactionHash = exports.asyncCallWithTimeout = exports.buildSignatureBytes = exports.getRpcProviderUrl = exports.signGnosisSafeTx = exports.short = exports.http = void 0;
|
6
|
+
exports.getContract = exports.buildWithdrawDataForTransaction = exports.buildDepositDataForTransaction = exports.buildDataForTransaction = exports.generateInteropTransactionHash = exports.asyncCallWithTimeout = exports.buildSignatureBytes = exports.getRpcProviderUrl = exports.signGnosisSafeTx = exports.short = exports.shortenHash = exports.http = void 0;
|
7
7
|
/**
|
8
8
|
* @module util
|
9
9
|
*/
|
@@ -16,6 +16,16 @@ const config_1 = __importDefault(require("@/config"));
|
|
16
16
|
const abi_1 = __importDefault(require("@/abi"));
|
17
17
|
exports.http = axios_1.default.create();
|
18
18
|
(0, axios_retry_1.default)(exports.http, { retries: 3, retryDelay: axios_retry_1.default.exponentialDelay });
|
19
|
+
function shortenHash(hash, length = 4) {
|
20
|
+
if (!hash)
|
21
|
+
return;
|
22
|
+
if (hash.length < 12)
|
23
|
+
return hash;
|
24
|
+
const beginningChars = hash.startsWith("0x") ? length + 2 : length;
|
25
|
+
const shortened = hash.substr(0, beginningChars) + "…" + hash.substr(-length);
|
26
|
+
return shortened;
|
27
|
+
}
|
28
|
+
exports.shortenHash = shortenHash;
|
19
29
|
function short(buffer) {
|
20
30
|
return buffer.toString('hex').slice(0, 8) + '...';
|
21
31
|
}
|
@@ -59,11 +69,11 @@ exports.signGnosisSafeTx = signGnosisSafeTx;
|
|
59
69
|
const getRpcProviderUrl = (chainId) => {
|
60
70
|
switch (chainId) {
|
61
71
|
case 1:
|
62
|
-
return 'https://rpc.
|
72
|
+
return 'https://rpc.ankr.com/eth';
|
63
73
|
case 137:
|
64
|
-
return 'https://rpc.
|
74
|
+
return 'https://rpc.ankr.com/polygon';
|
65
75
|
case 43114:
|
66
|
-
return 'https://rpc.
|
76
|
+
return 'https://rpc.ankr.com/avalanche';
|
67
77
|
default:
|
68
78
|
throw new Error(`Unknown chainId: ${chainId}`);
|
69
79
|
}
|
@@ -104,9 +114,20 @@ const generateInteropTransactionHash = (data) => {
|
|
104
114
|
exports.generateInteropTransactionHash = generateInteropTransactionHash;
|
105
115
|
const buildDataForTransaction = async (transaction, type) => {
|
106
116
|
type = type || transaction.sourceStatus === 'pending' ? 'source' : 'target';
|
117
|
+
switch (transaction.action) {
|
118
|
+
case "deposit":
|
119
|
+
return await (0, exports.buildDepositDataForTransaction)(transaction, type);
|
120
|
+
case "withdraw":
|
121
|
+
return await (0, exports.buildWithdrawDataForTransaction)(transaction, type);
|
122
|
+
default:
|
123
|
+
throw new Error(`Unknown action: ${transaction.action}`);
|
124
|
+
}
|
125
|
+
};
|
126
|
+
exports.buildDataForTransaction = buildDataForTransaction;
|
127
|
+
const buildDepositDataForTransaction = async (transaction, type) => {
|
107
128
|
const transactions = [];
|
108
|
-
if (transaction.action
|
109
|
-
throw new Error(
|
129
|
+
if (transaction.action !== 'deposit') {
|
130
|
+
throw new Error(`Invalid action: ${transaction.action}`);
|
110
131
|
}
|
111
132
|
if (transaction.action === 'deposit' && transaction.sourceStatus === 'pending') {
|
112
133
|
throw Error('Cannot build data for pending deposit transaction');
|
@@ -125,7 +146,7 @@ const buildDataForTransaction = async (transaction, type) => {
|
|
125
146
|
const targetChainProvider = new ethers_1.ethers.providers.JsonRpcProvider((0, exports.getRpcProviderUrl)(transaction.targetChainId));
|
126
147
|
const targetWallet = new ethers_1.ethers.Wallet(config_1.default.privateKey, targetChainProvider);
|
127
148
|
const interopBridgeContract = getContract(itoken.address, abi_1.default.interopBridgeToken, targetWallet);
|
128
|
-
const { data } = await interopBridgeContract.populateTransaction.mint(transaction.submitEvent.user, ethers_1.ethers.BigNumber.from(transaction.submitEvent.amount.toString()), ethers_1.ethers.BigNumber.from(transaction.submitEvent.sourceChainId.toString()), transaction.
|
149
|
+
const { data } = await interopBridgeContract.populateTransaction.mint(transaction.submitEvent.user, ethers_1.ethers.BigNumber.from(transaction.submitEvent.amount.toString()), ethers_1.ethers.BigNumber.from(transaction.submitEvent.sourceChainId.toString()), transaction.submitTransactionHash);
|
129
150
|
transactions.push({
|
130
151
|
to: itoken.address,
|
131
152
|
data: data,
|
@@ -134,12 +155,51 @@ const buildDataForTransaction = async (transaction, type) => {
|
|
134
155
|
});
|
135
156
|
return (0, ethers_multisend_1.encodeMulti)(transactions).data;
|
136
157
|
};
|
137
|
-
exports.
|
158
|
+
exports.buildDepositDataForTransaction = buildDepositDataForTransaction;
|
159
|
+
const buildWithdrawDataForTransaction = async (transaction, type) => {
|
160
|
+
const transactions = [];
|
161
|
+
if (transaction.action !== 'withdraw') {
|
162
|
+
throw new Error(`Invalid action: ${transaction.action}`);
|
163
|
+
}
|
164
|
+
if (transaction.action === 'withdraw' && transaction.sourceStatus === 'pending') {
|
165
|
+
throw Error('Cannot build data for pending withdraw transaction');
|
166
|
+
}
|
167
|
+
if (!transaction.submitEvent) {
|
168
|
+
throw Error('Cannot build data for transaction without submitEvent');
|
169
|
+
}
|
170
|
+
const { to, amount, chainId, itoken: itokenAddress } = transaction.submitEvent;
|
171
|
+
const itoken = constants_1.itokens[transaction.sourceChainId].find(token => token.address.toLowerCase() === itokenAddress.toLowerCase());
|
172
|
+
if (!itoken) {
|
173
|
+
throw Error('Cannot build data for transaction without itoken');
|
174
|
+
}
|
175
|
+
const token = constants_1.tokens[chainId].find(t => t.symbol.toLowerCase() === itoken.symbol.toLowerCase());
|
176
|
+
if (!token) {
|
177
|
+
throw Error('Cannot build data for transaction without token');
|
178
|
+
}
|
179
|
+
const targetChainProvider = new ethers_1.ethers.providers.JsonRpcProvider((0, exports.getRpcProviderUrl)(transaction.targetChainId));
|
180
|
+
const targetWallet = new ethers_1.ethers.Wallet(config_1.default.privateKey, targetChainProvider);
|
181
|
+
const gatewayAddress = constants_1.addresses[chainId].interopXGateway;
|
182
|
+
const interopBridgeContract = getContract(gatewayAddress, abi_1.default.interopXGateway, targetWallet);
|
183
|
+
const { data } = await interopBridgeContract.populateTransaction.systemWithdraw(ethers_1.ethers.BigNumber.from(amount.toString()), to, token.address, ethers_1.ethers.BigNumber.from(transaction.sourceChainId.toString()), transaction.submitTransactionHash);
|
184
|
+
transactions.push({
|
185
|
+
to: gatewayAddress,
|
186
|
+
data: data,
|
187
|
+
value: '0',
|
188
|
+
operation: ethers_multisend_1.OperationType.Call,
|
189
|
+
});
|
190
|
+
return (0, ethers_multisend_1.encodeMulti)(transactions).data;
|
191
|
+
};
|
192
|
+
exports.buildWithdrawDataForTransaction = buildWithdrawDataForTransaction;
|
138
193
|
function getContract(address, contractInterface, signerOrProvider) {
|
139
194
|
if (!ethers_1.ethers.utils.getAddress(address) || address === ethers_1.ethers.constants.AddressZero) {
|
140
195
|
throw Error(`Invalid 'address' parameter '${address}'.`);
|
141
196
|
}
|
142
197
|
const contract = new ethers_1.ethers.Contract(address, contractInterface, signerOrProvider);
|
198
|
+
// Make sure the contract properties is writable
|
199
|
+
const desc = Object.getOwnPropertyDescriptor(contract, 'functions');
|
200
|
+
if (!desc || desc.writable !== true) {
|
201
|
+
return contract;
|
202
|
+
}
|
143
203
|
return new Proxy(contract, {
|
144
204
|
get(target, prop, receiver) {
|
145
205
|
const value = Reflect.get(target, prop, receiver);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@instadapp/interop-x",
|
3
|
-
"version": "0.0.0-dev.
|
3
|
+
"version": "0.0.0-dev.a846f65",
|
4
4
|
"license": "MIT",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"engines": {
|
@@ -24,9 +24,10 @@
|
|
24
24
|
},
|
25
25
|
"dependencies": {
|
26
26
|
"@achingbrain/libp2p-gossipsub": "^0.12.2",
|
27
|
+
"@fastify/cors": "^7.0.0",
|
28
|
+
"await-spawn": "^4.0.2",
|
27
29
|
"axios": "^0.27.1",
|
28
30
|
"axios-retry": "^3.2.4",
|
29
|
-
"bignumber.js": "^9.0.2",
|
30
31
|
"chalk": "4.1.2",
|
31
32
|
"dotenv": "^16.0.0",
|
32
33
|
"ethereumjs-util": "^7.1.4",
|
@@ -34,7 +35,6 @@
|
|
34
35
|
"ethers-multisend": "^2.1.1",
|
35
36
|
"expand-home-dir": "^0.0.3",
|
36
37
|
"fastify": "^3.28.0",
|
37
|
-
"fastify-cors": "^6.0.3",
|
38
38
|
"libp2p": "^0.36.2",
|
39
39
|
"libp2p-bootstrap": "^0.14.0",
|
40
40
|
"libp2p-kad-dht": "^0.28.6",
|
@@ -46,6 +46,8 @@
|
|
46
46
|
"libp2p-websockets": "^0.16.2",
|
47
47
|
"luxon": "^2.3.2",
|
48
48
|
"module-alias": "^2.2.2",
|
49
|
+
"patch-package": "^6.4.7",
|
50
|
+
"postinstall-postinstall": "^2.1.0",
|
49
51
|
"sequelize": "6.18.0",
|
50
52
|
"sqlite3": "^5.0.5",
|
51
53
|
"waait": "^1.0.5"
|
@@ -60,8 +62,6 @@
|
|
60
62
|
"@types/fs-extra": "^9.0.13",
|
61
63
|
"@types/node": "^17.0.17",
|
62
64
|
"nodemon": "^2.0.15",
|
63
|
-
"patch-package": "^6.4.7",
|
64
|
-
"postinstall-postinstall": "^2.1.0",
|
65
65
|
"replace-in-file": "^6.3.2",
|
66
66
|
"rimraf": "^3.0.2",
|
67
67
|
"ts-node": "^10.5.0",
|
package/src/api/index.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import fastify from "fastify"
|
2
|
-
import cors from 'fastify
|
2
|
+
import cors from '@fastify/cors'
|
3
3
|
import Logger from "@/logger"
|
4
4
|
import { Transaction } from "@/db";
|
5
5
|
|
@@ -27,7 +27,7 @@ export const startApiServer = async () => {
|
|
27
27
|
|
28
28
|
logger.log(`RPC Server listening at http://${HOST}:${PORT}`)
|
29
29
|
} catch (err) {
|
30
|
-
logger.error(err)
|
30
|
+
logger.error(err.message)
|
31
31
|
process.exit(1)
|
32
32
|
}
|
33
33
|
}
|
package/src/config/index.ts
CHANGED
@@ -8,12 +8,14 @@ class Config {
|
|
8
8
|
public readonly privateKey: string
|
9
9
|
public readonly wallet: Wallet
|
10
10
|
public readonly staging: boolean
|
11
|
+
public readonly autoUpdate: boolean
|
11
12
|
|
12
13
|
constructor() {
|
13
14
|
this.events = new EventBus() as EventBusType
|
14
15
|
this.maxPeers = 10
|
15
16
|
this.privateKey = process.env.PRIVATE_KEY as string;
|
16
17
|
this.staging = !! process.env.STAGING && process.env.STAGING === 'true';
|
18
|
+
this.autoUpdate = !! process.env.AUTO_UPDATE && process.env.AUTO_UPDATE === 'true';
|
17
19
|
this.wallet = new Wallet(this.privateKey);
|
18
20
|
this.leadNodeAddress = '0x910E413DBF3F6276Fe8213fF656726bDc142E08E'
|
19
21
|
}
|
package/src/index.ts
CHANGED
@@ -16,8 +16,8 @@ moduleAlias.addAliases({
|
|
16
16
|
})
|
17
17
|
|
18
18
|
moduleAlias();
|
19
|
-
import assert from "assert";
|
20
19
|
import dotenv from "dotenv";
|
20
|
+
import chalk from 'chalk';
|
21
21
|
import { ethers } from "ethers";
|
22
22
|
import packageJson from '../package.json'
|
23
23
|
dotenv.config();
|
@@ -25,28 +25,46 @@ dotenv.config();
|
|
25
25
|
import Logger from "@/logger";
|
26
26
|
const logger = new Logger('Process')
|
27
27
|
|
28
|
-
|
29
|
-
if (process.argv.at(-1) === 'help') {
|
28
|
+
const printUsage = () => {
|
30
29
|
console.log('Usage:')
|
31
30
|
console.log(' PRIVATE_KEY=abcd1234 interop-x')
|
32
31
|
console.log(' PRIVATE_KEY=abcd1234 STAGING=true interop-x')
|
32
|
+
console.log(' PRIVATE_KEY=abcd1234 AUTO_UPDATE=true interop-x')
|
33
|
+
console.log(' PRIVATE_KEY=abcd1234 API_HOST=0.0.0.0 API_PORT=8080 interop-x')
|
34
|
+
}
|
35
|
+
|
36
|
+
if (process.argv.at(-1) === 'help') {
|
37
|
+
printUsage()
|
33
38
|
process.exit(0)
|
34
39
|
}
|
35
40
|
|
36
|
-
|
41
|
+
const GIT_SHORT_HASH = '@GIT_SHORT_HASH@';
|
37
42
|
|
43
|
+
if (process.argv.at(-1) === 'version') {
|
44
|
+
console.log(`Interop X Node (v${packageJson.version} - rev.${GIT_SHORT_HASH})`)
|
45
|
+
process.exit(0)
|
46
|
+
}
|
47
|
+
|
48
|
+
if(! process.env.PRIVATE_KEY) {
|
49
|
+
console.error(chalk.bgRed.white.bold('Please provide a private key\n'))
|
50
|
+
printUsage()
|
51
|
+
process.exit(1)
|
52
|
+
}
|
38
53
|
try {
|
39
54
|
new ethers.Wallet(process.env.PRIVATE_KEY!)
|
40
55
|
} catch (e) {
|
41
|
-
|
56
|
+
console.error(chalk.bgRed.white('Invalid private key\n'))
|
57
|
+
printUsage()
|
42
58
|
process.exit(1)
|
43
59
|
}
|
44
60
|
|
45
|
-
logger.debug(`Starting Interop X Node (v${packageJson.version} - rev
|
61
|
+
logger.debug(`Starting Interop X Node (v${packageJson.version} - rev.${GIT_SHORT_HASH})`)
|
46
62
|
|
47
63
|
import { Tasks } from "@/tasks";
|
48
|
-
import { startPeer } from "@/net";
|
64
|
+
import { startPeer, protocol, peerPool } from "@/net";
|
49
65
|
import { startApiServer } from '@/api';
|
66
|
+
import { Transaction } from './db';
|
67
|
+
import { shortenHash } from './utils';
|
50
68
|
|
51
69
|
async function main() {
|
52
70
|
|
@@ -57,6 +75,37 @@ async function main() {
|
|
57
75
|
tasks.start();
|
58
76
|
|
59
77
|
startApiServer()
|
78
|
+
|
79
|
+
protocol.on('TransactionStatus', async (payload) => {
|
80
|
+
if (!peerPool.isLeadNode(payload.peerId)) {
|
81
|
+
const peer = peerPool.getPeer(payload.peerId)
|
82
|
+
|
83
|
+
if(! peer) {
|
84
|
+
return;
|
85
|
+
}
|
86
|
+
|
87
|
+
logger.info(`ignored transaction status from ${payload.peerId} ${shortenHash(peer.publicAddress)} `)
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
|
91
|
+
const transaction = await Transaction.findOne({ where: { transactionHash: payload.data.transactionHash } })
|
92
|
+
|
93
|
+
if (!transaction) {
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
|
97
|
+
transaction.sourceStatus = payload.data.sourceStatus
|
98
|
+
transaction.sourceTransactionHash = payload.data.sourceTransactionHash
|
99
|
+
transaction.sourceErrors = payload.data.sourceErrors
|
100
|
+
|
101
|
+
transaction.targetStatus = payload.data.targetStatus
|
102
|
+
transaction.targetTransactionHash = payload.data.targetTransactionHash
|
103
|
+
transaction.targetErrors = payload.data.targetErrors
|
104
|
+
|
105
|
+
transaction.status = payload.data.status
|
106
|
+
|
107
|
+
await transaction.save()
|
108
|
+
})
|
60
109
|
}
|
61
110
|
|
62
111
|
main()
|
package/src/net/peer/index.ts
CHANGED
@@ -17,6 +17,7 @@ import KadDHT from "libp2p-kad-dht";
|
|
17
17
|
import PubsubPeerDiscovery from "libp2p-pubsub-peer-discovery";
|
18
18
|
import { protocol } from "@/net";
|
19
19
|
import config from "@/config";
|
20
|
+
import chalk from "chalk";
|
20
21
|
|
21
22
|
const logger = new Logger("Peer");
|
22
23
|
|
@@ -80,7 +81,7 @@ export const startPeer = async ({ }: IPeerOptions) => {
|
|
80
81
|
},
|
81
82
|
});
|
82
83
|
|
83
|
-
logger.info("Peer ID:", node.peerId.toB58String());
|
84
|
+
logger.info("Peer ID:", chalk.bold(node.peerId.toB58String()));
|
84
85
|
|
85
86
|
await node.start();
|
86
87
|
|
package/src/net/pool/index.ts
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
import { Event } from "@/types";
|
2
2
|
import config from "@/config";
|
3
3
|
import Logger from "@/logger";
|
4
|
+
import { getAddress } from "ethers/lib/utils";
|
5
|
+
import { shortenHash } from "@/utils";
|
6
|
+
import chalk from "chalk";
|
4
7
|
|
5
8
|
|
6
9
|
const logger = new Logger('PeerPool')
|
@@ -83,10 +86,10 @@ export class PeerPool {
|
|
83
86
|
const newPeer = !this.pool.get(peer.id);
|
84
87
|
this.pool.set(peer.id, peer)
|
85
88
|
peer.pooled = true
|
86
|
-
|
87
|
-
if(newPeer) {
|
89
|
+
|
90
|
+
if (newPeer) {
|
88
91
|
config.events.emit(Event.POOL_PEER_ADDED, peer)
|
89
|
-
logger.info(`Peer ${peer.id} with address ${peer.publicAddress} added to pool`)
|
92
|
+
logger.info(`Peer ${chalk.bold(shortenHash(peer.id, 16))} with address ${chalk.bold(shortenHash(peer.publicAddress))} added to pool`)
|
90
93
|
}
|
91
94
|
}
|
92
95
|
}
|
@@ -101,7 +104,7 @@ export class PeerPool {
|
|
101
104
|
if (this.pool.delete(peer.id)) {
|
102
105
|
peer.pooled = false
|
103
106
|
config.events.emit(Event.POOL_PEER_REMOVED, peer)
|
104
|
-
logger.info(`Peer ${peer.id} with address ${peer.publicAddress} removed from pool`)
|
107
|
+
logger.info(`Peer ${chalk.bold(shortenHash(peer.id, 16))} with address ${chalk.bold(shortenHash(peer.publicAddress))} removed from pool`)
|
105
108
|
}
|
106
109
|
}
|
107
110
|
}
|
@@ -110,7 +113,7 @@ export class PeerPool {
|
|
110
113
|
this.cleanup()
|
111
114
|
|
112
115
|
return this.peers.filter((p) => {
|
113
|
-
if(!p.pooled) return false;
|
116
|
+
if (!p.pooled) return false;
|
114
117
|
|
115
118
|
const now = new Date()
|
116
119
|
|
@@ -122,6 +125,23 @@ export class PeerPool {
|
|
122
125
|
return this.activePeers.map((p) => p.id)
|
123
126
|
}
|
124
127
|
|
128
|
+
getPeer(id: string){
|
129
|
+
return this.pool.get(id);
|
130
|
+
}
|
131
|
+
|
132
|
+
isLeadNode(id: string) {
|
133
|
+
const peer = this.pool.get(id);
|
134
|
+
|
135
|
+
if (!peer) {
|
136
|
+
return false;
|
137
|
+
}
|
138
|
+
|
139
|
+
return getAddress(peer.publicAddress) === getAddress(config.leadNodeAddress)
|
140
|
+
}
|
141
|
+
|
142
|
+
getLeadPeer() {
|
143
|
+
return this.peers.find((p) => this.isLeadNode(p.id))
|
144
|
+
}
|
125
145
|
|
126
146
|
cleanup() {
|
127
147
|
// let compDate = Date.now() - this.PEERS_CLEANUP_TIME_LIMIT * 60
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { BaseDialProtocol } from "./BaseDialProtocol";
|
2
|
+
import { Transaction } from "@/db";
|
3
|
+
|
4
|
+
export class TransactionStatusDialProtocol extends BaseDialProtocol<string, Pick<Transaction, 'transactionHash' | 'sourceStatus' | 'sourceTransactionHash' | 'sourceErrors' | 'targetStatus' | 'targetTransactionHash' | 'targetErrors' | 'status'> | null> {
|
5
|
+
protected timeout = 30000;
|
6
|
+
|
7
|
+
constructor(libp2p) {
|
8
|
+
super(libp2p, '/interop-x/transaction-status')
|
9
|
+
}
|
10
|
+
|
11
|
+
async response(transactionHash: string){
|
12
|
+
const transaction = await Transaction.findOne({ where: { transactionHash } })
|
13
|
+
|
14
|
+
if(! transaction){
|
15
|
+
return null
|
16
|
+
}
|
17
|
+
return {
|
18
|
+
transactionHash: transaction.transactionHash,
|
19
|
+
|
20
|
+
sourceStatus: transaction.sourceStatus,
|
21
|
+
sourceTransactionHash: transaction.sourceTransactionHash,
|
22
|
+
sourceErrors: transaction.sourceErrors,
|
23
|
+
|
24
|
+
targetStatus: transaction.targetStatus,
|
25
|
+
targetTransactionHash: transaction.targetTransactionHash,
|
26
|
+
targetErrors: transaction.targetErrors,
|
27
|
+
|
28
|
+
status: transaction.status,
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
@@ -5,6 +5,8 @@ import { SignatureDialProtocol, ISignatureRequest, ISignatureResponse } from "./
|
|
5
5
|
import { IPeerInfo, peerPool } from "..";
|
6
6
|
import config from "@/config";
|
7
7
|
import { Event } from "@/types";
|
8
|
+
import { Transaction } from "@/db";
|
9
|
+
import { TransactionStatusDialProtocol } from "./dial/SignatureDialProtocol.1";
|
8
10
|
|
9
11
|
export interface ProtocolOptions {
|
10
12
|
/* Handshake timeout in ms (default: 8000) */
|
@@ -33,7 +35,12 @@ interface PeerInfoEvent extends BaseMessageEvent {
|
|
33
35
|
data: Omit<IPeerInfo, 'id' | 'updated' | 'idle' | 'pooled'>
|
34
36
|
}
|
35
37
|
|
38
|
+
interface TransactionStatusEvent extends BaseMessageEvent {
|
39
|
+
data: Pick<Transaction, 'transactionHash' | 'sourceStatus' | 'sourceTransactionHash' | 'sourceErrors' | 'targetStatus' | 'targetTransactionHash' | 'targetErrors' | 'status'>
|
40
|
+
}
|
41
|
+
|
36
42
|
declare interface Protocol {
|
43
|
+
on(event: 'TransactionStatus', listener: (payload: TransactionStatusEvent) => void): this;
|
37
44
|
on(event: 'PeerInfo', listener: (payload: PeerInfoEvent) => void): this;
|
38
45
|
on(event: string, listener: (payload: BaseMessageEvent) => void): this;
|
39
46
|
}
|
@@ -44,7 +51,7 @@ class Protocol extends EventEmitter {
|
|
44
51
|
private protocolMessages: Message[] = [
|
45
52
|
{
|
46
53
|
name: 'PeerInfo',
|
47
|
-
code:
|
54
|
+
code: 0x01,
|
48
55
|
encode: (info: Pick<IPeerInfo, 'publicAddress'>) => [
|
49
56
|
Buffer.from(info.publicAddress),
|
50
57
|
],
|
@@ -52,8 +59,39 @@ class Protocol extends EventEmitter {
|
|
52
59
|
publicAddress: publicAddress.toString(),
|
53
60
|
}),
|
54
61
|
},
|
62
|
+
{
|
63
|
+
name: 'TransactionStatus',
|
64
|
+
code: 0x02,
|
65
|
+
encode: (transaction: Transaction) => [
|
66
|
+
Buffer.from(transaction.transactionHash),
|
67
|
+
|
68
|
+
Buffer.from(transaction.sourceStatus),
|
69
|
+
Buffer.from(transaction.sourceTransactionHash),
|
70
|
+
transaction.sourceErrors ? transaction.sourceErrors.map((e) => Buffer.from(e)) : [],
|
71
|
+
|
72
|
+
Buffer.from(transaction.targetStatus),
|
73
|
+
Buffer.from(transaction.targetTransactionHash),
|
74
|
+
transaction.targetErrors ? transaction.targetErrors.map((e) => Buffer.from(e)) : [],
|
75
|
+
|
76
|
+
Buffer.from(transaction.status),
|
77
|
+
],
|
78
|
+
decode: ([transactionHash, sourceStatus, sourceTransactionHash, sourceErrors, targetStatus, targetTransactionHash, targetErrors, status]: [Buffer, Buffer, Buffer, Buffer[], Buffer, Buffer, Buffer[], Buffer]) => ({
|
79
|
+
transactionHash: transactionHash.toString(),
|
80
|
+
|
81
|
+
sourceStatus: sourceStatus.toString(),
|
82
|
+
sourceTransactionHash: sourceTransactionHash.toString(),
|
83
|
+
sourceErrors: sourceErrors.map((e) => e.toString()),
|
84
|
+
|
85
|
+
targetStatus: targetStatus.toString(),
|
86
|
+
targetTransactionHash: targetTransactionHash.toString(),
|
87
|
+
targetErrors: targetErrors.map((e) => e.toString()),
|
88
|
+
|
89
|
+
status: status.toString(),
|
90
|
+
}),
|
91
|
+
},
|
55
92
|
];
|
56
93
|
private signature: SignatureDialProtocol;
|
94
|
+
private transactionStatus: TransactionStatusDialProtocol;
|
57
95
|
|
58
96
|
|
59
97
|
start({ libp2p, topic = null, }) {
|
@@ -73,6 +111,7 @@ class Protocol extends EventEmitter {
|
|
73
111
|
})
|
74
112
|
|
75
113
|
this.signature = new SignatureDialProtocol(this.libp2p);
|
114
|
+
this.transactionStatus = new TransactionStatusDialProtocol(this.libp2p);
|
76
115
|
}
|
77
116
|
|
78
117
|
|
@@ -121,6 +160,14 @@ class Protocol extends EventEmitter {
|
|
121
160
|
this.libp2p.pubsub.publish(this.topic, encoded)
|
122
161
|
}
|
123
162
|
|
163
|
+
public sendTransaction(transaction: Transaction) {
|
164
|
+
const message = this.protocolMessages.find((m) => m.name === 'TransactionStatus')!
|
165
|
+
|
166
|
+
const encoded = rlp.encode([message.code, message.encode(transaction)]);
|
167
|
+
|
168
|
+
this.libp2p.pubsub.publish(this.topic, encoded)
|
169
|
+
}
|
170
|
+
|
124
171
|
async requestSignatures(data: ISignatureRequest, peerIds?: string[]) {
|
125
172
|
try {
|
126
173
|
peerIds = peerIds || peerPool.activePeerIds;
|
@@ -133,6 +180,15 @@ class Protocol extends EventEmitter {
|
|
133
180
|
return []
|
134
181
|
}
|
135
182
|
}
|
183
|
+
|
184
|
+
async requestTransactionStatus(transactionHash: string, peerId: string) {
|
185
|
+
try {
|
186
|
+
return await this.transactionStatus.send(transactionHash, peerId);
|
187
|
+
} catch (error) {
|
188
|
+
console.log(error);
|
189
|
+
return null
|
190
|
+
}
|
191
|
+
}
|
136
192
|
}
|
137
193
|
|
138
194
|
export const protocol = new Protocol();
|