v6 initial commit, maybe more to follow
This commit is contained in:
parent
7f91be86c0
commit
d6a32870bc
34 changed files with 16875 additions and 0 deletions
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
################################################################################
|
||||
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
|
||||
################################################################################
|
||||
|
||||
/.vs
|
||||
/.vscode
|
||||
/node_modules
|
||||
/.metals
|
13
Notes
Normal file
13
Notes
Normal file
|
@ -0,0 +1,13 @@
|
|||
npm run dev
|
||||
PORT=3002 P2P_PORT=5002 PEERS=ws://localhost:5001 npm run dev
|
||||
PORT=3003 P2P_PORT=5003 PEERS=ws://localhost:5001,ws://localhost:5002 npm run dev
|
||||
PORT=3004 P2P_PORT=5004 PEERS=ws://localhost:5001,ws://localhost:5002,ws://localhost:5003 npm run dev
|
||||
PORT=3005 P2P_PORT=5005 PEERS=ws://localhost:5001,ws://localhost:5002,ws://localhost:5003,ws://localhost:5004 npm run dev
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
|
||||
* in this version, on top of adding Mqtt broker to each node and adding new module called integration and integrationVirtual
|
||||
* we ad blockNum to each block, and we limited the number of transaction for each block
|
47
Query.json
Normal file
47
Query.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
BIN
app/.DS_Store
vendored
Normal file
BIN
app/.DS_Store
vendored
Normal file
Binary file not shown.
898
app/index.js
Normal file
898
app/index.js
Normal file
|
@ -0,0 +1,898 @@
|
|||
/**
|
||||
* npm run dev
|
||||
* HTTP_PORT=3002 P2P_PORT=5002 MQTT_PORT=1884 PEERS=ws://localhost:5001 npm run dev
|
||||
* HTTP_PORT=3003 P2P_PORT=5003 MQTT_PORT=1885 PEERS=ws://localhost:5001,ws://localhost:5002 npm run dev
|
||||
* HTTP_PORT=3004 P2P_PORT=5004 MQTT_PORT=1886 PEERS=ws://localhost:5001,ws://localhost:5002,ws://localhost:5003 npm run dev
|
||||
* HTTP_PORT=3005 P2P_PORT=5005 MQTT_PORT=1887 PEERS=ws://localhost:5001,ws://localhost:5002,ws://localhost:5003,ws://localhost:5004 npm run dev
|
||||
*/
|
||||
|
||||
/**
|
||||
* npm run dev //node1
|
||||
* HTTP_PORT=3002 P2P_PORT=5002 MQTT_PORT=1884 PEERS=ws://45.113.235.182:5001 npm run dev //node2
|
||||
* HTTP_PORT=3003 P2P_PORT=5003 MQTT_PORT=1885 PEERS=ws://45.113.235.182:5001,ws://45.113.234.151:5002 npm run dev //node3
|
||||
* HTTP_PORT=3004 P2P_PORT=5004 MQTT_PORT=1886 PEERS=ws://IP:5001,ws://IP:5002,ws://IP:5003 npm run dev //node4
|
||||
* HTTP_PORT=3005 P2P_PORT=5005 MQTT_PORT=1887 PEERS=ws://IP:5001,ws://IP:5002,ws://IP:5003,ws://IP:5004 npm run dev //node5
|
||||
*/
|
||||
|
||||
/**
|
||||
* for monitoring the memory and cpu as well as run node in the background use the following,
|
||||
* note: the second section of the instruction is to change the heap memory
|
||||
* pm2 start app/index.js --node-args="--max_old_space_size=8192"
|
||||
* HTTP_PORT=3002 P2P_PORT=5002 MQTT_PORT=1884 PEERS=ws://45.113.235.182:5001 pm2 start app/index.js --node-args="--max_old_space_size=8192"
|
||||
* HTTP_PORT=3003 P2P_PORT=5003 MQTT_PORT=1885 PEERS=ws://45.113.235.182:5001,ws://45.113.234.151:5002 pm2 start app/index.js --node-args="--max_old_space_size=8192"
|
||||
* HTTP_PORT=3004 P2P_PORT=5004 MQTT_PORT=1886 PEERS=ws://IP:5001,ws://IP:5002,ws://IP:5003 pm2 start app/index.js --node-args="--max_old_space_size=8192"
|
||||
* HTTP_PORT=3005 P2P_PORT=5005 MQTT_PORT=1887 PEERS=ws://IP:5001,ws://IP:5002,ws://IP:5003,ws://IP:5004 pm2 start app/index.js --node-args="--max_old_space_size=8192"
|
||||
* use
|
||||
* $ pm2 monit
|
||||
* to monitor the node
|
||||
*
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const Blockchain = require('../blockchain');
|
||||
const P2pServer = require('./p2p-server');
|
||||
const Wallet = require('../wallet');
|
||||
const TransactionPool = require('../wallet/transaction-pool');
|
||||
const Miner = require('./miner');
|
||||
const morgan = require('morgan');//AddedM
|
||||
const multer = require('multer');
|
||||
//const productRoutes = require("./products");//addedM
|
||||
const newEngine = require('@comunica/actor-init-sparql').newEngine;
|
||||
const N3 = require('n3');
|
||||
const jsonld = require('jsonld');
|
||||
const DataFactory = require('n3').DataFactory;
|
||||
const fs = require('fs');
|
||||
const swaggerUi = require('swagger-ui-express')
|
||||
const swaggerFile = require('./swagger_output.json')
|
||||
var lodash = require('lodash');
|
||||
var mqtt = require('mqtt');
|
||||
var aedes = require('aedes')();
|
||||
var MQTTserver = require('net').createServer(aedes.handle);
|
||||
var mosca = require('mosca');
|
||||
//var awsIot = require('aws-iot-device-sdk');
|
||||
'use strict';// "use strict" is to indicate that the code should be executed in "strict mode".
|
||||
// With strict mode, you can not, for example, use undeclared variables.
|
||||
|
||||
const parser = new N3.Parser({format: 'application/n-quads'});
|
||||
const store = new N3.Store();
|
||||
const store2 = new N3.Store();
|
||||
const myEngine = newEngine();
|
||||
const app = express();
|
||||
const bc = new Blockchain();
|
||||
const wallet = new Wallet();
|
||||
const tp = new TransactionPool();
|
||||
const p2pServer = new P2pServer(bc, tp);
|
||||
const miner = new Miner(bc, tp, wallet, p2pServer);
|
||||
|
||||
//var client = mqtt.connect('mqtt://broker.hivemq.com');
|
||||
|
||||
var MOSCAsettings = { MOSCAport:1883 }
|
||||
//var MOSCAserver = new mosca.Server(MOSCAsettings);
|
||||
|
||||
|
||||
//Mosca mqtt server intialization
|
||||
// MOSCAserver.on('ready', function(){
|
||||
// console.log("ready");
|
||||
// });
|
||||
|
||||
//aedes mqtt server intialization
|
||||
const MQTTport = process.env.MQTT_PORT || 1883;
|
||||
MQTTserver.listen(MQTTport, function () {
|
||||
console.log('MQTTserver listening on port', MQTTport)
|
||||
})
|
||||
|
||||
//
|
||||
const storage = multer.diskStorage({
|
||||
destination: function(req, file, cb) {
|
||||
cb(null, './uploads/');
|
||||
},
|
||||
filename: function(req, file, cb) {
|
||||
cb(null, new Date().toISOString() + file.originalname);
|
||||
}
|
||||
});
|
||||
|
||||
//filtering the type of uploaded files
|
||||
const fileFilter = (req, file, cb) => {
|
||||
// reject a file
|
||||
if (file.mimetype === 'application/json' || file.mimetype === 'text/plain' ) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(null, false);
|
||||
}
|
||||
};
|
||||
|
||||
const upload = multer({
|
||||
storage: storage,
|
||||
limits: {
|
||||
fileSize: 1024 * 1024 * 5
|
||||
},
|
||||
fileFilter: fileFilter
|
||||
});
|
||||
|
||||
const port = process.env.HTTP_PORT || 3001;
|
||||
app.listen(port, () => console.log(`Listening on port ${port}`));
|
||||
p2pServer.listen();
|
||||
|
||||
app.use('/doc', swaggerUi.serve, swaggerUi.setup(swaggerFile))
|
||||
|
||||
function log(message) {
|
||||
console.log(`New block added: ${message.toString()}`);
|
||||
// fs.writeFileSync('./blocks.json', JSON.stringify(message),{'flags': 'a'}); //the problem with this function was overwrite even when i changed the flag to 'a'
|
||||
// fs.appendFile('./blocks.json', JSON.stringify(message) ,function(err){ //this function makes erorrs when the data is big
|
||||
// if(err) throw err;
|
||||
// console.log('IS WRITTEN')
|
||||
// });
|
||||
var BlockStream = fs.createWriteStream("blocks.json", {flags:'a'});
|
||||
BlockStream.write(message+ "\n");
|
||||
}
|
||||
|
||||
function logQuery(message) {
|
||||
//console.log(`New block added: ${message.toString()}`);
|
||||
// fs.writeFileSync('./blocks.json', JSON.stringify(message),{'flags': 'a'}); //the problem with this function was overwrite even when i changed the flag to 'a'
|
||||
// fs.appendFile('./blocks.json', JSON.stringify(message) ,function(err){ //this function makes erorrs when the data is big
|
||||
// if(err) throw err;
|
||||
// console.log('IS WRITTEN')
|
||||
// });
|
||||
var QueryStream = fs.createWriteStream("Query.json", {flags:'a'});
|
||||
QueryStream.write(message+ "\n");
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
app.use(morgan("dev"));//AddedM
|
||||
app.use('/uploads', express.static('uploads'));
|
||||
app.use(bodyParser.urlencoded({ extended: false }));//addedM
|
||||
app.use(bodyParser.json());
|
||||
//addedM
|
||||
app.use((req, res, next) => {
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
res.header(
|
||||
"Access-Control-Allow-Headers",
|
||||
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
|
||||
);
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
|
||||
return res.status(200).json({});
|
||||
}
|
||||
next();
|
||||
});
|
||||
//finished AddedM
|
||||
|
||||
//GET functions
|
||||
app.get('/blocks', (req, res) => {
|
||||
res.json(bc.chain);
|
||||
});
|
||||
|
||||
app.get('/MetaDataTransactions', (req, res) => {
|
||||
res.json(tp.metaDataTransactions);
|
||||
});
|
||||
|
||||
app.get('/CoinTransactions', (req, res) => {
|
||||
res.json(tp.cointransactions);
|
||||
});
|
||||
|
||||
app.get('/Transactions', (req, res) => {
|
||||
res.json(tp);
|
||||
});
|
||||
|
||||
app.get('/mine-transactions', (req, res) => {
|
||||
const block = miner.mine();
|
||||
console.log(`New block added: ${block.toString()}`);
|
||||
//res.redirect('/blocks');
|
||||
res.json("Block mined");
|
||||
});
|
||||
|
||||
app.get('/public-key', (req, res) => {
|
||||
res.json({ publicKey: wallet.publicKey });
|
||||
});
|
||||
|
||||
app.get('/Balance', (req, res) => {
|
||||
res.json({ Balance: wallet.balance });
|
||||
});
|
||||
/////////////////////////////
|
||||
|
||||
//POST functions
|
||||
app.post('/mine', (req, res) => {
|
||||
const block = bc.addBlock(req.body.data);
|
||||
console.log(`New block added: ${block.toString()}`);
|
||||
|
||||
p2pServer.syncChains();
|
||||
|
||||
res.redirect('/blocks');
|
||||
});
|
||||
|
||||
app.post('/RegistringIoTdevice', (req, res)=> {
|
||||
const {Name,Geo ,IP_URL , Topic_Token, Permission, RequestDetail,
|
||||
OrgOwner, DepOwner,PrsnOwner, PaymentPerKbyte,
|
||||
PaymentPerMinute,Protocol, MessageAttributes, Interval,
|
||||
FurtherDetails} = req.body;
|
||||
fs.readdir('./uploads', function(err, files) {
|
||||
console.log(files[files.length-2]);
|
||||
var FileName = files[files.length-2];
|
||||
let rawdata = fs.readFileSync(`./uploads/${FileName}`);
|
||||
let SSNmetadata = JSON.parse(rawdata);
|
||||
let NameIn = Name;
|
||||
let GeoIn = Geo;
|
||||
let IP_URLIn = IP_URL;
|
||||
let Topic_TokenIn = Topic_Token;
|
||||
let PermissionIn = Permission;
|
||||
let RequestDetailIn = RequestDetail;
|
||||
let OrgOwnerIn = OrgOwner;
|
||||
let DepOwnerIn = DepOwner;
|
||||
let PrsnOwnerIn = PrsnOwner;
|
||||
let PaymentPerKbyteIn = PaymentPerKbyte;
|
||||
let PaymentPerMinuteIn = PaymentPerMinute;
|
||||
let ProtocolIn = Protocol;
|
||||
let MessageAttributesIn = MessageAttributes;
|
||||
let IntervalIn = Interval;
|
||||
let FurtherDetailsIn = FurtherDetails;
|
||||
var metaDataTransaction = wallet.createMetaDataTransaction(NameIn,
|
||||
GeoIn, IP_URLIn,Topic_TokenIn,
|
||||
PermissionIn, RequestDetailIn, OrgOwnerIn,
|
||||
DepOwnerIn, PrsnOwnerIn, PaymentPerKbyteIn,
|
||||
PaymentPerMinuteIn,ProtocolIn,
|
||||
MessageAttributesIn, IntervalIn,
|
||||
FurtherDetailsIn,
|
||||
SSNmetadata, tp);
|
||||
p2pServer.broadcastMetaDataTransaction(metaDataTransaction);});
|
||||
res.json("MetadataTransactionCreated");});
|
||||
|
||||
/**
|
||||
* the following piece of code
|
||||
* is for storing the metadata as a Nquad format inside the blockchain
|
||||
*/
|
||||
// jsonld.toRDF(metaDataTransaction.SSNmetadata, {format: 'application/n-quads'},
|
||||
// (err, nquads) => {
|
||||
// // nquads is a string of N-Quads
|
||||
// parser.parse(
|
||||
// nquads,
|
||||
// (error, quadN, prefixes) => {
|
||||
// // console.log(quadN)
|
||||
// if (quadN)
|
||||
// //console.log(quadN.predicate)
|
||||
// store.addQuad(DataFactory.quad(
|
||||
// DataFactory.namedNode(quadN.subject.id),
|
||||
// DataFactory.namedNode(quadN.predicate.id),
|
||||
// DataFactory.namedNode(quadN.object.id)));
|
||||
// });
|
||||
// });
|
||||
// metaDataTransaction.SSNmetadata= store;
|
||||
|
||||
app.post('/IoTdevicePaymentTransaction', (req, res) => {
|
||||
const { Recipient_payment_address, Amount_of_money, Payment_method,
|
||||
Further_details} = req.body;
|
||||
if (Payment_method == "SensorCoin"){
|
||||
const PaymentTransaction = wallet.createCoinTransaction(
|
||||
Recipient_payment_address, Amount_of_money, bc, tp);
|
||||
p2pServer.broadcastCoinTransaction(PaymentTransaction);
|
||||
res.json("PaymentTransactionCreated");
|
||||
}
|
||||
else if (Payment_method == "Bitcoin") {
|
||||
res.redirect('/BitcoinTransaction')
|
||||
}
|
||||
else if (Payment_method == "PayPal") {
|
||||
res.redirect('/PayPalTransaction')
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/UploadMetafile", upload.single('file'), (req, res) => {
|
||||
// recipient: req.body.recipient,
|
||||
// amount : req.body.amount,
|
||||
// const Geo = req.body.Geo;
|
||||
// const IPSO = req.body.IPSO;
|
||||
// const Type = req.body.Type;
|
||||
// const Permission = req.body.Permission;
|
||||
// const OrgOwner = req.body.OrgOwner;
|
||||
const file = req.file;
|
||||
//file : req.body.file
|
||||
res.status(201).json({
|
||||
message: 'Uploading Metadata was successful',
|
||||
MetadataFile : file
|
||||
});
|
||||
});
|
||||
|
||||
//////simple search engine
|
||||
app.post('/selectedMeta', (req, res) => {
|
||||
const {Name}= req.body;
|
||||
data =bc.chain.map (a => a.data);
|
||||
var PickedSensors = [];
|
||||
for (let i= 1; i<data.length; i++ ){
|
||||
//var pickeditems = [null];
|
||||
|
||||
var metadata= data[i][1];
|
||||
//pickeditems.push(...metadata);
|
||||
// }
|
||||
// return meta_array.Geo === 30;
|
||||
//meta_array=bc.chain.map(b => b.input);
|
||||
|
||||
var picked = lodash.find(metadata, x=> x.Name === Name);
|
||||
if (picked != null){
|
||||
PickedSensors.push(picked);
|
||||
}
|
||||
}
|
||||
|
||||
res.json(PickedSensors);
|
||||
|
||||
});
|
||||
|
||||
//Start of comunica sparql query code
|
||||
/**
|
||||
* this code under construction
|
||||
* try Comunica SPARQL RDFJS
|
||||
* I believe we need to change the way of storing the metadata
|
||||
*/
|
||||
app.post('/sparql', (req, res) => {
|
||||
const {Select,subject,predicate,object,Limit}= req.body; /**these
|
||||
variable are used for the sparql query*/
|
||||
var meta = []//represents the array of all metadata inside blockchain
|
||||
var queryResult
|
||||
BlockData =bc.chain.map (a => a.data); /** extracting the data section
|
||||
from each block inside the whole blockchain */
|
||||
var i;//i represents the number of blocks inside the whole blockchain
|
||||
for ( i= 1; i < BlockData.length; i++ ){
|
||||
var j //represents number of metadata transaction inside each block
|
||||
for ( j= 0; j<BlockData[i][1].length ;j++){
|
||||
meta.push(BlockData[i][1][j]["SSNmetadata"]); } }
|
||||
parser.parse(
|
||||
nquads,
|
||||
(error, quadN, prefixes) => {
|
||||
if (quadN)
|
||||
store.addQuad(DataFactory.quad(
|
||||
DataFactory.namedNode(quadN.subject.id),
|
||||
DataFactory.namedNode(quadN.predicate.id),
|
||||
DataFactory.namedNode(quadN.object.id)));
|
||||
else {(console.log("no metadata"))
|
||||
store.addQuad(DataFactory.quad(
|
||||
DataFactory.namedNode('http://ex.org/null'),
|
||||
DataFactory.namedNode('http://ex.org/null'),
|
||||
DataFactory.namedNode('http://ex.org/null')));}});
|
||||
const start = async function (a,b){
|
||||
const result = await myEngine.query(`SELECT ${Select} WHERE
|
||||
{${subject} ${predicate} ${object}} LIMIT
|
||||
${Limit}`, { sources: [{ type: 'rdfjsSource',
|
||||
value: store}] })
|
||||
result.bindingsStream.on('data', (data) =>
|
||||
console.log(data.toObject()));
|
||||
queryResult= result.bindingsStream};
|
||||
start()
|
||||
logQuery(queryResult);
|
||||
res.json(queryResult);});
|
||||
|
||||
|
||||
|
||||
// this code to query the nquad data straight forward from the blockchain without changing the formt
|
||||
app.post('/sparql2', (req, res) => {
|
||||
//find a way to define default values for the comming variables
|
||||
const {Select,subject,predicate,object,Limit}= req.body; // these variable are used for the sparql query
|
||||
var meta = [] // represents the array of all metadata inside the blockchain
|
||||
var queryResult
|
||||
/**
|
||||
* change the following code to custome map function to remove the for loop
|
||||
* and make the code faster
|
||||
*/
|
||||
BlockData =bc.chain.map (a => a.data); //extracting the data section from each block inside the whole blockchain
|
||||
var i;//i represents the number of blocks inside the whole blockchain
|
||||
for ( i= 1; i < BlockData.length; i++ ){ /**the purpose of this for loop is passing each BlockData to check for metadata
|
||||
this loop could be avoided if we used custome map function */
|
||||
|
||||
var j // j represents the number of metadata transaction inside each block
|
||||
for ( j= 0; j<BlockData[i][1].length ;j++){ /** the purpose of this for loop is passing each metadata transaction inside each block
|
||||
this loop could be avoided if we used custome map function */
|
||||
meta.push(BlockData[i][1][j]["SSNmetadata"]); /**this array depends on the structure of the data section from chain from bc
|
||||
i represents the number of blocks inside the whole blockchain
|
||||
j represents the number of metadarta transaction inside each block */
|
||||
}
|
||||
|
||||
}
|
||||
console.log(meta) // printing the metadata just for testing purposes
|
||||
|
||||
// jsonld.toRDF(meta, {format: 'application/n-quads'}, (err, nquads) => { /**
|
||||
|
||||
// parser.parse( /**this piece of code is used for parse the metadata and store it in N3store */
|
||||
// nquads,
|
||||
// (error, quadN, prefixes) => {
|
||||
// // console.log(quadN)
|
||||
// if (quadN)
|
||||
// store2.addQuad(DataFactory.quad(
|
||||
// DataFactory.namedNode(meta.subject.id), DataFactory.namedNode(meta.predicate.id), DataFactory.namedNode(meta.object.id)));
|
||||
// // console.log(store)
|
||||
// });
|
||||
|
||||
// const start = async function (a,b){ // we need this line of code to allow "await" function to work because it requires async function
|
||||
// const result = await myEngine.query(`SELECT ${Select} WHERE {${subject} ${predicate} ${object}} LIMIT ${Limit}`,
|
||||
// { sources: [{ type: 'rdfjsSource', value: meta}] })
|
||||
// result.bindingsStream.on('data', (data) => console.log(data.toObject()));
|
||||
// queryResult= result.bindingsStream
|
||||
// // console.log(queryResult)
|
||||
// };
|
||||
// start()
|
||||
// res.json(queryResult);
|
||||
|
||||
});
|
||||
|
||||
//try to make it return the query results insted of the metadata
|
||||
|
||||
|
||||
//});
|
||||
|
||||
/**
|
||||
* this part is an implementation for sparql-engine
|
||||
* any line code will be added for this reason will have a comment of "sparql-engne"
|
||||
*
|
||||
*/
|
||||
// const {Parser, Store }=require('n3');
|
||||
// const {Graph, HashMapDataset, PlanBuilder}= require('sparql-engine');//sparql-engine related
|
||||
// const CustomGraph =require(/*import your Grapg subclass */);
|
||||
|
||||
|
||||
// // Format a triple pattern acccording to N3 API
|
||||
// // SPARQL variables must be replaced by `null` values
|
||||
// function formatTriplePattern (triple){
|
||||
// let subject = null
|
||||
// let predicate = null
|
||||
// let object = null
|
||||
// if (!triple.subject.startWith('?')){
|
||||
// subject = triple.subject
|
||||
// }
|
||||
// if (!triple.predicate.startWith('?')){
|
||||
// predicate = triple.predicate
|
||||
// }
|
||||
// if(!triple.object.startWith('?')){
|
||||
// object = triple.object
|
||||
// }
|
||||
// return { subject, predicate, object}
|
||||
// }
|
||||
//////////////////////END OF SPARQL_ENGINE CODE
|
||||
|
||||
|
||||
// ////////////////sparqle-engine code startred/////////
|
||||
// /**
|
||||
// * the following code is for checking sparql-engine
|
||||
// */
|
||||
|
||||
// // class CustomGraph extends Graph {
|
||||
|
||||
// // /**
|
||||
// // * Returns an iterator that finds RDF triples matching a triple pattern in the graph.
|
||||
// // * @param triple - Triple pattern to find
|
||||
// // * @return An observable which finds RDF triples matching a triple pattern
|
||||
// // */
|
||||
// // find (triple:TripleObject, options: Object): Observable<TripleObject> {/* */}
|
||||
// // }
|
||||
|
||||
// class N3Graph extends Graph {
|
||||
// constructor (){
|
||||
// super()
|
||||
// this._store = store()
|
||||
// }
|
||||
|
||||
// insert (triple){
|
||||
// return new Promise((resolve, reject) => {
|
||||
// try {
|
||||
// this._store.addTriple(triple.subject, triple.predicate, triple.object)
|
||||
// resolve()
|
||||
|
||||
// } catch (e) {
|
||||
// reject (e)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
// find (triple) {
|
||||
// const {subject, predicate, object}= formatTriplePattern(triple)
|
||||
// return this._store.getTriple (subject, predicate, object)
|
||||
// }
|
||||
|
||||
// estimateCardinality (triple){
|
||||
// const {subject,predicate,object} = formatTriplePattern(triple)
|
||||
// return Promise.resolve(this._store.countTriples(subject,predicate,object))
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
|
||||
// const graph = new N3Graph()
|
||||
// const dataset = new HashMapDataset ('http://example.org#default', graph)
|
||||
|
||||
// //load some RDF data into the graph
|
||||
// const parser = new Parser()
|
||||
// parser.parse(`
|
||||
// @prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
||||
// @prefic : <http://example.org#> .
|
||||
// :a foaf:name "a" .
|
||||
// :b foaf:name "b" .
|
||||
// `).forEach(t => {graph._store.addTriple(t)
|
||||
// })
|
||||
|
||||
|
||||
// // const GRAPH_A_IRI ='http://example.org#graph-a';
|
||||
// // const GRAPH_B_IRI ='http://example.org#graph-b';
|
||||
// // const graph_a =new CustomGraph(/* */);
|
||||
// // const graph_b = new CustomGraph(/* */);
|
||||
|
||||
// // //we set graph_a as a defualt RDF dataset
|
||||
// // const dataset = new HashMapDataset(GRAPH_A_IRI, graph_a);
|
||||
// // //insert graph_b as a Named Grapg
|
||||
// // dataset.addNamedGraph(GRAPH_B_IRI, graph_b);
|
||||
|
||||
// //Get the Name of all the people in the default Graph
|
||||
// // const query= `
|
||||
// // PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
// // PREFIX foaf: <http://xmlns.com/foaf/0.1>
|
||||
// // SELECT ?name
|
||||
// // WHERE{
|
||||
// // ?s a foaf:Person .
|
||||
// // ?s rdfs:label ?label .
|
||||
// // }`
|
||||
// const query = `
|
||||
// PREFIX foaf: <http://xmlns.com/foaf/0.1/>
|
||||
// SELECT ?name
|
||||
// WHERE {
|
||||
// ?s foaf:name ?name .
|
||||
// }`
|
||||
|
||||
// // Creates a plan builder for the RDF dataset
|
||||
// const builder = new PlanBuilder(dataset);
|
||||
|
||||
// // Get an iterator to evaluate the query
|
||||
// const iterator = builder.build(query);
|
||||
|
||||
// //read results
|
||||
// iterator.subscribe(
|
||||
// binding => console.log(bindings),
|
||||
// err => console.error(err),
|
||||
// () => console.log('Query evaluation complete')
|
||||
// );
|
||||
///////////////////////////////////////////////////////////Integration///////////////////////////////////////////////////////////
|
||||
DistributedBrokers = ["mqtt.eclipse.org", "test.mosquitto.org","broker.hivemq.com"];
|
||||
DistributedBrokersPorts = [1883,1883,1883];
|
||||
function makeTopic(length) {
|
||||
var result = '';
|
||||
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
var charactersLength = characters.length;
|
||||
for ( var i = 0; i < length; i++ ) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
paymentAmount = [];
|
||||
paymentAddress = [];
|
||||
IoTDeviceAddress = [];
|
||||
IoTApplicationAddress=[];
|
||||
MassagiesRecived = [];
|
||||
var MiddlewareClients =[];
|
||||
MassageCounter =[];
|
||||
StartSending = [];
|
||||
MiddlewareTracking =[];
|
||||
Durations = [];
|
||||
Intervals = [];
|
||||
i = 0;//RequestsIndex
|
||||
|
||||
app.post('/IoTdeviceIntegration-Control', (req, res) => {
|
||||
const {IoTDeviceID,paymentTransactionID,Duration,Protocol}= req.body;
|
||||
Durations.push(Duration);
|
||||
MassageCounter.push(0)
|
||||
MassagiesRecived.push(false);
|
||||
data =bc.chain.map (a => a.data);
|
||||
MetaANDTransFound = false;
|
||||
for (let j= data.length-1; j>0; j-- ){/** this for loop load
|
||||
Blockchain and search for metadata and payment transaction that match
|
||||
the provided MetadataID and TransactionID */
|
||||
var metadata = data[j][1];
|
||||
var transaction = data [j][0];
|
||||
var pickedMetadata = lodash.find(metadata, x=>
|
||||
x.id === IoTDeviceID);
|
||||
var pickedTransction = lodash.find(transaction, x=>
|
||||
x.id === paymentTransactionID);
|
||||
if (pickedMetadata != null && pickedTransction !=null){
|
||||
MetaANDTransFound = true;
|
||||
break;} }
|
||||
if (MetaANDTransFound){
|
||||
//Loading the IoTdevice parameters in order to connect to it
|
||||
var IoTDeviceBroker = pickedMetadata.IP_URL.toString();//mqtt broker
|
||||
var IoTDeviceTopic = pickedMetadata.Topic_Token;// mqtt topic
|
||||
paymentAmount.push(pickedTransction.outputs[1].amount);
|
||||
paymentAddress.push(pickedTransction.outputs[1].address);
|
||||
IoTDeviceAddress.push(pickedMetadata.Signiture.address);
|
||||
IoTApplicationAddress.push(pickedTransction.input.address);
|
||||
Intervals.push(pickedMetadata.Interval)
|
||||
if (paymentAddress[i] == wallet.publicKey){
|
||||
res.redirect('/IoTdataObtainingAndForward');}
|
||||
else{
|
||||
console.log("payment Address not match")}}
|
||||
else{
|
||||
console.log("Metadata or Transaction not found")
|
||||
if (pickedMetadata == null){
|
||||
console.log("metadata not found")}
|
||||
if (pickedTransction == null){
|
||||
console.log("Transaction not found")} }
|
||||
MetaANDTransFound = false;
|
||||
i++;
|
||||
res.json("true");});
|
||||
|
||||
|
||||
|
||||
app.get ('/IoTdataObtainingAndForward', (req, res) => {
|
||||
console.log (`transaction of IoT Application ${i} approved`)
|
||||
BrokerRandomNumber = (Math.floor(
|
||||
Math.random()*DistributedBrokers.length)+1)-1 /** collect
|
||||
a random number to select a random broker*/
|
||||
MiddlewareBroker = DistributedBrokers[BrokerRandomNumber];
|
||||
MiddlewareTopic = makeTopic(5);// generate random topic
|
||||
MiddlewarePort = DistributedBrokersPorts[BrokerRandomNumber];
|
||||
//loading the configuration massage
|
||||
configurationMessage = {"host/broker":MiddlewareBroker,
|
||||
"topic":MiddlewareTopic,
|
||||
"port":MiddlewarePort,
|
||||
"duration":Duration} /** add pk of the node
|
||||
connect to the IoT device and send the configuration massage*/
|
||||
var IoTDeviceClient = mqtt.connect(IoTDeviceBroker);
|
||||
MiddlewareClients.push(mqtt.connect(`mqtt://${MiddlewareBroker}`))
|
||||
var MiddlewareClient = MiddlewareClients[i]
|
||||
IoTDeviceClient.on("connect", ack => {
|
||||
console.log("connected! to IoT Device Client");
|
||||
IoTDeviceClient.subscribe(IoTDeviceTopic, err => {
|
||||
console.log(err); });
|
||||
IoTDeviceClient.publish(IoTDeviceTopic, JSON.stringify(
|
||||
configurationMessage));});
|
||||
IoTDeviceClient.on("error", err => {
|
||||
console.log(err);});
|
||||
IoTDeviceClient.on("message", (topic, message) => {
|
||||
console.log(message.toString())
|
||||
IoTDeviceClient.end(true)});
|
||||
/** connect the randomly choosed mqtt middlware broker to
|
||||
* listen to the transmitted massagies */
|
||||
MiddlewareClient.on("connect", ack => {
|
||||
console.log("connected!");
|
||||
console.log(MiddlewareBroker)
|
||||
StartSending.push(Date.now());
|
||||
MiddlewareClient.subscribe(MiddlewareTopic, err => {
|
||||
console.log(err); });});
|
||||
MiddlewareTracking.push({index:i,
|
||||
TrackingTopic:MiddlewareTopic})/** this used to track the connection
|
||||
in case there are multiple conection at the same time */
|
||||
MiddlewareClient.on("message", (topic, message) => {/** call back,
|
||||
will run each time a massage recived, I did it in a way if there are
|
||||
multiple connections, it will run for all the massagies, then truck the
|
||||
massagies by MiddlwareTracking Array */
|
||||
var MiddlewareFound = MiddlewareTracking.filter(function(item) {
|
||||
return item.TrackingTopic == topic;});
|
||||
console.log(MiddlewareFound);
|
||||
console.log(message.toString());
|
||||
MiddlewareIndex = MiddlewareFound[0].index/** this is the index of
|
||||
the connection or the Middleware*/
|
||||
console.log(MiddlewareIndex)
|
||||
MassageCounter[MiddlewareIndex]++;/** this used to track the number
|
||||
of recived massagies of each connection */
|
||||
console.log(Date.now()-StartSending[MiddlewareIndex])
|
||||
if (Date.now() - StartSending[MiddlewareIndex] >=
|
||||
(Durations[MiddlewareIndex]*1000)
|
||||
-Intervals[MiddlewareIndex]*1000){
|
||||
console.log("sending time finished")
|
||||
if (MassageCounter[MiddlewareIndex] > 0.75*(
|
||||
Durations[MiddlewareIndex]/Intervals[MiddlewareIndex])
|
||||
){/** which means most of massagies have been sent */
|
||||
console.log("massages recived")
|
||||
MassagiesRecived[MiddlewareIndex] = true;}
|
||||
if (MassagiesRecived[MiddlewareIndex]){/** if massagies recived,
|
||||
pay the 10% as service fees */
|
||||
const PaymentTransaction = wallet.createPaymentTransaction(
|
||||
NodeAddress,(0.1*paymentAmount[MiddlewareIndex]) , bc, tp);
|
||||
p2pServer.broadcastPaymentTransaction(PaymentTransaction);
|
||||
console.log("amount paid to the IoT device")
|
||||
console.log(MiddlewareIndex)
|
||||
MiddlewareClient = MiddlewareClients[MiddlewareIndex];
|
||||
/** disconnect the middleware mqtt broker */
|
||||
MiddlewareClient.end(true)}
|
||||
else{// if massagies not recived, pay the IoT application back
|
||||
res.redirect('/IoTapplicationCompensationTransaction')}};});
|
||||
|
||||
|
||||
app.post('/IoTApplicationCompensationTransaction', (req, res) => {
|
||||
const { Recipient_payment_address, Amount_of_money, Payment_method,
|
||||
Further_details} = req.body;
|
||||
if (Payment_method == "SensorCoin"){
|
||||
const PaymentTransaction = wallet.createPaymentTransaction(
|
||||
Recipient_payment_address, Amount_of_money, bc, tp);
|
||||
p2pServer.broadcastPaymentTransaction(PaymentTransaction);
|
||||
res.json("PaymentTransactionCreated");
|
||||
}
|
||||
else if (Payment_method == "Bitcoin") {
|
||||
res.redirect('/BitcoinTransaction')
|
||||
}
|
||||
else if (Payment_method == "PayPal") {
|
||||
res.redirect('/PayPalTransaction')
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
app.post ('/IoTapplicationCompensation', (req, res) => {
|
||||
const PaymentTransaction = wallet.createPaymentTransaction(IoTApplicationAddress[MiddlewareIndex],
|
||||
(paymentAmount[MiddlewareIndex]) , bc, tp);
|
||||
p2pServer.broadcastPaymentTransaction(PaymentTransaction);
|
||||
console.log("amount paid back to the IoT Application")
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var IoTDeviceMassage ="test"
|
||||
app.post('/integrateVirtual', (req, res) => {
|
||||
const {IoTDeviceID,paymentTransactionID,Duration,Protocol}= req.body;
|
||||
|
||||
Durations.push(Duration);
|
||||
MassageCounter.push(0)
|
||||
MassagiesRecived.push(false);
|
||||
|
||||
data =bc.chain.map (a => a.data);
|
||||
MetaANDTransFound = true;
|
||||
// for (let j= 1; j<data.length; j++ ){// this for loop load the Blockchain and search for metadata and payment transaction that match the provided MetadataID and TransactionID
|
||||
// var metadata = data[j][1];
|
||||
// var transaction = data [j][0];
|
||||
// var pickedMetadata = lodash.find(metadata, x=> x.id === IoTDeviceID); ////one thing to consider, what if the IoT device has multiple meatadata (updated metadata)??
|
||||
// var pickedTransction = lodash.find(transaction, x=> x.id === paymentTransactionID);
|
||||
// if (pickedMetadata != null && pickedTransction !=null){
|
||||
// MetaANDTransFound = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
if (MetaANDTransFound){
|
||||
//Loading the IoTdevice parameters in order to connect to it
|
||||
// var IoTDeviceBroker = pickedMetadata.IP_URL.toString();//mqtt broker
|
||||
// var IoTDeviceTopic = pickedMetadata.Topic_Token;// mqtt topic
|
||||
paymentAmount.push(10)//pickedTransction.outputs[1].amount);
|
||||
paymentAddress.push("ADsf")//pickedTransction.outputs[1].address);
|
||||
IoTDeviceAddress.push("fth")//pickedMetadata.Signiture.address);
|
||||
IoTApplicationAddress.push("dtyuyf")//pickedTransction.input.address);
|
||||
Intervals.push(10)//pickedMetadata.Interval)
|
||||
var device = awsIot.device({
|
||||
keyPath: './aws-iot-device-sdk/node_modules/certs/private.pem.key',
|
||||
certPath: './aws-iot-device-sdk/node_modules/certs/certificate.pem.crt',
|
||||
caPath: './aws-iot-device-sdk/node_modules/certs/RootCA1.pem',
|
||||
clientId: 'arn:aws:iot:us-east-1:712303746524:thing/SecondVirtualIoTdevice',
|
||||
host: 'a11joipjrff8s7-ats.iot.us-east-1.amazonaws.com'
|
||||
});
|
||||
//if (paymentAddress[i] == wallet.publicKey){
|
||||
console.log (`transaction of IoT Application ${i} approved`) // add later the check if the amount is match with the required duration
|
||||
BrokerRandomNumber = (Math.floor(Math.random()*DistributedBrokers.length)+1)-1 // collect a random number to select a random broker
|
||||
MiddlewareBroker = DistributedBrokers[BrokerRandomNumber];
|
||||
MiddlewareTopic = makeTopic(5);// generate random topic
|
||||
MiddlewarePort = DistributedBrokersPorts[BrokerRandomNumber];
|
||||
//loading the configuration massage
|
||||
// configurationMessage = {"host/broker":MiddlewareBroker,"topic":MiddlewareTopic, "port":MiddlewarePort, "duration":Duration} // add pk of the node
|
||||
// connect to the IoT device and send the configuration massage
|
||||
// var IoTDeviceClient = mqtt.connect(IoTDeviceBroker);
|
||||
// MiddlewareClients.push(mqtt.connect(`mqtt://${MiddlewareBroker}`))
|
||||
// var MiddlewareClient = MiddlewareClients[i]
|
||||
// IoTDeviceClient.on("connect", ack => {
|
||||
// console.log("connected! to IoT Device Client");
|
||||
// IoTDeviceClient.subscribe(IoTDeviceTopic, err => {
|
||||
// console.log(err);
|
||||
// });
|
||||
// IoTDeviceClient.publish(IoTDeviceTopic, JSON.stringify(configurationMessage));
|
||||
// });
|
||||
|
||||
// IoTDeviceClient.on("error", err => {
|
||||
// console.log(err);
|
||||
// });
|
||||
|
||||
// IoTDeviceClient.on("message", (topic, message) => {
|
||||
// console.log(message.toString())
|
||||
// IoTDeviceClient.end(true)
|
||||
// });
|
||||
// IoTDeviceClient.on("close", ack => {
|
||||
// console.log("Disconnected from IoT Device Client");
|
||||
// });
|
||||
|
||||
device
|
||||
.on('connect', function() {
|
||||
console.log('connect');
|
||||
device.subscribe('/weather/data');// change it to a topic from the metadata
|
||||
// device.publish('/weather/data', JSON.stringify({ test_data: 2}));
|
||||
});
|
||||
|
||||
device
|
||||
.on('message', function(topic, payload) {
|
||||
// console.log('message', topic, payload.toString());
|
||||
IoTDeviceMassage = payload.toString();
|
||||
MiddlewareClient.publish(MiddlewareTopic,IoTDeviceMassage)
|
||||
});
|
||||
|
||||
// connect the randomly choosed mqtt middlware broker to listen to the transmitted massagies
|
||||
MiddlewareClients.push(mqtt.connect(`mqtt://${MiddlewareBroker}`))
|
||||
var MiddlewareClient = MiddlewareClients[i]
|
||||
MiddlewareClient.on("connect", ack => {
|
||||
console.log("connected!");
|
||||
console.log(MiddlewareBroker)
|
||||
StartSending.push(Date.now());
|
||||
MiddlewareClient.subscribe(MiddlewareTopic, err => {
|
||||
console.log(err);
|
||||
});
|
||||
MiddlewareClient.publish(MiddlewareTopic,IoTDeviceMassage)
|
||||
});
|
||||
|
||||
MiddlewareTracking.push({index:i, TrackingTopic:MiddlewareTopic})// this used to track the connection in case there are multiple conection at the same time
|
||||
|
||||
MiddlewareClient.on("message", (topic, message) => {// call back, will run each time a massage recived, I did it in a way if there are multiple connections, it will run for all the massagies, then we truck the massahies by MiddlwareTracking Array
|
||||
console.log(message.toString());
|
||||
var MiddlewareFound = MiddlewareTracking.filter(function(item) {
|
||||
return item.TrackingTopic == topic;
|
||||
});
|
||||
console.log(MiddlewareFound);
|
||||
MiddlewareIndex = MiddlewareFound[0].index;// this is the index of the connection or the Middleware
|
||||
console.log(MiddlewareIndex);
|
||||
MassageCounter[MiddlewareIndex]++;// this used to track the number of recived massagies of each connection
|
||||
console.log(Date.now()-StartSending[MiddlewareIndex])
|
||||
if (Date.now() - StartSending[MiddlewareIndex] >= (Durations[MiddlewareIndex]*1000)-Intervals[MiddlewareIndex]*1000){
|
||||
console.log("sending time finished")
|
||||
if (MassageCounter[MiddlewareIndex] > 0.75*(Durations[MiddlewareIndex]/Intervals[MiddlewareIndex])){// which means most of massagies have been sent
|
||||
console.log("massages recived")
|
||||
MassagiesRecived[MiddlewareIndex] = true;
|
||||
}
|
||||
if (MassagiesRecived[MiddlewareIndex]){// if massagies recived, pay the IoT device and substract 10% as service fees
|
||||
const cointransaction = wallet.createCoinTransaction(IoTDeviceAddress[MiddlewareIndex],(paymentAmount[MiddlewareIndex]-0.1*paymentAmount[MiddlewareIndex]) , bc, tp);
|
||||
p2pServer.broadcastCoinTransaction(cointransaction);
|
||||
console.log("amount paid to the IoT device")
|
||||
console.log(MiddlewareIndex)
|
||||
MiddlewareClient = MiddlewareClients[MiddlewareIndex];// disconnect the middleware mqtt broker
|
||||
MiddlewareClient.end(true)
|
||||
}
|
||||
else{// if massagies not recived, pay the ioT application back
|
||||
const cointransaction = wallet.createCoinTransaction(IoTApplicationAddress[MiddlewareIndex],(paymentAmount[MiddlewareIndex]) , bc, tp);
|
||||
p2pServer.broadcastCoinTransaction(cointransaction);
|
||||
console.log("amount paid back to the IoT Application")
|
||||
console.log(MiddlewareIndex)
|
||||
MiddlewareClient = MiddlewareClients[MiddlewareIndex];// disconnect the middleware mqtt broker
|
||||
MiddlewareClient.end(true)
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
// }
|
||||
// else{
|
||||
// console.log("payment Address not match")
|
||||
// }
|
||||
}
|
||||
|
||||
else{
|
||||
console.log("Metadata or Transaction not found")
|
||||
if (pickedMetadata == null){
|
||||
console.log("metadata not found")
|
||||
}
|
||||
if (pickedTransction == null){
|
||||
console.log("Transaction not found")
|
||||
}
|
||||
}
|
||||
|
||||
MetaANDTransFound = false;
|
||||
i++;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Device is an instance returned by mqtt.Client(), see mqtt.js for full
|
||||
// documentation.
|
||||
//
|
||||
|
||||
|
||||
|
||||
res.json("true");
|
||||
});
|
||||
|
||||
|
||||
});
|
63
app/miner.js
Normal file
63
app/miner.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
const Wallet = require('../wallet');
|
||||
const CoinTransaction = require('../wallet/CoinTransaction');
|
||||
const MetaDataTransaction = require('../wallet/MetaDataTransaction');
|
||||
//const MetaDataPool= require('../wallet/metaData-Pool');
|
||||
const { MaxNumOfCoinTransactions, MaxNumOfMetadataTransactions} = require('../config');
|
||||
var TransactionPointer;
|
||||
var NumberOfClearedCoins;
|
||||
var NumberOfClearedMeta;
|
||||
class Miner {
|
||||
constructor(blockchain, transactionPool, wallet, p2pServer) {
|
||||
this.blockchain = blockchain;
|
||||
this.transactionPool = transactionPool;
|
||||
this.wallet = wallet;
|
||||
this.p2pServer = p2pServer;
|
||||
}
|
||||
|
||||
mine() {
|
||||
|
||||
//const validCoinTransactions = this.transactionPool.validCoinTransactions(); Temeperarly changed without checking transaction validity
|
||||
var SelectedCoinTransactions = this.transactionPool.cointransactions.slice(0, MaxNumOfCoinTransactions);
|
||||
var SelectedMetadataTransactions = this.transactionPool.metaDataTransactions.slice(0, MaxNumOfMetadataTransactions);
|
||||
//const validTransactions = validCoinTransactions.Concat(validMetaDataTransactions);
|
||||
// SelectedCoinTransactions = validCoinTransactions.splice (0, MaxNumOfCoinTransactions); //this will return only limited number of transactions to be stored
|
||||
// for (TransactionPointer=0; TransactionPointer<MaxNumOfCoinTransactions; TransactionPointer++){
|
||||
// SelectedCoinTransactions.push(validCoinTransactions[TransactionPointer]);
|
||||
// }
|
||||
|
||||
// SelectedMetadataTransactions = validMetadataTransactions.splice (0, MaxNumOfMetadataTransactions);
|
||||
// for (TransactionPointer=0; TransactionPointer<MaxNumOfCoinTransactions; TransactionPointer++){
|
||||
// SelectedCoinTransactions.push(validCoinTransactions[TransactionPointer]);
|
||||
// }
|
||||
// include a reward transaction for the miner
|
||||
SelectedCoinTransactions.push(CoinTransaction.rewardCoinTransaction(this.wallet, Wallet.blockchainWallet()));
|
||||
//CoinTransaction.rewardCoinTransaction(this.wallet, Wallet.blockchainWallet()));
|
||||
// create a block consisting of the valid transactions
|
||||
const block = this.blockchain.addBlock([SelectedCoinTransactions,SelectedMetadataTransactions]);
|
||||
//const block = this.blockchain.addBlock(validTransactions);
|
||||
// synchronize chains in the peer-to-peer server
|
||||
|
||||
|
||||
this.p2pServer.syncChains();
|
||||
|
||||
// clear the transaction pool
|
||||
// broadcast to every miner to clear their transaction pools
|
||||
// if (validCoinTransactions.length>MaxNumOfCoinTransactions){
|
||||
// this.transactionPool.clearCoin();// clears only selected cointransactions
|
||||
|
||||
this.transactionPool.clearCoin(SelectedCoinTransactions.length-1);
|
||||
this.transactionPool.clearMeta(SelectedMetadataTransactions.length);
|
||||
this.p2pServer.broadcastClearCoinTransactions();
|
||||
this.p2pServer.broadcastClearMetadataTransactions();
|
||||
SelectedCoinTransactions = [];
|
||||
SelectedMetadataTransactions =[];
|
||||
// }
|
||||
// else {
|
||||
// this.transactionPool.clearAll();
|
||||
// this.p2pServer.broadcastClearAllTransactions();
|
||||
// }
|
||||
return block;
|
||||
}
|
||||
}
|
||||
//module.exports = {NumberOfClearedCoins, NumberOfClearedMeta};
|
||||
module.exports = Miner;
|
124
app/p2p-server.js
Normal file
124
app/p2p-server.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
const Websocket = require('ws');
|
||||
const P2P_PORT = process.env.P2P_PORT || 5001;
|
||||
const peers = process.env.PEERS ? process.env.PEERS.split(',') : [];
|
||||
const MESSAGE_TYPES = {
|
||||
chain: 'CHAIN',
|
||||
cointransaction: 'COINTRANSACTION',
|
||||
clear_payment_transactions: 'CLEAR_Payment_TRANSACTIONS',
|
||||
clear_meta_transactions: 'CLEAR_META_TRANSACTIONS',
|
||||
clear_Comp_transactions: 'CLEAR_COMP_TRANSACTIONS',
|
||||
clear_Integration_transactions: 'CLEAR_Integration_TRANSACTIONS',
|
||||
metaDataTransaction: 'METADATATRANSACTION',};
|
||||
class P2pServer {
|
||||
constructor(blockchain, transactionPool) {
|
||||
this.blockchain = blockchain;
|
||||
this.transactionPool = transactionPool;
|
||||
this.sockets = [];}
|
||||
listen() {
|
||||
const server = new Websocket.Server({ port: P2P_PORT });
|
||||
server.on('connection', socket => this.connectSocket(socket));
|
||||
this.connectToPeers();
|
||||
console.log(`Listening for peer-to-peer connections on: ${P2P_PORT}`);}
|
||||
connectToPeers() {
|
||||
peers.forEach(peer => {
|
||||
const socket = new Websocket(peer);
|
||||
socket.on('open', () => this.connectSocket(socket)); });}
|
||||
connectSocket(socket) {
|
||||
this.sockets.push(socket);
|
||||
console.log('Socket connected');
|
||||
this.messageHandler(socket);
|
||||
this.sendChain(socket);}
|
||||
messageHandler(socket) {
|
||||
socket.on('message', message => {
|
||||
const data = JSON.parse(message);
|
||||
switch(data.type) {
|
||||
case MESSAGE_TYPES.chain:
|
||||
this.blockchain.replaceChain(data.chain);
|
||||
break;
|
||||
case MESSAGE_TYPES.paymenttransaction:
|
||||
this.transactionPool.updateOrAddPaymentTransaction(
|
||||
data.Paymenttransaction);
|
||||
break;
|
||||
case MESSAGE_TYPES.metaDataTransaction:
|
||||
this.transactionPool.updateOrAddMetaDataTransaction(
|
||||
data.metaDataTransaction);
|
||||
break;
|
||||
case MESSAGE_TYPES.CompTransaction:
|
||||
this.transactionPool.updateOrAddCompTransaction(
|
||||
data.CompTransaction);
|
||||
break;
|
||||
case MESSAGE_TYPES.IntegrationTransaction:
|
||||
this.transactionPool.updateOrAddIntegrationTransaction(
|
||||
data.IntegrationTransaction);
|
||||
break;
|
||||
case MESSAGE_TYPES.clear_Payment_transactions:
|
||||
this.transactionPool.clearPayment(this.blockchain.chain[this.
|
||||
blockchain.chain.length-1].data[0].length-1);
|
||||
break;
|
||||
case MESSAGE_TYPES.clear_meta_transactions:
|
||||
this.transactionPool.clearMeta(this.blockchain.chain[this.
|
||||
blockchain.chain.length-1].data[1].length);
|
||||
break;
|
||||
case MESSAGE_TYPES.clear_comp_transactions:
|
||||
this.transactionPool.clearMeta(this.blockchain.chain[this.
|
||||
blockchain.chain.length-1].data[1].length);
|
||||
break;
|
||||
case MESSAGE_TYPES.clear_intgration_transactions:
|
||||
this.transactionPool.clearMeta(this.blockchain.chain[this.
|
||||
blockchain.chain.length-1].data[1].length);
|
||||
break;}});}
|
||||
sendChain(socket) {
|
||||
socket.send(JSON.stringify({
|
||||
type: MESSAGE_TYPES.chain,
|
||||
chain: this.blockchain.chain}));}
|
||||
ClearedPayments (socket){
|
||||
socket.send(JSON.stringify({
|
||||
type: MESSAGE_TYPES.clear_payment_transactions,})); }
|
||||
ClearedMeta (socket){
|
||||
socket.send(JSON.stringify({
|
||||
type: MESSAGE_TYPES.clear_meta_transactions,}));}
|
||||
ClearedComp (socket){
|
||||
socket.send(JSON.stringify({
|
||||
type: MESSAGE_TYPES.clear_comp_transactions,}));}
|
||||
ClearedIntegration (socket){
|
||||
socket.send(JSON.stringify({
|
||||
type: MESSAGE_TYPES.clear_integration_transactions,}));}
|
||||
sendPaymentTransaction(socket, paymenttransaction) {
|
||||
socket.send(JSON.stringify({
|
||||
type: MESSAGE_TYPES.paymenttransaction,
|
||||
paymenttransaction}));}
|
||||
sendMetaDataTransaction(socket, metaDataTransaction) {
|
||||
socket.send(JSON.stringify({
|
||||
type: MESSAGE_TYPES.metaDataTransaction,
|
||||
metaDataTransaction}));}
|
||||
sendIntegrationTransaction(socket, integrationTransaction) {
|
||||
socket.send(JSON.stringify({
|
||||
type: MESSAGE_TYPES.integrationTransaction,
|
||||
integrationTransaction}));}
|
||||
sendCompTransaction(socket, compTransaction) {
|
||||
socket.send(JSON.stringify({
|
||||
type: MESSAGE_TYPES.compTransaction,
|
||||
compTransaction}));}
|
||||
syncChains() {
|
||||
this.sockets.forEach(socket => this.sendChain(socket));}
|
||||
broadcastPaymentTransaction(paymenttransaction) {
|
||||
this.sockets.forEach(socket => this.sendPaymentTransaction(socket,
|
||||
paymenttransaction));}
|
||||
broadcastMetaDataTransaction(metaDataTransaction) {
|
||||
this.sockets.forEach(socket => this.sendMetaDataTransaction(socket,
|
||||
metaDataTransaction));}
|
||||
broadcastCompTransaction(compTransaction) {
|
||||
this.sockets.forEach(socket => this.sendCompTransaction(socket,
|
||||
CompTransaction));}
|
||||
broadcastIntegrationTransaction(integrationTransaction) {
|
||||
this.sockets.forEach(socket => this.sendIntegrationTransaction(socket,
|
||||
integrationTransaction));}
|
||||
broadcastClearPaymentTransactions() {
|
||||
this.sockets.forEach(socket => this.ClearedCoins(socket));}
|
||||
broadcastClearMetadataTransactions() {
|
||||
this.sockets.forEach(socket => this.ClearedMeta(socket));}
|
||||
broadcastClearCompTransactions() {
|
||||
this.sockets.forEach(socket => this.ClearedComp(socket));}
|
||||
broadcastClearIntegrationTransactions() {
|
||||
this.sockets.forEach(socket => this.ClearedIntegration(socket));}}
|
||||
module.exports = P2pServer ;
|
6
app/swagger.js
Normal file
6
app/swagger.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
const swaggerAutogen = require('swagger-autogen')()
|
||||
|
||||
const outputFile = './swagger_output.json'
|
||||
const APIfiles = ['./index.js']
|
||||
|
||||
swaggerAutogen(outputFile, APIfiles)
|
369
app/swagger_output.json
Normal file
369
app/swagger_output.json
Normal file
|
@ -0,0 +1,369 @@
|
|||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "1.0.0",
|
||||
"title": "REST API",
|
||||
"description": ""
|
||||
},
|
||||
"host": "localhost:3000",
|
||||
"basePath": "/",
|
||||
"schemes": [
|
||||
"http"
|
||||
],
|
||||
"paths": {
|
||||
"/blocks": {
|
||||
"get": {
|
||||
"description": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/MetaDataTransactions": {
|
||||
"get": {
|
||||
"description": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/CoinTransactions": {
|
||||
"get": {
|
||||
"description": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/Transactions": {
|
||||
"get": {
|
||||
"description": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/mine-transactions": {
|
||||
"get": {
|
||||
"description": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/public-key": {
|
||||
"get": {
|
||||
"description": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/Balance": {
|
||||
"get": {
|
||||
"description": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/mine": {
|
||||
"post": {
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"example": "any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/IoTdeviceRegistration": {
|
||||
"post": {
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Name": {
|
||||
"example": "any"
|
||||
},
|
||||
"Geo": {
|
||||
"example": "any"
|
||||
},
|
||||
"IP_URL": {
|
||||
"example": "any"
|
||||
},
|
||||
"Topic_Token": {
|
||||
"example": "any"
|
||||
},
|
||||
"Permission": {
|
||||
"example": "any"
|
||||
},
|
||||
"RequestDetail": {
|
||||
"example": "any"
|
||||
},
|
||||
"OrgOwner": {
|
||||
"example": "any"
|
||||
},
|
||||
"DepOwner": {
|
||||
"example": "any"
|
||||
},
|
||||
"PrsnOwner": {
|
||||
"example": "any"
|
||||
},
|
||||
"PaymentPerKbyte": {
|
||||
"example": "any"
|
||||
},
|
||||
"PaymentPerMinute": {
|
||||
"example": "any"
|
||||
},
|
||||
"Protocol": {
|
||||
"example": "any"
|
||||
},
|
||||
"MessageAttributes": {
|
||||
"example": "any"
|
||||
},
|
||||
"Interval": {
|
||||
"example": "any"
|
||||
},
|
||||
"FurtherDetails": {
|
||||
"example": "any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/IoTdevicePaymentTransaction": {
|
||||
"post": {
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Recipient_payment_address": {
|
||||
"example": "any"
|
||||
},
|
||||
"Amount_of_money": {
|
||||
"example": "any"
|
||||
},
|
||||
"Payment_method": {
|
||||
"example": "any"
|
||||
},
|
||||
"Further_details": {
|
||||
"example": "any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/UploadMetafile": {
|
||||
"post": {
|
||||
"description": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"201": {
|
||||
"description": "Created"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/selectedMeta": {
|
||||
"post": {
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Name": {
|
||||
"example": "any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/sparql": {
|
||||
"post": {
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Select": {
|
||||
"example": "any"
|
||||
},
|
||||
"subject": {
|
||||
"example": "any"
|
||||
},
|
||||
"predicate": {
|
||||
"example": "any"
|
||||
},
|
||||
"object": {
|
||||
"example": "any"
|
||||
},
|
||||
"Limit": {
|
||||
"example": "any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/sparql2": {
|
||||
"post": {
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Select": {
|
||||
"example": "any"
|
||||
},
|
||||
"subject": {
|
||||
"example": "any"
|
||||
},
|
||||
"predicate": {
|
||||
"example": "any"
|
||||
},
|
||||
"object": {
|
||||
"example": "any"
|
||||
},
|
||||
"Limit": {
|
||||
"example": "any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/IoTdeviceIntegration-Control": {
|
||||
"post": {
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"IoTDeviceID": {
|
||||
"example": "any"
|
||||
},
|
||||
"paymentTransactionID": {
|
||||
"example": "any"
|
||||
},
|
||||
"Duration": {
|
||||
"example": "any"
|
||||
},
|
||||
"Protocol": {
|
||||
"example": "any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/IoTdataObtainingAndForward": {
|
||||
"get": {
|
||||
"description": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
BIN
blockchain/.DS_Store
vendored
Normal file
BIN
blockchain/.DS_Store
vendored
Normal file
Binary file not shown.
58
blockchain/block.js
Normal file
58
blockchain/block.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
const ChainUtil = require('../chain-util');
|
||||
const { DIFFICULTY, MINE_RATE } = require('../config');
|
||||
|
||||
class Block {
|
||||
constructor(timestamp,BlockNum, lastHash, hash, data, nonce,
|
||||
difficulty) {
|
||||
this.timestamp = timestamp;
|
||||
this.BlockNum = BlockNum;
|
||||
this.lastHash = lastHash;
|
||||
this.hash = hash;
|
||||
this.data = data;
|
||||
this.nonce = nonce;
|
||||
this.difficulty = difficulty || DIFFICULTY;
|
||||
}
|
||||
toString() {
|
||||
return `Block -
|
||||
Timestamp : ${this.timestamp}
|
||||
BlockNum : ${this.BlockNum}
|
||||
Last Hash : ${this.lastHash.substring(0, 10)}
|
||||
Hash : ${this.hash.substring(0, 10)}
|
||||
Nonce : ${this.nonce}
|
||||
Difficulty: ${this.difficulty}
|
||||
Data : ${this.data[0].length}`;
|
||||
}
|
||||
static genesis() {
|
||||
return new this('Genesis-time',0, '-----', 'First-Hash',
|
||||
[], 0, DIFFICULTY);
|
||||
}
|
||||
static mineBlock(lastBlock, data) {
|
||||
let hash, timestamp;
|
||||
const lastHash = lastBlock.hash;
|
||||
let { difficulty } = lastBlock;
|
||||
let nonce = 0;
|
||||
let BlockNum = lastBlock.BlockNum + 1;
|
||||
do {
|
||||
nonce++;
|
||||
timestamp = Date.now();
|
||||
difficulty = Block.adjustDifficulty(lastBlock, timestamp);
|
||||
hash = Block.hash(timestamp, lastHash, data, nonce, difficulty);
|
||||
} while (hash.substring(0, difficulty) !== '0'.repeat(difficulty));
|
||||
return new this(timestamp,BlockNum, lastHash, hash, data, nonce,
|
||||
difficulty);}
|
||||
static hash(timestamp,lastHash, data, nonce, difficulty) {
|
||||
return ChainUtil.hash(`${timestamp}${lastHash}${data}${nonce}
|
||||
${difficulty}`).toString();
|
||||
}
|
||||
static blockHash(block) {
|
||||
const { timestamp, lastHash, data, nonce, difficulty } = block;
|
||||
return Block.hash(timestamp, lastHash, data, nonce, difficulty);
|
||||
}
|
||||
static adjustDifficulty(lastBlock, currentTime) {
|
||||
let { difficulty } = lastBlock;
|
||||
difficulty = lastBlock.timestamp + MINE_RATE > currentTime ?
|
||||
difficulty + 1 : difficulty - 1;
|
||||
return difficulty;
|
||||
}
|
||||
}
|
||||
module.exports = Block;
|
34
blockchain/block.test.js
Normal file
34
blockchain/block.test.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
const Block = require('./block');
|
||||
|
||||
describe('Block', () => {
|
||||
let data, lastBlock, block;
|
||||
|
||||
beforeEach(() => {
|
||||
data = 'bar';
|
||||
lastBlock = Block.genesis();
|
||||
block = Block.mineBlock(lastBlock, data);
|
||||
});
|
||||
|
||||
it('sets the `data` to match the input', () => {
|
||||
expect(block.data).toEqual(data);
|
||||
});
|
||||
|
||||
it('sets the `lastHash` to match the hash of the last block', () => {
|
||||
expect(block.lastHash).toEqual(lastBlock.hash);
|
||||
});
|
||||
|
||||
it('generates a hash that matches the difficulty', () => {
|
||||
expect(block.hash.substring(0, block.difficulty))
|
||||
.toEqual('0'.repeat(block.difficulty));
|
||||
});
|
||||
|
||||
it('lowers the difficulty for slowly mined blocks', () => {
|
||||
expect(Block.adjustDifficulty(block, block.timestamp+360000))
|
||||
.toEqual(block.difficulty-1);
|
||||
});
|
||||
|
||||
it('raises the difficulty for quickly mined blocks', () => {
|
||||
expect(Block.adjustDifficulty(block, block.timestamp+1))
|
||||
.toEqual(block.difficulty+1);
|
||||
});
|
||||
});
|
45
blockchain/index.js
Normal file
45
blockchain/index.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
const Block = require('./block');
|
||||
|
||||
class Blockchain {
|
||||
constructor() {
|
||||
this.chain = [Block.genesis()];
|
||||
}
|
||||
|
||||
addBlock(data) {
|
||||
const block = Block.mineBlock(this.chain[this.chain.length-1], data);
|
||||
this.chain.push(block);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
isValidChain(chain) {
|
||||
if(JSON.stringify(chain[0]) !== JSON.stringify(Block.genesis())) return false;
|
||||
|
||||
for (let i=1; i<chain.length; i++) {
|
||||
const block = chain[i];
|
||||
const lastBlock = chain[i-1];
|
||||
|
||||
if (block.lastHash !== lastBlock.hash ||
|
||||
block.hash !== Block.blockHash(block)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
replaceChain(newChain) {
|
||||
if (newChain.length <= this.chain.length) {
|
||||
console.log('Received chain is not longer than the current chain.');
|
||||
return;
|
||||
} else if (!this.isValidChain(newChain)) {
|
||||
console.log('The received chain is not valid.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Replacing blockchain with the new chain.');
|
||||
this.chain = newChain;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Blockchain;
|
55
blockchain/index.test.js
Normal file
55
blockchain/index.test.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
const Blockchain = require('./index');
|
||||
const Block = require('./block');
|
||||
|
||||
describe('Blockchain', () => {
|
||||
let bc, bc2;
|
||||
|
||||
beforeEach(() => {
|
||||
bc = new Blockchain();
|
||||
bc2 = new Blockchain();
|
||||
});
|
||||
|
||||
it('starts with genesis block', () => {
|
||||
expect(bc.chain[0]).toEqual(Block.genesis());
|
||||
});
|
||||
|
||||
it('adds a new block', () => {
|
||||
const data = 'foo';
|
||||
bc.addBlock(data);
|
||||
|
||||
expect(bc.chain[bc.chain.length-1].data).toEqual(data);
|
||||
});
|
||||
|
||||
it('validates a valid chain', () => {
|
||||
bc2.addBlock('foo');
|
||||
|
||||
expect(bc.isValidChain(bc2.chain)).toBe(true);
|
||||
});
|
||||
|
||||
it('invalidates a chain with a corrupt genesis block', () => {
|
||||
bc2.chain[0].data = 'Bad data';
|
||||
|
||||
expect(bc.isValidChain(bc2.chain)).toBe(false);
|
||||
});
|
||||
|
||||
it('invalidates a corrupt chain', () => {
|
||||
bc2.addBlock('foo');
|
||||
bc2.chain[1].data = 'Not foo';
|
||||
|
||||
expect(bc.isValidChain(bc2.chain)).toBe(false);
|
||||
});
|
||||
|
||||
it('replaces the chain with a valid chain', () => {
|
||||
bc2.addBlock('goo');
|
||||
bc.replaceChain(bc2.chain);
|
||||
|
||||
expect(bc.chain).toEqual(bc2.chain);
|
||||
});
|
||||
|
||||
it('does not replace the chain with one of less than or equal to length', () => {
|
||||
bc.addBlock('foo');
|
||||
bc.replaceChain(bc2.chain);
|
||||
|
||||
expect(bc.chain).not.toEqual(bc2.chain);
|
||||
})
|
||||
});
|
296
blocks.json
Normal file
296
blocks.json
Normal file
|
@ -0,0 +1,296 @@
|
|||
Block -
|
||||
Timestamp : 1581892713022
|
||||
Last Hash : f1r57-h45h
|
||||
Hash : 0000f64170
|
||||
Nonce : 94889
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581892714610
|
||||
Last Hash : 0000f64170
|
||||
Hash : 000001941a
|
||||
Nonce : 121452
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581892736795
|
||||
Last Hash : 000004bdbe
|
||||
Hash : 0000af3e65
|
||||
Nonce : 1109949
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581892725766
|
||||
Last Hash : 00001402a6
|
||||
Hash : 000004bdbe
|
||||
Nonce : 114910
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581892752249
|
||||
Last Hash : 0000145513
|
||||
Hash : 0000085224
|
||||
Nonce : 484976
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581892762535
|
||||
Last Hash : 0000085224
|
||||
Hash : 00001cd286
|
||||
Nonce : 995419
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581892763338
|
||||
Last Hash : 00001cd286
|
||||
Hash : 00000c8fa5
|
||||
Nonce : 80136
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581892724628
|
||||
Last Hash : 000001941a
|
||||
Hash : 00001402a6
|
||||
Nonce : 964391
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581892746837
|
||||
Last Hash : 0000af3e65
|
||||
Hash : 0005cb06ba
|
||||
Nonce : 960133
|
||||
Difficulty: 3
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581892747191
|
||||
Last Hash : 0005cb06ba
|
||||
Hash : 0000145513
|
||||
Nonce : 35175
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894328935
|
||||
Last Hash : f1r57-h45h
|
||||
Hash : 0000027b9b
|
||||
Nonce : 41326
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894353562
|
||||
Last Hash : 00084950c6
|
||||
Hash : 0000cc1d6a
|
||||
Nonce : 16931
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894360160
|
||||
Last Hash : 0000cc1d6a
|
||||
Hash : 00000a55b4
|
||||
Nonce : 681141
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894370451
|
||||
Last Hash : 00000a55b4
|
||||
Hash : 000062a73f
|
||||
Nonce : 1065366
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894372244
|
||||
Last Hash : 000062a73f
|
||||
Hash : 000006be7e
|
||||
Nonce : 182919
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894383168
|
||||
Last Hash : 000006be7e
|
||||
Hash : 0000947649
|
||||
Nonce : 1129947
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894385832
|
||||
Last Hash : 0000947649
|
||||
Hash : 0000063c81
|
||||
Nonce : 274322
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894339035
|
||||
Last Hash : 0000027b9b
|
||||
Hash : 0007a1423c
|
||||
Nonce : 995688
|
||||
Difficulty: 3
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894343276
|
||||
Last Hash : 0007a1423c
|
||||
Hash : 00008d4e58
|
||||
Nonce : 379871
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581894353389
|
||||
Last Hash : 00008d4e58
|
||||
Hash : 00084950c6
|
||||
Nonce : 1043732
|
||||
Difficulty: 3
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914042391
|
||||
Last Hash : f1r57-h45h
|
||||
Hash : 00005dbdc7
|
||||
Nonce : 16289
|
||||
Difficulty: 4
|
||||
Data : [object Object],[object Object],[object Object]
|
||||
Block -
|
||||
Timestamp : 1581914052481
|
||||
Last Hash : 00005dbdc7
|
||||
Hash : 0002715612
|
||||
Nonce : 945209
|
||||
Difficulty: 3
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914052947
|
||||
Last Hash : 0002715612
|
||||
Hash : 00006f867b
|
||||
Nonce : 44547
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914073313
|
||||
Last Hash : 0002826b45
|
||||
Hash : 0000595eff
|
||||
Nonce : 7524
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914083348
|
||||
Last Hash : 0000595eff
|
||||
Hash : 000387395e
|
||||
Nonce : 974338
|
||||
Difficulty: 3
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914083523
|
||||
Last Hash : 000387395e
|
||||
Hash : 0000d7ada9
|
||||
Nonce : 15912
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914091333
|
||||
Last Hash : 0000d7ada9
|
||||
Hash : 00000ce8de
|
||||
Nonce : 733896
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914063218
|
||||
Last Hash : 000873faba
|
||||
Hash : 0000c9a5a8
|
||||
Nonce : 23871
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914073229
|
||||
Last Hash : 0000c9a5a8
|
||||
Hash : 0002826b45
|
||||
Nonce : 1004347
|
||||
Difficulty: 3
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914062966
|
||||
Last Hash : 00006f867b
|
||||
Hash : 000873faba
|
||||
Nonce : 964936
|
||||
Difficulty: 3
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914568417
|
||||
Last Hash : f1r57-h45h
|
||||
Hash : 0000646876
|
||||
Nonce : 8365
|
||||
Difficulty: 4
|
||||
Data : [object Object],[object Object],[object Object]
|
||||
Block -
|
||||
Timestamp : 1581914578440
|
||||
Last Hash : 0000646876
|
||||
Hash : 00034edf74
|
||||
Nonce : 948376
|
||||
Difficulty: 3
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914579386
|
||||
Last Hash : 00034edf74
|
||||
Hash : 00003f7371
|
||||
Nonce : 88529
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914847561
|
||||
Last Hash : f1r57-h45h
|
||||
Hash : 0000a45f66
|
||||
Nonce : 58810
|
||||
Difficulty: 4
|
||||
Data : [object Object],[object Object]
|
||||
Block -
|
||||
Timestamp : 1581914850074
|
||||
Last Hash : 0000a45f66
|
||||
Hash : 0000053121
|
||||
Nonce : 229566
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581914860093
|
||||
Last Hash : 0000053121
|
||||
Hash : 0000f0fa54
|
||||
Nonce : 968591
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581915028382
|
||||
Last Hash : f1r57-h45h
|
||||
Hash : 000012342d
|
||||
Nonce : 74682
|
||||
Difficulty: 4
|
||||
Data : [object Object],[object Object]
|
||||
Block -
|
||||
Timestamp : 1581915029059
|
||||
Last Hash : 000012342d
|
||||
Hash : 000009fa64
|
||||
Nonce : 59238
|
||||
Difficulty: 5
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1581915039087
|
||||
Last Hash : 000009fa64
|
||||
Hash : 0000219469
|
||||
Nonce : 963908
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1631336762365
|
||||
Last Hash : f1r57-h45h
|
||||
Hash : 0000cb4fc4
|
||||
Nonce : 87088
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Mined Block
|
||||
Block -
|
||||
Timestamp : 1631336852594
|
||||
Last Hash : f1r57-h45h
|
||||
Hash : 0000fa68c7
|
||||
Nonce : 31088
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Block -
|
||||
Timestamp : 1631337166316
|
||||
Last Hash : f1r57-h45h
|
||||
Hash : 0000b73e4b
|
||||
Nonce : 31185
|
||||
Difficulty: 4
|
||||
Data : [object Object],
|
||||
Mined Block
|
24
chain-util.js
Normal file
24
chain-util.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
const EC = require('elliptic').ec;
|
||||
const SHA256 = require('crypto-js/sha256');
|
||||
const uuidV1 = require('uuid/v1');
|
||||
const ec = new EC('secp256k1');
|
||||
|
||||
class ChainUtil {
|
||||
static genKeyPair() {
|
||||
return ec.genKeyPair();
|
||||
}
|
||||
|
||||
static id() {
|
||||
return uuidV1();
|
||||
}
|
||||
|
||||
static hash(data) {
|
||||
return SHA256(JSON.stringify(data)).toString();
|
||||
}
|
||||
|
||||
static verifySignature(publicKey, signature, dataHash) {
|
||||
return ec.keyFromPublic(publicKey, 'hex').verify(dataHash, signature);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChainUtil;
|
8
config.js
Normal file
8
config.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
const DIFFICULTY = 5;
|
||||
const MINE_RATE = 20000;
|
||||
const INITIAL_BALANCE = 500;
|
||||
const MINING_REWARD = 50;
|
||||
const MaxNumOfCoinTransactions = 3;
|
||||
const MaxNumOfMetadataTransactions = 3;
|
||||
|
||||
module.exports = { DIFFICULTY, MINE_RATE, INITIAL_BALANCE, MINING_REWARD, MaxNumOfCoinTransactions, MaxNumOfMetadataTransactions} ;
|
3
dev-test.js
Normal file
3
dev-test.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
const Wallet = require('./wallet');
|
||||
const wallet = new Wallet();
|
||||
console.log(wallet.toString());
|
5
nodemon.json
Normal file
5
nodemon.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"env": {
|
||||
"MONGO_ATLAS_PW":"11112222-m"
|
||||
}
|
||||
}
|
13938
package-lock.json
generated
Normal file
13938
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
55
package.json
Normal file
55
package.json
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "Sen-Sha-Mart",
|
||||
"version": "6.0.0",
|
||||
"description": "A novel Marketplace for sharing sensors in decentralized environment",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "jest --watchAll",
|
||||
"dev-test": "nodemon dev-test",
|
||||
"start": "node ./app",
|
||||
"dev": "nodemon ./app",
|
||||
"sparql": "nodemon ./test/comunicaSPARQL",
|
||||
"jsonld": "nodemon ./test/jsonld",
|
||||
"sparqlEngine": "nodemon ./test/sparqlEngine",
|
||||
"N3": "nodemon ./test/N3sudo yarn ",
|
||||
"swagger-autogen": "node ./app/swagger.js"
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "node"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "AnasDawod",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"jest": "^22.1.4",
|
||||
"nodemon": "^1.14.12",
|
||||
"swagger-autogen": "^2.22.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@comunica/actor-init-sparql": "^1.9.1",
|
||||
"@comunica/actor-init-sparql-file": "^1.9.1",
|
||||
"@comunica/actor-init-sparql-rdfjs": "^1.9.1",
|
||||
"aedes": "^0.42.5",
|
||||
"body-parser": "^1.18.2",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"elliptic": "^6.4.0",
|
||||
"express": "^4.16.2",
|
||||
"http": "0.0.0",
|
||||
"jsonld": "^1.7.0",
|
||||
"level": "^5.0.1",
|
||||
"level-browserify": "^2.0.0",
|
||||
"levelgraph": "^2.1.1",
|
||||
"lodash": "^4.17.11",
|
||||
"log4js": "^6.1.2",
|
||||
"morgan": "^1.9.1",
|
||||
"mosca": "^2.8.3",
|
||||
"mqtt": "^4.1.0",
|
||||
"multer": "^1.3.1",
|
||||
"n3": "^1.2.0",
|
||||
"sparql-engine": "^0.5.3",
|
||||
"stream": "^0.0.2",
|
||||
"swagger-ui-express": "^4.5.0",
|
||||
"uuid": "^3.2.1",
|
||||
"ws": "^4.0.0"
|
||||
}
|
||||
}
|
BIN
test/.DS_Store
vendored
Normal file
BIN
test/.DS_Store
vendored
Normal file
Binary file not shown.
49
test/N3/index.js
Normal file
49
test/N3/index.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
const N3 = require('n3');
|
||||
const newEngine = require('@comunica/actor-init-sparql-rdfjs').newEngine;
|
||||
const jsonld = require('jsonld');
|
||||
const N3Store = require('n3').Store;
|
||||
const DataFactory = require('n3').DataFactory;
|
||||
|
||||
|
||||
|
||||
const myEngine = newEngine();
|
||||
const parser = new N3.Parser();
|
||||
const store = new N3Store();
|
||||
|
||||
const doc = {
|
||||
"http://schema.org/name": "Manu Sporny",
|
||||
"http://schema.org/url": {"@id": "http://manu.sporny.org/"},
|
||||
"http://schema.org/image": {"@id": "http://manu.sporny.org/images/manu.png"}
|
||||
};
|
||||
|
||||
|
||||
jsonld.toRDF(doc, {format: 'application/n-quads'}, (err, nquads) => {
|
||||
// nquads is a string of N-Quads
|
||||
//console.log(nquads);
|
||||
|
||||
|
||||
parser.parse(
|
||||
nquads,
|
||||
(error, quad, prefixes) => {
|
||||
if (quad)
|
||||
//console.log(quad);
|
||||
store.addQuad(quad);
|
||||
else
|
||||
console.log(store);
|
||||
|
||||
const start = async function (a,b){
|
||||
const result = await myEngine.query('SELECT * { ?s ?p <http://manu.sporny.org/>. ?s ?p ?o} LIMIT 100',
|
||||
{ sources: [ { value: store } ] });
|
||||
//result.bindingsStream.on('data', (data) => {
|
||||
// Each data object contains a mapping from variables to RDFJS terms.
|
||||
console.log(result);
|
||||
// console.log(data.get('?p'));
|
||||
// console.log(data.get('?o'));
|
||||
// });
|
||||
};
|
||||
|
||||
start();
|
||||
});
|
||||
|
||||
|
||||
});
|
68
test/comunicaSPARQL/index.js
Normal file
68
test/comunicaSPARQL/index.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
const newEngine = require('@comunica/actor-init-sparql').newEngine;
|
||||
const N3 = require('n3');
|
||||
const jsonld = require('jsonld')
|
||||
const DataFactory = require('n3').DataFactory;
|
||||
const parser = new N3.Parser({format: 'application/n-quads'});
|
||||
|
||||
const store = new N3.Store();
|
||||
const myEngine = newEngine();
|
||||
|
||||
const doc = {
|
||||
"http://schema.org/name": "Manu Sporny",
|
||||
"http://schema.org/url": {"@id": "http://manu.sporny.org/"},
|
||||
"http://schema.org/image": {"@id": "http://manu.sporny.org/images/manu.png"}
|
||||
};
|
||||
|
||||
jsonld.toRDF(doc, {format: 'application/n-quads'}, (err, nquads) => {
|
||||
// nquads is a string of N-Quads
|
||||
// console.log(nquads);
|
||||
var quad= [];
|
||||
parser.parse(
|
||||
nquads,
|
||||
(error, quadN, prefixes) => {
|
||||
// console.log(quadN)
|
||||
if (quadN)
|
||||
{
|
||||
store.addQuad(DataFactory.quad(
|
||||
DataFactory.namedNode(quadN.subject.id), DataFactory.namedNode(quadN.predicate.id), DataFactory.namedNode(quadN.object.id)));
|
||||
|
||||
}
|
||||
else
|
||||
console.log("finished");
|
||||
// console.log(quadN)
|
||||
});
|
||||
|
||||
const start = async function (a,b){
|
||||
const result = await myEngine.query('SELECT * WHERE {?s ?p ?o } LIMIT 100',
|
||||
{ sources: [{ type: 'rdfjsSource', value: store}] })
|
||||
result.bindingsStream.on('data', (data) => console.log(data.toObject()));
|
||||
};
|
||||
start()
|
||||
console.log(quad)
|
||||
// store.addQuad(DataFactory.quad(
|
||||
// DataFactory.namedNode(quad.subject.id), DataFactory.namedNode(quad.predicate.id), DataFactory.namedNode(quad.object.id)));
|
||||
|
||||
|
||||
// store.addQuad(DataFactory.quad(
|
||||
// DataFactory.namedNode('http://schema.org/image'), DataFactory.namedNode('http://manu.sporny.org/images/manu.png'), DataFactory.namedNode('http://schema.org/name')));
|
||||
// store.addQuad(DataFactory.quad(
|
||||
// DataFactory.namedNode('http://schema.org/url'), DataFactory.namedNode('http://manu.sporny.org/'), DataFactory.namedNode('http://dbpedia.org/resource/Ghent')));
|
||||
//console.log(store)
|
||||
// const start = async function (a,b){
|
||||
// const result = await myEngine.query('SELECT * WHERE {?s ?p <http://manu.sporny.org/images/manu.png>. ?s ?p ?o } LIMIT 100',
|
||||
// { sources: [{ type: 'rdfjsSource', value: store}] })
|
||||
// result.bindingsStream.on('data', (data) => console.log(data.toObject()));
|
||||
// };
|
||||
// start()
|
||||
});
|
||||
|
||||
|
||||
// store.addQuad(DataFactory.quad(
|
||||
// DataFactory.namedNode('http://schema.org/image'), DataFactory.namedNode('http://manu.sporny.org/images/manu.png'), DataFactory.namedNode('http://schema.org/name')));
|
||||
// store.addQuad(DataFactory.quad(
|
||||
// DataFactory.namedNode('http://schema.org/url'), DataFactory.namedNode('http://manu.sporny.org/'), DataFactory.namedNode('http://dbpedia.org/resource/Ghent')));
|
||||
|
||||
// // console.log(store)
|
||||
|
||||
|
||||
|
20
test/jsonld/index.js
Normal file
20
test/jsonld/index.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const jsonld = require('jsonld');
|
||||
|
||||
const doc = {
|
||||
"http://schema.org/name": "Manu Sporny",
|
||||
"http://schema.org/url": {"@id": "http://manu.sporny.org/"},
|
||||
"http://schema.org/PrsnOwner": "0400985d4fca84fe0e8cff7e8902326a6703ba182cc8d6d8e20866b0acfc79ecb6bfd3d3b5d6ad7f48cd10fadc6d4348cab918f13db2ebb387ba16c57802bf47b1",
|
||||
|
||||
};
|
||||
|
||||
|
||||
jsonld.toRDF(doc, {format: 'application/n-quads'}, (err, nquads) => {
|
||||
// nquads is a string of N-Quads
|
||||
console.log(nquads);
|
||||
|
||||
});
|
||||
// const start = async function (a,b){
|
||||
// const rdf = await jsonld.toRDF(doc, {format: 'application/n-quads'});
|
||||
// console.log(rdf);
|
||||
// };
|
||||
// start();
|
78
test/sparqlEngine/index.js
Normal file
78
test/sparqlEngine/index.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
'use strict'
|
||||
|
||||
const { BindingBase, HashMapDataset, Graph, PlanBuilder } = require('sparql-engine')
|
||||
const level = require('level')
|
||||
const levelgraph = require('levelgraph')
|
||||
const { Transform } = require('stream')
|
||||
|
||||
// An utility class used to convert LevelGraph bindings
|
||||
// into a format undestood by sparql-engine
|
||||
class FormatterStream extends Transform {
|
||||
constructor () {
|
||||
super({objectMode: true})
|
||||
}
|
||||
|
||||
_transform (item, encoding, callback) {
|
||||
// Transform LevelGraph objects into set of mappings
|
||||
// using BindingBase.fromObject
|
||||
this.push(BindingBase.fromObject(item))
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
class LevelRDFGraph extends Graph {
|
||||
constructor (db) {
|
||||
super()
|
||||
this._db = db
|
||||
}
|
||||
|
||||
evalBGP (bgp) {
|
||||
// rewrite variables using levelgraph API
|
||||
bgp = bgp.map(t => {
|
||||
if (t.subject.startsWith('?')) {
|
||||
t.subject = this._db.v(t.subject.substring(1))
|
||||
}
|
||||
if (t.predicate.startsWith('?')) {
|
||||
t.predicate = this._db.v(t.predicate.substring(1))
|
||||
}
|
||||
if (t.object.startsWith('?')) {
|
||||
t.object = this._db.v(t.object.substring(1))
|
||||
}
|
||||
return t
|
||||
})
|
||||
// Transform the Stream returned by LevelGraph into an Stream of Bindings
|
||||
return new FormatterStream(this._db.searchStream(bgp))
|
||||
}
|
||||
}
|
||||
|
||||
const db = levelgraph(level('testing_db'))
|
||||
|
||||
// insert some triples
|
||||
var triple1 = { subject: 'http://example.org#a1', predicate: 'http://xmlns.com/foaf/0.1/name', object: '"c"' }
|
||||
var triple2 = { subject: 'http://example.org#a2', predicate: 'http://xmlns.com/foaf/0.1/name', object: '"d"' }
|
||||
db.put([triple1, triple2], () => {
|
||||
const graph = new LevelRDFGraph(db)
|
||||
const dataset = new HashMapDataset('http://example.org#default', graph)
|
||||
|
||||
const query = `
|
||||
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
|
||||
SELECT ?name
|
||||
WHERE {
|
||||
?s foaf:name ?name .
|
||||
}`
|
||||
|
||||
// Creates a plan builder for the RDF dataset
|
||||
const builder = new PlanBuilder(dataset)
|
||||
|
||||
// Get an iterator to evaluate the query
|
||||
const iterator = builder.build(query)
|
||||
|
||||
// Read results
|
||||
iterator.subscribe(bindings => {
|
||||
console.log('Find solutions:', bindings.toObject())
|
||||
}, err => {
|
||||
console.error('error', err)
|
||||
}, () => {
|
||||
console.log('Query evaluation complete!')
|
||||
})
|
||||
})
|
BIN
wallet/.DS_Store
vendored
Normal file
BIN
wallet/.DS_Store
vendored
Normal file
Binary file not shown.
67
wallet/CoinTransaction.js
Normal file
67
wallet/CoinTransaction.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
const ChainUtil = require('../chain-util');
|
||||
const { MINING_REWARD } = require('../config');
|
||||
|
||||
class CoinTransaction {
|
||||
constructor() {
|
||||
this.id = ChainUtil.id();
|
||||
this.input = null;
|
||||
this.outputs = [];
|
||||
}
|
||||
|
||||
update(senderWallet, recipient, amount) {
|
||||
const senderOutput = this.outputs.find(output => output.address === senderWallet.publicKey);
|
||||
if (amount > senderOutput.amount) {
|
||||
console.log(`Amount: ${amount} exceeds balance.`);
|
||||
return;
|
||||
}
|
||||
|
||||
senderOutput.amount = senderOutput.amount - amount;
|
||||
this.outputs.push({ amount, address: recipient });
|
||||
CoinTransaction.signCoinTransaction(this, senderWallet);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
static CoinTransactionWithOutputs(senderWallet, outputs) {
|
||||
const cointransaction = new this();
|
||||
cointransaction.outputs.push(...outputs);
|
||||
CoinTransaction.signCoinTransaction(cointransaction, senderWallet);
|
||||
return cointransaction;
|
||||
}
|
||||
|
||||
static newCoinTransaction(senderWallet, recipient, amount) {
|
||||
if (amount > senderWallet.balance) {
|
||||
console.log(`Amount: ${amount} exceeds balance.`);
|
||||
return;
|
||||
}
|
||||
|
||||
return CoinTransaction.CoinTransactionWithOutputs(senderWallet, [
|
||||
{ amount: senderWallet.balance - amount, address: senderWallet.publicKey},
|
||||
{ amount, address: recipient }]);
|
||||
}
|
||||
|
||||
static rewardCoinTransaction(minerWallet, blockchainWallet) {
|
||||
return CoinTransaction.CoinTransactionWithOutputs(blockchainWallet, [{
|
||||
amount: MINING_REWARD, address: minerWallet.publicKey
|
||||
}]);
|
||||
}
|
||||
|
||||
static signCoinTransaction(cointransaction, senderWallet) {
|
||||
cointransaction.input = {
|
||||
timestamp: Date.now(),
|
||||
amount: senderWallet.balance,
|
||||
address: senderWallet.publicKey,
|
||||
signature: senderWallet.sign(ChainUtil.hash(cointransaction.outputs))
|
||||
}
|
||||
}
|
||||
|
||||
static verifyCoinTransaction(cointransaction) {
|
||||
return ChainUtil.verifySignature(
|
||||
cointransaction.input.address,
|
||||
cointransaction.input.signature,
|
||||
ChainUtil.hash(cointransaction.outputs)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CoinTransaction;
|
100
wallet/MetaDataTransaction.js
Normal file
100
wallet/MetaDataTransaction.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
const ChainUtil = require('../chain-util');
|
||||
|
||||
class MetaDataTransaction {
|
||||
constructor() {
|
||||
this.id = null; // if there is a problem in the metadata transaction, change null with ChainUtil.id();
|
||||
this.Signiture = null;
|
||||
this.Name = null;
|
||||
this.Geo = [];
|
||||
this.IP_URL = null;
|
||||
this.Topic_Token = null;
|
||||
this.Permission = null;
|
||||
this.RequestDetail = null;
|
||||
this.OrgOwner = null;
|
||||
this.DepOwner = null;
|
||||
this.PrsnOwner = null;
|
||||
this.MetaHash = null;
|
||||
this.PaymentPerKbyte = null;
|
||||
this.PaymentPerMinute = null;
|
||||
this.Protocol = null;
|
||||
this.MessageAttributes= {};
|
||||
this.Interval = null;
|
||||
this.FurtherDetails = null;
|
||||
this.SSNmetadata = null;
|
||||
|
||||
// this.Geo = null;
|
||||
// this.Std = null;
|
||||
// this.name= null;
|
||||
// this.MetaHash= null;
|
||||
// this.file=null;
|
||||
}
|
||||
|
||||
// update(senderWallet, Geo, URI, Name,Permission, OrgOwner, SSNmetadata) {
|
||||
|
||||
// this.Geo = Geo;
|
||||
// this.URI = URI;
|
||||
// this.Name = Name;
|
||||
// this.Permission = Permission;
|
||||
// this.OrgOwner = OrgOwner;
|
||||
// this.PrsnOwner = senderWallet.publicKey;
|
||||
// this.MetaHash = ChainUtil.hash(SSNmetadata);
|
||||
// this.SSNmetadata = SSNmetadata;
|
||||
|
||||
// MetaDatatransaction.signMetaDataTransaction(this, senderWallet);
|
||||
|
||||
// return this;
|
||||
// }
|
||||
|
||||
static MetaDataTransactionWithIoT(senderWallet, Name,Geo ,IP_URL , Topic_Token, Permission, RequestDetail, OrgOwner, DepOwner,PrsnOwner, PaymentPerKbyte, PaymentPerMinute, Protocol, MessageAttributes, Intrval, FurtherDetails, SSNmetadata) {
|
||||
const metaDataTransaction = new this();
|
||||
metaDataTransaction.id = ChainUtil.id();
|
||||
metaDataTransaction.Name = Name;
|
||||
metaDataTransaction.Geo = Geo;
|
||||
metaDataTransaction.IP_URL = IP_URL;
|
||||
metaDataTransaction.Topic_Token = Topic_Token;
|
||||
metaDataTransaction.Permission = Permission;
|
||||
metaDataTransaction.RequestDetail = RequestDetail
|
||||
metaDataTransaction.OrgOwner = OrgOwner;
|
||||
metaDataTransaction.DepOwner = DepOwner;
|
||||
metaDataTransaction.PrsnOwner = PrsnOwner;
|
||||
metaDataTransaction.PaymentPerKbyte = PaymentPerKbyte ;
|
||||
metaDataTransaction.PaymentPerMinute = PaymentPerMinute;
|
||||
metaDataTransaction.Protocol = Protocol;
|
||||
metaDataTransaction.MessageAttributes = MessageAttributes;
|
||||
metaDataTransaction.MessageAttributes['DeviceID'] = metaDataTransaction.id;
|
||||
metaDataTransaction.MessageAttributes['DeviceName'] = Name;
|
||||
metaDataTransaction.MessageAttributes['Sensors'] =[{"SensorName":"","Value":"" , "Unit":""}];
|
||||
metaDataTransaction.MessageAttributes['TimeStamp'] = "";
|
||||
metaDataTransaction.Interval = Intrval;
|
||||
metaDataTransaction.FurtherDetails = FurtherDetails;
|
||||
metaDataTransaction.SSNmetadata = SSNmetadata;
|
||||
metaDataTransaction.MetaHash = ChainUtil.hash(SSNmetadata);
|
||||
MetaDataTransaction.signMetaDataTransaction(metaDataTransaction, senderWallet);
|
||||
return metaDataTransaction;
|
||||
}
|
||||
|
||||
|
||||
static newMetaDataTransaction(senderWallet,Name,Geo ,IP_URL , Topic_Token, Permission, RequestDetail, OrgOwner, DepOwner,PrsnOwner, PaymentPerKbyte, PaymentPerMinute, Protocol, MessageAttributes, Interval, FurtherDetails, SSNmetadata){
|
||||
return MetaDataTransaction.MetaDataTransactionWithIoT(senderWallet, Name,Geo ,IP_URL , Topic_Token, Permission, RequestDetail, OrgOwner, DepOwner,PrsnOwner, PaymentPerKbyte, PaymentPerMinute, Protocol, MessageAttributes, Interval, FurtherDetails, SSNmetadata
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
static signMetaDataTransaction (metaDataTransaction, senderWallet) {
|
||||
metaDataTransaction.Signiture = {
|
||||
timestamp: Date.now(),
|
||||
address: senderWallet.publicKey,
|
||||
signature: senderWallet.sign(ChainUtil.hash(metaDataTransaction.SSNmetadata))
|
||||
}
|
||||
}
|
||||
|
||||
static verifyMetaDataTransaction(metaDataTransaction) {
|
||||
return ChainUtil.verifySignature(
|
||||
metaDataTransaction.Signiture.address,
|
||||
metaDataTransaction.Signiture.signature,
|
||||
ChainUtil.hash(metaDataTransaction.SSNmetadata)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
module.exports = MetaDataTransaction;
|
99
wallet/index.js
Normal file
99
wallet/index.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
const ChainUtil = require('../chain-util');
|
||||
const CoinTransaction = require('./CoinTransaction');
|
||||
const { INITIAL_BALANCE } = require('../config');
|
||||
const MetaDataTransaction = require('./MetaDataTransaction');
|
||||
const transactionPool = require('./transaction-pool');
|
||||
|
||||
class Wallet {
|
||||
constructor() {
|
||||
this.balance = INITIAL_BALANCE;
|
||||
this.keyPair = ChainUtil.genKeyPair();
|
||||
this.publicKey = this.keyPair.getPublic().encode('hex');
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `Wallet -
|
||||
publicKey: ${this.publicKey.toString()}
|
||||
balance : ${this.balance}`
|
||||
}
|
||||
|
||||
sign(dataHash) {
|
||||
return this.keyPair.sign(dataHash);
|
||||
}
|
||||
|
||||
createCoinTransaction(recipient, amount, blockchain, transactionPool) {
|
||||
// this.balance = this.calculateBalance(blockchain);
|
||||
|
||||
if (amount > this.balance) {
|
||||
console.log(`Amount: ${amount} exceceds current balance: ${this.balance}`);
|
||||
return;
|
||||
}
|
||||
|
||||
let cointransaction = transactionPool.existingPaymentTransaction(this.publicKey);
|
||||
|
||||
|
||||
if (cointransaction) {
|
||||
cointransaction.update(this, recipient, amount);
|
||||
} else { //this should be the original one
|
||||
//just for test i make the transaction not to update if the sender is the same
|
||||
cointransaction = CoinTransaction.newCoinTransaction(this, recipient, amount);
|
||||
transactionPool.updateOrAddPaymentTransaction(cointransaction);
|
||||
}
|
||||
|
||||
return cointransaction;
|
||||
}
|
||||
createMetaDataTransaction(Name,Geo ,IP_URL , Topic_Token, Permission, RequestDetail, OrgOwner, DepOwner,PrsnOwner, PaymentPerKbyte, PaymentPerMinute, Protocol, MessageAttributes, Interval, FurtherDetails, SSNmetadata, transactionPool){
|
||||
/* let metaData = metaDataPool.existingMetaData(this.publicKey);
|
||||
|
||||
if (metaData) {
|
||||
metaData.update(this, Geo, Std, Name,MetaHash,file);
|
||||
} else {*/
|
||||
|
||||
const metaDataTransaction= MetaDataTransaction.newMetaDataTransaction(this, Name,Geo ,IP_URL , Topic_Token, Permission, RequestDetail, OrgOwner, DepOwner,PrsnOwner, PaymentPerKbyte, PaymentPerMinute, Protocol, MessageAttributes,Interval, FurtherDetails, SSNmetadata);
|
||||
transactionPool.updateOrAddMetaDataTransaction(metaDataTransaction);
|
||||
//}
|
||||
return metaDataTransaction;
|
||||
}
|
||||
|
||||
calculateBalance(blockchain) {
|
||||
let balance = this.balance;
|
||||
let cointransactions = [];
|
||||
blockchain.chain.forEach(block => block.data.forEach(cointransaction => {
|
||||
cointransactions.push(cointransaction);
|
||||
}));
|
||||
|
||||
const walletInputTs = cointransactions
|
||||
.filter(cointransaction => cointransaction.input.address === this.publicKey);
|
||||
|
||||
let startTime = 0;
|
||||
|
||||
if (walletInputTs.length > 0) {
|
||||
const recentInputT = walletInputTs.reduce(
|
||||
(prev, current) => prev.input.timestamp > current.input.timestamp ? prev : current
|
||||
);
|
||||
|
||||
balance = recentInputT.outputs.find(output => output.address === this.publicKey).amount;
|
||||
startTime = recentInputT.input.timestamp;
|
||||
}
|
||||
|
||||
cointransactions.forEach(cointransaction => {
|
||||
if (cointransaction.input.timestamp > startTime) {
|
||||
cointransaction.outputs.find(output => {
|
||||
if (output.address === this.publicKey) {
|
||||
balance += output.amount;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return balance;
|
||||
}
|
||||
|
||||
static blockchainWallet() {
|
||||
const blockchainWallet = new this();
|
||||
blockchainWallet.address = 'blockchain-wallet';
|
||||
return blockchainWallet;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Wallet;
|
90
wallet/index.test.js
Normal file
90
wallet/index.test.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
const Wallet = require('./index');
|
||||
const TransactionPool = require('./transaction-pool');
|
||||
const Blockchain = require('../blockchain');
|
||||
const { INITIAL_BALANCE } = require('../config');
|
||||
|
||||
describe('Wallet', () => {
|
||||
let wallet, tp, bc;
|
||||
|
||||
beforeEach(() => {
|
||||
wallet = new Wallet();
|
||||
tp = new TransactionPool();
|
||||
bc = new Blockchain();
|
||||
});
|
||||
|
||||
describe('creating a transaction', () => {
|
||||
let transaction, sendAmount, recipient;
|
||||
|
||||
beforeEach(() => {
|
||||
sendAmount = 50;
|
||||
recipient = 'r4nd0m-4ddr355';
|
||||
Geo = 20;
|
||||
Std = 9014;
|
||||
Name = 'temp';
|
||||
MetaHash = '123abcd';
|
||||
transaction = wallet.createCoinTransaction(recipient, sendAmount,Geo, Std, Name,MetaHash, bc, tp);
|
||||
});
|
||||
|
||||
describe('and doing the same transaction', () => {
|
||||
beforeEach(() => {
|
||||
wallet.createCoinTransaction(recipient, sendAmount,Geo, Std, Name,MetaHash, bc, tp);
|
||||
});
|
||||
|
||||
it('doubles the `sendAmount` subtracted from the wallet balance', () => {
|
||||
expect(transaction.outputs.find(output => output.address === wallet.publicKey).amount)
|
||||
.toEqual(wallet.balance - sendAmount * 2);
|
||||
});
|
||||
|
||||
it('clones the `sendAmount` output for the recipient', () => {
|
||||
expect(transaction.outputs.filter(output => output.address === recipient)
|
||||
.map(output => output.amount)).toEqual([sendAmount, sendAmount]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculating a balance', () => {
|
||||
let addBalance, repeatAdd, senderWallet;
|
||||
|
||||
beforeEach(() => {
|
||||
senderWallet = new Wallet();
|
||||
addBalance = 100;
|
||||
repeatAdd = 3;
|
||||
for (let i=0; i<repeatAdd; i++) {
|
||||
senderWallet.createCoinTransaction(wallet.publicKey, addBalance,Geo, Std, Name,MetaHash, bc, tp);
|
||||
}
|
||||
bc.addBlock(tp.paymenttransactions);
|
||||
});
|
||||
|
||||
it('calculates the balance for blockchain transactions matching the recipient', () => {
|
||||
expect(wallet.calculateBalance(bc)).toEqual(INITIAL_BALANCE + (addBalance * repeatAdd));
|
||||
});
|
||||
|
||||
it('calculates the balance for blockchain transactions matching the sender', () => {
|
||||
expect(senderWallet.calculateBalance(bc)).toEqual(INITIAL_BALANCE - (addBalance * repeatAdd));
|
||||
});
|
||||
|
||||
describe('and the recipient conducts a transaction', () => {
|
||||
let subtractBalance, recipientBalance;
|
||||
|
||||
beforeEach(() => {
|
||||
tp.clear();
|
||||
subtractBalance = 60;
|
||||
recipientBalance = wallet.calculateBalance(bc);
|
||||
wallet.createCoinTransaction(senderWallet.publicKey, subtractBalance,20,9014,'temp','123abc', bc, tp);
|
||||
bc.addBlock(tp.paymenttransactions);
|
||||
});
|
||||
|
||||
describe('and the sender sends another transaction to the recipient', () => {
|
||||
beforeEach(() => {
|
||||
tp.clear();
|
||||
senderWallet.createCoinTransaction(wallet.publicKey, addBalance, 20,9014,'temp','123abc',bc, tp);
|
||||
bc.addBlock(tp.paymenttransactions);
|
||||
});
|
||||
|
||||
it('calculate the recipient balance only using transactions since its most recent one', () => {
|
||||
expect(wallet.calculateBalance(bc)).toEqual(recipientBalance - subtractBalance + addBalance);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
118
wallet/transaction-pool.js
Normal file
118
wallet/transaction-pool.js
Normal file
|
@ -0,0 +1,118 @@
|
|||
const PaymntTransaction = require('./CoinTransaction');
|
||||
const MetaDataTransaction = require('./MetaDataTransaction');
|
||||
//const CompTransaction = require('./CompTransaction');
|
||||
//const IntegrationTransaction = require('./IntegrationTransaction');
|
||||
const { MaxNumOfPaymentTransactions, MaxNumOfMetadataTransactions,
|
||||
MaxNumOfCompTransactions, MaxNumOfIntegrationTransactions}
|
||||
= require('../config');
|
||||
class TransactionPool {
|
||||
constructor() {
|
||||
this.paymenttransactions = [];
|
||||
this.metaDataTransactions =[];
|
||||
this.comptransactions = [];
|
||||
this.integrationTransactions =[];
|
||||
}
|
||||
updateOrAddPaymentTransaction(paymenttransaction) {
|
||||
let paymenttransactionWithId = this.paymenttransactions.find(t =>
|
||||
t.id === paymenttransaction.id);
|
||||
if (paymenttransactionWithId) {
|
||||
this.paymenttransactions[this.paymenttransactions.indexOf
|
||||
(paymenttransactionWithId)] = paymenttransaction;
|
||||
} else {
|
||||
this.paymenttransactions.push(paymenttransaction);
|
||||
}
|
||||
}
|
||||
updateOrAddMetaDataTransaction(metaDataTransaction) {
|
||||
let metaDataTransactionWithId = this.metaDataTransactions.find(t =>
|
||||
t.id === metaDataTransaction.id);
|
||||
if (metaDataTransactionWithId) {
|
||||
this.metaDataTransactions[this.metaDataTransactions.indexOf
|
||||
(metaDataTransactionWithId)] = metaDataTransaction;
|
||||
} else {
|
||||
this.metaDataTransactions.push(metaDataTransaction);
|
||||
}
|
||||
}
|
||||
updateOrAddCompTransaction(comptransaction) {
|
||||
let comptransactionWithId = this.comptransactions.find(t =>
|
||||
t.id === comptransaction.id);
|
||||
if (comptransactionWithId) {
|
||||
this.comptransactions[this.comptransactions.indexOf
|
||||
(comptransactionWithId)] = comptransaction;
|
||||
} else {
|
||||
this.comptransactions.push(comptransaction);
|
||||
} }
|
||||
updateOrAddIntegrationTransaction(integrationTransaction) {
|
||||
let integrationTransactionWithId = this.integrationTransaction.find(
|
||||
t => t.id === integrationTransaction.id);
|
||||
if (integrationTransactionWithId) {
|
||||
this.integrationTransactions[this.integrationTransactions.indexOf
|
||||
(integrationTransactionWithId)] = integrationTransaction;
|
||||
} else {
|
||||
this.integrationTransactions.push(integrationTransaction);
|
||||
}
|
||||
}
|
||||
existingPaymentTransaction(address) {
|
||||
return this.paymenttransactions.find(t =>
|
||||
t.input.address === address); }
|
||||
existingMetaDataTransaction(address) {
|
||||
return this.metaDataTransactions.find(t =>
|
||||
t.Signiture.address === address);}
|
||||
existingCompTransaction(address) {
|
||||
return this.comptransactions.find(t =>
|
||||
t.input.address === address); }
|
||||
existingIntegrationTransaction(address) {
|
||||
return this.integrationTransactions.find(t =>
|
||||
t.Signiture.address === address);}
|
||||
validPaymentTransactions() {
|
||||
return this.paymenttransactions.filter(paymenttransaction => {
|
||||
const outputTotal = paymenttransaction.outputs.reduce(
|
||||
(total, output) => {
|
||||
return total + output.amount;
|
||||
}, 0);
|
||||
if (paymenttransaction.input.amount !== outputTotal) {
|
||||
console.log(`Invalid transaction from
|
||||
${paymenttransaction.input.address}.`);
|
||||
return;}
|
||||
if (!PaymentTransaction.verifyPaymentTransaction(
|
||||
paymenttransaction)) {
|
||||
console.log(`Invalid signature from
|
||||
${paymenttransaction.input.address}.`);
|
||||
return;}
|
||||
return paymenttransaction;
|
||||
});
|
||||
}
|
||||
validMetaDataTransactions(){
|
||||
if (!MetaDataTransaction.verifyMetaDataTransaction(
|
||||
metaDataTransaction)) {
|
||||
console.log(`Invalid signature from
|
||||
${metaDataTransaction.Signiture.address}.`);
|
||||
return;
|
||||
}
|
||||
return metaDataTransaction;
|
||||
}
|
||||
validCompTransactions(){
|
||||
if (!CompTransaction.verifyCompTransaction(
|
||||
CompTransaction)) {
|
||||
console.log(`Invalid signature from
|
||||
${CompTransaction.Signiture.address}.`);
|
||||
return;
|
||||
}
|
||||
return compTransaction;
|
||||
}
|
||||
validIntegrationTransactions(){
|
||||
if (!IntegrationTransaction.verifyIntegrationTransaction(
|
||||
integrationTransaction)) {
|
||||
console.log(`Invalid signature from
|
||||
${integrationTransaction.Signiture.address}.`);
|
||||
return;
|
||||
}
|
||||
return integrationTransaction;
|
||||
}
|
||||
clearAll() {
|
||||
this.cointransactions = [];
|
||||
this.metaDataTransactions = [];
|
||||
this.comptransactions = [];
|
||||
this.integrationTransactions = [];
|
||||
}
|
||||
}
|
||||
module.exports = TransactionPool;
|
58
wallet/transaction-pool.test.js
Normal file
58
wallet/transaction-pool.test.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
const TransactionPool = require('./transaction-pool');
|
||||
const Transaction = require('./Cointransaction');
|
||||
const Wallet = require('./index');
|
||||
const Blockchain = require('../blockchain');
|
||||
|
||||
describe('TransactionPool', () => {
|
||||
let tp, wallet, transaction, bc;
|
||||
|
||||
beforeEach(() => {
|
||||
tp = new TransactionPool();
|
||||
wallet = new Wallet();
|
||||
bc = new Blockchain();
|
||||
transaction = wallet.createCoinTransaction('r4nd-4dr355', 30,20,9014,'temp','123abc', bc, tp);
|
||||
});
|
||||
|
||||
it('adds a transaction to the pool', () => {
|
||||
expect(tp.paymenttransactions.find(t => t.id === transaction.id)).toEqual(transaction);
|
||||
});
|
||||
|
||||
it('updates a transaction in the pool', () => {
|
||||
const oldTransaction = JSON.stringify(transaction);
|
||||
const newTransaction = transaction.update(wallet, 'foo-4ddr355', 40,20,9014,'temp','123abc');
|
||||
tp.updateOrAddPaymentTransaction(newTransaction);
|
||||
|
||||
expect(JSON.stringify(tp.paymenttransactions.find(t => t.id === newTransaction.id)))
|
||||
.not.toEqual(oldTransaction);
|
||||
});
|
||||
|
||||
it('clears transactions', () => {
|
||||
tp.clear();
|
||||
expect(tp.paymenttransactions).toEqual([]);
|
||||
});
|
||||
|
||||
describe('mixing valid and corrupt transactions', () => {
|
||||
let validTransactions;
|
||||
|
||||
beforeEach(() => {
|
||||
validTransactions = [...tp.paymenttransactions];
|
||||
for (let i=0; i<6; i++) {
|
||||
wallet = new Wallet();
|
||||
transaction = wallet.createCoinTransaction('r4nd-4dr355', 30,20,9014,'temp','123abc', bc, tp);
|
||||
if (i%2==0) {
|
||||
transaction.input.amount = 99999;
|
||||
} else {
|
||||
validTransactions.push(transaction);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('shows a difference between valid and corrupt transactions', () => {
|
||||
expect(JSON.stringify(tp.paymenttransactions)).not.toEqual(JSON.stringify(validTransactions));
|
||||
});
|
||||
|
||||
it('grabs valid transactions', () => {
|
||||
expect(tp.validTransactions()).toEqual(validTransactions);
|
||||
});
|
||||
});
|
||||
});
|
79
wallet/transaction.test.js
Normal file
79
wallet/transaction.test.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
const Transaction = require('./Cointransaction');
|
||||
const Wallet = require('./index');
|
||||
const { MINING_REWARD } = require('../config');
|
||||
|
||||
describe('Transaction', () => {
|
||||
let transaction, wallet, recipient, amount;
|
||||
|
||||
beforeEach(() => {
|
||||
wallet = new Wallet();
|
||||
amount = 50;
|
||||
recipient = 'r3c1p13nt';
|
||||
transaction = Transaction.newTransaction(wallet, recipient, amount);
|
||||
});
|
||||
|
||||
it('outputs the `amount` subtracted from the wallet balance', () => {
|
||||
expect(transaction.outputs.find(output => output.address === wallet.publicKey).amount)
|
||||
.toEqual(wallet.balance - amount);
|
||||
});
|
||||
|
||||
it('outputs the `amount` added to the recipient', () => {
|
||||
expect(transaction.outputs.find(output => output.address === recipient).amount)
|
||||
.toEqual(amount);
|
||||
});
|
||||
|
||||
it('inputs the balance of the wallet', () => {
|
||||
expect(transaction.input.amount).toEqual(wallet.balance);
|
||||
});
|
||||
|
||||
it('validates a valid transaction', () => {
|
||||
expect(Transaction.verifyTransaction(transaction)).toBe(true);
|
||||
});
|
||||
|
||||
it('invalidates a corrupt transaction', () => {
|
||||
transaction.outputs[0].amount = 50000;
|
||||
expect(Transaction.verifyTransaction(transaction)).toBe(false);
|
||||
});
|
||||
|
||||
describe('transacting with an amount that exceeds the balance', () => {
|
||||
beforeEach(() => {
|
||||
amount = 50000;
|
||||
transaction = Transaction.newTransaction(wallet, recipient, amount);
|
||||
});
|
||||
|
||||
it('does not create the transaction', () => {
|
||||
expect(transaction).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('and updating a transaction', () => {
|
||||
let nextAmount, nextRecipient;
|
||||
|
||||
beforeEach(() => {
|
||||
nextAmount = 20;
|
||||
nextRecipient = 'n3xt-4ddr355';
|
||||
transaction = transaction.update(wallet, nextRecipient, nextAmount);
|
||||
});
|
||||
|
||||
it(`subtracts the next amount from the sender's output`, () => {
|
||||
expect(transaction.outputs.find(output => output.address === wallet.publicKey).amount)
|
||||
.toEqual(wallet.balance - amount - nextAmount);
|
||||
});
|
||||
|
||||
it('outputs an amount for the next recipient', () => {
|
||||
expect(transaction.outputs.find(output => output.address === nextRecipient).amount)
|
||||
.toEqual(nextAmount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('creating a reward transaction', () => {
|
||||
beforeEach(() => {
|
||||
transaction = Transaction.rewardTransaction(wallet, Wallet.blockchainWallet());
|
||||
});
|
||||
|
||||
it(`reward the miner's wallet`, () => {
|
||||
expect(transaction.outputs.find(output => output.address === wallet.publicKey).amount)
|
||||
.toEqual(MINING_REWARD);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue