Implement longest-block consensus algo

This commit is contained in:
Garrett Mills 2021-04-10 21:44:32 -05:00
parent 0580d2274f
commit 546663901a
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
3 changed files with 48 additions and 48 deletions

View File

@ -10,6 +10,7 @@ export interface BlockEncounterTransaction {
combinedHash: string; combinedHash: string;
timestamp: number; timestamp: number;
encodedGPSLocation: string; encodedGPSLocation: string;
uuid: string;
} }
/** /**
@ -18,6 +19,7 @@ export interface BlockEncounterTransaction {
export interface BlockInfectionTransaction { export interface BlockInfectionTransaction {
clientID: string; clientID: string;
timestamp: number; timestamp: number;
uuid: string;
} }
/** Union type of all possible block transactions. */ /** Union type of all possible block transactions. */

View File

@ -7,6 +7,7 @@ import {AsyncCollection} from "@extollo/util"
* Interface representing a client-submitted encounter transaction. * Interface representing a client-submitted encounter transaction.
*/ */
export interface ExposureResourceItem extends FirebaseResourceItem { export interface ExposureResourceItem extends FirebaseResourceItem {
uuid?: string;
clientID: string; // the exposed client's ID - used as one half of the hashes clientID: string; // the exposed client's ID - used as one half of the hashes
timestamp: number; // the unix-time in milliseconds when the interaction occurred timestamp: number; // the unix-time in milliseconds when the interaction occurred
} }

View File

@ -318,60 +318,49 @@ export class Blockchain extends Unit {
this.logging.debug('Called refresh().') this.logging.debug('Called refresh().')
const peers = this.getPeers() const peers = this.getPeers()
const time_x_block: {[key: string]: Block} = {} let longestChain: Block[] = []
const time_x_blocks: {[key: string]: Block[]} = {} const chains = await Promise.all(
const time_x_peer: {[key: string]: Peer | true} = {} peers.map(peer => this.getPeerSubmit(peer))
)
await Promise.all(peers.map(async peer => { for ( const chain of chains ) {
const blocks: Block[] | undefined = await this.getPeerSubmit(peer) if (
chain
if ( blocks && await this.validate(blocks) ) { && chain.length > longestChain.length
const block = blocks.slice(-1)[0] && await this.validate(chain)
if ( !block ) return // TODO fixme ) {
longestChain = chain
const penalty = blocks.slice(0, 10)
.map(block => block.peer === peer.host)
.filter(Boolean).length * this.PENALTY_INTERVAL
* (Math.min(peers.length, this.MAX_PEERS_PENALTY))
block.waitTime += penalty
time_x_block[block.waitTime] = block
time_x_blocks[block.waitTime] = blocks.reverse()
time_x_peer[block.waitTime] = peer
} else {
console.log('validation fail!')
} }
}))
console.log(time_x_blocks, time_x_peer, time_x_block)
const submitBlock = this.getSubmitBlock()
if ( submitBlock ) {
time_x_block[submitBlock.waitTime] = submitBlock
time_x_peer[submitBlock.waitTime] = true
} }
console.log('submit block', submitBlock) const submitted = this.getSubmitBlock()
if ( (this.approvedChain.length + (submitted ? 1 : 0)) > longestChain.length ) {
const min = Math.min(...Object.keys(time_x_block).map(parseFloat)) // Our chain is longer, so push the submit block onto it
const peer = time_x_peer[min] if ( submitted ) {
this.approvedChain.push(submitted)
console.log('peer?', peer)
if ( peer === true ) {
// Our version of the chain was accepted
this.approvedChain.push(submitBlock!)
this.pendingTransactions = [] this.pendingTransactions = []
} else if ( peer ) { }
// A different server's chain was accepted } else {
this.approvedChain = (time_x_blocks[min] || []).map(block => { const temp: Block[] = this.approvedChain.reverse()
if (!block.transactions) { this.approvedChain = longestChain.map(x => {
block.transactions = [] if ( !x.transactions ) {
x.transactions = []
} }
return block return x
}) })
for ( const block of temp ) {
const found = this.approvedChain.some(otherBlock => {
return otherBlock.uuid === block.uuid
})
if ( !found ) {
this.pendingTransactions.concat(...(block.transactions || []))
} else {
break
}
}
} }
console.log('approved chain', this.approvedChain) console.log('approved chain', this.approvedChain)
@ -443,7 +432,14 @@ export class Blockchain extends Unit {
* @param exposures * @param exposures
*/ */
public submitExposures(...exposures: ExposureResourceItem[]) { public submitExposures(...exposures: ExposureResourceItem[]) {
this.pendingTransactions.push(...exposures) // @ts-ignore
this.pendingTransactions.push(...exposures.map(exposure => {
if ( !exposure.uuid ) {
exposure.uuid = uuid_v4()
}
return exposure
}))
} }
/** /**
@ -503,6 +499,7 @@ export class Blockchain extends Unit {
*/ */
protected getEncounterTransaction(item: TransactionResourceItem): BlockEncounterTransaction { protected getEncounterTransaction(item: TransactionResourceItem): BlockEncounterTransaction {
return { return {
uuid: uuid_v4(),
combinedHash: item.combinedHash, combinedHash: item.combinedHash,
timestamp: item.timestamp, timestamp: item.timestamp,
encodedGPSLocation: item.encodedGPSLocation, encodedGPSLocation: item.encodedGPSLocation,