reorg code, integration publish/subscribe working, still some TODOs

This commit is contained in:
Josip Milovac 2023-02-01 13:01:51 +11:00
parent 043a95d9ef
commit 1af6d56e2d
35 changed files with 3052 additions and 1401 deletions

View file

@ -1,92 +0,0 @@
const Transaction = require('./transaction');
const { INITIAL_BALANCE } = require('../config');
const Metadata = require('./metadata');
const ChainUtil = require('../chain-util');
class Wallet {
constructor(keyPair) {
this.keyPair = keyPair;
this.publicKey = this.keyPair.getPublic().encode('hex');
this.counter = 0;
}
toString() {
return `Wallet -
publicKey: ${this.publicKey.toString()}
balance : ${this.balance}`
}
sign(dataHash) {
return this.keyPair.sign(dataHash);
}
createTransaction(recipient, amount, blockchain) {
const balance = blockchain.getBalanceCopy(this.publicKey);
if (balance.counter > this.counter) {
this.counter = balance.counter;
}
if (amount > balance.balance) {
console.log(`Amount: ${amount} exceceds current balance: ${balance.balance}`);
return null;
}
const counterToUse = this.counter + 1;
this.counter++;
const newTransaction = new Transaction(this.publicKey, counterToUse, [Transaction.createOutput(recipient, amount)]);
newTransaction.addSignature(this.sign(Transaction.hashToSign(newTransaction)));
return newTransaction;
}
createMetadata(SSNmetadata) {
return Metadata.newMetadata(this, SSNmetadata);
}
//calculateBalance(blockchain) {
// let balance = this.balance;
// let transactions = [];
// blockchain.chain.forEach(block => block.data.forEach(transaction => {
// transactions.push(transaction);
// }));
// console.log("transactions of balance")
// console.log(transactions);
// const PaymentTransactions = transactions[0];
// console.log("Payment transactions ")
// console.log(PaymentTransactions);
// const walletInputTs = PaymentTransactions.filter(transaction => transaction.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;
// }
// PaymentTransactions.forEach(transaction => {
// if (transaction.input.timestamp > startTime) {
// transaction.outputs.find(output => {
// if (output.address === this.publicKey) {
// balance += output.amount;
// }
// });
// }
// });
// return balance;
//}
//static blockchainWallet() {
// const blockchainWallet = new this(ChainUtil.genKeyPair());
// blockchainWallet.address = 'blockchain-wallet';
// return blockchainWallet;
//}
}
module.exports = Wallet;

View file

@ -1,86 +0,0 @@
const ChainUtil = require('../chain-util');
class Metadata {
constructor() {
this.id = null;
this.Signiture = null;
// this.Name = null;
// this.Geo = null;
// this.GeospatialLocation = [];
// this.Owenership = null;
// this.Cost = null;
// this.Identifications = null;
// this.Integration = null;
// 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;
}
static MetadataOfIoTDevice(senderWallet, SSNmetadata) {
const metadata = new this();
metadata.id = ChainUtil.id();
// metadata.Name = Name;
// metadata.Geo = Geo;
// metadata.IP_URL = IP_URL;
// metadata.Topic_Token = Topic_Token;
// metadata.Permission = Permission;
// metadata.RequestDetail = RequestDetail
// metadata.OrgOwner = OrgOwner;
// metadata.DepOwner = DepOwner;
// metadata.PrsnOwner = PrsnOwner;
// metadata.PaymentPerKbyte = PaymentPerKbyte ;
// metadata.PaymentPerMinute = PaymentPerMinute;
// metadata.Protocol = Protocol;
// metadata.MessageAttributes = MessageAttributes;
// metadata.MessageAttributes['DeviceID'] = metadata.id;
// metadata.MessageAttributes['DeviceName'] = Name;
// metadata.MessageAttributes['Sensors'] =[{"SensorName":"","Value":"" , "Unit":""}];
// metadata.MessageAttributes['TimeStamp'] = "";
// metadata.Interval = Intrval;
// metadata.FurtherDetails = FurtherDetails;
metadata.SSNmetadata = SSNmetadata;
metadata.MetaHash = ChainUtil.hash(SSNmetadata);
Metadata.signMetadata(metadata, senderWallet);
return metadata;
}
static newMetadata(senderWallet,SSNmetadata){
return Metadata.MetadataOfIoTDevice(senderWallet, SSNmetadata);
}
static signMetadata (metadata, senderWallet) {
metadata.Signiture = {
timestamp: Date.now(),
address: senderWallet.publicKey,
signature: senderWallet.sign(ChainUtil.hash(metadata.SSNmetadata))
}
}
static verifyMetadata(metadata) {
return ChainUtil.verifySignature(
metadata.Signiture.address,
metadata.Signiture.signature,
ChainUtil.hash(metadata.SSNmetadata)
);
}
}
module.exports = Metadata;

View file

@ -1,109 +0,0 @@
const Transaction = require('./transaction');
const Metadata = require('./metadata');
const Wallet = require('./index');
const { MINING_REWARD } = require('../config');
describe('Transaction & Metadata', () => {
let transaction, metadata, wallet, recipient, amount,
senderWallet,Name,Geo ,IP_URL , Topic_Token, Permission,
RequestDetail, OrgOwner, DepOwner,PrsnOwner, PaymentPerKbyte,
PaymentPerMinute, Protocol, MessageAttributes, Interval,
FurtherDetails, SSNmetadata;
beforeEach(() => {
wallet = new Wallet();
amount = 50;
recipient = 'r3c1p13nt';
senderWallet = new Wallet();
Name = 'IoT_Lab_Temp_Sensor'
Geo = [1.045,0.0135]
IP_URL = 'www.IoT-locationbar.com/sensors/temp'
Topic_Token = 'ACCESS_TOKEN'
Permission = 'Public'
RequestDetail = 'Null'
OrgOwner = 'Swinburne_University'
DepOwner = 'Computer_Science'
PrsnOwner = 'Anas_Dawod'
PaymentPerKbyte = 10
PaymentPerMinute = 5
Protocol = 'MQTT'
MessageAttributes = 'null'
Interval = 10
FurtherDetails = 'null'
SSNmetadata = 'null'
transaction = Transaction.newTransaction(wallet, recipient, amount);
metadata = Metadata.newMetadata(senderWallet,Name,Geo ,IP_URL , Topic_Token, Permission,
RequestDetail, OrgOwner, DepOwner,PrsnOwner, PaymentPerKbyte,
PaymentPerMinute, Protocol, MessageAttributes, Interval,
FurtherDetails, SSNmetadata)
});
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('validates a valid metadata', () => {
expect(Metadata.verifyMetadata(metadata)).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);
});
});
});

View file

@ -1,95 +0,0 @@
const Transaction = require('../wallet/transaction');
const Metadata = require('../wallet/metadata');
const Block = require('../blockchain/block');
const Return = {
add: 1,
update: 2,
error: 3
};
class TransactionPool {
constructor() {
this.transactions = [];
this.metadatas = [];
}
//returns true on update, false on add
updateOrAddTransaction(transaction) {
if (!Transaction.verify(transaction)) {
console.log("Couldn't update or add transaction, transaction couldn't be verified");
return Return.error;
}
const foundIndex = this.transactions.findIndex(t => t.input === transaction.input && t.counter === transaction.counter);
if (foundIndex !== -1) {
this.transactions[foundIndex] = transaction;
return Return.update;
} else {
this.transactions.push(transaction);
return Return.add;
}
}
updateOrAddMetadata(metadata) {
if (!Metadata.verifyMetadata(metadata)) {
console.log("Couldn't update metdata, metadata couldn't be verified");
return Return.error;
}
const foundIndex = this.metadatas.findIndex(t => t.id === metadata.id);
if (foundIndex !== -1) {
this.metadatas[foundIndex] = metadata;
return Return.update;
} else {
this.metadatas.push(metadata);
return Return.add;
}
}
existingTransaction(address) {
return this.transactions.find(t => t.input.address === address);
}
existingMetadata(address) {
return this.metadatas.find(t => t.Signiture.address === address);
}
//we could check for possible double spends here
validTransactionsCopy() {
return [...this.transactions];
}
validMetadatasCopy(){
return [...this.metadatas];
}
clearFromBlock(block) {
const blockTransactions = Block.getTransactions(block);
const blockMetadatas = Block.getMetadatas(block);
for (const transaction of blockTransactions) {
const foundTransaction = this.transactions.findIndex(t => t.id === transaction.id);
if (foundTransaction !== -1) {
this.transactions.splice(foundTransaction, 1);
}
}
for (const metadata of blockMetadatas) {
const foundMetadata = this.metadatas.findIndex(m => m.id === metadata.id);
if (foundMetadata !== -1) {
this.metadatas.splice(foundMetadata, 1);
}
}
}
clearAll() {
this.transactions = [];
this.metadatas = [];
}
}
module.exports = TransactionPool;
module.exports.Return = Return;

