Skip to content

Commit 5be5c26

Browse files
committed
hsm signing service, refactor for TransactionSender signing functions,
etc.
1 parent 82168ef commit 5be5c26

File tree

4 files changed

+93
-7
lines changed

4 files changed

+93
-7
lines changed

federator/config/config.sample.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ module.exports = {
99
etherscanApiKey: '',
1010
runHeartbeatEvery: 1, // In hours
1111
endpointsPort: 5000, // Server port
12+
hsmPort: 6000, // [HSM] signing service port
13+
hsmHost: '127.0.0.1' // [HSM] signing service host
1214
}

federator/src/lib/HSM.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const net = require('net');
2+
const utils = require('./utils');
3+
4+
const payloadBuilder =
5+
(
6+
command,
7+
keyId,
8+
txnHash
9+
) => `{"command":"${command}","keyId":"${keyId}","message":{"hash":"${txnHash}"},"version":2}`;
10+
11+
module.exports = class HSM {
12+
constructor({
13+
host = '127.0.0.1',
14+
port = 6000,
15+
}) {
16+
this.host = host;
17+
this.port = port;
18+
this.client = null;
19+
}
20+
21+
async receive() {
22+
return new Promise((resolve, reject) => {
23+
this.client.on('data', (data) => {
24+
resolve(data.toString());
25+
this.client.end();
26+
})
27+
28+
this.client.on('end', () => {
29+
resolve(`connection to ${this.host}:${this.port} closed`)
30+
})
31+
32+
this.client.on('error', (err) => {
33+
reject(`Error: ${err.message}`)
34+
})
35+
})
36+
}
37+
38+
send(msgToSign = '') {
39+
const payload = utils.hsmPayloadBuilder(`sign`, `m/44'/137'/0'/0/0`, msgToSign);
40+
return this.client.write(`${payload}\n`);
41+
}
42+
43+
async connectSendAndReceive(msgToSign) {
44+
try {
45+
this.client = net.connect(this.port, this.host);
46+
this.send(msgToSign);
47+
return this.receive();
48+
} catch(err) {
49+
console.log(`HSM (connectSendAndReceive)`, err);
50+
}
51+
}
52+
}

federator/src/lib/TransactionSender.js

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
21
const Tx = require('ethereumjs-tx');
32
const ethUtils = require('ethereumjs-util');
43
const utils = require('./utils');
54
const fs = require('fs');
65
const axios = require('axios');
6+
const HSM = require('./HSM');
77

88
module.exports = class TransactionSender {
99
constructor(client, logger, config) {
@@ -13,6 +13,10 @@ module.exports = class TransactionSender {
1313
this.manuallyCheck = `${config.storagePath || __dirname}/manuallyCheck.txt`;
1414
this.etherscanApiKey = config.etherscanApiKey;
1515
this.debuggingMode = false;
16+
this.hsm = new HSM({
17+
port: config.hsmPort,
18+
host: config.hsmHost
19+
})
1620
}
1721

1822
async getNonce(address) {
@@ -126,12 +130,36 @@ module.exports = class TransactionSender {
126130
return rawTx;
127131
}
128132

129-
signRawTransaction(rawTx, privateKey) {
133+
async signRawTransaction(rawTx, privateKey, useHSM) {
130134
let tx = new Tx(rawTx);
131-
tx.sign(utils.hexStringToBuffer(privateKey));
135+
if(!useHSM) {
136+
tx.sign(utils.hexStringToBuffer(privateKey));
137+
} else {
138+
const txHash = tx.hash(false).toString();
139+
const {
140+
errorcode,
141+
signature: {
142+
r,
143+
s
144+
}
145+
} = JSON.parse(await this.hsm.connectSendAndReceive(txHash));
146+
147+
if(errorcode != 0) {
148+
throw new Error(`error while signing txn with HSM`)
149+
}
150+
151+
tx = {
152+
...tx,
153+
r,
154+
s,
155+
v: this.getChainId() * 2 + 8
156+
}
157+
158+
}
132159
return tx;
133160
}
134161

162+
135163
async getAddress(privateKey) {
136164
let address = null;
137165
if (privateKey && privateKey.length) {
@@ -170,15 +198,15 @@ module.exports = class TransactionSender {
170198
return response.data;
171199
}
172200

173-
async sendTransaction(to, data, value, privateKey) {
201+
async sendTransaction(to, data, value, privateKey, useHSM = false) {
174202
const chainId = await this.getChainId();
175203
let txHash;
176204
let receipt;
177205
try {
178206
let from = await this.getAddress(privateKey);
179207
let rawTx = await this.createRawTransaction(from, to, data, value);
180-
if (privateKey && privateKey.length) {
181-
let signedTx = this.signRawTransaction(rawTx, privateKey);
208+
if (privateKey && privateKey.length || useHSM) {
209+
let signedTx = await this.signRawTransaction(rawTx, privateKey, useHSM);
182210
const serializedTx = ethUtils.bufferToHex(signedTx.serialize());
183211
receipt = await this.client.eth.sendSignedTransaction(serializedTx).once('transactionHash', async (hash) => {
184212
txHash = hash;

federator/src/lib/utils.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ async function evm_mine(iterations, web3Instance = null) {
176176
await asyncMine(web3Instance);
177177
};
178178
};
179+
function hsmPayloadBuilder(command, keyId, txnHash) {
180+
return `{"command":"${command}","keyId":"${keyId}","message":{"hash":"${txnHash}"},"version":2}`;
181+
}
179182

180183
module.exports = {
181184
asyncMine,
@@ -193,5 +196,6 @@ module.exports = {
193196
zeroHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
194197
retry,
195198
retry3Times,
196-
getHeartbeatPollingInterval
199+
getHeartbeatPollingInterval,
200+
hsmPayloadBuilder
197201
}

0 commit comments

Comments
 (0)