Add Mordinal/black marble analysis and plots

This commit is contained in:
Rucknium 2023-04-13 16:15:43 +00:00
parent af0e084ba7
commit 8f84e9db52
2 changed files with 201 additions and 0 deletions

View file

@ -0,0 +1,140 @@
# Must install:
# install.packages(c("data.table", "ggplot2", "scales"))
library(data.table)
library(ggplot2)
# Must also have scales package installed
p2pool.upgrade <- as.Date("2023-03-18")
first.mordinal <- as.Date("2023-03-10")
black.marble.share <- melt(black.marble.share, id.vars = "block_date", variable.factor = FALSE)
black.marble.share[grepl("mordinal", variable), variable := "Mordinal"]
black.marble.share[grepl("coinbase", variable), variable := "Coinbase"]
black.marble.share <- black.marble.share[block_date >= as.Date("2023-02-01"), ]
black.marble.share[variable == "Coinbase" & block_date < as.Date("2023-03-18"), mean(value)]
black.marble.share[variable == "Coinbase" & block_date > as.Date("2023-03-18"), mean(value)]
png("Monero-Effective-Ring-Size/analysis/images/mordinal-coinbase-output-share.png", width = 800, height = 800)
ggplot(black.marble.share) +
geom_line(aes(x = block_date, y = value, colour = variable), size = 1.5) +
ggtitle("Percentage of Monero Transaction Outputs That Are Mordinals and Coinbases") +
geom_vline( aes(xintercept = first.mordinal,
colour = "First Mordinal minted"), size = 1.5, linetype = 2, key_glyph = "rect") +
geom_vline( aes(xintercept = p2pool.upgrade,
colour = "P2Pool payout efficiency upgrade"), size = 1.5, linetype = 2, key_glyph = "rect") +
scale_colour_manual(name = NULL, aesthetics = c("colour", "fill"),
values = c("Mordinal" = "black", "Coinbase" = "darkgoldenrod2", "First Mordinal minted" = "khaki4",
"P2Pool payout efficiency upgrade" = "#FF6600FF")) +
xlab(" Date github.com/Rucknium") +
ylab("Share of Transaction Outputs") +
theme(plot.title = element_text(size = 20), legend.position = "top",
legend.text = element_text(size = 15),
axis.text = element_text(size = 15),
axis.title.x = element_text(size = 15, margin = margin(t = 10)),
axis.title.y = element_text(size = 15), strip.text = element_text(size = 15)) +
guides(colour = guide_legend(nrow = 2, byrow = TRUE)) +
geom_hline(aes(yintercept = 0), colour = "gray20") +
scale_y_continuous(labels = scales::percent_format(scale = 1),
breaks = seq(0, 100, by = 5), sec.axis = dup_axis(name = NULL))
dev.off()
eff.ring.size.stats.mean <- eff.ring.size.stats[, .(block_timestamp_ring.time.date,
effective.ring.size.coinbase.mean, effective.ring.size.mordinal.mean,
effective.ring.size.coinbase.mordinal.mean )]
eff.ring.size.stats.mean <- melt(eff.ring.size.stats.mean,
id.vars = "block_timestamp_ring.time.date", variable.factor = FALSE)
eff.ring.size.stats.mean <- eff.ring.size.stats.mean[block_timestamp_ring.time.date >= as.Date("2023-02-01"), ]
eff.ring.size.stats.mean[grepl("coinbase.mordinal", variable), variable := "Combined Mordinal & Coinbase"]
eff.ring.size.stats.mean[grepl("mordinal", variable), variable := "Mordinal"]
eff.ring.size.stats.mean[grepl("coinbase", variable), variable := "Coinbase"]
png("Monero-Effective-Ring-Size/analysis/images/mean-effective-ring-size.png", width = 800, height = 800)
ggplot(eff.ring.size.stats.mean) +
geom_line(aes(x = block_timestamp_ring.time.date , y = value, colour = variable), size = 1.5) +
ggtitle("Average Empirical Effective Ring Size of Monero Transactions") +
geom_vline( aes(xintercept = first.mordinal,
colour = "First Mordinal"), size = 1.5, linetype = 2, key_glyph = "rect") +
geom_vline( aes(xintercept = p2pool.upgrade,
colour = "P2Pool payout efficiency upgrade"), size = 1.5, linetype = 2, key_glyph = "rect") +
scale_color_manual(name = NULL,
values = c("Mordinal" = "black", "Coinbase" = "darkgoldenrod1", "Combined Mordinal & Coinbase" = "purple",
"First Mordinal" = "khaki4", "P2Pool payout efficiency upgrade" = "#FF6600FF")) +
xlab(" Date github.com/Rucknium") +
ylab("Effective ring size (ring size minus number of Mordinal/coinbase outputs in the ring)") +
theme(plot.title = element_text(size = 20), legend.position = "top",
legend.text = element_text(size = 15),
axis.text = element_text(size = 15),
axis.title.x = element_text(size = 15, margin = margin(t = 10)),
axis.title.y = element_text(size = 15), strip.text = element_text(size = 15)) +
guides(colour = guide_legend(nrow = 2, byrow = TRUE)) +
scale_y_continuous(breaks = 0:100, sec.axis = dup_axis(name = NULL))
# Have an axis tick at every integer
dev.off()
eff.ring.size.stats.5th.percentile <- eff.ring.size.stats[, .(block_timestamp_ring.time.date,
effective.ring.size.coinbase.percentile.05, effective.ring.size.mordinal.percentile.05,
effective.ring.size.coinbase.mordinal.percentile.05 )]
eff.ring.size.stats.5th.percentile <- melt(eff.ring.size.stats.5th.percentile,
id.vars = "block_timestamp_ring.time.date", variable.factor = FALSE)
eff.ring.size.stats.5th.percentile <- eff.ring.size.stats.5th.percentile[
block_timestamp_ring.time.date >= as.Date("2023-02-01"), ]
eff.ring.size.stats.5th.percentile[grepl("coinbase.mordinal", variable), variable := "Combined Mordinal & Coinbase"]
eff.ring.size.stats.5th.percentile[grepl("mordinal", variable), variable := "Mordinal"]
eff.ring.size.stats.5th.percentile[grepl("coinbase", variable), variable := "Coinbase"]
png("Monero-Effective-Ring-Size/analysis/images/5th-percentile-effective-ring-size.png", width = 800, height = 800)
ggplot(eff.ring.size.stats.5th.percentile) +
geom_line(aes(x = block_timestamp_ring.time.date , y = value, colour = variable), size = 1.5) +
ggtitle('Empirical Effective Ring Size for the "Unluckiest" 5 Percent of Monero Rings\n(i.e. 5th Percentile of Empirical Effective Ring Size)') +
geom_vline( aes(xintercept = first.mordinal,
colour = "First Mordinal"), size = 1.5, linetype = 2, key_glyph = "rect") +
geom_vline( aes(xintercept = p2pool.upgrade,
colour = "P2Pool payout efficiency upgrade"), size = 1.5, linetype = 2, key_glyph = "rect") +
scale_color_manual(name = NULL,
values = c("Mordinal" = "black", "Coinbase" = "darkgoldenrod1", "Combined Mordinal & Coinbase" = "purple",
"First Mordinal" = "khaki4", "P2Pool payout efficiency upgrade" = "#FF6600FF")) +
xlab(" Date github.com/Rucknium") +
ylab("Effective ring size (ring size minus number of Mordinal/coinbase outputs in the ring)") +
theme(plot.title = element_text(size = 20), legend.position = "top",
legend.text = element_text(size = 15),
axis.text = element_text(size = 15),
axis.title.x = element_text(size = 15, margin = margin(t = 10)),
axis.title.y = element_text(size = 15), strip.text = element_text(size = 15)) +
guides(colour = guide_legend(nrow = 2, byrow = TRUE)) +
scale_y_continuous(breaks = 0:100, sec.axis = dup_axis(name = NULL))
# Have an axis tick at every integer
dev.off()

