Added account options

This commit is contained in:
Richard Ramos 2018-10-10 15:31:04 -04:00
parent 47c449c035
commit a27d230c4c
9 changed files with 140 additions and 30 deletions

View File

@ -11,7 +11,13 @@ module.exports = {
"port": 8545
},
"blockchain": {
"account": "0xb8d851486d1c953e31a44374aca11151d49b8bb3"
// privateKey: "your_private_key",
// privateKeyFile: "path/to/file"
// mnemonic: "12 word mnemonic",
// addressIndex: "0", // Optionnal. The index to start getting the address
// hdpath: "m/44'/60'/0'/0/" // Optionnal. HD derivation path
},
"whisper": {
"symKey": "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b",

View File

@ -22,8 +22,10 @@
},
"dependencies": {
"axios": "^0.18.0",
"bip39": "^2.5.0",
"consola": "^1.4.3",
"daemonize2": "^0.4.2",
"ethereumjs-wallet": "^0.6.2",
"ganache-cli": "^6.1.0",
"jsum": "^0.1.4",
"memory-cache": "^0.2.0",

View File

@ -0,0 +1,70 @@
const bip39 = require("bip39");
const hdkey = require('ethereumjs-wallet/hdkey');
const ethereumjsWallet = require('ethereumjs-wallet');
const path = require('path');
const fs = require('fs');
class AccountParser {
static get(accountConfig, web3) {
if (accountConfig.privateKey) {
if (!accountConfig.privateKey.startsWith('0x')) {
accountConfig.privateKey = '0x' + accountConfig.privateKey;
}
if (!web3.utils.isHexStrict(accountConfig.privateKey)) {
console.error(`Private key ending with ${accountConfig.privateKey.substr(accountConfig.privateKey.length - 5)} is not a HEX string`);
return null;
}
return web3.eth.accounts.privateKeyToAccount(accountConfig.privateKey);
}
if (accountConfig.privateKeyFile) {
let privateKeyFile = path.resolve(accountConfig.privateKeyFile);
let fileContent = fs.readFileSync(privateKeyFile).toString();
if (accountConfig.password) {
try {
fileContent = JSON.parse(fileContent);
if (!ethereumjsWallet['fromV' + fileContent.version]) {
console.error(`Key file ${accountConfig.privateKeyFile} is not a valid keystore file`);
return null;
}
const wallet = ethereumjsWallet['fromV' + fileContent.version](fileContent, accountConfig.password);
return web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex'));
} catch (e) {
console.error('Private key file is not a keystore JSON file but a password was provided');
console.error(e.message || e);
return null;
}
}
fileContent = fileContent.trim().split(/[,;]/);
return fileContent.map((key, index) => {
if (!key.startsWith('0x')) {
key = '0x' + key;
}
if (!web3.utils.isHexStrict(key)) {
console.error(`Private key is not a HEX string in file ${accountConfig.privateKeyFile} at index ${index}`);
return null;
}
return web3.eth.accounts.privateKeyToAccount(key);
});
}
if (accountConfig.mnemonic) {
const hdwallet = hdkey.fromMasterSeed(bip39.mnemonicToSeed(accountConfig.mnemonic.trim()));
const addressIndex = accountConfig.addressIndex || 0;
const wallet_hdpath = accountConfig.hdpath || "m/44'/60'/0'/0/";
const wallet = hdwallet.derivePath(wallet_hdpath + addressIndex).getWallet();
return web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex'));
}
console.error('Unsupported account configuration: ' + JSON.stringify(accountConfig));
console.error('Try using one of those: ' +
'{ "privateKey": "your-private-key", "privateKeyFile": "path/to/file/containing/key", "mnemonic": "12 word mnemonic" }');
return null;
}
}
module.exports = AccountParser;

View File

@ -92,29 +92,37 @@ class MessageProcessor {
* @param {function} reply - function to reply a message
* @returns {undefined}
*/
async processTransaction(contract, input, reply, cb){
async processTransaction(contract, input, reply, account, cb){
const validationResult = await this.processStrategy(contract, input, reply);
const {toHex} = this.web3.utils;
if(!validationResult.success) return;
const {toBN} = this.web3.utils;
const gasPrice = toBN(await this.web3.eth.getGasPrice()).add(toBN(this.config.gasPrice.modifier)).toString();
let p = {
from: this.config.node.blockchain.account,
to: input.contract,
value: 0,
data: input.payload,
gasPrice
};
const nonce = await this.web3.eth.getTransactionCount(this.config.node.blockchain.account.address);
if(!validationResult.estimatedGas){
validationResult.estimatedGas = await this.web3.eth.estimateGas(p);
}
p.gas = Math.floor(parseInt(validationResult.estimatedGas, 10)); // Tune this
const estimatedGas = parseInt(validationResult.estimatedGas, 10);
const nodeBalance = await this.web3.eth.getBalance(this.config.node.blockchain.account);
let p = {
from: this.config.node.blockchain.account.address,
to: input.contract,
value: "0x00",
data: input.payload,
nonce: toHex(nonce),
gasPrice: toHex(parseInt(gasPrice, 10)),
gasLimit: toHex(estimatedGas) // Tune this,
};
const nodeBalance = await this.web3.eth.getBalance(this.config.node.blockchain.account.address);
if(nodeBalance < p.gas){
reply("Relayer unavailable");
@ -122,14 +130,16 @@ class MessageProcessor {
this.events.emit('exit');
} else {
try {
this.web3.eth.sendTransaction(p)
.on('transactionHash', function(hash){
reply("Transaction broadcasted: " + hash);
cb();
})
.on('receipt', function(receipt){
reply("Transaction mined", receipt);
});
const signedTrx = await account.signTransaction(p);
this.web3.eth.sendSignedTransaction(signedTrx.rawTransaction)
.on('transactionHash', function(hash){
reply("Transaction broadcasted: " + hash);
cb();
})
.on('receipt', function(receipt){
reply("Transaction mined", receipt);
});
} catch(err){
reply("Couldn't mine transaction: " + err.message);

View File

@ -6,7 +6,8 @@ const MessageProcessor = require('./message-processor');
const JSum = require('jsum');
const logger = require('consola');
const winston = require('winston');
var cache = require('memory-cache');
const cache = require('memory-cache');
const accountParser = require('./account-parser');
// Setting up logging
const wLogger = winston.createLogger({
@ -28,6 +29,8 @@ const events = new EventEmitter();
const connectionURL = `${config.node.local.protocol}://${config.node.local.host}:${config.node.local.port}`;
const wsProvider = new Web3.providers.WebsocketProvider(connectionURL, {headers: {Origin: "gas-relayer"}});
const web3 = new Web3(wsProvider);
let account;
web3.eth.net.isListening()
.then(() => events.emit('web3:connected', connectionURL))
@ -39,6 +42,15 @@ web3.eth.net.isListening()
events.on('web3:connected', connURL => {
logger.info("Connected to '" + connURL + "'");
account = accountParser.get(config.node.blockchain, web3);
if(!account) {
process.exit(1);
} else {
config.node.blockchain.account = account;
}
let settings = new ContractSettings(config, web3, events, logger);
settings.process();
});
@ -50,10 +62,10 @@ const shhOptions = {
};
const verifyBalance = async (exitSubs) => {
const nodeBalance = await web3.eth.getBalance(config.node.blockchain.account);
const nodeBalance = await web3.eth.getBalance(config.node.blockchain.account.address);
if(web3.utils.toBN(nodeBalance).lte(web3.utils.toBN(100000))){ // TODO: tune minimum amount required for transactions
logger.info("Not enough balance available for processing transactions");
logger.info("> Account: " + config.node.blockchain.account);
logger.info("> Account: " + config.node.blockchain.account.address);
logger.info("> Balance: " + nodeBalance);
if(exitSubs){
@ -171,6 +183,7 @@ events.on('server:listen', (shhOptions, settings) => {
processor.processTransaction(settings.getContractByTopic(message.topic),
input,
reply,
account,
() => {
cache.put(inputCheckSum, (new Date().getTime()), 3600000);
}

View File

@ -32,7 +32,7 @@ class AvailabilityStrategy extends Strategy {
success: true,
message: {
message: "Available",
address: this.config.node.blockchain.account,
address: this.config.node.blockchain.account.address,
minGasPrice: gasPrices.inTokens.toString(),
gasPriceETH: gasPrices.inEther.add(toBN(this.config.gasPrice.modifier)).toString()
}

View File

@ -84,7 +84,7 @@ class BaseStrategy {
*/
async _estimateGas(input){
let p = {
from: this.config.node.blockchain.account,
from: this.config.node.blockchain.account.address,
to: input.contract,
data: input.payload
};

View File

@ -82,7 +82,7 @@ class IdentityStrategy extends Strategy {
if(exc.message.indexOf("revert") > -1) return {success: false, message: "Transaction will revert"};
else {
console.error(exc);
return {success: false, message: "Couldn't process transaction"};
return {success: false, message: "Transaction will fail"};
}
}

View File

@ -23,11 +23,20 @@ class SNTStrategy extends Strategy {
const balance = await this.getBalance(input.address, token);
const estimatedGas = await this.web3.eth.estimateGas({
data: input.payload,
from: this.config.node.blockchain.account,
to: input.contract
});
let estimatedGas;
try {
estimatedGas = await this.web3.eth.estimateGas({
data: input.payload,
from: this.config.node.blockchain.account.address,
to: input.contract
});
} catch(exc){
if(exc.message.indexOf("revert") > -1) return {success: false, message: "Transaction will revert"};
else {
console.error(exc);
return {success: false, message: "Transaction will fail"};
}
}
let tokenRate = await this.getTokenRate(token, cache);
if(!tokenRate){