From 888e1967c46516b6b0681bec35cc534ea045ebcb Mon Sep 17 00:00:00 2001 From: Selim Mustafaev Date: Sun, 9 May 2021 08:07:38 +0300 Subject: [PATCH] Basic support of parsing scripts --- CMakeLists.txt | 1 + Models/Block.cpp | 2 +- Models/Script.cpp | 55 +++++++++++++++++++++++++++++++++++++++--- Models/Script.h | 27 +++++++++++++++++++-- Models/Transaction.cpp | 4 +-- Models/TxInput.cpp | 9 ++++--- Models/TxInput.h | 6 +++++ Models/TxOutput.cpp | 6 ++++- Models/TxOutput.h | 4 +++ main.cpp | 15 +++++++++--- 10 files changed, 112 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 394c768..691a592 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,5 +3,6 @@ project(btcexplorer) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 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) \ No newline at end of file diff --git a/Models/Block.cpp b/Models/Block.cpp index 4561dd9..8860089 100644 --- a/Models/Block.cpp +++ b/Models/Block.cpp @@ -9,8 +9,8 @@ Block::Block(const std::byte* pBlock, size_t size): _header{} { 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(); + _transactions.emplace_back(std::move(transaction)); } } diff --git a/Models/Script.cpp b/Models/Script.cpp index 08d6f4c..6312341 100644 --- a/Models/Script.cpp +++ b/Models/Script.cpp @@ -1,5 +1,52 @@ -// -// Created by Selim Mustafaev on 05.05.2021. -// - #include "Script.h" + +#include +#include + +Script::Script(std::span data) { + for(auto iter = data.begin(); iter != data.end();) { + ScriptOperation operation; + uint8_t* ptr = data.data(); + size_t bytes = data.size_bytes(); + operation.opCode = OpCode(*iter++); + //std::cout << "found opcode: " << std::showbase << std::hex << std::setw(4) << (int)operation.opCode << std::dec << std::endl; + if(operation.opCode <= OpCode::OP_PUSHDATA4) { + size_t dataSize = 0; + if(operation.opCode < OpCode::OP_PUSHDATA1) { + dataSize = operation.opCode; + } else if(operation.opCode == OpCode::OP_PUSHDATA1) { + dataSize = *iter++; + } else if(operation.opCode == OpCode::OP_PUSHDATA2) { + dataSize = *((uint16_t*)&iter[0]); + iter += 2; + } else if(operation.opCode == OpCode::OP_PUSHDATA4) { + dataSize = *((uint32_t *) &iter[0]); + iter += 4; + } + operation.input = std::vector(iter, iter + dataSize); + iter += dataSize; + } + _operations.emplace_back(operation); + } + + _type = getType(); +} + +Script::Script() { + +} + +ScriptType Script::getType() { + if(_operations[0].opCode <= OpCode::OP_PUSHDATA4 && _operations[1].opCode == OpCode::OP_CHECKSIG) { + return ScriptType::P2PK; + } else if(_operations[0].opCode == OpCode::OP_DUP + && _operations[1].opCode == OpCode::OP_HASH160 + && _operations[2].opCode <= OpCode::OP_PUSHDATA4 + && _operations[3].opCode == OpCode::OP_EQUALVERIFY + && _operations[4].opCode == OpCode::OP_CHECKSIG) + { + return ScriptType::P2PKH; + } else { + throw std::runtime_error("Unsupported script type"); + } +} diff --git a/Models/Script.h b/Models/Script.h index 3e3d9c8..96e36b0 100644 --- a/Models/Script.h +++ b/Models/Script.h @@ -1,7 +1,12 @@ #ifndef BTCEXPLORER_SCRIPT_H #define BTCEXPLORER_SCRIPT_H -enum OpCode { +#include +#include +#include +#include + +enum OpCode: uint8_t { // push value OP_0 = 0x00, OP_FALSE = OP_0, @@ -142,8 +147,26 @@ enum OpCode { OP_INVALIDOPCODE = 0xff, }; -class Script { +enum ScriptType { + P2PK, P2PKH +}; +struct ScriptOperation { + OpCode opCode; + std::vector input; +}; + +class Script { +private: + std::vector _operations; + ScriptType _type; + +private: + ScriptType getType(); + +public: + Script(); + explicit Script(std::span data); }; #endif //BTCEXPLORER_SCRIPT_H diff --git a/Models/Transaction.cpp b/Models/Transaction.cpp index 470a464..8ae0015 100644 --- a/Models/Transaction.cpp +++ b/Models/Transaction.cpp @@ -9,7 +9,7 @@ Transaction::Transaction(const std::byte *data) { for(size_t i = 0; i < inputCount.value(); ++i) { TxInput input(curPtr); curPtr += input.size(); - _inputs.push_back(input); + _inputs.emplace_back(std::move(input)); } VarInt outputCount(curPtr); @@ -17,7 +17,7 @@ Transaction::Transaction(const std::byte *data) { for(size_t i = 0; i < outputCount.value(); ++i) { TxOutput output(curPtr); curPtr += output.size(); - _outputs.push_back(output); + _outputs.emplace_back(std::move(output)); } _lockTime = *((uint32_t*)curPtr); diff --git a/Models/TxInput.cpp b/Models/TxInput.cpp index 386fc63..671d5ef 100644 --- a/Models/TxInput.cpp +++ b/Models/TxInput.cpp @@ -1,6 +1,7 @@ #include "TxInput.h" #include "VarInt.h" #include +#include TxInput::TxInput(const std::byte *data) { std::copy_n(data, _txId.size(), _txId.begin()); @@ -8,10 +9,12 @@ TxInput::TxInput(const std::byte *data) { _vOut = *reinterpret_cast(data); data += sizeof(_vOut); VarInt scriptSigSize(data); - - // TODO: save ScriptSig - data += scriptSigSize.size(); + + //std::cout << "=== Creating signature script of size: " << scriptSigSize.value() << std::endl; + _signatureScript = std::make_unique