From b905e2a53a280d44bd75c1a3b0f7005549267f82 Mon Sep 17 00:00:00 2001 From: timemarkovqtum Date: Thu, 1 Feb 2024 13:44:42 +0100 Subject: [PATCH] Port primitives --- src/primitives/block.cpp | 118 +++++++++++++++++++++++++++++- src/primitives/block.h | 72 +++++++++++++++++- src/primitives/transaction.cpp | 75 +++++++++++++++++++ src/primitives/transaction.h | 54 +++++++++++++- src/script/descriptor.cpp | 1 + src/script/script.cpp | 130 +++++++++++++++++++++++++++++++++ src/script/script.h | 122 ++++++++++++++++++++++++++++++- 7 files changed, 565 insertions(+), 7 deletions(-) diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 3d21708820..a700e71a15 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -7,24 +7,140 @@ #include #include +#include +#include +#include +#include + +// Used to serialize the header without signature +// Workaround due to removing serialization templates in Bitcoin Core 0.18 +class CBlockHeaderSign +{ +public: + CBlockHeaderSign(const CBlockHeader& header) + { + fHasProofOfDelegation = header.HasProofOfDelegation(); + nVersion = header.nVersion; + hashPrevBlock = header.hashPrevBlock; + hashMerkleRoot = header.hashMerkleRoot; + nTime = header.nTime; + nBits = header.nBits; + nNonce = header.nNonce; + hashStateRoot = header.hashStateRoot; + hashUTXORoot = header.hashUTXORoot; + prevoutStake = header.prevoutStake; + vchBlockDlgt = header.GetProofOfDelegation(); + } + + SERIALIZE_METHODS(CBlockHeaderSign, obj) { + READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce, obj.hashStateRoot, obj.hashUTXORoot, obj.prevoutStake); + if(obj.fHasProofOfDelegation) + { + READWRITE(obj.vchBlockDlgt); + } + } + +private: + bool fHasProofOfDelegation; + + // header without signature + int32_t nVersion; + uint256 hashPrevBlock; + uint256 hashMerkleRoot; + uint32_t nTime; + uint32_t nBits; + uint32_t nNonce; + uint256 hashStateRoot; + uint256 hashUTXORoot; + COutPoint prevoutStake; + std::vector vchBlockDlgt; +}; uint256 CBlockHeader::GetHash() const { return (CHashWriter{PROTOCOL_VERSION} << *this).GetHash(); } +uint256 CBlockHeader::GetHashWithoutSign() const +{ + return (CHashWriter{PROTOCOL_VERSION} << CBlockHeaderSign(*this)).GetHash(); +} + +std::string CBlockHeader::GetWithoutSign() const +{ + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << CBlockHeaderSign(*this); + return EncodeBase64(ss.str()); +} + std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n", + s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, hashStateRoot=%s, hashUTXORoot=%s, blockSig=%s, proof=%s, prevoutStake=%s, vtx=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashMerkleRoot.ToString(), nTime, nBits, nNonce, + hashStateRoot.ToString(), // qtum + hashUTXORoot.ToString(), // qtum + HexStr(vchBlockSigDlgt), + IsProofOfStake() ? "PoS" : "PoW", + prevoutStake.ToString(), vtx.size()); for (const auto& tx : vtx) { s << " " << tx->ToString() << "\n"; } return s.str(); } + +std::vector CBlockHeader::GetBlockSignature() const +{ + if(vchBlockSigDlgt.size() < 2 * CPubKey::COMPACT_SIGNATURE_SIZE) + { + return vchBlockSigDlgt; + } + + return std::vector(vchBlockSigDlgt.begin(), vchBlockSigDlgt.end() - CPubKey::COMPACT_SIGNATURE_SIZE ); +} + +std::vector CBlockHeader::GetProofOfDelegation() const +{ + if(vchBlockSigDlgt.size() < 2 * CPubKey::COMPACT_SIGNATURE_SIZE) + { + return std::vector(); + } + + return std::vector(vchBlockSigDlgt.begin() + vchBlockSigDlgt.size() - CPubKey::COMPACT_SIGNATURE_SIZE, vchBlockSigDlgt.end()); + +} + +bool CBlockHeader::HasProofOfDelegation() const +{ + return vchBlockSigDlgt.size() >= 2 * CPubKey::COMPACT_SIGNATURE_SIZE; +} + +void CBlockHeader::SetBlockSignature(const std::vector &vchSign) +{ + if(HasProofOfDelegation()) + { + std::vector vchPoD = GetProofOfDelegation(); + vchBlockSigDlgt = vchSign; + vchBlockSigDlgt.insert(vchBlockSigDlgt.end(), vchPoD.begin(), vchPoD.end()); + } + else + { + vchBlockSigDlgt = vchSign; + } +} + +void CBlockHeader::SetProofOfDelegation(const std::vector &vchPoD) +{ + std::vector vchSign = GetBlockSignature(); + if(vchSign.size() != CPubKey::COMPACT_SIGNATURE_SIZE) + { + vchSign.resize(CPubKey::COMPACT_SIGNATURE_SIZE, 0); + } + vchBlockSigDlgt = vchSign; + vchBlockSigDlgt.insert(vchBlockSigDlgt.end(), vchPoD.begin(), vchPoD.end()); +} diff --git a/src/primitives/block.h b/src/primitives/block.h index 99accfc7dd..b294417248 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -28,13 +28,19 @@ class CBlockHeader uint32_t nTime; uint32_t nBits; uint32_t nNonce; + uint256 hashStateRoot; // qtum + uint256 hashUTXORoot; // qtum + // proof-of-stake specific fields + COutPoint prevoutStake; + std::vector vchBlockSigDlgt; // The delegate is 65 bytes or 0 bytes, it can be added in the signature paramether at the end to avoid compatibility problems CBlockHeader() { SetNull(); } + virtual ~CBlockHeader(){}; - SERIALIZE_METHODS(CBlockHeader, obj) { READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce); } + SERIALIZE_METHODS(CBlockHeader, obj) { READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce, obj.hashStateRoot, obj.hashUTXORoot, obj.prevoutStake, obj.vchBlockSigDlgt); } void SetNull() { @@ -44,6 +50,10 @@ class CBlockHeader nTime = 0; nBits = 0; nNonce = 0; + hashStateRoot.SetNull(); // qtum + hashUTXORoot.SetNull(); // qtum + vchBlockSigDlgt.clear(); + prevoutStake.SetNull(); } bool IsNull() const @@ -53,6 +63,10 @@ class CBlockHeader uint256 GetHash() const; + uint256 GetHashWithoutSign() const; + + std::string GetWithoutSign() const; + NodeSeconds Time() const { return NodeSeconds{std::chrono::seconds{nTime}}; @@ -62,6 +76,53 @@ class CBlockHeader { return (int64_t)nTime; } + + // ppcoin: two types of block: proof-of-work or proof-of-stake + virtual bool IsProofOfStake() const //qtum + { + return !prevoutStake.IsNull(); + } + + virtual bool IsProofOfWork() const + { + return !IsProofOfStake(); + } + + virtual uint32_t StakeTime() const + { + uint32_t ret = 0; + if(IsProofOfStake()) + { + ret = nTime; + } + return ret; + } + + void SetBlockSignature(const std::vector& vchSign); + std::vector GetBlockSignature() const; + + void SetProofOfDelegation(const std::vector& vchPoD); + std::vector GetProofOfDelegation() const; + + bool HasProofOfDelegation() const; + + CBlockHeader& operator=(const CBlockHeader& other) //qtum + { + if (this != &other) + { + this->nVersion = other.nVersion; + this->hashPrevBlock = other.hashPrevBlock; + this->hashMerkleRoot = other.hashMerkleRoot; + this->nTime = other.nTime; + this->nBits = other.nBits; + this->nNonce = other.nNonce; + this->hashStateRoot = other.hashStateRoot; + this->hashUTXORoot = other.hashUTXORoot; + this->vchBlockSigDlgt = other.vchBlockSigDlgt; + this->prevoutStake = other.prevoutStake; + } + return *this; + } }; @@ -97,6 +158,11 @@ class CBlock : public CBlockHeader fChecked = false; } + std::pair GetProofOfStake() const //qtum + { + return IsProofOfStake()? std::make_pair(prevoutStake, nTime) : std::make_pair(COutPoint(), (unsigned int)0); + } + CBlockHeader GetBlockHeader() const { CBlockHeader block; @@ -106,6 +172,10 @@ class CBlock : public CBlockHeader block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; + block.hashStateRoot = hashStateRoot; // qtum + block.hashUTXORoot = hashUTXORoot; // qtum + block.vchBlockSigDlgt = vchBlockSigDlgt; + block.prevoutStake = prevoutStake; return block; } diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 2c913bf432..b869a97ec9 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -83,6 +83,7 @@ uint256 CTransaction::ComputeWitnessHash() const return (CHashWriter{0} << *this).GetHash(); } +CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash{}, m_witness_hash{} {} CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} @@ -120,3 +121,77 @@ std::string CTransaction::ToString() const str += " " + tx_out.ToString() + "\n"; return str; } + +///////////////////////////////////////////////////////////// qtum +bool CTransaction::HasCreateOrCall() const{ + for(const CTxOut& v : vout){ + if(v.scriptPubKey.HasOpCreate() || v.scriptPubKey.HasOpCall()){ + return true; + } + } + return false; +} + + + +bool CTransaction::HasOpSpend() const{ + for(const CTxIn& i : vin){ + if(i.scriptSig.HasOpSpend()){ + return true; + } + } + return false; +} +///////////////////////////////////////////////////////////// + +bool CTransaction::HasOpCreate() const +{ + for(const CTxOut& v : vout){ + if(v.scriptPubKey.HasOpCreate()){ + return true; + } + } + return false; +} + +template +bool hasOpCall(const T& txTo) +{ + for(const CTxOut& v : txTo.vout){ + if(v.scriptPubKey.HasOpCall()){ + return true; + } + } + return false; +} + +bool CTransaction::HasOpCall() const +{ + return hasOpCall(*this); +} + +bool CMutableTransaction::HasOpCall() const +{ + return hasOpCall(*this); +} + +template +bool hasOpSender(const T& txTo) +{ + for(const CTxOut& v : txTo.vout){ + if(v.scriptPubKey.HasOpSender()){ + return true; + } + } + return false; +} + +bool CTransaction::HasOpSender() const +{ + return hasOpSender(*this); +} + +bool CMutableTransaction::HasOpSender() const +{ + return hasOpSender(*this); +} diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index bd7eb16bec..0aa993e6e1 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -180,6 +180,17 @@ class CTxOut return (nValue == -1); } + void SetEmpty() + { + nValue = 0; + scriptPubKey.clear(); + } + + bool IsEmpty() const + { + return (nValue == 0 && scriptPubKey.empty()); + } + friend bool operator==(const CTxOut& a, const CTxOut& b) { return (a.nValue == b.nValue && @@ -307,6 +318,14 @@ class CTransaction const int32_t nVersion; const uint32_t nLockTime; + // Operation codes + enum OpCode + { + OpNone = 0, + OpCall = 1, + OpCreate = 2 + }; + private: /** Memory only. */ const uint256 hash; @@ -316,8 +335,11 @@ class CTransaction uint256 ComputeWitnessHash() const; public: + /** Construct a CTransaction that qualifies as IsNull() */ + CTransaction(); + /** Convert a CMutableTransaction into a CTransaction. */ - explicit CTransaction(const CMutableTransaction& tx); + CTransaction(const CMutableTransaction& tx); explicit CTransaction(CMutableTransaction&& tx); template @@ -347,9 +369,33 @@ class CTransaction */ unsigned int GetTotalSize() const; +//////////////////////////////////////// // qtum + bool HasCreateOrCall() const; + bool HasOpSpend() const; +//////////////////////////////////////// + bool HasOpCreate() const; + bool HasOpCall() const; + inline int GetCreateOrCall() const + { + return (HasOpCall() ? OpCode::OpCall : 0) + (HasOpCreate() ? OpCode::OpCreate : 0); + } + bool HasOpSender() const; + bool IsCoinBase() const { - return (vin.size() == 1 && vin[0].prevout.IsNull()); + return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() >= 1); + } + + bool IsCoinStake() const + { + // ppcoin: the coin stake transaction is marked with the first output empty + return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty()); + } + + bool IsNormalTx() const + { + // not coin base or coin stake transaction + return !IsCoinBase() && !IsCoinStake(); } friend bool operator==(const CTransaction& a, const CTransaction& b) @@ -407,6 +453,10 @@ struct CMutableTransaction */ uint256 GetHash() const; + bool HasOpCall() const; + + bool HasOpSender() const; + bool HasWitness() const { for (size_t i = 0; i < vin.size(); i++) { diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 7e62d75583..f50b5b59c2 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -783,6 +783,7 @@ class PKDescriptor final : public DescriptorImpl } public: PKDescriptor(std::unique_ptr prov, bool xonly = false) : DescriptorImpl(Vector(std::move(prov)), "pk"), m_xonly(xonly) {} + std::optional GetOutputType() const override { return OutputType::LEGACY; } bool IsSingleType() const final { return true; } std::optional ScriptSize() const override { diff --git a/src/script/script.cpp b/src/script/script.cpp index 1594d3cc79..4c6263adbc 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -146,6 +146,12 @@ std::string GetOpName(opcodetype opcode) // Opcode added by BIP 342 (Tapscript) case OP_CHECKSIGADD : return "OP_CHECKSIGADD"; + // byte code execution + case OP_CREATE : return "OP_CREATE"; + case OP_CALL : return "OP_CALL"; + case OP_SPEND : return "OP_SPEND"; + case OP_SENDER : return "OP_SENDER"; + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; default: @@ -210,6 +216,32 @@ bool CScript::IsPayToScriptHash() const (*this)[22] == OP_EQUAL); } +///////////////////////////////////////////////////////// // qtum +bool CScript::IsPayToPubkey() const +{ + if (this->size() == 35 && (*this)[0] == 33 && (*this)[34] == OP_CHECKSIG + && ((*this)[1] == 0x02 || (*this)[1] == 0x03)) { + return true; + } + if (this->size() == 67 && (*this)[0] == 65 && (*this)[66] == OP_CHECKSIG + && (*this)[1] == 0x04) { + return true; + } + return false; +} + +bool CScript::IsPayToPubkeyHash() const +{ + // Extra-fast test for pay-to-pubkeyhash CScripts: + return (this->size() == 25 && + (*this)[0] == OP_DUP && + (*this)[1] == OP_HASH160 && + (*this)[2] == 0x14 && + (*this)[23] == OP_EQUALVERIFY && + (*this)[24] == OP_CHECKSIG); +} +///////////////////////////////////////////////////////// + bool CScript::IsPayToWitnessScriptHash() const { // Extra-fast test for pay-to-witness-script-hash CScripts: @@ -367,3 +399,101 @@ bool CheckMinimalPush(const std::vector& data, opcodetype opcode) } return true; } + +bool CScript::ReplaceParam(opcodetype findOp, int posBefore, const std::vector &vchParam, CScript &scriptRet) const +{ + if(posBefore < 0) + return false; + + // Find parameter with opcode and replace the parameter before with other value + bool ret = false; + std::vector opcodes; + int minSize = posBefore + 1; + opcodetype opcode = OP_INVALIDOPCODE; + opcodes.push_back(begin()); + for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);) + { + if (opcode == findOp) + { + int size = opcodes.size(); + if(size > minSize) + { + int firstPart = size -1 -posBefore; + int secondPart = size -posBefore; + scriptRet = CScript(begin(), opcodes[firstPart]) << vchParam; + scriptRet += CScript(opcodes[secondPart], end()); + ret = true; + } + break; + } + opcodes.push_back(pc); + } + + return ret; +} + +bool CScript::FindParam(opcodetype findOp, int posBefore, std::vector &vchParam) const +{ + if(posBefore < 0) + return false; + + // Find parameter with opcode and return the parameter before + bool ret = false; + std::vector>> opcodes; + int minSize = posBefore + 1; + opcodetype opcode; + std::vector tmpParam; + for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode, tmpParam);) + { + opcodes.push_back(std::make_pair(pc, tmpParam)); + if (opcode == findOp) + { + int size = opcodes.size(); + if(size > minSize) + { + int position = size -1 -posBefore; + vchParam = opcodes[position].second; + ret = true; + } + break; + } + } + + return ret; +} + +bool CScript::GetData(std::vector &data) const +{ + if(HasOpCreate()) + { + return FindParam(OP_CREATE, 1, data); + } + else if(HasOpCall()) + { + return FindParam(OP_CALL, 2, data); + } + + return false; +} + +bool CScript::SetData(const std::vector &data, CScript &scriptRet) const +{ + if(HasOpCreate()) + { + return ReplaceParam(OP_CREATE, 1, data, scriptRet); + } + else if(HasOpCall()) + { + return ReplaceParam(OP_CALL, 2, data, scriptRet); + } + + return false; +} + +bool CScript::IsPayToWitnessPubkeyHash() const +{ + // Extra-fast test for pay-to-witness-pubkey-hash CScripts: + return (this->size() == 22 && + (*this)[0] == OP_0 && + (*this)[1] == 0x14); +} diff --git a/src/script/script.h b/src/script/script.h index c329a2afd6..319e545231 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -23,7 +23,7 @@ #include // Maximum number of bytes pushable to the stack -static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; +static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 128000; //(128 kb) // Maximum number of non-push operations per script static const int MAX_OPS_PER_SCRIPT = 201; @@ -34,8 +34,10 @@ static const int MAX_PUBKEYS_PER_MULTISIG = 20; /** The limit of keys in OP_CHECKSIGADD-based scripts. It is due to the stack limit in BIP342. */ static constexpr unsigned int MAX_PUBKEYS_PER_MULTI_A = 999; -// Maximum script length in bytes -static const int MAX_SCRIPT_SIZE = 10000; +static const int MAX_SCRIPT_SIZE = 129000; // (129 kb) + +// Maximum base script length in bytes +static const int MAX_BASE_SCRIPT_SIZE = 10000; // Maximum number of values on script interpreter stack static const int MAX_STACK_SIZE = 1000; @@ -207,6 +209,25 @@ enum opcodetype // Opcode added by BIP 342 (Tapscript) OP_CHECKSIGADD = 0xba, + // Execute EXT byte code. + OP_CREATE = 0xc1, + OP_CALL = 0xc2, + OP_SPEND = 0xc3, + OP_SENDER = 0xc4, + + // template matching params + OP_ADDRESS_TYPE = 0xf2, + OP_ADDRESS = 0xf3, + OP_SCRIPT_SIG = 0xf4, + OP_GAS_PRICE = 0xf5, + OP_VERSION = 0xf6, + OP_GAS_LIMIT = 0xf7, + OP_DATA = 0xf8, + OP_SMALLINTEGER = 0xfa, + OP_PUBKEYS = 0xfb, + OP_PUBKEYHASH = 0xfd, + OP_PUBKEY = 0xfe, + OP_INVALIDOPCODE = 0xff, }; @@ -344,6 +365,30 @@ class CScriptNum return serialize(m_value); } + ///////////////////////////////// qtum + static uint64_t vch_to_uint64(const std::vector& vch) + { + if (vch.size() > 8) { + throw scriptnum_error("script number overflow"); + } + + if (vch.empty()) + return 0; + + uint64_t result = 0; + for (size_t i = 0; i != vch.size(); ++i) + result |= static_cast(vch[i]) << 8*i; + + // If the input vector's most significant byte is 0x80, remove it from + // the result's msb and return a negative. + if (vch.back() & 0x80) + throw scriptnum_error("Negative gas value."); + // return -((uint64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1))))); + + return result; + } + ///////////////////////////////// + static std::vector serialize(const int64_t& value) { if(value == 0) @@ -436,6 +481,20 @@ class CScript : public CScriptBase SERIALIZE_METHODS(CScript, obj) { READWRITE(AsBase(obj)); } + CScript& operator+=(const CScript& b) + { + reserve(size() + b.size()); + insert(end(), b.begin(), b.end()); + return *this; + } + + friend CScript operator+(const CScript& a, const CScript& b) + { + CScript ret = a; + ret += b; + return ret; + } + explicit CScript(int64_t b) { operator<<(b); } explicit CScript(opcodetype b) { operator<<(b); } explicit CScript(const CScriptNum& b) { operator<<(b); } @@ -516,6 +575,15 @@ class CScript : public CScriptBase return OP_0; return (opcodetype)(OP_1+n-1); } + int Find(opcodetype op) const + { + int nFound = 0; + opcodetype opcode = OP_INVALIDOPCODE; + for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);) + if (opcode == op) + ++nFound; + return nFound; + } /** * Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs @@ -533,6 +601,10 @@ class CScript : public CScriptBase unsigned int GetSigOpCount(const CScript& scriptSig) const; bool IsPayToScriptHash() const; + ///////////////////////////////////////////////// // qtum + bool IsPayToPubkey() const; + bool IsPayToPubkeyHash() const; + ///////////////////////////////////////////////// bool IsPayToWitnessScriptHash() const; bool IsWitnessProgram(int& version, std::vector& program) const; @@ -553,12 +625,56 @@ class CScript : public CScriptBase return (size() > 0 && *begin() == OP_RETURN) || (size() > MAX_SCRIPT_SIZE); } + bool HasOpCreate() const + { + return Find(OP_CREATE) == 1; + } + + bool HasOpCall() const + { + return Find(OP_CALL) == 1; + } + + bool HasOpSpend() const + { + return size()==1 && *begin() == OP_SPEND; + } + + bool HasOpSender() const + { + return Find(OP_SENDER) == 1; + } + + bool UpdateSenderSig(const std::vector& scriptSig, CScript& scriptRet) const + { + return ReplaceParam(OP_SENDER, 1, scriptSig, scriptRet); + } + + bool GetData(std::vector& data) const; + + bool SetData(const std::vector& data, CScript& scriptRet) const; + + CScript WithoutSenderSig() const + { + std::vector scriptSig; + CScript scriptRet; + if(!UpdateSenderSig(scriptSig, scriptRet)) + scriptRet = CScript(begin(), end()); + return scriptRet; + } + + bool ReplaceParam(opcodetype findOp, int posBefore, const std::vector& vchParam, CScript& scriptRet) const; + bool FindParam(opcodetype findOp, int posBefore, std::vector& vchParam) const; + ///////////////////////////////////////// + void clear() { // The default prevector::clear() does not release memory CScriptBase::clear(); shrink_to_fit(); } + + bool IsPayToWitnessPubkeyHash() const; }; struct CScriptWitness