demo version

This commit is contained in:
Josip Milovac 2023-07-13 11:32:02 +10:00
parent fbb282a801
commit 672d6daa8e
125 changed files with 17918 additions and 1481 deletions

View file

@ -1,9 +1,14 @@
const ChainUtil = require('../chain-util');
const { DIFFICULTY, MINE_RATE } = require('../constants');
const ChainUtil = require('../util/chain-util');
const { DIFFICULTY, MINE_RATE } = require('../util/constants');
const BrokerRegistration = require('./broker-registration');
const SensorRegistration = require('./sensor-registration');
const Integration = require('./integration');
const Payment = require('./payment');
const Compensation = require('./compensation');
function concatIfNotUndefined(concatTo, prefix, concatting) {
if (typeof concatting !== "undefined" && concatting.length !== 0) {
return concatTo + `${prefix}${concatting}`;
return concatTo + `${prefix}${concatting.signature}`;
} else {
return concatTo;
}
@ -20,18 +25,24 @@ function getData(block, key) {
}
}
const acceptableMembers = new Set();
acceptableMembers.add("timestamp");
acceptableMembers.add("lastHash");
acceptableMembers.add("hash");
acceptableMembers.add("reward");
acceptableMembers.add("payments");
acceptableMembers.add("sensorRegistrations");
acceptableMembers.add("brokerRegistrations");
acceptableMembers.add("integrations");
acceptableMembers.add("compensations");
acceptableMembers.add("nonce");
acceptableMembers.add("difficulty");
const baseValidation = {
timestamp: ChainUtil.createValidateIsIntegerWithMin(0),
lastHash: ChainUtil.validateIsString,
hash: ChainUtil.validateIsString,
reward: ChainUtil.validateIsPublicKey,
nonce: ChainUtil.createValidateIsIntegerWithMin(0),
difficulty: ChainUtil.createValidateIsIntegerWithMin(0),
sensorRegistrations: ChainUtil.createValidateOptional(
ChainUtil.createValidateArray(SensorRegistration.verify)),
brokerRegistrations: ChainUtil.createValidateOptional(
ChainUtil.createValidateArray(BrokerRegistration.verify)),
integrations: ChainUtil.createValidateOptional(
ChainUtil.createValidateArray(Integration.verify)),
compensations: ChainUtil.createValidateOptional(
ChainUtil.createValidateArray(Compensation.verify)),
payments: ChainUtil.createValidateOptional(
ChainUtil.createValidateArray(Payment.verify))
}
class Block {
constructor(timestamp, lastHash, hash, reward, payments, sensorRegistrations, brokerRegistrations, integrations, compensations, nonce, difficulty) {
@ -185,104 +196,17 @@ class Block {
difficulty);
}
static validateIsBlock(block) {
if (!(block instanceof Object)) {
return {
result: false,
reason: "Is not an object"
};
}
static verify(block) {
const validationRes = ChainUtil.validateObject(block, baseValidation);
for (const key in block) {
if (!acceptableMembers.has(key)) {
return {
result: false,
reason: `Block has key not in acceptable members`
};
}
}
if (!validationRes.result) {
return validationRes;
}
if (!("timestamp" in block)) {
if (!Block.checkHash(block)) {
return {
result: false,
reason: "Block doesn't have a timestamp"
};
}
const timestampRes = ChainUtil.validateIsIntegerWithMin(block.timestamp, 0);
if (!timestampRes.result) {
return {
result: false,
reason: "Timestamp validation failed: " + timestampRes.reason
};
}
if (!("lastHash" in block)) {
return {
result: false,
reason: "Block doesn't have lastHash"
};
}
const lastHashRes = ChainUtil.validateIsString(block.lastHash);
if (!lastHashRes.result) {
return {
result: false,
reason: "lastHash validation failed: " + lastHashRes.reason
};
}
if (!("hash" in block)) {
return {
result: false,
reason: "Block doesn't have hash"
};
}
const hashRes = ChainUtil.validateIsString(block.hash);
if (!hashRes.result) {
return {
result: false,
reason: "hash validation failed: " + hashRes.reason
};
}
if (!("reward" in block)) {
return {
result: false,
reason: "Block doesn't have reward"
};
}
const rewardRes = ChainUtil.validateIsPublicKey(block.reward);
if (!rewardRes.result) {
return {
result: false,
reason: "reward validation failed: " + rewardRes.reason
};
}
if (!("nonce" in block)) {
return {
result: false,
reason: "Block doesn't have nonce"
};
}
const nonceRes = ChainUtil.validateIsIntegerWithMin(block.nonce);
if (!nonceRes.result) {
return {
result: false,
reason: "nonce validation failed: " + nonceRes.reason
};
}
if (!("difficulty" in block)) {
return {
result: false,
reason: "Block doesn't have difficulty"
};
}
const difficultyRes = ChainUtil.validateIsIntegerWithMin(block.difficulty);
if (!difficultyRes.result) {
return {
result: false,
reason: "difficulty validation failed: " + difficultyRes.reason
reason: "Couldn't verify hash"
};
}

View file

@ -6,10 +6,13 @@ const BrokerRegistration = require('./broker-registration');
const Integration = require('./integration');
const Compensation = require('./compensation');
const fs = require('fs');
const ChainUtil = require('../chain-util');
const ChainUtil = require('../util/chain-util');
const RdsStore = require('./rds-store');
const {
MINING_REWARD} = require('../constants');
MINING_REWARD,
SENSHAMART_URI_REPLACE } = require('../util/constants');
const URIS = require('./uris');
function makeIntegrationKey(publicKey, counter) {
return `${publicKey}/${counter}`;
@ -80,7 +83,9 @@ class PropertyHistory {
throw new Error("Finishing Property History with null backing");
}
this.backing.undos.push(...this.undos);
for (const undo of this.undos) {
this.backing.undos.push(undo);
}
Object.assign(this.backing.current, this.current);
this.backing = null;
@ -113,6 +118,30 @@ function getPropertyClone(propertyHistory, key, fallback) {
}
}
function namedNode(x) {
return DataFactory.namedNode(x);
}
function literal(x) {
return DataFactory.literal(x);
}
function makeBlockName(block) {
return URIS.OBJECT.BLOCK + '/' + block.hash;
}
function makeSensorTransactionName(sensorRegistration) {
return URIS.OBJECT.SENSOR_REGISTRATION + '/' + SensorRegistration.hashToSign(sensorRegistration);
}
function makeBrokerTransactionName(brokerRegistration) {
return URIS.OBJECT.BROKER_REGISTRATION + '/' + BrokerRegistration.hashToSign(brokerRegistration);
}
function makeWalletName(input) {
return URIS.OBJECT.WALLET + '/' + input;
}
class Updater {
constructor(parent, block) {
this.parent = parent;
@ -126,20 +155,23 @@ class Updater {
this.store.startPush();
if (block !== null) {
this.store.push(
DataFactory.quad(
DataFactory.namedNode(this.block.hash),
DataFactory.namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
DataFactory.namedNode("http://SSM/Block")));
this.pushQuad(
namedNode(makeBlockName(this.block)),
namedNode(URIS.PREDICATE.TYPE),
namedNode(URIS.OBJECT.BLOCK));
this.store.push(
DataFactory.quad(
DataFactory.namedNode(this.block.hash),
DataFactory.namedNode("http://SSM/lastBlock"),
DataFactory.namedNode(this.parent.getBlockFromTop(0).hash)));
this.pushQuad(
namedNode(makeBlockName(this.block.hash)),
namedNode(URIS.PREDICATE.LAST_BLOCK),
namedNode(makeBlockName(this.parent.getBlockFromTop(0))));
}
}
pushQuad(subject, predicate, object) {
this.store.push(
DataFactory.quad(subject, predicate, object));
}
getBalanceCopy(publicKey) {
if (publicKey in this.balances) {
return Object.assign({}, this.balances[publicKey]);
@ -177,9 +209,9 @@ class Updater {
}
getBrokerPublicKeys() {
const keys = this.parent.getBrokerPublicKeysSet();
const keys = this.parent.getBrokerKeysSet();
for (const [key, value] of this.brokers) {
for (const [key, value] of Object.entries(this.brokers)) {
keys.add(value.input);
}
@ -339,7 +371,9 @@ class Chain {
throw new Error("Finishing Blockchain Metadata with null parent");
}
this.parent.blocks.push(...this.blocks);
for (const block of this.blocks) {
this.parent.blocks.push(block);
}
this.balances.finish();
this.sensors.finish();
this.brokers.finish();
@ -349,13 +383,30 @@ class Chain {
}
}
function addRDF(store, metadata) {
function uriReplacePrefix(testing, sensorName) {
if (testing.startsWith(SENSHAMART_URI_REPLACE)) {
return sensorName.concat(testing.slice(SENSHAMART_URI_REPLACE.length));
} else {
return testing;
}
}
function addNodeRDF(updater, metadata, sensorName) {
for (const triple of metadata) {
store.push(
DataFactory.quad(
DataFactory.namedNode(triple.s),
DataFactory.namedNode(triple.p),
DataFactory.namedNode(triple.o)));
updater.pushQuad(
namedNode(uriReplacePrefix(triple.s, sensorName)),
namedNode(uriReplacePrefix(triple.p, sensorName)),
namedNode(uriReplacePrefix(triple.o, sensorName)));
}
}
function addLiteralRDF(updater, metadata, sensorName) {
for (const triple of metadata) {
updater.pushQuad(
namedNode(uriReplacePrefix(triple.s, sensorName)),
namedNode(uriReplacePrefix(triple.p, sensorName)),
literal(triple.o));
}
}
@ -442,7 +493,7 @@ function stepIntegration(updater, reward, integration) {
inputBalance.balance -= integration.rewardAmount;
for (const output of integration.outputs) {
const foundSensor = updater.getSensorCopy(output.sensor);
const foundSensor = updater.getSensorCopy(output.sensorName);
if (foundSensor === null) {
return {
@ -450,12 +501,29 @@ function stepIntegration(updater, reward, integration) {
reason: `Integration references non-existant sensor: ${output.sensor}`
};
}
if (foundSensor.counter !== output.counter) {
if (SensorRegistration.hashToSign(foundSensor) !== output.sensorHash) {
return {
result: false,
reason: "Integration references non-current version of sensor"
};
}
const foundBroker = updater.getBrokerCopy(SensorRegistration.getIntegrationBroker(foundSensor));
if (foundBroker === null) {
return {
result: false,
reason: "Internal consitency error, can't find broker referenced by commited sensor registration"
};
}
if (BrokerRegistration.hashToSign(foundBroker) !== output.brokerHash) {
return {
result: false,
reason: "Integration references non-current version of sensor's broker"
};
}
if (inputBalance.balance < output.amount) {
return {
result: false,
@ -471,14 +539,21 @@ function stepIntegration(updater, reward, integration) {
updater.setBalance(reward, rewardBalance);
const integrationCopy = Object.assign({}, integration);
const brokers = updater.getBrokerKeys();
const brokers = updater.getBrokerPublicKeys();
const witnesses = Integration.chooseWitnesses(integration, brokers);
if (!witnesses.result) {
return {
result: false,
reason: "Couldn't choose witnesses: " + witnesses.reason
};
}
integrationCopy.witnesses = {};
integrationCopy.compensationCount = 0;
for (const witness of witnesses) {
for (const witness of witnesses.witnesses) {
integrationCopy.witnesses[witness] = false;
}
@ -567,16 +642,7 @@ function stepSensorRegistration(updater, reward, sensorRegistration) {
};
}
const extInfo = SensorRegistration.getExtInformation(sensorRegistration);
if (!extInfo.result) {
return {
result: false,
reason: "Couldn't get sensor registration ext information: " + extInfo.reason
};
}
const foundBroker = updater.getBrokerCopy(extInfo.metadata.integrationBroker);
const foundBroker = updater.getBrokerCopy(SensorRegistration.getIntegrationBroker(sensorRegistration));
if (foundBroker === null) {
return {
@ -609,32 +675,65 @@ function stepSensorRegistration(updater, reward, sensorRegistration) {
rewardBalance.balance += sensorRegistration.rewardAmount;
updater.setBalance(reward, rewardBalance);
addRDF(updater.store, sensorRegistration.metadata);
const sensorName = SensorRegistration.getSensorName(sensorRegistration);
const newSensor = extInfo.metadata;
updater.store.push(
DataFactory.quad(
DataFactory.namedNode(newSensor.sensorName),
DataFactory.namedNode("http://SSM/transactionCounter"),
DataFactory.literal(sensorRegistration.counter)));
updater.store.push(
DataFactory.quad(
DataFactory.namedNode(newSensor.sensorName),
DataFactory.namedNode("http://SSM/OwnedBy"),
DataFactory.namedNode("http://SSM/Wallet/" + sensorRegistration.input)));
updater.store.push(
DataFactory.quad(
DataFactory.namedNode(updater.block.hash),
DataFactory.namedNode("http://SSM/Transaction"),
DataFactory.namedNode(newSensor.sensorName)));
updater.store.push(
DataFactory.quad(
DataFactory.namedNode(updater.block.hash),
DataFactory.namedNode("http://SSM/SensorRegistration"),
DataFactory.namedNode(newSensor.sensorName)));
const foundExistingSensor = updater.getSensorCopy(sensorName);
newSensor.counter = sensorRegistration.counter;
updater.setSensor(newSensor.sensorName, newSensor);
if (foundExistingSensor !== null) {
if(foundExistingSensor.input !== sensorRegistration.input) {
return {
result: false,
reason: "A sensor has already been defined with this name"
};
}
}
addNodeRDF(updater, SensorRegistration.getExtraNodeMetadata(sensorRegistration), sensorName);
addLiteralRDF(updater, SensorRegistration.getExtraLiteralMetadata(sensorRegistration), sensorName);
const transactionName = makeSensorTransactionName(sensorRegistration);
if (updater.block !== null) {
updater.pushQuad(
namedNode(makeBlockName(updater.block)),
namedNode(URIS.PREDICATE.CONTAINS_TRANSACTION),
namedNode(transactionName));
updater.pushQuad(
namedNode(makeBlockName(updater.block)),
namedNode(URIS.PREDICATE.CONTAINS_SENSOR_REGISTRATION),
namedNode(transactionName));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.TYPE),
namedNode(URIS.OBJECT.SENSOR_REGISTRATION));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.HAS_COUNTER),
literal(sensorRegistration.counter));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.IS_OWNED_BY),
namedNode(makeWalletName(sensorRegistration.input)));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.DEFINES),
namedNode(sensorName));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.COSTS_PER_MINUTE),
literal(SensorRegistration.getCostPerMinute(sensorRegistration)));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.COSTS_PER_KB),
literal(SensorRegistration.getCostPerKB(sensorRegistration)));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.USES_BROKER),
namedNode(makeBrokerTransactionName(foundBroker)));
}
updater.setSensor(sensorName, sensorRegistration);
return {
result: true
@ -650,15 +749,6 @@ function stepBrokerRegistration(updater, reward, brokerRegistration) {
};
}
const extInfo = BrokerRegistration.getExtInformation(brokerRegistration);
if (!extInfo.result) {
return {
result: false,
reason: "Couldn't get broker registration ext information: " + extInfo.reason
};
}
const inputBalance = updater.getBalanceCopy(brokerRegistration.input);
if (brokerRegistration.counter <= inputBalance.counter) {
@ -683,33 +773,56 @@ function stepBrokerRegistration(updater, reward, brokerRegistration) {
rewardBalance.balance += brokerRegistration.rewardAmount;
updater.setBalance(reward, rewardBalance);
addRDF(updater.store, brokerRegistration.metadata);
const brokerName = BrokerRegistration.getBrokerName(brokerRegistration);
const newBroker = extInfo.metadata;
newBroker.input = brokerRegistration.input;
updater.store.push(
DataFactory.quad(
DataFactory.namedNode(newBroker.brokerName),
DataFactory.namedNode("http://SSM/transactionCounter"),
DataFactory.literal(brokerRegistration.counter)));
updater.store.push(
DataFactory.quad(
DataFactory.namedNode(newBroker.brokerName),
DataFactory.namedNode("http://SSM/OwnedBy"),
DataFactory.namedNode("http://SSM/Wallet/" + brokerRegistration.input)));
updater.store.push(
DataFactory.quad(
DataFactory.namedNode(updater.block.hash),
DataFactory.namedNode("http://SSM/Transaction"),
DataFactory.namedNode(newBroker.brokerName)));
updater.store.push(
DataFactory.quad(
DataFactory.namedNode(updater.block.hash),
DataFactory.namedNode("http://SSM/BrokerRegistration"),
DataFactory.namedNode(newBroker.brokerName)));
const foundExistingBroker = updater.getBrokerCopy(brokerName);
newBroker.counter = brokerRegistration.counter;
updater.setBroker(newBroker.brokerName, newBroker);
if (foundExistingBroker !== null) {
if(foundExistingBroker.input !== brokerRegistration.input) {
return {
result: false,
reason: "A broker has already been defined with this name"
};
}
}
addNodeRDF(updater, BrokerRegistration.getExtraNodeMetadata(brokerRegistration), brokerName);
addLiteralRDF(updater, BrokerRegistration.getExtraLiteralMetadata(brokerRegistration), brokerName);
const transactionName = makeBrokerTransactionName(brokerRegistration);
if (updater.block !== null) {
updater.pushQuad(
namedNode(makeBlockName(updater.block)),
namedNode(URIS.PREDICATE.CONTAINS_TRANSACTION),
namedNode(transactionName));
updater.pushQuad(
namedNode(makeBlockName(updater.block)),
namedNode(URIS.PREDICATE.CONTAINS_BROKER_REGISTRATION),
namedNode(transactionName));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.TYPE),
namedNode(URIS.OBJECT.BROKER_REGISTRATION));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.HAS_COUNTER),
literal(brokerRegistration.counter));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.IS_OWNED_BY),
namedNode(makeWalletName(brokerRegistration.input)));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.DEFINES),
namedNode(brokerName));
updater.pushQuad(
namedNode(transactionName),
namedNode(URIS.PREDICATE.HAS_ENDPOINT),
literal(BrokerRegistration.getEndpoint(brokerRegistration)));
}
updater.setBroker(BrokerRegistration.getBrokerName(brokerRegistration), brokerRegistration);
return {
result: true
@ -850,6 +963,8 @@ function findBlocksDifference(oldBlocks, newBlocks) {
const verifyRes = verifyBlockHash(newBlocks[i - 1], newBlocks[i]);
if (!verifyRes.result) {
console.log(`${newBlocks[i - 1].hash}`);
console.log(`${newBlocks[i].lastHash}`);
return {
result: false,
reason: `Couldn't verify hashes for block ${i}: ${verifyRes.reason}`
@ -976,9 +1091,9 @@ class Blockchain {
return true;
}
wouldBeValidBlock(rewardee, payments, sensorRegistrations, brokerRegistrations, integrations) {
wouldBeValidBlock(rewardee, payments, sensorRegistrations, brokerRegistrations, integrations, compensations) {
const updater = this.chain.createUpdater(null);
return verifyTxs(updater, rewardee, payments, sensorRegistrations, brokerRegistrations, integrations).result;
return verifyTxs(updater, rewardee, payments, sensorRegistrations, brokerRegistrations, integrations, compensations).result;
}
static isValidChain(blocks) {
@ -1025,8 +1140,11 @@ class Blockchain {
this.chain = baseChain;
verifyResult.newChain.finish();
onChange(this, this.blocks(), oldChain, chainDifferenceRes.difference);
console.log(`new chain of length: ${this.blocks().length}`);
onChange(this, this.blocks(), oldChain.blocks, chainDifferenceRes.difference);
return {
result: true,
chainDifference: chainDifferenceRes.difference,

View file

@ -1,4 +1,4 @@
const Blockchain = require('./index');
const Blockchain = require('./blockchain');
const Block = require('./block');
describe('Blockchain', () => {
@ -15,13 +15,13 @@ describe('Blockchain', () => {
it('adds a new block', () => {
const reward = 'test-reward-key';
expect(bc.addBlock(Block.debugMine(bc.lastBlock(),reward,[],[]))).toBe(true);
expect(bc.addBlock(Block.debugMine(bc.lastBlock(),reward))).toBe(true);
expect(bc.lastBlock().reward).toEqual(reward);
});
it('validates a valid chain', () => {
expect(bc2.addBlock(Block.debugMine(bc2.lastBlock(), 'test-reward-key', [], []))).toBe(true);
expect(bc2.addBlock(Block.debugMine(bc2.lastBlock(), 'test-reward-key'))).toBe(true);
expect(Blockchain.isValidChain(bc2.chain)).toBe(true);
});

View file

@ -1,151 +1,91 @@
const ChainUtil = require('../chain-util');
const ChainUtil = require('../util/chain-util');
const SENSHAMART_URI_PREFIX = require('../util/constants').SENSHAMART_URI_PREFIX;
const tripleValidator = {
s: ChainUtil.validateIsString,
p: ChainUtil.validateIsString,
o: ChainUtil.validateIsString
};
function validateTerm(t) {
const stringRes = ChainUtil.validateIsString(t);
function validateMetadata(t) {
let isBroker = [];
let costPerMinute = [];
let costPerKB = [];
let integrationEndpoint = [];
const validationRes = ChainUtil.validateArray(t, ChainUtil.createValidateObject(tripleValidator));
if (!validationRes.result) {
return validationRes;
if (!stringRes.result) {
return stringRes;
}
for (const triple of t) {
switch (triple.p) {
case "http://SSM/Cost_of_Using_IoT_Devices/Cost_Per_Minute": costPerMinute.push(triple); break;
case "http://SSM/Cost_of_Using_IoT_Devices/Cost_Per_Kbyte": costPerKB.push(triple); break;
case "http://www.w3.org/1999/02/22-rdf-syntax-ns#type":
if (triple.o === "http://SSM/Broker") {
isBroker.push(triple.s);
}
break;
case "http://SSM/Integration/Endpoint": integrationEndpoint.push(triple); break;
}
}
if (isBroker.length === 0) {
if (t.startsWith(SENSHAMART_URI_PREFIX)) {
return {
result: false,
reason: "No broker is defined"
};
} else if (isBroker.length > 1) {
return {
result: false,
reason: "Multiple brokers are defined"
};
}
const brokerName = isBroker[0];
if (costPerMinute.length === 0) {
return {
result: false,
reason: "No cost per minute was defined"
};
} else if (costPerMinute.length > 1) {
return {
result: false,
reason: "Multiple cost per minutes were defined"
}
}
const CostPerMinuteValue = Number.parseInt(costPerMinute[0].o);
if (CostPerMinuteValue === NaN) {
return {
result: false,
reason: "Couldn't parse cost per minute as an integer"
};
} else if (CostPerMinuteValue < 1) {
return {
result: false,
reason: "Cost per minute was negative"
}
} else if (costPerMinute[0].s != brokerName) {
return {
result: false,
reason: "Cost per minute object isn't the broker"
};
}
if (costPerKB.length === 0) {
return {
result: false,
reason: "No cost per KB was defined"
};
} else if (costPerKB.length > 1) {
return {
result: false,
reason: "Multiple cost per KB were defined"
}
}
const CostPerKBValue = Number.parseInt(costPerKB[0].o);
if (CostPerKBValue === NaN) {
return {
result: false,
reason: "Couldn't parse cost per KB as an integer"
};
} else if (CostPerKBValue < 1) {
return {
result: false,
reason: "Cost per KB was negative"
}
} else if (costPerKB[0].s != brokerName) {
return {
result: false,
reason: "Cost per KB object isn't the broker"
};
}
if (integrationEndpoint.length === 0) {
return {
result: false,
reason: "No integration endpoint was defined"
};
} else if (integrationEndpoint.length > 1) {
return {
result: false,
reason: "Multiple integration endpoints were defined"
};
} else if (integrationEndpoint[0].s != brokerName) {
return {
result: false,
reason: "Integration endpoint object isn't the broker"
reason: "Starts with reserved prefix"
};
}
return {
result: true,
metadata: {
brokerName: brokerName,
costPerMinute: CostPerMinuteValue,
costPerKB: CostPerKBValue,
integrationEndpoint: integrationEndpoint[0].o
}
result: true
};
}
function validateLiteral(t) {
const termRes = validateTerm(t);
if (termRes.result) {
return termRes;
}
const numberRes = ChainUtil.validateIsNumber(t);
if (numberRes.result) {
return numberRes;
}
return {
result: false,
reason: "Wasn't a string or a number"
};
}
const nodeValidator = {
s: validateTerm,
p: validateTerm,
o: validateTerm
};
const literalValidator = {
s: validateTerm,
p: validateTerm,
o: validateLiteral
};
const metadataValidation = {
name: ChainUtil.validateIsString,
endpoint: ChainUtil.validateIsString,
extraNodes: ChainUtil.createValidateOptional(
ChainUtil.createValidateArray(
ChainUtil.createValidateObject(
nodeValidator))),
extraLiterals: ChainUtil.createValidateOptional(
ChainUtil.createValidateArray(
ChainUtil.createValidateObject(
literalValidator)))
}
const baseValidation = {
input: ChainUtil.validateIsPublicKey,
counter: ChainUtil.validateIsInteger,
counter: ChainUtil.createValidateIsIntegerWithMin(0),
rewardAmount: ChainUtil.createValidateIsIntegerWithMin(0),
metadata: validateMetadata,
metadata: ChainUtil.createValidateObject(metadataValidation),
signature: ChainUtil.validateIsSignature
};
class BrokerRegistration {
constructor(senderKeyPair, counter, metadata, rewardAmount) {
constructor(senderKeyPair, counter, brokerName, endpoint, nodeMetadata, literalMetadata, rewardAmount) {
this.input = senderKeyPair.getPublic().encode('hex');
this.counter = counter;
this.rewardAmount = rewardAmount;
this.metadata = metadata;
this.metadata = {
name: brokerName,
endpoint: endpoint
};
if (typeof nodeMetadata !== undefined && nodeMetadata !== null) {
this.metadata.extraNodes = nodeMetadata;
};
if (typeof literalMetadata !== undefined && literalMetadata !== null) {
this.metadata.extraLiterals = literalMetadata;
};
this.signature = senderKeyPair.sign(BrokerRegistration.hashToSign(this));
const verification = BrokerRegistration.verify(this);
@ -154,6 +94,30 @@ class BrokerRegistration {
}
}
static getBrokerName(registration) {
return registration.metadata.name;
}
static getEndpoint(registration) {
return registration.metadata.endpoint;
}
static getExtraNodeMetadata(registration) {
if ("extraNodes" in registration.metadata) {
return registration.metadata.extraNodes;
} else {
return [];
}
}
static getExtraLiteralMetadata(registration) {
if ("extraLiterals" in registration.metadata) {
return registration.metadata.extraLiterals;
} else {
return [];
}
}
static hashToSign(registration) {
return ChainUtil.hash([
registration.counter,
@ -173,7 +137,7 @@ class BrokerRegistration {
BrokerRegistration.hashToSign(registration));
if (!signatureRes.result) {
return signatureRes.reason;
return signatureRes;
}
return {
@ -181,8 +145,8 @@ class BrokerRegistration {
};
}
static getExtInformation(registration) {
return validateMetadata(registration.metadata);
static name() {
return "BrokerRegistration";
}
}

View file

@ -0,0 +1,205 @@
const BrokerRegistration = require('./broker-registration');
const ChainUtil = require('../util/chain-util');
const SENSHAMART_URI_PREFIX = require('../util/constants').SENSHAMART_URI_PREFIX;
describe('Broker Registration', () => {
let keyPair;
beforeEach(() => {
keyPair = ChainUtil.genKeyPair();
});
it("Construct a broker", () => {
new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [], 0);
});
it("Construct a broker with invalid counter", () => {
expect(() => new BrokerRegistration(keyPair, "hello", "test", 0, 0, "test", null, 0)).toThrow();
});
it("Construct a broker with invalid name", () => {
expect(() => new BrokerRegistration(keyPair, 1, 5, 0, 0, "test", null, 0)).toThrow();
});
it("Construct a broker with negative costPerMinute", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", -1, 0, "test", null, 0)).toThrow();
});
it("Construct a broker with invalid costPerMinute", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 1.5, 0, "test", null, 0)).toThrow();
});
it("Construct a broker with negative costPerKB", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, -1, "test", null, 0)).toThrow();
});
it("Construct a broker with invalid costPerKB", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, "hello", "test", null, 0)).toThrow();
});
it("Construct a broker with invalid broker", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, 0, 5, null, 0)).toThrow();
});
it("Construct a broker with negative rewardAmount", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", null, -1)).toThrow();
});
it("Construct a broker with invalid rewardAmount", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", null, "0")).toThrow();
});
it("Construct a broker with extra metadata", () => {
new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
});
it("Construct a broker invalid subject in extra metadata", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: 0,
p: "and",
o: "something else"
}], 0)).toThrow();
});
it("Construct a broker reserved subject in extra metadata", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: SENSHAMART_URI_PREFIX + "something",
p: "and",
o: "something else"
}], 0)).toThrow();
});
it("Construct a broker with invalid predicate in extra metadata", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: {},
o: "something else"
}], 0)).toThrow();
});
it("Construct a broker with reserved predicate in extra metadata", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: SENSHAMART_URI_PREFIX + "and",
o: "something else"
}], 0)).toThrow();
});
it("Construct a broker with invalid object in extra metadata", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: []
}], 0)).toThrow();
});
it("Construct a broker with reserved object in extra metadata", () => {
expect(() => new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: SENSHAMART_URI_PREFIX + "something else"
}], 0)).toThrow();
});
it("Changing input fails verify", () => {
const changing = new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(BrokerRegistration.verify(changing).result).toBe(true);
changing.input = ChainUtil.genKeyPair();
expect(BrokerRegistration.verify(changing).result).toBe(false);
});
it("Changing counter fails verify", () => {
const changing = new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(BrokerRegistration.verify(changing).result).toBe(true);
changing.counter++;
expect(BrokerRegistration.verify(changing).result).toBe(false);
});
it("Changing rewardAmount fails verify", () => {
const changing = new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(BrokerRegistration.verify(changing).result).toBe(true);
changing.rewardAmount++;
expect(BrokerRegistration.verify(changing).result).toBe(false);
});
it("Changing metadata name fails verify", () => {
const changing = new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(BrokerRegistration.verify(changing).result).toBe(true);
changing.metadata.name = "else";
expect(BrokerRegistration.verify(changing).result).toBe(false);
});
it("Changing metadata costPerMinute fails verify", () => {
const changing = new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(BrokerRegistration.verify(changing).result).toBe(true);
changing.metadata.costPerMinute++;
expect(BrokerRegistration.verify(changing).result).toBe(false);
});
it("Changing metadata costPerKB fails verify", () => {
const changing = new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(BrokerRegistration.verify(changing).result).toBe(true);
changing.metadata.costPerKB++;
expect(BrokerRegistration.verify(changing).result).toBe(false);
});
it("Changing metadata endpoint fails verify", () => {
const changing = new BrokerRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(BrokerRegistration.verify(changing).result).toBe(true);
changing.metadata.endpoint += "a";
expect(BrokerRegistration.verify(changing).result).toBe(false);
});
});

