Update transaction counts beyond page one and cleanup pending transaction behavior

pull/816/head
Stamates 6 years ago
parent 50b164629e
commit 61ee2b8ef8
  1. 50
      apps/block_scout_web/assets/__tests__/pages/address.js
  2. 47
      apps/block_scout_web/assets/js/pages/address.js
  3. 5
      apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex

@ -6,15 +6,13 @@ describe('PAGE_LOAD', () => {
const action = { const action = {
type: 'PAGE_LOAD', type: 'PAGE_LOAD',
addressHash: '1234', addressHash: '1234',
beyondPageOne: false, beyondPageOne: false
pendingTransactionHashes: ['0x00']
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.addressHash).toBe('1234') expect(output.addressHash).toBe('1234')
expect(output.beyondPageOne).toBe(false) expect(output.beyondPageOne).toBe(false)
expect(output.filter).toBe(undefined) expect(output.filter).toBe(undefined)
expect(output.pendingTransactionHashes).toEqual(['0x00'])
}) })
test('page 2 without filter', () => { test('page 2 without filter', () => {
const state = initialState const state = initialState
@ -96,7 +94,6 @@ describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual(['test']) expect(output.newPendingTransactions).toEqual(['test'])
expect(output.pendingTransactionHashes).toEqual(['0x00'])
expect(output.batchCountAccumulator).toEqual(0) expect(output.batchCountAccumulator).toEqual(0)
expect(output.transactionCount).toEqual(null) expect(output.transactionCount).toEqual(null)
}) })
@ -142,17 +139,15 @@ describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([]) expect(output.newPendingTransactions).toEqual([])
expect(output.pendingTransactionHashes).toEqual([ expect(output.newPendingTransactionHashesBatch).toEqual([
"0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x10", "0x11" "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x10", "0x11"
]) ])
expect(output.batchPendingCountAccumulator).toEqual(11)
expect(output.batchCountAccumulator).toEqual(0) expect(output.batchCountAccumulator).toEqual(0)
expect(output.transactionCount).toEqual(null) expect(output.transactionCount).toEqual(null)
}) })
test('single transaction after single transaction', () => { test('single transaction after single transaction', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
newPendingTransactions: ['test 1'], newPendingTransactions: ['test 1']
pendingTransactionHashes: ['0x01']
}) })
const action = { const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
@ -164,13 +159,13 @@ describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual(['test 1', 'test 2']) expect(output.newPendingTransactions).toEqual(['test 1', 'test 2'])
expect(output.pendingTransactionHashes).toEqual(['0x01', '0x02']) expect(output.newPendingTransactionHashesBatch.length).toEqual(0)
expect(output.batchPendingCountAccumulator).toEqual(0)
}) })
test('single transaction after large batch of transactions', () => { test('single transaction after large batch of transactions', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
newTransactions: [], newPendingTransactionHashesBatch: [
batchPendingCountAccumulator: 11 "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x10", "0x11"
]
}) })
const action = { const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
@ -182,13 +177,14 @@ describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([]) expect(output.newPendingTransactions).toEqual([])
expect(output.pendingTransactionHashes).toEqual(['0x12']) expect(output.newPendingTransactionHashesBatch.length).toEqual(12)
expect(output.batchPendingCountAccumulator).toEqual(12) expect(output.newPendingTransactionHashesBatch).toContain('0x12')
}) })
test('large batch of transactions after large batch of transactions', () => { test('large batch of transactions after large batch of transactions', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
newPendingTransactions: [], newPendingTransactionHashesBatch: [
batchPendingCountAccumulator: 11 "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x10", "0x11"
]
}) })
const action = { const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
@ -230,8 +226,7 @@ describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([]) expect(output.newPendingTransactions).toEqual([])
expect(output.pendingTransactionHashes.length).toBe(11) expect(output.newPendingTransactionHashesBatch.length).toEqual(22)
expect(output.batchPendingCountAccumulator).toEqual(22)
}) })
test('after disconnection', () => { test('after disconnection', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
@ -247,8 +242,7 @@ describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([]) expect(output.newPendingTransactions).toEqual([])
expect(output.pendingTransactionHashes).toEqual([]) expect(output.newPendingTransactionHashesBatch).toEqual([])
expect(output.batchPendingCountAccumulator).toEqual(0)
}) })
test('on page 2', () => { test('on page 2', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
@ -264,7 +258,7 @@ describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([]) expect(output.newPendingTransactions).toEqual([])
expect(output.pendingTransactionHashes).toEqual([]) expect(output.newPendingTransactionHashesBatch).toEqual([])
expect(output.batchCountAccumulator).toEqual(0) expect(output.batchCountAccumulator).toEqual(0)
}) })
}) })
@ -402,7 +396,8 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
}) })
test('on page 2', () => { test('on page 2', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
beyondPageOne: true beyondPageOne: true,
transactionCount: 1
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION_BATCH',
@ -414,6 +409,7 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
expect(output.newTransactions).toEqual([]) expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(0) expect(output.batchCountAccumulator).toEqual(0)
expect(output.transactionCount).toEqual(2)
}) })
test('transaction from current address with "from" filter', () => { test('transaction from current address with "from" filter', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
@ -480,9 +476,7 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
expect(output.newTransactions).toEqual([]) expect(output.newTransactions).toEqual([])
}) })
test('single transaction collated from pending', () => { test('single transaction collated from pending', () => {
const state = Object.assign({}, initialState, { const state = initialState
pendingTransactionHashes: ['0x00']
})
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{ msgs: [{
@ -493,14 +487,11 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual(['test']) expect(output.newTransactions).toEqual(['test'])
expect(output.pendingTransactionHashes).toEqual([])
expect(output.batchCountAccumulator).toEqual(0) expect(output.batchCountAccumulator).toEqual(0)
expect(output.transactionCount).toEqual(1) expect(output.transactionCount).toEqual(1)
}) })
test('large batch of transactions', () => { test('large batch of transactions', () => {
const state = Object.assign({}, initialState, { const state = initialState
pendingTransactionHashes: ['0x01', '0x02', '0x12']
})
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{ msgs: [{
@ -541,7 +532,6 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual([]) expect(output.newTransactions).toEqual([])
expect(output.pendingTransactionHashes).toEqual(['0x12'])
expect(output.transactionCount).toEqual(11) expect(output.transactionCount).toEqual(11)
}) })
}) })

@ -15,7 +15,6 @@ export const initialState = {
addressHash: null, addressHash: null,
balance: null, balance: null,
batchCountAccumulator: 0, batchCountAccumulator: 0,
batchPendingCountAccumulator: 0,
beyondPageOne: null, beyondPageOne: null,
channelDisconnected: false, channelDisconnected: false,
filter: null, filter: null,
@ -23,7 +22,7 @@ export const initialState = {
newPendingTransactions: [], newPendingTransactions: [],
newTransactions: [], newTransactions: [],
newTransactionHashes: [], newTransactionHashes: [],
pendingTransactionHashes: [], newPendingTransactionHashesBatch: [],
transactionCount: null transactionCount: null
} }
@ -34,7 +33,6 @@ export function reducer (state = initialState, action) {
addressHash: action.addressHash, addressHash: action.addressHash,
beyondPageOne: action.beyondPageOne, beyondPageOne: action.beyondPageOne,
filter: action.filter, filter: action.filter,
pendingTransactionHashes: action.pendingTransactionHashes,
transactionCount: numeral(action.transactionCount).value() transactionCount: numeral(action.transactionCount).value()
}) })
} }
@ -83,29 +81,28 @@ export function reducer (state = initialState, action) {
(state.filter === 'to' && toAddressHash === state.addressHash) || (state.filter === 'to' && toAddressHash === state.addressHash) ||
(state.filter === 'from' && fromAddressHash === state.addressHash) (state.filter === 'from' && fromAddressHash === state.addressHash)
)) ))
if (!state.batchPendingCountAccumulator && incomingPendingTransactions.length < BATCH_THRESHOLD) { if (!state.newPendingTransactionHashesBatch.length && incomingPendingTransactions.length < BATCH_THRESHOLD) {
return Object.assign({}, state, { return Object.assign({}, state, {
newPendingTransactions: [ newPendingTransactions: [
...state.newPendingTransactions, ...state.newPendingTransactions,
..._.map(incomingPendingTransactions, 'transactionHtml') ..._.map(incomingPendingTransactions, 'transactionHtml')
],
pendingTransactionHashes: [
...state.pendingTransactionHashes,
..._.map(incomingPendingTransactions, 'transactionHash')
] ]
}) })
} else { } else {
return Object.assign({}, state, { return Object.assign({}, state, {
batchPendingCountAccumulator: state.batchPendingCountAccumulator + incomingPendingTransactions.length, newPendingTransactionHashesBatch: [
pendingTransactionHashes: [ ...state.newPendingTransactionHashesBatch,
...state.pendingTransactionHashes,
..._.map(incomingPendingTransactions, 'transactionHash') ..._.map(incomingPendingTransactions, 'transactionHash')
] ]
}) })
} }
} }
case 'RECEIVED_NEW_TRANSACTION_BATCH': { case 'RECEIVED_NEW_TRANSACTION_BATCH': {
if (state.channelDisconnected || state.beyondPageOne) return state if (state.channelDisconnected) return state
const transactionCount = state.transactionCount + action.msgs.length
if (state.beyondPageOne) return Object.assign({}, state, { transactionCount })
const incomingTransactions = humps.camelizeKeys(action.msgs) const incomingTransactions = humps.camelizeKeys(action.msgs)
.filter(({toAddressHash, fromAddressHash}) => ( .filter(({toAddressHash, fromAddressHash}) => (
@ -114,27 +111,25 @@ export function reducer (state = initialState, action) {
(state.filter === 'from' && fromAddressHash === state.addressHash) (state.filter === 'from' && fromAddressHash === state.addressHash)
)) ))
const updatePendingTransactionHashes = const updatedPendingTransactionHashesBatch =
_.difference(state.pendingTransactionHashes, _.map(incomingTransactions, 'transactionHash')) _.difference(state.newPendingTransactionHashesBatch, _.map(incomingTransactions, 'transactionHash'))
if (!state.batchCountAccumulator && incomingTransactions.length < BATCH_THRESHOLD) { if (!state.batchCountAccumulator && incomingTransactions.length < BATCH_THRESHOLD) {
return Object.assign({}, state, { return Object.assign({}, state, {
batchPendingCountAccumulator: state.batchPendingCountAccumulator - incomingTransactions.length,
newTransactions: [ newTransactions: [
...state.newTransactions, ...state.newTransactions,
..._.map(incomingTransactions, 'transactionHtml') ..._.map(incomingTransactions, 'transactionHtml')
], ],
newTransactionHashes: _.map(incomingTransactions, 'transactionHash'), newTransactionHashes: _.map(incomingTransactions, 'transactionHash'),
pendingTransactionHashes: updatePendingTransactionHashes, newPendingTransactionHashesBatch: updatedPendingTransactionHashesBatch,
transactionCount: state.transactionCount + action.msgs.length transactionCount: transactionCount
}) })
} else { } else {
return Object.assign({}, state, { return Object.assign({}, state, {
batchCountAccumulator: state.batchCountAccumulator + incomingTransactions.length, batchCountAccumulator: state.batchCountAccumulator + incomingTransactions.length,
batchPendingCountAccumulator: state.batchPendingCountAccumulator - incomingTransactions.length,
newTransactionHashes: _.map(incomingTransactions, 'transactionHash'), newTransactionHashes: _.map(incomingTransactions, 'transactionHash'),
pendingTransactionHashes: updatePendingTransactionHashes, newPendingTransactionHashesBatch: updatedPendingTransactionHashesBatch,
transactionCount: state.transactionCount + action.msgs.length transactionCount: transactionCount
}) })
} }
} }
@ -158,15 +153,11 @@ if ($addressDetailsPage.length) {
const addressHash = $addressDetailsPage[0].dataset.pageAddressHash const addressHash = $addressDetailsPage[0].dataset.pageAddressHash
const addressChannel = socket.channel(`addresses:${addressHash}`, {}) const addressChannel = socket.channel(`addresses:${addressHash}`, {})
const { filter, blockNumber } = humps.camelizeKeys(URI(window.location).query(true)) const { filter, blockNumber } = humps.camelizeKeys(URI(window.location).query(true))
const state = store.dispatch({ store.dispatch({
type: 'PAGE_LOAD', type: 'PAGE_LOAD',
addressHash, addressHash,
beyondPageOne: !!blockNumber, beyondPageOne: !!blockNumber,
filter, filter,
pendingTransactionHashes:
$('[data-selector="pending-transactions-list"] [data-transaction-hash]').map((index, el) =>
el.attributes['data-transaction-hash'].nodeValue
).toArray(),
transactionCount: $('[data-selector="transaction-count"]').text() transactionCount: $('[data-selector="transaction-count"]').text()
}) })
addressChannel.join() addressChannel.join()
@ -224,13 +215,13 @@ if ($addressDetailsPage.length) {
} else { } else {
$channelBatching.hide() $channelBatching.hide()
} }
if (state.batchPendingCountAccumulator > 0) { if (oldState.newPendingTransactionHashesBatch !== state.newPendingTransactionHashesBatch && state.newPendingTransactionHashesBatch.length > 0) {
$channelPendingBatching.show() $channelPendingBatching.show()
$channelPendingBatchingCount[0].innerHTML = numeral(state.batchPendingCountAccumulator).format() $channelPendingBatchingCount[0].innerHTML = numeral(state.newPendingTransactionHashesBatch.length).format()
} else { } else {
$channelPendingBatching.hide() $channelPendingBatching.hide()
} }
if (oldState.pendingTransactionHashes !== state.pendingTransactionHashes && state.newTransactionHashes.length > 0) { if (oldState.newTransactionHashes !== state.newTransactionHashes && state.newTransactionHashes.length > 0) {
let $transaction let $transaction
_.each(state.newTransactionHashes, (hash) => { _.each(state.newTransactionHashes, (hash) => {
$transaction = $(`[data-selector="pending-transactions-list"] [data-transaction-hash="${hash}"]`) $transaction = $(`[data-selector="pending-transactions-list"] [data-transaction-hash="${hash}"]`)

@ -9,6 +9,11 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<div data-selector="channel-pending-batching-message" class="d-none">
<div data-selector="reload-button" class="alert alert-info">
<a href="#" class="alert-link"><span data-selector="channel-pending-batching-count"></span> <%= gettext "More pending transactions have come in" %></a>
</div>
</div>
<div data-selector="channel-batching-message" class="d-none"> <div data-selector="channel-batching-message" class="d-none">
<div data-selector="reload-button" class="alert alert-info"> <div data-selector="reload-button" class="alert alert-info">
<a href="#" class="alert-link"><span data-selector="channel-batching-count"></span> <%= gettext "More transactions have come in" %></a> <a href="#" class="alert-link"><span data-selector="channel-batching-count"></span> <%= gettext "More transactions have come in" %></a>

Loading…
Cancel
Save