75 lines
2.7 KiB
C++
75 lines
2.7 KiB
C++
#include "Script.h"
|
|
#include "../hash.h"
|
|
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
|
|
Script::Script(std::span<uint8_t> data, bool coinbase): _operations(5) {
|
|
for(auto iter = data.begin(); iter != data.end();) {
|
|
ScriptOperation operation;
|
|
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 = coinbase ? ScriptType::Coinbase : type();
|
|
}
|
|
|
|
ScriptType Script::type() const {
|
|
if(_operations.size() < 2) {
|
|
return ScriptType::Unknown;
|
|
}
|
|
|
|
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 {
|
|
return ScriptType::Unknown;
|
|
//throw std::runtime_error("Unsupported script type");
|
|
}
|
|
}
|
|
|
|
std::string Script::address() {
|
|
auto pubKey = publicKey();
|
|
if(!pubKey.empty()) {
|
|
auto hash160 = hash::hash160(pubKey, 0); // TODO: this value should depend on BlockMagic
|
|
auto secondHash = hash::hash256(hash160);
|
|
std::array<uint8_t, RIPEMD160_DIGEST_LENGTH + 1 + 4> finalHash{};
|
|
std::copy(hash160.begin(), hash160.end(), finalHash.begin());
|
|
std::copy_n(secondHash.begin(), 4, finalHash.begin() + hash160.size());
|
|
return hash::base58(finalHash);
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
std::span<uint8_t> Script::publicKey() {
|
|
switch (_type) {
|
|
case P2PK: return _operations[0].input.value();
|
|
case P2PKH: return _operations[2].input.value();
|
|
default: return {};
|
|
}
|
|
}
|