View file

@ -1,4 +1,4 @@
const ChainUtil = require('../chain-util');
const ChainUtil = require('../util/chain-util');
const Integration = require('./integration');
const integrationValidation = {
@ -60,6 +60,10 @@ class Compensation {
result: true,
};
}
static name() {
return "Compensation";
}
}
module.exports = Compensation;

View file

@ -1,11 +1,11 @@
const ChainUtil = require('../chain-util');
const ChainUtil = require('../util/chain-util');
const SeedRandom = require('seedrandom');
const outputValidation = {
publicKey: ChainUtil.validateIsPublicKey,
sensor: ChainUtil.validateIsString,
sensorName: ChainUtil.validateIsString,
amount: ChainUtil.createValidateIsIntegerWithMin(1),
counter: ChainUtil.createValidateIsIntegerWithMin(1)
sensorHash: ChainUtil.validateIsString,
brokerHash: ChainUtil.validateIsString
};
function validateOutputs(t) {
@ -54,12 +54,12 @@ class Integration {
}
}
static createOutput(recipientPublicKey, sensorId, amount, counter) {
static createOutput(amount, sensorName, sensorRegistrationHash, brokerRegistrationHash) {
return {
publicKey: recipientPublicKey,
sensor: sensorId,
amount: amount,
counter: counter
sensorName: sensorName,
sensorHash: sensorRegistrationHash,
brokerHash: brokerRegistrationHash
};
}
@ -128,6 +128,10 @@ class Integration {
witnesses: witnesses
};
}
static name() {
return "Integration";
}
}
module.exports = Integration;

