Changeset View
Changeset View
Standalone View
Standalone View
src/script/script.h
Show First 20 Lines • Show All 409 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* We use a prevector for the script to reduce the considerable memory overhead | * We use a prevector for the script to reduce the considerable memory overhead | ||||
* of vectors in cases where they normally contain a small number of small | * of vectors in cases where they normally contain a small number of small | ||||
* elements. Tests in October 2015 showed use of this reduced dbcache memory | * elements. Tests in October 2015 showed use of this reduced dbcache memory | ||||
* usage by 23% and made an initial sync 13% faster. | * usage by 23% and made an initial sync 13% faster. | ||||
*/ | */ | ||||
typedef prevector<28, uint8_t> CScriptBase; | typedef prevector<28, uint8_t> CScriptBase; | ||||
bool GetScriptOp(CScriptBase::const_iterator &pc, | |||||
CScriptBase::const_iterator end, opcodetype &opcodeRet, | |||||
std::vector<uint8_t> *pvchRet); | |||||
/** Serialized script, used inside transaction inputs and outputs */ | /** Serialized script, used inside transaction inputs and outputs */ | ||||
class CScript : public CScriptBase { | class CScript : public CScriptBase { | ||||
protected: | protected: | ||||
CScript &push_int64(int64_t n) { | CScript &push_int64(int64_t n) { | ||||
if (n == -1 || (n >= 1 && n <= 16)) { | if (n == -1 || (n >= 1 && n <= 16)) { | ||||
push_back(n + (OP_1 - 1)); | push_back(n + (OP_1 - 1)); | ||||
} else if (n == 0) { | } else if (n == 0) { | ||||
push_back(OP_0); | push_back(OP_0); | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | CScript &operator<<(const CScript &b) { | ||||
// I'm not sure if this should push the script or concatenate scripts. | // I'm not sure if this should push the script or concatenate scripts. | ||||
// If there's ever a use for pushing a script onto a script, delete this | // If there's ever a use for pushing a script onto a script, delete this | ||||
// member fn. | // member fn. | ||||
assert(!"Warning: Pushing a CScript onto a CScript with << is probably " | assert(!"Warning: Pushing a CScript onto a CScript with << is probably " | ||||
"not intended, use + to concatenate!"); | "not intended, use + to concatenate!"); | ||||
return *this; | return *this; | ||||
} | } | ||||
bool GetOp(iterator &pc, opcodetype &opcodeRet, | |||||
std::vector<uint8_t> &vchRet) { | |||||
// Wrapper so it can be called with either iterator or const_iterator. | |||||
const_iterator pc2 = pc; | |||||
bool fRet = GetOp2(pc2, opcodeRet, &vchRet); | |||||
pc = begin() + (pc2 - begin()); | |||||
return fRet; | |||||
} | |||||
bool GetOp(iterator &pc, opcodetype &opcodeRet) { | |||||
const_iterator pc2 = pc; | |||||
bool fRet = GetOp2(pc2, opcodeRet, nullptr); | |||||
pc = begin() + (pc2 - begin()); | |||||
return fRet; | |||||
} | |||||
bool GetOp(const_iterator &pc, opcodetype &opcodeRet, | bool GetOp(const_iterator &pc, opcodetype &opcodeRet, | ||||
std::vector<uint8_t> &vchRet) const { | std::vector<uint8_t> &vchRet) const { | ||||
return GetOp2(pc, opcodeRet, &vchRet); | return GetScriptOp(pc, end(), opcodeRet, &vchRet); | ||||
} | } | ||||
bool GetOp(const_iterator &pc, opcodetype &opcodeRet) const { | bool GetOp(const_iterator &pc, opcodetype &opcodeRet) const { | ||||
return GetOp2(pc, opcodeRet, nullptr); | return GetScriptOp(pc, end(), opcodeRet, nullptr); | ||||
} | |||||
bool GetOp2(const_iterator &pc, opcodetype &opcodeRet, | |||||
std::vector<uint8_t> *pvchRet) const { | |||||
opcodeRet = OP_INVALIDOPCODE; | |||||
if (pvchRet) { | |||||
pvchRet->clear(); | |||||
} | |||||
if (pc >= end()) { | |||||
return false; | |||||
} | |||||
// Read instruction | |||||
if (end() - pc < 1) { | |||||
return false; | |||||
} | |||||
uint32_t opcode = *pc++; | |||||
// Immediate operand | |||||
if (opcode <= OP_PUSHDATA4) { | |||||
uint32_t nSize = 0; | |||||
if (opcode < OP_PUSHDATA1) { | |||||
nSize = opcode; | |||||
} else if (opcode == OP_PUSHDATA1) { | |||||
if (end() - pc < 1) { | |||||
return false; | |||||
} | |||||
nSize = *pc++; | |||||
} else if (opcode == OP_PUSHDATA2) { | |||||
if (end() - pc < 2) { | |||||
return false; | |||||
} | |||||
nSize = ReadLE16(&pc[0]); | |||||
pc += 2; | |||||
} else if (opcode == OP_PUSHDATA4) { | |||||
if (end() - pc < 4) { | |||||
return false; | |||||
} | |||||
nSize = ReadLE32(&pc[0]); | |||||
pc += 4; | |||||
} | |||||
if (end() - pc < 0 || uint32_t(end() - pc) < nSize) { | |||||
return false; | |||||
} | |||||
if (pvchRet) { | |||||
pvchRet->assign(pc, pc + nSize); | |||||
} | |||||
pc += nSize; | |||||
} | |||||
opcodeRet = static_cast<opcodetype>(opcode); | |||||
return true; | |||||
} | } | ||||
/** Encode/decode small integers: */ | /** Encode/decode small integers: */ | ||||
static int DecodeOP_N(opcodetype opcode) { | static int DecodeOP_N(opcodetype opcode) { | ||||
if (opcode == OP_0) { | if (opcode == OP_0) { | ||||
return 0; | return 0; | ||||
} | } | ||||
assert(opcode >= OP_1 && opcode <= OP_16); | assert(opcode >= OP_1 && opcode <= OP_16); | ||||
return int(opcode) - int(OP_1 - 1); | return int(opcode) - int(OP_1 - 1); | ||||
} | } | ||||
static opcodetype EncodeOP_N(int n) { | static opcodetype EncodeOP_N(int n) { | ||||
assert(n >= 0 && n <= 16); | assert(n >= 0 && n <= 16); | ||||
if (n == 0) { | if (n == 0) { | ||||
return OP_0; | return OP_0; | ||||
} | } | ||||
return (opcodetype)(OP_1 + n - 1); | return (opcodetype)(OP_1 + n - 1); | ||||
} | } | ||||
int FindAndDelete(const CScript &b) { | |||||
int nFound = 0; | |||||
if (b.empty()) { | |||||
return nFound; | |||||
} | |||||
CScript result; | |||||
iterator pc = begin(), pc2 = begin(); | |||||
opcodetype opcode; | |||||
do { | |||||
result.insert(result.end(), pc2, pc); | |||||
while (size_t(end() - pc) >= b.size() && | |||||
std::equal(b.begin(), b.end(), pc)) { | |||||
pc = pc + b.size(); | |||||
++nFound; | |||||
} | |||||
pc2 = pc; | |||||
} while (GetOp(pc, opcode)); | |||||
if (nFound > 0) { | |||||
result.insert(result.end(), pc2, end()); | |||||
*this = result; | |||||
} | |||||
return nFound; | |||||
} | |||||
/** | /** | ||||
* Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs as 20 sigops. With | * Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs as 20 sigops. With | ||||
* pay-to-script-hash, that changed: CHECKMULTISIGs serialized in scriptSigs | * pay-to-script-hash, that changed: CHECKMULTISIGs serialized in scriptSigs | ||||
* are counted more accurately, assuming they are of the form | * are counted more accurately, assuming they are of the form | ||||
* ... OP_N CHECKMULTISIG ... | * ... OP_N CHECKMULTISIG ... | ||||
*/ | */ | ||||
uint32_t GetSigOpCount(uint32_t flags, bool fAccurate) const; | uint32_t GetSigOpCount(uint32_t flags, bool fAccurate) const; | ||||
▲ Show 20 Lines • Show All 44 Lines • Show Last 20 Lines |