mirror of
				https://github.com/hackku21/loc-chain-backend.git
				synced 2025-06-13 12:53:59 +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