View file

@ -0,0 +1,61 @@
# Must install:
# install.packages("data.table")
library(data.table)
black.marble.share <- output.index[, .(
coinbase.share = 100 * sum(tx_num == 1)/.N,
mordinal.share = 100 * sum(is_mordinal)/.N), by = "block_date"]
setorder(black.marble.share, block_date)
# Get number of Mordinals, fees paid, and tx size
output.index[is_mordinal & output_num == 1, .N]
output.index[is_mordinal & output_num == 1, sum(tx_fee) * 0.000000000001]
output.index[is_mordinal & output_num == 1, sum(tx_size_bytes)]
eff.ring.size <- xmr.rings[, .(
n.coinbase.ring.members = sum(tx_num == 1), n.mordinal.ring.members = sum(is_mordinal), ring.size = .N),
by = c("tx_hash", "input_num", "block_timestamp_ring")]
eff.ring.size[, share.mordinal.ring.members := n.mordinal.ring.members/ring.size]
eff.ring.size[, effective.ring.size.coinbase := ring.size - n.coinbase.ring.members]
eff.ring.size[, effective.ring.size.mordinal := ring.size - n.mordinal.ring.members]
eff.ring.size[, effective.ring.size.coinbase.mordinal := ring.size - n.coinbase.ring.members - n.mordinal.ring.members]
eff.ring.size[, block_timestamp_ring.time := as.POSIXct(block_timestamp_ring, origin = "1970-01-01")]
eff.ring.size.date <- unique(eff.ring.size[, .(block_timestamp_ring.time = block_timestamp_ring.time)])
eff.ring.size.date[, block_timestamp_ring.time.isoweek :=
paste(lubridate::isoyear(block_timestamp_ring.time),
formatC(lubridate::isoweek(block_timestamp_ring.time), width = 2, flag = "0"), sep = "-")]
eff.ring.size.date[, block_timestamp_ring.time.date := as.Date(block_timestamp_ring.time)]
eff.ring.size <- merge(eff.ring.size, eff.ring.size.date)
# speed improvement by splitting and then merging
setorder(eff.ring.size, block_timestamp_ring.time.date)
eff.ring.size.stats <- eff.ring.size[, .(
effective.ring.size.coinbase.mean = as.numeric(mean(effective.ring.size.coinbase)),
effective.ring.size.coinbase.median = as.numeric(median(effective.ring.size.coinbase)),
effective.ring.size.coinbase.percentile.05 = as.numeric(quantile(effective.ring.size.coinbase, probs = 0.05)),
effective.ring.size.mordinal.mean = as.numeric(mean(effective.ring.size.mordinal)),
effective.ring.size.mordinal.median = as.numeric(median(effective.ring.size.mordinal)),
effective.ring.size.mordinal.percentile.05 = as.numeric(quantile(effective.ring.size.mordinal, probs = 0.05)),
effective.ring.size.coinbase.mordinal.mean = as.numeric(mean(effective.ring.size.coinbase.mordinal)),
effective.ring.size.coinbase.mordinal.median = as.numeric(median(effective.ring.size.coinbase.mordinal)),
effective.ring.size.coinbase.mordinal.percentile.05 = as.numeric(quantile(effective.ring.size.coinbase.mordinal, probs = 0.05))
# as.numeric() to make sure results of each "by" subset are all floats
), by = "block_timestamp_ring.time.date"]
setorder(eff.ring.size.stats, block_timestamp_ring.time.date)