Remove drivechain support using OP_COUNT_ACKS
This commit is contained in:
@@ -209,8 +209,6 @@ libbitcoin_server_a_SOURCES = \
|
||||
rpc/server.cpp \
|
||||
script/sigcache.cpp \
|
||||
script/ismine.cpp \
|
||||
script/drivechain.cpp \
|
||||
script/drivechain.h \
|
||||
timedata.cpp \
|
||||
torcontrol.cpp \
|
||||
txdb.cpp \
|
||||
|
||||
115
src/main.cpp
115
src/main.cpp
@@ -26,7 +26,6 @@
|
||||
#include "primitives/block.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "random.h"
|
||||
#include "script/drivechain.h"
|
||||
#include "script/script.h"
|
||||
#include "script/sigcache.h"
|
||||
#include "script/standard.h"
|
||||
@@ -1898,113 +1897,6 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
||||
UpdateCoins(tx, state, inputs, txundo, nHeight);
|
||||
}
|
||||
|
||||
class CachingTransactionSignatureCheckerWithBlockReader : public CachingTransactionSignatureChecker, public BaseBlockReader
|
||||
{
|
||||
typedef std::pair<uint256, CTransaction> CoinbaseCacheItem;
|
||||
typedef boost::multi_index_container<
|
||||
CoinbaseCacheItem,
|
||||
boost::multi_index::indexed_by<
|
||||
boost::multi_index::sequenced<>,
|
||||
boost::multi_index::ordered_unique<
|
||||
boost::multi_index::member<CoinbaseCacheItem, uint256, &CoinbaseCacheItem::first>
|
||||
>
|
||||
>
|
||||
> CoinbaseCacheContainer;
|
||||
|
||||
int nHeight;
|
||||
uint256 hash;
|
||||
|
||||
mutable boost::mutex mutexCache;
|
||||
mutable CoinbaseCacheContainer cacheCoinbase; // block hash -> block coinbase
|
||||
|
||||
void UpdateCache(const CoinbaseCacheItem& coinbase) const;
|
||||
|
||||
CTransaction ReadBlockCoinbase(CBlockIndex* pblockindex) const;
|
||||
|
||||
public:
|
||||
const unsigned int MAX_COUNT_ACKS_CACHE = 1000;
|
||||
|
||||
public:
|
||||
virtual int GetBlockNumber() const;
|
||||
|
||||
virtual CTransaction GetBlockCoinbase(int blockNumber) const;
|
||||
|
||||
virtual bool CountAcks(const std::vector<unsigned char>& chainId, int periodAck, int periodLiveness, int& positive, int& negative) const;
|
||||
|
||||
CachingTransactionSignatureCheckerWithBlockReader(const CTransaction* txToIn, unsigned int nInIn, bool storeIn, int height);
|
||||
};
|
||||
|
||||
CachingTransactionSignatureCheckerWithBlockReader::CachingTransactionSignatureCheckerWithBlockReader(const CTransaction* txToIn, unsigned int nInIn, bool storeIn, int height)
|
||||
: CachingTransactionSignatureChecker(txToIn, nInIn, storeIn), nHeight(height), hash(txToIn->GetHash())
|
||||
{
|
||||
}
|
||||
|
||||
int CachingTransactionSignatureCheckerWithBlockReader::GetBlockNumber() const
|
||||
{
|
||||
return nHeight;
|
||||
}
|
||||
|
||||
CTransaction CachingTransactionSignatureCheckerWithBlockReader::GetBlockCoinbase(int blockNumber) const
|
||||
{
|
||||
//AssertLockHeld(cs_main);
|
||||
|
||||
int nHeight = blockNumber;
|
||||
if (nHeight < 0 || nHeight > chainActive.Height())
|
||||
return CTransaction();
|
||||
|
||||
CBlockIndex* pblockindex = chainActive[nHeight];
|
||||
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(mutexCache);
|
||||
CoinbaseCacheContainer::nth_index<1>::type::iterator it = cacheCoinbase.get<1>().find(*pblockindex->phashBlock);
|
||||
if (it != cacheCoinbase.get<1>().end())
|
||||
return it->second;
|
||||
}
|
||||
|
||||
CTransaction coinbase = ReadBlockCoinbase(pblockindex);
|
||||
if (!coinbase.IsNull())
|
||||
UpdateCache(std::make_pair(*pblockindex->phashBlock, coinbase));
|
||||
|
||||
return coinbase;
|
||||
}
|
||||
|
||||
CTransaction CachingTransactionSignatureCheckerWithBlockReader::ReadBlockCoinbase(CBlockIndex* pblockindex) const
|
||||
{
|
||||
|
||||
CBlock block;
|
||||
|
||||
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
|
||||
return CTransaction();
|
||||
|
||||
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
|
||||
return CTransaction();
|
||||
|
||||
if (block.vtx.empty())
|
||||
return CTransaction();
|
||||
|
||||
if (!block.vtx[0].IsCoinBase())
|
||||
return CTransaction();
|
||||
|
||||
return block.vtx[0];
|
||||
}
|
||||
|
||||
void CachingTransactionSignatureCheckerWithBlockReader::UpdateCache(const CachingTransactionSignatureCheckerWithBlockReader::CoinbaseCacheItem& coinbase) const
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(mutexCache);
|
||||
std::pair<CoinbaseCacheContainer::iterator, bool> result = cacheCoinbase.push_front(coinbase);
|
||||
if (!result.second) {
|
||||
cacheCoinbase.relocate(cacheCoinbase.begin(), result.first);
|
||||
} else if (cacheCoinbase.size() > MAX_COUNT_ACKS_CACHE) {
|
||||
cacheCoinbase.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool CachingTransactionSignatureCheckerWithBlockReader::CountAcks(const std::vector<unsigned char>& chainId, int periodAck, int periodLiveness, int& positiveAcks, int& negativeAcks) const
|
||||
{
|
||||
std::vector<unsigned char> hashSpend(hash.begin(), hash.end());
|
||||
return ::CountAcks(hashSpend, chainId, periodAck, periodLiveness, positiveAcks, negativeAcks, *this);
|
||||
}
|
||||
|
||||
bool CScriptCheck::operator()() {
|
||||
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
||||
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &error)) {
|
||||
@@ -2082,8 +1974,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
||||
{
|
||||
if (!tx.IsCoinBase())
|
||||
{
|
||||
int height = GetSpendHeight(inputs);
|
||||
if (!Consensus::CheckTxInputs(tx, state, inputs, height))
|
||||
if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs)))
|
||||
return false;
|
||||
|
||||
if (pvChecks)
|
||||
@@ -2103,7 +1994,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
||||
assert(coins);
|
||||
|
||||
// Verify signature
|
||||
CScriptCheck check(*coins, tx, i, flags, cacheStore, height);
|
||||
CScriptCheck check(*coins, tx, i, flags, cacheStore);
|
||||
if (pvChecks) {
|
||||
pvChecks->push_back(CScriptCheck());
|
||||
check.swap(pvChecks->back());
|
||||
@@ -2116,7 +2007,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
||||
// avoid splitting the network between upgraded and
|
||||
// non-upgraded nodes.
|
||||
CScriptCheck check2(*coins, tx, i,
|
||||
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, height);
|
||||
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
|
||||
if (check2())
|
||||
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
||||
}
|
||||
|
||||
@@ -420,13 +420,12 @@ private:
|
||||
unsigned int nFlags;
|
||||
bool cacheStore;
|
||||
ScriptError error;
|
||||
int nHeight;
|
||||
|
||||
public:
|
||||
CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR), nHeight(-1) {}
|
||||
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, int height) :
|
||||
CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
|
||||
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
|
||||
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
|
||||
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), nHeight(height) { }
|
||||
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { }
|
||||
|
||||
bool operator()();
|
||||
|
||||
@@ -437,7 +436,6 @@ public:
|
||||
std::swap(nFlags, check.nFlags);
|
||||
std::swap(cacheStore, check.cacheStore);
|
||||
std::swap(error, check.error);
|
||||
std::swap(nHeight, check.nHeight);
|
||||
}
|
||||
|
||||
ScriptError GetScriptError() const { return error; }
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -373,7 +373,6 @@ I ReadVarInt(Stream& is)
|
||||
|
||||
#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
|
||||
#define VARINT(obj) REF(WrapVarInt(REF(obj)))
|
||||
#define COMPACTSIZE(obj) REF(CCompactSize(REF(obj)))
|
||||
#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj)))
|
||||
|
||||
/**
|
||||
@@ -444,28 +443,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CCompactSize
|
||||
{
|
||||
protected:
|
||||
uint64_t &n;
|
||||
public:
|
||||
CCompactSize(uint64_t& nIn) : n(nIn) { }
|
||||
|
||||
unsigned int GetSerializeSize(int, int) const {
|
||||
return GetSizeOfCompactSize(n);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s, int, int) const {
|
||||
WriteCompactSize<Stream>(s, n);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, int, int) {
|
||||
n = ReadCompactSize<Stream>(s);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t Limit>
|
||||
class LimitedString
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user