Adding availability validation
This commit is contained in:
parent
2525ac062c
commit
4dd1004c4e
|
@ -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.
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue