mirror of
https://github.com/hackku21/loc-chain-backend.git
synced 2024-10-27 20:34:03 +00:00
Add time-based penalty system for repeat block-pushers
This commit is contained in:
parent
9e4164632c
commit
8f34fd3be0
@ -4,6 +4,8 @@ import {LocalFilesystem, LocalFilesystemConfig} from "@extollo/util"
|
||||
export default {
|
||||
debug: env('DEBUG_MODE', false),
|
||||
|
||||
base_url: env('BASE_URL', 'http://localhost:8000/'),
|
||||
|
||||
session: {
|
||||
/* The implementation of @extollo/lib.Session that serves as the session backend. */
|
||||
driver: MemorySession,
|
||||
|
@ -58,6 +58,7 @@ export interface BlockResourceItem extends FirebaseResourceItem {
|
||||
proof: string; // the generated proof-of-work string
|
||||
timestamp: number; // millisecond unix timestamp when this block was created
|
||||
waitTime: number; // number of milliseconds between last block and this one
|
||||
peer: string; // the host URL of the peer that submitted this block
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,6 +29,7 @@ export class Block implements BlockResourceItem {
|
||||
lastBlockUUID: string
|
||||
proof: string
|
||||
waitTime: number
|
||||
peer: string
|
||||
|
||||
get config(): Config {
|
||||
return Application.getApplication().make(Config)
|
||||
@ -44,6 +45,7 @@ export class Block implements BlockResourceItem {
|
||||
this.proof = rec.proof
|
||||
this.timestamp = rec.timestamp
|
||||
this.waitTime = rec.waitTime
|
||||
this.peer = rec.peer
|
||||
}
|
||||
|
||||
/** Returns true if this is the genesis block. */
|
||||
@ -86,6 +88,7 @@ export class Block implements BlockResourceItem {
|
||||
proof: this.proof,
|
||||
timestamp: this.timestamp,
|
||||
waitTime: this.waitTime,
|
||||
peer: this.peer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,6 +119,11 @@ export interface Peer {
|
||||
*/
|
||||
@Singleton()
|
||||
export class Blockchain extends Unit {
|
||||
private readonly MIN_WAIT_TIME = 1000
|
||||
private readonly MAX_WAIT_TIME = 5000
|
||||
private readonly PENALTY_INTERVAL = 500
|
||||
private readonly MAX_PEERS_PENALTY = 10
|
||||
|
||||
@Inject()
|
||||
protected readonly logging!: Logging
|
||||
|
||||
@ -240,6 +248,7 @@ export class Blockchain extends Unit {
|
||||
|
||||
const peers = await this.getPeers()
|
||||
const time_x_block: {[key: string]: Block} = {}
|
||||
const time_x_blocks: {[key: string]: Block[]} = {}
|
||||
const time_x_peer: {[key: string]: Peer | true} = {}
|
||||
|
||||
for ( const peer of peers ) {
|
||||
@ -248,7 +257,15 @@ export class Blockchain extends Unit {
|
||||
const block = blocks.reverse()[0]
|
||||
if ( !block || block.seqID === validSeqID || !block.seqID ) continue
|
||||
|
||||
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
|
||||
time_x_peer[block.waitTime] = peer
|
||||
}
|
||||
}
|
||||
@ -266,11 +283,15 @@ export class Blockchain extends Unit {
|
||||
const block = time_x_block[min]
|
||||
const peer = time_x_peer[min]
|
||||
|
||||
await (<BlockResource>this.app().make(BlockResource)).push(block)
|
||||
if ( peer === true ) {
|
||||
this.pendingSubmit = undefined
|
||||
this.pendingTransactions = []
|
||||
await (<BlockResource>this.app().make(BlockResource)).push(block)
|
||||
} else {
|
||||
await this.firebase.ref('block').transaction((_) => {
|
||||
return time_x_blocks[min].map(x => x.toItem())
|
||||
})
|
||||
|
||||
this.pendingSubmit = undefined
|
||||
await this.attemptSubmit()
|
||||
}
|
||||
@ -292,7 +313,7 @@ export class Blockchain extends Unit {
|
||||
public async attemptSubmit() {
|
||||
if ( !this.pendingSubmit && this.pendingTransactions.length ) {
|
||||
const lastBlock = await this.getLastBlock()
|
||||
const waitTime = this.random(3000, 5000)
|
||||
const waitTime = this.random(this.MIN_WAIT_TIME, this.MAX_WAIT_TIME)
|
||||
const proof = await this.generateProofOfWork(lastBlock, waitTime)
|
||||
|
||||
const block: BlockResourceItem = {
|
||||
@ -303,6 +324,7 @@ export class Blockchain extends Unit {
|
||||
lastBlockUUID: lastBlock!.uuid,
|
||||
proof,
|
||||
waitTime,
|
||||
peer: this.getBaseURL(),
|
||||
|
||||
firebaseID: '',
|
||||
seqID: -1,
|
||||
@ -404,6 +426,7 @@ export class Blockchain extends Unit {
|
||||
firebaseID: '',
|
||||
seqID: -1,
|
||||
waitTime: 0,
|
||||
peer: this.getBaseURL(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -483,6 +506,16 @@ export class Blockchain extends Unit {
|
||||
return !!(await result.signatures?.[0]?.verified)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base URL that identifies this peer.
|
||||
* This should be the endpoint used to fetch the submitted blockchain.
|
||||
* @protected
|
||||
*/
|
||||
protected getBaseURL(): string {
|
||||
const base = this.config.get('server.base_url')
|
||||
return `${base}${base.endsWith('/') ? '' : '/'}api/v1/chain/submit`
|
||||
}
|
||||
|
||||
/** Sleep for (roughly) the given number of milliseconds. */
|
||||
async sleep(ms: number) {
|
||||
await new Promise<void>(res => {
|
||||
|
Loading…
Reference in New Issue
Block a user