misc-research/Pre-fork-BCH-BTC-Spending/extract-tx-graphs.R

157 lines
4.9 KiB
R
Raw Normal View History

# install.packages("rbch")
# install.packages("data.table")
# install.packages("future.apply")
library(rbch)
library(data.table)
library(future.apply)
# 478,558 is last block that BCH and BTC have in common
bitcoin.conf.file <- ""
# Input filepath for your bitcoin.conf file
data.dir <- ""
# Input data directory here, with trailing "/"
dir.create(paste0(data.dir, "tx_graphs"))
bch.config <- rbch::conrpc(bitcoin.conf.file)
# current.block.height <- rbch::getblockchaininfo(bch.config)@result$blocks
current.block.height <- 733867
# 733867 is for BCH
# current.block.height <- 729896
# 729896 is for BTC
cut.seq <- seq(20, current.block.height, by = 20)
cut.seq <- c(-1, cut.seq, current.block.height)
heights.to.process <- 0:current.block.height
heights.to.process <- split(heights.to.process,
cut(heights.to.process, cut.seq))
future::plan(future::multiprocess())
for (height.set in heights.to.process) {
extracted.txs <- future.apply::future_lapply(height.set, function(iter.block.height) {
if (iter.block.height %% 1000 == 0) {
cat(iter.block.height, base::date(), "\n")
}
block.hash <- rbch::getblockhash(bch.config, iter.block.height)
block.data <- rbch::getblock(bch.config, blockhash = block.hash@result, verbosity = "l2")
# Argument verbose = 2 gives full transaction data
# For some reason it doesn't give the fee:
# https://docs.bitcoincashnode.org/doc/json-rpc/getrawtransaction.html
raw.txs.ls <- block.data@result$tx
coinbase.tx <- raw.txs.ls[[1]]
value <- vector("numeric", length(coinbase.tx$vout) )
for (j in seq_along(coinbase.tx$vout)) {
value[j] <- coinbase.tx$vout[[j]]$value
}
outgoing.coinbase <- data.table(txid = coinbase.tx$txid,
position = seq_along(coinbase.tx$vout), value = value, block_height = iter.block.height, stringsAsFactors = FALSE)
coinbase.return.value <- list(incoming =
data.table(txid = character(0), origin.txid = character(0),
origin.position = numeric(0), block_height = integer(0), stringsAsFactors = FALSE),
outgoing = outgoing.coinbase)
if ( length(raw.txs.ls) < 2) {
return(list(coinbase.return.value))
}
# No incoming txs for coinbase-only
# Results of this lapply below are returned
return.value <- lapply(2:length(raw.txs.ls), function(iter) {
# Start at 2 since the first tx is the coinbase tx
latest.tx <- raw.txs.ls[[iter]]
# addresses <- vector("character", length(latest.tx$vout) )
value <- vector("numeric", length(latest.tx$vout) )
for (j in seq_along(latest.tx$vout)) {
extracted.address <- latest.tx$vout[[j]]$scriptPubKey$addresses
if (length(extracted.address) > 1) {
extracted.address <- list(paste0(sort(unlist(extracted.address)), collapse = "|"))
# sort() so that the address order is always the same
}
stopifnot(length(extracted.address[[1]]) <= 1)
if (length(extracted.address) == 0) {next}
# addresses[j] <- extracted.address[[1]]
value[j] <- latest.tx$vout[[j]]$value
}
outgoing <- data.table(txid = latest.tx$txid,
# address = addresses,
position = seq_along(latest.tx$vout), value = value, block_height = iter.block.height, stringsAsFactors = FALSE)
origin.txid <- vector("character", length(latest.tx$vin) )
origin.position <- vector("numeric", length(latest.tx$vin) )
for (j in seq_along(latest.tx$vin)) {
extracted.address <- latest.tx$vin[[j]]$txid
stopifnot(length(extracted.address) <= 1)
stopifnot(length(extracted.address[[1]]) <= 1)
if (length(extracted.address) == 0) {next}
origin.txid[j] <- latest.tx$vin[[j]]$txid
origin.position[j] <- latest.tx$vin[[j]]$vout + 1
}
incoming <- data.table(txid = latest.tx$txid, origin.txid = origin.txid,
origin.position = origin.position, block_height = iter.block.height, stringsAsFactors = FALSE)
list(incoming = incoming, outgoing = outgoing)
})
return.value[[length(return.value) + 1]] <- coinbase.return.value
# Note that this means that coinbase txs are now "last in the block"
return.value
})
print(object.size(extracted.txs), units = "Mb")
extracted.txs <- unlist(extracted.txs, recursive = FALSE)
incoming <- data.table::rbindlist(lapply(extracted.txs, function(x) {
x[[1]]
})
)
outgoing <- data.table::rbindlist(lapply(extracted.txs, function(x) {
x[[2]]
})
)
rm(extracted.txs)
saveRDS(list(incoming = incoming, outgoing = outgoing),
file = paste0(data.dir, "tx_graphs/tx_graph_height_",
paste0(formatC(range(height.set), width = 6, flag = "0"), collapse = "_to_"), ".rds"),
compress = FALSE)
rm(incoming)
rm(outgoing)
}