Initial commit

This commit is contained in:
Selim Mustafaev 2021-05-06 16:58:11 +03:00
commit 9173093dbf
15 changed files with 441 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.idea/
cmake-build-*/

7
CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.19)
project(btcexplorer)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
add_executable(btcexplorer main.cpp Models/Block.cpp Models/Block.h Models/Transaction.cpp Models/Transaction.h Models/VarInt.cpp Models/VarInt.h Models/TxInput.cpp Models/TxInput.h Models/TxOutput.cpp Models/TxOutput.h Models/Script.cpp Models/Script.h)

31
Models/Block.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "Block.h"
#include "VarInt.h"
Block::Block(const std::byte* pBlock, size_t size): _header{} {
_size = size;
_header = *((BlockHeader*)pBlock);
VarInt txCount(pBlock + sizeof(BlockHeader));
auto pTxData = pBlock + sizeof(BlockHeader) + txCount.size();
for(size_t i = 0; i < txCount.value(); ++i) {
Transaction transaction(pTxData);
_transactions.push_back(transaction);
pTxData += transaction.size();
}
}
uint32_t Block::version() const {
return _header.version;
}
uint32_t Block::time() const {
return _header.time;
}
const std::vector<Transaction>& Block::transactions() const {
return _transactions;
}
size_t Block::size() const {
return _size;
}

44
Models/Block.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef BTCEXPLORER_BLOCK_H
#define BTCEXPLORER_BLOCK_H
#include <cstdint>
#include <array>
#include <vector>
#include "Transaction.h"
enum BlockMagic: uint32_t {
Mainnet = 0xf9beb4d9,
Testnet3 = 0x0b110907,
Regtest = 0xfabfb5da
};
struct PreBlockHeader {
BlockMagic magic;
uint32_t blockSize;
};
struct BlockHeader {
uint32_t version;
std::array<uint8_t,32> prevBlockHeaderHash;
std::array<uint8_t,32> merkleRootHash;
uint32_t time;
uint32_t nBits;
uint32_t nOnce;
};
class Block {
private:
BlockHeader _header;
std::vector<Transaction> _transactions;
size_t _size;
public:
Block(const std::byte* pBlock, size_t size);
[[nodiscard]] uint32_t version() const;
[[nodiscard]] uint32_t time() const;
[[nodiscard]] const std::vector<Transaction>& transactions() const;
[[nodiscard]] size_t size() const;
};
#endif //BTCEXPLORER_BLOCK_H

5
Models/Script.cpp Normal file
View File

@ -0,0 +1,5 @@
//
// Created by Selim Mustafaev on 05.05.2021.
//
#include "Script.h"

149
Models/Script.h Normal file
View File