View file

@ -1,86 +0,0 @@
const TransactionPool = require('./transaction-pool');
const Transaction = require('./transaction');
const Metadata = require('./metadata')
const Wallet = require('./index');
const Blockchain = require('../blockchain');
describe('TransactionPool', () => {
let tp, wallet, transaction, metadata, bc;
beforeEach(() => {
tp = new TransactionPool();
wallet = new Wallet();
wallet2 =new Wallet();
bc = new Blockchain();
transaction = wallet.createTransaction('r4nd-4dr355', 30, bc, tp);
// senderWallet = 'address';
// Name = 'IoT_Lab_Temp_Sensor'
// Geo = [1.045,0.0135]
// IP_URL = 'www.IoT-locationbar.com/sensors/temp'
// Topic_Token = 'ACCESS_TOKEN'
// Permission = 'Public'
// RequestDetail = 'Null'
// OrgOwner = 'Swinburne_University'
// DepOwner = 'Computer_Science'
// PrsnOwner = 'Anas_Dawod'
// PaymentPerKbyte = 10
// PaymentPerMinute = 5
// Protocol = 'MQTT'
// MessageAttributes = 'null'
// Interval = 10
// FurtherDetails = 'null'
// SSNmetadata = 'null'
metadata = wallet.createMetadata('IoT_Lab_Temp_Sensor',[1.045,0.0135],"www.IoT-locationbar.com/sensors/temp" ,'ACCESS_TOKEN' , 'Public',
'Null', 'Swinburne_University', 'Computer_Science','Anas_Dawod', 10,
5, 'MQTT', 'null', 10,
'FurtherDetails', 'SSNmetadata',tp);
});
it('adds a transaction to the pool', () => {
expect(tp.transactions.find(t => t.id === transaction.id)).toEqual(transaction);
});
it('adds a metadata to the pool', () => {
expect(tp.metadataS.find(t => t.id === metadata.id)).toEqual(metadata);
});
it('updates a transaction in the pool', () => {
const oldTransaction = JSON.stringify(transaction);
const newTransaction = transaction.update(wallet, 'foo-4ddr355', 40);
tp.updateOrAddTransaction(newTransaction);
expect(JSON.stringify(tp.transactions.find(t => t.id === newTransaction.id)))
.not.toEqual(oldTransaction);
});
it('clears transactions and metadata', () => {
tp.clear();
expect(tp.transactions).toEqual([]);
expect(tp.metadataS).toEqual([]);
});
describe('mixing valid and corrupt transactions', () => {
let validTransactions;
beforeEach(() => {
validTransactions = [...tp.transactions];
for (let i=0; i<6; i++) {
wallet = new Wallet();
transaction = wallet.createTransaction('r4nd-4dr355', 30, 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.transactions)).not.toEqual(JSON.stringify(validTransactions));
});
it('grabs valid transactions', () => {
expect(tp.validTransactions()).toEqual(validTransactions);
});
});
});

View file

