Adding availability validation

This commit is contained in:
Richard Ramos 2018-08-27 10:54:19 -04:00
parent 2525ac062c
commit 4dd1004c4e
7 changed files with 71 additions and 22 deletions

View File

@ -23,9 +23,9 @@ Before executing this program, `config/config.json` must be setup and `npm insta
- Host, port and protocol Ganache will use when forking the blockchain for gas estimations and other operations
- Wallet account used for processing the transactions
- Symmetric key used to receive the Whisper messages
- Symmetric key used to send the heartbeats that notify the tokens and prices accepted
- Accepted tokens information
- Contract configuration
This program is configured with the default values for a embark installation run from 0
A `geth` node running whisper (via `-shh` option) is required. To execute the gas-relayer, you may use any of the following three methods.

View File

@ -105,8 +105,7 @@ class ContractSettings {
// Obtaining strategy
if(this.contracts[topicName].strategy){
const strategy = require(this.contracts[topicName].strategy);
this.contracts[topicName].strategy = new strategy(this.web3, this.config, this, this.contracts[topicName]);
this.contracts[topicName].strategy = this.buildStrategy(this.contracts[topicName].strategy, topicName);
}
this._obtainContractBytecode(topicName);
@ -114,6 +113,11 @@ class ContractSettings {
this._extractFunctions(topicName);
}
}
buildStrategy(strategyFile, topicName){
const strategy = require(strategyFile);
return new strategy(this.web3, this.config, this, this.contracts[topicName]);
}
}

View File

@ -8,13 +8,13 @@ class MessageProcessor {
}
async _validateInput(contract, input){
console.info("Processing request to: %s, %s", input.contract, input.functionName);
console.info("Processing '%s' request to contract: %s", input.action, input.contract);
if(contract == undefined){
return {success: false, message: 'Unknown contract'};
}
if(!contract.functionSignatures.includes(input.functionName)){
if(input.functionName && !contract.functionSignatures.includes(input.functionName)){
return {success: false, message: 'Function not allowed'};
}
@ -37,7 +37,7 @@ class MessageProcessor {
return {success: true};
}
async process(contract, input, reply){
async processStrategy(contract, input, reply, strategy){
const inputValidation = await this._validateInput(contract, input);
if(!inputValidation.success){
// TODO Log?
@ -45,16 +45,26 @@ class MessageProcessor {
return;
}
let validationResult;
if(strategy || contract.strategy){
let validationResult;
if(strategy){
validationResult = await strategy.execute(input, reply);
} else {
validationResult = await contract.strategy.execute(input, reply);
}
if(contract.strategy){
validationResult = await contract.strategy.execute(input, reply);
if(!validationResult.success){
reply(validationResult.message);
return;
}
}
return validationResult;
}
}
async processTransaction(contract, input, reply){
const validationResult = await this.processStrategy(contract, input, reply);
let p = {
from: this.config.node.blockchain.account,
to: input.contract,

View File

@ -4,9 +4,6 @@ const config = require('../config/config.js');
const ContractSettings = require('./contract-settings');
const MessageProcessor = require('./message-processor');
// IDEA: A node should call an API (probably from a status node) to register itself as a
// token gas relayer.
console.info("Starting...");
const events = new EventEmitter();
@ -84,7 +81,14 @@ events.on('setup:complete', async (settings) => {
const replyFunction = (message) => (text, receipt) => {
if(message.sig !== undefined){
console.log(text);
let payloadContent;
if(typeof text === 'object'){
payloadContent = {...text, receipt};
} else {
payloadContent = {text, receipt};
}
web3.shh.post({
pubKey: message.sig,
sig: shhOptions.kId,
@ -92,7 +96,7 @@ const replyFunction = (message) => (text, receipt) => {
powTarget:config.node.whisper.minPow,
powTime: config.node.whisper.powTime,
topic: message.topic,
payload: web3.utils.fromAscii(JSON.stringify({message:text, receipt}, null, " "))
payload: web3.utils.fromAscii(JSON.stringify(payloadContent, null, " "))
}).catch(console.error);
}
};
@ -115,7 +119,7 @@ const extractInput = (message) => {
obj.functionParameters = "0x" + parsedObj.encodedFunctionCall.slice(10);
obj.payload = parsedObj.encodedFunctionCall;
} else if(obj.action == 'availability') {
obj.token = parsedObj.token;
obj.gasToken = parsedObj.gasToken;
obj.gasPrice = parsedObj.gasPrice;
}
} catch(err){
@ -128,7 +132,7 @@ const extractInput = (message) => {
events.on('server:listen', (shhOptions, settings) => {
let processor = new MessageProcessor(config, settings, web3, events);
web3.shh.subscribe('messages', shhOptions, (error, message) => {
web3.shh.subscribe('messages', shhOptions, async (error, message) => {
if(error){
console.error(error);
return;
@ -138,15 +142,22 @@ events.on('server:listen', (shhOptions, settings) => {
const input = extractInput(message);
const reply = replyFunction(message);
let validationResult;
switch(input.action){
case 'transaction':
processor.process(settings.getContractByTopic(message.topic),
processor.processTransaction(settings.getContractByTopic(message.topic),
input,
reply);
break;
case 'availability':
reply("available");
validationResult = await processor.processStrategy(settings.getContractByTopic(message.topic),
input,
reply,
settings.buildStrategy("./strategy/AvailabilityStrategy", message.topic)
);
if(validationResult.success) reply(validationResult.message);
break;
default:
reply("unknown-action");

View File

@ -0,0 +1,24 @@
const Strategy = require('./BaseStrategy');
class AvailabilityStrategy extends Strategy {
async execute(input){
// Verifying if token is allowed
const token = this.settings.getToken(input.gasToken);
if(token == undefined) return {success: false, message: "Token not allowed"};
// TODO Validate gasPrice, and return the minPrice accepted
const minPrice = 0.00;
return {
success: true,
message: {
message: "Available",
minPrice: minPrice
}
};
}
}
module.exports = AvailabilityStrategy;

View File

@ -57,7 +57,7 @@ class Body extends Component {
const msg = web3js.utils.toAscii(message.payload);
const msgObj = JSON.parse(msg);
if(msgObj.message == 'available'){
if(msgObj.message == 'Available'){
// found a relayer
console.log("Relayer available: " + message.sig);

View File

@ -59,7 +59,7 @@ class Body extends Component {
const msg = web3js.utils.toAscii(message.payload);
const msgObj = JSON.parse(msg);
if(msgObj.message == 'available'){
if(msgObj.message == 'Available'){
// found a relayer
console.log("Relayer available: " + message.sig);