View file

@ -1,5 +1,5 @@
const Integration = require('./integration');
const ChainUtil = require('../chain-util');
const ChainUtil = require('../util/chain-util');
function createDummyIntegration(keyPair, witnesses) {
return new Integration(

View file

@ -1,4 +1,4 @@
const ChainUtil = require('../chain-util');
const ChainUtil = require('../util/chain-util');
const outputValidation = {
publicKey: ChainUtil.validateIsPublicKey,
@ -79,6 +79,10 @@ class Payment {
result: true,
};
}
static name() {
return "Payment";
}
}
module.exports = Payment;

View file

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

View file

@ -1,5 +1,4 @@
const Stream = require("stream");
const DataFactory = require('n3').DataFactory;
//class NamedNode {
// constructor(value) {
@ -294,32 +293,29 @@ function addQuadToMap(counter, map, key, quad, toPop) {
if (toPop.has(key)) {
popper = toPop.get(key);
} else {
popper = {
delete: false,
removing: []
};
popper = [];
toPop.set(key, popper);
}
if (map.has(key)) {
quadMap = map.get(key);
popper.removing.push(counter);
} else {
quadMap = new Map();
map.set(key, quadMap);
popper.delete = true;
}
popper.push(counter);
quadMap.set(counter, quad);
}
function popFromSource(list, map) {
for (const [key, popper] of list) {
if (popper.delete) {
const innerMap = map.get(key);
if (popper.length === innerMap.size) {
map.delete(key)
} else {
const keyMap = map.get(key);
for (const counter of popper.removing) {
keyMap.delete(counter);
for (const counter of popper) {
innerMap.delete(counter);
}
}
}
@ -342,12 +338,12 @@ class Source {
this.objects = new Map();
this.graphs = new Map();
this.all = [];
this.pop = [];
this.popping = [];
this.counter = 0;
}
startPush() {
this.pop.push({
this.popping.push({
subjects: new Map(),
predicates: new Map(),
objects: new Map(),
@ -357,7 +353,7 @@ class Source {
}
push(quad) {
const toPop = this.pop[this.pop.length - 1];
const toPop = this.popping[this.popping.length - 1];
addQuadToMap(this.counter, this.subjects, quad.subject.value, quad, toPop.subjects);
addQuadToMap(this.counter, this.predicates, quad.predicate.value, quad, toPop.predicates);
@ -369,11 +365,11 @@ class Source {
}
pop() {
if (this.pop.length === 0) {
if (this.popping.length === 0) {
throw new Error("Nothing to pop");
}
const toPop = this.pop.pop();
const toPop = this.popping.pop();
this.all.slice(0, -toPop.count);
@ -453,7 +449,7 @@ class Source {
cloneTermMap(this.graphs, returning.graphs);
this.all.forEach(item => returning.all.push(item));
this.pop.forEach(item => returning.pop.push(item));
this.popping.forEach(item => returning.popping.push(item));
returning.counter = this.counter;
return returning;
@ -461,7 +457,7 @@ class Source {
pushInto(parent) {
let on = 0;
for (const toPop of this.pop) {
for (const toPop of this.popping) {
parent.startPush();
for (const quad of this.all.slice(on, on + toPop.count)) {
parent.push(quad);

View file

@ -1,150 +1,95 @@
const ChainUtil = require('../chain-util');
const ChainUtil = require('../util/chain-util');
const SENSHAMART_URI_PREFIX = require('../util/constants').SENSHAMART_URI_PREFIX;
const tripleValidator = {
s: ChainUtil.validateIsString,
p: ChainUtil.validateIsString,
o: ChainUtil.validateIsString
};
function validateTerm(t) {
const stringRes = ChainUtil.validateIsString(t);
function validateMetadata(t) {
let isSensor = [];
let costPerMinute = [];
let costPerKB = [];
let integrationBroker = [];
const validationRes = ChainUtil.validateArray(t, ChainUtil.createValidateObject(tripleValidator));
if (!validationRes.result) {
return validationRes;
if (!stringRes.result) {
return stringRes;
}
for (const triple of t) {
switch (triple.p) {
case "http://SSM/Cost_of_Using_IoT_Devices/Cost_Per_Minute": costPerMinute.push(triple); break;
case "http://SSM/Cost_of_Using_IoT_Devices/Cost_Per_Kbyte": costPerKB.push(triple); break;
case "http://www.w3.org/1999/02/22-rdf-syntax-ns#type":
if (triple.o === "http://www.w3.org/ns/sosa/Sensor") {
isSensor.push(triple.s);
}
break;
case "http://SSM/Integration/Broker": integrationBroker.push(triple); break;
}
}
if (isSensor.length === 0) {
if (t.startsWith(SENSHAMART_URI_PREFIX)) {
return {
result: false,
reason: "No sensor is defined"
};
} else if (isSensor.length > 1) {
return {
result: false,
reason: "Multiple sensors are defined"
};
}
const sensorName = isSensor[0];
if (costPerMinute.length === 0) {
return {
result: false,
reason: "No cost per minute was defined"
};
} else if (costPerMinute.length > 1) {
return {
result: false,
reason: "Multiple cost per minutes were defined"
}
}
const CostPerMinuteValue = Number.parseInt(costPerMinute[0].o);
if (CostPerMinuteValue === NaN) {
return {
result: false,
reason: "Couldn't parse cost per minute as an integer"
};
} else if (CostPerMinuteValue < 1) {
return {
result: false,
reason: "Cost per minute was negative"
}
} else if (costPerMinute[0].s != sensorName) {
return {
result: false,
reason: "Cost per minute object isn't the broker"
};
}
if (costPerKB.length === 0) {
return {
result: false,
reason: "No cost per KB was defined"
};
} else if (costPerKB.length > 1) {
return {
result: false,
reason: "Multiple cost per KB were defined"
}
}
const CostPerKBValue = Number.parseInt(costPerKB[0].o);
if (CostPerKBValue === NaN) {
return {
result: false,
reason: "Couldn't parse cost per KB as an integer"
};
} else if (CostPerKBValue < 1) {
return {
result: false,
reason: "Cost per KB was negative"
}
} else if (costPerKB[0].s != sensorName) {
return {
result: false,
reason: "Cost per KB object isn't the broker"
};
}
if (integrationBroker.length === 0) {
return {
result: false,
reason: "No integration broker was defined"
};
} else if (integrationBroker.length > 1) {
return {
result: false,
reason: "Multiple integration brokers were defined"
};
} else if (integrationBroker[0].s != sensorName) {
return {
result: false,
reason: "Integration broker subjsect isn't the sensor"
reason: "Starts with reserved prefix"
};
}
return {
result: true,
metadata: {
sensorName: sensorName,
costPerMinute: CostPerMinuteValue,
costPerKB: CostPerKBValue,
integrationBroker: integrationBroker[0].o
}
result: true
};
}
function validateLiteral(t) {
const termRes = validateTerm(t);
if (termRes.result) {
return termRes;
}
const numberRes = ChainUtil.validateIsNumber(t);
if (numberRes.result) {
return numberRes;
}
return {
result: false,
reason: "Wasn't a string or a number"
};
}
const nodeValidator = {
s: validateTerm,
p: validateTerm,
o: validateTerm
};
const literalValidator = {
s: validateTerm,
p: validateTerm,
o: validateLiteral
};
const metadataValidation = {
name: ChainUtil.validateIsString,
costPerMinute: ChainUtil.createValidateIsIntegerWithMin(0),
costPerKB: ChainUtil.createValidateIsIntegerWithMin(0),
integrationBroker: ChainUtil.validateIsString,
extraNodes: ChainUtil.createValidateOptional(
ChainUtil.createValidateArray(
ChainUtil.createValidateObject(
nodeValidator))),
extraLiterals: ChainUtil.createValidateOptional(
ChainUtil.createValidateArray(
ChainUtil.createValidateObject(
literalValidator)))
};
const baseValidation = {
input: ChainUtil.validateIsPublicKey,
counter: ChainUtil.createValidateIsIntegerWithMin(1),
rewardAmount: ChainUtil.createValidateIsIntegerWithMin(0),
metadata: validateMetadata,
metadata: ChainUtil.createValidateObject(metadataValidation),
signature: ChainUtil.validateIsSignature
};
class SensorRegistration {
constructor(senderKeyPair, counter, metadata, rewardAmount) {
constructor(senderKeyPair, counter, sensorName, costPerMinute, costPerKB, integrationBroker, nodeMetadata, literalMetadata, rewardAmount) {
this.input = senderKeyPair.getPublic().encode('hex');
this.counter = counter;
this.rewardAmount = rewardAmount;
this.metadata = metadata;
this.metadata = {
name: sensorName,
costPerMinute: costPerMinute,
costPerKB: costPerKB,
integrationBroker: integrationBroker,
};
if (typeof nodeMetadata !== undefined && nodeMetadata !== null) {
this.metadata.extraNodes = nodeMetadata;
}
if (typeof literalMetadata !== undefined && literalMetadata !== null) {
this.metadata.extraLiterals = literalMetadata;
}
this.signature = senderKeyPair.sign(SensorRegistration.hashToSign(this));
const verification = SensorRegistration.verify(this);
@ -153,6 +98,38 @@ class SensorRegistration {
}
}
static getSensorName(registration) {
return registration.metadata.name;
}
static getCostPerMinute(registration) {
return registration.metadata.costPerMinute;
}
static getCostPerKB(registration) {
return registration.metadata.costPerKB;
}
static getIntegrationBroker(registration) {
return registration.metadata.integrationBroker;
}
static getExtraNodeMetadata(registration) {
if ("extraNodes" in registration.metadata) {
return registration.metadata.extraNodes;
} else {
return [];
}
}
static getExtraLiteralMetadata(registration) {
if ("extraLiterals" in registration.metadata) {
return registration.metadata.extraLiterals;
} else {
return [];
}
}
static hashToSign(registration) {
return ChainUtil.hash([
registration.counter,
@ -163,8 +140,7 @@ class SensorRegistration {
static verify(registration) {
const validationResult = ChainUtil.validateObject(registration, baseValidation);
if (!validationResult.result) {
console.log(`Failed validation: ${validationResult.reason}`);
return false;
return validationResult;
}
const verifyRes = ChainUtil.verifySignature(
@ -180,8 +156,8 @@ class SensorRegistration {
};
}
static getExtInformation(registration) {
return validateMetadata(registration.metadata);
static name() {
return "SensorRegistration";
}
}

View file

@ -1,109 +1,205 @@
const Transaction = require('./transaction');
const Metadata = require('./metadata');
const Wallet = require('./index');
const { MINING_REWARD } = require('../constants');
const SensorRegistration = require('./sensor-registration');
const ChainUtil = require('../util/chain-util');
const SENSHAMART_URI_PREFIX = require('../util/constants').SENSHAMART_URI_PREFIX;
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;
describe('Sensor Registration', () => {
let keyPair;
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)
keyPair = ChainUtil.genKeyPair();
});
it('outputs the `amount` subtracted from the wallet balance', () => {
expect(transaction.outputs.find(output => output.address === wallet.publicKey).amount)
.toEqual(wallet.balance - amount);
it("Construct a sensor", () => {
new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [], 0);
});
it('outputs the `amount` added to the recipient', () => {
expect(transaction.outputs.find(output => output.address === recipient).amount)
.toEqual(amount);
it("Construct a sensor with invalid counter", () => {
expect(() => new SensorRegistration(keyPair, "hello", "test", 0, 0, "test", null, 0)).toThrow();
});
it('inputs the balance of the wallet', () => {
expect(transaction.input.amount).toEqual(wallet.balance);
it("Construct a sensor with invalid name", () => {
expect(() => new SensorRegistration(keyPair, 1, 5, 0, 0, "test", null, 0)).toThrow();
});
it('validates a valid transaction', () => {
expect(Transaction.verifyTransaction(transaction)).toBe(true);
it("Construct a sensor with negative costPerMinute", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", -1, 0, "test", null, 0)).toThrow();
});
it('validates a valid metadata', () => {
expect(Metadata.verifyMetadata(metadata)).toBe(true);
it("Construct a sensor with invalid costPerMinute", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 1.5, 0, "test", null, 0)).toThrow();
});
it('invalidates a corrupt transaction', () => {
transaction.outputs[0].amount = 50000;
expect(Transaction.verifyTransaction(transaction)).toBe(false);
it("Construct a sensor with negative costPerKB", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, -1, "test", null, 0)).toThrow();
});
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);
});
it("Construct a sensor with invalid costPerKB", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, "hello", "test", null, 0)).toThrow();
});
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);
});
it("Construct a sensor with invalid broker", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, 0, 5, null, 0)).toThrow();
});
describe('creating a reward transaction', () => {
beforeEach(() => {
transaction = Transaction.rewardTransaction(wallet, Wallet.blockchainWallet());
});
it("Construct a sensor with negative rewardAmount", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, 0, "test", null, -1)).toThrow();
});
it(`reward the miner's wallet`, () => {
expect(transaction.outputs.find(output => output.address === wallet.publicKey).amount)
.toEqual(MINING_REWARD);
});
it("Construct a sensor with invalid rewardAmount", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, 0, "test", null, "0")).toThrow();
});
it("Construct a sensor with extra metadata", () => {
new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
});
it("Construct a sensor invalid subject in extra metadata", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: 0,
p: "and",
o: "something else"
}], 0)).toThrow();
});
it("Construct a sensor reserved subject in extra metadata", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: SENSHAMART_URI_PREFIX + "something",
p: "and",
o: "something else"
}], 0)).toThrow();
});
it("Construct a sensor with invalid predicate in extra metadata", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: {},
o: "something else"
}], 0)).toThrow();
});
it("Construct a sensor with reserved predicate in extra metadata", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: SENSHAMART_URI_PREFIX + "and",
o: "something else"
}], 0)).toThrow();
});
it("Construct a sensor with invalid object in extra metadata", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: []
}], 0)).toThrow();
});
it("Construct a sensor with reserved object in extra metadata", () => {
expect(() => new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: SENSHAMART_URI_PREFIX + "something else"
}], 0)).toThrow();
});
it("Changing input fails verify", () => {
const changing = new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(SensorRegistration.verify(changing).result).toBe(true);
changing.input = ChainUtil.genKeyPair();
expect(SensorRegistration.verify(changing).result).toBe(false);
});
it("Changing counter fails verify", () => {
const changing = new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(SensorRegistration.verify(changing).result).toBe(true);
changing.counter++;
expect(SensorRegistration.verify(changing).result).toBe(false);
});
it("Changing rewardAmount fails verify", () => {
const changing = new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(SensorRegistration.verify(changing).result).toBe(true);
changing.rewardAmount++;
expect(SensorRegistration.verify(changing).result).toBe(false);
});
it("Changing metadata name fails verify", () => {
const changing = new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(SensorRegistration.verify(changing).result).toBe(true);
changing.metadata.name = "else";
expect(SensorRegistration.verify(changing).result).toBe(false);
});
it("Changing metadata costPerMinute fails verify", () => {
const changing = new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(SensorRegistration.verify(changing).result).toBe(true);
changing.metadata.costPerMinute++;
expect(SensorRegistration.verify(changing).result).toBe(false);
});
it("Changing metadata costPerKB fails verify", () => {
const changing = new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(SensorRegistration.verify(changing).result).toBe(true);
changing.metadata.costPerKB++;
expect(SensorRegistration.verify(changing).result).toBe(false);
});
it("Changing metadata integrationBroker fails verify", () => {
const changing = new SensorRegistration(keyPair, 1, "test", 0, 0, "test", [{
s: "something",
p: "and",
o: "something else"
}], 0);
expect(SensorRegistration.verify(changing).result).toBe(true);
changing.metadata.integrationBroker += "a";
expect(SensorRegistration.verify(changing).result).toBe(false);
});
});

