Basic infrastructure for remote peering

This commit is contained in:
Garrett Mills 2021-04-10 13:00:29 -05:00
parent 46131e2219
commit 313fdb65e9
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
4 changed files with 73 additions and 7 deletions

View File

@ -81,7 +81,7 @@ export class FirebaseResource<T extends FirebaseResourceItem> extends Iterable<T
// @ts-ignore // @ts-ignore
delete item.firebaseID delete item.firebaseID
collection.push(item) collection.push(this.filter(item))
return collection return collection
}) })
@ -123,4 +123,22 @@ export class FirebaseResource<T extends FirebaseResourceItem> extends Iterable<T
inst.refName = this.refName inst.refName = this.refName
return inst return inst
} }
filter(obj: {[key: string]: any}) {
for (let key in obj) {
if (obj[key] === undefined) {
delete obj[key]
continue
}
if (obj[key] && typeof obj[key] === "object") {
this.filter(obj[key])
if (!Object.keys(obj[key]).length) {
delete obj[key]
}
}
}
return obj
}
} }

View File

@ -6,6 +6,10 @@ export default {
base_url: env('BASE_URL', 'http://localhost:8000/'), base_url: env('BASE_URL', 'http://localhost:8000/'),
peers: [
// 'http://127.0.0.1:8100/',
],
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,

View File

@ -22,11 +22,11 @@ export class ServerGPGTokenVerify extends Middleware {
} }
// if single string // if single string
if (typeof(value) === 'string') { if (typeof(value) === 'string') {
this.verifyToken(value) this.verifyToken(Buffer.from(value, 'base64').toString('utf-8'))
return return
} else { // else an array of strings } else { // else an array of strings
for (const item of value) { for (const item of value) {
if (await this.verifyToken(item)) { if (await this.verifyToken(Buffer.from(item, 'base64').toString('utf-8'))) {
return return
} }
} }

View File

@ -144,6 +144,15 @@ export class Blockchain extends Unit {
protected isSubmitting: boolean = false protected isSubmitting: boolean = false
async up() {
const peers = this.config.get('server.peers')
for ( const peer of peers ) {
await this.registerPeer({
host: peer,
})
}
}
/** /**
* Returns true if the given host is registered as a peer. * Returns true if the given host is registered as a peer.
* @param host * @param host
@ -166,7 +175,7 @@ export class Blockchain extends Unit {
*/ */
public async getPeerSubmit(peer: Peer): Promise<Block[] | undefined> { public async getPeerSubmit(peer: Peer): Promise<Block[] | undefined> {
try { try {
const result = await axios.get(peer.host) const result = await axios.get(`${peer.host}api/v1/chain/submit`)
const blocks: unknown = result.data?.data?.records const blocks: unknown = result.data?.data?.records
if ( Array.isArray(blocks) && blocks.every(isBlockResourceItem) ) { if ( Array.isArray(blocks) && blocks.every(isBlockResourceItem) ) {
return blocks.map(x => new Block(x)) return blocks.map(x => new Block(x))
@ -182,6 +191,7 @@ export class Blockchain extends Unit {
*/ */
public async registerPeer(peer: Peer) { public async registerPeer(peer: Peer) {
if (!(await this.hasPeer(peer.host))) { if (!(await this.hasPeer(peer.host))) {
this.logging.info(`Registering peer: ${peer.host}`)
await (<PeerResource> this.make(PeerResource)).push({ await (<PeerResource> this.make(PeerResource)).push({
firebaseID: '', firebaseID: '',
seqID: -1, seqID: -1,
@ -189,7 +199,28 @@ export class Blockchain extends Unit {
host: peer.host, host: peer.host,
}) })
const header = this.config.get('app.api_server_header')
try {
console.log('return peering', [`${peer.host}api/v1/peer`, {
host: this.getBaseURL(),
}, {
headers: {
[header]: await this.getPeerToken(),
}
}])
await axios.post(`${peer.host}api/v1/peer`, {
host: this.getBaseURL(),
}, {
headers: {
[header]: await this.getPeerToken(),
}
})
this.refresh() this.refresh()
} catch (e) {
this.logging.error(e)
}
} }
} }
@ -289,7 +320,7 @@ export class Blockchain extends Unit {
await (<BlockResource>this.app().make(BlockResource)).push(block) await (<BlockResource>this.app().make(BlockResource)).push(block)
} else { } else {
await this.firebase.ref('block').transaction((_) => { await this.firebase.ref('block').transaction((_) => {
return time_x_blocks[min].map(x => x.toItem()) return (time_x_blocks[min] || []).map(x => x.toItem())
}) })
this.pendingSubmit = undefined this.pendingSubmit = undefined
@ -307,6 +338,7 @@ export class Blockchain extends Unit {
blocks.push(submit.toItem()) blocks.push(submit.toItem())
} }
this.refresh()
return blocks return blocks
} }
@ -404,6 +436,18 @@ export class Blockchain extends Unit {
return new Block(block)*/ return new Block(block)*/
} }
public async getPeerToken() {
const message = openpgp.Message.fromText("0000")
const privateKey = this.config.get("app.gpg.key.private")
return Buffer.from((await openpgp.sign({
message,
privateKeys: await openpgp.readKey({
armoredKey: privateKey
}),
})), 'utf-8').toString('base64')
}
/** /**
* Instantiate the genesis block of the entire chain. * Instantiate the genesis block of the entire chain.
*/ */
@ -513,7 +557,7 @@ export class Blockchain extends Unit {
*/ */
protected getBaseURL(): string { protected getBaseURL(): string {
const base = this.config.get('server.base_url') const base = this.config.get('server.base_url')
return `${base}${base.endsWith('/') ? '' : '/'}api/v1/chain/submit` return `${base}${base.endsWith('/') ? '' : '/'}`
} }
/** Sleep for (roughly) the given number of milliseconds. */ /** Sleep for (roughly) the given number of milliseconds. */