From 65b8f9dfdf60dfdb79554d0e2a3d5784d3cf3214 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Mon, 18 Jun 2018 17:36:55 +0200 Subject: [PATCH 1/7] Add namecoin backend package --- contrib/backends/Makefile | 2 +- contrib/backends/namecoin/Makefile | 13 +++++ .../debian/backend-namecoin.conffiles | 1 + .../namecoin/debian/backend-namecoin.dirs | 1 + .../namecoin/debian/backend-namecoin.install | 2 + .../debian/backend-namecoin.logrotate | 10 ++++ .../namecoin/debian/backend-namecoin.postinst | 20 ++++++++ .../namecoin/debian/backend-namecoin.service | 47 +++++++++++++++++++ contrib/backends/namecoin/debian/changelog | 5 ++ contrib/backends/namecoin/debian/compat | 1 + contrib/backends/namecoin/debian/control | 11 +++++ contrib/backends/namecoin/debian/rules | 11 +++++ contrib/backends/namecoin/namecoin.conf | 19 ++++++++ 13 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 contrib/backends/namecoin/Makefile create mode 100644 contrib/backends/namecoin/debian/backend-namecoin.conffiles create mode 100644 contrib/backends/namecoin/debian/backend-namecoin.dirs create mode 100644 contrib/backends/namecoin/debian/backend-namecoin.install create mode 100644 contrib/backends/namecoin/debian/backend-namecoin.logrotate create mode 100644 contrib/backends/namecoin/debian/backend-namecoin.postinst create mode 100644 contrib/backends/namecoin/debian/backend-namecoin.service create mode 100644 contrib/backends/namecoin/debian/changelog create mode 100644 contrib/backends/namecoin/debian/compat create mode 100644 contrib/backends/namecoin/debian/control create mode 100755 contrib/backends/namecoin/debian/rules create mode 100644 contrib/backends/namecoin/namecoin.conf diff --git a/contrib/backends/Makefile b/contrib/backends/Makefile index 2862f19e..be61a88e 100644 --- a/contrib/backends/Makefile +++ b/contrib/backends/Makefile @@ -1,4 +1,4 @@ -TARGETS = bitcoin zcash bcash ethereum bgold dash litecoin dogecoin +TARGETS = bitcoin zcash bcash ethereum bgold dash litecoin dogecoin namecoin IMAGE = blockbook-backend-build-deb NO_CACHE = false diff --git a/contrib/backends/namecoin/Makefile b/contrib/backends/namecoin/Makefile new file mode 100644 index 00000000..5b5d7498 --- /dev/null +++ b/contrib/backends/namecoin/Makefile @@ -0,0 +1,13 @@ +NAMECOIN_VERSION := 0.13.99 + +all: + wget https://namecoin.org/files/namecoin-core-${NAMECOIN_VERSION}-name-tab-beta1-notreproduced/namecoin-${NAMECOIN_VERSION}-x86_64-linux-gnu.tar.gz + tar -xf namecoin-${NAMECOIN_VERSION}-x86_64-linux-gnu.tar.gz + mv namecoin-${NAMECOIN_VERSION} namecoin + rm namecoin/bin/namecoin-qt + rm namecoin/bin/test_namecoin* + + +clean: + rm -rf namecoin + rm -f namecoin-${NAMECOIN_VERSION}-x86_64-linux-gnu.tar.gz diff --git a/contrib/backends/namecoin/debian/backend-namecoin.conffiles b/contrib/backends/namecoin/debian/backend-namecoin.conffiles new file mode 100644 index 00000000..723eb4b6 --- /dev/null +++ b/contrib/backends/namecoin/debian/backend-namecoin.conffiles @@ -0,0 +1 @@ +/opt/coins/nodes/namecoin/namecoin.conf diff --git a/contrib/backends/namecoin/debian/backend-namecoin.dirs b/contrib/backends/namecoin/debian/backend-namecoin.dirs new file mode 100644 index 00000000..e5a2195f --- /dev/null +++ b/contrib/backends/namecoin/debian/backend-namecoin.dirs @@ -0,0 +1 @@ +/opt/coins/data/namecoin/backend diff --git a/contrib/backends/namecoin/debian/backend-namecoin.install b/contrib/backends/namecoin/debian/backend-namecoin.install new file mode 100644 index 00000000..099e6621 --- /dev/null +++ b/contrib/backends/namecoin/debian/backend-namecoin.install @@ -0,0 +1,2 @@ +namecoin/* /opt/coins/nodes/namecoin +namecoin.conf /opt/coins/nodes/namecoin diff --git a/contrib/backends/namecoin/debian/backend-namecoin.logrotate b/contrib/backends/namecoin/debian/backend-namecoin.logrotate new file mode 100644 index 00000000..e3e59529 --- /dev/null +++ b/contrib/backends/namecoin/debian/backend-namecoin.logrotate @@ -0,0 +1,10 @@ +/opt/coins/data/namecoin/backend/debug.log +/opt/coins/data/namecoin/backend/db.log +{ + rotate 7 + daily + compress + missingok + notifempty + copytruncate +} diff --git a/contrib/backends/namecoin/debian/backend-namecoin.postinst b/contrib/backends/namecoin/debian/backend-namecoin.postinst new file mode 100644 index 00000000..2eae5e29 --- /dev/null +++ b/contrib/backends/namecoin/debian/backend-namecoin.postinst @@ -0,0 +1,20 @@ +#!/bin/bash +set -e + +case "$1" in + + configure) + if ! id -u namecoin &> /dev/null + then + useradd --system -M -U namecoin -s /bin/false + fi + + if [ "$(stat -c '%U' /opt/coins/data/namecoin/backend)" != "namecoin" ] + then + chown -R namecoin:namecoin /opt/coins/data/namecoin/backend + fi + ;; + +esac + +#DEBHELPER# diff --git a/contrib/backends/namecoin/debian/backend-namecoin.service b/contrib/backends/namecoin/debian/backend-namecoin.service new file mode 100644 index 00000000..1dd79fb7 --- /dev/null +++ b/contrib/backends/namecoin/debian/backend-namecoin.service @@ -0,0 +1,47 @@ +# It is not recommended to modify this file in-place, because it will +# be overwritten during package upgrades. If you want to add further +# options or overwrite existing ones then use +# $ systemctl edit namecoin.service +# See "man systemd.service" for details. + +# Note that almost all daemon options could be specified in +# /opt/coins/nodes/namecoin/namecoin.conf + +[Unit] +Description=Namecoin daemon (mainnet) +After=network.target + +[Service] +ExecStart=/opt/coins/nodes/namecoin/bin/namecoind -datadir=/opt/coins/data/namecoin/backend -conf=/opt/coins/nodes/namecoin/namecoin.conf -pid=/run/namecoind/namecoin.pid +# Creates /run/namecoind owned by namecoin +RuntimeDirectory=namecoind +User=namecoin +Type=forking +PIDFile=/run/namecoind/namecoin.pid +Restart=on-failure + +# Resource limits +LimitNOFILE=500000 + +# Hardening measures +#################### + +# Provide a private /tmp and /var/tmp. +PrivateTmp=true + +# Mount /usr, /boot/ and /etc read-only for the process. +ProtectSystem=full + +# Disallow the process and all of its children to gain +# new privileges through execve(). +NoNewPrivileges=true + +# Use a new /dev namespace only populated with API pseudo devices +# such as /dev/null, /dev/zero and /dev/random. +PrivateDevices=true + +# Deny the creation of writable and executable memory mappings. +# MemoryDenyWriteExecute=true + +[Install] +WantedBy=multi-user.target diff --git a/contrib/backends/namecoin/debian/changelog b/contrib/backends/namecoin/debian/changelog new file mode 100644 index 00000000..50f2bb4d --- /dev/null +++ b/contrib/backends/namecoin/debian/changelog @@ -0,0 +1,5 @@ +namecoin (0.13.99-satoshilabs1) unstable; urgency=medium + + * Initial build + + -- Martin Bohm Mon, 18 Jun 2018 11:12:13 +0200 diff --git a/contrib/backends/namecoin/debian/compat b/contrib/backends/namecoin/debian/compat new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/contrib/backends/namecoin/debian/compat @@ -0,0 +1 @@ +9 diff --git a/contrib/backends/namecoin/debian/control b/contrib/backends/namecoin/debian/control new file mode 100644 index 00000000..4726da03 --- /dev/null +++ b/contrib/backends/namecoin/debian/control @@ -0,0 +1,11 @@ +Source: namecoin +Section: satoshilabs +Priority: optional +Maintainer: martin.bohm@satoshilabs.com +Build-Depends: debhelper, wget, tar, gzip, make, dh-systemd, dh-exec +Standards-Version: 3.9.5 + +Package: backend-namecoin +Architecture: amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, logrotate +Description: Satoshilabs packaged namecoin server diff --git a/contrib/backends/namecoin/debian/rules b/contrib/backends/namecoin/debian/rules new file mode 100755 index 00000000..f69489df --- /dev/null +++ b/contrib/backends/namecoin/debian/rules @@ -0,0 +1,11 @@ +#!/usr/bin/make -f + +DH_VERBOSE = 1 + +%: + dh $@ --with=systemd + +override_dh_systemd_start: + dh_systemd_start --no-start + +override_dh_installinit: diff --git a/contrib/backends/namecoin/namecoin.conf b/contrib/backends/namecoin/namecoin.conf new file mode 100644 index 00000000..d33f9cdc --- /dev/null +++ b/contrib/backends/namecoin/namecoin.conf @@ -0,0 +1,19 @@ +daemon=1 +server=1 +nolisten=1 +rpcuser=rpc +rpcpassword=rpc +rpcport=8039 +txindex=1 +whitelist=127.0.0.1 +upnp=0 +discover=0 + +zmqpubhashtx=tcp://127.0.0.1:38339 +zmqpubhashblock=tcp://127.0.0.1:38339 + +rpcworkqueue=1100 +maxmempool=2000 +dbcache=1000 + + From afb50f55c803e1f3e0b4fad58358ab19a127bc82 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Tue, 19 Jun 2018 14:11:37 +0200 Subject: [PATCH 2/7] Update namecoin backend config file --- contrib/backends/namecoin/namecoin.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/backends/namecoin/namecoin.conf b/contrib/backends/namecoin/namecoin.conf index d33f9cdc..2671a69e 100644 --- a/contrib/backends/namecoin/namecoin.conf +++ b/contrib/backends/namecoin/namecoin.conf @@ -8,6 +8,10 @@ txindex=1 whitelist=127.0.0.1 upnp=0 discover=0 +whitelistrelay=1 +listenonion=0 + +addnode=45.24.110.177:8334 zmqpubhashtx=tcp://127.0.0.1:38339 zmqpubhashblock=tcp://127.0.0.1:38339 From e3f7a0ae5eb902a1389d0d788df908adaa864961 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Tue, 19 Jun 2018 14:39:53 +0200 Subject: [PATCH 3/7] Add parser utils to reuse commonly used function --- bchain/coins/btg/bgoldparser.go | 45 +--------- bchain/coins/dogecoin/dogecoinparser.go | 96 +--------------------- bchain/coins/utils/parserutils.go | 105 ++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 135 deletions(-) create mode 100644 bchain/coins/utils/parserutils.go diff --git a/bchain/coins/btg/bgoldparser.go b/bchain/coins/btg/bgoldparser.go index 7c20a005..67d2c7ef 100644 --- a/bchain/coins/btg/bgoldparser.go +++ b/bchain/coins/btg/bgoldparser.go @@ -3,8 +3,8 @@ package btg import ( "blockbook/bchain" "blockbook/bchain/coins/btc" + "blockbook/bchain/coins/utils" "bytes" - "fmt" "io" "github.com/btcsuite/btcd/chaincfg" @@ -72,19 +72,6 @@ func GetChainParams(chain string) *chaincfg.Params { } } -// minTxPayload is the minimum payload size for a transaction. Note -// that any realistically usable transaction must have at least one -// input or output, but that is a rule enforced at a higher layer, so -// it is intentionally not included here. -// Version 4 bytes + Varint number of transaction inputs 1 byte + Varint -// number of transaction outputs 1 byte + LockTime 4 bytes + min input -// payload + min output payload. -const minTxPayload = 10 - -// maxTxPerBlock is the maximum number of transactions that could -// possibly fit into a block. -const maxTxPerBlock = (wire.MaxBlockPayload / minTxPayload) + 1 - // headerFixedLength is the length of fixed fields of a block (i.e. without solution) // see https://github.com/BTCGPU/BTCGPU/wiki/Technical-Spec#block-header const headerFixedLength = 44 + (chainhash.HashSize * 3) @@ -98,7 +85,7 @@ func (p *BGoldParser) ParseBlock(b []byte) (*bchain.Block, error) { } w := wire.MsgBlock{} - err = decodeTransactions(r, 0, wire.WitnessEncoding, &w) + err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w) if err != nil { return nil, err } @@ -129,31 +116,3 @@ func skipHeader(r io.ReadSeeker, pver uint32) error { return nil } - -func decodeTransactions(r io.Reader, pver uint32, enc wire.MessageEncoding, blk *wire.MsgBlock) error { - txCount, err := wire.ReadVarInt(r, pver) - if err != nil { - return err - } - - // Prevent more transactions than could possibly fit into a block. - // It would be possible to cause memory exhaustion and panics without - // a sane upper bound on this count. - if txCount > maxTxPerBlock { - str := fmt.Sprintf("too many transactions to fit into a block "+ - "[count %d, max %d]", txCount, maxTxPerBlock) - return &wire.MessageError{Func: "btg.decodeTransactions", Description: str} - } - - blk.Transactions = make([]*wire.MsgTx, 0, txCount) - for i := uint64(0); i < txCount; i++ { - tx := wire.MsgTx{} - err := tx.BtcDecode(r, pver, enc) - if err != nil { - return err - } - blk.Transactions = append(blk.Transactions, &tx) - } - - return nil -} diff --git a/bchain/coins/dogecoin/dogecoinparser.go b/bchain/coins/dogecoin/dogecoinparser.go index 075cdfa9..ac7ea94b 100644 --- a/bchain/coins/dogecoin/dogecoinparser.go +++ b/bchain/coins/dogecoin/dogecoinparser.go @@ -3,9 +3,8 @@ package dogecoin import ( "blockbook/bchain" "blockbook/bchain/coins/btc" + "blockbook/bchain/coins/utils" "bytes" - "fmt" - "io" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" @@ -50,21 +49,6 @@ func GetChainParams(chain string) *chaincfg.Params { } } -// minTxPayload is the minimum payload size for a transaction. Note -// that any realistically usable transaction must have at least one -// input or output, but that is a rule enforced at a higher layer, so -// it is intentionally not included here. -// Version 4 bytes + Varint number of transaction inputs 1 byte + Varint -// number of transaction outputs 1 byte + LockTime 4 bytes + min input -// payload + min output payload. -const minTxPayload = 10 - -// maxTxPerBlock is the maximum number of transactions that could -// possibly fit into a block. -const maxTxPerBlock = (wire.MaxBlockPayload / minTxPayload) + 1 - -const versionAuxpow = (1 << 8) - // ParseBlock parses raw block to our Block struct // it has special handling for Auxpow blocks that cannot be parsed by standard btc wire parser func (p *DogecoinParser) ParseBlock(b []byte) (*bchain.Block, error) { @@ -75,57 +59,13 @@ func (p *DogecoinParser) ParseBlock(b []byte) (*bchain.Block, error) { if err != nil { return nil, err } - if (h.Version & versionAuxpow) != 0 { - // skip Auxpow part of the block - // https://github.com/dogecoin/dogecoin/blob/master/src/auxpow.h#L130 - // CMerkleTx CTransaction - tx := wire.MsgTx{} - err = tx.BtcDecode(r, 0, wire.WitnessEncoding) - if err != nil { - return nil, err - } - // CMerkleTx uint256 hashBlock - _, err = r.Seek(32, io.SeekCurrent) - if err != nil { - return nil, err - } - // CMerkleTx std::vector vMerkleBranch - size, err := wire.ReadVarInt(r, 0) - if err != nil { - return nil, err - } - _, err = r.Seek(int64(size)*32, io.SeekCurrent) - if err != nil { - return nil, err - } - // CMerkleTx int nIndex - _, err = r.Seek(4, io.SeekCurrent) - if err != nil { - return nil, err - } - // CAuxPow std::vector vChainMerkleBranch; - size, err = wire.ReadVarInt(r, 0) - if err != nil { - return nil, err - } - _, err = r.Seek(int64(size)*32, io.SeekCurrent) - if err != nil { - return nil, err - } - // CAuxPow int nChainIndex; - _, err = r.Seek(4, io.SeekCurrent) - if err != nil { - return nil, err - } - // CAuxPow CPureBlockHeader parentBlock; - ph := wire.BlockHeader{} - err = ph.Deserialize(r) - if err != nil { + if (h.Version & utils.VersionAuxpow) != 0 { + if err = utils.SkipAuxpow(r); err != nil { return nil, err } } - err = decodeTransactions(r, 0, wire.WitnessEncoding, &w) + err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w) if err != nil { return nil, err } @@ -137,31 +77,3 @@ func (p *DogecoinParser) ParseBlock(b []byte) (*bchain.Block, error) { return &bchain.Block{Txs: txs}, nil } - -func decodeTransactions(r io.Reader, pver uint32, enc wire.MessageEncoding, blk *wire.MsgBlock) error { - txCount, err := wire.ReadVarInt(r, pver) - if err != nil { - return err - } - - // Prevent more transactions than could possibly fit into a block. - // It would be possible to cause memory exhaustion and panics without - // a sane upper bound on this count. - if txCount > maxTxPerBlock { - str := fmt.Sprintf("too many transactions to fit into a block "+ - "[count %d, max %d]", txCount, maxTxPerBlock) - return &wire.MessageError{Func: "btg.decodeTransactions", Description: str} - } - - blk.Transactions = make([]*wire.MsgTx, 0, txCount) - for i := uint64(0); i < txCount; i++ { - tx := wire.MsgTx{} - err := tx.BtcDecode(r, pver, enc) - if err != nil { - return err - } - blk.Transactions = append(blk.Transactions, &tx) - } - - return nil -} diff --git a/bchain/coins/utils/parserutils.go b/bchain/coins/utils/parserutils.go new file mode 100644 index 00000000..4fbe422c --- /dev/null +++ b/bchain/coins/utils/parserutils.go @@ -0,0 +1,105 @@ +package utils + +import ( + "fmt" + "io" + + "github.com/btcsuite/btcd/wire" +) + +// minTxPayload is the minimum payload size for a transaction. Note +// that any realistically usable transaction must have at least one +// input or output, but that is a rule enforced at a higher layer, so +// it is intentionally not included here. +// Version 4 bytes + Varint number of transaction inputs 1 byte + Varint +// number of transaction outputs 1 byte + LockTime 4 bytes + min input +// payload + min output payload. +const minTxPayload = 10 + +// maxTxPerBlock is the maximum number of transactions that could +// possibly fit into a block. +const maxTxPerBlock = (wire.MaxBlockPayload / minTxPayload) + 1 + +// DecodeTransactions decodes transactions from input stream using wire +func DecodeTransactions(r io.Reader, pver uint32, enc wire.MessageEncoding, blk *wire.MsgBlock) error { + txCount, err := wire.ReadVarInt(r, pver) + if err != nil { + return err + } + + // Prevent more transactions than could possibly fit into a block. + // It would be possible to cause memory exhaustion and panics without + // a sane upper bound on this count. + if txCount > maxTxPerBlock { + str := fmt.Sprintf("too many transactions to fit into a block "+ + "[count %d, max %d]", txCount, maxTxPerBlock) + return &wire.MessageError{Func: "btg.decodeTransactions", Description: str} + } + + blk.Transactions = make([]*wire.MsgTx, 0, txCount) + for i := uint64(0); i < txCount; i++ { + tx := wire.MsgTx{} + err := tx.BtcDecode(r, pver, enc) + if err != nil { + return err + } + blk.Transactions = append(blk.Transactions, &tx) + } + + return nil +} + +// VersionAuxpow marks that block contains Auxpow +const VersionAuxpow = (1 << 8) + +// SkipAuxpow skips Auxpow data in block +func SkipAuxpow(r io.ReadSeeker) error { + // skip Auxpow part of the block + // https://github.com/dogecoin/dogecoin/blob/master/src/auxpow.h#L130 + // CMerkleTx CTransaction + tx := wire.MsgTx{} + err := tx.BtcDecode(r, 0, wire.WitnessEncoding) + if err != nil { + return err + } + // CMerkleTx uint256 hashBlock + _, err = r.Seek(32, io.SeekCurrent) + if err != nil { + return err + } + // CMerkleTx std::vector vMerkleBranch + size, err := wire.ReadVarInt(r, 0) + if err != nil { + return err + } + _, err = r.Seek(int64(size)*32, io.SeekCurrent) + if err != nil { + return err + } + // CMerkleTx int nIndex + _, err = r.Seek(4, io.SeekCurrent) + if err != nil { + return err + } + // CAuxPow std::vector vChainMerkleBranch; + size, err = wire.ReadVarInt(r, 0) + if err != nil { + return err + } + _, err = r.Seek(int64(size)*32, io.SeekCurrent) + if err != nil { + return err + } + // CAuxPow int nChainIndex; + _, err = r.Seek(4, io.SeekCurrent) + if err != nil { + return err + } + // CAuxPow CPureBlockHeader parentBlock; + ph := wire.BlockHeader{} + err = ph.Deserialize(r) + if err != nil { + return err + } + return nil +} From e909ae454bbe9deefd262650ca7640939d0dcc26 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Wed, 20 Jun 2018 17:57:51 +0200 Subject: [PATCH 4/7] Add namecoin blockbook implementation --- bchain/coins/blockchain.go | 2 + bchain/coins/namecoin/namecoinparser.go | 80 ++++++++++++++ bchain/coins/namecoin/namecoinparser_test.go | 103 ++++++++++++++++++ bchain/coins/namecoin/namecoinrpc.go | 76 +++++++++++++ .../coins/namecoin/testdata/block_dump.40000 | 1 + bchain/coins/{zec => utils}/address.go | 3 +- bchain/coins/zec/zcashparser.go | 5 +- configs/namecoin.json | 12 ++ 8 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 bchain/coins/namecoin/namecoinparser.go create mode 100644 bchain/coins/namecoin/namecoinparser_test.go create mode 100644 bchain/coins/namecoin/namecoinrpc.go create mode 100644 bchain/coins/namecoin/testdata/block_dump.40000 rename bchain/coins/{zec => utils}/address.go (98%) create mode 100644 configs/namecoin.json diff --git a/bchain/coins/blockchain.go b/bchain/coins/blockchain.go index 12827037..605d80b3 100644 --- a/bchain/coins/blockchain.go +++ b/bchain/coins/blockchain.go @@ -9,6 +9,7 @@ import ( "blockbook/bchain/coins/dogecoin" "blockbook/bchain/coins/eth" "blockbook/bchain/coins/litecoin" + "blockbook/bchain/coins/namecoin" "blockbook/bchain/coins/zec" "blockbook/common" "context" @@ -40,6 +41,7 @@ func init() { blockChainFactories["Litecoin"] = litecoin.NewLitecoinRPC blockChainFactories["Litecoin Testnet"] = litecoin.NewLitecoinRPC blockChainFactories["Dogecoin"] = dogecoin.NewDogecoinRPC + blockChainFactories["Namecoin"] = namecoin.NewNamecoinRPC } // GetCoinNameFromConfig gets coin name from config file diff --git a/bchain/coins/namecoin/namecoinparser.go b/bchain/coins/namecoin/namecoinparser.go new file mode 100644 index 00000000..eba53f9d --- /dev/null +++ b/bchain/coins/namecoin/namecoinparser.go @@ -0,0 +1,80 @@ +package namecoin + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "blockbook/bchain/coins/utils" + "bytes" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/wire" +) + +const ( + MainnetMagic wire.BitcoinNet = 0xfeb4bef9 +) + +var ( + MainNetParams chaincfg.Params +) + +func init() { + MainNetParams = chaincfg.MainNetParams + MainNetParams.Net = MainnetMagic + MainNetParams.PubKeyHashAddrID = 52 + MainNetParams.ScriptHashAddrID = 13 + MainNetParams.Bech32HRPSegwit = "nc" + + err := chaincfg.Register(&MainNetParams) + if err != nil { + panic(err) + } +} + +// NamecoinParser handle +type NamecoinParser struct { + *btc.BitcoinParser +} + +// NewNamecoinParser returns new NamecoinParser instance +func NewNamecoinParser(params *chaincfg.Params, c *btc.Configuration) *NamecoinParser { + return &NamecoinParser{BitcoinParser: btc.NewBitcoinParser(params, c)} +} + +// GetChainParams contains network parameters for the main Namecoin network, +// and the test Namecoin network +func GetChainParams(chain string) *chaincfg.Params { + switch chain { + default: + return &MainNetParams + } +} + +// ParseBlock parses raw block to our Block struct +// it has special handling for Auxpow blocks that cannot be parsed by standard btc wire parser +func (p *NamecoinParser) ParseBlock(b []byte) (*bchain.Block, error) { + r := bytes.NewReader(b) + w := wire.MsgBlock{} + h := wire.BlockHeader{} + err := h.Deserialize(r) + if err != nil { + return nil, err + } + if (h.Version & utils.VersionAuxpow) != 0 { + if err = utils.SkipAuxpow(r); err != nil { + return nil, err + } + } + + err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w) + if err != nil { + return nil, err + } + + txs := make([]bchain.Tx, len(w.Transactions)) + for ti, t := range w.Transactions { + txs[ti] = p.TxFromMsgTx(t, false) + } + + return &bchain.Block{Txs: txs}, nil +} diff --git a/bchain/coins/namecoin/namecoinparser_test.go b/bchain/coins/namecoin/namecoinparser_test.go new file mode 100644 index 00000000..0bdce63c --- /dev/null +++ b/bchain/coins/namecoin/namecoinparser_test.go @@ -0,0 +1,103 @@ +package namecoin + +import ( + "blockbook/bchain/coins/btc" + "bytes" + "encoding/hex" + "fmt" + "io/ioutil" + "path/filepath" + "reflect" + "testing" +) + +func TestAddressToOutputScript_Mainnet(t *testing.T) { + type args struct { + address string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "P2PKH1", + args: args{address: "MzBvZ4F759X6wHTjzwkMEbKh12am3PHT6F"}, + want: "76a91427a1f12771de5cc3b73941664b2537c15316be4388ac", + wantErr: false, + }, + { + name: "P2PKH2", + args: args{address: "N8Jkcm44Uq55GdmPojkpuGyoW4Cm658TwW"}, + want: "76a91480ad90d403581fa3bf46086a91b2d9d4125db6c188ac", + wantErr: false, + }, + } + parser := NewNamecoinParser(GetChainParams("main"), &btc.Configuration{}) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parser.AddressToOutputScript(tt.args.address) + if (err != nil) != tt.wantErr { + t.Errorf("AddressToOutputScript() error = %v, wantErr %v", err, tt.wantErr) + return + } + h := hex.EncodeToString(got) + if !reflect.DeepEqual(h, tt.want) { + t.Errorf("AddressToOutputScript() = %v, want %v", h, tt.want) + } + }) + } +} + +var testParseBlockTxs = map[int][]string{ + 40000: []string{ + "e193a821393b20b99f4a4e05a481368ef8a8cfd43d0c45bdad7f53bc9535e844", + "ddcbf95797e81dd04127885bd001e96695b717e11c52721f6e8ee53f6dea8a6f", + "31ff728f24200f59fa4958e6c26de03d172b320e6eef2b8abecf6f94d01dd4ae", + }, +} + +func helperLoadBlock(t *testing.T, height int) []byte { + name := fmt.Sprintf("block_dump.%d", height) + path := filepath.Join("testdata", name) + + d, err := ioutil.ReadFile(path) + if err != nil { + t.Fatal(err) + } + + d = bytes.TrimSpace(d) + + b := make([]byte, hex.DecodedLen(len(d))) + _, err = hex.Decode(b, d) + if err != nil { + t.Fatal(err) + } + + return b +} + +func TestParseBlock(t *testing.T) { + p := NewNamecoinParser(GetChainParams("main"), &btc.Configuration{}) + + for height, txs := range testParseBlockTxs { + b := helperLoadBlock(t, height) + + blk, err := p.ParseBlock(b) + if err != nil { + t.Fatal(err) + } + + if len(blk.Txs) != len(txs) { + t.Errorf("ParseBlock() number of transactions: got %d, want %d", len(blk.Txs), len(txs)) + } + + for ti, tx := range txs { + if blk.Txs[ti].Txid != tx { + t.Errorf("ParseBlock() transaction %d: got %s, want %s", ti, blk.Txs[ti].Txid, tx) + } + } + } +} diff --git a/bchain/coins/namecoin/namecoinrpc.go b/bchain/coins/namecoin/namecoinrpc.go new file mode 100644 index 00000000..faa14fd3 --- /dev/null +++ b/bchain/coins/namecoin/namecoinrpc.go @@ -0,0 +1,76 @@ +package namecoin + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "encoding/json" + + "github.com/golang/glog" +) + +// NamecoinRPC is an interface to JSON-RPC namecoin service. +type NamecoinRPC struct { + *btc.BitcoinRPC +} + +// NewNamecoinRPC returns new NamecoinRPC instance. +func NewNamecoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) { + b, err := btc.NewBitcoinRPC(config, pushHandler) + if err != nil { + return nil, err + } + + s := &NamecoinRPC{ + b.(*btc.BitcoinRPC), + } + s.RPCMarshaler = btc.JSONMarshalerV1{} + + return s, nil +} + +// Initialize initializes NamecoinRPC instance. +func (b *NamecoinRPC) Initialize() error { + chainName, err := b.GetChainInfoAndInitializeMempool(b) + if err != nil { + return err + } + + glog.Info("Chain name ", chainName) + params := GetChainParams(chainName) + + // always create parser + b.Parser = NewNamecoinParser(params, b.ChainConfig) + + // parameters for getInfo request + if params.Net == MainnetMagic { + b.Testnet = false + b.Network = "livenet" + } else { + b.Testnet = true + b.Network = "testnet" + } + + glog.Info("rpc: block chain ", params.Name) + + return nil +} + +// GetBlock returns block with given hash. +func (b *NamecoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) { + var err error + if hash == "" { + hash, err = b.GetBlockHash(height) + if err != nil { + return nil, err + } + } + if !b.ParseBlocks { + return b.GetBlockFull(hash) + } + return b.GetBlockWithoutHeader(hash, height) +} + +// EstimateSmartFee returns fee estimation. +func (b *NamecoinRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) { + return b.EstimateFee(blocks) +} diff --git a/bchain/coins/namecoin/testdata/block_dump.40000 b/bchain/coins/namecoin/testdata/block_dump.40000 new file mode 100644 index 00000000..bd0c7925 --- /dev/null +++ b/bchain/coins/namecoin/testdata/block_dump.40000 @@ -0,0 +1 @@ +0101010097d1d2cc478b4133407fc1ad4d8c8933b6c609b4ad32ddc4847bc25915cf2fe262408198c85ce883099de301b529280bd925791e3cad9404135dacee2f0d4250bd87234f8780201a0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff49043fd40c1a02a045122f503253482f42495031362f736c7573682f522cfabe6d6d40b41e94828aee66c19918b4da58a8d172329d321390ee9d260f7988402aa7b80100000000000000ffffffff0100f2052a01000000434104d31303d99295c26106241ba05bd4f0cf8019f0e2d23eb974b19b3eb13299d15e40c483af4517c8351307965d48697623e2b1a694ddff9a6d87d3ed349c1a1777ac00000000688dfcc6adf63446c8730082fa891ea665619311f4b409c4ec1800000000000004424a004f96a7100aed62e4f864c8d9234ef13bc8ceec263dbed155788c819552e72db83155702b8876691c102e598b8c7a94a32db86a54a8a47327ec2010ff2282939c62b3b1c218535a06c7912c3661c7074802d48e2d92b59acaba1f064c6e3f5352dc79864c6d856220657538a996835960ceedadc231a0ee376008d4b58d00000000000000000001000000fd28a68536508d85160396eb7341aa24749702d0c5db994d1e070000000000004e109c00dceed1da22ee7190fa9d7ad209ceb20c128ea7ce8a8cfb4befae011dc888234f3fd40c1a36d24c8d0301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08048780201a010152ffffffff01a078072a01000000434104e926558cfefc8bc7fb256b681ee0edf15565c6174549b7f1293fcc0be208ed86f1a14cc18ea94ffa9c52b171d81f1d1efed00941bafeab92cc251c2d2aa345a3ac000000000071000002a93033530122276984f390bb2f974e1a7ff8da5f1be917838fa7b0352aa47678010000008b48304502201a1c6a80a0f0a3c5ea73be2b72d1f430e9eff43b6af4c735dc4ba6acd616640f022100a6680fbe27215365015007470d8bd6f38b49110916244eff5734a30124ef842901410499891bc83f6cf8aa1e538fa24320c072105753c078edcbbd8ce672c6eda9d94fc0aa38bf9b07cc6a3390bc0d7753a285f31eafc4c3dfdfbea00b492cb24f6ac5ffffffffa93033530122276984f390bb2f974e1a7ff8da5f1be917838fa7b0352aa476780000000049483045022100b43dbe3306698000cbb760947b31c99e87479861c208434db9dae8261479bd1f022054f044785dd0e67d71b7dd8d0bc0eb92b112436352d441854c550b80a62d8bb201ffffffff0340420f00000000003e520e467574726f6e204e75636c656172094cdb42c80c00f697000852455345525645446d6d76a914053a73e0c100ae994c6cd5cb128930bf0c33eb2d88ac802a645f0000000043410480294ad87bc7bad362df1c244048bc5e767004898acf42066366e4e191d2d485935f179aaa6247c614a0403d6ca4deefd86d076a23616c5a4c957c5231a99c87ac00093d0000000000016a0000000000710000016f8aea6d3fe58e6e1f72521ce117b79566e901d05b882741d01de89757f9cbdd010000004a493046022100ec16ef5125b67272706305419077bc40b849f84610624bf744ff1b1498d0cb29022100979407f7378eb5e2beff9f5a952410e7f4a4581182ccafcbcd73aecd9ded1e8f01ffffffff02f024545f000000004341047ffb631e4f525c756bf21225845cd7cdd7736151da56db362dac829a7d8de9789deba832d88e5a943036c3221156dc28224636669ef6c5865451a41aa5ebfc37ac40420f000000000030511426dc02d4a5aaeeab17e1872c761f3cca247c00896d76a9141728f2e7af41221eb00a7fa373cc0630afd382ea88ac00000000 \ No newline at end of file diff --git a/bchain/coins/zec/address.go b/bchain/coins/utils/address.go similarity index 98% rename from bchain/coins/zec/address.go rename to bchain/coins/utils/address.go index be69c4a3..9fb2708e 100644 --- a/bchain/coins/zec/address.go +++ b/bchain/coins/utils/address.go @@ -1,8 +1,9 @@ -package zec +package utils import ( "crypto/sha256" "errors" + "github.com/btcsuite/btcutil/base58" ) diff --git a/bchain/coins/zec/zcashparser.go b/bchain/coins/zec/zcashparser.go index 60c23276..eacf8bbd 100644 --- a/bchain/coins/zec/zcashparser.go +++ b/bchain/coins/zec/zcashparser.go @@ -3,6 +3,7 @@ package zec import ( "blockbook/bchain" "blockbook/bchain/coins/btc" + "blockbook/bchain/coins/utils" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" @@ -54,12 +55,12 @@ func (p *ZCashParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { if len(output.ScriptPubKey.Addresses) != 1 { return nil, nil } - hash, _, err := CheckDecode(output.ScriptPubKey.Addresses[0]) + hash, _, err := utils.CheckDecode(output.ScriptPubKey.Addresses[0]) return hash, err } // GetAddrIDFromAddress returns internal address representation of given address func (p *ZCashParser) GetAddrIDFromAddress(address string) ([]byte, error) { - hash, _, err := CheckDecode(address) + hash, _, err := utils.CheckDecode(address) return hash, err } diff --git a/configs/namecoin.json b/configs/namecoin.json new file mode 100644 index 00000000..8fadb00d --- /dev/null +++ b/configs/namecoin.json @@ -0,0 +1,12 @@ +{ + "coin_name": "Namecoin", + "rpcURL": "http://127.0.0.1:8039", + "rpcUser": "rpc", + "rpcPass": "rpc", + "rpcTimeout": 25, + "parse": true, + "zeroMQBinding": "tcp://127.0.0.1:38339", + "mempoolWorkers": 8, + "mempoolSubWorkers": 2, + "blockAddressesToKeep": 300 +} From cd6df1f5caea11b966349bc9f562dbf84a9a6fe5 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Wed, 20 Jun 2018 18:00:08 +0200 Subject: [PATCH 5/7] Add namecoin blockbook debian package --- build/deb/debian/blockbook-namecoin.conffiles | 1 + .../deb/debian/blockbook-namecoin.cron.daily | 2 + build/deb/debian/blockbook-namecoin.dirs | 2 + build/deb/debian/blockbook-namecoin.install | 6 +++ build/deb/debian/blockbook-namecoin.links | 2 + build/deb/debian/blockbook-namecoin.postinst | 23 ++++++++++ build/deb/debian/blockbook-namecoin.service | 43 +++++++++++++++++++ build/deb/debian/control | 5 +++ 8 files changed, 84 insertions(+) create mode 100644 build/deb/debian/blockbook-namecoin.conffiles create mode 100644 build/deb/debian/blockbook-namecoin.cron.daily create mode 100644 build/deb/debian/blockbook-namecoin.dirs create mode 100755 build/deb/debian/blockbook-namecoin.install create mode 100644 build/deb/debian/blockbook-namecoin.links create mode 100644 build/deb/debian/blockbook-namecoin.postinst create mode 100644 build/deb/debian/blockbook-namecoin.service diff --git a/build/deb/debian/blockbook-namecoin.conffiles b/build/deb/debian/blockbook-namecoin.conffiles new file mode 100644 index 00000000..0a22d717 --- /dev/null +++ b/build/deb/debian/blockbook-namecoin.conffiles @@ -0,0 +1 @@ +/opt/coins/blockbook/namecoin/config/blockchaincfg.json diff --git a/build/deb/debian/blockbook-namecoin.cron.daily b/build/deb/debian/blockbook-namecoin.cron.daily new file mode 100644 index 00000000..dd3a2d73 --- /dev/null +++ b/build/deb/debian/blockbook-namecoin.cron.daily @@ -0,0 +1,2 @@ +#!/bin/sh +/opt/coins/blockbook/namecoin/bin/logrotate.sh diff --git a/build/deb/debian/blockbook-namecoin.dirs b/build/deb/debian/blockbook-namecoin.dirs new file mode 100644 index 00000000..83f92862 --- /dev/null +++ b/build/deb/debian/blockbook-namecoin.dirs @@ -0,0 +1,2 @@ +/opt/coins/data/namecoin/blockbook +/opt/coins/blockbook/namecoin/logs diff --git a/build/deb/debian/blockbook-namecoin.install b/build/deb/debian/blockbook-namecoin.install new file mode 100755 index 00000000..603f1500 --- /dev/null +++ b/build/deb/debian/blockbook-namecoin.install @@ -0,0 +1,6 @@ +#!/usr/bin/dh-exec +blockbook /opt/coins/blockbook/namecoin/bin +cert /opt/coins/blockbook/namecoin +static /opt/coins/blockbook/namecoin +configs/namecoin.json => /opt/coins/blockbook/namecoin/config/blockchaincfg.json +logrotate.sh /opt/coins/blockbook/namecoin/bin diff --git a/build/deb/debian/blockbook-namecoin.links b/build/deb/debian/blockbook-namecoin.links new file mode 100644 index 00000000..12f9e387 --- /dev/null +++ b/build/deb/debian/blockbook-namecoin.links @@ -0,0 +1,2 @@ +/opt/coins/blockbook/namecoin/cert/testcert.crt /opt/coins/blockbook/namecoin/cert/blockbook.crt +/opt/coins/blockbook/namecoin/cert/testcert.key /opt/coins/blockbook/namecoin/cert/blockbook.key diff --git a/build/deb/debian/blockbook-namecoin.postinst b/build/deb/debian/blockbook-namecoin.postinst new file mode 100644 index 00000000..81a4a97a --- /dev/null +++ b/build/deb/debian/blockbook-namecoin.postinst @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +case "$1" in + + configure) + if ! id -u blockbook-namecoin &> /dev/null + then + useradd --system -M -U blockbook-namecoin -s /bin/false + fi + + for dir in /opt/coins/data/namecoin/blockbook /opt/coins/blockbook/namecoin/logs + do + if [ "$(stat -c '%U' $dir)" != "blockbook-namecoin" ] + then + chown -R blockbook-namecoin:blockbook-namecoin $dir + fi + done + ;; + +esac + +#DEBHELPER# diff --git a/build/deb/debian/blockbook-namecoin.service b/build/deb/debian/blockbook-namecoin.service new file mode 100644 index 00000000..c2e525f6 --- /dev/null +++ b/build/deb/debian/blockbook-namecoin.service @@ -0,0 +1,43 @@ +# It is not recommended to modify this file in-place, because it will +# be overwritten during package upgrades. If you want to add further +# options or overwrite existing ones then use +# $ systemctl edit blockbook-namecoin.service +# See "man systemd.service" for details. + +[Unit] +Description=Blockbook daemon (Namecoin mainnet) +After=network.target +Wants=backend-namecoin.service + +[Service] +ExecStart=/opt/coins/blockbook/namecoin/bin/blockbook -blockchaincfg=/opt/coins/blockbook/namecoin/config/blockchaincfg.json -datadir=/opt/coins/data/namecoin/blockbook/db -sync -httpserver=:9034 -socketio=:9134 -certfile=/opt/coins/blockbook/namecoin/cert/blockbook -explorer=https://ltc-explorer.trezor.io/ -log_dir=/opt/coins/blockbook/namecoin/logs +User=blockbook-namecoin +Type=simple +Restart=on-failure +WorkingDirectory=/opt/coins/blockbook/namecoin + +# Resource limits +LimitNOFILE=500000 + +# Hardening measures +#################### + +# Provide a private /tmp and /var/tmp. +PrivateTmp=true + +# Mount /usr, /boot/ and /etc read-only for the process. +ProtectSystem=full + +# Disallow the process and all of its children to gain +# new privileges through execve(). +NoNewPrivileges=true + +# Use a new /dev namespace only populated with API pseudo devices +# such as /dev/null, /dev/zero and /dev/random. +PrivateDevices=true + +# Deny the creation of writable and executable memory mappings. +MemoryDenyWriteExecute=true + +[Install] +WantedBy=multi-user.target diff --git a/build/deb/debian/control b/build/deb/debian/control index 1557d713..05cc65fd 100644 --- a/build/deb/debian/control +++ b/build/deb/debian/control @@ -79,3 +79,8 @@ Package: blockbook-dogecoin Architecture: amd64 Depends: ${shlibs:Depends}, ${misc:Depends}, coreutils, passwd, findutils, psmisc, backend-dogecoin Description: Satoshilabs blockbook server (Dogecoin mainnet) + +Package: blockbook-namecoin +Architecture: amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, coreutils, passwd, findutils, psmisc, backend-namecoin +Description: Satoshilabs blockbook server (Dogecoin mainnet) From 7ecddfe7d0cd85d2ccf17e42bb9391b59dc96ae2 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Wed, 20 Jun 2018 18:15:09 +0200 Subject: [PATCH 6/7] Update namecoin blockbook service config --- build/deb/debian/blockbook-namecoin.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/deb/debian/blockbook-namecoin.service b/build/deb/debian/blockbook-namecoin.service index c2e525f6..db5f440b 100644 --- a/build/deb/debian/blockbook-namecoin.service +++ b/build/deb/debian/blockbook-namecoin.service @@ -10,7 +10,7 @@ After=network.target Wants=backend-namecoin.service [Service] -ExecStart=/opt/coins/blockbook/namecoin/bin/blockbook -blockchaincfg=/opt/coins/blockbook/namecoin/config/blockchaincfg.json -datadir=/opt/coins/data/namecoin/blockbook/db -sync -httpserver=:9034 -socketio=:9134 -certfile=/opt/coins/blockbook/namecoin/cert/blockbook -explorer=https://ltc-explorer.trezor.io/ -log_dir=/opt/coins/blockbook/namecoin/logs +ExecStart=/opt/coins/blockbook/namecoin/bin/blockbook -blockchaincfg=/opt/coins/blockbook/namecoin/config/blockchaincfg.json -datadir=/opt/coins/data/namecoin/blockbook/db -sync -httpserver=:9039 -socketio=:9139 -certfile=/opt/coins/blockbook/namecoin/cert/blockbook -explorer=https://namecha.in/ -log_dir=/opt/coins/blockbook/namecoin/logs User=blockbook-namecoin Type=simple Restart=on-failure From 76d99ccee10a9151db4124d395c2a6160ef1df26 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Wed, 20 Jun 2018 23:57:06 +0200 Subject: [PATCH 7/7] Remove bech32 prefix from namecoin --- bchain/coins/namecoin/namecoinparser.go | 1 - 1 file changed, 1 deletion(-) diff --git a/bchain/coins/namecoin/namecoinparser.go b/bchain/coins/namecoin/namecoinparser.go index eba53f9d..344dbeb4 100644 --- a/bchain/coins/namecoin/namecoinparser.go +++ b/bchain/coins/namecoin/namecoinparser.go @@ -23,7 +23,6 @@ func init() { MainNetParams.Net = MainnetMagic MainNetParams.PubKeyHashAddrID = 52 MainNetParams.ScriptHashAddrID = 13 - MainNetParams.Bech32HRPSegwit = "nc" err := chaincfg.Register(&MainNetParams) if err != nil {