View file

@ -1,7 +1,8 @@
const Payment = require('./payment');
const Integration = require('./integration');
const SensorRegistration = require('./sensor-registration');
const BrokerRegistration = require('./broker-registration');
const Integration = require('./integration');
const Payment = require('./payment');
const Compensation = require('./compensation');
class Transaction {
constructor(transaction, type) {
@ -10,9 +11,13 @@ class Transaction {
this.type = type;
}
static mapId(type) {
return type.name();
}
static ALL_TYPES = [
SensorRegistration,
BrokerRegistration,
Integration,
Payment,
Compensation
];
};
module.exports = Transaction;

26
blockchain/uris.js Normal file
View file

@ -0,0 +1,26 @@
const PREFIX = require('../util/constants').SENSHAMART_URI_PREFIX;
module.exports = {
PREDICATE: {
IS_OWNED_BY: PREFIX + "IsOwnedBy",
DEFINES: PREFIX + "Defines",
HAS_COUNTER: PREFIX + "HasCounter",
COSTS_PER_MINUTE: PREFIX + "CostsPerMinute",
COSTS_PER_KB: PREFIX + "CostsPerKB",
USES_BROKER: PREFIX + "UsesBroker",
HAS_ENDPOINT: PREFIX + "HasEndpoint",
CONTAINS_TRANSACTION: PREFIX + "ContainsTransaction",
CONTAINS_SENSOR_REGISTRATION: PREFIX + "ContainsSensorRegistration",
CONTAINS_BROKER_REGISTRATION: PREFIX + "ContainsBrokerRegistration",
TYPE: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
LAST_BLOCK: PREFIX + "LastBlock"
},
OBJECT: {
SENSOR_REGISTRATION: PREFIX + "SensorRegistration",
BROKER_REGISTRATION: PREFIX + "BrokerRegistration",
TRANSACTION: PREFIX + "Transaction",
WALLET: PREFIX + "Wallet",
BLOCK: PREFIX + "Block",
}
};