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 {
|
export default {
|
||||||
debug: env('DEBUG_MODE', false),
|
debug: env('DEBUG_MODE', false),
|
||||||
|
|
||||||
|
base_url: env('BASE_URL', 'http://localhost:8000/'),
|
||||||
|
|
||||||
session: {
|
session: {
|
||||||
/* The implementation of @extollo/lib.Session that serves as the session backend. */
|
/* The implementation of @extollo/lib.Session that serves as the session backend. */
|
||||||
driver: MemorySession,
|
driver: MemorySession,
|
||||||
|
@ -58,6 +58,7 @@ export interface BlockResourceItem extends FirebaseResourceItem {
|
|||||||
proof: string; // the generated proof-of-work string
|
proof: string; // the generated proof-of-work string
|
||||||
timestamp: number; // millisecond unix timestamp when this block was created
|
timestamp: number; // millisecond unix timestamp when this block was created
|
||||||
waitTime: number; // number of milliseconds between last block and this one
|
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
|
lastBlockUUID: string
|
||||||
proof: string
|
proof: string
|
||||||
waitTime: number
|
waitTime: number
|
||||||
|
peer: string
|
||||||
|
|
||||||
get config(): Config {
|
get config(): Config {
|
||||||
return Application.getApplication().make(Config)
|
return Application.getApplication().make(Config)
|
||||||
@ -44,6 +45,7 @@ export class Block implements BlockResourceItem {
|
|||||||
this.proof = rec.proof
|
this.proof = rec.proof
|
||||||
this.timestamp = rec.timestamp
|
this.timestamp = rec.timestamp
|
||||||
this.waitTime = rec.waitTime
|
this.waitTime = rec.waitTime
|
||||||
|
this.peer = rec.peer
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns true if this is the genesis block. */
|
/** Returns true if this is the genesis block. */
|
||||||
@ -86,6 +88,7 @@ export class Block implements BlockResourceItem {
|
|||||||
proof: this.proof,
|
proof: this.proof,
|
||||||
timestamp: this.timestamp,
|
timestamp: this.timestamp,
|
||||||
waitTime: this.waitTime,
|
waitTime: this.waitTime,
|
||||||
|
peer: this.peer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +119,11 @@ export interface Peer {
|
|||||||
*/
|
*/
|
||||||
@Singleton()
|
@Singleton()
|
||||||
export class Blockchain extends Unit {
|
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()
|
@Inject()
|
||||||
protected readonly logging!: Logging
|
protected readonly logging!: Logging
|
||||||
|
|
||||||
@ -240,6 +248,7 @@ export class Blockchain extends Unit {
|
|||||||
|
|
||||||
const peers = await this.getPeers()
|
const peers = await this.getPeers()
|
||||||
const time_x_block: {[key: string]: Block} = {}
|
const time_x_block: {[key: string]: Block} = {}
|
||||||
|
const time_x_blocks: {[key: string]: Block[]} = {}
|
||||||
const time_x_peer: {[key: string]: Peer | true} = {}
|
const time_x_peer: {[key: string]: Peer | true} = {}
|
||||||
|
|
||||||
for ( const peer of peers ) {
|
for ( const peer of peers ) {
|
||||||
@ -248,7 +257,15 @@ export class Blockchain extends Unit {
|
|||||||
const block = blocks.reverse()[0]
|
const block = blocks.reverse()[0]
|
||||||
if ( !block || block.seqID === validSeqID || !block.seqID ) continue
|
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_block[block.waitTime] = block
|
||||||
|
time_x_blocks[block.waitTime] = blocks
|
||||||
time_x_peer[block.waitTime] = peer
|
time_x_peer[block.waitTime] = peer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,11 +283,15 @@ export class Blockchain extends Unit {
|
|||||||
const block = time_x_block[min]
|
const block = time_x_block[min]
|
||||||
const peer = time_x_peer[min]
|
const peer = time_x_peer[min]
|
||||||
|
|
||||||
await (<BlockResource>this.app().make(BlockResource)).push(block)
|
|
||||||
if ( peer === true ) {
|
if ( peer === true ) {
|
||||||
this.pendingSubmit = undefined
|
this.pendingSubmit = undefined
|
||||||
this.pendingTransactions = []
|
this.pendingTransactions = []
|
||||||
|
await (<BlockResource>this.app().make(BlockResource)).push(block)
|
||||||
} else {
|
} else {
|
||||||
|
await this.firebase.ref('block').transaction((_) => {
|
||||||
|
return time_x_blocks[min].map(x => x.toItem())
|
||||||
|
})
|
||||||
|
|
||||||
this.pendingSubmit = undefined
|
this.pendingSubmit = undefined
|
||||||
await this.attemptSubmit()
|
await this.attemptSubmit()
|
||||||
}
|
}
|
||||||
@ -292,7 +313,7 @@ export class Blockchain extends Unit {
|
|||||||
public async attemptSubmit() {
|
public async attemptSubmit() {
|
||||||
if ( !this.pendingSubmit && this.pendingTransactions.length ) {
|
if ( !this.pendingSubmit && this.pendingTransactions.length ) {
|
||||||
const lastBlock = await this.getLastBlock()
|
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 proof = await this.generateProofOfWork(lastBlock, waitTime)
|
||||||
|
|
||||||
const block: BlockResourceItem = {
|
const block: BlockResourceItem = {
|
||||||
@ -303,6 +324,7 @@ export class Blockchain extends Unit {
|
|||||||
lastBlockUUID: lastBlock!.uuid,
|
lastBlockUUID: lastBlock!.uuid,
|
||||||
proof,
|
proof,
|
||||||
waitTime,
|
waitTime,
|
||||||
|
peer: this.getBaseURL(),
|
||||||
|
|
||||||
firebaseID: '',
|
firebaseID: '',
|
||||||
seqID: -1,
|
seqID: -1,
|
||||||
@ -404,6 +426,7 @@ export class Blockchain extends Unit {
|
|||||||
firebaseID: '',
|
firebaseID: '',
|
||||||
seqID: -1,
|
seqID: -1,
|
||||||
waitTime: 0,
|
waitTime: 0,
|
||||||
|
peer: this.getBaseURL(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,6 +506,16 @@ export class Blockchain extends Unit {
|
|||||||
return !!(await result.signatures?.[0]?.verified)
|
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. */
|
/** Sleep for (roughly) the given number of milliseconds. */
|
||||||
async sleep(ms: number) {
|
async sleep(ms: number) {
|
||||||
await new Promise<void>(res => {
|
await new Promise<void>(res => {
|
||||||
|
Loading…
Reference in New Issue
Block a user