Skip to content
This repository has been archived by the owner on Jul 18, 2020. It is now read-only.

Commit

Permalink
store all required fields to accounts table.
Browse files Browse the repository at this point in the history
  • Loading branch information
crchemist-ip committed Dec 3, 2019
1 parent 2e8f28d commit a1a26b8
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 27 deletions.
9 changes: 5 additions & 4 deletions migrations-shelley/1574938181811_add-accounts-table.js
Expand Up @@ -5,15 +5,16 @@ CREATE TABLE accounts (
epoch integer, epoch integer,
slot integer, slot integer,
tx_ordinal integer, tx_ordinal integer,
block_num integer, block_num bigint,
operation_id text UNIQUE, operation_id text,
operation_type integer, operation_type integer,
account text, account text,
value integer, value bigint,
balance integer, balance bigint,
spending_counter integer, spending_counter integer,
PRIMARY KEY (operation_id, account) PRIMARY KEY (operation_id, account)
); );
CREATE INDEX ON accounts (operation_id);
` `


exports.up = (pgm) => { exports.up = (pgm) => {
Expand Down
2 changes: 1 addition & 1 deletion src/blockchain/common/index.js
Expand Up @@ -3,7 +3,7 @@
export { Block } from './block' export { Block } from './block'
export type { EpochIdType, SlotIdType } from './block' export type { EpochIdType, SlotIdType } from './block'
export type { export type {
AccountInput, TxInputType, TxType, UtxoInput, AccountInputType, TxInputType, TxType, UtxoInputType,
} from './tx' } from './tx'
export { TX_STATUS } from './tx' export { TX_STATUS } from './tx'
export { default as utils } from './utils' export { default as utils } from './utils'
6 changes: 3 additions & 3 deletions src/blockchain/common/tx.js
Expand Up @@ -7,19 +7,19 @@
* features are added this will have to change. * features are added this will have to change.
*/ */


export type UtxoInput = { export type UtxoInputType = {
type: 'utxo', type: 'utxo',
txId: string, txId: string,
idx: number, idx: number,
} }


export type AccountInput = { export type AccountInputType = {
type: 'account', type: 'account',
account_id: string, account_id: string,
value: number, value: number,
} }


export type TxInputType = UtxoInput | AccountInput export type TxInputType = UtxoInputType | AccountInputType


export type TxOutputType = { export type TxOutputType = {
// derived from address, here for convenience // derived from address, here for convenience
Expand Down
2 changes: 2 additions & 0 deletions src/blockchain/shelley/block.js
Expand Up @@ -115,6 +115,8 @@ export default class ShelleyBlock implements Block {
txOrdinal: index, txOrdinal: index,
blockNum: chainLength, blockNum: chainLength,
blockHash, blockHash,
epoch: epochId,
slot: slotId,
} }
const fragment = fragments.get(index) const fragment = fragments.get(index)
if (fragment.is_transaction()) console.log(`#${index} = TRANSACTION`) if (fragment.is_transaction()) console.log(`#${index} = TRANSACTION`)
Expand Down
99 changes: 80 additions & 19 deletions src/entities/postgres-storage/db-shelley.js
Expand Up @@ -3,7 +3,11 @@
import _ from 'lodash' import _ from 'lodash'


import { CERT_TYPE } from '../../blockchain/shelley/certificate' import { CERT_TYPE } from '../../blockchain/shelley/certificate'
import type { ShelleyTxType as TxType } from '../../blockchain/shelley/tx' import type {
ShelleyTxType as TxType,
} from '../../blockchain/shelley/tx'

import type { AccountInputType, Block } from '../../blockchain/common'
import type { Database } from '../../interfaces' import type { Database } from '../../interfaces'


import DB from './database' import DB from './database'
Expand All @@ -12,6 +16,7 @@ import Q from './db-queries'


const DELEGATION_CERTIFICATES_TBL = 'delegation_certificates' const DELEGATION_CERTIFICATES_TBL = 'delegation_certificates'
const ACCOUNTS_TBL = 'accounts' const ACCOUNTS_TBL = 'accounts'
const ACCOUNT_INP_TYPE = 'account'


const ACCOUNT_OP_TYPE = { const ACCOUNT_OP_TYPE = {
REGULAR_TX: 0, REGULAR_TX: 0,
Expand Down Expand Up @@ -53,48 +58,104 @@ class DBShelley extends DB<TxType> implements Database<TxType> {
await this.getConn().query(sql) await this.getConn().query(sql)
} }


async getAccountDbData(accountInputs: Array<AccountInputType>): Promise<{
}> {
const accountIds = _.map(accountInputs, 'account_id')
const query = Q.sql.select()
.from(Q.sql.select()
.from(ACCOUNTS_TBL)
.where('account in ?', accountIds)
.order('account')
.order('spending_counter', false)
.distinct('account'), 't')
.order('spending_counter', false)
.toString()
const dbRes = await this.getConn().query(query)
let result = {}
for (const row of dbRes.rows) {
result = {
...result,
...{
[row.account]: {
balance: parseInt(row.balance, 10),
counter: parseInt(row.spending_counter, 10),
},
},
}
}
return result
}

async storeAccountsChanges(tx: TxType): Promise<void> { async storeAccountsChanges(tx: TxType): Promise<void> {
const accountInputs = tx.inputs.filter(inp => inp.type === 'account') const accountInputs = tx.inputs.filter(inp => inp.type === ACCOUNT_INP_TYPE)
const accountOutputs = tx.outputs.filter(out => out.type === 'account') const accountOutputs = tx.outputs.filter(out => out.type === ACCOUNT_INP_TYPE)
if (_.isEmpty([...accountInputs, ...accountOutputs])) { const allAccountIdsAndValues = [
...accountInputs,
...(accountOutputs).map(inp => ({
account_id: inp.address,
value: inp.value,
})),
]
if (_.isEmpty(allAccountIdsAndValues)) {
return return
} }


const accountsBalance = new Map<string, number>() const accountStoredData = await this.getAccountDbData(allAccountIdsAndValues)
accountInputs.forEach((account, counter) => {
const accountChanges = {}
accountInputs.forEach(account => {
const { account_id, value } = account const { account_id, value } = account
const currentBalance = accountsBalance.get(account_id) const currentChange = accountChanges[account_id]
if (currentBalance !== undefined) { if (currentChange !== undefined) {
accountsBalance.set(account_id, currentBalance - value) accountChanges[account_id] = {
value: currentChange - value,
counter: accountChanges[account_id] + 1,
}
} else { } else {
accountsBalance.set(account_id, 0 - value) accountChanges[account_id] = { value: 0 - value, counter: 1 }
} }
}) })


accountOutputs.forEach((account, counter) => { accountOutputs.forEach(account => {
const { address, value } = account const { address, value } = account
const currentBalance = accountsBalance.get(address) const currentChange = accountChanges[address]
if (currentBalance !== undefined) { if (currentChange !== undefined) {
accountsBalance.set(address, currentBalance + value) accountChanges[address] = {
value: currentChange + value,
counter: accountChanges[address].counter,
}
} else { } else {
accountsBalance.set(address, value) accountChanges[address] = { value, counter: 0 }
} }
}) })


const accountsData = [] const accountsData = []
for (const [account, balance] of accountsBalance) { for (const [account, data] of _.toPairs(accountChanges)) {
let previousBalance = 0
let previousCounter = 0
if (accountStoredData[account] !== undefined) {
previousBalance = accountStoredData[account].balance
previousCounter = accountStoredData[account].counter
}
accountsData.push({ accountsData.push({
account, epoch: tx.epoch,
balance: Math.ceil(balance / 100000), slot: tx.slot,
tx_ordinal: tx.txOrdinal,
block_num: tx.blockNum,
operation_id: tx.id,
operation_type: ACCOUNT_OP_TYPE.REGULAR_TX, operation_type: ACCOUNT_OP_TYPE.REGULAR_TX,
operation_id: `${account}:${tx.id}`, account,
value: data.value,
balance: previousBalance + data.value,
spending_counter: previousCounter + data.counter,
}) })
} }
const conn = this.getConn() const conn = this.getConn()
const sql = Q.sql.insert() const sql = Q.sql.insert()
.into(ACCOUNTS_TBL) .into(ACCOUNTS_TBL)
.setFieldsRows(accountsData) .setFieldsRows(accountsData)
.toString() .toString()
this.logger.debug('storeAccountsChanges', sql)
await conn.query(sql) await conn.query(sql)
} }


Expand Down
2 changes: 2 additions & 0 deletions src/entities/raw-data-parsers/shelley-data-parser.js
Expand Up @@ -33,6 +33,8 @@ class ShelleyDataParser implements RawDataParser {
parseTx(data: Buffer, extraData: { parseTx(data: Buffer, extraData: {
blockHash: ?string, blockHash: ?string,
blockNum: ?number, blockNum: ?number,
epoch: ?number,
slot: ?number,
txOrdinal: ?number, txOrdinal: ?number,
txTime: Date, txTime: Date,
}): TxType { }): TxType {
Expand Down

0 comments on commit a1a26b8

Please sign in to comment.