Beginning of N@S solution using CoinbaseGuard CC
This commit is contained in:
@@ -10,6 +10,8 @@
|
||||
#include "keystore.h"
|
||||
#include "script/standard.h"
|
||||
#include "uint256.h"
|
||||
#include "cc/CCinclude.h"
|
||||
#include "cc/eval.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
@@ -19,10 +21,12 @@ typedef std::vector<unsigned char> valtype;
|
||||
|
||||
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, uint32_t consensusBranchId) const
|
||||
bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId, CKey *pprivKey, void *extraData) const
|
||||
{
|
||||
CKey key;
|
||||
if (!keystore->GetKey(address, key))
|
||||
if (pprivKey)
|
||||
key = *pprivKey;
|
||||
else if (!keystore->GetKey(address, key))
|
||||
return false;
|
||||
|
||||
uint256 hash;
|
||||
@@ -32,8 +36,19 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!key.Sign(hash, vchSig))
|
||||
return false;
|
||||
if (scriptCode.IsPayToCryptoCondition())
|
||||
{
|
||||
CC *cc = (CC *)extraData;
|
||||
// assume either 1of1 or 1of2. if the condition created by the
|
||||
if (!cc || cc_signTreeSecp256k1Msg32(cc, key.begin(), hash.begin()) == 0)
|
||||
return false;
|
||||
vchSig = CCSigVec(cc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!key.Sign(hash, vchSig))
|
||||
return false;
|
||||
}
|
||||
vchSig.push_back((unsigned char)nHashType);
|
||||
return true;
|
||||
}
|
||||
@@ -61,6 +76,201 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
|
||||
return nSigned==nRequired;
|
||||
}
|
||||
|
||||
CC *CCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2)
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk1));
|
||||
pks.push_back(CCNewSecp256k1(pk2));
|
||||
CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
|
||||
CC *Sig = CCNewThreshold(1, pks);
|
||||
return CCNewThreshold(2, {condCC, Sig});
|
||||
}
|
||||
|
||||
CC *CCcond1(uint8_t evalcode,CPubKey pk)
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk));
|
||||
CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
|
||||
CC *Sig = CCNewThreshold(1, pks);
|
||||
return CCNewThreshold(2, {condCC, Sig});
|
||||
}
|
||||
|
||||
bool CCinitLite(struct CCcontract_info *cp, uint8_t evalcode)
|
||||
{
|
||||
cp->evalcode = evalcode;
|
||||
switch ( evalcode )
|
||||
{
|
||||
case EVAL_COINBASEGUARD:
|
||||
uint8_t privKey[32] = { 0x9b, 0x17, 0x66, 0xe5, 0x82, 0x66, 0xac, 0xb6, 0xba, 0x43, 0x83, 0x74, 0xf7, 0x63, 0x11, 0x3b, 0xf0, 0xf3, 0x50, 0x6f, 0xd9, 0x6b, 0x67, 0x85, 0xf9, 0x7a, 0xf0, 0x54, 0x4d, 0xb1, 0x30, 0x77 };
|
||||
strcpy(cp->unspendableCCaddr,"RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6");
|
||||
strcpy(cp->normaladdr,"RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u");
|
||||
strcpy(cp->CChexstr,"02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702");
|
||||
memcpy(cp->CCpriv, privKey,32);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool SignStepCC(const BaseSignatureCreator& creator, const CScript& scriptPubKey, vector<valtype> &vSolutions,
|
||||
vector<valtype>& ret, uint32_t consensusBranchId)
|
||||
{
|
||||
CScript subScript;
|
||||
vector<CPubKey> vPK;
|
||||
vector<CKeyID> vKeyID = vector<CKeyID>();
|
||||
vector<valtype> vParams = vector<valtype>();
|
||||
COptCCParams p;
|
||||
|
||||
scriptPubKey.IsPayToCryptoCondition(&subScript, vParams);
|
||||
if (vParams.size() > 1 && (p = COptCCParams(vParams[0])).IsValid())
|
||||
{
|
||||
bool is1of2 = (p.n == 1 && p.m == 1);
|
||||
uint32_t extraAddrs = p.m;
|
||||
CKey privKey;
|
||||
|
||||
// get information to sign with
|
||||
CCcontract_info C;
|
||||
|
||||
// must be a valid cc eval code
|
||||
if (CCinitLite(&C, p.evalCode))
|
||||
{
|
||||
// pay to cc address is a valid tx
|
||||
if (!is1of2)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!extraAddrs)
|
||||
{
|
||||
vKeyID.push_back(CKeyID(uint160(vSolutions[0])));
|
||||
// if this isn't our main CC address, we can't do anything with it
|
||||
if (strcmp(C.unspendableCCaddr, CBitcoinAddress(CTxDestination(vKeyID[0])).ToString().c_str()) != 0)
|
||||
return false;
|
||||
|
||||
// otherwise, push back the corresponding pub key
|
||||
vPK.push_back(CPubKey(ParseHex(C.CChexstr)));
|
||||
}
|
||||
else if (vParams.size() >= (extraAddrs + 1))
|
||||
{
|
||||
bool havePriv;
|
||||
vKeyID.push_back(CKeyID(uint160(vParams[1])));
|
||||
// if this isn't the normal CC address and we also don't have it in our keystore, fail
|
||||
CBitcoinAddress addr = CBitcoinAddress(CTxDestination(vKeyID[0]));
|
||||
if (strcmp(C.normaladdr, addr.ToString().c_str()) == 0 &&
|
||||
!(havePriv = creator.KeyStore().GetKey(vKeyID[0], privKey)))
|
||||
return false;
|
||||
|
||||
vPK.push_back(CPubKey());
|
||||
|
||||
// if we don't have the private key, it is the unspendable address
|
||||
if (!havePriv)
|
||||
{
|
||||
vPK[0] = CPubKey(ParseHex(C.CChexstr));
|
||||
privKey = CKey();
|
||||
CPrivKey vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv));
|
||||
privKey.SetPrivKey(vch, false);
|
||||
}
|
||||
else if (!creator.KeyStore().GetPubKey(vKeyID[0], vPK[0]))
|
||||
return false;
|
||||
}
|
||||
} catch (...)
|
||||
{
|
||||
fprintf(stderr,"exception calculating 1of1 spend\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
CC *cc = CCcond1(p.evalCode, vPK[0]);
|
||||
|
||||
if (cc)
|
||||
{
|
||||
vector<unsigned char> vch;
|
||||
if (creator.CreateSig(vch, vKeyID[0], scriptPubKey, consensusBranchId, &privKey, (void *)cc))
|
||||
{
|
||||
ret.push_back(vch);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"vin has 1of1 CC signing error with address.(%s)\n", vKeyID[0].ToString().c_str());
|
||||
}
|
||||
|
||||
cc_free(cc);
|
||||
return ret.size() != 0;
|
||||
}
|
||||
}
|
||||
else if (extraAddrs > 1 && vParams.size() >= (extraAddrs + 1))
|
||||
{
|
||||
// we need to get 2 addresses, and we will need the private key for one
|
||||
// to spend
|
||||
bool pkValid = false;
|
||||
for (int i = 0; i < extraAddrs; i++)
|
||||
{
|
||||
// loop through in order and choose the first key we have a priv key to for signing
|
||||
try
|
||||
{
|
||||
bool isCCAddr = false;
|
||||
CPubKey pk;
|
||||
vKeyID.push_back(CKeyID(uint160(vParams[i + 1])));
|
||||
|
||||
// if this isn't the CC address and we also don't have the pubkey in our keystore, fail, because we won't
|
||||
// be able to make the condition to fulfill
|
||||
if (!(isCCAddr = (strcmp(C.normaladdr, CBitcoinAddress(CTxDestination(vKeyID[0])).ToString().c_str()) == 0)) &&
|
||||
!creator.KeyStore().GetPubKey(vKeyID[0], pk))
|
||||
return false;
|
||||
|
||||
if (isCCAddr)
|
||||
{
|
||||
pk = CPubKey(ParseHex(C.CChexstr));
|
||||
// only set the private key to this address if we don't have one yet
|
||||
if (!pkValid)
|
||||
{
|
||||
privKey = CKey();
|
||||
CPrivKey vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv));
|
||||
privKey.SetPrivKey(vch, false);
|
||||
pkValid = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pkValid)
|
||||
{
|
||||
if (creator.KeyStore().GetKey(vKeyID[0], privKey))
|
||||
pkValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
vPK.push_back(pk);
|
||||
|
||||
} catch (...)
|
||||
{
|
||||
fprintf(stderr,"exception calculating 1of2 spend\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pkValid)
|
||||
return false;
|
||||
|
||||
CC *cc = CCcond1of2(p.evalCode, vPK[0], vPK[1]);
|
||||
|
||||
if (cc)
|
||||
{
|
||||
vector<unsigned char> vch;
|
||||
if (creator.CreateSig(vch, vKeyID[0], scriptPubKey, consensusBranchId, &privKey, (void *)cc))
|
||||
{
|
||||
ret.push_back(vch);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"vin has 1of2 CC signing error with address.(%s)\n", vKeyID[0].ToString().c_str());
|
||||
}
|
||||
|
||||
cc_free(cc);
|
||||
return ret.size() != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign scriptPubKey using signature made with creator.
|
||||
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
|
||||
@@ -96,6 +306,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
|
||||
}
|
||||
|
||||
CKeyID keyID;
|
||||
|
||||
switch (whichTypeRet)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
@@ -121,6 +332,9 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case TX_CRYPTOCONDITION:
|
||||
return SignStepCC(creator, scriptPubKey, vSolutions, ret, consensusBranchId);
|
||||
|
||||
case TX_MULTISIG:
|
||||
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
|
||||
@@ -384,7 +598,9 @@ bool DummySignatureCreator::CreateSig(
|
||||
std::vector<unsigned char>& vchSig,
|
||||
const CKeyID& keyid,
|
||||
const CScript& scriptCode,
|
||||
uint32_t consensusBranchId) const
|
||||
uint32_t consensusBranchId,
|
||||
CKey *key,
|
||||
void *extraData) const
|
||||
{
|
||||
// Create a dummy signature that is a valid DER-encoding
|
||||
vchSig.assign(72, '\000');
|
||||
|
||||
Reference in New Issue
Block a user