Skip to content

Commit

Permalink
Added utility functions, fixed BTC address
Browse files Browse the repository at this point in the history
  • Loading branch information
bpfaff committed Sep 4, 2018
1 parent 917a94a commit dd50bd4
Show file tree
Hide file tree
Showing 21 changed files with 296 additions and 145 deletions.
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ Package: rbtc
Title: Bitcoin API
Version: 0.1-4
Authors@R: person("Bernhard", "Pfaff", email = "[email protected]", role = c("aut", "cre"))
Description: Implementation of the RPC-JSON API for Bitcoin and utility functions for address creation.
Description: Implementation of the RPC-JSON API for Bitcoin and utility functions for address creation and content analysis of the blockchain.
Depends: R (>= 3.4.0)
License: GPL-3
Encoding: UTF-8
LazyData: true
RoxygenNote: 6.1.0
Imports: methods, rjson, httr, openssl, gmp
NeedsCompilation: no
Packaged: 2018-09-03 15:51:24 UTC; pfaffb
Packaged: 2018-09-04 12:43:26 UTC; pfaffb
Author: Bernhard Pfaff [aut, cre]
Maintainer: Bernhard Pfaff <[email protected]>
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export(Wif2PrivKey)
export(addnode)
export(base58CheckDecode)
export(base58CheckEncode)
export(bkfee)
export(blockattime)
export(blockstats)
export(clearbanned)
Expand Down Expand Up @@ -72,6 +73,7 @@ export(txids)
export(txinids)
export(txstats)
export(utxoage)
export(utxotype)
export(utxovalue)
export(validBtcAdr)
export(verifychain)
Expand Down
86 changes: 49 additions & 37 deletions R/BtcAddresses.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#' Creation of a private key
#'
#'
#' Returns a random 256-bit private key in hex notation.
#'
#' @return \code{character}.
Expand All @@ -8,19 +8,21 @@
#' @references \url{https://en.bitcoin.it/wiki/Wallet_import_format},\cr
#' \url{https://en.bitcoin.it/wiki/Address}
#' @name createPrivateKey
#' @aliases createPrivateKey
#' @aliases createPrivateKey
#' @rdname createPrivateKey
#' @examples
#' createPrivateKey()
#' @export
createPrivateKey <- function(){
warning(paste0("\nFor exemplary purposes, only.\n",
"Use at your own risk!\n"))
s <- "0123456789ABCDEF"
idx <- sample(1:16, 64, replace = TRUE)
pk <- sapply(idx, function(x) substr(s, x, x))
pk <- paste(pk, collapse = "")
pk
}
#' Create WIF from a private key
#' Create WIF from a private key
#'
#' Returns the corresponding WIF key from a private key
#'
Expand All @@ -29,19 +31,21 @@ createPrivateKey <- function(){
#' to the mainnet or testnet.
#'
#' @return \code{character}, the WIF key
#'
#'
#' @family BtcAdresses
#' @author Bernhard Pfaff
#' @references \url{https://en.bitcoin.it/wiki/Wallet_import_format},\cr
#' \url{https://en.bitcoin.it/wiki/Address}
#' @name PrivKey2Wif
#' @aliases PrivKey2Wif
#' @aliases PrivKey2Wif
#' @rdname PrivKey2Wif
#' @examples
#' pk <- createPrivateKey()
#' PrivKey2Wif(pk)
#' @export
PrivKey2Wif <- function(privkey, mainnet = TRUE){
warning(paste0("\nFor exemplary purposes, only.\n",
"Use at your own risk!\n"))
if (mainnet){
pke <- paste0("80", privkey)
} else {
Expand All @@ -53,20 +57,20 @@ PrivKey2Wif <- function(privkey, mainnet = TRUE){
privkeyextcs <- c(privkeyext, checksum)
base58CheckEncode(privkeyextcs)
}
#' Create private key from WIF
#' Create private key from WIF
#'
#' Returns the corresponding private key from a WIF key.
#'
#' @param wif \code{character}, a WIF key.
#'
#' @return \code{character}, the corresponding private key.
#'
#'
#' @family BtcAdresses
#' @author Bernhard Pfaff
#' @references \url{https://en.bitcoin.it/wiki/Wallet_import_format},\cr
#' \url{https://en.bitcoin.it/wiki/Address}
#' @name Wif2PrivKey
#' @aliases Wif2PrivKey
#' @aliases Wif2PrivKey
#' @rdname Wif2PrivKey
#' @examples
#' pk1 <- createPrivateKey()
Expand All @@ -75,6 +79,8 @@ PrivKey2Wif <- function(privkey, mainnet = TRUE){
#' identical(pk1, pk2)
#' @export
Wif2PrivKey <- function(wif){
warning(paste0("\nFor exemplary purposes, only.\n",
"Use at your own risk!\n"))
fc <- substr(wif, 1, 1)
if (!(fc %in% c("5", "9"))){
msg <- paste0("First character in WIF does neither\n",
Expand Down Expand Up @@ -104,10 +110,12 @@ Wif2PrivKey <- function(wif){
#' @author Bernhard Pfaff
#' @references \url{https://en.bitcoin.it/wiki/Address}
#' @name PrivKey2PubKey
#' @aliases PrivKey2PubKey
#' @aliases PrivKey2PubKey
#' @rdname PrivKey2PubKey
#' @export
PrivKey2PubKey <- function(privkey, mainnet = TRUE){
warning(paste0("\nFor exemplary purposes, only.\n",
"Use at your own risk!\n"))
pk <- paste0("0x", privkey, collapse = "")
pk <- gmp::as.bigz(pk)
p <- "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"
Expand Down Expand Up @@ -137,10 +145,12 @@ PrivKey2PubKey <- function(privkey, mainnet = TRUE){
#' @author Bernhard Pfaff
#' @references \url{https://en.bitcoin.it/wiki/Address}
#' @name PubKey2PubHash
#' @aliases PubKey2PubHash
#' @aliases PubKey2PubHash
#' @rdname PubKey2PubHash
#' @export
PubKey2PubHash <- function(pubkey, mainnet = TRUE){
warning(paste0("\nFor exemplary purposes, only.\n",
"Use at your own risk!\n"))
pubkey160 <- hash160(decodeHex(pubkey))
checksum <- pubkey160[1:4]
if (mainnet){
Expand All @@ -165,10 +175,12 @@ PubKey2PubHash <- function(pubkey, mainnet = TRUE){
#' @author Bernhard Pfaff
#' @references \url{https://en.bitcoin.it/wiki/Address}
#' @name PubHash2BtcAdr
#' @aliases PubHash2BtcAdr
#' @aliases PubHash2BtcAdr
#' @rdname PubHash2BtcAdr
#' @export
PubHash2BtcAdr <- function(pubhash){
warning(paste0("\nFor exemplary purposes, only.\n",
"Use at your own risk!\n"))
pubhashhex <- decodeHex(pubhash)
base58CheckEncode(pubhashhex)
}
Expand All @@ -184,15 +196,18 @@ PubHash2BtcAdr <- function(pubhash){
#' @author Bernhard Pfaff
#' @references \url{https://en.bitcoin.it/wiki/Address}
#' @name createBtcAdr
#' @aliases createBtcAdr
#' @aliases createBtcAdr
#' @rdname createBtcAdr
#' @export
createBtcAdr <- function(privkey, mainnet = TRUE){
pk <- sapply(seq(1, nchar(privkey), by = 2),
function(x) substr(privkey, x, x + 1))
if (mainnet){
createBtcAdr <- function (privkey, mainnet = TRUE) {
warning(paste0("\nFor exemplary purposes, only.\n",
"Use at your own risk!\n"))
pk <- sapply(seq(1, nchar(privkey), by = 2), function(x) substr(privkey,
x, x + 1))
if (mainnet) {
pke <- c("80", pk)
} else {
}
else {
pke <- c("ef", pk)
}
pke <- as.raw(strtoi(pke, base = 16L))
Expand All @@ -202,37 +217,34 @@ createBtcAdr <- function(privkey, mainnet = TRUE){
wif <- base58CheckEncode(pkecs)
pubkey <- PrivKey2PubKey(privkey)
pub160 <- hash160(decodeHex(pubkey))
cs <- pub160[1:4]
if (mainnet){
if (mainnet) {
pub160e <- c(decodeHex("00"), pub160)
} else {
}
else {
pub160e <- c(decodeHex("6f"), pub160)
}
cs <- hash256(pub160e)[1:4]
pubhash <- c(pub160e, cs)
btcadr <- base58CheckEncode(pubhash)
new("BTCADR",
privkey = privkey,
wif = wif,
pubkey = pubkey,
pubhash = toupper(paste(pubhash, collapse = "")),
btcadr = btcadr,
new("BTCADR", privkey = privkey, wif = wif, pubkey = pubkey,
pubhash = toupper(paste(pubhash, collapse = "")), btcadr = btcadr,
mainnet = mainnet)
}
#' Decoding of a hex string
#'
#'
#' This function converts a hex string,, whereby the string must not
#' contain the \code{0x} prefix, to a \code{list} object with the associated
#' integers as its elements.
#'
#' @param s \code{character}, the hex string.
#'
#'
#' @return \code{list}
#' @family BtcAdresses
#' @author Bernhard Pfaff
#' @references \url{https://en.bitcoin.it/wiki/Wallet_import_format},\cr
#' \url{https://en.bitcoin.it/wiki/Address}
#' @name decodeHex
#' @aliases decodeHex
#' @aliases decodeHex
#' @rdname decodeHex
#' @examples
#' pk <- createPrivateKey()
Expand All @@ -257,7 +269,7 @@ decodeHex <- function(s){
#' @references \url{https://en.bitcoin.it/wiki/Wallet_import_format},\cr
#' \url{https://en.bitcoin.it/wiki/Address}
#' @name concatHex
#' @aliases concatHex
#' @aliases concatHex
#' @rdname concatHex
#' @examples
#' h1 <- "80"
Expand Down Expand Up @@ -287,7 +299,7 @@ concatHex <- function(hex1, hex2){
#' \url{https://en.bitcoin.it/wiki/Address},\cr
#' \url{https://en.bitcoin.it/wiki/Base58Check_encoding}
#' @name base58CheckEncode
#' @aliases base58CheckEncode
#' @aliases base58CheckEncode
#' @rdname base58CheckEncode
#' @export
base58CheckEncode <- function(x){
Expand Down Expand Up @@ -323,7 +335,7 @@ base58CheckEncode <- function(x){
#' \url{https://en.bitcoin.it/wiki/Address},\cr
#' \url{https://en.bitcoin.it/wiki/Base58Check_encoding}
#' @name base58CheckDecode
#' @aliases base58CheckDecode
#' @aliases base58CheckDecode
#' @rdname base58CheckDecode
#' @export
base58CheckDecode <- function(x){
Expand All @@ -346,7 +358,7 @@ base58CheckDecode <- function(x){
}
decodeHex(shex)
}
#' BTC hash256
#' BTC hash256
#'
#' This function returns the hash by applying the \code{sha256} hashing
#' algorithm twice to a \code{raw} object.
Expand All @@ -358,7 +370,7 @@ base58CheckDecode <- function(x){
#' @author Bernhard Pfaff
#' @references \url{https://en.bitcoin.it/wiki/Address}
#' @name hash256
#' @aliases hash256
#' @aliases hash256
#' @rdname hash256
#' @export
hash256 <- function(d){
Expand All @@ -375,10 +387,10 @@ hash256 <- function(d){
d2 <- decodeHex(paste(d2, collapse = ":"))
d2
}
#' BTC hash160
#' BTC hash160
#'
#' This function returns the hash by applying the \code{sha256} hashing
#' first and then to the resulting hash the \code{ripemd160} algorithm.
#' first and then to the resulting hash the \code{ripemd160} algorithm.
#'
#' @param d \code{raw}, vector.
#'
Expand All @@ -388,7 +400,7 @@ hash256 <- function(d){
#' @author Bernhard Pfaff
#' @references \url{https://en.bitcoin.it/wiki/Address}
#' @name hash160
#' @aliases hash160
#' @aliases hash160
#' @rdname hash160
#' @export
hash160 <- function(d){
Expand Down
51 changes: 51 additions & 0 deletions R/UtilFuncs.R
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,30 @@ utxovalue <- function(con, txid){
)
ans
}
#' Retrieving types of UTXOs
#'
#' This function returns the types of the UTXO(s) in a transaction.
#'
#' @param con \code{CONRPC}, configuration object.
#' @param txid \code{character}, the id of the transaction.
#'
#' @return \code{character}
#' @family UtilityFuncs
#' @author Bernhard Pfaff
#' @name utxotype
#' @rdname utxotype
#' @export
utxotype <- function(con, txid){
txraw <- slot(getrawtransaction(con, txid),
"result")
txdec <- slot(decoderawtransaction(con, txraw),
"result")
vout <- txdec[["vout"]]
ans <- unlist(
lapply(vout, function(x) x[["type"]])
)
ans
}
#' Age of UTXOs
#'
#' This function returns a \code{difftime} object measuring the elapsed time(s)
Expand Down Expand Up @@ -293,6 +317,33 @@ txfee <- function(con, txid){
ans <- vali - valo
ans
}

#' Compute fee in a block
#'
#' This function returns the fee of the coinbase transaction.
#' Hereby, the mining reward has been deducted.
#' Initially, the mining reward was 50 BTC and is halved every
#' 210,000 blocks.
#'
#' @param con \code{CONRPC}, configuration object.
#' @param height \code{integer}, the height of the block.
#'
#' @return \code{numeric}
#' @family UtilityFuncs
#' @author Bernhard Pfaff
#' @name bkfee
#' @rdname bkfee
#' @export
bkfee <- function(con, height){
height <- as.integer(abs(height))
cb <- txids(con, height, excoinbase = FALSE)[1]
mtot <- utxovalue(con, cb)
hf <- ceiling(height / 209999) - 1
hf <- 2 ^ hf
mrwd <- 50 / hf
ans <- mtot - mrwd
ans
}
#' Obtaining statistics of a block
#'
#' This function returns key statistics of a block's content,
Expand Down
Loading

0 comments on commit dd50bd4

Please sign in to comment.