You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

90 lines
2.8 KiB

import { FirebaseUnit } from "../FirebaseUnit"
import { TransactionResource, TransactionResourceItem } from "../../rtdb/TransactionResource"
import { Singleton, Inject } from "@extollo/di"
import { Unit, Logging } from "@extollo/lib"
import * as openpgp from "openpgp"
import { Blockchain } from "../Blockchain"
/**
* Transaction Unit
* ---------------------------------------
* This unit listens for transactions created on the realtime database.
* When new ones come through, it matches them up, validates them, and pushes
* them onto this server's blockchain.
*/
@Singleton()
export class Transaction extends Unit {
@Inject()
protected readonly firebase!: FirebaseUnit
@Inject()
protected readonly blockchain!: Blockchain
@Inject()
protected readonly logging!: Logging
async compare(t1: TransactionResourceItem, t2: TransactionResourceItem) {
const [t2key, t1sig, t1key, t2sig] = await Promise.all([
openpgp.readKey({
armoredKey: t2.partnerPublicKey
}),
openpgp.readMessage({
armoredMessage: t1.validationSignature,
}),
openpgp.readKey({
armoredKey: t1.partnerPublicKey
}),
openpgp.readMessage({
armoredMessage: t2.validationSignature,
}),
])
const [r1, r2] = await Promise.all([
openpgp.verify({
publicKeys: t2key,
message: t1sig,
}),
openpgp.verify({
publicKeys: t1key,
message: t2sig,
}),
])
const [v1, v2] = await Promise.all([
r1.signatures[0]?.verified,
r2.signatures[0]?.verified
])
return v1 && v2
}
/**
* Subscribe to the transactions reference and wait for new transactions to be added.
*/
public async up() {
this.firebase.ref('transaction').on('value', snapshot => {
if ( !Array.isArray(snapshot.val()) || snapshot.val().length < 2 ) return;
let newSnapshot = [...snapshot.val()]
for ( const left of snapshot.val() ) {
for ( const right of snapshot.val() ) {
this.compare(left, right).then(match => {
if ( match ) {
this.blockchain.submitTransactions([left, right])
this.firebase.ref('transaction').child(left.key).remove()
this.firebase.ref('transaction').child(right.key).remove()
}
})
}
}
})
}
/**
* Release listeners and resources before shutdown.
*/
public async down() {
// Release all subscriptions before shutdown
this.firebase.ref("transaction").off()
}
}