@ -1,80 +0,0 @@
const ChainUtil = require('../chain-util');
const { MINING_REWARD } = require('../config');
class Transaction {
constructor(senderPublicKey, counter, outputs) {
this.input = senderPublicKey;
this.signature = null;
this.counter = counter;
this.outputs = outputs;
}
addSignature(signature) {
if (!ChainUtil.verifySignature(
this.input,
signature,
Transaction.hashToSign(this))) {
console.log("Tried to add an invalid signature to a transaction");
throw new Error("Tried to add an invalid signature to a transaction");
}
this.signature = signature;
}
static hashToSign(transaction) {
return ChainUtil.hash({
counter: transaction.counter,
outputs: transaction.outputs
});
}
static createOutput(recipient, amount) {
return {
publicKey: recipient,
amount: amount
};
}
//update(senderWallet, recipients) {
// 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 });
// Transaction.signTransaction(this, senderWallet);
// return this;
//}
//static signTransaction(transaction, senderWallet) {
// transaction.input = {
// timestamp: Date.now(),
// address: senderWallet.publicKey,
// signature: senderWallet.sign(ChainUtil.hash(transaction.outputs))
// }
//}
static verify(transaction) {
if (transaction.outputs.length === 0) {
return false;
}
for (const output of transaction.outputs) {
if (!output.hasOwnProperty('amount')) {
return false;
}
if (!output.hasOwnProperty('publicKey')) {
return false;
}
}
return ChainUtil.verifySignature(
transaction.input,
transaction.signature,
Transaction.hashToSign(transaction)
);
}
}
module.exports = Transaction;

View file

@ -1,79 +0,0 @@
const Transaction = require('./transaction');
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);
});
});
});

287
wallet/wallet-app.js Normal file
View file

@ -0,0 +1,287 @@
//WALLET
const express = require('express');
const bodyParser = require('body-parser');
const P2pServer = require('../p2p-server');
const N3 = require('n3');
const Wallet = require('./wallet');
const Config = require('../config');
const ChainUtil = require('../chain-util');
const QueryEngine = require('@comunica/query-sparql-rdfjs').QueryEngine;
const Blockchain = require('../blockchain/blockchain');
const {
DEFAULT_PORT_WALLET_API,
DEFAULT_PORT_WALLET_CHAIN,
DEFAULT_PORT_MINER_CHAIN
} = require('../constants');
'use strict';
const CONFIGS_STORAGE_LOCATION = "./settings.json";
const config = new Config(CONFIGS_STORAGE_LOCATION);
const wallet = new Wallet(config.get({
key: "wallet-keypair",
default: ChainUtil.genKeyPair(),
transform: ChainUtil.deserializeKeyPair
}));
const apiPort = config.get({
key: "wallet-api-port",
default: DEFAULT_PORT_WALLET_API
});
const blockchainLocation = config.get({
key: "wallet-blockchain-location",
default: "./wallet_blockchain.json"
});
const chainServerPort = config.get({
key: "wallet-chain-server-port",
default: DEFAULT_PORT_WALLET_CHAIN
});
const chainServerPeers = config.get({
key: "wallet-chain-server-peers",
default: ["ws://127.0.0.1:" + DEFAULT_PORT_MINER_CHAIN]
});
const blockchain = Blockchain.loadFromDisk(blockchainLocation);
function onChainServerRecv(data) {
const replaceResult = blockchain.replaceChain(Blockchain.deserialize(data));
if (!replaceResult.result) {
console.log(`Failed to replace chain: ${replaceResult.reason}`);
//failed to replace
return;
}
blockchain.saveToDisk(blockchainLocation);
}
const chainServer = new P2pServer("Chain-server");
chainServer.start(chainServerPort, chainServerPeers, (_) => { }, onChainServerRecv);
const app = express();
app.use(bodyParser.json());
app.listen(apiPort, () => console.log(`Listening on port ${apiPort}`));
app.get('/ChainServer/sockets', (req, res) => {
res.json(chainServer.sockets);
});
app.post('/ChainServer/connect', (req, res) => {
chainServer.connect(req.body.url);
res.json("Connecting");
});
app.get('/public-key', (req, res) => {
res.json(wallet.publicKey);
});
app.get('/key-pair', (req, res) => {
res.json(ChainUtil.serializeKeyPair(wallet.keyPair));
});
app.get('/MyBalance', (req, res) => {
res.json(blockchain.getBalanceCopy(wallet.publicKey));
});
app.get('/Balance', (req, res) => {
const balance = blockchain.getBalanceCopy(req.body.publicKey);
res.json(balance);
});
app.get('/Balances', (req, res) => {
const balances = blockchain.balances;
res.json(balances);
});
app.post('/Payment', (req, res) => {
res.json(wallet.createPayment(
req.body.rewardAmount,
req.body.outputs,
blockchain));
});
app.post('/Integration', (req, res) => {
res.json(wallet.createIntegration(
req.body.rewardAmount,
req.body.outputs,
blockchain));
});
function extToRdf(triples, sensorId, parentString, obj) {
for (const key in obj) {
const value = obj[key];
const type = typeof value;
switch (typeof value) {
case "string":
triples.push({
s: sensorId,
p: parentString + key,
o: value
});
break;
case "object":
extToRdf(triples, sensorId, parentString + key + '/', value);
break;
default:
console.log("Unsupported value type: " + type);
break;
}
}
}
const brokerRegistrationValidators = {
ssnMetadata: ChainUtil.validateIsString,
rewardAmount: ChainUtil.createValidateIsIntegerWithMin(0),
extMetadata: ChainUtil.validateIsObject
};
app.post('/BrokerRegistration', (req, res) => {
const validateRes = ChainUtil.validateObject(req.body, brokerRegistrationValidators);
if (!validateRes.result) {
res.json(validateRes.reason);
return;
}
const brokers = [];
const triples = [];
const parser = new N3.Parser();
parser.parse(
req.body.ssnMetadata,
(error, quad, prefixes) => {
if (error) {
res.json(error);
return;
}
if (quad) {
triples.push({
s: quad.subject.id,
p: quad.predicate.id,
o: quad.object.id
});
if (quad.predicate.id === "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
&& quad.object.id === "SSM/Broker") {
brokers.push(quad.subject.id);
}
return;
}
//quad is null, we come here, and we are finished parsing
if (brokers.length === 0) {
res.json("Couldn't find a defined broker");
return;
} else if (brokers.length > 1) {
res.json("Found multiple defined brokers");
return;
}
extToRdf(triples, brokers[0], "", req.body.extMetadata);
try {
res.json(wallet.createBrokerRegistration(
triples,
req.body.rewardAmount,
blockchain));
} catch (err) {
console.log(err);
res.json(err.message);
}
});
});
const sensorRegistrationValidators = {
ssnMetadata: ChainUtil.validateIsString,
rewardAmount: ChainUtil.createValidateIsIntegerWithMin(0),
extMetadata: ChainUtil.validateIsObject
};
app.post('/SensorRegistration', (req, res) => {
const validateRes = ChainUtil.validateObject(req.body, sensorRegistrationValidators);
if (!validateRes.result) {
res.json(validateRes.reason);
return;
}
const sensors = [];
const triples = [];
const parser = new N3.Parser();
parser.parse(
req.body.ssnMetadata,
(error, quad, prefixes) => {
if (error) {
res.json(error);
return;
}
if (quad) {
triples.push({
s: quad.subject.id,
p: quad.predicate.id,
o: quad.object.id
});
if (quad.predicate.id === "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
&& quad.object.id === "http://www.w3.org/ns/sosa/Sensor") {
sensors.push(quad.subject.id);
}
return;
}
//quad is null, we come here, and we are finished parsing
if (sensors.length === 0) {
res.json("Couldn't find a defined sensor");
return;
} else if (sensors.length > 1) {
res.json("Found multiple defined sensors");
return;
}
extToRdf(triples, sensors[0], "", req.body.extMetadata);
try {
res.json(wallet.createSensorRegistration(
triples,
req.body.rewardAmount,
blockchain));
} catch (err) {
console.log(err);
res.json(err.message);
}
});
});
const myEngine = new QueryEngine();
app.post('/sparql', (req, res) => {
const start = async function () {
try {
let result = [];
const bindingsStream = await myEngine.queryBindings(
req.body.query,
{
readOnly: true,
sources: blockchain.stores
});
bindingsStream.on('data', (binding) => {
result.push(binding);
});
bindingsStream.on('end', () => {
res.json(JSON.stringify(result));
});
bindingsStream.on('error', (err) => {
console.error(err);
});
} catch (err) {
console.error(err);
res.json("Error occured while querying");
}
};
start()
});

133
wallet/wallet.js Normal file
View file

