Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
bestchain
parser
transaction
*.dat
*.d
*.o
*.dSYM
include/hexxer.hpp
include/ranger.hpp
include/serial.hpp
Expand Down
14 changes: 9 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ SOURCES=$(shell find src -name '*.c' -o -name '*.cpp')
OBJECTS=$(addsuffix .o, $(basename $(SOURCES)))
DEPENDENCIES=$(OBJECTS:.o=.d)
INCLUDES=include/hexxer.hpp include/ranger.hpp include/serial.hpp include/threadpool.hpp
PROGRAMS=bestchain parser transaction

# TARGETS
.PHONY: all clean includes

all: $(INCLUDES) bestchain parser
all: $(INCLUDES) bestchain parser transaction

clean:
$(RM) $(INCLUDES) $(DEPENDENCIES) $(OBJECTS) bestchain parser

bestchain: $(filter-out src/parser.o, $(OBJECTS))
$(CXX) $(filter-out src/parser.o, $(OBJECTS)) $(LFLAGS) $(OFLAGS) -o $@
bestchain: $(filter-out src/parser.o src/transaction.o, $(OBJECTS))
$(CXX) $(filter-out src/parser.o src/transaction.o, $(OBJECTS)) $(LFLAGS) $(OFLAGS) -o $@

parser: $(filter-out src/bestchain.o, $(OBJECTS))
$(CXX) $(filter-out src/bestchain.o, $(OBJECTS)) $(LFLAGS) $(OFLAGS) -pthread -o $@
parser: $(filter-out src/bestchain.o src/transaction.o, $(OBJECTS))
$(CXX) $(filter-out src/bestchain.o src/transaction.o, $(OBJECTS)) $(LFLAGS) $(OFLAGS) -pthread -o $@

transaction: $(filter-out src/bestchain.o src/parser.o, $(OBJECTS))
$(CXX) $(filter-out src/bestchain.o src/parser.o, $(OBJECTS)) $(LFLAGS) $(OFLAGS) -o $@

# INFERENCES
%.o: %.cpp
Expand Down
14 changes: 14 additions & 0 deletions include/bitcoin-ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ enum OP {
OP_NOP9 = 0xb8,
OP_NOP10 = 0xb9,

// magic operators
OP_NOWITNESS = 0xe0,
OP_P2WPKH = 0xe2,
OP_P2WSH = 0xe3,

OP_ERROR = 0xf0,

// template matching params
OP_SMALLINTEGER = 0xfa,
OP_PUBKEYS = 0xfb,
Expand Down Expand Up @@ -262,6 +269,13 @@ auto getOpString (const uint8_t opcode) {
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";

// magic operators
case OP_NOWITNESS : return "OP_NOWITNESS";
case OP_P2WPKH : return "OP_P2WPKH";
case OP_P2WSH : return "OP_P2WSH";

case OP_ERROR : return "OP_ERROR";

// expansion
case OP_NOP1 : return "OP_NOP1";
case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
Expand Down
69 changes: 68 additions & 1 deletion include/bitcoin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ struct TransactionBase {
R hash;
uint32_t vout;
R script;
std::vector<R> scriptStack;
uint32_t sequence;
uint8_t witnessFlag; // OP_NOWITNESS means not a witness program
};

struct Output {
Expand Down Expand Up @@ -111,11 +113,60 @@ namespace {
const auto vout = serial::read<uint32_t>(data);

const auto scriptLen = readVI(data);

__ranger::Range scriptRanger(data.begin(), data.begin() + scriptLen);

std::vector<R> scriptStack;

while(scriptRanger.size()) {

auto opcode = serial::read<uint8_t>(scriptRanger);

if(!opcode || opcode > OP_PUSHDATA4)
continue;

auto size = readPD(opcode, scriptRanger);

assert(size <= scriptRanger.size());

if(size > scriptRanger.size())
size = (uint32_t)scriptRanger.size();

scriptStack.push_back(readRange(scriptRanger, size));
}

const auto script = readRange(data, scriptLen);
const auto sequence = serial::read<uint32_t>(data);
isave.popBackN(data.size());

inputs.emplace_back(typename Transaction::Input{isave, hash, vout, script, sequence});
uint8_t witnessFlag = OP_NOWITNESS;

if(hasWitnesses) {

if(script.size() == 0) {

// In this case we must analyze witness data to determine the witness type.
// We'll check for OP_ERROR during witness data processing and set the type there.

witnessFlag = OP_ERROR;
}
else if(script.size() >= 3) {

// As per https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program

if(script[0] > 2 && script[0] < 40 && script[1] == 0) {

if(script[2] == 0x14)
witnessFlag |= OP_P2WPKH;
else if(script[2] == 0x20)
witnessFlag |= OP_P2WSH;
else
witnessFlag = OP_ERROR;
}
}
}

inputs.emplace_back(typename Transaction::Input{isave, hash, vout, script, scriptStack, sequence, witnessFlag});
}

const auto nOutputs = readVI(data);
Expand All @@ -139,6 +190,22 @@ namespace {
wsave.popBackN(data.size());

witnesses.emplace_back(typename Transaction::Witness{wsave, std::move(stack)});

if(inputs[i].witnessFlag == OP_ERROR && !inputs[i].script.size()) {

// As stated in https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program
//
// If the version byte is 0, and the witness program is 20 bytes:
// It is interpreted as a pay-to-witness-public-key-hash (P2WPKH) program.
// The witness must consist of exactly 2 items (≤ 520 bytes each). The first one a signature, and the second one a public key.

// We will check for exactly 2 items in witness stack to conform to above

if(witnesses.back().stack.size() == 2)
inputs[i].witnessFlag = OP_P2WPKH;
else if(witnesses.back().stack.size() > 2)
inputs[i].witnessFlag = OP_P2WSH;
}
}
}

Expand Down
Loading