@ -0,0 +1,149 @@
#ifndef BTCEXPLORER_SCRIPT_H
#define BTCEXPLORER_SCRIPT_H
enum OpCode {
// push value
OP_0 = 0x00,
OP_FALSE = OP_0,
OP_PUSHDATA1 = 0x4c,
OP_PUSHDATA2 = 0x4d,
OP_PUSHDATA4 = 0x4e,
OP_1NEGATE = 0x4f,
OP_RESERVED = 0x50,
OP_1 = 0x51,
OP_TRUE=OP_1,
OP_2 = 0x52,
OP_3 = 0x53,
OP_4 = 0x54,
OP_5 = 0x55,
OP_6 = 0x56,
OP_7 = 0x57,
OP_8 = 0x58,
OP_9 = 0x59,
OP_10 = 0x5a,
OP_11 = 0x5b,
OP_12 = 0x5c,
OP_13 = 0x5d,
OP_14 = 0x5e,
OP_15 = 0x5f,
OP_16 = 0x60,
// control
OP_NOP = 0x61,
OP_VER = 0x62,
OP_IF = 0x63,
OP_NOTIF = 0x64,
OP_VERIF = 0x65,
OP_VERNOTIF = 0x66,
OP_ELSE = 0x67,
OP_ENDIF = 0x68,
OP_VERIFY = 0x69,
OP_RETURN = 0x6a,
// stack ops
OP_TOALTSTACK = 0x6b,
OP_FROMALTSTACK = 0x6c,
OP_2DROP = 0x6d,
OP_2DUP = 0x6e,
OP_3DUP = 0x6f,
OP_2OVER = 0x70,
OP_2ROT = 0x71,
OP_2SWAP = 0x72,
OP_IFDUP = 0x73,
OP_DEPTH = 0x74,
OP_DROP = 0x75,
OP_DUP = 0x76,
OP_NIP = 0x77,
OP_OVER = 0x78,
OP_PICK = 0x79,
OP_ROLL = 0x7a,
OP_ROT = 0x7b,
OP_SWAP = 0x7c,
OP_TUCK = 0x7d,
// splice ops
OP_CAT = 0x7e,
OP_SUBSTR = 0x7f,
OP_LEFT = 0x80,
OP_RIGHT = 0x81,
OP_SIZE = 0x82,
// bit logic
OP_INVERT = 0x83,
OP_AND = 0x84,
OP_OR = 0x85,
OP_XOR = 0x86,
OP_EQUAL = 0x87,
OP_EQUALVERIFY = 0x88,
OP_RESERVED1 = 0x89,
OP_RESERVED2 = 0x8a,
// numeric
OP_1ADD = 0x8b,
OP_1SUB = 0x8c,
OP_2MUL = 0x8d,
OP_2DIV = 0x8e,
OP_NEGATE = 0x8f,
OP_ABS = 0x90,
OP_NOT = 0x91,
OP_0NOTEQUAL = 0x92,
OP_ADD = 0x93,
OP_SUB = 0x94,
OP_MUL = 0x95,
OP_DIV = 0x96,
OP_MOD = 0x97,
OP_LSHIFT = 0x98,
OP_RSHIFT = 0x99,
OP_BOOLAND = 0x9a,
OP_BOOLOR = 0x9b,
OP_NUMEQUAL = 0x9c,
OP_NUMEQUALVERIFY = 0x9d,
OP_NUMNOTEQUAL = 0x9e,
OP_LESSTHAN = 0x9f,
OP_GREATERTHAN = 0xa0,
OP_LESSTHANOREQUAL = 0xa1,
OP_GREATERTHANOREQUAL = 0xa2,
OP_MIN = 0xa3,
OP_MAX = 0xa4,
OP_WITHIN = 0xa5,
// crypto
OP_RIPEMD160 = 0xa6,
OP_SHA1 = 0xa7,
OP_SHA256 = 0xa8,
OP_HASH160 = 0xa9,
OP_HASH256 = 0xaa,
OP_CODESEPARATOR = 0xab,
OP_CHECKSIG = 0xac,
OP_CHECKSIGVERIFY = 0xad,
OP_CHECKMULTISIG = 0xae,
OP_CHECKMULTISIGVERIFY = 0xaf,
// expansion
OP_NOP1 = 0xb0,
OP_CHECKLOCKTIMEVERIFY = 0xb1,
OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,
OP_CHECKSEQUENCEVERIFY = 0xb2,
OP_NOP3 = OP_CHECKSEQUENCEVERIFY,
OP_NOP4 = 0xb3,
OP_NOP5 = 0xb4,
OP_NOP6 = 0xb5,
OP_NOP7 = 0xb6,
OP_NOP8 = 0xb7,
OP_NOP9 = 0xb8,
OP_NOP10 = 0xb9,
// Opcode added by BIP 342 (Tapscript)
OP_CHECKSIGADD = 0xba,
OP_INVALIDOPCODE = 0xff,
};
class Script {
};
#endif //BTCEXPLORER_SCRIPT_H

29
Models/Transaction.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "Transaction.h"
#include "VarInt.h"
Transaction::Transaction(const std::byte *data) {
_version = *((uint32_t*)data);
VarInt inputCount(data + sizeof(_version));
const std::byte* curPtr = data + sizeof(_version) + inputCount.size();
for(size_t i = 0; i < inputCount.value(); ++i) {
TxInput input(curPtr);
curPtr += input.size();
_inputs.push_back(input);
}
VarInt outputCount(curPtr);
curPtr += outputCount.size();
for(size_t i = 0; i < outputCount.value(); ++i) {
TxOutput output(curPtr);
curPtr += output.size();
_outputs.push_back(output);
}
_lockTime = *((uint32_t*)curPtr);
_size = curPtr - data + sizeof(_lockTime);
}
size_t Transaction::size() const {
return _size;
}

24
Models/Transaction.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef BTCEXPLORER_TRANSACTION_H
#define BTCEXPLORER_TRANSACTION_H
#include <cstdint>
#include <cstdlib>
#include <vector>
#include "TxInput.h"
#include "TxOutput.h"
class Transaction {
private:
uint32_t _version;
size_t _size;
std::vector<TxInput> _inputs;
std::vector<TxOutput> _outputs;
uint32_t _lockTime;
public:
explicit Transaction(const std::byte* data);
[[nodiscard]] size_t size() const;
};
#endif //BTCEXPLORER_TRANSACTION_H

