Remove drivechain support using OP_COUNT_ACKS
This commit is contained in:
@@ -1,142 +0,0 @@
|
||||
// Copyright (c) 2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "drivechain.h"
|
||||
|
||||
#include "crypto/sha256.h"
|
||||
#include "script/interpreter.h"
|
||||
#include "streams.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
std::pair<CScript::const_iterator, CScript::const_iterator> FindAckLabel(const CTransaction& coinbase)
|
||||
{
|
||||
for (const CTxOut& txout : coinbase.vout) {
|
||||
const CScript& scriptPubKey = txout.scriptPubKey;
|
||||
auto result = std::search(scriptPubKey.begin(), scriptPubKey.end(), ACK_LABEL, ACK_LABEL + ACK_LABEL_LENGTH);
|
||||
if (result != scriptPubKey.end()) {
|
||||
// Skip ACK label, we know result + ACK_LABEL_LENGTH <= scriptPubKey.end()
|
||||
return std::make_pair(result + ACK_LABEL_LENGTH, scriptPubKey.end());
|
||||
}
|
||||
}
|
||||
return std::make_pair(CScript::const_iterator(nullptr), CScript::const_iterator(nullptr));
|
||||
}
|
||||
|
||||
FullAckList ParseFullAckList(const std::vector<unsigned char>& data)
|
||||
{
|
||||
try {
|
||||
FullAckList fullAckList;
|
||||
CDataStream ss(data, SER_DISK, 0);
|
||||
ss >> fullAckList;
|
||||
return fullAckList;
|
||||
} catch (...) {
|
||||
}
|
||||
return FullAckList();
|
||||
}
|
||||
|
||||
struct ChainVote {
|
||||
std::vector<unsigned char> hash;
|
||||
uint32_t positiveAcks;
|
||||
uint32_t negativeAcks;
|
||||
};
|
||||
|
||||
std::vector<ChainVote>::const_iterator FindPrefix(const std::vector<ChainVote>& votes, const std::vector<unsigned char>& prefix)
|
||||
{
|
||||
assert(prefix.size() > 0);
|
||||
for (std::vector<ChainVote>::const_iterator itVote = votes.begin(); itVote != votes.end(); ++itVote) {
|
||||
if (memcmp(begin_ptr(itVote->hash), begin_ptr(prefix), prefix.size()) == 0) {
|
||||
return itVote;
|
||||
}
|
||||
}
|
||||
return votes.end();
|
||||
}
|
||||
|
||||
bool CountAcks(const std::vector<unsigned char> hashSpend, const std::vector<unsigned char>& chainId, int periodAck, int periodLiveness, int& positiveAcks, int& negativeAcks, const BaseBlockReader& blockReader)
|
||||
{
|
||||
int blockNumber = blockReader.GetBlockNumber();
|
||||
// Check valid block range
|
||||
if (blockNumber - periodLiveness - periodAck < 0)
|
||||
return false;
|
||||
std::vector<ChainVote> A;
|
||||
int poll_start = blockNumber - periodLiveness - periodAck;
|
||||
for (int i = poll_start; i < poll_start + periodAck; ++i) {
|
||||
CTransaction coinbase = blockReader.GetBlockCoinbase(i);
|
||||
auto result = FindAckLabel(coinbase);
|
||||
if (result.first == result.second)
|
||||
continue;
|
||||
// Parse votes
|
||||
FullAckList fullAckList = ParseFullAckList(std::vector<unsigned char>(result.first, result.second));
|
||||
for (const ChainAckList& chainAcks : fullAckList.vChainAcks) {
|
||||
// Ensure correct ChainId
|
||||
if (chainAcks.chainId != chainId)
|
||||
continue;
|
||||
std::set<uint32_t> new_acks; // votes found
|
||||
for (const Ack& ack : chainAcks.ackList.vAck) {
|
||||
std::vector<unsigned char> tx_hash = ack.prefix;
|
||||
std::vector<unsigned char> tx_hash_preimage = ack.preimage;
|
||||
// Check vote validity
|
||||
bool valid = ((tx_hash.size() <= 32) && (tx_hash_preimage.size() == 0)) ||
|
||||
((tx_hash.size() == 0) && (tx_hash_preimage.size() == 32));
|
||||
if ((tx_hash.size() == 32) && (tx_hash_preimage.size() == 32)) {
|
||||
std::vector<unsigned char> hash(32);
|
||||
// Check hash correspond to given preimage
|
||||
CSHA256().Write(begin_ptr(tx_hash_preimage), tx_hash_preimage.size()).Finalize(begin_ptr(hash));
|
||||
valid = memcmp(begin_ptr(hash), begin_ptr(tx_hash), 32) == 0;
|
||||
}
|
||||
if (!valid)
|
||||
continue;
|
||||
// New proposal with empty hash
|
||||
if ((tx_hash.size() == 0) && (tx_hash_preimage.size() == 32)) {
|
||||
tx_hash.resize(32);
|
||||
CSHA256().Write(&tx_hash_preimage[0], tx_hash_preimage.size()).Finalize(begin_ptr(tx_hash));
|
||||
}
|
||||
// Empty hash here is a negative vote
|
||||
if (tx_hash.size() != 0) {
|
||||
// Check existing prefix
|
||||
auto it = FindPrefix(A, tx_hash);
|
||||
// If it is not a prefix of a hash in A
|
||||
if (it == A.end()) {
|
||||
// It is a new proposal add to A
|
||||
if (tx_hash_preimage.size() == 32) {
|
||||
A.push_back(ChainVote{tx_hash, uint32_t(0), uint32_t(0)});
|
||||
new_acks.insert(A.size() - 1);
|
||||
} else {
|
||||
if (memcmp(begin_ptr(hashSpend), begin_ptr(tx_hash), tx_hash.size()) != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Existing proposal record to ack later
|
||||
uint32_t index = it - A.begin();
|
||||
new_acks.insert(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Account for votes found
|
||||
for (uint32_t k = 0; k < A.size(); ++k) {
|
||||
if (new_acks.count(k) == 1) {
|
||||
A[k].positiveAcks++;
|
||||
} else /* if (allowed_negative_acks) */ {
|
||||
A[k].negativeAcks++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Search if hashSpend is among the proposals
|
||||
auto it = FindPrefix(A, hashSpend);
|
||||
if (it != A.end()) {
|
||||
positiveAcks = it->positiveAcks;
|
||||
negativeAcks = it->negativeAcks;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
// Copyright (c) 2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SCRIPT_DRIVECHAIN_H
|
||||
#define BITCOIN_SCRIPT_DRIVECHAIN_H
|
||||
|
||||
#include "serialize.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#define LIMITED_VECTOR(obj, n) REF(MakeLimitedVector<n>(obj))
|
||||
|
||||
const unsigned char ACK_LABEL[] = {0x41, 0x43, 0x4B, 0x3A}; // "ACK:"
|
||||
const size_t ACK_LABEL_LENGTH = sizeof(ACK_LABEL);
|
||||
|
||||
template <size_t Limit, typename U>
|
||||
class LimitedVector
|
||||
{
|
||||
protected:
|
||||
std::vector<U>& vec;
|
||||
|
||||
public:
|
||||
LimitedVector(std::vector<U>& vec) : vec(vec) {}
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s, int, int = 0)
|
||||
{
|
||||
size_t size = ReadCompactSize(s);
|
||||
if (size > Limit) {
|
||||
throw std::ios_base::failure("String length limit exceeded");
|
||||
}
|
||||
vec.resize(size);
|
||||
if (size != 0)
|
||||
s.read((char*)&vec[0], size);
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void Serialize(Stream& s, int, int = 0) const
|
||||
{
|
||||
WriteCompactSize(s, vec.size());
|
||||
if (!vec.empty())
|
||||
s.write((char*)&vec[0], vec.size());
|
||||
}
|
||||
|
||||
unsigned int GetSerializeSize(int, int = 0) const
|
||||
{
|
||||
return GetSizeOfCompactSize(vec.size()) + vec.size();
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N, typename U>
|
||||
LimitedVector<N, U> MakeLimitedVector(std::vector<U>& obj)
|
||||
{
|
||||
return LimitedVector<N, U>(obj);
|
||||
}
|
||||
|
||||
class Ack
|
||||
{
|
||||
public:
|
||||
std::vector<unsigned char> prefix;
|
||||
std::vector<unsigned char> preimage;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
uint64_t nPayload = 0;
|
||||
if (!ser_action.ForRead())
|
||||
nPayload = CalcPayloadSize(nType, nVersion);
|
||||
READWRITE(COMPACTSIZE(nPayload));
|
||||
if (nPayload == 0)
|
||||
throw std::runtime_error("Not valid ACK");
|
||||
READWRITE(LIMITED_VECTOR(prefix, 32));
|
||||
// Empty preimage should not be serialized
|
||||
if (ser_action.ForRead()) {
|
||||
uint64_t nPrefix = prefix.size();
|
||||
nPrefix += GetSizeOfCompactSize(nPrefix);
|
||||
if (nPayload > nPrefix)
|
||||
READWRITE(LIMITED_VECTOR(preimage, 32));
|
||||
if (CalcPayloadSize(nType, nVersion) != nPayload)
|
||||
throw std::runtime_error("Not valid ACK");
|
||||
} else {
|
||||
if (preimage.size() > 0)
|
||||
READWRITE(LIMITED_VECTOR(preimage, 32));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CalcPayloadSize(int nType, int nVersion) const
|
||||
{
|
||||
unsigned int nPayload = 0;
|
||||
nPayload += GetSizeOfCompactSize(prefix.size());
|
||||
nPayload += prefix.size();
|
||||
// Empty preimage should not be serialized
|
||||
if (!preimage.empty()) {
|
||||
nPayload += GetSizeOfCompactSize(preimage.size());
|
||||
nPayload += preimage.size();
|
||||
}
|
||||
return nPayload;
|
||||
}
|
||||
|
||||
Ack() {}
|
||||
Ack(std::vector<unsigned char> prefix, std::vector<unsigned char> preimage = std::vector<unsigned char>())
|
||||
: prefix(prefix), preimage(preimage)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class AckList
|
||||
{
|
||||
public:
|
||||
std::vector<Ack> vAck;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
uint64_t sizePayload = 0;
|
||||
if (!ser_action.ForRead())
|
||||
sizePayload = CalcPayloadSize(nType, nVersion);
|
||||
READWRITE(COMPACTSIZE(sizePayload));
|
||||
if (ser_action.ForRead()) {
|
||||
unsigned int read = 0;
|
||||
while (read < sizePayload) {
|
||||
Ack ack;
|
||||
READWRITE(ack);
|
||||
read += ack.GetSerializeSize(nType, nVersion);
|
||||
vAck.push_back(ack);
|
||||
}
|
||||
if (read != sizePayload)
|
||||
throw std::runtime_error("Not valid ACK LIST");
|
||||
} else {
|
||||
for (Ack& ack : vAck) {
|
||||
READWRITE(ack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CalcPayloadSize(int nType, int nVersion) const
|
||||
{
|
||||
unsigned int nPayload = 0;
|
||||
for (const Ack& ack : vAck) {
|
||||
nPayload += ack.GetSerializeSize(nType, nVersion);
|
||||
}
|
||||
return nPayload;
|
||||
}
|
||||
|
||||
AckList() {}
|
||||
AckList(std::vector<Ack> acks) : vAck(acks) {}
|
||||
};
|
||||
|
||||
class ChainAckList
|
||||
{
|
||||
public:
|
||||
std::vector<unsigned char> chainId;
|
||||
AckList ackList;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
uint64_t nPayload = 0;
|
||||
if (!ser_action.ForRead())
|
||||
nPayload = CalcPayloadSize(nType, nVersion);
|
||||
READWRITE(COMPACTSIZE(nPayload));
|
||||
READWRITE(LIMITED_VECTOR(chainId, 20));
|
||||
READWRITE(ackList);
|
||||
if (ser_action.ForRead() && nPayload != CalcPayloadSize(nType, nVersion))
|
||||
throw std::runtime_error("Not valid CHAIN ACK LIST");
|
||||
}
|
||||
|
||||
unsigned int CalcPayloadSize(int nType, int nVersion) const
|
||||
{
|
||||
unsigned int nPayload = 0;
|
||||
nPayload += GetSizeOfCompactSize(chainId.size());
|
||||
nPayload += chainId.size();
|
||||
nPayload += ackList.GetSerializeSize(nType, nVersion);
|
||||
return nPayload;
|
||||
}
|
||||
|
||||
ChainAckList& operator<<(Ack ack)
|
||||
{
|
||||
ackList.vAck.push_back(ack);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChainAckList() {}
|
||||
ChainAckList(std::vector<unsigned char> chainId) : chainId(chainId) {}
|
||||
};
|
||||
|
||||
class FullAckList
|
||||
{
|
||||
public:
|
||||
std::vector<ChainAckList> vChainAcks;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
uint64_t sizePayload = 0;
|
||||
if (!ser_action.ForRead())
|
||||
sizePayload = CalcPayloadSize(nType, nVersion);
|
||||
READWRITE(COMPACTSIZE(sizePayload));
|
||||
if (ser_action.ForRead()) {
|
||||
uint64_t read = 0;
|
||||
while (read < sizePayload) {
|
||||
ChainAckList chainAcks;
|
||||
READWRITE(chainAcks);
|
||||
read += chainAcks.GetSerializeSize(nType, nVersion);
|
||||
vChainAcks.push_back(chainAcks);
|
||||
}
|
||||
if (read != sizePayload)
|
||||
throw std::runtime_error("Not valid FULL ACK LIST");
|
||||
} else {
|
||||
for (auto& chainAcks : vChainAcks) {
|
||||
READWRITE(chainAcks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CalcPayloadSize(int nType, int nVersion) const
|
||||
{
|
||||
unsigned int nPayloadSize = 0;
|
||||
for (const auto& chainAcks : vChainAcks) {
|
||||
nPayloadSize += chainAcks.GetSerializeSize(nType, nVersion);
|
||||
}
|
||||
return nPayloadSize;
|
||||
}
|
||||
|
||||
FullAckList& operator<<(Ack ack)
|
||||
{
|
||||
if (!vChainAcks.empty()) {
|
||||
vChainAcks.rbegin()[0].ackList.vAck.push_back(ack);
|
||||
} else {
|
||||
throw std::runtime_error("Empty Chain");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
FullAckList& operator<<(ChainAckList chainAckList)
|
||||
{
|
||||
vChainAcks.push_back(chainAckList);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FullAckList() {}
|
||||
};
|
||||
|
||||
class BaseBlockReader
|
||||
{
|
||||
public:
|
||||
virtual int GetBlockNumber() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual CTransaction GetBlockCoinbase(int blockNumber) const
|
||||
{
|
||||
return CTransaction();
|
||||
}
|
||||
};
|
||||
|
||||
bool CountAcks(const std::vector<unsigned char> hashSpend, const std::vector<unsigned char>& chainId, int periodAck, int periodLiveness, int& positiveAcks, int& negativeAcks, const BaseBlockReader& blockReader);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_DRIVECHAIN_H
|
||||
@@ -426,48 +426,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_COUNT_ACKS:
|
||||
{
|
||||
if (SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
||||
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
|
||||
}
|
||||
|
||||
|
||||
if (SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
||||
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
|
||||
}
|
||||
|
||||
// (secondary_chain_id ack_period liveness_period -- )
|
||||
if (stack.size() < 3)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype& secondaryChainId = stacktop(-3);
|
||||
if (secondaryChainId.size() < 1 || secondaryChainId.size() > MAX_CHAIN_ID_LENGTH)
|
||||
return set_error(serror, SCRIPT_ERR_COUNT_ACKS_INVALID_PARAM);
|
||||
|
||||
CScriptNum periodAck(stacktop(-2), fRequireMinimal);
|
||||
if (periodAck < 1 || periodAck > MAX_ACK_PERIOD)
|
||||
return set_error(serror, SCRIPT_ERR_COUNT_ACKS_INVALID_PARAM);
|
||||
|
||||
CScriptNum periodLiveness(stacktop(-1), fRequireMinimal);
|
||||
if (periodLiveness < MIN_LIVENESS_PERIOD || periodLiveness > MAX_LIVENESS_PERIOD)
|
||||
return set_error(serror, SCRIPT_ERR_COUNT_ACKS_INVALID_PARAM);
|
||||
|
||||
int positiveAcks, negativeAcks;
|
||||
if (checker.CountAcks(secondaryChainId, periodAck.getint(), periodLiveness.getint(), positiveAcks, negativeAcks)) {
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
stack.push_back(CScriptNum(positiveAcks).getvch());
|
||||
stack.push_back(CScriptNum(negativeAcks).getvch());
|
||||
} else {
|
||||
return set_error(serror, SCRIPT_ERR_COUNT_ACKS_INVALID_PARAM);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_NOP1: case OP_NOP5:
|
||||
case OP_NOP1: case OP_NOP4: case OP_NOP5:
|
||||
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
|
||||
{
|
||||
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
|
||||
@@ -122,11 +122,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool CountAcks(const std::vector<unsigned char>& chainId, int periodAck, int periodLiveness, int& positiveAcks, int& negativeAcks) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual ~BaseSignatureChecker() {}
|
||||
};
|
||||
|
||||
|
||||
@@ -34,18 +34,6 @@ static const int MAX_SCRIPT_SIZE = 10000;
|
||||
// otherwise as UNIX timestamp.
|
||||
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
|
||||
|
||||
// Maximum chain id length
|
||||
static const int MAX_CHAIN_ID_LENGTH = 20;
|
||||
|
||||
// Maximum chain ack period (in blocks)
|
||||
static const int MAX_ACK_PERIOD = 144;
|
||||
|
||||
// Minimum chain ack liveness period
|
||||
static const int MIN_LIVENESS_PERIOD = 100;
|
||||
|
||||
// Maximum chain ack liveness period
|
||||
static const int MAX_LIVENESS_PERIOD = 144;
|
||||
|
||||
template <typename T>
|
||||
std::vector<unsigned char> ToByteVector(const T& in)
|
||||
{
|
||||
@@ -181,8 +169,7 @@ enum opcodetype
|
||||
OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,
|
||||
OP_NOP3 = 0xb2,
|
||||
OP_CHECKSEQUENCEVERIFY = OP_NOP3,
|
||||
OP_COUNT_ACKS = 0xb3,
|
||||
OP_NOP4 = OP_COUNT_ACKS,
|
||||
OP_NOP4 = 0xb3,
|
||||
OP_NOP5 = 0xb4,
|
||||
OP_NOP6 = 0xb5,
|
||||
OP_NOP7 = 0xb6,
|
||||
|
||||
Reference in New Issue
Block a user