This is only done if the latest balance we have is as of a block
that is older than approximately one day. We could just fetch a
day old block and compare, but using the average_block_time lets
us avoid hitting the database again, and also accounts for somehow
having bad information in the blocks table, getting us the latest
balance no matter what.
If there is an unfetched coin balance, then we just fetch that
instead of doing the above. We also don't render the balance
if there is an unfetched row.
Tests for BlockTransactionController mistakenly simulated transactions
on non-consensus blocks by making the `transaction.block` `consensus`
`false`, but this is unrealistic - the importing only sets the consensus
block to `transaction.block` and non-consensus blocks show up as
`transaction.transaction_forks` `transaction_fork.uncle`. To prevent
this from happening again, `Explorer.Factory.with_block` now checks the
`block` has `consensus: true`. With this setup fixed, the tests needed
to be updated to show that *no* _transactions_ would be shown for
non-consensus blocks (because there are only transactions forks) and
whether the non-consensus blocks showed as "above tip" only had to do
with the number being above the consensus number and not to do with it
being non-consensus.
Floki selectors are used to improve error messages when messages are
unexpected.
The block height should be used when calculating confirmations while
the max consensus block number when a block number is needed and you
want to tell if the chain is empty or only the genesis block is
available. The block height is 0 if there are no blocks or if there is
only the genesis block.
For simple value transfers, the UI already doesn't show the redundant
single internal transaction, but we can speed up the indexing by
determine the internal transactions aren't needed when the transacion is
a successful simple value transfer as determined by status being `:ok` and the
input being empty (`0x`).
`TokenHolderCounter` was created 20 days before the current_token_balances
table and wasn't redesigned to make use of `current_token_balances`.
With `current_token_balances` in place, the problematic query over
`token_balances` that necessitated `TokenHoldersCounter` can use
`current_token_balances`.
Using `current_token_balances` with `COUNT(*)` is when
tested on eth60-test, the new query for
`Explorer.Chain.count_token_holders_from_token_hash/1` still took 11
seconds.
```
sql> SELECT COUNT(*)
FROM address_current_token_balances
WHERE token_contract_address_hash = decode('f230b790e05390fc8295f4d3f60332c93bed42e2', 'hex') AND
address_hash != decode('0000000000000000000000000000000000000000', 'hex') AND
value > 0
[2019-01-02 08:04:26] 1 row retrieved starting from 1 in 11 s 554 ms (execution: 11 s 463 ms, fetching: 91 ms)
```
Using `EXPLAIN`, it should this was using a full sequential scan of
table, so like in the other `COUNT(*)` optimizations PRs, I added an
index to enable an index scan.
Running the migration to add the index took only 1 minute on eth60-test:
```
2019-01-02T08:40:16.220 application=ecto_sql [info] == Running 20190102141900 Explorer.Repo.Migrations.IndexCurrentTokenHolders.change/0 forward
2019-01-02T08:40:16.220 application=ecto_sql [info] create index address_current_token_balances_token_contract_address_hash_index
2019-01-02T08:41:13.746 application=ecto_sql [info] == Migrated 20190102141900 in 57.5s
```
After the migration ran, Index Scan was enabled and the query took only
837ms.
```
sql> SELECT COUNT(*)
FROM address_current_token_balances
WHERE token_contract_address_hash = decode('f230b790e05390fc8295f4d3f60332c93bed42e2', 'hex') AND
address_hash != decode('0000000000000000000000000000000000000000', 'hex') AND
value > 0
[2019-01-02 08:42:44] 1 row retrieved starting from 1 in 866 ms (execution: 837 ms, fetching: 29 ms)
```