Fix block download race condition

This commit is contained in:
Mononaut 2022-06-09 22:46:55 +00:00
parent 29627a5ebd
commit 1c2f9e5649
8 changed files with 29 additions and 28 deletions

View File

@ -1,6 +1,6 @@
{
"name": "bitfeed-client",
"version": "2.3.2",
"version": "2.3.3",
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",

View File

@ -3,7 +3,7 @@ import Overlay from '../components/Overlay.svelte'
import Icon from './Icon.svelte'
import BookmarkIcon from '../assets/icon/cil-bookmark.svg'
import { longBtcFormat, numberFormat, feeRateFormat, dateFormat } from '../utils/format.js'
import { exchangeRates, settings, sidebarToggle, newHighlightQuery, highlightingFull, detailTx, pageWidth, latestBlockHeight, highlightInOut, loading, urlPath, currentBlock, overlay, explorerBlockData } from '../stores.js'
import { exchangeRates, settings, sidebarToggle, newHighlightQuery, highlightingFull, detailTx, pageWidth, latestBlockHeight, highlightInOut, loading, urlPath, currentBlock, overlay, explorerBlock } from '../stores.js'
import { formatCurrency } from '../utils/fx.js'
import { hlToHex, mixColor, teal, purple } from '../utils/color.js'
import { SPKToAddress } from '../utils/encodings.js'
@ -298,9 +298,11 @@ async function goToBlock(e) {
let hash = $detailTx.block.hash || $detailTx.block.id
let height = $detailTx.block.height
if (hash === $currentBlock.id) {
onClose()
$overlay = null
} else if (height == $latestBlockHeight) {
$explorerBlockData = null
onClose()
$explorerBlock = null
$overlay = null
} else if (hash) {
loading.increment()

View File

@ -1,4 +1,4 @@
import { urlPath, settings, loading, detailTx, highlightInOut, explorerBlockData, overlay } from '../stores.js'
import { urlPath, settings, loading, detailTx, highlightInOut, explorerBlock, overlay } from '../stores.js'
import { searchTx, searchBlockHash, searchBlockHeight } from '../utils/search.js'
export default class Router {
@ -37,7 +37,7 @@ export default class Router {
detailTx.set(null)
highlightInOut.set(null)
urlPath.set("/")
explorerBlockData.set(null)
explorerBlock.set(null)
overlay.set(null)
} else {
switch (parts[1]) {

View File

@ -6,7 +6,7 @@ import BitcoinBlock from '../models/BitcoinBlock.js'
import TxSprite from '../models/TxSprite.js'
import { FastVertexArray } from '../utils/memory.js'
import { searchTx, fetchSpends, addSpends } from '../utils/search.js'
import { overlay, txCount, mempoolCount, mempoolScreenHeight, blockVisible, currentBlock, selectedTx, detailTx, blockAreaSize, highlight, colorMode, blocksEnabled, latestBlockHeight, explorerBlockData, blockTransitionDirection, loading, urlPath } from '../stores.js'
import { overlay, txCount, mempoolCount, mempoolScreenHeight, blockVisible, currentBlock, selectedTx, detailTx, blockAreaSize, highlight, colorMode, blocksEnabled, latestBlockHeight, explorerBlock, blockTransitionDirection, loading, urlPath } from '../stores.js'
import config from "../config.js"
import { tick } from 'svelte';
@ -48,9 +48,9 @@ export default class TxController {
colorMode.subscribe(mode => {
this.setColorMode(mode)
})
explorerBlockData.subscribe(blockData => {
if (blockData) {
this.exploreBlock(blockData)
explorerBlock.subscribe(block => {
if (block) {
this.exploreBlock(block)
} else {
this.resumeLatest()
}
@ -168,21 +168,18 @@ export default class TxController {
}).map(key => {
return {
...this.txs[key],
inputs: this.txs[key].inputs.map(input => { return {...input, script_pub_key: null, value: null }}),
inputs: this.txs[key].inputs ? this.txs[key].inputs.map(input => { return {...input, script_pub_key: null, value: null }}) : [],
}
})]
})
}
addBlock (blockData, realtime=true) {
addBlock (block, realtime=true) {
// discard duplicate blocks
if (!blockData || !blockData.id || this.knownBlocks[blockData.id]) {
if (!block || !block.id || this.knownBlocks[block.id]) {
return
}
let block
block = new BitcoinBlock(blockData)
latestBlockHeight.set(block.height)
// this.knownBlocks[block.id] = true
if (this.clearBlockTimeout) clearTimeout(this.clearBlockTimeout)
@ -285,9 +282,7 @@ export default class TxController {
return block
}
async exploreBlock (blockData) {
const block = blockData.isBlock ? blockData : new BitcoinBlock(blockData)
async exploreBlock (block) {
if (this.block && this.block.id === block.id) {
this.showBlock()
return

View File

@ -1,4 +1,4 @@
import { serverConnected, serverDelay, lastBlockId } from '../stores.js'
import { serverConnected, serverDelay, lastBlockId, latestBlockHeight } from '../stores.js'
import config from '../config.js'
import api from '../utils/api.js'
import { fetchBlockByHash } from '../utils/search.js'
@ -6,7 +6,8 @@ import { fetchBlockByHash } from '../utils/search.js'
let mempoolTimer
let lastBlockSeen
lastBlockId.subscribe(val => { lastBlockSeen = val })
let latestBlockHeightVal
latestBlockHeight.subscribe(val => { latestBlockHeightVal = val })
class TxStream {
constructor () {
@ -122,8 +123,11 @@ class TxStream {
async fetchBlock (id, calledOnLoad) {
if (!id) return
if (id !== lastBlockSeen) {
const blockData = await fetchBlockByHash(id)
window.dispatchEvent(new CustomEvent('bitcoin_block', { detail: { block: blockData, realtime: !calledOnLoad} }))
const block = await fetchBlockByHash(id)
// ignore this block if we've downloaded a newer one while we were waiting
if (block.height >= latestBlockHeightVal) {
window.dispatchEvent(new CustomEvent('bitcoin_block', { detail: { block, realtime: !calledOnLoad} }))
}
} else {
console.log('already seen block ', lastBlockSeen)
}

View File

@ -179,7 +179,7 @@ export const blocksEnabled = derived([settings], ([$settings]) => {
export const latestBlockHeight = writable(null)
export const highlightInOut = writable(null)
export const loading = createCounter()
export const explorerBlockData = writable(null)
export const explorerBlock = writable(null)
export const blockTransitionDirection = writable(null)
export const urlPath = writable(null)

View File

@ -1,7 +1,7 @@
import api from './api.js'
import BitcoinTx from '../models/BitcoinTx.js'
import BitcoinBlock from '../models/BitcoinBlock.js'
import { detailTx, selectedTx, currentBlock, explorerBlockData, overlay, highlightInOut, urlPath } from '../stores.js'
import { detailTx, selectedTx, currentBlock, explorerBlock, overlay, highlightInOut, urlPath } from '../stores.js'
import { addressToSPK } from './encodings.js'
// Quick heuristic matching to guess what kind of search a query is for
@ -154,7 +154,7 @@ async function fetchBlockByHash (hash) {
if (blockData) {
if (blockData.id) {
block = new BitcoinBlock(blockData)
} else block = BitcoinBlock.decompress(blockData)
} else block = new BitcoinBlock(BitcoinBlock.decompress(blockData))
}
if (block && block.id) {
console.log('downloaded block', block.id)
@ -255,7 +255,7 @@ export async function searchBlockHash (hash) {
const searchResult = await fetchBlockByHash(hash)
if (searchResult) {
if (searchResult.id) {
explorerBlockData.set(searchResult)
explorerBlock.set(searchResult)
}
return null
} else {
@ -274,7 +274,7 @@ export async function searchBlockHeight (height) {
const searchResult = await fetchBlockByHeight(height)
if (searchResult) {
if (searchResult.id) {
explorerBlockData.set(searchResult)
explorerBlock.set(searchResult)
}
return null
} else {

View File

@ -4,7 +4,7 @@ defmodule BitcoinStream.MixProject do
def project do
[
app: :bitcoin_stream,
version: "2.3.2",
version: "2.3.3",
elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps(),