Reorganizing code
This commit is contained in:
parent
9432694fa3
commit
56879acc00
|
@ -1,19 +1,17 @@
|
|||
{
|
||||
"blockchain": {
|
||||
"account": "0x9e14016ba37b23498885864053fded5226161a3a",
|
||||
"protocol": "ws",
|
||||
"host": "localhost",
|
||||
"port": 8545
|
||||
},
|
||||
|
||||
"whisper": {
|
||||
"symKey": "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b",
|
||||
"node": {
|
||||
"protocol": "ws",
|
||||
"host": "localhost",
|
||||
"port": 8546,
|
||||
"ttl": 20,
|
||||
"minPow": 0.8,
|
||||
"powTime": 1000
|
||||
"blockchain": {
|
||||
"account": "0x9e14016ba37b23498885864053fded5226161a3a"
|
||||
},
|
||||
"whisper": {
|
||||
"symKey": "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b",
|
||||
"ttl": 20,
|
||||
"minPow": 0.8,
|
||||
"powTime": 1000
|
||||
}
|
||||
},
|
||||
|
||||
"tokens": {
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
const md5 = require('md5');
|
||||
|
||||
class ContractSettings {
|
||||
|
||||
constructor(config, web3, eventEmitter){
|
||||
this.tokens = config.tokens;
|
||||
this.topics = [];
|
||||
this.contracts = config.contracts;
|
||||
|
||||
this.web3 = web3;
|
||||
this.events = eventEmitter;
|
||||
|
||||
this.pendingToLoad = 0;
|
||||
|
||||
this.events.on('setup:bytecode-address', this._obtainContractBytecode.bind(this))
|
||||
}
|
||||
|
||||
process(){
|
||||
this._setTokenPricePlugin();
|
||||
this._processContracts();
|
||||
}
|
||||
|
||||
getToken(token){
|
||||
return this.tokens[token];
|
||||
}
|
||||
|
||||
getContractByTopic(topicName){
|
||||
return this.contracts[topicName];
|
||||
}
|
||||
|
||||
getTopicName(contractName){
|
||||
return this.web3.utils.toHex(contractName).slice(0, 10);
|
||||
}
|
||||
|
||||
_setTokenPricePlugin(){
|
||||
for(let token in this.tokens){
|
||||
if(this.tokens[token].pricePlugin !== undefined){
|
||||
let PricePlugin = require(this.tokens[token].pricePlugin);
|
||||
this.tokens[token].pricePlugin = new PricePlugin(this.tokens[token]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_determineBytecodeAddress(topicName, i){
|
||||
let contractAddress = this.contracts[topicName].address;
|
||||
if(this.contracts[topicName].isIdentity){
|
||||
this.pendingToLoad++;
|
||||
const lastKernelSignature = "0x4ac99424"; // REFACTOR
|
||||
this.web3.eth.call({to: this.contracts[topicName].factoryAddress, data: lastKernelSignature})
|
||||
.then(kernel => {
|
||||
contractAddress = '0x' + kernel.slice(26);
|
||||
this.events.emit('setup:bytecode-address', topicName, contractAddress);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_obtainContractBytecode(topicName, contractAddress){
|
||||
this.web3.eth.getCode(contractAddress)
|
||||
.then(code => {
|
||||
this.contracts[topicName].code = md5(code);
|
||||
this.pendingToLoad--;
|
||||
if(this.pendingToLoad == 0) this.events.emit("setup:complete", this);
|
||||
})
|
||||
.catch(function(err){
|
||||
console.error("Invalid contract for " + contractName);
|
||||
console.error(err);
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
|
||||
_extractFunctions(topicName){
|
||||
const contract = this.getContractByTopic(topicName);
|
||||
|
||||
for(let i = 0; i < contract.allowedFunctions.length; i++){
|
||||
contract.allowedFunctions[i].functionName = contract.allowedFunctions[i].function.slice(0, contract.allowedFunctions[i].function.indexOf('('));
|
||||
|
||||
// Extracting input
|
||||
contract.allowedFunctions[i].inputs = contract.abi.filter(x => x.name == contract.allowedFunctions[i].functionName && x.type == "function")[0].inputs;
|
||||
|
||||
// Obtaining function signatures
|
||||
let functionSignature = this.web3.utils.sha3(contract.allowedFunctions[i].function).slice(0, 10);
|
||||
contract.allowedFunctions[functionSignature] = contract.allowedFunctions[i];
|
||||
delete this.contracts[topicName].allowedFunctions[i];
|
||||
}
|
||||
|
||||
contract.functionSignatures = Object.keys(contract.allowedFunctions);
|
||||
this.contracts[topicName] = contract;
|
||||
}
|
||||
|
||||
_processContracts(){
|
||||
for(let contractName in this.contracts){
|
||||
// Obtaining the abis
|
||||
this.contracts[contractName].abi = require(this.contracts[contractName].abiFile);
|
||||
|
||||
const topicName = this.getTopicName(contractName);
|
||||
|
||||
// Extracting topic
|
||||
this.topics.push(topicName);
|
||||
this.contracts[topicName] = this.contracts[contractName];
|
||||
this.contracts[topicName].name = contractName;
|
||||
delete this.contracts[contractName];
|
||||
|
||||
this._determineBytecodeAddress(topicName);
|
||||
|
||||
this._extractFunctions(topicName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = ContractSettings;
|
|
@ -0,0 +1,182 @@
|
|||
const md5 = require('md5');
|
||||
const erc20ABI = require('../abi/ERC20.json');
|
||||
const ganache = require("ganache-cli");
|
||||
|
||||
class MessageProcessor {
|
||||
|
||||
constructor(config, settings, web3, kId){
|
||||
this.config = config;
|
||||
this.settings = settings;
|
||||
this.web3 = web3;
|
||||
this.kId = kId;
|
||||
}
|
||||
|
||||
|
||||
_reply(text, message){
|
||||
if(message.sig !== undefined){
|
||||
this.web3.shh.post({
|
||||
pubKey: message.sig,
|
||||
sig: this.kId,
|
||||
ttl: this.config.node.whisper.ttl,
|
||||
powTarget:this.config.node.whisper.minPow,
|
||||
powTime: this.config.node.whisper.powTime,
|
||||
topic: message.topic,
|
||||
payload: this.web3.utils.fromAscii(text)
|
||||
}).catch(console.error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async _validateInput(message, input){
|
||||
const contract = this.settings.getContractByTopic(message.topic);
|
||||
|
||||
if(!/^0x[0-9a-f]{40}$/i.test(input.address)){
|
||||
this._reply('Invalid address', message);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(contract == undefined){
|
||||
this._reply('Invalid topic', message);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!contract.functionSignatures.includes(input.functionName)){
|
||||
this._reply('Function not allowed', message);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get code from address and compare it against the contract code
|
||||
const code = md5(await this.web3.eth.getCode(input.address));
|
||||
if(code != contract.code){
|
||||
this._reply('Invalid contract code', message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
_extractInput(message){
|
||||
return {
|
||||
address: message.payload.slice(0, 42),
|
||||
functionName: '0x' + message.payload.slice(42, 50),
|
||||
functionParameters: '0x' + message.payload.slice(50),
|
||||
payload: '0x' + message.payload.slice(42)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_obtainParametersFunc(contract, input){
|
||||
const parameterList = this.web3.eth.abi.decodeParameters(contract.allowedFunctions[input.functionName].inputs, input.functionParameters);
|
||||
return function(parameterName){
|
||||
return parameterList[contract.allowedFunctions[input.functionName][parameterName]];
|
||||
}
|
||||
}
|
||||
|
||||
_getFactor(input, contract, gasToken){
|
||||
if(contract.allowedFunctions[input.functionName].isToken){
|
||||
return this.web3.utils.toBN(this.settings.getToken(gasToken).pricePlugin.getFactor());
|
||||
} else {
|
||||
return this.web3.utils.toBN(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async getBalance(token, input){
|
||||
// Determining balances of token used
|
||||
if(token.symbol == "ETH")
|
||||
return new this.web3.utils.BN(await this.web3.eth.getBalance(input.address));
|
||||
else {
|
||||
const Token = new this.web3.eth.Contract(erc20ABI);
|
||||
Token.options.address = params('gasToken');
|
||||
return new this.web3.utils.BN(await Token.methods.balanceOf(input.address).call());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async process(error, message){
|
||||
|
||||
if(error){
|
||||
console.error(error);
|
||||
} else {
|
||||
|
||||
let input = this._extractInput(message);
|
||||
|
||||
const contract = this.settings.getContractByTopic(message.topic);
|
||||
|
||||
console.info("Processing request to: %s, %s", input.address, input.functionName);
|
||||
|
||||
if(!this._validateInput(message, input)) return; // TODO Log
|
||||
|
||||
const params = this._obtainParametersFunc(contract, input);
|
||||
|
||||
const token = this.settings.getToken(params('gasToken'));
|
||||
if(token == undefined)
|
||||
return reply("Token not allowed", message);
|
||||
|
||||
const gasPrice = this.web3.utils.toBN(params('gasPrice'));
|
||||
const gasLimit = this.web3.utils.toBN(params('gasLimit'));
|
||||
|
||||
|
||||
// Determine if enough balance for baseToken
|
||||
if(contract.allowedFunctions[input.functionName].isToken){
|
||||
const Token = new this.web3.eth.Contract(erc20ABI);
|
||||
Token.options.address = params('token');
|
||||
const baseToken = new this.web3.utils.BN(await Token.methods.balanceOf(input.address).call());
|
||||
if(balance.lt(this.web3.utils.BN(params('value')))){
|
||||
this._reply("Not enough balance", message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const balance = await this.getBalance(token, input);
|
||||
const gasToken = params('gasToken');
|
||||
const factor = this._getFactor(input, contract, gasToken);
|
||||
|
||||
|
||||
const balanceInETH = balance.div(factor);
|
||||
const gasLimitInETH = gasLimit.div(factor);
|
||||
|
||||
if(balanceInETH.lt(this.web3.utils.toBN(gasPrice.mul(gasLimit)))) {
|
||||
this._reply("Not enough balance", message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Estimate costs
|
||||
const web3Sim = new Web3(ganache.provider({fork: `${config.node.protocol}://${config.node.host}:${config.node.port}`}));
|
||||
const simAccounts = await web3Sim.eth.getAccounts();
|
||||
let simulatedReceipt = await web3Sim.eth.sendTransaction({
|
||||
from: simAccounts[0],
|
||||
to: input.address,
|
||||
value: 0,
|
||||
data: input.payload
|
||||
});
|
||||
|
||||
const estimatedGas = web3.utils.toBN(simulatedReceipt.gasUsed);
|
||||
if(gasLimit.lt(estimatedGas)) {
|
||||
return this._reply("Gas limit below estimated gas", message);
|
||||
}
|
||||
|
||||
this.web3.eth.sendTransaction({
|
||||
from: config.node.blockchain.account,
|
||||
to: address,
|
||||
value: 0,
|
||||
data: input.payload,
|
||||
gasLimit: gasLimitInETH
|
||||
})
|
||||
.then(function(receipt){
|
||||
return this._reply("Transaction mined;" + receipt.transactionHash, message);
|
||||
}).catch(function(err){
|
||||
this._reply("Couldn't mine transaction", message);
|
||||
// TODO log this?
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MessageProcessor;
|
|
@ -1,245 +1,71 @@
|
|||
const md5 = require('md5');
|
||||
const EventEmitter = require('events');
|
||||
const Web3 = require('web3');
|
||||
const config = require('../config/config.json');
|
||||
const web3 = new Web3(`${config.whisper.protocol}://${config.whisper.host}:${config.whisper.port}`);
|
||||
var ganache = require("ganache-cli");
|
||||
|
||||
const erc20ABI = require('../abi/ERC20.json');
|
||||
const ContractSettings = require('./contract-settings');
|
||||
const MessageProcessor = require('./message-processor');
|
||||
|
||||
console.info("Starting...")
|
||||
|
||||
// TODO A node should call an API (probably from a status node) to register itself as a
|
||||
// token gas relayer.
|
||||
|
||||
async function start(){
|
||||
for(token in config.tokens){
|
||||
if(config.tokens[token].pricePlugin !== undefined){
|
||||
let PricePlugin = require(config.tokens[token].pricePlugin);
|
||||
config.tokens[token].pricePlugin = new PricePlugin(config.tokens)
|
||||
}
|
||||
}
|
||||
console.info("Starting...");
|
||||
const events = new EventEmitter();
|
||||
|
||||
config.topics = [];
|
||||
for(let contractName in config.contracts){
|
||||
// Web3 Connection
|
||||
let connectionURL = `${config.node.protocol}://${config.node.host}:${config.node.port}`;
|
||||
const web3 = new Web3(connectionURL);
|
||||
|
||||
// Obtaining the abis
|
||||
config.contracts[contractName].abi = require(config.contracts[contractName].abiFile);
|
||||
|
||||
const lngt = config.contracts[contractName].allowedFunctions.length;
|
||||
for(i = 0; i < lngt; i++){
|
||||
config.contracts[contractName].allowedFunctions[i].functionName = config.contracts[contractName].allowedFunctions[i].function.slice(0, config.contracts[contractName].allowedFunctions[i].function.indexOf('('));
|
||||
|
||||
// Extracting input
|
||||
config.contracts[contractName].allowedFunctions[i].inputs = config.contracts[contractName].abi.filter(x => x.name == config.contracts[contractName].allowedFunctions[i].functionName && x.type == "function")[0].inputs;
|
||||
|
||||
// Obtaining function signatures
|
||||
let functionSignature = web3.utils.sha3(config.contracts[contractName].allowedFunctions[i].function).slice(0, 10);
|
||||
config.contracts[contractName].allowedFunctions[functionSignature] = config.contracts[contractName].allowedFunctions[i];
|
||||
delete config.contracts[contractName].allowedFunctions[i];
|
||||
}
|
||||
|
||||
config.contracts[contractName].functionSignatures = Object.keys(config.contracts[contractName].allowedFunctions);
|
||||
|
||||
// Extracting topics and available functions
|
||||
let topicName = web3.utils.toHex(contractName).slice(0, 10);
|
||||
config.topics.push(topicName);
|
||||
config.contracts[topicName] = config.contracts[contractName];
|
||||
config.contracts[topicName].name = contractName;
|
||||
delete config.contracts[contractName];
|
||||
|
||||
// Get Contract Bytecode
|
||||
let contractAddress = config.contracts[topicName].address;
|
||||
if(config.contracts[topicName].isIdentity){
|
||||
const lastKernelSignature = "0x4ac99424";
|
||||
let kernel = await web3.eth.call({to: config.contracts[topicName].factoryAddress, data: lastKernelSignature});
|
||||
contractAddress = '0x' + kernel.slice(26);
|
||||
}
|
||||
web3.eth.net.isListening()
|
||||
.then(listening => events.emit('web3:connected', connectionURL))
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
process.exit();
|
||||
});
|
||||
|
||||
|
||||
try {
|
||||
config.contracts[topicName].code = md5(await web3.eth.getCode(contractAddress));
|
||||
} catch(err){
|
||||
console.error("Invalid contract for " + contractName);
|
||||
console.error(err);
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
events.on('web3:connected', connURL => {
|
||||
console.info("Connected to '%s'", connURL);
|
||||
let settings = new ContractSettings(config, web3, events);
|
||||
settings.process();
|
||||
});
|
||||
|
||||
// Setting up Whisper options
|
||||
const shhOptions = {
|
||||
ttl: config.whisper.ttl,
|
||||
minPow: config.whisper.minPow,
|
||||
};
|
||||
|
||||
let kId;
|
||||
let symKId;
|
||||
// Listening to whisper
|
||||
events.on('setup:complete', (settings) => {
|
||||
// Setting up Whisper options
|
||||
const shhOptions = {
|
||||
ttl: config.node.whisper.ttl,
|
||||
minPow: config.node.whisper.minPow,
|
||||
};
|
||||
|
||||
web3.shh.addSymKey(config.whisper.symKey)
|
||||
let kId;
|
||||
let symKId;
|
||||
|
||||
// Listening to whisper
|
||||
web3.shh.addSymKey(config.node.whisper.symKey)
|
||||
.then(symKeyId => {
|
||||
symKId = symKeyId;
|
||||
return web3.shh.newKeyPair();
|
||||
symKId = symKeyId;
|
||||
return web3.shh.newKeyPair();
|
||||
})
|
||||
.then(keyId => {
|
||||
shhOptions.symKeyId = symKId;
|
||||
shhOptions.kId = keyId;
|
||||
|
||||
kId = keyId;
|
||||
|
||||
console.info(`Sym Key: ${config.whisper.symKey}`);
|
||||
console.info(`Sym Key: ${config.node.whisper.symKey}`);
|
||||
console.info("Topics Available:");
|
||||
|
||||
config.topics = [];
|
||||
for(let contractName in config.contracts) {
|
||||
console.info("- %s: %s [%s]", config.contracts[contractName].name, contractName, Object.keys(config.contracts[contractName].allowedFunctions).join(', '));
|
||||
shhOptions.topics = [contractName];
|
||||
web3.shh.subscribe('messages', shhOptions, processMessages);
|
||||
for(let contract in settings.contracts) {
|
||||
console.info("- %s: %s [%s]", settings.getContractByTopic(contract).name, contract, Object.keys(settings.getContractByTopic(contract).allowedFunctions).join(', '));
|
||||
shhOptions.topics = [contract];
|
||||
events.emit('server:listen', shhOptions, settings);
|
||||
}
|
||||
|
||||
console.info("Started.");
|
||||
console.info("Listening for messages...")
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
const reply = async function(text, message){
|
||||
try {
|
||||
if(message.sig !== undefined){
|
||||
let shhOptions = {
|
||||
pubKey: message.sig,
|
||||
sig: kId,
|
||||
ttl: config.whisper.ttl,
|
||||
powTarget:config.whisper.minPow,
|
||||
powTime: config.whisper.powTime,
|
||||
topic: message.topic,
|
||||
payload: web3.utils.fromAscii(text)
|
||||
};
|
||||
await web3.shh.post(shhOptions);
|
||||
}
|
||||
} catch(Err){
|
||||
// TODO
|
||||
console.error(Err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Process individual whisper message
|
||||
const processMessages = async function(error, message, subscription){
|
||||
if(error){
|
||||
// TODO log
|
||||
console.error(error);
|
||||
} else {
|
||||
const address = message.payload.slice(0, 42);
|
||||
const functionName = '0x' + message.payload.slice(42, 50);
|
||||
const functionParameters = '0x' + message.payload.slice(50);
|
||||
const payload = '0x' + message.payload.slice(42);
|
||||
|
||||
console.info("Processing request to: %s, %s", address, functionName);
|
||||
|
||||
if(!/^0x[0-9a-f]{40}$/i.test(address))
|
||||
return reply('Invalid address', message);
|
||||
|
||||
if(config.contracts[message.topic] == undefined)
|
||||
return reply('Invalid topic', message);
|
||||
|
||||
const contract = config.contracts[message.topic];
|
||||
if(!contract.functionSignatures.includes(functionName))
|
||||
return reply('Function not allowed', message) // TODO Log this
|
||||
|
||||
// Get code from address and compare it against the contract code
|
||||
const code = md5(await web3.eth.getCode(address));
|
||||
if(code != contract.code){
|
||||
return reply('Invalid contract code', message); // TODO Log this
|
||||
}
|
||||
|
||||
const params = web3.eth.abi.decodeParameters(contract.allowedFunctions[functionName].inputs, functionParameters);
|
||||
const token = config.tokens[params[contract.allowedFunctions[functionName].gasToken]];
|
||||
if(token == undefined){
|
||||
return reply("Token not allowed", message);
|
||||
}
|
||||
|
||||
const gasPrice = web3.utils.toBN(params[contract.allowedFunctions[functionName].gasPrice]);
|
||||
const gasLimit = web3.utils.toBN(params[contract.allowedFunctions[functionName].gasLimit]);
|
||||
|
||||
// Determining balances of token used
|
||||
let balance;
|
||||
if(token.symbol == "ETH")
|
||||
balance = new web3.utils.BN(await web3.eth.getBalance(address));
|
||||
else {
|
||||
const Token = new web3.eth.Contract(erc20ABI);
|
||||
Token.options.address = params[contract.allowedFunctions[functionName].gasToken];
|
||||
balance = new web3.utils.BN(await Token.methods.balanceOf(address).call());
|
||||
}
|
||||
|
||||
// Determine if enough balance for baseToken
|
||||
if(contract.allowedFunctions[functionName].isToken){
|
||||
const Token = new web3.eth.Contract(erc20ABI);
|
||||
Token.options.address = params[contract.allowedFunctions[functionName].token];
|
||||
balance = new web3.utils.BN(await Token.methods.balanceOf(address).call());
|
||||
if(balance.lt(web3.utils.BN(params[contract.allowedFunctions[functionName].value]))){
|
||||
return reply("Not enough balance", message);
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain factor
|
||||
let factor;
|
||||
if(contract.allowedFunctions[functionName].isToken){
|
||||
factor =web3.utils.toBN(config.tokens[tokenAddress].pricePlugin.getFactor());
|
||||
} else {
|
||||
factor = web3.utils.toBN(1);
|
||||
}
|
||||
|
||||
const balanceInETH = balance.div(factor);
|
||||
const gasLimitInETH = gasLimit.div(factor);
|
||||
|
||||
if(balanceInETH.lt(web3.utils.toBN(gasPrice.mul(gasLimit)))) {
|
||||
return reply("Not enough balance", message);
|
||||
}
|
||||
|
||||
// Estimate costs
|
||||
const web3Sim = new Web3(ganache.provider({fork: `http://localhost:8545`}));
|
||||
const simAccounts = await web3Sim.eth.getAccounts();
|
||||
let simulatedReceipt = await web3Sim.eth.sendTransaction({
|
||||
from: simAccounts[0],
|
||||
to: address,
|
||||
value: 0,
|
||||
data: payload
|
||||
});
|
||||
|
||||
const estimatedGas = web3.utils.toBN(simulatedReceipt.gasUsed);
|
||||
console.log(simulatedReceipt);
|
||||
if(gasLimit.lt(estimatedGas)) {
|
||||
return reply("Gas limit below estimated gas", message);
|
||||
}
|
||||
|
||||
|
||||
web3.eth.sendTransaction({
|
||||
from: config.blockchain.account,
|
||||
to: address,
|
||||
value: 0,
|
||||
data: payload,
|
||||
gasLimit: gasLimitInETH
|
||||
})
|
||||
.then(function(receipt){
|
||||
return reply("Transaction mined;" + receipt.transactionHash, message);
|
||||
}).catch(function(err){
|
||||
reply("Couldn't mine transaction", message);
|
||||
// TODO log this?
|
||||
//console.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
start();
|
||||
|
||||
|
||||
|
||||
|
||||
events.on('server:listen', (shhOptions, settings) => {
|
||||
let processor = new MessageProcessor(config, settings, web3, shhOptions.kId);
|
||||
web3.shh.subscribe('messages', shhOptions, (error, message, subscription) => processor.process(error, message));
|
||||
});
|
||||
|
||||
|
||||
// Daemon helper functions
|
||||
|
@ -248,14 +74,6 @@ process.on("uncaughtException", function(err) {
|
|||
|
||||
});
|
||||
|
||||
process.on("SIGUSR1", function() {
|
||||
log("Reloading...");
|
||||
|
||||
|
||||
log("Reloaded.");
|
||||
});
|
||||
|
||||
process.once("SIGTERM", function() {
|
||||
log("Stopping...");
|
||||
});
|
||||
|
||||
|
|
|
@ -40,8 +40,6 @@ contract TestIdentityFactory {
|
|||
function TestIdentityFactory(){
|
||||
latestKernel = address(new TestIdentityGasRelay());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
contract TestSNTController {
|
||||
|
|
Loading…
Reference in New Issue