├── .dockerignore
├── .gitignore
├── .gitmodules
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── bitcoin-mainnet.yml
├── bitcoin-testnet.yml
├── build.sh
├── build
└── base
│ └── Dockerfile
├── coins
├── bitcoin-mainnet.json
├── bitcoin-testnet.json
├── litecoin-mainnet.json
├── litecoin-testnet.json
├── vertcoin-mainnet.json
└── vertcoin-testnet.json
├── docker-compose.yml
├── litecoin-mainnet.yml
├── litecoin-testnet.yml
├── src
├── blockchaintypes.h
├── blockfilewatcher.cpp
├── blockfilewatcher.h
├── blockindexer.cpp
├── blockindexer.h
├── blockreader.cpp
├── blockreader.h
├── blockscanner.cpp
├── blockscanner.h
├── byte_array_buffer.cpp
├── byte_array_buffer.h
├── coinparams.cpp
├── coinparams.h
├── crypto
│ ├── bech32.cpp
│ ├── bech32.h
│ ├── common.h
│ ├── ripemd160.cpp
│ └── ripemd160.h
├── cxxopts.hpp
├── filereader.cpp
├── filereader.h
├── httpserver.cpp
├── httpserver.h
├── json.hpp
├── main.cpp
├── membuf.h
├── mempoolmonitor.cpp
├── mempoolmonitor.h
├── scriptsolver.cpp
├── scriptsolver.h
├── utility.cpp
├── utility.h
└── vertcoinrpc.h
├── vertcoin-mainnet.yml
└── vertcoin-testnet.yml
/.dockerignore:
--------------------------------------------------------------------------------
1 | data/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | vtc_indexer
3 | .vscode/
4 | data/
5 | build_and_restart.sh
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vertcoin-project/blockchain-indexer/f2ae12d3afe68ea599198cfa24334fe71293f97c/.gitmodules
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@vertcoin.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: https://contributor-covenant.org
46 | [version]: https://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM vtc-wallet-middleware-base
2 |
3 | ADD src /root/sources/vtc-wallet-middleware-cpp/src
4 | ADD Makefile /root/sources/vtc-wallet-middleware-cpp/Makefile
5 |
6 | RUN make clean -C /root/sources/vtc-wallet-middleware-cpp
7 | RUN make -C /root/sources/vtc-wallet-middleware-cpp
8 |
9 | ENTRYPOINT ["/root/sources/vtc-wallet-middleware-cpp/vtc_indexer"]
10 |
11 |
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-present The Vertcoin developers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | UNAME := $(shell uname)
2 |
3 |
4 | ifeq ($(UNAME), Linux)
5 | BINFLAGS ?= -I. -L. -L/usr/local/lib -I/usr/local/include
6 | PLATFORMCXXFLAGS ?= -fPIC
7 | INDEXERBIN ?= vtc_indexer
8 | CC = g++
9 | C = gcc
10 | endif
11 | ifeq ($(UNAME), MINGW32_NT-6.2)
12 | BINFLAGS ?= -I. -L.
13 | INDEXERBIN ?= vtc_indexer.exe
14 | CC = g++
15 | C = gcc
16 | endif
17 | ifeq ($(UNAME), Darwin)
18 | BINFLAGS ?= -I. -L.
19 | INDEXERBIN ?= vtc_indexer
20 | CC = clang++
21 | C = clang
22 | endif
23 | ifeq ($(UNAME), Darwin-Cross)
24 | BINFLAGS ?= -I. -L.
25 | INDEXERBIN ?= vtc_indexer
26 | CC = o64-clang++
27 | C = o64-clang
28 | endif
29 |
30 | PLATFORMCXXFLAGS += -g -Wall -std=c++14 -O3 -Wl,-E
31 |
32 | INDEXERSRC = src/main.cpp src/blockfilewatcher.cpp src/coinparams.cpp src/byte_array_buffer.cpp src/blockscanner.cpp src/scriptsolver.cpp src/httpserver.cpp src/utility.cpp src/blockreader.cpp src/filereader.cpp src/mempoolmonitor.cpp src/blockindexer.cpp src/crypto/ripemd160.cpp src/crypto/bech32.cpp
33 | INDEXEROBJS = $(INDEXERSRC:.cpp=.cpp.o)
34 |
35 | INDEXERLDFLAGS = $(BINFLAGS) -lrestbed -lcrypto -ldl -pthread -lleveldb -lssl -lsecp256k1 -ljsonrpccpp-client -ljsonrpccpp-common -ljsoncpp
36 |
37 | CXXFLAGS = $(PLATFORMCXXFLAGS)
38 |
39 | all: indexer
40 |
41 | indexer: $(INDEXERSRC) $(INDEXERBIN)
42 |
43 | clean:
44 | $(RM) -r $(INDEXEROBJS)
45 |
46 | $(INDEXERBIN): $(INDEXEROBJS)
47 | $(CC) $(INDEXEROBJS) -o $@ $(INDEXERLDFLAGS)
48 |
49 | %.c.o: %.c
50 | $(C) $(PLATFORMCXXFLAGS) -O3 -c $< -o $@
51 |
52 | %.cpp.o: %.cpp
53 | $(CC) $(CXXFLAGS) -c $< -o $@
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # C++ Blockchain Indexer
2 |
3 | https://blkidx.org/
4 |
5 | Pre-release warning
6 | ----------------
7 | IMPORTANT: This software is still under active development. Do not depend on this for production situations.
8 |
9 | What is this?
10 | ----------------
11 | This project aims to be a independant blockchain indexer for Bitcoin-based blockchains. It can read the blockfiles directly and indexes these blocks to allow a number of queries via its built-in HTTP service:
12 |
13 | * Fetch TXOs for an address
14 | * Optionally only return new TXOs since a particular height
15 | * Return only unspent TXOs
16 | * Fetch the balance for an address
17 | * Check if one or more outpoints are spent
18 | * Get a transaction
19 | * Send a transaction
20 | * Return the most recent blocks (hash, height, time)
21 | * Return basic sync status (highest block on coind, highest block in index)
22 |
23 | Supported elements
24 | ----------------
25 | The indexer currently supports:
26 | * Standard P2PK and P2SH scripts
27 | * Segwit P2WPK and P2WSH scripts (using bech32 address formats)
28 | * Multi-sig scripts
29 |
30 | Compatible coins
31 | ----------------
32 | The indexer should work for any Bitcoin derivative. The indexer is working for Vertcoin and Litecoin, whereas Bitcoin support is currently under development.
33 |
34 | Docker
35 | ----------------
36 | The indexer is built around Docker. It is possible to compile and run it on bare Linux, but to get running quickly it's easier to use Docker. There's docker-compose files available for all the supported coins.
37 |
38 | Get started
39 | ----------------
40 | * Install [Docker](https://www.docker.com/)
41 |
42 | * Since the containers for the indexer will run in an isolated network, we first have to create it:
43 | ```
44 | docker network create blockchain-indexer
45 | ```
46 |
47 | * Clone the repository and build the images
48 | ```
49 | git clone https://github.com/gertjaap/blockchain-indexer
50 | cd blockchain-indexer
51 | ./build.sh
52 | ```
53 |
54 | * Once the images are built, you can start the indexer -for example- for Vertcoin:
55 | ```
56 | docker-compose -f vertcoin-mainnet.yml up -d
57 | ```
58 |
59 | * You can now check you running containers and look up the IP address for the indexer:
60 | ```
61 | docker ps
62 | ```
63 |
64 | ```
65 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
66 | 034492bce34b vtc-wallet-middleware "/root/sources/vtc..." 5 seconds ago Up 1 second 8888/tcp blockchainindexer_vtc-middleware-cpp-main_1
67 | 48c3446ed3df lukechilds/vertcoind "init -rpcuser=mid..." 5 seconds ago Up 3 seconds 0.0.0.0:5889->5889/tcp, 8332-8333/tcp blockchainindexer_vertcoind-main_1
68 | ```
69 |
70 | * Using the ID of the container you can find out its IP address
71 |
72 | ```
73 | docker inspect 034492bce34b
74 | ```
75 |
76 | ```
77 | {
78 | {...}
79 | "Networks": {
80 | "blockchain-indexer": {
81 | {...}
82 | "IPAddress": "172.19.0.3",
83 | {...}
84 | }
85 | }
86 | }
87 | ```
88 |
89 | * You can then look at the status by opening the URL in the browser port 8888:
90 |
91 | ```
92 | http://172.19.0.3:8888/blocks
93 | ```
94 |
95 |
--------------------------------------------------------------------------------
/bitcoin-mainnet.yml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | services:
3 |
4 | bitcoind-main:
5 | image: kylemanna/bitcoind
6 | restart: always
7 | expose:
8 | - "8332"
9 | ports:
10 | - "8333:8333"
11 | volumes:
12 | - ./data/btc/main/coind:/bitcoin/.bitcoin
13 | environment:
14 | - RPCUSER=middleware
15 | - RPCPASSWORD=middleware
16 | command: -rpcport=8332 -server -rpcallowip='0.0.0.0/0' -txindex
17 |
18 | btc-middleware-cpp-main:
19 | image: vtc-wallet-middleware
20 | environment:
21 | - COIND_HOST=bitcoind-main
22 | expose:
23 | - "8888"
24 | depends_on:
25 | - bitcoind-main
26 | volumes:
27 | - ./data/btc/main/coind/blocks:/blocks
28 | - ./data/btc/main/index:/index
29 | - ./coins:/coins
30 | command: --coinParams=/coins/bitcoin-mainnet.json
31 |
32 | networks:
33 | default:
34 | external:
35 | name: blockchain-indexer
--------------------------------------------------------------------------------
/bitcoin-testnet.yml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | services:
3 |
4 | bitcoind-test:
5 | image: kylemanna/bitcoind
6 | restart: always
7 | expose:
8 | - "8332"
9 | ports:
10 | - "8333:8333"
11 | volumes:
12 | - ./data/btc/test/coind:/bitcoin/.bitcoin
13 | environment:
14 | - RPCUSER=middleware
15 | - RPCPASSWORD=middleware
16 | command: -rpcport=8332 -server -rpcallowip='0.0.0.0/0' -testnet -txindex
17 |
18 | btc-middleware-cpp-test:
19 | image: vtc-wallet-middleware
20 | environment:
21 | - COIND_HOST=bitcoind-test
22 | expose:
23 | - "8888"
24 | depends_on:
25 | - bitcoind-test
26 | volumes:
27 | - ./data/btc/test/coind/testnet3/blocks:/blocks
28 | - ./data/btc/test/index:/index
29 | - ./coins:/coins
30 | command: --coinParams=/coins/bitcoin-testnet.json
31 |
32 | networks:
33 | default:
34 | external:
35 | name: blockchain-indexer
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | docker build -t vtc-wallet-middleware-base build/base/
3 | docker build -t vtc-wallet-middleware .
4 |
--------------------------------------------------------------------------------
/build/base/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:16.04
2 |
3 | RUN apt-get update && apt install -y git wget build-essential libleveldb-dev cmake automake libssl-dev libtool autoconf libjsonrpccpp-dev libjsoncpp-dev libcurl4-openssl-dev
4 |
5 | RUN git clone --recursive https://github.com/Corvusoft/restbed
6 | RUN mkdir restbed/build
7 | WORKDIR /restbed/build
8 | RUN cmake ..
9 | RUN make install
10 | RUN cp -r ../distribution/include/* /usr/local/include
11 | RUN cp -r ../distribution/library/* /usr/lib
12 |
13 | WORKDIR /
14 | RUN git clone https://github.com/vertcoin/vertcoin
15 | WORKDIR /vertcoin/src/secp256k1
16 | RUN ./autogen.sh
17 | RUN ./configure
18 | RUN make
19 | RUN make install
20 |
21 | RUN ldconfig
22 |
--------------------------------------------------------------------------------
/coins/bitcoin-mainnet.json:
--------------------------------------------------------------------------------
1 | {
2 | "magic" : "f9beb4d9",
3 | "version_p2pkh" : "00",
4 | "version_p2sh" : "05",
5 | "prefix_bech32": "btc"
6 | }
--------------------------------------------------------------------------------
/coins/bitcoin-testnet.json:
--------------------------------------------------------------------------------
1 | {
2 | "magic" : "0b110907",
3 | "version_p2pkh" : "6f",
4 | "version_p2sh" : "c4",
5 | "prefix_bech32": "tbtc"
6 | }
--------------------------------------------------------------------------------
/coins/litecoin-mainnet.json:
--------------------------------------------------------------------------------
1 | {
2 | "magic" : "fbc0b6db",
3 | "version_p2pkh" : "30",
4 | "version_p2sh" : "32",
5 | "prefix_bech32": "ltc"
6 | }
--------------------------------------------------------------------------------
/coins/litecoin-testnet.json:
--------------------------------------------------------------------------------
1 | {
2 | "magic" : "fdd2c8f1",
3 | "version_p2pkh" : "6f",
4 | "version_p2sh" : "c4",
5 | "prefix_bech32": "tltc"
6 | }
--------------------------------------------------------------------------------
/coins/vertcoin-mainnet.json:
--------------------------------------------------------------------------------
1 | {
2 | "magic" : "fabfb5da",
3 | "version_p2pkh" : "47",
4 | "version_p2sh" : "05",
5 | "prefix_bech32": "vtc"
6 | }
--------------------------------------------------------------------------------
/coins/vertcoin-testnet.json:
--------------------------------------------------------------------------------
1 | {
2 | "magic" : "76657274",
3 | "version_p2pkh" : "4a",
4 | "version_p2sh" : "c4",
5 | "prefix_bech32": "tvtc"
6 | }
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | vertcoin-mainnet.yml
--------------------------------------------------------------------------------
/litecoin-mainnet.yml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | services:
3 |
4 | litecoind-main:
5 | image: uphold/litecoind
6 | restart: always
7 | expose:
8 | - "8332"
9 | ports:
10 | - "9333:9333"
11 | volumes:
12 | - ./data/ltc/main/coind:/home/litecoin/.litecoin
13 | command: -rpcuser=middleware -rpcpassword=middleware -rpcallowip='0.0.0.0/0' -rpcport=8332 -server -txindex
14 |
15 | ltc-middleware-cpp-main:
16 | image: vtc-wallet-middleware
17 | restart: always
18 | environment:
19 | - COIND_HOST=litecoind-main
20 | expose:
21 | - "8888"
22 | volumes:
23 | - ./data/ltc/main/coind/blocks:/blocks
24 | - ./data/ltc/main/index:/index
25 | - ./coins:/coins
26 | command: --coinParams=/coins/litecoin-mainnet.json
27 |
28 | networks:
29 | default:
30 | external:
31 | name: blockchain-indexer
--------------------------------------------------------------------------------
/litecoin-testnet.yml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | services:
3 |
4 | litecoind-test:
5 | image: uphold/litecoind
6 | restart: always
7 | expose:
8 | - "8332"
9 | ports:
10 | - "9333:9333"
11 | volumes:
12 | - ./data/ltc/test/coind:/home/litecoin/.litecoin
13 | command: -rpcuser=middleware -rpcpassword=middleware -rpcport=8332 -rpcallowip='0.0.0.0/0' -testnet -server -txindex
14 |
15 | ltc-middleware-cpp-test:
16 | image: vtc-wallet-middleware
17 | restart: always
18 | environment:
19 | - COIND_HOST=litecoind-test
20 | expose:
21 | - "8888"
22 | volumes:
23 | - ./data/ltc/test/coind/testnet4/blocks:/blocks
24 | - ./data/ltc/test/index:/index
25 | - ./coins:/coins
26 | command: --coinParams=/coins/litecoin-testnet.json
27 |
28 | networks:
29 | default:
30 | external:
31 | name: blockchain-indexer
--------------------------------------------------------------------------------
/src/blockchaintypes.h:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 |
21 | #ifndef BLOCKCHAINTYPES_H_INCLUDED
22 | #define BLOCKCHAINTYPES_H_INCLUDED
23 |
24 | #include
25 | #include
26 | using namespace std;
27 |
28 | namespace VtcBlockIndexer {
29 | // ScannedBlock is used to store information about block headers obtained while initially scanning through the block files
30 | struct ScannedBlock {
31 | // The filename (without path) where the block is located in
32 | string fileName;
33 |
34 | // The position inside the block file where the block header starts
35 | uint64_t filePosition;
36 |
37 | // The total size of the block
38 | uint32_t blockSize;
39 |
40 | // The hash of the block. This string is the the "reverse hash" used on block explorers
41 | string blockHash;
42 |
43 | // The hash of the previous block used to form the chain. This string is the the "reverse hash" used on block explorers
44 | string previousBlockHash;
45 | };
46 |
47 | // Describes a transaction output inside a blockchain transaction
48 | struct TransactionOutput {
49 | // The value of the output in Satoshis (0.00000001 VTC)
50 | uint64_t value;
51 |
52 | // The output script in Bitcoinscript
53 | vector script;
54 |
55 | // The index of the output in the list of outputs
56 | uint32_t index;
57 |
58 | // Convenience method for keeping TXOs in memory (mempool)
59 | string txHash;
60 | };
61 |
62 | // Describes a transaction input inside a blockchain transaction
63 | struct TransactionInput {
64 | // The index of the input int he list of indexes
65 | uint32_t index;
66 |
67 | // The hash of the transaction whose output is being spent
68 | string txHash;
69 |
70 | // The index of the output inside the transaction being spent
71 | uint32_t txoIndex;
72 |
73 | // Part of all transactions. A number intended to allow unconfirmed time-locked transactions to be updated before being finalized; not currently used except to disable locktime in a transaction
74 | uint32_t sequence;
75 |
76 | // Indicating if this is a coinbase (Generated coins) input
77 | bool coinbase;
78 |
79 | // The script of the input in Bitcoinscript
80 | vector script;
81 |
82 | // The witness data for the input
83 | vector> witnessData;
84 | };
85 |
86 | // Describes a transaction inside a block
87 | struct Transaction {
88 | // The list of inputs for this transaction
89 | vector inputs;
90 |
91 | // The list of outputs for this transaction
92 | vector outputs;
93 |
94 | // The hash for the transaction. This is the reverse hash as used on block explorers.
95 | string txHash;
96 |
97 | // The hash for the witness transaction. Contains a different hash in case the transaction uses SegWit. Will be equal to TXHash otherwise.
98 | string txWitHash;
99 |
100 | // Position inside the blockfile where this transaction starts
101 | uint64_t filePosition;
102 |
103 | // Version bit for the transaction
104 | uint32_t version;
105 |
106 | // Locktime. Transaction cannot be spent until this number of blocks have been confirmed after its initial inclusion in the blockchain
107 | uint32_t lockTime;
108 | };
109 |
110 | // Describes a block
111 | struct Block {
112 | // The blk????.dat file this block is located in.
113 | string fileName;
114 |
115 | // The position where the block starts inside the file
116 | int filePosition;
117 |
118 | // The hash of the block. This string is the the "reverse hash" used on block explorers
119 | string blockHash;
120 |
121 | string previousBlockHash;
122 |
123 | // The merkle root of the transactions inside this block
124 | string merkleRoot;
125 |
126 | // The height of the block in the chain
127 | uint64_t height;
128 |
129 | // Size of the block in bytes
130 | uint64_t byteSize;
131 |
132 | // Timestamp of the block
133 | uint32_t time;
134 |
135 | // encoded target threshold
136 | uint32_t bits;
137 |
138 | // Unique value to make the header hash match the target
139 | uint32_t nonce;
140 |
141 | // Version of the block
142 | uint32_t version;
143 |
144 | // The list of transactions inside this block
145 | vector transactions;
146 | };
147 |
148 |
149 | }
150 | #endif // BLOCKCHAINTYPES_H_INCLUDED
--------------------------------------------------------------------------------
/src/blockfilewatcher.cpp:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 | #include "blockfilewatcher.h"
21 | #include "scriptsolver.h"
22 | #include "blockchaintypes.h"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include "blockscanner.h"
31 |
32 | #include
33 | #include
34 | #include
35 |
36 | using namespace std;
37 |
38 | // Constructor
39 | VtcBlockIndexer::BlockFileWatcher::BlockFileWatcher(string blocksDir, const shared_ptr db, const shared_ptr mempoolMonitor) {
40 | this->db = db;
41 | this->mempoolMonitor = mempoolMonitor;
42 | blockIndexer.reset(new VtcBlockIndexer::BlockIndexer(this->db, this->mempoolMonitor));
43 | blockReader.reset(new VtcBlockIndexer::BlockReader(blocksDir));
44 | this->blocksDir = blocksDir;
45 | this->maxLastModified.tv_sec = 0;
46 | this->maxLastModified.tv_nsec = 0;
47 | }
48 |
49 | void VtcBlockIndexer::BlockFileWatcher::startWatcher() {
50 | DIR *dir;
51 | dirent *ent;
52 | string blockFilePrefix = "blk";
53 |
54 | while(true) {
55 | bool shouldUpdate = false;
56 | dir = opendir(&*this->blocksDir.begin());
57 | while ((ent = readdir(dir)) != NULL) {
58 | const string file_name = ent->d_name;
59 | struct stat result;
60 |
61 | // Check if the filename starts with "blk"
62 | if(strncmp(file_name.c_str(), blockFilePrefix.c_str(), blockFilePrefix.size()) == 0)
63 | {
64 | stringstream fullPath;
65 | fullPath << this->blocksDir << "/" << file_name;
66 | if(stat(fullPath.str().c_str(), &result)==0)
67 | {
68 | if(result.st_mtim.tv_sec > this->maxLastModified.tv_sec) {
69 | this->maxLastModified = result.st_mtim;
70 | if(!shouldUpdate)
71 | cout << "Change(s) detected, starting index update." << endl;
72 | shouldUpdate = true;
73 | }
74 | }
75 | }
76 | }
77 |
78 | closedir(dir);
79 |
80 | if(shouldUpdate) {
81 | updateIndex();
82 | }
83 |
84 | std::this_thread::sleep_for(std::chrono::seconds(1));
85 | }
86 | }
87 |
88 | void VtcBlockIndexer::BlockFileWatcher::scanBlocks(string fileName) {
89 | unique_ptr blockScanner(new VtcBlockIndexer::BlockScanner(blocksDir, fileName));
90 | if(blockScanner->open())
91 | {
92 | while(blockScanner->moveNext()) {
93 | this->totalBlocks++;
94 | VtcBlockIndexer::ScannedBlock block = blockScanner->scanNextBlock();
95 | // Create an empty vector inside the unordered map if this previousBlockHash
96 | // was not found before.
97 | if(this->blocks.find(block.previousBlockHash) == this->blocks.end()) {
98 | this->blocks[block.previousBlockHash] = {};
99 | }
100 |
101 | // Check if a block with the same hash already exists. Unfortunately, I found
102 | // instances where a block is included in the block files more than once.
103 | vector matchingBlocks = this->blocks[block.previousBlockHash];
104 | bool blockFound = false;
105 | for(VtcBlockIndexer::ScannedBlock matchingBlock : matchingBlocks) {
106 | if(matchingBlock.blockHash == block.blockHash) {
107 | blockFound = true;
108 | }
109 | }
110 |
111 | // If the block is not present, add it to the vector.
112 | if(!blockFound) {
113 | this->blocks[block.previousBlockHash].push_back(block);
114 | }
115 | }
116 | blockScanner->close();
117 | }
118 | }
119 |
120 |
121 | void VtcBlockIndexer::BlockFileWatcher::scanBlockFiles(string dirPath) {
122 | DIR *dir;
123 | dirent *ent;
124 |
125 | dir = opendir(&*dirPath.begin());
126 | while ((ent = readdir(dir)) != NULL) {
127 | const string file_name = ent->d_name;
128 |
129 | // Check if the filename starts with "blk"
130 | string prefix = "blk";
131 | if(strncmp(file_name.c_str(), prefix.c_str(), prefix.size()) == 0)
132 | {
133 | scanBlocks(file_name);
134 | }
135 | }
136 | closedir(dir);
137 | }
138 |
139 |
140 | VtcBlockIndexer::ScannedBlock VtcBlockIndexer::BlockFileWatcher::findLongestChain(vector matchingBlocks) {
141 | vector nextBlockHashes;
142 | for(uint i = 0; i < matchingBlocks.size(); i++) {
143 | nextBlockHashes.push_back(matchingBlocks.at(i).blockHash);
144 | }
145 |
146 | while(true) {
147 |
148 | for(uint i = 0; i < nextBlockHashes.size(); i++) {
149 | int countChains = 0;
150 | for(uint i = 0; i < nextBlockHashes.size(); i++) {
151 | if(nextBlockHashes.at(i) != "") {
152 | countChains++;
153 | }
154 | }
155 |
156 | if(countChains == 1) {
157 | for(uint i = 0; i < nextBlockHashes.size(); i++) {
158 | if(nextBlockHashes.at(i) != "") {
159 | return matchingBlocks.at(i);
160 | }
161 | }
162 | }
163 |
164 | if(this->blocks.find(nextBlockHashes.at(i)) == this->blocks.end()) {
165 | nextBlockHashes.at(i).assign("");
166 | } else {
167 | vector matchingBlocks = this->blocks[nextBlockHashes.at(i)];
168 | VtcBlockIndexer::ScannedBlock bestBlock = matchingBlocks.at(0);
169 | if(matchingBlocks.size() > 1) {
170 | bestBlock = findLongestChain(matchingBlocks);
171 | }
172 | nextBlockHashes.at(i).assign(bestBlock.blockHash);
173 | }
174 | }
175 | }
176 | }
177 |
178 |
179 | string VtcBlockIndexer::BlockFileWatcher::processNextBlock(string prevBlockHash) {
180 |
181 |
182 | // If there is no block present with this hash as previousBlockHash, return an empty
183 | // string signaling we're at the end of the chain.
184 | if(this->blocks.find(prevBlockHash) == this->blocks.end()) {
185 | return "";
186 | }
187 |
188 | // Find the blocks that match
189 | vector matchingBlocks = this->blocks[prevBlockHash];
190 |
191 | if(matchingBlocks.size() > 0) {
192 | VtcBlockIndexer::ScannedBlock bestBlock = matchingBlocks.at(0);
193 |
194 | if(matchingBlocks.size() > 1) {
195 | bestBlock = findLongestChain(matchingBlocks);
196 | }
197 |
198 | if(!blockIndexer->hasIndexedBlock(bestBlock.blockHash, this->blockHeight)) {
199 | VtcBlockIndexer::Block fullBlock = blockReader->readBlock(bestBlock.fileName, bestBlock.filePosition, this->blockHeight, false);
200 |
201 | blockIndexer->indexBlock(fullBlock);
202 | }
203 | return bestBlock.blockHash;
204 |
205 | } else {
206 | // Somehow found an empty vector in the unordered_map. This should not happen.
207 | // But just in case, returning an empty value here.
208 | return "";
209 | }
210 | }
211 |
212 | void VtcBlockIndexer::BlockFileWatcher::updateIndex() {
213 |
214 | time_t start;
215 | time(&start);
216 |
217 | this->blockHeight = 0;
218 | this->totalBlocks = 0;
219 | cout << "Scanning blocks..." << endl;
220 |
221 | scanBlockFiles(blocksDir);
222 |
223 | cout << "Found " << this->totalBlocks << " blocks. Constructing longest chain..." << endl;
224 |
225 | // The blockchain starts with the genesis block that has a zero hash as Previous Block Hash
226 | string nextBlock = "0000000000000000000000000000000000000000000000000000000000000000";
227 | string processedBlock = processNextBlock(nextBlock);
228 | double nextUpdate = 10;
229 | while(processedBlock != "") {
230 |
231 | // Show progress every 10 seconds
232 | double seconds = difftime(time(NULL), start);
233 | if(seconds >= nextUpdate) {
234 | nextUpdate += 10;
235 | cout << "Construction is at height " << this->blockHeight << endl;
236 | }
237 | this->blockHeight++;
238 | nextBlock = processedBlock;
239 | processedBlock = processNextBlock(nextBlock);
240 | }
241 |
242 | cout << "Done. Processed " << this->blockHeight << " blocks. Have a nice day." << endl;
243 |
244 | this->blocks.clear();
245 | }
246 |
--------------------------------------------------------------------------------
/src/blockfilewatcher.h:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 |
21 |
22 | #ifndef BLOCKFILEWATCHER_H_INCLUDED
23 | #define BLOCKFILEWATCHER_H_INCLUDED
24 |
25 | #include
26 | #include
27 | #include
28 | #include "leveldb/db.h"
29 | #include "leveldb/write_batch.h"
30 | #include "blockchaintypes.h"
31 | #include "mempoolmonitor.h"
32 | #include "blockindexer.h"
33 | #include "blockreader.h"
34 |
35 | using namespace std;
36 |
37 | namespace VtcBlockIndexer {
38 |
39 | /**
40 | * The BlockFileWatcher class provides methods to watch and scan a blocks directory
41 | * and process the blockfiles when changes occur.
42 | */
43 |
44 | class BlockFileWatcher {
45 | public:
46 | /** Constructs a BlockIndexer instance using the given block data directory
47 | */
48 | BlockFileWatcher(string blocksDir, const shared_ptr db, const shared_ptr mempoolMonitor);
49 |
50 | /** Starts watching the blocksdir for changes and will execute an incremental
51 | * indexing when files have changed */
52 | void startWatcher();
53 |
54 | /** Updates the blockchain index incrementally */
55 | void updateIndex();
56 |
57 | private:
58 | /** Uses the blockscanner to scan blocks within a file and add them to the
59 | * unordered map.
60 | *
61 | * @param fileName The file name of the BLK????.DAT to scan for blocks.
62 | */
63 | void scanBlocks(string fileName);
64 |
65 | /** Scans a folder for block files present and passes them to the scanBlocks
66 | * method
67 | *
68 | * @param dirPath The directory to scan for blockfiles.
69 | */
70 | void scanBlockFiles(string dirName);
71 |
72 | /** Orphaned blocks stay in the blockfiles. So this method is created to find out which of the canditate follow-up blocks
73 | * chain of work behind it.
74 | * @param matchingBlocks The blocks that should be investigated.
75 | */
76 | VtcBlockIndexer::ScannedBlock findLongestChain(vector matchingBlocks);
77 |
78 | /** Finds the next block in line (by matching the prevBlockHash which is the
79 | * key in the unordered_map). Then uses the block processor to do the indexing.
80 | * Returns the hash of the block that was processed.
81 | *
82 | * @param prevBlockHash the hex hash of the block that was last processed that we should
83 | * extend the chain onto.
84 | */
85 | string processNextBlock(string prevBlockHash);
86 | string blocksDir;
87 | shared_ptr db;
88 | shared_ptr mempoolMonitor;
89 | unique_ptr blockReader;
90 | unique_ptr blockIndexer;
91 | int totalBlocks;
92 | int blockHeight;
93 | unordered_map> blocks;
94 | struct timespec maxLastModified;
95 | };
96 |
97 | }
98 |
99 | #endif // BLOCKINDEXER_H_INCLUDED
--------------------------------------------------------------------------------
/src/blockindexer.cpp:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 | #include "blockindexer.h"
21 | #include "scriptsolver.h"
22 | #include "blockchaintypes.h"
23 | #include
24 | #include
25 |
26 | //#include "hashing.h"
27 | #include
28 | #include
29 | #include
30 |
31 |
32 | using namespace std;
33 |
34 | // This map keeps the nextTxoIndex in memory for speed - no database fetching on every TX
35 | unordered_map nextTxoIndex;
36 |
37 |
38 |
39 | VtcBlockIndexer::BlockIndexer::BlockIndexer(const shared_ptr db, const shared_ptr mempoolMonitor) {
40 | this->db = db;
41 | this->mempoolMonitor = mempoolMonitor;
42 | this->scriptSolver = make_unique();
43 | }
44 |
45 |
46 | int VtcBlockIndexer::BlockIndexer::getNextTxoIndex(string prefix) {
47 | if(nextTxoIndex.find(prefix) == nextTxoIndex.end()) {
48 | leveldb::Iterator* it = this->db->NewIterator(leveldb::ReadOptions());
49 | nextTxoIndex[prefix] = 1;
50 | string start(prefix + "-00000001");
51 | string limit(prefix + "-99999999");
52 |
53 | for (it->Seek(start);
54 | it->Valid() && it->key().ToString() < limit;
55 | it->Next()) {
56 | nextTxoIndex[prefix]++;
57 | }
58 | assert(it->status().ok()); // Check for any errors found during the scan
59 | delete it;
60 | } else {
61 | nextTxoIndex[prefix]++;
62 | }
63 |
64 | return nextTxoIndex[prefix];
65 | }
66 |
67 | bool VtcBlockIndexer::BlockIndexer::clearBlockTxos(string blockHash) {
68 | leveldb::WriteBatch batch;
69 |
70 | string start(blockHash + "-txo-00000001");
71 | string limit(blockHash + "-txo-99999999");
72 | leveldb::Iterator* it = this->db->NewIterator(leveldb::ReadOptions());
73 | for (it->Seek(start);
74 | it->Valid() && it->key().ToString() < limit;
75 | it->Next()) {
76 | batch.Delete(it->value().ToString());
77 | }
78 | assert(it->status().ok()); // Check for any errors found during the scan
79 | delete it;
80 |
81 | string spentStart(blockHash + "-txospent-00000001");
82 | string spentLimit(blockHash + "-txospent-99999999");
83 | it = this->db->NewIterator(leveldb::ReadOptions());
84 | for (it->Seek(spentStart);
85 | it->Valid() && it->key().ToString() < spentLimit;
86 | it->Next()) {
87 | batch.Delete(it->value().ToString());
88 | }
89 | assert(it->status().ok()); // Check for any errors found during the scan
90 | delete it;
91 |
92 | leveldb::Status s = this->db->Write(leveldb::WriteOptions(), &batch);
93 | return s.ok();
94 | }
95 |
96 | bool VtcBlockIndexer::BlockIndexer::hasIndexedBlock(string blockHash, int blockHeight)
97 | {
98 | stringstream ss;
99 | ss << "block-" << setw(8) << setfill('0') << blockHeight;
100 |
101 | string existingBlockHash;
102 | leveldb::Status s = this->db->Get(leveldb::ReadOptions(), ss.str(), &existingBlockHash);
103 | if(s.ok() && existingBlockHash == blockHash) {
104 | return true;
105 | }
106 |
107 | return false;
108 | }
109 |
110 | bool VtcBlockIndexer::BlockIndexer::indexBlock(Block block) {
111 | //cout << "Indexing block " << block.blockHash << " (Height " << block.height << ")" << endl;
112 |
113 | stringstream ss;
114 | ss << "block-" << setw(8) << setfill('0') << block.height;
115 |
116 | string existingBlockHash;
117 | leveldb::Status s = this->db->Get(leveldb::ReadOptions(), ss.str(), &existingBlockHash);
118 |
119 | if(s.ok() && existingBlockHash == block.blockHash) {
120 | // Block found in database and matches. This block is indexed already, so skip.
121 | return true;
122 | } else if (s.ok()) {
123 | // There was a different block at this height. Ditch the TXOs from the old block.
124 | clearBlockTxos(existingBlockHash);
125 | }
126 |
127 | stringstream blockHeight;
128 | blockHeight << setw(8) << setfill('0') << block.height;
129 |
130 | string highestBlock;
131 | s = this->db->Get(leveldb::ReadOptions(), "highestblock", &highestBlock);
132 | if(!s.ok()) {
133 | this->db->Put(leveldb::WriteOptions(), "highestblock", blockHeight.str());
134 | } else {
135 | if(stoull(highestBlock) < block.height) {
136 | this->db->Put(leveldb::WriteOptions(), "highestblock", blockHeight.str());
137 | }
138 | }
139 |
140 | this->db->Put(leveldb::WriteOptions(), ss.str(), block.blockHash);
141 |
142 | stringstream ssBlockFilePositionKey;
143 | ssBlockFilePositionKey << "block-filePosition-" << setw(8) << setfill('0') << block.height;
144 | stringstream ssBlockFilePositionValue;
145 | ssBlockFilePositionValue << block.fileName << setw(12) << setfill('0') << block.filePosition;
146 |
147 | this->db->Put(leveldb::WriteOptions(), ssBlockFilePositionKey.str(), ssBlockFilePositionValue.str());
148 |
149 | stringstream ssBlockHashHeightKey;
150 | ssBlockHashHeightKey << "block-hash-" << block.blockHash;
151 | stringstream ssBlockHashHeightValue;
152 | ssBlockHashHeightValue << setw(8) << setfill('0') << block.height;
153 |
154 | this->db->Put(leveldb::WriteOptions(), ssBlockHashHeightKey.str(), ssBlockHashHeightValue.str());
155 |
156 | stringstream ssBlockTimeHeightKey;
157 | ssBlockTimeHeightKey << "block-time-" << setw(8) << setfill('0') << block.height;
158 | this->db->Put(leveldb::WriteOptions(), ssBlockTimeHeightKey.str(), std::to_string(block.time));
159 |
160 | stringstream ssBlockSizeHeightKey;
161 | ssBlockSizeHeightKey << "block-size-" << setw(8) << setfill('0') << block.height;
162 | this->db->Put(leveldb::WriteOptions(), ssBlockSizeHeightKey.str(), std::to_string(block.byteSize));
163 |
164 | stringstream ssBlockTxCountHeightKey;
165 | ssBlockTxCountHeightKey << "block-txcount-" << setw(8) << setfill('0') << block.height;
166 | this->db->Put(leveldb::WriteOptions(), ssBlockTxCountHeightKey.str(), std::to_string(block.transactions.size()));
167 |
168 | int txIndex = -1;
169 | // TODO: Verify block integrity
170 | for(VtcBlockIndexer::Transaction tx : block.transactions) {
171 | txIndex++;
172 | stringstream blockTxKey;
173 | blockTxKey << "block-" << block.blockHash << "-tx-" << setw(8) << setfill('0') << txIndex;
174 | this->db->Put(leveldb::WriteOptions(), blockTxKey.str(), tx.txHash);
175 |
176 | stringstream ssTxFilePositionKey;
177 | ssTxFilePositionKey << "tx-filePosition-" << tx.txHash;
178 | stringstream ssTxFilePositionValue;
179 | ssTxFilePositionValue << block.fileName << setw(12) << setfill('0') << tx.filePosition;
180 |
181 | this->db->Put(leveldb::WriteOptions(), ssTxFilePositionKey.str(), ssTxFilePositionValue.str());
182 |
183 | stringstream txBlockKey;
184 | txBlockKey << "tx-" << tx.txHash << "-block";
185 | this->db->Put(leveldb::WriteOptions(), txBlockKey.str(), block.blockHash);
186 |
187 |
188 | for(VtcBlockIndexer::TransactionOutput out : tx.outputs) {
189 | vector addresses = this->scriptSolver->getAddressesFromScript(out.script);
190 | if(addresses.size() > 1) {
191 | if(scriptSolver->isMultiSig(out.script)) {
192 | stringstream txoMultiSigKey;
193 | txoMultiSigKey << "multisigtx-" << tx.txHash << "-" << setw(8) << setfill('0') << out.index;
194 | this->db->Put(leveldb::WriteOptions(), txoMultiSigKey.str(), std::to_string(scriptSolver->requiredSignatures(out.script)));
195 | }
196 | }
197 | for(string address : addresses) {
198 | int nextIndex = getNextTxoIndex(address + "-txo");
199 | stringstream txoKey;
200 | txoKey << address << "-txo-" << setw(8) << setfill('0') << nextIndex;
201 | stringstream txoValue;
202 | txoValue << tx.txHash << setw(8) << setfill('0') << out.index << setw(8) << setfill('0') << block.height << out.value;
203 | this->db->Put(leveldb::WriteOptions(), txoKey.str(), txoValue.str());
204 |
205 | nextIndex = getNextTxoIndex(block.blockHash + "-txo");
206 | stringstream blockTxoKey;
207 | blockTxoKey << block.blockHash << "-txo-" << setw(8) << setfill('0') << nextIndex;
208 | this->db->Put(leveldb::WriteOptions(), blockTxoKey.str(), txoKey.str());
209 | }
210 | }
211 |
212 | for(VtcBlockIndexer::TransactionInput txi : tx.inputs) {
213 | if(!txi.coinbase)
214 | {
215 | stringstream txSpentKey;
216 | txSpentKey << "txo-" << txi.txHash << "-" << setw(8) << setfill('0') << txi.txoIndex << "-spent";
217 |
218 | stringstream spendingTx;
219 | spendingTx << block.blockHash << "-" << tx.txHash;
220 |
221 | this->db->Put(leveldb::WriteOptions(), txSpentKey.str(), spendingTx.str());
222 |
223 | int nextIndex = getNextTxoIndex(block.blockHash + "-txospent");
224 | stringstream blockTxoSpentKey;
225 | blockTxoSpentKey << block.blockHash << "-txospent-" << setw(8) << setfill('0') << nextIndex;
226 | this->db->Put(leveldb::WriteOptions(), blockTxoSpentKey.str(), txSpentKey.str());
227 | }
228 | }
229 | this->mempoolMonitor->transactionIndexed(tx.txHash);
230 | }
231 |
232 |
233 |
234 | return true;
235 | }
236 |
237 |
--------------------------------------------------------------------------------
/src/blockindexer.h:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 |
21 |
22 | #ifndef BLOCKINDEXER_H_INCLUDED
23 | #define BLOCKINDEXER_H_INCLUDED
24 |
25 | #include
26 | #include
27 | #include "leveldb/db.h"
28 | #include "leveldb/write_batch.h"
29 | #include "blockchaintypes.h"
30 | #include "scriptsolver.h"
31 | #include "mempoolmonitor.h"
32 |
33 | using namespace std;
34 |
35 | namespace VtcBlockIndexer {
36 |
37 | /**
38 | * The BlockIndexer class provides methods to index a block that was fully
39 | * read (so including its transactions). It will index the necessary elements
40 | * to be able to query balances per address, blocks by hash and index, and
41 | * data to handle reorgs.
42 | */
43 |
44 | class BlockIndexer {
45 | public:
46 | /** Constructs a BlockIndexer instance using the given block data directory
47 | */
48 | BlockIndexer(const shared_ptr db, const shared_ptr mempoolMonitor);
49 |
50 | /** Indexes the contents of the block
51 | */
52 | bool indexBlock(Block block);
53 |
54 | /** Returns true when there's already a block with the passed hash
55 | * in the index at the passed blockheight. No need to reindex
56 | * in that case.
57 | */
58 | bool hasIndexedBlock(string blockHash, int blockHeight);
59 |
60 | private:
61 | /** Removes TXOs and spends from a particular blockhash
62 | * in case of a reorg */
63 |
64 | bool clearBlockTxos(string blockHash);
65 | /** Returns the next index to use for storing the TXO
66 | */
67 | int getNextTxoIndex(string prefix);
68 |
69 | shared_ptr db;
70 | shared_ptr mempoolMonitor;
71 |
72 | // Reference to the scriptsolver class
73 | unique_ptr scriptSolver;
74 | };
75 |
76 | }
77 |
78 | #endif // BLOCKINDEXER_H_INCLUDED
--------------------------------------------------------------------------------
/src/blockreader.cpp:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 | #include "blockreader.h"
21 | #include "filereader.h"
22 | #include "blockchaintypes.h"
23 | #include "utility.h"
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | using namespace std;
34 |
35 | VtcBlockIndexer::BlockReader::BlockReader(const string blocksDir) {
36 |
37 | this->blocksDir = blocksDir;
38 | }
39 |
40 | std::vector VtcBlockIndexer::BlockReader::readRawBlockHeader(string fileName, uint64_t filePosition) {
41 | stringstream ss;
42 | ss << blocksDir << "/" << fileName;
43 | ifstream blockFile(ss.str(), ios_base::in | ios_base::binary);
44 | vector blockHeader(80);
45 | blockFile.read(reinterpret_cast(&blockHeader[0]) , 80);
46 | blockFile.close();
47 | return blockHeader;
48 | }
49 |
50 |
51 | VtcBlockIndexer::Block VtcBlockIndexer::BlockReader::readBlock(string fileName, uint64_t filePosition, uint64_t blockHeight, bool headerOnly) {
52 | VtcBlockIndexer::Block fullBlock;
53 |
54 | fullBlock.fileName = fileName;
55 | fullBlock.filePosition = filePosition;
56 | fullBlock.height = blockHeight;
57 |
58 | stringstream ss;
59 | ss << blocksDir << "/" << fileName;
60 | ifstream blockFile(ss.str(), ios_base::in | ios_base::binary);
61 |
62 | if(!blockFile.is_open()) {
63 | cerr << "Block file could not be opened" << endl;
64 | exit(0);
65 | }
66 |
67 | blockFile.seekg(filePosition, ios_base::beg);
68 | vector blockHeader(80);
69 | blockFile.read(reinterpret_cast(&blockHeader[0]) , 80);
70 | fullBlock.blockHash = VtcBlockIndexer::Utility::hashToReverseHex(VtcBlockIndexer::Utility::sha256(VtcBlockIndexer::Utility::sha256(blockHeader)));
71 |
72 | blockFile.seekg(filePosition, ios_base::beg);
73 |
74 | blockFile.read(reinterpret_cast(&fullBlock.version), sizeof(fullBlock.version));
75 | fullBlock.previousBlockHash = VtcBlockIndexer::Utility::hashToReverseHex(VtcBlockIndexer::FileReader::readHash(blockFile));
76 | fullBlock.merkleRoot = VtcBlockIndexer::Utility::hashToReverseHex(VtcBlockIndexer::FileReader::readHash(blockFile));
77 | blockFile.read(reinterpret_cast(&fullBlock.time), sizeof(fullBlock.time));
78 | blockFile.read(reinterpret_cast(&fullBlock.bits), sizeof(fullBlock.bits));
79 | blockFile.read(reinterpret_cast(&fullBlock.nonce), sizeof(fullBlock.nonce));
80 |
81 | if(!headerOnly) {
82 | // Find number of transactions
83 | blockFile.seekg(filePosition+80, ios_base::beg);
84 | uint64_t txCount = VtcBlockIndexer::FileReader::readVarInt(blockFile);
85 | fullBlock.transactions = {};
86 | for(uint64_t tx = 0; tx < txCount; tx++) {
87 | VtcBlockIndexer::Transaction transaction = readTransaction(blockFile);
88 | fullBlock.transactions.push_back(transaction);
89 | }
90 | }
91 | uint64_t endPosBlock = blockFile.tellg();
92 | fullBlock.byteSize = endPosBlock - filePosition;
93 | blockFile.close();
94 | return fullBlock;
95 | }
96 |
97 | VtcBlockIndexer::Transaction VtcBlockIndexer::BlockReader::readTransaction(istream& blockFile) {
98 | bool segwit = false;
99 |
100 | VtcBlockIndexer::Transaction transaction;
101 | uint64_t startPosTx = blockFile.tellg();
102 |
103 | transaction.filePosition = startPosTx;
104 | blockFile.read(reinterpret_cast(&transaction.version), sizeof(transaction.version));
105 |
106 | // determine if this is a segwit tx
107 | // https://bitcoincore.org/en/segwit_wallet_dev/
108 | unique_ptr segwitMarker(new unsigned char[2]);
109 | blockFile.read(reinterpret_cast(&segwitMarker.get()[0]) , 2);
110 | segwit = (segwitMarker.get()[0] == 0x00 && segwitMarker.get()[1] != 0x00);
111 |
112 | // If the segwit marker is not found, the number of inputs is located in its place
113 | // so rewind the stream to continue.
114 | if(!segwit) blockFile.seekg(-2, ios_base::cur);
115 |
116 | uint64_t startPosInputs = blockFile.tellg();
117 |
118 | transaction.inputs = {};
119 |
120 | uint64_t inputCount = VtcBlockIndexer::FileReader::readVarInt(blockFile);
121 |
122 | for(uint64_t input = 0; input < inputCount; input++) {
123 | VtcBlockIndexer::TransactionInput txInput;
124 | txInput.txHash = VtcBlockIndexer::Utility::hashToReverseHex(VtcBlockIndexer::FileReader::readHash(blockFile));
125 | blockFile.read(reinterpret_cast(&txInput.txoIndex), sizeof(txInput.txoIndex));
126 | txInput.script = VtcBlockIndexer::FileReader::readString(blockFile);
127 | blockFile.read(reinterpret_cast(&txInput.sequence), sizeof(txInput.sequence));
128 | txInput.index = input;
129 | txInput.coinbase = (input == 0 && txInput.txHash == "0000000000000000000000000000000000000000000000000000000000000000" && txInput.txoIndex == 4294967295);
130 | transaction.inputs.push_back(txInput);
131 | }
132 |
133 | uint64_t outputCount = VtcBlockIndexer::FileReader::readVarInt(blockFile);
134 | transaction.outputs = {};
135 | for(uint64_t output = 0; output < outputCount; output++) {
136 | VtcBlockIndexer::TransactionOutput txOutput;
137 | blockFile.read(reinterpret_cast(&txOutput.value), sizeof(txOutput.value));
138 | txOutput.script = VtcBlockIndexer::FileReader::readString(blockFile);
139 | txOutput.index = output;
140 | transaction.outputs.push_back(txOutput);
141 | }
142 |
143 | uint64_t endPosOutputs = blockFile.tellg();
144 |
145 |
146 | if(segwit) {
147 | for(uint64_t input = 0; input < inputCount; input++) {
148 | uint64_t witnessItems = VtcBlockIndexer::FileReader::readVarInt(blockFile);
149 | if(witnessItems > 0) {
150 | transaction.inputs.at(input).witnessData = {};
151 | for(uint64_t witnessItem = 0; witnessItem < witnessItems; witnessItem++) {
152 | vector witnessData = VtcBlockIndexer::FileReader::readString(blockFile);
153 | transaction.inputs.at(input).witnessData.push_back(witnessData);
154 | }
155 | }
156 | }
157 | }
158 |
159 | blockFile.read(reinterpret_cast(&transaction.lockTime), sizeof(transaction.lockTime));
160 |
161 | uint64_t endPosTx = blockFile.tellg();
162 |
163 | blockFile.seekg(startPosTx, ios_base::beg);
164 |
165 | // The tx hash must still be calculated over the original serialization format.
166 | // That's why this seems a bit overcomplex
167 | uint64_t txitxoLength = endPosOutputs-startPosInputs;
168 | std::vector txHashBytes(
169 | 4 + // version
170 | txitxoLength +
171 | 4 // locktime
172 | );
173 |
174 | blockFile.read(reinterpret_cast(&txHashBytes[0]), sizeof(transaction.version));
175 |
176 | blockFile.seekg(startPosInputs, ios_base::beg);
177 | blockFile.read(reinterpret_cast(&txHashBytes[0] + 4), txitxoLength);
178 |
179 | blockFile.seekg(endPosTx-4, ios_base::beg);
180 | blockFile.read(reinterpret_cast(&txHashBytes[0] + 4 + txitxoLength), sizeof(transaction.lockTime));
181 | transaction.txHash = VtcBlockIndexer::Utility::hashToReverseHex(VtcBlockIndexer::Utility::sha256(VtcBlockIndexer::Utility::sha256(txHashBytes)));
182 |
183 | if(segwit) {
184 | blockFile.seekg(startPosTx, ios_base::beg);
185 | uint64_t length = endPosTx-startPosTx;
186 | std::vector transactionBytes(length);
187 | blockFile.read(reinterpret_cast(&transactionBytes[0]) , length);
188 | transaction.txWitHash = VtcBlockIndexer::Utility::hashToReverseHex(VtcBlockIndexer::Utility::sha256(VtcBlockIndexer::Utility::sha256(transactionBytes)));
189 | } else {
190 | transaction.txWitHash = string(transaction.txHash);
191 | }
192 | blockFile.seekg(endPosTx, ios_base::beg);
193 |
194 | return transaction;
195 | }
196 |
--------------------------------------------------------------------------------
/src/blockreader.h:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 |
21 |
22 | #ifndef BLOCKREADER_H_INCLUDED
23 | #define BLOCKREADER_H_INCLUDED
24 |
25 | #include
26 | #include
27 |
28 | #include "blockchaintypes.h"
29 |
30 | namespace VtcBlockIndexer {
31 |
32 | /**
33 | * The BlockReader class provides methods to read in the full details of
34 | * a block and its transactions from the block file based on a ScannedBlock
35 | */
36 |
37 | class BlockReader {
38 | public:
39 | /** Constructs a BlockReader instance using the given block data directory
40 | *
41 | * @param blocksDir required Directory where the blockfiles are located.
42 | */
43 | BlockReader(const std::string blocksDir);
44 |
45 | /** Reads the contents of the block that was scanned
46 | */
47 | Block readBlock(std::string fileName, uint64_t filePosition, uint64_t blockHeight, bool headerOnly);
48 |
49 | /** Reads a transaction from an open stream
50 | */
51 | Transaction readTransaction(std::istream& blockFile);
52 |
53 | /** Reads a transaction from an open file stream
54 | */
55 | std::vector readRawBlockHeader(std::string fileName, uint64_t filePosition);
56 |
57 | private:
58 |
59 | /** Directory containing the blocks
60 | */
61 | std::string blocksDir;
62 | };
63 |
64 | }
65 |
66 | #endif // BLOCKREADER_H_INCLUDED
--------------------------------------------------------------------------------
/src/blockscanner.cpp:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 | #include "blockscanner.h"
21 | #include "utility.h"
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 |
29 | VtcBlockIndexer::BlockScanner::BlockScanner(const std::string blocksDir, const std::string blockFileName) {
30 | std::stringstream ss;
31 | ss << blocksDir << "/" << blockFileName;
32 | this->blockFilePath = ss.str();
33 | this->blockFileName = blockFileName;
34 | }
35 |
36 | bool VtcBlockIndexer::BlockScanner::open() {
37 | this->blockFileStream.open(this->blockFilePath, std::ios_base::in | std::ios_base::binary);
38 | return this->blockFileStream.is_open();
39 | }
40 |
41 | bool VtcBlockIndexer::BlockScanner::close() {
42 | if(!this->blockFileStream.is_open()) return false;
43 | this->blockFileStream.close();
44 | return !this->blockFileStream.is_open();
45 | }
46 |
47 | bool VtcBlockIndexer::BlockScanner::moveNext() {
48 | std::vector buffer(4);
49 | this->blockFileStream.read(reinterpret_cast(&buffer[0]), 4);
50 |
51 | if(this->blockFileStream.eof()) {
52 | return false;
53 | }
54 |
55 | if(this->blockFileStream.fail()) {
56 | return false;
57 | }
58 |
59 | return std::equal(buffer.begin(), buffer.end(), VtcBlockIndexer::CoinParams::magic.begin());
60 | }
61 |
62 | VtcBlockIndexer::ScannedBlock VtcBlockIndexer::BlockScanner::scanNextBlock() {
63 | VtcBlockIndexer::ScannedBlock block;
64 |
65 | uint32_t blockSize;
66 | this->blockFileStream.read(reinterpret_cast(&blockSize), sizeof(blockSize));
67 |
68 | // Store the file name and position of the block inside the struct so we can
69 | // use that to read the actual block later after sorting the blockchain.
70 | block.fileName = this->blockFileName;
71 | block.filePosition = this->blockFileStream.tellg();
72 |
73 | vector blockHeader(80);
74 | this->blockFileStream.read(reinterpret_cast(&blockHeader[0]) , 80);
75 |
76 | block.blockHash = VtcBlockIndexer::Utility::hashToReverseHex(VtcBlockIndexer::Utility::sha256(VtcBlockIndexer::Utility::sha256(blockHeader)));
77 | vector previousBlockHash(32);
78 | memcpy(&previousBlockHash[0], &blockHeader[4], 32);
79 | block.previousBlockHash = VtcBlockIndexer::Utility::hashToReverseHex(previousBlockHash);
80 |
81 | this->blockFileStream.seekg(blockSize - 80, std::ios_base::cur);
82 |
83 | return block;
84 | }
--------------------------------------------------------------------------------
/src/blockscanner.h:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 |
21 |
22 | #ifndef BLOCKSCANNER_H_INCLUDED
23 | #define BLOCKSCANNER_H_INCLUDED
24 |
25 | #include
26 | #include
27 |
28 | #include "blockchaintypes.h"
29 | #include "coinparams.h"
30 | namespace VtcBlockIndexer {
31 |
32 | /**
33 | * The BlockScanner class provides methods to scan blk????.dat files
34 | * for block data. It only scans blocks, and reads its header. No
35 | * block data like transactions are read.
36 | */
37 |
38 | class BlockScanner {
39 | public:
40 | /** Constructs a BlockScanner instance using the given block data file
41 | *
42 | * @param blocksDir required Directory where the blockfile is located.
43 | * @param blockFileName required Filename of the block file to read.
44 | */
45 | BlockScanner(const std::string blocksDir, const std::string blockFileName);
46 |
47 | /** Opens the file for reading and allows scanning for blocks
48 | */
49 | bool open();
50 |
51 | /** Tries reading the magic string from the file stream and move the
52 | * file pointer to the start of the block following it. If the magic
53 | * string was not found, either because of the EOF or the wrong
54 | * sequence was found, there is no block and this function will return
55 | * false.
56 | */
57 | bool moveNext();
58 |
59 | /** Scans the next block. Scanning only reads the header and returns a
60 | * ScannedBlock struct that contains the file the block was found in,
61 | * the start position and length inside that file, its hash and
62 | * previousBlockHash. A collection of ScannedBlock objects should be
63 | * sufficient to construct the blockchain.
64 | */
65 | ScannedBlock scanNextBlock();
66 |
67 | /** Closes the file
68 | */
69 | bool close();
70 |
71 | private:
72 |
73 | /** Reference to the stream when the blockfile was opened
74 | */
75 | std::ifstream blockFileStream;
76 |
77 | /** Full path to the blockfile
78 | */
79 | std::string blockFilePath;
80 |
81 | /** File name only of the blockfile
82 | */
83 | std::string blockFileName;
84 |
85 | };
86 |
87 | }
88 |
89 | #endif // BLOCKSCANNER_H_INCLUDED
--------------------------------------------------------------------------------
/src/byte_array_buffer.cpp:
--------------------------------------------------------------------------------
1 | #include "byte_array_buffer.h"
2 |
3 | #include
4 |
5 |
6 | byte_array_buffer::byte_array_buffer(const uint8_t *begin, const size_t size) :
7 | begin_(begin),
8 | end_(begin + size),
9 | current_(begin_)
10 | {
11 | assert(std::less_equal()(begin_, end_));
12 | }
13 |
14 | byte_array_buffer::int_type byte_array_buffer::underflow()
15 | {
16 | if (current_ == end_)
17 | return traits_type::eof();
18 |
19 | return traits_type::to_int_type(*current_);
20 | }
21 |
22 | byte_array_buffer::int_type byte_array_buffer::uflow()
23 | {
24 | if (current_ == end_)
25 | return traits_type::eof();
26 |
27 | return traits_type::to_int_type(*current_++);
28 | }
29 |
30 | byte_array_buffer::int_type byte_array_buffer::pbackfail(int_type ch)
31 | {
32 | if (current_ == begin_ || (ch != traits_type::eof() && ch != current_[-1]))
33 | return traits_type::eof();
34 |
35 | return traits_type::to_int_type(*--current_);
36 | }
37 |
38 | std::streamsize byte_array_buffer::showmanyc()
39 | {
40 | assert(std::less_equal()(current_, end_));
41 | return end_ - current_;
42 | }
43 |
44 |
45 | std::streampos byte_array_buffer::seekoff ( std::streamoff off, std::ios_base::seekdir way,
46 | std::ios_base::openmode which )
47 | {
48 | if (way == std::ios_base::beg)
49 | {
50 | current_ = begin_ + off;
51 | }
52 | else if (way == std::ios_base::cur)
53 | {
54 | current_ += off;
55 | }
56 | else if (way == std::ios_base::end)
57 | {
58 | current_ = end_;
59 | }
60 |
61 | if (current_ < begin_ || current_ > end_)
62 | return -1;
63 |
64 |
65 | return current_ - begin_;
66 | }
67 |
68 | std::streampos byte_array_buffer::seekpos ( std::streampos sp,
69 | std::ios_base::openmode which )
70 | {
71 | current_ = begin_ + sp;
72 |
73 | if (current_ < begin_ || current_ > end_)
74 | return -1;
75 |
76 | return current_ - begin_;
77 | }
--------------------------------------------------------------------------------
/src/byte_array_buffer.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | //
8 | // http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
9 | //
10 |
11 | class byte_array_buffer : public std::streambuf
12 | {
13 | public:
14 | byte_array_buffer(const uint8_t *begin, const size_t size);
15 |
16 | private:
17 | int_type underflow();
18 | int_type uflow();
19 | int_type pbackfail(int_type ch);
20 | std::streamsize showmanyc();
21 | std::streampos seekoff ( std::streamoff off, std::ios_base::seekdir way,
22 | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out );
23 | std::streampos seekpos ( std::streampos sp,
24 | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
25 |
26 | // copy ctor and assignment not implemented;
27 | // copying not allowed
28 | byte_array_buffer(const byte_array_buffer &);
29 | byte_array_buffer &operator= (const byte_array_buffer &);
30 |
31 | private:
32 | const uint8_t * const begin_;
33 | const uint8_t * const end_;
34 | const uint8_t * current_;
35 | };
--------------------------------------------------------------------------------
/src/coinparams.cpp:
--------------------------------------------------------------------------------
1 | #include "coinparams.h"
2 | /* VTC Blockindexer - A utility to build additional indexes to the
3 | Vertcoin blockchain by scanning and indexing the blockfiles
4 | downloaded by Vertcoin Core.
5 |
6 | Copyright (C) 2017 Gert-Jaap Glasbergen
7 |
8 | This program is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation, either version 3 of the License, or
11 | (at your option) any later version.
12 |
13 | This program is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 |
18 | You should have received a copy of the GNU General Public License
19 | along with this program. If not, see .
20 | */
21 |
22 |
23 | #include
24 | #include
25 | #include "json.hpp"
26 | #include "utility.h"
27 | using json = nlohmann::json;
28 | using namespace std;
29 |
30 | vector VtcBlockIndexer::CoinParams::magic;
31 | string VtcBlockIndexer::CoinParams::bech32Prefix;
32 | unsigned char VtcBlockIndexer::CoinParams::p2pkhVersion;
33 | unsigned char VtcBlockIndexer::CoinParams::p2shVersion;
34 |
35 | void VtcBlockIndexer::CoinParams::readFromFile(string fileName)
36 | {
37 | cout << "Reading coin params from [" << fileName << "]" << endl;
38 | ifstream i(fileName);
39 | json j;
40 | i >> j;
41 |
42 | assert(j["magic"].is_string());
43 | assert(j["prefix_bech32"].is_string());
44 | assert(j["version_p2sh"].is_string());
45 | assert(j["version_p2pkh"].is_string());
46 |
47 | magic = VtcBlockIndexer::Utility::hexToBytes(j["magic"].get());
48 | bech32Prefix = j["prefix_bech32"].get();
49 | p2shVersion = (unsigned char) strtol(j["version_p2sh"].get().c_str(), NULL, 16);
50 | p2pkhVersion = (unsigned char) strtol(j["version_p2pkh"].get().c_str(), NULL, 16);
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/coinparams.h:
--------------------------------------------------------------------------------
1 | /* VTC Blockindexer - A utility to build additional indexes to the
2 | Vertcoin blockchain by scanning and indexing the blockfiles
3 | downloaded by Vertcoin Core.
4 |
5 | Copyright (C) 2017 Gert-Jaap Glasbergen
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 | */
20 |
21 | #include
22 | #include
23 |
24 | using namespace std;
25 |
26 | namespace VtcBlockIndexer {
27 |
28 | /**
29 | * The CoinParms class provides static access to the coin parameters and a method
30 | * to read them from a JSON file
31 | */
32 |
33 | class CoinParams {
34 | public:
35 | static void readFromFile(string fileName);
36 | static vector magic;
37 | static string bech32Prefix;
38 | static unsigned char p2pkhVersion;
39 | static unsigned char p2shVersion;
40 | ~CoinParams();
41 |
42 | private:
43 | CoinParams() {}
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/src/crypto/bech32.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Pieter Wuille
2 | // Distributed under the MIT software license, see the accompanying
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 |
5 | #include "bech32.h"
6 | #include
7 |
8 | namespace
9 | {
10 |
11 | typedef std::vector data;
12 |
13 | /** The Bech32 character set for encoding. */
14 | const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
15 |
16 | /** The Bech32 character set for decoding. */
17 | const int8_t CHARSET_REV[128] = {
18 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
19 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
20 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 | 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
22 | -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
23 | 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
24 | -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
25 | 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
26 | };
27 |
28 | /** Concatenate two byte arrays. */
29 | data Cat(data x, const data& y)
30 | {
31 | x.insert(x.end(), y.begin(), y.end());
32 | return x;
33 | }
34 |
35 |
36 |
37 |
38 | /** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
39 | * make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
40 | * bits correspond to earlier values. */
41 | uint32_t PolyMod(const data& v)
42 | {
43 | // The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an
44 | // implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) =
45 | // 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that
46 | // [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...].
47 |
48 | // The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of
49 | // v(x) mod g(x), where g(x) is the Bech32 generator,
50 | // x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way
51 | // that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a
52 | // window of 1023 characters. Among the various possible BCH codes, one was selected to in
53 | // fact guarantee detection of up to 4 errors within a window of 89 characters.
54 |
55 | // Note that the coefficients are elements of GF(32), here represented as decimal numbers
56 | // between {}. In this finite field, addition is just XOR of the corresponding numbers. For
57 | // example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires
58 | // treating the bits of values themselves as coefficients of a polynomial over a smaller field,
59 | // GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} =
60 | // (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a
61 | // = a^3 + 1 (mod a^5 + a^3 + 1) = {9}.
62 |
63 | // During the course of the loop below, `c` contains the bitpacked coefficients of the
64 | // polynomial constructed from just the values of v that were processed so far, mod g(x). In
65 | // the above example, `c` initially corresponds to 1 mod (x), and after processing 2 inputs of
66 | // v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value
67 | // for `c`.
68 | uint32_t c = 1;
69 | for (auto v_i : v) {
70 | // We want to update `c` to correspond to a polynomial with one extra term. If the initial
71 | // value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to
72 | // correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to
73 | // process. Simplifying:
74 | // c'(x) = (f(x) * x + v_i) mod g(x)
75 | // ((f(x) mod g(x)) * x + v_i) mod g(x)
76 | // (c(x) * x + v_i) mod g(x)
77 | // If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute
78 | // c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x)
79 | // = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x)
80 | // = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i
81 | // If we call (x^6 mod g(x)) = k(x), this can be written as
82 | // c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x)
83 |
84 | // First, determine the value of c0:
85 | uint8_t c0 = c >> 25;
86 |
87 | // Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i:
88 | c = ((c & 0x1ffffff) << 5) ^ v_i;
89 |
90 | // Finally, for each set bit n in c0, conditionally add {2^n}k(x):
91 | if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}
92 | if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13}
93 | if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26}
94 | if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29}
95 | if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19}
96 | }
97 | return c;
98 | }
99 |
100 | /** Convert to lower case. */
101 | inline unsigned char LowerCase(unsigned char c)
102 | {
103 | return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
104 | }
105 |
106 | /** Expand a HRP for use in checksum computation. */
107 | data ExpandHRP(const std::string& hrp)
108 | {
109 | data ret;
110 | ret.reserve(hrp.size() + 90);
111 | ret.resize(hrp.size() * 2 + 1);
112 | for (size_t i = 0; i < hrp.size(); ++i) {
113 | unsigned char c = hrp[i];
114 | ret[i] = c >> 5;
115 | ret[i + hrp.size() + 1] = c & 0x1f;
116 | }
117 | ret[hrp.size()] = 0;
118 | return ret;
119 | }
120 |
121 | /** Verify a checksum. */
122 | bool VerifyChecksum(const std::string& hrp, const data& values)
123 | {
124 | // PolyMod computes what value to xor into the final values to make the checksum 0. However,
125 | // if we required that the checksum was 0, it would be the case that appending a 0 to a valid
126 | // list of values would result in a new valid list. For that reason, Bech32 requires the
127 | // resulting checksum to be 1 instead.
128 | return PolyMod(Cat(ExpandHRP(hrp), values)) == 1;
129 | }
130 |
131 | /** Create a checksum. */
132 | data CreateChecksum(const std::string& hrp, const data& values)
133 | {
134 | data enc = Cat(ExpandHRP(hrp), values);
135 | enc.resize(enc.size() + 6); // Append 6 zeroes
136 | uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes.
137 | data ret(6);
138 | for (size_t i = 0; i < 6; ++i) {
139 | // Convert the 5-bit groups in mod to checksum values.
140 | ret[i] = (mod >> (5 * (5 - i))) & 31;
141 | }
142 | return ret;
143 | }
144 |
145 | } // namespace
146 |
147 | namespace bech32
148 | {
149 |
150 | /** Encode a Bech32 string. */
151 | std::string Encode(const std::string& hrp, const data& values) {
152 | data checksum = CreateChecksum(hrp, values);
153 | data combined = Cat(values, checksum);
154 |
155 | std::string ret = hrp + '1';
156 | ret.reserve(ret.size() + combined.size());
157 | for (auto c : combined) {
158 | ret += CHARSET[c];
159 | }
160 | return ret;
161 | }
162 |
163 | /** Decode a Bech32 string. */
164 | std::pair Decode(const std::string& str) {
165 | bool lower = false, upper = false;
166 | for (size_t i = 0; i < str.size(); ++i) {
167 | unsigned char c = str[i];
168 | if (c < 33 || c > 126) return {};
169 | if (c >= 'a' && c <= 'z') lower = true;
170 | if (c >= 'A' && c <= 'Z') upper = true;
171 | }
172 | if (lower && upper) return {};
173 | size_t pos = str.rfind('1');
174 | if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
175 | return {};
176 | }
177 | data values(str.size() - 1 - pos);
178 | for (size_t i = 0; i < str.size() - 1 - pos; ++i) {
179 | unsigned char c = str[i + pos + 1];
180 | int8_t rev = (c < 33 || c > 126) ? -1 : CHARSET_REV[c];
181 | if (rev == -1) {
182 | return {};
183 | }
184 | values[i] = rev;
185 | }
186 | std::string hrp;
187 | for (size_t i = 0; i < pos; ++i) {
188 | hrp += LowerCase(str[i]);
189 | }
190 | if (!VerifyChecksum(hrp, values)) {
191 | return {};
192 | }
193 | return {hrp, data(values.begin(), values.end() - 6)};
194 | }
195 |
196 | } // namespace bech32
--------------------------------------------------------------------------------
/src/crypto/bech32.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Pieter Wuille
2 | // Distributed under the MIT software license, see the accompanying
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 |
5 | // Bech32 is a string encoding format used in newer address types.
6 | // The output consists of a human-readable part (alphanumeric), a
7 | // separator character (1), and a base32 data section, the last
8 | // 6 characters of which are a checksum.
9 | //
10 | // For more information, see BIP 173.
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | namespace bech32
17 | {
18 |
19 | /** Encode a Bech32 string. Returns the empty string in case of failure. */
20 | std::string Encode(const std::string& hrp, const std::vector& values);
21 |
22 | /** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */
23 | std::pair> Decode(const std::string& str);
24 |
25 | } // namespace bech32
--------------------------------------------------------------------------------
/src/crypto/common.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014 The Bitcoin Core developers
2 | // Distributed under the MIT software license, see the accompanying
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 |
5 | #ifndef BITCOIN_CRYPTO_COMMON_H
6 | #define BITCOIN_CRYPTO_COMMON_H
7 |
8 | #include
9 |
10 | uint16_t static inline ReadLE16(const unsigned char* ptr)
11 | {
12 | return le16toh(*((uint16_t*)ptr));
13 | }
14 |
15 | uint32_t static inline ReadLE32(const unsigned char* ptr)
16 | {
17 | return le32toh(*((uint32_t*)ptr));
18 | }
19 |
20 | uint64_t static inline ReadLE64(const unsigned char* ptr)
21 | {
22 | return le64toh(*((uint64_t*)ptr));
23 | }
24 |
25 | void static inline WriteLE16(unsigned char* ptr, uint16_t x)
26 | {
27 | *((uint16_t*)ptr) = htole16(x);
28 | }
29 |
30 | void static inline WriteLE32(unsigned char* ptr, uint32_t x)
31 | {
32 | *((uint32_t*)ptr) = htole32(x);
33 | }
34 |
35 | void static inline WriteLE64(unsigned char* ptr, uint64_t x)
36 | {
37 | *((uint64_t*)ptr) = htole64(x);
38 | }
39 |
40 | uint32_t static inline ReadBE32(const unsigned char* ptr)
41 | {
42 | return be32toh(*((uint32_t*)ptr));
43 | }
44 |
45 | uint64_t static inline ReadBE64(const unsigned char* ptr)
46 | {
47 | return be64toh(*((uint64_t*)ptr));
48 | }
49 |
50 | void static inline WriteBE32(unsigned char* ptr, uint32_t x)
51 | {
52 | *((uint32_t*)ptr) = htobe32(x);
53 | }
54 |
55 | void static inline WriteBE64(unsigned char* ptr, uint64_t x)
56 | {
57 | *((uint64_t*)ptr) = htobe64(x);
58 | }
59 |
60 | #endif // BITCOIN_CRYPTO_COMMON_H
61 |
--------------------------------------------------------------------------------
/src/crypto/ripemd160.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014 The Bitcoin Core developers
2 | // Distributed under the MIT software license, see the accompanying
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 |
5 | #include "ripemd160.h"
6 |
7 | #include "common.h"
8 |
9 | #include
10 |
11 | // Internal implementation code.
12 | namespace
13 | {
14 | /// Internal RIPEMD-160 implementation.
15 | namespace ripemd160
16 | {
17 | uint32_t inline f1(uint32_t x, uint32_t y, uint32_t z) { return x ^ y ^ z; }
18 | uint32_t inline f2(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (~x & z); }
19 | uint32_t inline f3(uint32_t x, uint32_t y, uint32_t z) { return (x | ~y) ^ z; }
20 | uint32_t inline f4(uint32_t x, uint32_t y, uint32_t z) { return (x & z) | (y & ~z); }
21 | uint32_t inline f5(uint32_t x, uint32_t y, uint32_t z) { return x ^ (y | ~z); }
22 |
23 | /** Initialize RIPEMD-160 state. */
24 | void inline Initialize(uint32_t* s)
25 | {
26 | s[0] = 0x67452301ul;
27 | s[1] = 0xEFCDAB89ul;
28 | s[2] = 0x98BADCFEul;
29 | s[3] = 0x10325476ul;
30 | s[4] = 0xC3D2E1F0ul;
31 | }
32 |
33 | uint32_t inline rol(uint32_t x, int i) { return (x << i) | (x >> (32 - i)); }
34 |
35 | void inline Round(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t f, uint32_t x, uint32_t k, int r)
36 | {
37 | a = rol(a + f + x + k, r) + e;
38 | c = rol(c, 10);
39 | }
40 |
41 | void inline R11(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); }
42 | void inline R21(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x5A827999ul, r); }
43 | void inline R31(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6ED9EBA1ul, r); }
44 | void inline R41(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x8F1BBCDCul, r); }
45 | void inline R51(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0xA953FD4Eul, r); }
46 |
47 | void inline R12(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0x50A28BE6ul, r); }
48 | void inline R22(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x5C4DD124ul, r); }
49 | void inline R32(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6D703EF3ul, r); }
50 | void inline R42(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x7A6D76E9ul, r); }
51 | void inline R52(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); }
52 |
53 | /** Perform a RIPEMD-160 transformation, processing a 64-byte chunk. */
54 | void Transform(uint32_t* s, const unsigned char* chunk)
55 | {
56 | uint32_t a1 = s[0], b1 = s[1], c1 = s[2], d1 = s[3], e1 = s[4];
57 | uint32_t a2 = a1, b2 = b1, c2 = c1, d2 = d1, e2 = e1;
58 | uint32_t w0 = ReadLE32(chunk + 0), w1 = ReadLE32(chunk + 4), w2 = ReadLE32(chunk + 8), w3 = ReadLE32(chunk + 12);
59 | uint32_t w4 = ReadLE32(chunk + 16), w5 = ReadLE32(chunk + 20), w6 = ReadLE32(chunk + 24), w7 = ReadLE32(chunk + 28);
60 | uint32_t w8 = ReadLE32(chunk + 32), w9 = ReadLE32(chunk + 36), w10 = ReadLE32(chunk + 40), w11 = ReadLE32(chunk + 44);
61 | uint32_t w12 = ReadLE32(chunk + 48), w13 = ReadLE32(chunk + 52), w14 = ReadLE32(chunk + 56), w15 = ReadLE32(chunk + 60);
62 |
63 | R11(a1, b1, c1, d1, e1, w0, 11);
64 | R12(a2, b2, c2, d2, e2, w5, 8);
65 | R11(e1, a1, b1, c1, d1, w1, 14);
66 | R12(e2, a2, b2, c2, d2, w14, 9);
67 | R11(d1, e1, a1, b1, c1, w2, 15);
68 | R12(d2, e2, a2, b2, c2, w7, 9);
69 | R11(c1, d1, e1, a1, b1, w3, 12);
70 | R12(c2, d2, e2, a2, b2, w0, 11);
71 | R11(b1, c1, d1, e1, a1, w4, 5);
72 | R12(b2, c2, d2, e2, a2, w9, 13);
73 | R11(a1, b1, c1, d1, e1, w5, 8);
74 | R12(a2, b2, c2, d2, e2, w2, 15);
75 | R11(e1, a1, b1, c1, d1, w6, 7);
76 | R12(e2, a2, b2, c2, d2, w11, 15);
77 | R11(d1, e1, a1, b1, c1, w7, 9);
78 | R12(d2, e2, a2, b2, c2, w4, 5);
79 | R11(c1, d1, e1, a1, b1, w8, 11);
80 | R12(c2, d2, e2, a2, b2, w13, 7);
81 | R11(b1, c1, d1, e1, a1, w9, 13);
82 | R12(b2, c2, d2, e2, a2, w6, 7);
83 | R11(a1, b1, c1, d1, e1, w10, 14);
84 | R12(a2, b2, c2, d2, e2, w15, 8);
85 | R11(e1, a1, b1, c1, d1, w11, 15);
86 | R12(e2, a2, b2, c2, d2, w8, 11);
87 | R11(d1, e1, a1, b1, c1, w12, 6);
88 | R12(d2, e2, a2, b2, c2, w1, 14);
89 | R11(c1, d1, e1, a1, b1, w13, 7);
90 | R12(c2, d2, e2, a2, b2, w10, 14);
91 | R11(b1, c1, d1, e1, a1, w14, 9);
92 | R12(b2, c2, d2, e2, a2, w3, 12);
93 | R11(a1, b1, c1, d1, e1, w15, 8);
94 | R12(a2, b2, c2, d2, e2, w12, 6);
95 |
96 | R21(e1, a1, b1, c1, d1, w7, 7);
97 | R22(e2, a2, b2, c2, d2, w6, 9);
98 | R21(d1, e1, a1, b1, c1, w4, 6);
99 | R22(d2, e2, a2, b2, c2, w11, 13);
100 | R21(c1, d1, e1, a1, b1, w13, 8);
101 | R22(c2, d2, e2, a2, b2, w3, 15);
102 | R21(b1, c1, d1, e1, a1, w1, 13);
103 | R22(b2, c2, d2, e2, a2, w7, 7);
104 | R21(a1, b1, c1, d1, e1, w10, 11);
105 | R22(a2, b2, c2, d2, e2, w0, 12);
106 | R21(e1, a1, b1, c1, d1, w6, 9);
107 | R22(e2, a2, b2, c2, d2, w13, 8);
108 | R21(d1, e1, a1, b1, c1, w15, 7);
109 | R22(d2, e2, a2, b2, c2, w5, 9);
110 | R21(c1, d1, e1, a1, b1, w3, 15);
111 | R22(c2, d2, e2, a2, b2, w10, 11);
112 | R21(b1, c1, d1, e1, a1, w12, 7);
113 | R22(b2, c2, d2, e2, a2, w14, 7);
114 | R21(a1, b1, c1, d1, e1, w0, 12);
115 | R22(a2, b2, c2, d2, e2, w15, 7);
116 | R21(e1, a1, b1, c1, d1, w9, 15);
117 | R22(e2, a2, b2, c2, d2, w8, 12);
118 | R21(d1, e1, a1, b1, c1, w5, 9);
119 | R22(d2, e2, a2, b2, c2, w12, 7);
120 | R21(c1, d1, e1, a1, b1, w2, 11);
121 | R22(c2, d2, e2, a2, b2, w4, 6);
122 | R21(b1, c1, d1, e1, a1, w14, 7);
123 | R22(b2, c2, d2, e2, a2, w9, 15);
124 | R21(a1, b1, c1, d1, e1, w11, 13);
125 | R22(a2, b2, c2, d2, e2, w1, 13);
126 | R21(e1, a1, b1, c1, d1, w8, 12);
127 | R22(e2, a2, b2, c2, d2, w2, 11);
128 |
129 | R31(d1, e1, a1, b1, c1, w3, 11);
130 | R32(d2, e2, a2, b2, c2, w15, 9);
131 | R31(c1, d1, e1, a1, b1, w10, 13);
132 | R32(c2, d2, e2, a2, b2, w5, 7);
133 | R31(b1, c1, d1, e1, a1, w14, 6);
134 | R32(b2, c2, d2, e2, a2, w1, 15);
135 | R31(a1, b1, c1, d1, e1, w4, 7);
136 | R32(a2, b2, c2, d2, e2, w3, 11);
137 | R31(e1, a1, b1, c1, d1, w9, 14);
138 | R32(e2, a2, b2, c2, d2, w7, 8);
139 | R31(d1, e1, a1, b1, c1, w15, 9);
140 | R32(d2, e2, a2, b2, c2, w14, 6);
141 | R31(c1, d1, e1, a1, b1, w8, 13);
142 | R32(c2, d2, e2, a2, b2, w6, 6);
143 | R31(b1, c1, d1, e1, a1, w1, 15);
144 | R32(b2, c2, d2, e2, a2, w9, 14);
145 | R31(a1, b1, c1, d1, e1, w2, 14);
146 | R32(a2, b2, c2, d2, e2, w11, 12);
147 | R31(e1, a1, b1, c1, d1, w7, 8);
148 | R32(e2, a2, b2, c2, d2, w8, 13);
149 | R31(d1, e1, a1, b1, c1, w0, 13);
150 | R32(d2, e2, a2, b2, c2, w12, 5);
151 | R31(c1, d1, e1, a1, b1, w6, 6);
152 | R32(c2, d2, e2, a2, b2, w2, 14);
153 | R31(b1, c1, d1, e1, a1, w13, 5);
154 | R32(b2, c2, d2, e2, a2, w10, 13);
155 | R31(a1, b1, c1, d1, e1, w11, 12);
156 | R32(a2, b2, c2, d2, e2, w0, 13);
157 | R31(e1, a1, b1, c1, d1, w5, 7);
158 | R32(e2, a2, b2, c2, d2, w4, 7);
159 | R31(d1, e1, a1, b1, c1, w12, 5);
160 | R32(d2, e2, a2, b2, c2, w13, 5);
161 |
162 | R41(c1, d1, e1, a1, b1, w1, 11);
163 | R42(c2, d2, e2, a2, b2, w8, 15);
164 | R41(b1, c1, d1, e1, a1, w9, 12);
165 | R42(b2, c2, d2, e2, a2, w6, 5);
166 | R41(a1, b1, c1, d1, e1, w11, 14);
167 | R42(a2, b2, c2, d2, e2, w4, 8);
168 | R41(e1, a1, b1, c1, d1, w10, 15);
169 | R42(e2, a2, b2, c2, d2, w1, 11);
170 | R41(d1, e1, a1, b1, c1, w0, 14);
171 | R42(d2, e2, a2, b2, c2, w3, 14);
172 | R41(c1, d1, e1, a1, b1, w8, 15);
173 | R42(c2, d2, e2, a2, b2, w11, 14);
174 | R41(b1, c1, d1, e1, a1, w12, 9);
175 | R42(b2, c2, d2, e2, a2, w15, 6);
176 | R41(a1, b1, c1, d1, e1, w4, 8);
177 | R42(a2, b2, c2, d2, e2, w0, 14);
178 | R41(e1, a1, b1, c1, d1, w13, 9);
179 | R42(e2, a2, b2, c2, d2, w5, 6);
180 | R41(d1, e1, a1, b1, c1, w3, 14);
181 | R42(d2, e2, a2, b2, c2, w12, 9);
182 | R41(c1, d1, e1, a1, b1, w7, 5);
183 | R42(c2, d2, e2, a2, b2, w2, 12);
184 | R41(b1, c1, d1, e1, a1, w15, 6);
185 | R42(b2, c2, d2, e2, a2, w13, 9);
186 | R41(a1, b1, c1, d1, e1, w14, 8);
187 | R42(a2, b2, c2, d2, e2, w9, 12);
188 | R41(e1, a1, b1, c1, d1, w5, 6);
189 | R42(e2, a2, b2, c2, d2, w7, 5);
190 | R41(d1, e1, a1, b1, c1, w6, 5);
191 | R42(d2, e2, a2, b2, c2, w10, 15);
192 | R41(c1, d1, e1, a1, b1, w2, 12);
193 | R42(c2, d2, e2, a2, b2, w14, 8);
194 |
195 | R51(b1, c1, d1, e1, a1, w4, 9);
196 | R52(b2, c2, d2, e2, a2, w12, 8);
197 | R51(a1, b1, c1, d1, e1, w0, 15);
198 | R52(a2, b2, c2, d2, e2, w15, 5);
199 | R51(e1, a1, b1, c1, d1, w5, 5);
200 | R52(e2, a2, b2, c2, d2, w10, 12);
201 | R51(d1, e1, a1, b1, c1, w9, 11);
202 | R52(d2, e2, a2, b2, c2, w4, 9);
203 | R51(c1, d1, e1, a1, b1, w7, 6);
204 | R52(c2, d2, e2, a2, b2, w1, 12);
205 | R51(b1, c1, d1, e1, a1, w12, 8);
206 | R52(b2, c2, d2, e2, a2, w5, 5);
207 | R51(a1, b1, c1, d1, e1, w2, 13);
208 | R52(a2, b2, c2, d2, e2, w8, 14);
209 | R51(e1, a1, b1, c1, d1, w10, 12);
210 | R52(e2, a2, b2, c2, d2, w7, 6);
211 | R51(d1, e1, a1, b1, c1, w14, 5);
212 | R52(d2, e2, a2, b2, c2, w6, 8);
213 | R51(c1, d1, e1, a1, b1, w1, 12);
214 | R52(c2, d2, e2, a2, b2, w2, 13);
215 | R51(b1, c1, d1, e1, a1, w3, 13);
216 | R52(b2, c2, d2, e2, a2, w13, 6);
217 | R51(a1, b1, c1, d1, e1, w8, 14);
218 | R52(a2, b2, c2, d2, e2, w14, 5);
219 | R51(e1, a1, b1, c1, d1, w11, 11);
220 | R52(e2, a2, b2, c2, d2, w0, 15);
221 | R51(d1, e1, a1, b1, c1, w6, 8);
222 | R52(d2, e2, a2, b2, c2, w3, 13);
223 | R51(c1, d1, e1, a1, b1, w15, 5);
224 | R52(c2, d2, e2, a2, b2, w9, 11);
225 | R51(b1, c1, d1, e1, a1, w13, 6);
226 | R52(b2, c2, d2, e2, a2, w11, 11);
227 |
228 | uint32_t t = s[0];
229 | s[0] = s[1] + c1 + d2;
230 | s[1] = s[2] + d1 + e2;
231 | s[2] = s[3] + e1 + a2;
232 | s[3] = s[4] + a1 + b2;
233 | s[4] = t + b1 + c2;
234 | }
235 |
236 | } // namespace ripemd160
237 |
238 | } // namespace
239 |
240 | ////// RIPEMD160
241 |
242 | CRIPEMD160::CRIPEMD160() : bytes(0)
243 | {
244 | ripemd160::Initialize(s);
245 | }
246 |
247 | CRIPEMD160& CRIPEMD160::Write(const unsigned char* data, size_t len)
248 | {
249 | const unsigned char* end = data + len;
250 | size_t bufsize = bytes % 64;
251 | if (bufsize && bufsize + len >= 64) {
252 | // Fill the buffer, and process it.
253 | memcpy(buf + bufsize, data, 64 - bufsize);
254 | bytes += 64 - bufsize;
255 | data += 64 - bufsize;
256 | ripemd160::Transform(s, buf);
257 | bufsize = 0;
258 | }
259 | while (end >= data + 64) {
260 | // Process full chunks directly from the source.
261 | ripemd160::Transform(s, data);
262 | bytes += 64;
263 | data += 64;
264 | }
265 | if (end > data) {
266 | // Fill the buffer with what remains.
267 | memcpy(buf + bufsize, data, end - data);
268 | bytes += end - data;
269 | }
270 | return *this;
271 | }
272 |
273 | void CRIPEMD160::Finalize(unsigned char hash[OUTPUT_SIZE])
274 | {
275 | static const unsigned char pad[64] = {0x80};
276 | unsigned char sizedesc[8];
277 | WriteLE64(sizedesc, bytes << 3);
278 | Write(pad, 1 + ((119 - (bytes % 64)) % 64));
279 | Write(sizedesc, 8);
280 | WriteLE32(hash, s[0]);
281 | WriteLE32(hash + 4, s[1]);
282 | WriteLE32(hash + 8, s[2]);
283 | WriteLE32(hash + 12, s[3]);
284 | WriteLE32(hash + 16, s[4]);
285 | }
286 |
287 | CRIPEMD160& CRIPEMD160::Reset()
288 | {
289 | bytes = 0;
290 | ripemd160::Initialize(s);
291 | return *this;
292 | }
293 |
--------------------------------------------------------------------------------
/src/crypto/ripemd160.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014 The Bitcoin Core developers
2 | // Distributed under the MIT software license, see the accompanying
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 |
5 | #ifndef BITCOIN_CRYPTO_RIPEMD160_H
6 | #define BITCOIN_CRYPTO_RIPEMD160_H
7 |
8 | #include
9 | #include
10 |
11 | /** A hasher class for RIPEMD-160. */
12 | class CRIPEMD160
13 | {
14 | private:
15 | uint32_t s[5];
16 | unsigned char buf[64];
17 | uint64_t bytes;
18 |
19 | public:
20 | static const size_t OUTPUT_SIZE = 20;
21 |
22 | CRIPEMD160();
23 | CRIPEMD160& Write(const unsigned char* data, size_t len);
24 | void Finalize(unsigned char hash[OUTPUT_SIZE]);
25 | CRIPEMD160& Reset();
26 | };
27 |
28 | #endif // BITCOIN_CRYPTO_RIPEMD160_H
29 |
--------------------------------------------------------------------------------
/src/cxxopts.hpp:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
23 | */
24 |
25 | #ifndef CXX_OPTS_HPP
26 | #define CXX_OPTS_HPP
27 |
28 | #if defined(__GNUC__)
29 | #pragma GCC diagnostic push
30 | #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
31 | #endif
32 |
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include