Many updates; getting close to final version

This commit is contained in:
Rucknium 2022-04-29 20:44:29 +00:00
parent 222f62b905
commit fcf5507736
3 changed files with 404 additions and 54 deletions

View file

@ -2,10 +2,13 @@
library(data.table)
library(RSQLite)
library(DBI)
library(scales)
# NOTE: Also need lubridate package installed, but not loading it due to
# it masking functions
# WARNING: This code assumes that pre-fork bitcoin has been spent every day since the fork,
# which is true up to March 31, 2022. If this code runs on later data, then will
# have to pre-fill data.frames with dates
bch.data.dir <- ""
btc.data.dir <- ""
# Input data directory here, with trailing "/"
@ -22,6 +25,9 @@ pre.fork.utxo.set <- setdiff(pre.fork.edgelist$destination_index, pre.fork.edgel
DBI::dbWriteTable(con.bch, "pre_fork_utxo_set",
data.frame(destination_index = pre.fork.utxo.set, stringsAsFactors = FALSE))
DBI::dbWriteTable(con.btc, "pre_fork_utxo_set",
data.frame(destination_index = pre.fork.utxo.set, stringsAsFactors = FALSE))
# Need to do this operation for both the BCH and BTC databases
pre.fork.utxo.set.value <- DBI::dbGetQuery(con.bch,
'SELECT destination_index, value FROM edgelist_intermediate_2 WHERE destination_index IN (SELECT destination_index FROM pre_fork_utxo_set)')
@ -32,7 +38,10 @@ pre.fork.utxo.set.value[, sum(value)] / pre.fork.bitcoin.supply
pre.fork.bitcoin.supply - pre.fork.utxo.set.value[, sum(value)]
# [1] 2637.559
pre.fork.utxo.set.value <- pre.fork.utxo.set.value[ ! destination_index %in% c(1740174960, 1740175469), ]
duplicated.destination_index <-
unlist(pre.fork.utxo.set.value[duplicated(destination_index), .(destination_index)])
pre.fork.utxo.set.value <- pre.fork.utxo.set.value[ ! destination_index %in% duplicated.destination_index, ]
# Removes the transactions that are coinbases of blocks 91722, 91812, 91842, 91880
# Since they are duplicated transaction hashes. See:
# https://bitcoin.stackexchange.com/questions/40444/what-happens-when-two-txids-collide
@ -42,63 +51,187 @@ excluded.duplicate.tx.hashes.output.count <- 4
excluded.duplicate.tx.hashes.value <- 50 * 4
spent.status <- DBI::dbGetQuery(con.bch,
'SELECT origin_index, block_height FROM edgelist_intermediate_2 WHERE origin_index IN (SELECT destination_index FROM pre_fork_utxo_set)')
colnames(spent.status) <- c("destination_index", "bch.spent.block_height")
setDT(spent.status)
bch.spent.status <- DBI::dbGetQuery(con.bch,
'SELECT origin_index, block_height FROM edgelist_intermediate_1 WHERE origin_index IN (SELECT destination_index FROM pre_fork_utxo_set)')
colnames(bch.spent.status) <- c("destination_index", "bch.spent.block_height")
setDT(bch.spent.status)
spent.status <- merge(pre.fork.utxo.set.value, spent.status, all.x = TRUE)
# rm(pre.fork.utxo.set.value)
btc.spent.status <- DBI::dbGetQuery(con.btc,
'SELECT origin_index, block_height FROM edgelist_intermediate_1 WHERE origin_index IN (SELECT destination_index FROM pre_fork_utxo_set)')
colnames(btc.spent.status) <- c("destination_index", "btc.spent.block_height")
setDT(btc.spent.status)
spent.status <- merge(pre.fork.utxo.set.value, bch.spent.status, all.x = TRUE)
rm(pre.fork.utxo.set.value, bch.spent.status)
spent.status <- merge(spent.status, btc.spent.status, all.x = TRUE)
rm(btc.spent.status)
# aggregate(spent.status$value, by = list(! is.na(spent.status$bch.spent.block_height)), FUN = sum)
# Group.1 x
# 1 FALSE 5699742
# 2 TRUE 10779508
# table(spent.status[value > 0, ! is.na(bch.spent.block_height)])
# FALSE TRUE
# 29154762 21307064
bch.block.times <- readRDS(paste0(bch.data.dir, "block_times.rds"))
bch.block.times[, block_time := as.POSIXct(block_time, origin = "1970-01-01", tz = "GMT")]
colnames(bch.block.times) <- c("bch.spent.block_height", "block_time")
colnames(bch.block.times) <- c("bch.spent.block_height", "bch.block_time")
spent.status <- merge(spent.status, bch.block.times, all = TRUE, by = "bch.spent.block_height")
# Note that due to all = TRUE this will get all blocks,
# even if there are no target spent outputs within the block
spent.status.by.block <- spent.status[,
.(value = sum(value, na.rm= TRUE), n.outputs = length(destination_index[ (! is.na(value)) & value > 0])),
by = .(bch.spent.block_height, block_time)]
spent.status.by.block[, block_time.date := lubridate::date(block_time)]
btc.block.times <- readRDS(paste0(btc.data.dir, "block_times.rds"))
spent.status.by.date <- spent.status.by.block[,
.(value = sum(value, na.rm= TRUE), n.outputs = sum(n.outputs, na.rm= TRUE)),
by = .(block_time.date)]
btc.block.times[, block_time := as.POSIXct(block_time, origin = "1970-01-01", tz = "GMT")]
colnames(btc.block.times) <- c("btc.spent.block_height", "btc.block_time")
unspent <- spent.status.by.date[is.na(block_time.date), value]
cumsum.na.rm <- function(x) {x[is.na(x)] <- 0; cumsum(x)}
spent.status.by.date[, value.cumsum := cumsum.na.rm(value) - unspent]
spent.status.by.date[, perc.value.cumsum := 100 * value.cumsum / sum(value, na.rm = TRUE)]
spent.status.by.date[, unspent.perc.value.cumsum := 100 - perc.value.cumsum]
spent.status <- merge(spent.status, btc.block.times, all = TRUE, by = "btc.spent.block_height")
write.csv(spent.status, file = paste0(bch.data.dir, "spent_status-test.csv"), row.names = FALSE)
btc.spent.status <- DBI::dbGetQuery(con.btc,
'SELECT origin_index, block_height FROM edgelist_intermediate_2 WHERE origin_index IN (SELECT destination_index FROM pre_fork_utxo_set)')
colnames(btc.spent.status) <- c("destination_index, btc.spent.block_height")
setDT(btc.spent.status)
spent.status <- merge(spent.status, btc.spent.status, all.x = TRUE)
spent.status[, bch.block_time.date := lubridate::date(bch.block_time)]
spent.status[, btc.block_time.date := lubridate::date(btc.block_time)]
# Column format below is:
# {BTC spent status}{BCH spent status}.to.{BTC spent status}{BCH spent status}
# u = unspent; s = spent
spent.status[, uu.to.su := as.Date(ifelse(
ifelse(is.na(btc.block_time.date), Inf, btc.block_time.date) < ifelse(is.na(bch.block_time.date), Inf, bch.block_time.date),
btc.block_time.date, rep(NA, .N)), origin = "1970-01-01")]
spent.status[, uu.to.us := as.Date(ifelse(
ifelse(is.na(bch.block_time.date), Inf, bch.block_time.date) < ifelse(is.na(btc.block_time.date), Inf, btc.block_time.date),
bch.block_time.date, rep(NA, .N)), origin = "1970-01-01")]
spent.status[, uu.to.ss := as.Date(ifelse(
ifelse(is.na(btc.block_time.date), Inf, btc.block_time.date) == ifelse(is.na(bch.block_time.date), Inf, bch.block_time.date),
btc.block_time.date, rep(NA, .N)), origin = "1970-01-01")]
spent.status[, su.to.ss := as.Date(ifelse(
(! is.na(uu.to.su)) &
ifelse(is.na(bch.block_time.date), Inf, bch.block_time.date) > ifelse(is.na(btc.block_time.date), Inf, btc.block_time.date),
bch.block_time.date, rep(NA, .N)), origin = "1970-01-01")]
spent.status[, us.to.ss := as.Date(ifelse(
(! is.na(uu.to.us)) &
ifelse(is.na(btc.block_time.date), Inf, btc.block_time.date) > ifelse(is.na(bch.block_time.date), Inf, bch.block_time.date),
btc.block_time.date, rep(NA, .N)), origin = "1970-01-01")]
uu.to.su <- spent.status[ (! is.na(uu.to.su)),
.(value.uu.to.su = sum(value, na.rm = TRUE), outputs.uu.to.su = .N), by = uu.to.su]
names(uu.to.su)[1] <- "block_time.date"
uu.to.us <- spent.status[ (! is.na(uu.to.us)),
.(value.uu.to.us = sum(value, na.rm = TRUE), outputs.uu.to.us = .N), by = uu.to.us]
names(uu.to.us)[1] <- "block_time.date"
uu.to.ss <- spent.status[ (! is.na(uu.to.ss)),
.(value.uu.to.ss = sum(value, na.rm = TRUE), outputs.uu.to.ss = .N), by = uu.to.ss]
names(uu.to.ss)[1] <- "block_time.date"
su.to.ss <- spent.status[ (! is.na(su.to.ss)),
.(value.su.to.ss = sum(value, na.rm = TRUE), outputs.su.to.ss = .N), by = su.to.ss]
names(su.to.ss)[1] <- "block_time.date"
us.to.ss <- spent.status[ (! is.na(us.to.ss)),
.(value.us.to.ss = sum(value, na.rm = TRUE), outputs.us.to.ss = .N), by = us.to.ss]
names(us.to.ss)[1] <- "block_time.date"
trans.matrix.prep <-
data.table(block_time.date = sort(unique(lubridate::date(c(spent.status$bch.block_time, spent.status$btc.block_time)))))
trans.matrix.prep <- merge(trans.matrix.prep, uu.to.su, all = TRUE)
trans.matrix.prep <- merge(trans.matrix.prep, uu.to.us, all = TRUE)
trans.matrix.prep <- merge(trans.matrix.prep, uu.to.ss, all = TRUE)
trans.matrix.prep <- merge(trans.matrix.prep, su.to.ss, all = TRUE)
trans.matrix.prep <- merge(trans.matrix.prep, us.to.ss, all = TRUE)
trans.matrix.prep[is.na(trans.matrix.prep)] <- 0
spent.status.by.day <-
data.table(block_time.date = sort(unique(lubridate::date(c(spent.status$bch.block_time, spent.status$btc.block_time)))),
value.btc.unspent.bch.unspent = NA_real_,
outputs.btc.unspent.bch.unspent = NA_integer_,
value.btc.spent.bch.unspent = NA_real_,
outputs.btc.spent.bch.unspent = NA_integer_,
value.btc.unspent.bch.spent = NA_real_,
outputs.btc.unspent.bch.spent = NA_integer_,
value.btc.spent.bch.spent = NA_real_,
outputs.btc.spent.bch.spent = NA_integer_)
for (day.i in spent.status.by.day$block_time.date) {
spent.status[, btc.spent := (btc.block_time.date <= day.i) & (! is.na(btc.block_time.date))]
spent.status[, bch.spent := (bch.block_time.date <= day.i) & (! is.na(bch.block_time.date))]
spent.status.by.day$value.btc.unspent.bch.unspent[spent.status.by.day$block_time.date == day.i] <-
spent.status[ (! btc.spent) & (! bch.spent), sum(value, na.rm = TRUE)]
spent.status.by.day$outputs.btc.unspent.bch.unspent[spent.status.by.day$block_time.date == day.i] <-
spent.status[ (! btc.spent) & (! bch.spent), .N]
spent.status.by.day$value.btc.spent.bch.unspent[spent.status.by.day$block_time.date == day.i] <-
spent.status[ ( btc.spent) & (! bch.spent), sum(value, na.rm = TRUE)]
spent.status.by.day$outputs.btc.spent.bch.unspent[spent.status.by.day$block_time.date == day.i] <-
spent.status[ ( btc.spent) & (! bch.spent), .N]
spent.status.by.day$value.btc.unspent.bch.spent[spent.status.by.day$block_time.date == day.i] <-
spent.status[ (! btc.spent) & ( bch.spent), sum(value, na.rm = TRUE)]
spent.status.by.day$outputs.btc.unspent.bch.spent[spent.status.by.day$block_time.date == day.i] <-
spent.status[ (! btc.spent) & ( bch.spent), .N]
spent.status.by.day$value.btc.spent.bch.spent[spent.status.by.day$block_time.date == day.i] <-
spent.status[ ( btc.spent) & ( bch.spent), sum(value, na.rm = TRUE)]
spent.status.by.day$outputs.btc.spent.bch.spent[spent.status.by.day$block_time.date == day.i] <-
spent.status[ ( btc.spent) & ( bch.spent), .N]
cat(base::date(), which(spent.status.by.day$block_time.date == day.i),
"of", nrow(spent.status.by.day),"\n")
}
# Fairly inefficient implementation, but gets the job done
## Data validity check below
value.row.sum.check <- rowSums(spent.status.by.day[, .(
value.btc.unspent.bch.unspent, value.btc.spent.bch.unspent,
value.btc.unspent.bch.spent, value.btc.spent.bch.spent)
])
stopifnot(max(value.row.sum.check) - min(value.row.sum.check) < 0.000001)
# Some small error allowed for floating point arithmetic inaccuracy
outputs.row.sum.check <- rowSums(spent.status.by.day[, .(
outputs.btc.unspent.bch.unspent, outputs.btc.spent.bch.unspent,
outputs.btc.unspent.bch.spent, outputs.btc.spent.bch.spent)
])
stopifnot(max(outputs.row.sum.check) - min(outputs.row.sum.check) == 0)
saveRDS(spent.status.by.day, file = paste0(bch.data.dir, "spent_status_by_day.rds"))
saveRDS(trans.matrix.prep, file = paste0(bch.data.dir, "trans_matrix_prep.rds"))

View file

@ -1,14 +1,107 @@
library(data.table)
library(ggplot2)
library(scales)
library(Cairo)
# NOTE: Also need lubridate package installed, but not loading it due to
# it masking functions
spent.status.by.date <- spent.status.by.date[ ! is.na(block_time.date), ]
spent.status.by.date.reshaped <- melt(spent.status.by.date, id.vars = c("block_time.date"),
measure.vars = c("perc.value.cumsum", "unspent.perc.value.cumsum"))
sum.value.pre.fork <- sum(spent.status.by.day[1,
.(value.btc.unspent.bch.unspent, value.btc.spent.bch.unspent,
value.btc.unspent.bch.spent, value.btc.spent.bch.spent)])
sum.outputs.pre.fork <- sum(spent.status.by.day[1,
.(outputs.btc.unspent.bch.unspent, outputs.btc.spent.bch.unspent,
outputs.btc.unspent.bch.spent, outputs.btc.spent.bch.spent)])
current.status <- spent.status.by.day[block_time.date == "2022-03-31", ]
current.status[,
.(value.btc.unspent.bch.unspent, value.btc.spent.bch.unspent,
value.btc.unspent.bch.spent, value.btc.spent.bch.spent)]
100 * current.status[,
.(value.btc.unspent.bch.unspent, value.btc.spent.bch.unspent,
value.btc.unspent.bch.spent, value.btc.spent.bch.spent)] / sum.value.pre.fork
current.status[,
.(outputs.btc.unspent.bch.unspent, outputs.btc.spent.bch.unspent,
outputs.btc.unspent.bch.spent, outputs.btc.spent.bch.spent)]
100 * current.status[,
.(outputs.btc.unspent.bch.unspent, outputs.btc.spent.bch.unspent,
outputs.btc.unspent.bch.spent, outputs.btc.spent.bch.spent)] / sum.outputs.pre.fork
spent.status.by.day.value.reshaped <- melt(spent.status.by.day[,
.(block_time.date, value.btc.unspent.bch.unspent, value.btc.spent.bch.unspent,
value.btc.unspent.bch.spent, value.btc.spent.bch.spent)], id.vars = c("block_time.date"),
measure.vars = c("value.btc.unspent.bch.unspent", "value.btc.spent.bch.unspent",
"value.btc.unspent.bch.spent", "value.btc.spent.bch.spent"))
spent.status.by.day.value.reshaped[, block_time.date := as.POSIXct(block_time.date)]
spent.status.by.day.value.reshaped[, variable :=
factor(variable, levels = c("value.btc.unspent.bch.unspent", "value.btc.unspent.bch.spent",
"value.btc.spent.bch.unspent", "value.btc.spent.bch.spent"))]
spent.status.by.day.outputs.reshaped <- melt(spent.status.by.day[,
.(block_time.date, outputs.btc.unspent.bch.unspent, outputs.btc.spent.bch.unspent,
outputs.btc.unspent.bch.spent, outputs.btc.spent.bch.spent)], id.vars = c("block_time.date"),
measure.vars = c("outputs.btc.unspent.bch.unspent", "outputs.btc.spent.bch.unspent",
"outputs.btc.unspent.bch.spent", "outputs.btc.spent.bch.spent"))
spent.status.by.day.outputs.reshaped[, block_time.date := as.POSIXct(block_time.date)]
spent.status.by.day.outputs.reshaped[, variable :=
factor(variable, levels = c("outputs.btc.unspent.bch.unspent", "outputs.btc.spent.bch.unspent",
"outputs.btc.unspent.bch.spent", "outputs.btc.spent.bch.spent"))]
trans.matrix.prep.value.reshaped <- melt(trans.matrix.prep[,
.(block_time.date, value.uu.to.su, value.uu.to.us, value.uu.to.ss,
value.su.to.ss, value.us.to.ss)], id.vars = c("block_time.date"),
measure.vars = c("value.uu.to.su", "value.uu.to.us", "value.uu.to.ss",
"value.su.to.ss", "value.us.to.ss"))
trans.matrix.prep.value.reshaped[, block_time.date := as.POSIXct(block_time.date)]
trans.matrix.prep.value.reshaped[, variable :=
factor(variable, levels = c("value.uu.to.su", "value.uu.to.us", "value.uu.to.ss",
"value.su.to.ss", "value.us.to.ss"))]
trans.matrix.prep.outputs.reshaped <- melt(trans.matrix.prep[,
.(block_time.date, outputs.uu.to.su, outputs.uu.to.us, outputs.uu.to.ss,
outputs.su.to.ss, outputs.us.to.ss)], id.vars = c("block_time.date"),
measure.vars = c("outputs.uu.to.su", "outputs.uu.to.us", "outputs.uu.to.ss",
"outputs.su.to.ss", "outputs.us.to.ss"))
trans.matrix.prep.outputs.reshaped[, block_time.date := as.POSIXct(block_time.date)]
trans.matrix.prep.outputs.reshaped[, variable :=
factor(variable, levels = c("outputs.uu.to.su", "outputs.uu.to.us", "outputs.uu.to.ss",
"outputs.su.to.ss", "outputs.us.to.ss"))]
date.breaks <- seq.POSIXt(min(spent.status.by.day.value.reshaped$block_time.date),
max(spent.status.by.day.value.reshaped$block_time.date), by = "month")
c_trans <- function(a, b, breaks = b$breaks, format = b$format) {
@ -26,36 +119,160 @@ c_trans <- function(a, b, breaks = b$breaks, format = b$format) {
rev_date <- c_trans("reverse", "time")
spent.status.by.date.reshaped[, block_time.date := as.POSIXct(block_time.date)]
spent.status.by.date.reshaped[, variable :=
factor(variable, levels = c("perc.value.cumsum", "unspent.perc.value.cumsum"))]
# #FF9900 BTC color
# https://gist.github.com/paladini/ef383fce1b782d919898
# #0AC18E BCH color
# https://bitcoincashstandards.org/
png(paste0(bch.data.dir, "preliminary-pre-fork-BCH-spent-status.png"), width = 800, height = 2000)
png(paste0(bch.data.dir, "preliminary-pre-fork-BTC-BCH-spent-status-by-value.png"), width = 800, height = 2000)
print(
ggplot(spent.status.by.date.reshaped, aes(x = block_time.date, y=value, fill=variable)) +
ggplot(spent.status.by.day.value.reshaped, aes(x = block_time.date, y = value, fill = variable)) +
ggtitle("Spent status of Pre-fork BTC and BCH by Bitcoin Value") +
geom_area(alpha = 0.6 , size = 0, colour = "black") + coord_flip() +
scale_x_continuous(trans = rev_date) +
scale_fill_manual(values = c("#0AC18E", "purple"), breaks = rev(c("perc.value.cumsum", "unspent.perc.value.cumsum"))) +
ylab("\t\t\t\t\t\tPercent github.com/Rucknium") +
scale_x_continuous(trans = rev_date, breaks = date.breaks, labels = date_format("%b-%Y"), expand = c(0, 0)) +
scale_y_continuous(breaks = sum.value.pre.fork * seq(0, 1, by = 0.1),
labels = scales::percent_format(scale = 100 * 1/sum.value.pre.fork, accuracy = 1), expand = c(0, 0)) +
scale_fill_manual(
labels = c("BTC & BCH spent", "BTC spent & BCH unspent", "BTC unspent & BCH spent", "BTC & BCH unspent"),
values = c("purple", "#FF9900", "#0AC18E", "darkgrey"),
breaks = c("value.btc.spent.bch.spent", "value.btc.spent.bch.unspent",
"value.btc.unspent.bch.spent", "value.btc.unspent.bch.unspent")) +
ylab("Percentage of Pre-fork Bitcoin Value") +
theme(legend.position = "top", axis.title.y = element_blank(),
plot.title = element_text(size = 27),
axis.text = element_text(size = 20), axis.title.x = element_text(size = 20),
legend.title = element_blank(), legend.text = element_text(size = 15)) +
legend.title = element_blank(), legend.text = element_text(size = 14)) +
geom_vline(xintercept = as.POSIXct("2017-11-12"), linetype = 3) +
geom_text(aes(x = as.POSIXct("2017-11-12"), label = "Max BCH/BTC Exchange Rate", y = 25), colour = "white", size = 7.5) +
geom_text(aes(x = as.POSIXct("2017-11-12"), label = "Max BCH/BTC Exchange Rate",
y = 0.75 * sum.value.pre.fork), colour = "black", size = 6, check_overlap = TRUE) +
geom_vline(xintercept = as.POSIXct("2017-12-20"), linetype = 3) +
geom_text(aes(x = as.POSIXct("2017-12-20"), label = "Max BCH/USD Exchange Rate", y = 25), colour = "white", size = 7.5) +
geom_text(aes(x = as.POSIXct("2017-12-20"), label = "Max BCH/USD Exchange Rate",
y = 0.75 * sum.value.pre.fork), colour = "black", size = 6, check_overlap = TRUE) +
geom_vline(xintercept = as.POSIXct("2018-11-15"), linetype = 3) +
geom_text(aes(x = as.POSIXct("2018-11-15"), label = "BSV Hard Fork", y = 12), colour = "white", size = 7.5) +
geom_text(aes(x = as.POSIXct("2018-11-15"), label = "BSV Hard Fork",
y = 0.25 * sum.value.pre.fork), colour = "black", size = 6, check_overlap = TRUE) +
geom_vline(xintercept = as.POSIXct("2020-11-15"), linetype = 3) +
geom_text(aes(x = as.POSIXct("2020-11-15"), label = "BCHABC Hard Fork", y = 15), colour = "white", size = 7.5)
geom_text(aes(x = as.POSIXct("2020-11-15"), label = "BCHABC Hard Fork",
y = 0.25 * sum.value.pre.fork), colour = "black", size = 6, check_overlap = TRUE) +
geom_text(aes(x = as.POSIXct("2022-03-15"), label = "github.com/Rucknium",
y = 0.87 * sum.value.pre.fork), colour = "black", size = 6, check_overlap = TRUE)
)
# https://en.wikipedia.org/wiki/List_of_bitcoin_forks
# expand = c(0, 0) due to:
# https://stackoverflow.com/questions/48611719/remove-inner-padding-in-ggplot
dev.off()
png(paste0(bch.data.dir, "preliminary-pre-fork-BTC-BCH-spent-status-by-outputs.png"), width = 800, height = 2000)
print(
ggplot(spent.status.by.day.outputs.reshaped, aes(x = block_time.date, y = value, fill = variable)) +
ggtitle("Spent status of Pre-fork BTC and BCH by Number of Outputs") +
geom_area(alpha = 0.6 , size = 0, colour = "black") + coord_flip() +
scale_x_continuous(trans = rev_date, breaks = date.breaks, labels = date_format("%b-%Y"), expand = c(0, 0)) +
scale_y_continuous(breaks = sum.outputs.pre.fork * seq(0, 1, by = 0.1),
labels = scales::percent_format(scale = 100 * 1/sum.outputs.pre.fork, accuracy = 1), expand = c(0, 0)) +
scale_fill_manual(
labels = c("BTC & BCH spent", "BTC spent & BCH unspent", "BTC unspent & BCH spent", "BTC & BCH unspent"),
values = c("purple", "#FF9900", "#0AC18E", "darkgrey"),
breaks = c("outputs.btc.spent.bch.spent", "outputs.btc.spent.bch.unspent",
"outputs.btc.unspent.bch.spent", "outputs.btc.unspent.bch.unspent")) +
ylab("Percentage of Pre-fork Outputs") +
theme(legend.position = "top", axis.title.y = element_blank(),
plot.title = element_text(size = 26),
axis.text = element_text(size = 20), axis.title.x = element_text(size = 20),
legend.title = element_blank(), legend.text = element_text(size = 14)) +
geom_vline(xintercept = as.POSIXct("2017-11-12"), linetype = 3) +
geom_text(aes(x = as.POSIXct("2017-11-12"), label = "Max BCH/BTC Exchange Rate",
y = 0.75 * sum.outputs.pre.fork), colour = "black", size = 6, check_overlap = TRUE) +
geom_vline(xintercept = as.POSIXct("2017-12-20"), linetype = 3) +
geom_text(aes(x = as.POSIXct("2017-12-20"), label = "Max BCH/USD Exchange Rate",
y = 0.75 * sum.outputs.pre.fork), colour = "black", size = 6, check_overlap = TRUE) +
geom_vline(xintercept = as.POSIXct("2018-11-15"), linetype = 3) +
geom_text(aes(x = as.POSIXct("2018-11-15"), label = "BSV Hard Fork",
y = 0.10 * sum.outputs.pre.fork), colour = "black", size = 6, check_overlap = TRUE) +
geom_vline(xintercept = as.POSIXct("2020-11-15"), linetype = 3) +
geom_text(aes(x = as.POSIXct("2020-11-15"), label = "BCHABC Hard Fork",
y = 0.15 * sum.outputs.pre.fork), colour = "black", size = 6, check_overlap = TRUE) +
geom_text(aes(x = as.POSIXct("2022-03-15"), label = "github.com/Rucknium",
y = 0.87 * sum.outputs.pre.fork), colour = "black", size = 6, check_overlap = TRUE)
)
dev.off()
ann_text.value <- data.frame(
block_time.date = as.POSIXct("2022-03-15"),
value = 300000,
variable = factor("value.us.to.ss", levels = levels(trans.matrix.prep.value.reshaped$variable)))
# Due to
# https://stackoverflow.com/questions/11889625/annotating-text-on-individual-facet-in-ggplot2
png(paste0(bch.data.dir, "preliminary-pre-fork-BTC-BCH-trans-matrix-by-value.png"), width = 800, height = 2000)
print(
ggplot(trans.matrix.prep.value.reshaped, aes(x = block_time.date, y = value, fill = variable)) +
ggtitle("State Transition of Pre-fork BTC and BCH by Bitcoin Value\nKEY: {BTC Spent}{BCH Spent} to {BTC Spent}{BCH Spent}") +
geom_line(aes(color = variable)) + coord_flip() +
scale_x_continuous(trans = rev_date, labels = date_format("%b-%Y"), expand = c(0, 0),
breaks = date.breaks) +
scale_y_continuous(labels = scales::comma) +
facet_grid(. ~ variable, labeller = labeller(variable =
c(value.uu.to.su = "FF to TF", value.uu.to.us = "FF to FT", value.uu.to.ss = "FF to TT",
value.su.to.ss = "TF to TT", value.us.to.ss = "FT to TT" ))) +
ylab("Quantity of Bitcoin Value Transitioned per Day") +
theme(legend.position = "none", axis.title.y = element_blank(),
strip.text.x = element_text(size = 20), plot.title = element_text(size = 24),
axis.text = element_text(size = 15), axis.title.x = element_text(size = 15),
axis.text.x = element_text(angle = 270)) +
geom_vline(xintercept = as.POSIXct("2017-11-12"), linetype = 3) +
geom_vline(xintercept = as.POSIXct("2017-12-20"), linetype = 3) +
geom_vline(xintercept = as.POSIXct("2018-11-15"), linetype = 3) +
geom_vline(xintercept = as.POSIXct("2020-11-15"), linetype = 3) +
geom_text(data = ann_text.value, label = "github.com/Rucknium",
colour = "black", size = 4.5, check_overlap = TRUE)
)
dev.off()
ann_text.output <- data.frame(
block_time.date = as.POSIXct("2022-03-15"),
value = 280000,
variable = factor("outputs.us.to.ss", levels = levels(trans.matrix.prep.outputs.reshaped$variable)))
png(paste0(bch.data.dir, "preliminary-pre-fork-BTC-BCH-trans-matrix-by-outputs.png"), width = 800, height = 2000)
print(
ggplot(trans.matrix.prep.outputs.reshaped, aes(x = block_time.date, y = value, fill = variable)) +
ggtitle("State Transition of Pre-fork BTC and BCH by Number of Outputs\nKEY: {BTC Spent}{BCH Spent} to {BTC Spent}{BCH Spent}") +
geom_line(aes(color = variable)) + coord_flip() +
scale_x_continuous(trans = rev_date, labels = date_format("%b-%Y"), expand = c(0, 0),
breaks = date.breaks) +
scale_y_continuous(labels = scales::comma) +
facet_grid(. ~ variable, labeller = labeller(variable =
c(outputs.uu.to.su = "FF to TF", outputs.uu.to.us = "FF to FT", outputs.uu.to.ss = "FF to TT",
outputs.su.to.ss = "TF to TT", outputs.us.to.ss = "FT to TT" ))) +
ylab("Number of Transitioned Outputs per Day") +
theme(legend.position = "none", axis.title.y = element_blank(),
strip.text.x = element_text(size = 20), plot.title = element_text(size = 24),
axis.text = element_text(size = 15), axis.title.x = element_text(size = 15),
axis.text.x = element_text(angle = 270)) +
geom_vline(xintercept = as.POSIXct("2017-11-12"), linetype = 3) +
geom_vline(xintercept = as.POSIXct("2017-12-20"), linetype = 3) +
geom_vline(xintercept = as.POSIXct("2018-11-15"), linetype = 3) +
geom_vline(xintercept = as.POSIXct("2020-11-15"), linetype = 3) +
geom_text(data = ann_text.output, label = "github.com/Rucknium",
colour = "black", size = 4.5, check_overlap = TRUE)
)
dev.off()

View file

@ -6,7 +6,7 @@ bitcoin.conf.file <- ""
data.dir <- ""
# Input data directory here, with trailing "/"
bch.config <- rbch::conrpc(bitcoin.conf.file)
bitcoin.config <- rbch::conrpc(bitcoin.conf.file)
initial.fork.height <- 478558 - 1
@ -23,8 +23,8 @@ for (iter.block.height in initial.fork.height:current.block.height) {
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 = "l1")
block.hash <- rbch::getblockhash(bitcoin.config, iter.block.height)
block.data <- rbch::getblock(bitcoin.config, blockhash = block.hash@result, verbosity = "l1")
block.times[[iter.block.height - initial.fork.height + 1]] <-
data.frame(block_height = iter.block.height, block_time = block.data@result$time)
}