@ -0,0 +1,133 @@
const Payment = require('../blockchain/payment');
const Integration = require('../blockchain/integration');
const SensorRegistration = require('../blockchain/sensor-registration');
const BrokerRegistration = require('../blockchain/broker-registration');
const Transaction = require('../blockchain/transaction');
//TODO: keep track of issued transactions, so we don't accidently try and double spend
class Wallet {
constructor(keyPair) {
this.keyPair = keyPair;
this.publicKey = this.keyPair.getPublic().encode('hex');
this.counter = 0;
}
sign(dataHash) {
return this.keyPair.sign(dataHash);
}
//TODO: API for multiple outputs
//returns Transaction
createPayment(rewardAmount, outputs, blockchain) {
const balance = blockchain.getBalanceCopy(this.publicKey);
if (balance.counter > this.counter) {
this.counter = balance.counter;
}
let totalAmount = 0;
for (const output of outputs) {
totalAmount += output.amount;
}
if (totalAmount + rewardAmount > balance.balance) {
console.log(`Total amount: ${totalAmount} + reward amount: ${rewardAmount} exceeds current balance: ${balance.balance}`);
return null;
}
const counterToUse = this.counter + 1;
this.counter++;
return new Payment(this.keyPair, counterToUse, outputs, rewardAmount);
}
createPaymentAsTransaction(rewardAmount, outputs, blockchain) {
return new Transaction(
this.createPayment(rewardAmount, outputs, blockchain),
Payment);
}
//TODO: API for multiple sensors
//returns Transaction
createIntegration(rewardAmount, outputs, blockchain) {
const balance = blockchain.getBalanceCopy(this.publicKey);
if (balance.counter > this.counter) {
this.counter = balance.counter;
}
let totalAmount = 0;
for (const output of outputs) {
totalAmount += output.amount;
}
if (totalAmount + rewardAmount > balance.balance) {
console.log(`Total amount: ${totalAmount} + reward amount: ${rewardAmount} exceeds current known balance: ${balance.balance}`);
return null;
}
const counterToUse = this.counter + 1;
this.counter++;
return new Integration(this.keyPair, counterToUse, outputs, rewardAmount);
}
createIntegrationAsTransaction(rewardAmount, outputs, blockchain) {
return new Transaction(
this.createIntegration(rewardAmount, outputs, blockchain),
Integration);
}
//returns Transaction
createBrokerRegistration(metadata, rewardAmount, blockchain) {
const balance = blockchain.getBalanceCopy(this.publicKey);
if (balance.counter > this.counter) {
this.counter = balance.counter;
}
if (rewardAmount > balance.balance) {
console.log(`Reward amount: ${rewardAmount} exceeds current balance: ${balance.balance}`);
return null;
}
const counterToUse = this.counter + 1;
this.counter++;
return new BrokerRegistration(this.keyPair, counterToUse, metadata, rewardAmount)
}
createBrokerRegistrationAsTransaction(metadata, rewardAmount, blockchain) {
return new Transaction(
this.createBrokerRegistration(metadata, rewardAmount, blockchain),
BrokerRegistration);
}
//return Transaction
createSensorRegistration(metadata, rewardAmount, blockchain) {
const balance = blockchain.getBalanceCopy(this.publicKey);
if (balance.counter > this.counter) {
this.counter = balance.counter;
}
if (rewardAmount > balance.balance) {
console.log(`Reward amount: ${rewardAmount} exceeds current balance: ${balance.balance}`);
return null;
}
const counterToUse = this.counter + 1;
this.counter++;
return new SensorRegistration(this.keyPair, counterToUse, metadata, rewardAmount);
}
createSensorRegistrationAsTransaction(metadata, rewardAmount, blockchain) {
return new Transaction(
this.createSensorRegistration(metadata, rewardAmount, blockchain),
SensorRegistration);
}
}
module.exports = Wallet;

View file

@ -1,14 +1,13 @@
const Wallet = require('./index');
const TransactionPool = require('./transaction-pool');
const Blockchain = require('../blockchain');
const ChainUtil = require('../chain-util');
const { INITIAL_BALANCE } = require('../config');
describe('Wallet', () => {
let wallet, tp, bc;
let wallet, bc;
beforeEach(() => {
wallet = new Wallet();
tp = new TransactionPool();
wallet = new Wallet(ChainUtil.genKeyPair());
bc = new Blockchain();
});
@ -28,6 +27,7 @@ describe('Wallet', () => {
tp.updateOrAddTransaction(transaction);
});
//?
it('doubles the `sendAmount` subtracted from the wallet balance', () => {
expect(transaction.outputs.find(output => output.address === wallet.publicKey).amount)
.toEqual(wallet.balance - sendAmount * 2);