Merge branch 'beta' into mergemaster
# Conflicts: # src/main.cpp
This commit is contained in:
137
src/script/cc.cpp
Normal file
137
src/script/cc.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "cryptoconditions/include/cryptoconditions.h"
|
||||
#include "script/cc.h"
|
||||
|
||||
|
||||
bool IsCryptoConditionsEnabled()
|
||||
{
|
||||
return 0 != ASSETCHAINS_CC;
|
||||
}
|
||||
|
||||
|
||||
bool IsSupportedCryptoCondition(const CC *cond)
|
||||
{
|
||||
int mask = cc_typeMask(cond);
|
||||
|
||||
if (mask & ~CCEnabledTypes) return false;
|
||||
|
||||
// Also require that the condition have at least one signable node
|
||||
if (!(mask & CCSigningNodes)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IsSignedCryptoCondition(const CC *cond)
|
||||
{
|
||||
if (!cc_isFulfilled(cond)) return false;
|
||||
if (1 << cc_typeId(cond) & CCSigningNodes) return true;
|
||||
if (cc_typeId(cond) == CC_Threshold)
|
||||
for (int i=0; i<cond->size; i++)
|
||||
if (IsSignedCryptoCondition(cond->subconditions[i])) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char* CopyPubKey(CPubKey pkIn)
|
||||
{
|
||||
unsigned char* pk = (unsigned char*) malloc(33);
|
||||
memcpy(pk, pkIn.begin(), 33); // TODO: compressed?
|
||||
return pk;
|
||||
}
|
||||
|
||||
|
||||
CC* CCNewThreshold(int t, std::vector<CC*> v)
|
||||
{
|
||||
CC *cond = cc_new(CC_Threshold);
|
||||
cond->threshold = t;
|
||||
cond->size = v.size();
|
||||
cond->subconditions = (CC**) calloc(v.size(), sizeof(CC*));
|
||||
memcpy(cond->subconditions, v.data(), v.size() * sizeof(CC*));
|
||||
return cond;
|
||||
}
|
||||
|
||||
|
||||
CC* CCNewSecp256k1(CPubKey k)
|
||||
{
|
||||
CC *cond = cc_new(CC_Secp256k1);
|
||||
cond->publicKey = CopyPubKey(k);
|
||||
return cond;
|
||||
}
|
||||
|
||||
|
||||
CC* CCNewEval(std::vector<unsigned char> code)
|
||||
{
|
||||
CC *cond = cc_new(CC_Eval);
|
||||
cond->code = (unsigned char*) malloc(code.size());
|
||||
memcpy(cond->code, code.data(), code.size());
|
||||
cond->codeLength = code.size();
|
||||
return cond;
|
||||
}
|
||||
|
||||
|
||||
CScript CCPubKey(const CC *cond)
|
||||
{
|
||||
unsigned char buf[1000];
|
||||
size_t len = cc_conditionBinary(cond, buf);
|
||||
return CScript() << std::vector<unsigned char>(buf, buf+len) << OP_CHECKCRYPTOCONDITION;
|
||||
}
|
||||
|
||||
|
||||
CScript CCSig(const CC *cond)
|
||||
{
|
||||
unsigned char buf[10000];
|
||||
size_t len = cc_fulfillmentBinary(cond, buf, 10000);
|
||||
auto ffill = std::vector<unsigned char>(buf, buf+len);
|
||||
ffill.push_back(1); // SIGHASH_ALL
|
||||
return CScript() << ffill;
|
||||
}
|
||||
|
||||
|
||||
std::string CCShowStructure(CC *cond)
|
||||
{
|
||||
std::string out;
|
||||
if (cc_isAnon(cond)) {
|
||||
out = "A" + std::to_string(cc_typeId(cond));
|
||||
}
|
||||
else if (cc_typeId(cond) == CC_Threshold) {
|
||||
out += "(" + std::to_string(cond->threshold) + " of ";
|
||||
for (int i=0; i<cond->size; i++) {
|
||||
out += CCShowStructure(cond->subconditions[i]);
|
||||
if (i < cond->size - 1) out += ",";
|
||||
}
|
||||
out += ")";
|
||||
}
|
||||
else {
|
||||
out = std::to_string(cc_typeId(cond));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
CC* CCPrune(CC *cond)
|
||||
{
|
||||
std::vector<unsigned char> ffillBin;
|
||||
GetPushData(CCSig(cond), ffillBin);
|
||||
return cc_readFulfillmentBinary(ffillBin.data(), ffillBin.size()-1);
|
||||
}
|
||||
|
||||
|
||||
bool GetPushData(const CScript &sig, std::vector<unsigned char> &data)
|
||||
{
|
||||
opcodetype opcode;
|
||||
auto pc = sig.begin();
|
||||
if (sig.GetOp(pc, opcode, data)) return opcode > OP_0 && opcode <= OP_PUSHDATA4;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool GetOpReturnData(const CScript &sig, std::vector<unsigned char> &data)
|
||||
{
|
||||
auto pc = sig.begin();
|
||||
opcodetype opcode;
|
||||
if (sig.GetOp2(pc, opcode, NULL))
|
||||
if (opcode == OP_RETURN)
|
||||
if (sig.GetOp(pc, opcode, data))
|
||||
return opcode > OP_0 && opcode <= OP_PUSHDATA4;
|
||||
return false;
|
||||
}
|
||||
83
src/script/cc.h
Normal file
83
src/script/cc.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef SCRIPT_CC_H
|
||||
#define SCRIPT_CC_H
|
||||
|
||||
#include "pubkey.h"
|
||||
#include "script/script.h"
|
||||
#include "cryptoconditions/include/cryptoconditions.h"
|
||||
|
||||
|
||||
extern int32_t ASSETCHAINS_CC;
|
||||
bool IsCryptoConditionsEnabled();
|
||||
|
||||
// Limit acceptable condition types
|
||||
// Prefix not enabled because no current use case, ambiguity on how to combine with secp256k1
|
||||
// RSA not enabled because no current use case, not implemented
|
||||
const int CCEnabledTypes = 1 << CC_Secp256k1 | \
|
||||
1 << CC_Threshold | \
|
||||
1 << CC_Eval | \
|
||||
1 << CC_Preimage | \
|
||||
1 << CC_Ed25519;
|
||||
|
||||
const int CCSigningNodes = 1 << CC_Ed25519 | 1 << CC_Secp256k1;
|
||||
|
||||
|
||||
/*
|
||||
* Check if the server can accept the condition based on it's structure / types
|
||||
*/
|
||||
bool IsSupportedCryptoCondition(const CC *cond);
|
||||
|
||||
|
||||
/*
|
||||
* Check if crypto condition is signed. Can only accept signed conditions.
|
||||
*/
|
||||
bool IsSignedCryptoCondition(const CC *cond);
|
||||
|
||||
|
||||
/*
|
||||
* Construct crypto conditions
|
||||
*/
|
||||
CC* CCNewPreimage(std::vector<unsigned char> preimage);
|
||||
CC* CCNewEval(std::vector<unsigned char> code);
|
||||
CC* CCNewSecp256k1(CPubKey k);
|
||||
CC* CCNewThreshold(int t, std::vector<CC*> v);
|
||||
|
||||
|
||||
/*
|
||||
* Turn a condition into a scriptPubKey
|
||||
*/
|
||||
CScript CCPubKey(const CC *cond);
|
||||
|
||||
|
||||
/*
|
||||
* Turn a condition into a scriptSig
|
||||
*
|
||||
* Note: This will fail in undefined ways if the condition is missing signatures
|
||||
*/
|
||||
CScript CCSig(const CC *cond);
|
||||
|
||||
|
||||
/*
|
||||
* Produces a string showing the structure of a CC condition
|
||||
*/
|
||||
std::string CCShowStructure(CC *cond);
|
||||
|
||||
|
||||
/*
|
||||
* Take a signed CC, encode it, and decode it again. This has the effect
|
||||
* of removing branches unneccesary for fulfillment.
|
||||
*/
|
||||
CC* CCPrune(CC *cond);
|
||||
|
||||
|
||||
/*
|
||||
* Get PUSHDATA from a script
|
||||
*/
|
||||
bool GetPushData(const CScript &sig, std::vector<unsigned char> &data);
|
||||
|
||||
/*
|
||||
* Get OP_RETURN data from a script
|
||||
*/
|
||||
bool GetOpReturnData(const CScript &sig, std::vector<unsigned char> &data);
|
||||
|
||||
|
||||
#endif /* SCRIPT_CC_H */
|
||||
@@ -5,14 +5,16 @@
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
#include "consensus/upgrades.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "crypto/ripemd160.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "eccryptoverify.h"
|
||||
#include "pubkey.h"
|
||||
#include "script/script.h"
|
||||
#include "uint256.h"
|
||||
#include "cryptoconditions/include/cryptoconditions.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -102,7 +104,7 @@ bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {
|
||||
// excluding the sighash byte.
|
||||
// * R-length: 1-byte length descriptor of the R value that follows.
|
||||
// * R: arbitrary-length big-endian encoded R value. It must use the shortest
|
||||
// possible encoding for a positive integers (which means no null bytes at
|
||||
// possible encoding for a positive integer (which means no null bytes at
|
||||
// the start, except a single one when the next byte has its highest bit set).
|
||||
// * S-length: 1-byte length descriptor of the S value that follows.
|
||||
// * S: arbitrary-length big-endian encoded S value. The same rules apply.
|
||||
@@ -165,16 +167,14 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
|
||||
if (!IsValidSignatureEncoding(vchSig)) {
|
||||
return set_error(serror, SCRIPT_ERR_SIG_DER);
|
||||
}
|
||||
unsigned int nLenR = vchSig[3];
|
||||
unsigned int nLenS = vchSig[5+nLenR];
|
||||
const unsigned char *S = &vchSig[6+nLenR];
|
||||
// https://bitcoin.stackexchange.com/a/12556:
|
||||
// Also note that inside transaction signatures, an extra hashtype byte
|
||||
// follows the actual signature data.
|
||||
std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1);
|
||||
// If the S value is above the order of the curve divided by two, its
|
||||
// complement modulo the order could have been used instead, which is
|
||||
// one byte shorter when encoded correctly.
|
||||
if (!eccrypto::CheckSignatureElement(S, nLenS, true))
|
||||
return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);
|
||||
|
||||
return true;
|
||||
return CPubKey::CheckLowS(vchSigCopy);
|
||||
}
|
||||
|
||||
bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
|
||||
@@ -194,7 +194,7 @@ bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, Sc
|
||||
if (vchSig.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsValidSignatureEncoding(vchSig)) {
|
||||
if (!IsValidSignatureEncoding(vchSig)) {
|
||||
return set_error(serror, SCRIPT_ERR_SIG_DER);
|
||||
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {
|
||||
// serror is set
|
||||
@@ -235,7 +235,13 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
||||
bool EvalScript(
|
||||
vector<vector<unsigned char> >& stack,
|
||||
const CScript& script,
|
||||
unsigned int flags,
|
||||
const BaseSignatureChecker& checker,
|
||||
uint32_t consensusBranchId,
|
||||
ScriptError* serror)
|
||||
{
|
||||
static const CScriptNum bnZero(0);
|
||||
static const CScriptNum bnOne(1);
|
||||
@@ -832,7 +838,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
//serror is set
|
||||
return false;
|
||||
}
|
||||
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script);
|
||||
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId);
|
||||
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
@@ -890,7 +896,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
}
|
||||
|
||||
// Check signature
|
||||
bool fOk = checker.CheckSig(vchSig, vchPubKey, script);
|
||||
bool fOk = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId);
|
||||
|
||||
if (fOk) {
|
||||
isig++;
|
||||
@@ -934,6 +940,37 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_CHECKCRYPTOCONDITION:
|
||||
case OP_CHECKCRYPTOCONDITIONVERIFY:
|
||||
{
|
||||
if (!IsCryptoConditionsEnabled()) {
|
||||
goto INTERPRETER_DEFAULT;
|
||||
}
|
||||
|
||||
if (stack.size() < 2)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
int fResult = checker.CheckCryptoCondition(stacktop(-1), stacktop(-2), script, consensusBranchId);
|
||||
if (fResult == -1) {
|
||||
return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT);
|
||||
}
|
||||
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
|
||||
stack.push_back(fResult == 1 ? vchTrue : vchFalse);
|
||||
|
||||
if (opcode == OP_CHECKCRYPTOCONDITIONVERIFY)
|
||||
{
|
||||
if (fResult == 1)
|
||||
popstack(stack);
|
||||
else
|
||||
return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_VERIFY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
INTERPRETER_DEFAULT:
|
||||
default:
|
||||
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
||||
}
|
||||
@@ -1054,15 +1091,148 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
|
||||
{'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'};
|
||||
const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
|
||||
{'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'};
|
||||
const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
|
||||
{'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'};
|
||||
const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
|
||||
{'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'};
|
||||
|
||||
uint256 GetPrevoutHash(const CTransaction& txTo) {
|
||||
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION);
|
||||
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
|
||||
ss << txTo.vin[n].prevout;
|
||||
}
|
||||
return ss.GetHash();
|
||||
}
|
||||
|
||||
uint256 GetSequenceHash(const CTransaction& txTo) {
|
||||
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SEQUENCE_HASH_PERSONALIZATION);
|
||||
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
|
||||
ss << txTo.vin[n].nSequence;
|
||||
}
|
||||
return ss.GetHash();
|
||||
}
|
||||
|
||||
uint256 GetOutputsHash(const CTransaction& txTo) {
|
||||
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
|
||||
for (unsigned int n = 0; n < txTo.vout.size(); n++) {
|
||||
ss << txTo.vout[n];
|
||||
}
|
||||
return ss.GetHash();
|
||||
}
|
||||
|
||||
uint256 GetJoinSplitsHash(const CTransaction& txTo) {
|
||||
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_JOINSPLITS_HASH_PERSONALIZATION);
|
||||
for (unsigned int n = 0; n < txTo.vjoinsplit.size(); n++) {
|
||||
ss << txTo.vjoinsplit[n];
|
||||
}
|
||||
ss << txTo.joinSplitPubKey;
|
||||
return ss.GetHash();
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
|
||||
{
|
||||
hashPrevouts = GetPrevoutHash(txTo);
|
||||
hashSequence = GetSequenceHash(txTo);
|
||||
hashOutputs = GetOutputsHash(txTo);
|
||||
hashJoinSplits = GetJoinSplitsHash(txTo);
|
||||
}
|
||||
|
||||
SigVersion SignatureHashVersion(const CTransaction& txTo)
|
||||
{
|
||||
if (txTo.fOverwintered) {
|
||||
return SIGVERSION_OVERWINTER;
|
||||
} else {
|
||||
return SIGVERSION_SPROUT;
|
||||
}
|
||||
}
|
||||
|
||||
uint256 SignatureHash(
|
||||
const CScript& scriptCode,
|
||||
const CTransaction& txTo,
|
||||
unsigned int nIn,
|
||||
int nHashType,
|
||||
const CAmount& amount,
|
||||
uint32_t consensusBranchId,
|
||||
const PrecomputedTransactionData* cache)
|
||||
{
|
||||
if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) {
|
||||
// nIn out of range
|
||||
throw logic_error("input index is out of range");
|
||||
}
|
||||
|
||||
auto sigversion = SignatureHashVersion(txTo);
|
||||
|
||||
if (sigversion == SIGVERSION_OVERWINTER) {
|
||||
uint256 hashPrevouts;
|
||||
uint256 hashSequence;
|
||||
uint256 hashOutputs;
|
||||
uint256 hashJoinSplits;
|
||||
|
||||
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
|
||||
hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
|
||||
}
|
||||
|
||||
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
|
||||
hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
|
||||
}
|
||||
|
||||
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
|
||||
hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
|
||||
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
|
||||
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
|
||||
ss << txTo.vout[nIn];
|
||||
hashOutputs = ss.GetHash();
|
||||
}
|
||||
|
||||
if (!txTo.vjoinsplit.empty()) {
|
||||
hashJoinSplits = cache ? cache->hashJoinSplits : GetJoinSplitsHash(txTo);
|
||||
}
|
||||
|
||||
uint32_t leConsensusBranchId = htole32(consensusBranchId);
|
||||
unsigned char personalization[16] = {};
|
||||
memcpy(personalization, "ZcashSigHash", 12);
|
||||
memcpy(personalization+12, &leConsensusBranchId, 4);
|
||||
|
||||
CBLAKE2bWriter ss(SER_GETHASH, 0, personalization);
|
||||
// Header
|
||||
ss << txTo.GetHeader();
|
||||
// Version group ID
|
||||
ss << txTo.nVersionGroupId;
|
||||
// Input prevouts/nSequence (none/all, depending on flags)
|
||||
ss << hashPrevouts;
|
||||
ss << hashSequence;
|
||||
// Outputs (none/one/all, depending on flags)
|
||||
ss << hashOutputs;
|
||||
// JoinSplits
|
||||
ss << hashJoinSplits;
|
||||
// Locktime
|
||||
ss << txTo.nLockTime;
|
||||
// Expiry height
|
||||
ss << txTo.nExpiryHeight;
|
||||
// Sighash type
|
||||
ss << nHashType;
|
||||
|
||||
// If this hash is for a transparent input signature
|
||||
// (i.e. not for txTo.joinSplitSig):
|
||||
if (nIn != NOT_AN_INPUT){
|
||||
// The input being signed (replacing the scriptSig with scriptCode + amount)
|
||||
// The prevout may already be contained in hashPrevout, and the nSequence
|
||||
// may already be contained in hashSequence.
|
||||
ss << txTo.vin[nIn].prevout;
|
||||
ss << scriptCode;
|
||||
ss << amount;
|
||||
ss << txTo.vin[nIn].nSequence;
|
||||
}
|
||||
|
||||
return ss.GetHash();
|
||||
}
|
||||
|
||||
// Check for invalid use of SIGHASH_SINGLE
|
||||
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
|
||||
if (nIn >= txTo.vout.size()) {
|
||||
@@ -1080,12 +1250,17 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
|
||||
return ss.GetHash();
|
||||
}
|
||||
|
||||
bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
bool TransactionSignatureChecker::VerifySignature(
|
||||
const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
return pubkey.Verify(sighash, vchSig);
|
||||
}
|
||||
|
||||
bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
|
||||
bool TransactionSignatureChecker::CheckSig(
|
||||
const vector<unsigned char>& vchSigIn,
|
||||
const vector<unsigned char>& vchPubKey,
|
||||
const CScript& scriptCode,
|
||||
uint32_t consensusBranchId) const
|
||||
{
|
||||
CPubKey pubkey(vchPubKey);
|
||||
if (!pubkey.IsValid())
|
||||
@@ -1100,7 +1275,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
|
||||
|
||||
uint256 sighash;
|
||||
try {
|
||||
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
|
||||
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata);
|
||||
} catch (logic_error ex) {
|
||||
return false;
|
||||
}
|
||||
@@ -1111,6 +1286,49 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int TransactionSignatureChecker::CheckCryptoCondition(
|
||||
const std::vector<unsigned char>& condBin,
|
||||
const std::vector<unsigned char>& ffillBin,
|
||||
const CScript& scriptCode,
|
||||
uint32_t consensusBranchId) const
|
||||
{
|
||||
// Hash type is one byte tacked on to the end of the fulfillment
|
||||
if (ffillBin.empty())
|
||||
return false;
|
||||
|
||||
CC *cond = cc_readFulfillmentBinary((unsigned char*)ffillBin.data(), ffillBin.size()-1);
|
||||
if (!cond) return -1;
|
||||
|
||||
if (!IsSupportedCryptoCondition(cond)) return 0;
|
||||
if (!IsSignedCryptoCondition(cond)) return 0;
|
||||
|
||||
uint256 sighash;
|
||||
int nHashType = ffillBin.back();
|
||||
try {
|
||||
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata);
|
||||
} catch (logic_error ex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
VerifyEval eval = [] (CC *cond, void *checker) {
|
||||
return ((TransactionSignatureChecker*)checker)->CheckEvalCondition(cond);
|
||||
};
|
||||
|
||||
int out = cc_verify(cond, (const unsigned char*)&sighash, 32, 0,
|
||||
condBin.data(), condBin.size(), eval, (void*)this);
|
||||
cc_free(cond);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
int TransactionSignatureChecker::CheckEvalCondition(const CC *cond) const
|
||||
{
|
||||
fprintf(stderr, "Cannot check crypto-condition Eval outside of server\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
|
||||
{
|
||||
// There are two times of nLockTime: lock-by-blockheight
|
||||
@@ -1129,7 +1347,10 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
|
||||
// Now that we know we're comparing apples-to-apples, the
|
||||
// comparison is a simple numeric one.
|
||||
if (nLockTime > (int64_t)txTo->nLockTime)
|
||||
{
|
||||
//fprintf(stderr,"CLTV error: nLockTime %llu > %u txTo->nLockTime\n",*(long long *)&nLockTime,(uint32_t)txTo->nLockTime);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finally the nLockTime feature can be disabled and thus
|
||||
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
|
||||
@@ -1142,13 +1363,53 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
|
||||
// inputs, but testing just this input minimizes the data
|
||||
// required to prove correct CHECKLOCKTIMEVERIFY execution.
|
||||
if (txTo->vin[nIn].IsFinal())
|
||||
{
|
||||
//fprintf(stderr,"CLTV error: nonfinal vin.%d nSequence.%u vs %u\n",(int32_t)nIn,(uint32_t)txTo->vin[nIn].nSequence,(uint32_t)std::numeric_limits<uint32_t>::max());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
||||
/*
|
||||
* Allow larger opcode in case of crypto condition scriptSig
|
||||
*/
|
||||
bool EvalCryptoConditionSig(
|
||||
vector<vector<unsigned char> >& stack,
|
||||
const CScript& scriptSig,
|
||||
ScriptError* serror)
|
||||
{
|
||||
CScript::const_iterator pc = scriptSig.begin();
|
||||
opcodetype opcode;
|
||||
valtype vchPushValue;
|
||||
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
||||
|
||||
if (!scriptSig.GetOp(pc, opcode, vchPushValue))
|
||||
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
||||
|
||||
if (opcode == 0 || opcode > OP_PUSHDATA4)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
if (pc != scriptSig.end())
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
if (vchPushValue.size() > MAX_SCRIPT_CRYPTOCONDITION_FULFILLMENT_SIZE)
|
||||
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
|
||||
|
||||
stack.push_back(vchPushValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool VerifyScript(
|
||||
const CScript& scriptSig,
|
||||
const CScript& scriptPubKey,
|
||||
unsigned int flags,
|
||||
const BaseSignatureChecker& checker,
|
||||
uint32_t consensusBranchId,
|
||||
ScriptError* serror)
|
||||
{
|
||||
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
||||
|
||||
@@ -1157,12 +1418,17 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
|
||||
}
|
||||
|
||||
vector<vector<unsigned char> > stack, stackCopy;
|
||||
if (!EvalScript(stack, scriptSig, flags, checker, serror))
|
||||
if (IsCryptoConditionsEnabled() && scriptPubKey.IsPayToCryptoCondition()) {
|
||||
if (!EvalCryptoConditionSig(stack, scriptSig, serror))
|
||||
// serror is set
|
||||
return false;
|
||||
}
|
||||
else if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror))
|
||||
// serror is set
|
||||
return false;
|
||||
if (flags & SCRIPT_VERIFY_P2SH)
|
||||
stackCopy = stack;
|
||||
if (!EvalScript(stack, scriptPubKey, flags, checker, serror))
|
||||
if (!EvalScript(stack, scriptPubKey, flags, checker, consensusBranchId, serror))
|
||||
// serror is set
|
||||
return false;
|
||||
if (stack.empty())
|
||||
@@ -1189,7 +1455,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
|
||||
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
|
||||
popstack(stack);
|
||||
|
||||
if (!EvalScript(stack, pubKey2, flags, checker, serror))
|
||||
if (!EvalScript(stack, pubKey2, flags, checker, consensusBranchId, serror))
|
||||
// serror is set
|
||||
return false;
|
||||
if (stack.empty())
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "script_error.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "script/cc.h"
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
@@ -45,7 +46,8 @@ enum
|
||||
SCRIPT_VERIFY_STRICTENC = (1U << 1),
|
||||
|
||||
// Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)
|
||||
SCRIPT_VERIFY_DERSIG = (1U << 2),
|
||||
// In Zcash this is required, and validation of non-strict-DER signatures is not implemented.
|
||||
//SCRIPT_VERIFY_DERSIG = (1U << 2),
|
||||
|
||||
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
|
||||
// (softfork safe, BIP62 rule 5).
|
||||
@@ -87,12 +89,36 @@ enum
|
||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
|
||||
};
|
||||
|
||||
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
struct PrecomputedTransactionData
|
||||
{
|
||||
uint256 hashPrevouts, hashSequence, hashOutputs, hashJoinSplits;
|
||||
|
||||
PrecomputedTransactionData(const CTransaction& tx);
|
||||
};
|
||||
|
||||
enum SigVersion
|
||||
{
|
||||
SIGVERSION_SPROUT = 0,
|
||||
SIGVERSION_OVERWINTER = 1,
|
||||
};
|
||||
|
||||
uint256 SignatureHash(
|
||||
const CScript &scriptCode,
|
||||
const CTransaction& txTo,
|
||||
unsigned int nIn,
|
||||
int nHashType,
|
||||
const CAmount& amount,
|
||||
uint32_t consensusBranchId,
|
||||
const PrecomputedTransactionData* cache = NULL);
|
||||
|
||||
class BaseSignatureChecker
|
||||
{
|
||||
public:
|
||||
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
|
||||
virtual bool CheckSig(
|
||||
const std::vector<unsigned char>& scriptSig,
|
||||
const std::vector<unsigned char>& vchPubKey,
|
||||
const CScript& scriptCode,
|
||||
uint32_t consensusBranchId) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -102,22 +128,39 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual int CheckCryptoCondition(
|
||||
const std::vector<unsigned char>& condBin,
|
||||
const std::vector<unsigned char>& ffillBin,
|
||||
const CScript& scriptCode,
|
||||
uint32_t consensusBranchId) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual ~BaseSignatureChecker() {}
|
||||
};
|
||||
|
||||
class TransactionSignatureChecker : public BaseSignatureChecker
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
const CTransaction* txTo;
|
||||
unsigned int nIn;
|
||||
const CAmount amount;
|
||||
const PrecomputedTransactionData* txdata;
|
||||
|
||||
protected:
|
||||
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
|
||||
public:
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
|
||||
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
|
||||
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const;
|
||||
bool CheckLockTime(const CScriptNum& nLockTime) const;
|
||||
int CheckCryptoCondition(
|
||||
const std::vector<unsigned char>& condBin,
|
||||
const std::vector<unsigned char>& ffillBin,
|
||||
const CScript& scriptCode,
|
||||
uint32_t consensusBranchId) const;
|
||||
virtual int CheckEvalCondition(const CC *cond) const;
|
||||
};
|
||||
|
||||
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
@@ -126,10 +169,22 @@ private:
|
||||
const CTransaction txTo;
|
||||
|
||||
public:
|
||||
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), txTo(*txToIn) {}
|
||||
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
|
||||
};
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
|
||||
bool EvalScript(
|
||||
std::vector<std::vector<unsigned char> >& stack,
|
||||
const CScript& script,
|
||||
unsigned int flags,
|
||||
const BaseSignatureChecker& checker,
|
||||
uint32_t consensusBranchId,
|
||||
ScriptError* error = NULL);
|
||||
bool VerifyScript(
|
||||
const CScript& scriptSig,
|
||||
const CScript& scriptPubKey,
|
||||
unsigned int flags,
|
||||
const BaseSignatureChecker& checker,
|
||||
uint32_t consensusBranchId,
|
||||
ScriptError* serror = NULL);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_INTERPRETER_H
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "tinyformat.h"
|
||||
#include "utilstrencodings.h"
|
||||
#include "script/cc.h"
|
||||
#include "cryptoconditions/include/cryptoconditions.h"
|
||||
|
||||
namespace {
|
||||
inline std::string ValueString(const std::vector<unsigned char>& vch)
|
||||
@@ -138,8 +140,11 @@ const char* GetOpName(opcodetype opcode)
|
||||
case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
|
||||
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
|
||||
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
|
||||
case OP_CHECKCRYPTOCONDITION : return "OP_CHECKCRYPTOCONDITION";
|
||||
case OP_CHECKCRYPTOCONDITIONVERIFY
|
||||
: return "OP_CHECKCRYPTOCONDITIONVERIFY";
|
||||
|
||||
// expanson
|
||||
// expansion
|
||||
case OP_NOP1 : return "OP_NOP1";
|
||||
case OP_NOP2 : return "OP_NOP2";
|
||||
case OP_NOP3 : return "OP_NOP3";
|
||||
@@ -220,6 +225,36 @@ bool CScript::IsPayToScriptHash() const
|
||||
this->at(22) == OP_EQUAL);
|
||||
}
|
||||
|
||||
bool CScript::IsPayToCryptoCondition() const
|
||||
{
|
||||
const_iterator pc = this->begin();
|
||||
vector<unsigned char> data;
|
||||
opcodetype opcode;
|
||||
if (this->GetOp(pc, opcode, data))
|
||||
// Sha256 conditions are <76 bytes
|
||||
if (opcode > OP_0 && opcode < OP_PUSHDATA1)
|
||||
if (this->GetOp(pc, opcode, data))
|
||||
if (opcode == OP_CHECKCRYPTOCONDITION)
|
||||
if (pc == this->end())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CScript::MayAcceptCryptoCondition() const
|
||||
{
|
||||
// Get the type mask of the condition
|
||||
const_iterator pc = this->begin();
|
||||
vector<unsigned char> data;
|
||||
opcodetype opcode;
|
||||
if (!this->GetOp(pc, opcode, data)) return false;
|
||||
if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) return false;
|
||||
CC *cond = cc_readConditionBinary(data.data(), data.size());
|
||||
if (!cond) return false;
|
||||
bool out = IsSupportedCryptoCondition(cond);
|
||||
cc_free(cond);
|
||||
return out;
|
||||
}
|
||||
|
||||
bool CScript::IsPushOnly() const
|
||||
{
|
||||
const_iterator pc = begin();
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
|
||||
|
||||
// Max size of pushdata in a CC sig in bytes
|
||||
static const unsigned int MAX_SCRIPT_CRYPTOCONDITION_FULFILLMENT_SIZE = 2048;
|
||||
|
||||
// Maximum script length in bytes
|
||||
static const int MAX_SCRIPT_SIZE = 10000;
|
||||
|
||||
@@ -154,6 +157,8 @@ enum opcodetype
|
||||
OP_CHECKSIGVERIFY = 0xad,
|
||||
OP_CHECKMULTISIG = 0xae,
|
||||
OP_CHECKMULTISIGVERIFY = 0xaf,
|
||||
OP_CHECKCRYPTOCONDITION = 0xcc,
|
||||
OP_CHECKCRYPTOCONDITIONVERIFY = 0xcd,
|
||||
|
||||
// expansion
|
||||
OP_NOP1 = 0xb0,
|
||||
@@ -168,13 +173,13 @@ enum opcodetype
|
||||
OP_NOP9 = 0xb8,
|
||||
OP_NOP10 = 0xb9,
|
||||
|
||||
|
||||
// template matching params
|
||||
OP_SMALLDATA = 0xf9,
|
||||
OP_SMALLINTEGER = 0xfa,
|
||||
OP_PUBKEYS = 0xfb,
|
||||
OP_PUBKEYHASH = 0xfd,
|
||||
OP_PUBKEY = 0xfe,
|
||||
OP_CRYPTOCONDITION = 0xfc,
|
||||
|
||||
OP_INVALIDOPCODE = 0xff,
|
||||
};
|
||||
@@ -562,6 +567,8 @@ public:
|
||||
unsigned int GetSigOpCount(const CScript& scriptSig) const;
|
||||
|
||||
bool IsPayToScriptHash() const;
|
||||
bool IsPayToCryptoCondition() const;
|
||||
bool MayAcceptCryptoCondition() const;
|
||||
|
||||
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
||||
bool IsPushOnly() const;
|
||||
|
||||
@@ -67,6 +67,8 @@ const char* ScriptErrorString(const ScriptError serror)
|
||||
return "NOPx reserved for soft-fork upgrades";
|
||||
case SCRIPT_ERR_PUBKEYTYPE:
|
||||
return "Public key is neither compressed or uncompressed";
|
||||
case SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT:
|
||||
return "Crypto-Condition payload is invalid";
|
||||
case SCRIPT_ERR_UNKNOWN_ERROR:
|
||||
case SCRIPT_ERR_ERROR_COUNT:
|
||||
default: break;
|
||||
|
||||
@@ -52,7 +52,11 @@ typedef enum ScriptError_t
|
||||
/* softfork safeness */
|
||||
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS,
|
||||
|
||||
SCRIPT_ERR_ERROR_COUNT
|
||||
SCRIPT_ERR_ERROR_COUNT,
|
||||
|
||||
/* crypto-condition script errors */
|
||||
SCRIPT_ERR_CRYPTOCONDITION_VERIFY,
|
||||
SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT
|
||||
} ScriptError;
|
||||
|
||||
#define SCRIPT_ERR_LAST SCRIPT_ERR_ERROR_COUNT
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "sigcache.h"
|
||||
#include "serverchecker.h"
|
||||
#include "script/cc.h"
|
||||
#include "cc/eval.h"
|
||||
|
||||
#include "pubkey.h"
|
||||
#include "random.h"
|
||||
@@ -26,13 +28,13 @@ private:
|
||||
//! sigdata_type is (signature hash, signature, public key):
|
||||
typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
|
||||
std::set< sigdata_type> setValid;
|
||||
boost::shared_mutex cs_sigcache;
|
||||
boost::shared_mutex cs_serverchecker;
|
||||
|
||||
public:
|
||||
bool
|
||||
Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
|
||||
boost::shared_lock<boost::shared_mutex> lock(cs_serverchecker);
|
||||
|
||||
sigdata_type k(hash, vchSig, pubKey);
|
||||
std::set<sigdata_type>::iterator mi = setValid.find(k);
|
||||
@@ -45,12 +47,12 @@ public:
|
||||
{
|
||||
// DoS prevention: limit cache size to less than 10MB
|
||||
// (~200 bytes per cache entry times 50,000 entries)
|
||||
// Since there are a maximum of 20,000 signature operations per block
|
||||
// Since there can be no more than 20,000 signature operations per block
|
||||
// 50,000 is a reasonable default.
|
||||
int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
|
||||
int64_t nMaxCacheSize = GetArg("-maxservercheckersize", 50000);
|
||||
if (nMaxCacheSize <= 0) return;
|
||||
|
||||
boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
|
||||
boost::unique_lock<boost::shared_mutex> lock(cs_serverchecker);
|
||||
|
||||
while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize)
|
||||
{
|
||||
@@ -74,7 +76,7 @@ public:
|
||||
|
||||
}
|
||||
|
||||
bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
bool ServerTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
static CSignatureCache signatureCache;
|
||||
|
||||
@@ -88,3 +90,17 @@ bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsig
|
||||
signatureCache.Set(sighash, vchSig, pubkey);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The reason that these functions are here is that the what used to be the
|
||||
* CachingTransactionSignatureChecker, now the ServerTransactionSignatureChecker,
|
||||
* is an entry point that the server uses to validate signatures and which is not
|
||||
* included as part of bitcoin common libs. Since Crypto-Condtions eval methods
|
||||
* may call server code (GetTransaction etc), the best way to get it to run this
|
||||
* code without pulling the whole bitcoin server code into bitcoin common was
|
||||
* using this class. Thus it has been renamed to ServerTransactionSignatureChecker.
|
||||
*/
|
||||
int ServerTransactionSignatureChecker::CheckEvalCondition(const CC *cond) const
|
||||
{
|
||||
return RunCCEval(cond, *txTo, nIn);
|
||||
}
|
||||
27
src/script/serverchecker.h
Normal file
27
src/script/serverchecker.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 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_SERVERCHECKER_H
|
||||
#define BITCOIN_SCRIPT_SERVERCHECKER_H
|
||||
|
||||
#include "script/interpreter.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class CPubKey;
|
||||
|
||||
class ServerTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
{
|
||||
private:
|
||||
bool store;
|
||||
|
||||
public:
|
||||
ServerTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nIn, amount, txdataIn), store(storeIn) {}
|
||||
|
||||
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
int CheckEvalCondition(const CC *cond) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SERVERCHECKER_H
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 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_SIGCACHE_H
|
||||
#define BITCOIN_SCRIPT_SIGCACHE_H
|
||||
|
||||
#include "script/interpreter.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class CPubKey;
|
||||
|
||||
class CachingTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
{
|
||||
private:
|
||||
bool store;
|
||||
|
||||
public:
|
||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn), store(storeIn) {}
|
||||
|
||||
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SIGCACHE_H
|
||||
@@ -17,9 +17,9 @@ using namespace std;
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
|
||||
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {}
|
||||
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
|
||||
|
||||
bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode) const
|
||||
bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId) const
|
||||
{
|
||||
CKey key;
|
||||
if (!keystore->GetKey(address, key))
|
||||
@@ -27,7 +27,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
|
||||
|
||||
uint256 hash;
|
||||
try {
|
||||
hash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
|
||||
hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId);
|
||||
} catch (logic_error ex) {
|
||||
return false;
|
||||
}
|
||||
@@ -38,16 +38,16 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
|
||||
static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, uint32_t consensusBranchId)
|
||||
{
|
||||
vector<unsigned char> vchSig;
|
||||
if (!creator.CreateSig(vchSig, address, scriptCode))
|
||||
if (!creator.CreateSig(vchSig, address, scriptCode, consensusBranchId))
|
||||
return false;
|
||||
scriptSigRet << vchSig;
|
||||
ret.push_back(vchSig);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
|
||||
static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, uint32_t consensusBranchId)
|
||||
{
|
||||
int nSigned = 0;
|
||||
int nRequired = multisigdata.front()[0];
|
||||
@@ -55,7 +55,7 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
|
||||
{
|
||||
const valtype& pubkey = multisigdata[i];
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
if (Sign1(keyID, creator, scriptCode, scriptSigRet))
|
||||
if (Sign1(keyID, creator, scriptCode, ret, consensusBranchId))
|
||||
++nSigned;
|
||||
}
|
||||
return nSigned==nRequired;
|
||||
@@ -68,9 +68,11 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
|
||||
* Returns false if scriptPubKey could not be completely satisfied.
|
||||
*/
|
||||
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
|
||||
CScript& scriptSigRet, txnouttype& whichTypeRet)
|
||||
std::vector<valtype>& ret, txnouttype& whichTypeRet, uint32_t consensusBranchId)
|
||||
{
|
||||
scriptSigRet.clear();
|
||||
CScript scriptRet;
|
||||
uint160 h160;
|
||||
ret.clear();
|
||||
|
||||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
||||
@@ -84,85 +86,127 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
|
||||
return false;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
return Sign1(keyID, creator, scriptPubKey, scriptSigRet);
|
||||
return Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId);
|
||||
case TX_PUBKEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet))
|
||||
if (!Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
CPubKey vch;
|
||||
creator.KeyStore().GetPubKey(keyID, vch);
|
||||
scriptSigRet << ToByteVector(vch);
|
||||
ret.push_back(ToByteVector(vch));
|
||||
}
|
||||
return true;
|
||||
case TX_SCRIPTHASH:
|
||||
return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet);
|
||||
|
||||
case TX_MULTISIG:
|
||||
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
|
||||
return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig)
|
||||
{
|
||||
txnouttype whichType;
|
||||
if (!SignStep(creator, fromPubKey, scriptSig, whichType))
|
||||
if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) {
|
||||
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
if (whichType == TX_SCRIPTHASH)
|
||||
case TX_MULTISIG:
|
||||
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
|
||||
return (SignN(vSolutions, creator, scriptPubKey, ret, consensusBranchId));
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static CScript PushAll(const vector<valtype>& values)
|
||||
{
|
||||
CScript result;
|
||||
BOOST_FOREACH(const valtype& v, values) {
|
||||
if (v.size() == 0) {
|
||||
result << OP_0;
|
||||
} else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) {
|
||||
result << CScript::EncodeOP_N(v[0]);
|
||||
} else {
|
||||
result << v;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata, uint32_t consensusBranchId)
|
||||
{
|
||||
CScript script = fromPubKey;
|
||||
bool solved = true;
|
||||
std::vector<valtype> result;
|
||||
txnouttype whichType;
|
||||
solved = SignStep(creator, script, result, whichType, consensusBranchId);
|
||||
CScript subscript;
|
||||
|
||||
if (solved && whichType == TX_SCRIPTHASH)
|
||||
{
|
||||
// Solver returns the subscript that need to be evaluated;
|
||||
// Solver returns the subscript that needs to be evaluated;
|
||||
// the final scriptSig is the signatures from that
|
||||
// and then the serialized subscript:
|
||||
CScript subscript = scriptSig;
|
||||
|
||||
txnouttype subType;
|
||||
bool fSolved =
|
||||
SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH;
|
||||
// Append serialized subscript whether or not it is completely signed:
|
||||
scriptSig << static_cast<valtype>(subscript);
|
||||
if (!fSolved) return false;
|
||||
script = subscript = CScript(result[0].begin(), result[0].end());
|
||||
solved = solved && SignStep(creator, script, result, whichType, consensusBranchId) && whichType != TX_SCRIPTHASH;
|
||||
result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end()));
|
||||
}
|
||||
|
||||
sigdata.scriptSig = PushAll(result);
|
||||
|
||||
// Test solution
|
||||
return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
|
||||
return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker(), consensusBranchId);
|
||||
}
|
||||
|
||||
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn)
|
||||
{
|
||||
SignatureData data;
|
||||
assert(tx.vin.size() > nIn);
|
||||
data.scriptSig = tx.vin[nIn].scriptSig;
|
||||
return data;
|
||||
}
|
||||
|
||||
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data)
|
||||
{
|
||||
assert(tx.vin.size() > nIn);
|
||||
tx.vin[nIn].scriptSig = data.scriptSig;
|
||||
}
|
||||
|
||||
bool SignSignature(
|
||||
const CKeyStore &keystore,
|
||||
const CScript& fromPubKey,
|
||||
CMutableTransaction& txTo,
|
||||
unsigned int nIn,
|
||||
const CAmount& amount,
|
||||
int nHashType,
|
||||
uint32_t consensusBranchId)
|
||||
{
|
||||
assert(nIn < txTo.vin.size());
|
||||
CTxIn& txin = txTo.vin[nIn];
|
||||
|
||||
CTransaction txToConst(txTo);
|
||||
TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType);
|
||||
TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType);
|
||||
|
||||
return ProduceSignature(creator, fromPubKey, txin.scriptSig);
|
||||
SignatureData sigdata;
|
||||
bool ret = ProduceSignature(creator, fromPubKey, sigdata, consensusBranchId);
|
||||
UpdateTransaction(txTo, nIn, sigdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
bool SignSignature(
|
||||
const CKeyStore &keystore,
|
||||
const CTransaction& txFrom,
|
||||
CMutableTransaction& txTo,
|
||||
unsigned int nIn,
|
||||
int nHashType,
|
||||
uint32_t consensusBranchId)
|
||||
{
|
||||
assert(nIn < txTo.vin.size());
|
||||
CTxIn& txin = txTo.vin[nIn];
|
||||
assert(txin.prevout.n < txFrom.vout.size());
|
||||
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
||||
|
||||
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
|
||||
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, consensusBranchId);
|
||||
}
|
||||
|
||||
static CScript PushAll(const vector<valtype>& values)
|
||||
{
|
||||
CScript result;
|
||||
BOOST_FOREACH(const valtype& v, values)
|
||||
result << v;
|
||||
return result;
|
||||
}
|
||||
|
||||
static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
||||
static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
||||
const vector<valtype>& vSolutions,
|
||||
const vector<valtype>& sigs1, const vector<valtype>& sigs2)
|
||||
const vector<valtype>& sigs1, const vector<valtype>& sigs2, uint32_t consensusBranchId)
|
||||
{
|
||||
// Combine all the signatures we've got:
|
||||
set<valtype> allsigs;
|
||||
@@ -190,7 +234,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
|
||||
if (sigs.count(pubkey))
|
||||
continue; // Already got a sig for this pubkey
|
||||
|
||||
if (checker.CheckSig(sig, pubkey, scriptPubKey))
|
||||
if (checker.CheckSig(sig, pubkey, scriptPubKey, consensusBranchId))
|
||||
{
|
||||
sigs[pubkey] = sig;
|
||||
break;
|
||||
@@ -199,87 +243,100 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
|
||||
}
|
||||
// Now build a merged CScript:
|
||||
unsigned int nSigsHave = 0;
|
||||
CScript result; result << OP_0; // pop-one-too-many workaround
|
||||
std::vector<valtype> result; result.push_back(valtype()); // pop-one-too-many workaround
|
||||
for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
|
||||
{
|
||||
if (sigs.count(vSolutions[i+1]))
|
||||
{
|
||||
result << sigs[vSolutions[i+1]];
|
||||
result.push_back(sigs[vSolutions[i+1]]);
|
||||
++nSigsHave;
|
||||
}
|
||||
}
|
||||
// Fill any missing with OP_0:
|
||||
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
|
||||
result << OP_0;
|
||||
result.push_back(valtype());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
||||
namespace
|
||||
{
|
||||
struct Stacks
|
||||
{
|
||||
std::vector<valtype> script;
|
||||
|
||||
Stacks() {}
|
||||
explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_) {}
|
||||
explicit Stacks(const SignatureData& data, uint32_t consensusBranchId) {
|
||||
EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), consensusBranchId);
|
||||
}
|
||||
|
||||
SignatureData Output() const {
|
||||
SignatureData result;
|
||||
result.scriptSig = PushAll(script);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
||||
const txnouttype txType, const vector<valtype>& vSolutions,
|
||||
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
||||
Stacks sigs1, Stacks sigs2, uint32_t consensusBranchId)
|
||||
{
|
||||
switch (txType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
// Don't know anything about this, assume bigger one is correct:
|
||||
if (sigs1.size() >= sigs2.size())
|
||||
return PushAll(sigs1);
|
||||
return PushAll(sigs2);
|
||||
if (sigs1.script.size() >= sigs2.script.size())
|
||||
return sigs1;
|
||||
return sigs2;
|
||||
case TX_PUBKEY:
|
||||
case TX_PUBKEYHASH:
|
||||
// Signatures are bigger than placeholders or empty scripts:
|
||||
if (sigs1.empty() || sigs1[0].empty())
|
||||
return PushAll(sigs2);
|
||||
return PushAll(sigs1);
|
||||
if (sigs1.script.empty() || sigs1.script[0].empty())
|
||||
return sigs2;
|
||||
return sigs1;
|
||||
case TX_SCRIPTHASH:
|
||||
if (sigs1.empty() || sigs1.back().empty())
|
||||
return PushAll(sigs2);
|
||||
else if (sigs2.empty() || sigs2.back().empty())
|
||||
return PushAll(sigs1);
|
||||
if (sigs1.script.empty() || sigs1.script.back().empty())
|
||||
return sigs2;
|
||||
else if (sigs2.script.empty() || sigs2.script.back().empty())
|
||||
return sigs1;
|
||||
else
|
||||
{
|
||||
// Recur to combine:
|
||||
valtype spk = sigs1.back();
|
||||
valtype spk = sigs1.script.back();
|
||||
CScript pubKey2(spk.begin(), spk.end());
|
||||
|
||||
txnouttype txType2;
|
||||
vector<vector<unsigned char> > vSolutions2;
|
||||
Solver(pubKey2, txType2, vSolutions2);
|
||||
sigs1.pop_back();
|
||||
sigs2.pop_back();
|
||||
CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2);
|
||||
result << spk;
|
||||
sigs1.script.pop_back();
|
||||
sigs2.script.pop_back();
|
||||
Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, consensusBranchId);
|
||||
result.script.push_back(spk);
|
||||
return result;
|
||||
}
|
||||
case TX_MULTISIG:
|
||||
return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2);
|
||||
return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, consensusBranchId));
|
||||
default:
|
||||
return Stacks();
|
||||
}
|
||||
|
||||
return CScript();
|
||||
}
|
||||
|
||||
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
const CScript& scriptSig1, const CScript& scriptSig2)
|
||||
{
|
||||
TransactionSignatureChecker checker(&txTo, nIn);
|
||||
return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2);
|
||||
}
|
||||
|
||||
CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
||||
const CScript& scriptSig1, const CScript& scriptSig2)
|
||||
SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
||||
const SignatureData& scriptSig1, const SignatureData& scriptSig2,
|
||||
uint32_t consensusBranchId)
|
||||
{
|
||||
txnouttype txType;
|
||||
vector<vector<unsigned char> > vSolutions;
|
||||
Solver(scriptPubKey, txType, vSolutions);
|
||||
|
||||
vector<valtype> stack1;
|
||||
EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
|
||||
vector<valtype> stack2;
|
||||
EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
|
||||
|
||||
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
|
||||
return CombineSignatures(
|
||||
scriptPubKey, checker, txType, vSolutions,
|
||||
Stacks(scriptSig1, consensusBranchId),
|
||||
Stacks(scriptSig2, consensusBranchId),
|
||||
consensusBranchId).Output();
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -289,7 +346,11 @@ class DummySignatureChecker : public BaseSignatureChecker
|
||||
public:
|
||||
DummySignatureChecker() {}
|
||||
|
||||
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
|
||||
bool CheckSig(
|
||||
const std::vector<unsigned char>& scriptSig,
|
||||
const std::vector<unsigned char>& vchPubKey,
|
||||
const CScript& scriptCode,
|
||||
uint32_t consensusBranchId) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -302,7 +363,11 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const
|
||||
return dummyChecker;
|
||||
}
|
||||
|
||||
bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const
|
||||
bool DummySignatureCreator::CreateSig(
|
||||
std::vector<unsigned char>& vchSig,
|
||||
const CKeyID& keyid,
|
||||
const CScript& scriptCode,
|
||||
uint32_t consensusBranchId) const
|
||||
{
|
||||
// Create a dummy signature that is a valid DER-encoding
|
||||
vchSig.assign(72, '\000');
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
virtual const BaseSignatureChecker& Checker() const =0;
|
||||
|
||||
/** Create a singular (non-script) signature. */
|
||||
virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const =0;
|
||||
virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const =0;
|
||||
};
|
||||
|
||||
/** A signature creator for transactions. */
|
||||
@@ -35,33 +35,67 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
|
||||
const CTransaction* txTo;
|
||||
unsigned int nIn;
|
||||
int nHashType;
|
||||
CAmount amount;
|
||||
const TransactionSignatureChecker checker;
|
||||
|
||||
public:
|
||||
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn=SIGHASH_ALL);
|
||||
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
|
||||
const BaseSignatureChecker& Checker() const { return checker; }
|
||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
|
||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const;
|
||||
};
|
||||
|
||||
/** A signature creator that just produces 72-byte empty signatyres. */
|
||||
class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
|
||||
CTransaction tx;
|
||||
|
||||
public:
|
||||
MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
|
||||
};
|
||||
|
||||
/** A signature creator that just produces 72-byte empty signatures. */
|
||||
class DummySignatureCreator : public BaseSignatureCreator {
|
||||
public:
|
||||
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
|
||||
const BaseSignatureChecker& Checker() const;
|
||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
|
||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const;
|
||||
};
|
||||
|
||||
struct SignatureData {
|
||||
CScript scriptSig;
|
||||
|
||||
SignatureData() {}
|
||||
explicit SignatureData(const CScript& script) : scriptSig(script) {}
|
||||
};
|
||||
|
||||
/** Produce a script signature using a generic signature creator. */
|
||||
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig);
|
||||
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata, uint32_t consensusBranchId);
|
||||
|
||||
/** Produce a script signature for a transaction. */
|
||||
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
bool SignSignature(
|
||||
const CKeyStore &keystore,
|
||||
const CScript& fromPubKey,
|
||||
CMutableTransaction& txTo,
|
||||
unsigned int nIn,
|
||||
const CAmount& amount,
|
||||
int nHashType,
|
||||
uint32_t consensusBranchId);
|
||||
bool SignSignature(
|
||||
const CKeyStore& keystore,
|
||||
const CTransaction& txFrom,
|
||||
CMutableTransaction& txTo,
|
||||
unsigned int nIn,
|
||||
int nHashType,
|
||||
uint32_t consensusBranchId);
|
||||
|
||||
/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */
|
||||
CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const CScript& scriptSig1, const CScript& scriptSig2);
|
||||
SignatureData CombineSignatures(
|
||||
const CScript& scriptPubKey,
|
||||
const BaseSignatureChecker& checker,
|
||||
const SignatureData& scriptSig1,
|
||||
const SignatureData& scriptSig2,
|
||||
uint32_t consensusBranchId);
|
||||
|
||||
/** Combine two script signatures on transactions. */
|
||||
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
|
||||
/** Extract signature data from a transaction, and insert it. */
|
||||
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);
|
||||
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SIGN_H
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "script/script.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
#include "script/cc.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
@@ -68,6 +69,17 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsCryptoConditionsEnabled()) {
|
||||
// Shortcut for pay-to-crypto-condition
|
||||
if (scriptPubKey.IsPayToCryptoCondition()) {
|
||||
if (scriptPubKey.MayAcceptCryptoCondition()) {
|
||||
typeRet = TX_CRYPTOCONDITION;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan templates
|
||||
const CScript& script1 = scriptPubKey;
|
||||
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
||||
@@ -179,6 +191,8 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
|
||||
return vSolutions[0][0] + 1;
|
||||
case TX_SCRIPTHASH:
|
||||
return 1; // doesn't include args needed by the script
|
||||
case TX_CRYPTOCONDITION:
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -31,9 +31,8 @@ extern unsigned nMaxDatacarrierBytes;
|
||||
/**
|
||||
* Mandatory script verification flags that all new blocks must comply with for
|
||||
* them to be valid. (but old blocks may not comply with) Currently just P2SH,
|
||||
* but in the future other flags may be added, such as a soft-fork to enforce
|
||||
* strict DER encoding.
|
||||
*
|
||||
* but in the future other flags may be added.
|
||||
*
|
||||
* Failing one of these tests may trigger a DoS ban - see CheckInputs() for
|
||||
* details.
|
||||
*/
|
||||
@@ -45,7 +44,7 @@ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
||||
* blocks and we must accept those blocks.
|
||||
*/
|
||||
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||
SCRIPT_VERIFY_DERSIG |
|
||||
// SCRIPT_VERIFY_DERSIG is always enforced
|
||||
SCRIPT_VERIFY_STRICTENC |
|
||||
SCRIPT_VERIFY_MINIMALDATA |
|
||||
SCRIPT_VERIFY_NULLDUMMY |
|
||||
@@ -65,6 +64,7 @@ enum txnouttype
|
||||
TX_PUBKEYHASH,
|
||||
TX_SCRIPTHASH,
|
||||
TX_MULTISIG,
|
||||
TX_CRYPTOCONDITION,
|
||||
TX_NULL_DATA,
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
#include "zcashconsensus.h"
|
||||
|
||||
#include "consensus/upgrades.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "pubkey.h"
|
||||
#include "script/interpreter.h"
|
||||
#include "version.h"
|
||||
|
||||
@@ -60,7 +62,13 @@ inline int set_error(zcashconsensus_error* ret, zcashconsensus_error serror)
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
struct ECCryptoClosure
|
||||
{
|
||||
ECCVerifyHandle handle;
|
||||
};
|
||||
|
||||
ECCryptoClosure instance_of_eccryptoclosure;
|
||||
}
|
||||
|
||||
int zcashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
@@ -77,8 +85,16 @@ int zcashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int
|
||||
|
||||
// Regardless of the verification result, the tx did not error.
|
||||
set_error(err, zcashconsensus_ERR_OK);
|
||||
|
||||
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn), NULL);
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
CAmount am(0);
|
||||
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||
return VerifyScript(
|
||||
tx.vin[nIn].scriptSig,
|
||||
CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen),
|
||||
flags,
|
||||
TransactionSignatureChecker(&tx, nIn, am, txdata),
|
||||
consensusBranchId,
|
||||
NULL);
|
||||
} catch (const std::exception&) {
|
||||
return set_error(err, zcashconsensus_ERR_TX_DESERIALIZE); // Error deserializing
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#ifndef BITCOIN_ZCASHCONSENSUS_H
|
||||
#define BITCOIN_ZCASHCONSENSUS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "config/bitcoin-config.h"
|
||||
#if defined(_WIN32)
|
||||
@@ -46,7 +48,6 @@ enum
|
||||
{
|
||||
zcashconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
|
||||
zcashconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
|
||||
zcashconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
|
||||
zcashconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user