From df8584f4b846475004cbe8c9d993580e5cff062d Mon Sep 17 00:00:00 2001 From: garrettmills Date: Sat, 10 Apr 2021 02:01:57 -0500 Subject: [PATCH] Add basic block object interfaces --- src/app/configs/app.config.ts | 1 + src/app/rtdb/BlockResource.ts | 57 ++++++++++++++++++ src/app/units/Blockchain.ts | 110 ++++++++++++++++++++++++++++++++++ src/app/units/FirebaseUnit.ts | 2 +- 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/app/rtdb/BlockResource.ts create mode 100644 src/app/units/Blockchain.ts diff --git a/src/app/configs/app.config.ts b/src/app/configs/app.config.ts index a4a026e..fb7bfbd 100644 --- a/src/app/configs/app.config.ts +++ b/src/app/configs/app.config.ts @@ -17,6 +17,7 @@ export default { refs: { peers: 'chain/server/peers', transaction: 'chain/pending/transactions', + block: 'chain/local/block', }, }, } diff --git a/src/app/rtdb/BlockResource.ts b/src/app/rtdb/BlockResource.ts new file mode 100644 index 0000000..9d8cf18 --- /dev/null +++ b/src/app/rtdb/BlockResource.ts @@ -0,0 +1,57 @@ +import {FirebaseResource, FirebaseResourceItem} from "../FirebaseResource" +import {Injectable} from "@extollo/di" +import {RTDBRef} from "../units/FirebaseUnit" +import {AsyncCollection} from "@extollo/util" + +export interface BlockEncounterTransaction { + combinedHash: string; + timestamp: number; + encodedGPSLocation: string; +} + +export interface BlockInfectionTransaction { + clientID: string; + timestamp: number; +} + +export type BlockTransaction = BlockInfectionTransaction | BlockEncounterTransaction + +export function isBlockEncounterTransaction(what: any): what is BlockEncounterTransaction { + return ( + what + && typeof what.combinedHash === 'string' + && typeof what.timestamp === 'number' + && typeof what.encodedGPSLocation === 'string' + ) +} + +export function isBlockInfectionTransaction(what: any): what is BlockInfectionTransaction { + return ( + what + && typeof what.clientID === 'string' + && typeof what.timestamp === 'number' + ) +} + +export function isBlockTransaction(what: any): what is BlockTransaction { + return isBlockEncounterTransaction(what) || isBlockInfectionTransaction(what) +} + +export interface BlockResourceItem extends FirebaseResourceItem { + uuid: string; + combinedHash: string; + timestamp: number; + encodedGPSLocation: string; + transactions: BlockTransaction[]; + lastBlockHash: string; + lastBlockUUID: string; +} + +@Injectable() +export class BlockResource extends FirebaseResource { + public static collect(): AsyncCollection { + return new AsyncCollection(new BlockResource()) + } + + protected refName: RTDBRef = 'block' +} diff --git a/src/app/units/Blockchain.ts b/src/app/units/Blockchain.ts new file mode 100644 index 0000000..6d5f737 --- /dev/null +++ b/src/app/units/Blockchain.ts @@ -0,0 +1,110 @@ +import {Singleton, Inject} from "@extollo/di" +import {Unit, Logging} from "@extollo/lib" +import {FirebaseUnit} from "./FirebaseUnit" +import {BlockResource, BlockResourceItem, BlockTransaction} from "../rtdb/BlockResource" +import {TransactionResourceItem} from "../rtdb/TransactionResource" +import * as crypto from "crypto" + +export class Block implements BlockResourceItem { + seqID: number; + uuid: string; + combinedHash: string; + timestamp: number; + encodedGPSLocation: string; + transactions: BlockTransaction[]; + lastBlockHash: string; + lastBlockUUID: string; + + constructor(rec: BlockResourceItem) { + this.seqID = rec.seqID + this.uuid = rec.uuid + this.combinedHash = rec.combinedHash + this.timestamp = rec.timestamp + this.encodedGPSLocation = rec.encodedGPSLocation + this.transactions = rec.transactions + this.lastBlockHash = rec.lastBlockHash + this.lastBlockUUID = rec.lastBlockUUID + } + + hash() { + return crypto.createHash('sha256') + .update(this.toString(), 'utf-8') + .digest('hex') + } + + toString() { + return [ + this.uuid, + this.combinedHash, + this.timestamp.toString(), + this.encodedGPSLocation, + JSON.stringify(this.transactions), + this.lastBlockHash, + this.lastBlockUUID, + ].join('%') + } +} + +export interface Peer { + host: string, + name?: string, +} + +/** + * Blockchain Unit + * --------------------------------------- + * Main service for interacting with the contact blockchain. + */ +@Singleton() +export class Blockchain extends Unit { + @Inject() + protected readonly logging!: Logging + + @Inject() + protected readonly firebase!: FirebaseUnit + + public async hasPeer(host: string): Promise { + const peers = await this.getPeers() + return peers.some(peer => peer.host.toLowerCase() === host.toLowerCase()) + } + + public async getPeers(): Promise { + const data = await this.firebase.ref('peers').once('value') + return (data.val() as Peer[]) || [] + } + + public async registerPeer(peer: Peer) { + if ( !(await this.hasPeer(peer.host)) ) { + await this.firebase.ref('peers').push().set(peer) + } + } + + public async validate(chain: Block[]) { + + } + + public async refresh() { + + } + + public async submitBlock(afterBlock: Block, proofToken: string) { + + } + + public async submitTransactions(group: [TransactionResourceItem, TransactionResourceItem]) { + // Not sure yet + } + + public async getLastBlock(): Promise { + const rec: BlockResourceItem | undefined = await BlockResource.collect().last() + return rec ? new Block(rec) : undefined + } + + public async up() { + + } + + public async down() { + + } +} diff --git a/src/app/units/FirebaseUnit.ts b/src/app/units/FirebaseUnit.ts index dee0e58..57e8b3b 100644 --- a/src/app/units/FirebaseUnit.ts +++ b/src/app/units/FirebaseUnit.ts @@ -2,7 +2,7 @@ import {Singleton, Inject} from "@extollo/di" import {Unit, Logging, Config} from "@extollo/lib" import * as firebase from "firebase-admin" -export type RTDBRef = 'peers' | 'transaction' +export type RTDBRef = 'peers' | 'transaction' | 'block' /** * FirebaseUnit Unit