2021-04-10 09:23:54 +00:00
|
|
|
import { FirebaseUnit } from "../FirebaseUnit"
|
|
|
|
import { TransactionResource, TransactionResourceItem } from "../../rtdb/TransactionResource"
|
|
|
|
import { Singleton, Inject } from "@extollo/di"
|
|
|
|
import { Unit, Logging } from "@extollo/lib"
|
2021-04-10 07:15:54 +00:00
|
|
|
import * as openpgp from "openpgp"
|
2021-04-10 09:23:54 +00:00
|
|
|
import { Blockchain } from "../Blockchain"
|
2021-04-10 07:30:39 +00:00
|
|
|
|
2021-04-10 07:15:54 +00:00
|
|
|
/**
|
|
|
|
* Transaction Unit
|
|
|
|
* ---------------------------------------
|
2021-04-10 12:26:42 +00:00
|
|
|
* 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.
|
2021-04-10 07:15:54 +00:00
|
|
|
*/
|
|
|
|
@Singleton()
|
|
|
|
export class Transaction extends Unit {
|
|
|
|
@Inject()
|
|
|
|
protected readonly firebase!: FirebaseUnit
|
|
|
|
|
2021-04-10 07:30:39 +00:00
|
|
|
@Inject()
|
|
|
|
protected readonly blockchain!: Blockchain
|
|
|
|
|
2021-04-10 12:12:03 +00:00
|
|
|
@Inject()
|
|
|
|
protected readonly logging!: Logging
|
|
|
|
|
2021-04-11 01:35:29 +00:00
|
|
|
async compare(t1: TransactionResourceItem, t2: TransactionResourceItem) {
|
|
|
|
const [t2key, t1sig, t1key, t2sig] = await Promise.all([
|
|
|
|
openpgp.readKey({
|
|
|
|
armoredKey: t2.partnerPublicKey
|
2021-04-10 07:15:54 +00:00
|
|
|
}),
|
2021-04-11 01:35:29 +00:00
|
|
|
openpgp.readMessage({
|
|
|
|
armoredMessage: t1.validationSignature,
|
2021-04-10 12:12:03 +00:00
|
|
|
}),
|
2021-04-11 01:35:29 +00:00
|
|
|
openpgp.readKey({
|
|
|
|
armoredKey: t1.partnerPublicKey
|
|
|
|
}),
|
|
|
|
openpgp.readMessage({
|
|
|
|
armoredMessage: t2.validationSignature,
|
|
|
|
}),
|
|
|
|
])
|
2021-04-10 12:12:03 +00:00
|
|
|
|
2021-04-11 01:35:29 +00:00
|
|
|
const [r1, r2] = await Promise.all([
|
|
|
|
openpgp.verify({
|
|
|
|
publicKeys: t2key,
|
|
|
|
message: t1sig,
|
2021-04-10 07:15:54 +00:00
|
|
|
}),
|
2021-04-11 01:35:29 +00:00
|
|
|
openpgp.verify({
|
|
|
|
publicKeys: t1key,
|
|
|
|
message: t2sig,
|
2021-04-10 12:12:03 +00:00
|
|
|
}),
|
2021-04-11 01:35:29 +00:00
|
|
|
])
|
|
|
|
|
|
|
|
const [v1, v2] = await Promise.all([
|
|
|
|
r1.signatures[0]?.verified,
|
|
|
|
r2.signatures[0]?.verified
|
|
|
|
])
|
2021-04-10 12:12:03 +00:00
|
|
|
|
2021-04-11 01:35:29 +00:00
|
|
|
return v1 && v2
|
2021-04-10 07:15:54 +00:00
|
|
|
}
|
2021-04-10 09:23:54 +00:00
|
|
|
|
2021-04-10 12:26:42 +00:00
|
|
|
/**
|
|
|
|
* Subscribe to the transactions reference and wait for new transactions to be added.
|
|
|
|
*/
|
2021-04-10 07:15:54 +00:00
|
|
|
public async up() {
|
2021-04-11 01:35:29 +00:00
|
|
|
this.firebase.ref('transaction').on('value', snapshot => {
|
|
|
|
if ( !Array.isArray(snapshot.val()) || snapshot.val().length < 2 ) return;
|
2021-04-11 02:03:23 +00:00
|
|
|
let newSnapshot = [...snapshot.val()]
|
2021-04-11 01:35:29 +00:00
|
|
|
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])
|
2021-04-11 02:03:23 +00:00
|
|
|
newSnapshot = newSnapshot.filter( (item) => item !== left && item !== right )
|
2021-04-11 01:35:29 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-04-11 02:03:23 +00:00
|
|
|
this.firebase.ref('transaction').set(newSnapshot)
|
2021-04-11 01:35:29 +00:00
|
|
|
})
|
2021-04-10 07:15:54 +00:00
|
|
|
}
|
2021-04-10 09:23:54 +00:00
|
|
|
|
2021-04-10 12:26:42 +00:00
|
|
|
/**
|
|
|
|
* Release listeners and resources before shutdown.
|
|
|
|
*/
|
2021-04-10 07:15:54 +00:00
|
|
|
public async down() {
|
2021-04-10 12:12:03 +00:00
|
|
|
// Release all subscriptions before shutdown
|
|
|
|
this.firebase.ref("transaction").off()
|
2021-04-10 07:15:54 +00:00
|
|
|
}
|
|
|
|
}
|