Skip to content

Commit

Permalink
Remove duplication in transaction data in cache
Browse files Browse the repository at this point in the history
  • Loading branch information
jcramer committed Feb 7, 2019
1 parent 1c1e6db commit 0e709dd
Showing 1 changed file with 38 additions and 42 deletions.
80 changes: 38 additions & 42 deletions lib/localvalidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import * as bitcore from 'bitcore-lib-cash';
import { BitcoreTransaction } from './global';
import BigNumber from 'bignumber.js';

export interface Validation { hex: string|null; validity: boolean|null; parents: Parent[], details: SlpTransactionDetails|null, invalidReason: string|null }
export type GetRawTransactionsAsync = (txid: string[]) => Promise<string[]|null>;
export interface Validation { validity: boolean|null; parents: Parent[], details: SlpTransactionDetails|null, invalidReason: string|null }
export type GetRawTransactionsAsync = (txid: string[]) => Promise<(string|null)[]>;

const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))

Expand Down Expand Up @@ -39,7 +39,7 @@ export class LocalValidator implements SlpValidator {
addValidationFromStore(hex: string, isValid: boolean) {
let id = (<Buffer>this.BITBOX.Crypto.sha256(this.BITBOX.Crypto.sha256(Buffer.from(hex, 'hex'))).reverse()).toString('hex');
if(!this.cachedValidations[id])
this.cachedValidations[id] = { hex: hex, validity: isValid, parents: [], details: null, invalidReason: null }
this.cachedValidations[id] = { validity: isValid, parents: [], details: null, invalidReason: null }
if(!this.cachedRawTransactions[id])
this.cachedRawTransactions[id] = hex;
}
Expand All @@ -58,15 +58,15 @@ export class LocalValidator implements SlpValidator {
async waitForTransactionPreProcessing(txid: string){
// TODO: Add some timeout?
while(true) {
if(this.cachedValidations[txid].hex && (this.cachedValidations[txid].details || typeof this.cachedValidations.validity === 'boolean'))
if(this.cachedRawTransactions[txid] && (this.cachedValidations[txid].details || typeof this.cachedValidations.validity === 'boolean'))
break
await sleep(10);
}
//await sleep(100); // short wait to make sure parent's properties gets set first.
return
}

async getRawTransaction(txid: string) {
async retrieveRawTransaction(txid: string) {
if(this.cachedRawTransactions[txid])
return this.cachedRawTransactions[txid];
this.cachedRawTransactions[txid] = (await this.getRawTransactions([txid]))[0]
Expand All @@ -81,20 +81,20 @@ export class LocalValidator implements SlpValidator {

async isValidSlpTxid(txid: string) {
if(txid && !this.cachedValidations[txid]) {
this.cachedValidations[txid] = { hex: null, validity: null, parents: [], details: null, invalidReason: null }
this.cachedValidations[txid].hex = await this.getRawTransaction(txid);
this.cachedValidations[txid] = { validity: null, parents: [], details: null, invalidReason: null }
await this.retrieveRawTransaction(txid);
}

// Check to see how we should proceed based on the validation-cache state
if(!this.cachedValidations[txid].hex)
if(!this.cachedRawTransactions[txid])
await this.waitForTransactionPreProcessing(txid);
if(typeof this.cachedValidations[txid].validity === 'boolean')
return this.cachedValidations[txid].validity;
if(this.cachedValidations[txid].details)
await this.waitForCurrentValidationProcessing(txid);

// Check SLP message validity
let txn: BitcoreTransaction = new bitcore.Transaction(this.cachedValidations[txid].hex)
let txn: BitcoreTransaction = new bitcore.Transaction(this.cachedRawTransactions[txid])
let slpmsg: SlpTransactionDetails;
try {
slpmsg = this.cachedValidations[txid].details = this.slp.parseSlpOutputScript(txn.outputs[0]._scriptBuffer)
Expand All @@ -110,21 +110,19 @@ export class LocalValidator implements SlpValidator {
else if (slpmsg.transactionType === SlpTransactionType.MINT) {
for(let i = 0; i < txn.inputs.length; i++) {
let input_txid = txn.inputs[i].prevTxId.toString('hex')
let input_txhex = await this.getRawTransaction(input_txid)
if (input_txhex) {
let input_tx: BitcoreTransaction = new bitcore.Transaction(input_txhex);
try {
let input_slpmsg = this.slp.parseSlpOutputScript(input_tx.outputs[0]._scriptBuffer)
if(input_slpmsg.transactionType === SlpTransactionType.GENESIS)
input_slpmsg.tokenIdHex = input_txid;
if(input_slpmsg.tokenIdHex === slpmsg.tokenIdHex) {
if(input_slpmsg.transactionType === SlpTransactionType.GENESIS || input_slpmsg.transactionType === SlpTransactionType.MINT) {
if(txn.inputs[i].outputIndex === input_slpmsg.batonVout)
this.cachedValidations[txid].parents.push({ txid: txn.inputs[i].prevTxId.toString('hex'), versionType: input_slpmsg.versionType ,valid: null, inputQty: null })
}
let input_txhex = await this.retrieveRawTransaction(input_txid)
let input_tx: BitcoreTransaction = new bitcore.Transaction(input_txhex);
try {
let input_slpmsg = this.slp.parseSlpOutputScript(input_tx.outputs[0]._scriptBuffer)
if(input_slpmsg.transactionType === SlpTransactionType.GENESIS)
input_slpmsg.tokenIdHex = input_txid;
if(input_slpmsg.tokenIdHex === slpmsg.tokenIdHex) {
if(input_slpmsg.transactionType === SlpTransactionType.GENESIS || input_slpmsg.transactionType === SlpTransactionType.MINT) {
if(txn.inputs[i].outputIndex === input_slpmsg.batonVout)
this.cachedValidations[txid].parents.push({ txid: txn.inputs[i].prevTxId.toString('hex'), versionType: input_slpmsg.versionType ,valid: null, inputQty: null })
}
} catch(_) {}
}
}
} catch(_) {}
}
if(this.cachedValidations[txid].parents.length !== 1) {
this.cachedValidations[txid].invalidReason = "MINT transaction must have 1 valid baton parent."
Expand All @@ -136,26 +134,24 @@ export class LocalValidator implements SlpValidator {
let tokenInQty = new BigNumber(0);
for(let i = 0; i < txn.inputs.length; i++) {
let input_txid = txn.inputs[i].prevTxId.toString('hex')
let input_txhex = await this.getRawTransaction(input_txid)
if (input_txhex) {
let input_tx: BitcoreTransaction = new bitcore.Transaction(input_txhex);
try {
let input_slpmsg = this.slp.parseSlpOutputScript(input_tx.outputs[0]._scriptBuffer)
if(input_slpmsg.transactionType === SlpTransactionType.GENESIS)
input_slpmsg.tokenIdHex = input_txid;
if(input_slpmsg.tokenIdHex === slpmsg.tokenIdHex) {
if(input_slpmsg.transactionType === SlpTransactionType.SEND) {
tokenInQty = tokenInQty.plus(input_slpmsg.sendOutputs[txn.inputs[i].outputIndex])
this.cachedValidations[txid].parents.push({txid: txn.inputs[i].prevTxId.toString('hex'), versionType: input_slpmsg.versionType, valid: null, inputQty: input_slpmsg.sendOutputs[txn.inputs[i].outputIndex] })
}
else if(input_slpmsg.transactionType === SlpTransactionType.GENESIS || input_slpmsg.transactionType === SlpTransactionType.MINT) {
if(txn.inputs[i].outputIndex === 1)
tokenInQty = tokenInQty.plus(input_slpmsg.genesisOrMintQuantity)
this.cachedValidations[txid].parents.push({txid: txn.inputs[i].prevTxId.toString('hex'), versionType: input_slpmsg.versionType, valid: null, inputQty: input_slpmsg.genesisOrMintQuantity })
}
let input_txhex = await this.retrieveRawTransaction(input_txid)
let input_tx: BitcoreTransaction = new bitcore.Transaction(input_txhex);
try {
let input_slpmsg = this.slp.parseSlpOutputScript(input_tx.outputs[0]._scriptBuffer)
if(input_slpmsg.transactionType === SlpTransactionType.GENESIS)
input_slpmsg.tokenIdHex = input_txid;
if(input_slpmsg.tokenIdHex === slpmsg.tokenIdHex) {
if(input_slpmsg.transactionType === SlpTransactionType.SEND) {
tokenInQty = tokenInQty.plus(input_slpmsg.sendOutputs[txn.inputs[i].outputIndex])
this.cachedValidations[txid].parents.push({txid: txn.inputs[i].prevTxId.toString('hex'), versionType: input_slpmsg.versionType, valid: null, inputQty: input_slpmsg.sendOutputs[txn.inputs[i].outputIndex] })
}
} catch(_) {}
}
else if(input_slpmsg.transactionType === SlpTransactionType.GENESIS || input_slpmsg.transactionType === SlpTransactionType.MINT) {
if(txn.inputs[i].outputIndex === 1)
tokenInQty = tokenInQty.plus(input_slpmsg.genesisOrMintQuantity)
this.cachedValidations[txid].parents.push({txid: txn.inputs[i].prevTxId.toString('hex'), versionType: input_slpmsg.versionType, valid: null, inputQty: input_slpmsg.genesisOrMintQuantity })
}
}
} catch(_) {}
}

// Check token inputs are greater than token outputs (includes valid and invalid inputs)
Expand Down

0 comments on commit 0e709dd

Please sign in to comment.