Skip to content
Permalink
Browse files

store all required fields to accounts table.

  • Loading branch information
crchemist-ip committed Dec 3, 2019
1 parent 2e8f28d commit a1a26b800a63de58c7be55fa199afaa82cbdb5b5
@@ -5,15 +5,16 @@ CREATE TABLE accounts (
epoch integer,
slot integer,
tx_ordinal integer,
block_num integer,
operation_id text UNIQUE,
block_num bigint,
operation_id text,
operation_type integer,
account text,
value integer,
balance integer,
value bigint,
balance bigint,
spending_counter integer,
PRIMARY KEY (operation_id, account)
);
CREATE INDEX ON accounts (operation_id);
`

exports.up = (pgm) => {
@@ -3,7 +3,7 @@
export { Block } from './block'
export type { EpochIdType, SlotIdType } from './block'
export type {
AccountInput, TxInputType, TxType, UtxoInput,
AccountInputType, TxInputType, TxType, UtxoInputType,
} from './tx'
export { TX_STATUS } from './tx'
export { default as utils } from './utils'
@@ -7,19 +7,19 @@
* features are added this will have to change.
*/

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

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

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

export type TxOutputType = {
// derived from address, here for convenience
@@ -115,6 +115,8 @@ export default class ShelleyBlock implements Block {
txOrdinal: index,
blockNum: chainLength,
blockHash,
epoch: epochId,
slot: slotId,
}
const fragment = fragments.get(index)
if (fragment.is_transaction()) console.log(`#${index} = TRANSACTION`)
@@ -3,7 +3,11 @@
import _ from 'lodash'

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 DB from './database'
@@ -12,6 +16,7 @@ import Q from './db-queries'

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

const ACCOUNT_OP_TYPE = {
REGULAR_TX: 0,
@@ -53,48 +58,104 @@ class DBShelley extends DB<TxType> implements Database<TxType> {
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> {
const accountInputs = tx.inputs.filter(inp => inp.type === 'account')
const accountOutputs = tx.outputs.filter(out => out.type === 'account')
if (_.isEmpty([...accountInputs, ...accountOutputs])) {
const accountInputs = tx.inputs.filter(inp => inp.type === ACCOUNT_INP_TYPE)
const accountOutputs = tx.outputs.filter(out => out.type === ACCOUNT_INP_TYPE)
const allAccountIdsAndValues = [
...accountInputs,
...(accountOutputs).map(inp => ({
account_id: inp.address,
value: inp.value,
})),
]
if (_.isEmpty(allAccountIdsAndValues)) {
return
}

const accountsBalance = new Map<string, number>()
accountInputs.forEach((account, counter) => {
const accountStoredData = await this.getAccountDbData(allAccountIdsAndValues)

const accountChanges = {}
accountInputs.forEach(account => {
const { account_id, value } = account
const currentBalance = accountsBalance.get(account_id)
if (currentBalance !== undefined) {
accountsBalance.set(account_id, currentBalance - value)
const currentChange = accountChanges[account_id]
if (currentChange !== undefined) {
accountChanges[account_id] = {
value: currentChange - value,
counter: accountChanges[account_id] + 1,
}
} 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 currentBalance = accountsBalance.get(address)
if (currentBalance !== undefined) {
accountsBalance.set(address, currentBalance + value)
const currentChange = accountChanges[address]
if (currentChange !== undefined) {
accountChanges[address] = {
value: currentChange + value,
counter: accountChanges[address].counter,
}
} else {
accountsBalance.set(address, value)
accountChanges[address] = { value, counter: 0 }
}
})

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({
account,
balance: Math.ceil(balance / 100000),
epoch: tx.epoch,
slot: tx.slot,
tx_ordinal: tx.txOrdinal,
block_num: tx.blockNum,
operation_id: tx.id,
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 sql = Q.sql.insert()
.into(ACCOUNTS_TBL)
.setFieldsRows(accountsData)
.toString()
this.logger.debug('storeAccountsChanges', sql)
await conn.query(sql)
}

@@ -33,6 +33,8 @@ class ShelleyDataParser implements RawDataParser {
parseTx(data: Buffer, extraData: {
blockHash: ?string,
blockNum: ?number,
epoch: ?number,
slot: ?number,
txOrdinal: ?number,
txTime: Date,
}): TxType {

0 comments on commit a1a26b8

Please sign in to comment.
You can’t perform that action at this time.