Remove drivechain support using OP_COUNT_ACKS

This commit is contained in:
lateminer
2018-10-13 16:30:31 +03:00
parent b76793c9f9
commit c6238629b3
9 changed files with 8 additions and 617 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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() {}
};

View File

@@ -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,