21
Models/TxInput.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "TxInput.h"
#include "VarInt.h"
#include <algorithm>
TxInput::TxInput(const std::byte *data) {
std::copy_n(data, _txId.size(), _txId.begin());
data += _txId.size();
_vOut = *reinterpret_cast<const uint32_t*>(data);
data += sizeof(_vOut);
VarInt scriptSigSize(data);
// TODO: save ScriptSig
data += scriptSigSize.size();
_sequence = *reinterpret_cast<const uint32_t*>(data);
_size = _txId.size() + sizeof(_vOut) + scriptSigSize.size() + scriptSigSize.value() + sizeof(_sequence);
}
size_t TxInput::size() const {
return _size;
}

18
Models/TxInput.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef BTCEXPLORER_TXINPUT_H
#define BTCEXPLORER_TXINPUT_H
#include <array>
class TxInput {
private:
std::array<std::byte,32> _txId;
uint32_t _vOut;
uint32_t _sequence;
size_t _size;
public:
explicit TxInput(const std::byte* data);
[[nodiscard]] size_t size() const;
};
#endif //BTCEXPLORER_TXINPUT_H

16
Models/TxOutput.cpp Normal file
View File

@ -0,0 +1,16 @@
#include "TxOutput.h"
#include "VarInt.h"
TxOutput::TxOutput(const std::byte *data) {
_value = *reinterpret_cast<const uint64_t*>(data);
data += sizeof(_value);
VarInt scriptPubKeySize(data);
// TODO: Read ScriptSizeKey
_size = sizeof(_value) + scriptPubKeySize.size() + scriptPubKeySize.value();
}
size_t TxOutput::size() const {
return _size;
}

17
Models/TxOutput.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef BTCEXPLORER_TXOUTPUT_H
#define BTCEXPLORER_TXOUTPUT_H
#include <cstdint>
#include <cstddef>
class TxOutput {
private:
uint64_t _value;
size_t _size;
public:
explicit TxOutput(const std::byte* data);
[[nodiscard]] size_t size() const;
};
#endif //BTCEXPLORER_TXOUTPUT_H

19
Models/VarInt.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "VarInt.h"
VarInt::VarInt(const std::byte *data) {
auto pByte = reinterpret_cast<const uint8_t*>(data);
switch (*pByte) {
case 0xfd: _value = *((uint16_t*)(pByte + 1)); _size = 2 + 1; break;
case 0xfe: _value = *((uint32_t*)(pByte + 1)); _size = 4 + 1; break;
case 0xff: _value = *((uint64_t*)(pByte + 1)); _size = 8 + 1; break;
default: _value = *pByte; _size = 1; break;
}
}
uint64_t VarInt::value() const {
return _value;
}
uint8_t VarInt::size() const {
return _size;
}

19
Models/VarInt.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef BTCEXPLORER_VARINT_H
#define BTCEXPLORER_VARINT_H
#include <cstdint>
#include <cstddef>
class VarInt {
private:
uint64_t _value;
uint8_t _size;
public:
explicit VarInt(const std::byte* data);
[[nodiscard]] uint64_t value() const;
[[nodiscard]] uint8_t size() const;
};
#endif //BTCEXPLORER_VARINT_H

39
main.cpp Normal file
View File

@ -0,0 +1,39 @@
#include <iostream>
#include <fstream>
#include <memory>
#include <vector>
#include "Models/Block.h"
int main() {
std::string path = "/Users/selim/Documents/blk00000.dat";
std::fstream file(path);
std::vector<Block> blocks;
PreBlockHeader header{};
size_t index = 0;
while (true) {
file.read((char*)&header, sizeof(header));
header.magic = (BlockMagic)__builtin_bswap32(header.magic);
if(file.eof()) {
break;
}
auto blockData = std::make_unique<std::byte[]>(header.blockSize);
file.read((char*)blockData.get(), header.blockSize);
Block block(blockData.get(), header.blockSize);
blocks.push_back(block);
//std::cout << "Parsed new block " << index++ << " with size: " << header.blockSize << std::endl;
}
std::cout << "Blocks found: " << blocks.size() << std::endl;
// for(size_t i = 0; i < 100; ++i) {
// std::cout << "version: " << blocks[i].time() << std::endl;
// }
return 0;
}