Browse Source

Beginning of N@S solution using CoinbaseGuard CC

pull/4/head
miketout 6 years ago
parent
commit
8a727a26a7
  1. 2
      src/Makefile.am
  2. 2
      src/cc/CCGateways.h
  3. 2
      src/cc/CCMofN.h
  4. 2
      src/cc/CCOracles.h
  5. 2
      src/cc/CCPayments.h
  6. 2
      src/cc/CCPegs.h
  7. 2
      src/cc/CCPrices.h
  8. 2
      src/cc/CCTriggers.h
  9. 2
      src/cc/CCassets.h
  10. 2
      src/cc/CCauction.h
  11. 2
      src/cc/CCchannels.h
  12. 12
      src/cc/CCcustom.cpp
  13. 2
      src/cc/CCdice.h
  14. 2
      src/cc/CCfaucet.h
  15. 2
      src/cc/CCfsm.h
  16. 19
      src/cc/CCinclude.h
  17. 2
      src/cc/CClotto.h
  18. 2
      src/cc/CCrewards.h
  19. 28
      src/cc/CCutils.cpp
  20. 254
      src/cc/CoinbaseGuard.cpp
  21. 47
      src/cc/CoinbaseGuard.h
  22. 2
      src/cc/MofN.cpp
  23. 2
      src/cc/assets.cpp
  24. 2
      src/cc/auction.cpp
  25. 2
      src/cc/channels.cpp
  26. 2
      src/cc/dice.cpp
  27. 11
      src/cc/eval.cpp
  28. 1
      src/cc/eval.h
  29. 2
      src/cc/faucet.cpp
  30. 2
      src/cc/fsm.cpp
  31. 2
      src/cc/gateways.cpp
  32. 2
      src/cc/lotto.cpp
  33. 2
      src/cc/oracles.cpp
  34. 2
      src/cc/payments.cpp
  35. 2
      src/cc/pegs.cpp
  36. 2
      src/cc/prices.cpp
  37. 2
      src/cc/rewards.cpp
  38. 2
      src/cc/triggers.cpp
  39. 2
      src/crypto/verus_hash.h
  40. 8
      src/script/cc.cpp
  41. 6
      src/script/cc.h
  42. 2
      src/script/interpreter.cpp
  43. 81
      src/script/script.cpp
  44. 7
      src/script/script.h
  45. 226
      src/script/sign.cpp
  46. 12
      src/script/sign.h
  47. 34
      src/script/standard.cpp
  48. 38
      src/script/standard.h
  49. 44
      src/wallet/wallet.cpp

2
src/Makefile.am

@ -289,6 +289,8 @@ libbitcoin_server_a_SOURCES = \
cc/CCcustom.cpp \
cc/CCtx.cpp \
cc/CCutils.cpp \
cc/CoinbaseGuard.cpp \
cc/CoinbaseGuard.h \
cc/assets.cpp \
cc/faucet.cpp \
cc/rewards.cpp \

2
src/cc/CCGateways.h

@ -20,7 +20,7 @@
#include "CCinclude.h"
#include "../merkleblock.h"
bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys);
std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount);
std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount);

2
src/cc/CCMofN.h

@ -21,7 +21,7 @@
#define EVAL_MOFN 0xea
bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue MofNInfo();

2
src/cc/CCOracles.h

@ -19,7 +19,7 @@
#include "CCinclude.h"
bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format);
std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee);
std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount);

2
src/cc/CCPayments.h

@ -19,7 +19,7 @@
#include "CCinclude.h"
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue PaymentsInfo();

2
src/cc/CCPegs.h

@ -19,7 +19,7 @@
#include "CCinclude.h"
bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue PegsInfo();

2
src/cc/CCPrices.h

@ -19,7 +19,7 @@
#include "CCinclude.h"
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue PricesInfo();

2
src/cc/CCTriggers.h

@ -19,7 +19,7 @@
#include "CCinclude.h"
bool TriggersValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool TriggersValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue TriggersInfo();

2
src/cc/CCassets.h

@ -26,7 +26,7 @@
#include "CCinclude.h"
// CCcustom
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCassetsCore
//CTxOut MakeAssetsVout(CAmount nValue,CPubKey pk);

2
src/cc/CCauction.h

@ -21,7 +21,7 @@
#define EVAL_AUCTION 0xe8
bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string AuctionPost(uint64_t txfee,uint256 itemhash,int64_t minbid,char *title,char *description);
std::string AuctionBid(uint64_t txfee,uint256 itemhash,int64_t amount);

2
src/cc/CCchannels.h

@ -20,7 +20,7 @@
#include "CCinclude.h"
#define CHANNELS_MAXPAYMENTS 1000
bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment);
std::string ChannelStop(uint64_t txfee,CPubKey destpub,uint256 origtxid);
std::string ChannelPayment(uint64_t txfee,uint256 prevtxid,uint256 origtxid,int32_t n,int64_t amount);

12
src/cc/CCcustom.cpp

@ -29,6 +29,7 @@
#include "CCTriggers.h"
#include "CCPayments.h"
#include "CCGateways.h"
#include "CoinbaseGuard.h"
/*
CCcustom has most of the functions that need to be extended to create a new CC contract.
@ -221,11 +222,20 @@ uint8_t GatewaysCCpriv[32] = { 0xf7, 0x4b, 0x5b, 0xa2, 0x7a, 0x5e, 0x9c, 0xda, 0
#undef FUNCNAME
#undef EVALCODE
struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode)
struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
{
cp->evalcode = evalcode;
switch ( evalcode )
{
case EVAL_COINBASEGUARD:
strcpy(cp->unspendableCCaddr,AssetsCCaddr);
strcpy(cp->normaladdr,AssetsNormaladdr);
strcpy(cp->CChexstr,AssetsCChexstr);
memcpy(cp->CCpriv,AssetsCCpriv,32);
cp->validate = AssetsValidate;
cp->ismyvin = IsAssetsInput;
break;
case EVAL_ASSETS:
strcpy(cp->unspendableCCaddr,AssetsCCaddr);
strcpy(cp->normaladdr,AssetsNormaladdr);

2
src/cc/CCdice.h

@ -21,7 +21,7 @@
#define EVAL_DICE 0xe6
bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds);
std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout);

2
src/cc/CCfaucet.h

@ -22,7 +22,7 @@
#define EVAL_FAUCET 0xe4
#define FAUCETSIZE (COIN / 10)
bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
std::string FaucetFund(uint64_t txfee,int64_t funds);

2
src/cc/CCfsm.h

@ -21,7 +21,7 @@
#define EVAL_FSM 0xe7
bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string FSMList();
std::string FSMInfo(uint256 fsmtxid);

19
src/cc/CCinclude.h

@ -64,13 +64,23 @@ struct CC_utxo
int32_t vout;
};
// these are the parameters stored after Verus crypto-condition vouts. new versions may change
// the format
struct CC_meta
{
std::vector<unsigned char> version;
uint8_t evalCode;
bool is1of2;
uint8_t numDestinations;
// followed by address destinations
};
struct CCcontract_info
{
uint256 prevtxid;
char unspendableCCaddr[64],CChexstr[72],normaladdr[64],unspendableaddr2[64],unspendableaddr3[64];
uint8_t CCpriv[32],unspendablepriv2[32],unspendablepriv3[32];
CPubKey unspendablepk2,unspendablepk3;
bool (*validate)(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool (*validate)(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn);
bool (*ismyvin)(CScript const& scriptSig);
uint8_t evalcode,evalcode2,evalcode3,didinit;
};
@ -102,6 +112,7 @@ int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
int64_t CCaddress_balance(char *coinaddr);
CPubKey CCtxidaddr(char *txidaddr,uint256 txid);
bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn, std::vector<std::vector<unsigned char>> &preConditions, std::vector<std::vector<unsigned char>> &params);
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format);
uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format);
@ -125,7 +136,8 @@ uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv);
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk);
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2);
CC *MakeCCcond1(uint8_t evalcode,CPubKey pk);
CC* GetCryptoCondition(CScript const& scriptSig);
CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2);
CC *GetCryptoCondition(CScript const& scriptSig);
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
bool IsCCInput(CScript const& scriptSig);
@ -149,6 +161,7 @@ bool Myprivkey(uint8_t myprivkey[]);
int64_t CCduration(int32_t &numblocks,uint256 txid);
// CCtx
bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey);
std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret);
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr);
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr);

2
src/cc/CClotto.h

@ -21,7 +21,7 @@
#define EVAL_LOTTO 0xe9
bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
UniValue LottoInfo(uint256 lottoid);
UniValue LottoList();

2
src/cc/CCrewards.h

@ -22,7 +22,7 @@
#define EVAL_REWARDS 0xe5
#define REWARDSCC_MAXAPR (COIN * 25)
bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
UniValue RewardsInfo(uint256 rewardid);
UniValue RewardsList();

28
src/cc/CCutils.cpp

@ -197,6 +197,32 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
return(false);
}
bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn, std::vector<std::vector<unsigned char>> &preConditions, std::vector<std::vector<unsigned char>> &params)
{
CTransaction txOut;
uint256 blockHash;
bool isValid = false;
if (myGetTransaction(tx.vin[nIn].prevout.hash, txOut, blockHash))
{
CBlockIndex index;
if (eval->GetBlock(blockHash, index))
{
// read preconditions
CScript subScript = CScript();
preConditions.clear();
if (txOut.vout[tx.vin[nIn].prevout.n].scriptPubKey.IsPayToCryptoCondition(&subScript, preConditions))
{
// read any available parameters in the output transaction
params.clear();
tx.vout[tx.vout.size() - 1].scriptPubKey.GetOpretData(params);
isValid = true;
}
}
}
return isValid;
}
CPubKey CCtxidaddr(char *txidaddr,uint256 txid)
{
uint8_t buf33[33]; CPubKey pk;
@ -361,7 +387,7 @@ bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> param
return eval->Invalid("Cannot have params");
else if ( ctx.vout.size() == 0 )
return eval->Invalid("no-vouts");
else if ( (*cp->validate)(cp,eval,ctx) != 0 )
else if ( (*cp->validate)(cp,eval,ctx,nIn) != 0 )
{
//fprintf(stderr,"done CC %02x\n",cp->evalcode);
//cp->prevtxid = txid;

254
src/cc/CoinbaseGuard.cpp

@ -0,0 +1,254 @@
/********************************************************************
* (C) 2018 Michael Toutonghi
*
* Distributed under the MIT software license, see the accompanying
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
*
* This crypto-condition eval solves the problem of nothing-at-stake
* in a proof of stake consensus system.
*
*/
#include "CoinbaseGuard.h"
#include "main.h"
extern int32_t VERUS_MIN_STAKEAGE;
bool UnpackStakeOpRet(const CTransaction &stakeTx, std::vector<std::vector<unsigned char>> vData)
{
bool isValid = stakeTx.vout[stakeTx.vout.size() - 1].scriptPubKey.GetOpretData(vData);
if (isValid && (vData.size() >= CStakeParams::STAKE_MINPARAMS) && (vData.size() <= CStakeParams::STAKE_MAXPARAMS))
{
return true;
}
return false;
}
CStakeParams::CStakeParams(std::vector<std::vector<unsigned char>> vData)
{
// A stake OP_RETURN contains:
// 1. source block height in little endian 32 bit
// 2. target block height in little endian 32 bit
// 3. 32 byte prev block hash
// 4. alternate 20 byte pubkey hash, 33 byte pubkey, or not present to use same as stake destination
srcHeight = 0;
blkHeight = 0;
if (vData[0].size() == 1 &&
vData[0][0] == OPRETTYPE_STAKEPARAMS && vData[1].size() <= 4 &&
vData[2].size() <= 4 &&
vData[3].size() == sizeof(prevHash) &&
(vData.size() == STAKE_MINPARAMS || vData[4].size() == 20 || vData[5].size() == 33))
{
for (auto ch : vData[1])
{
srcHeight = srcHeight << 8 | ch;
}
for (auto ch : vData[2])
{
blkHeight = blkHeight << 8 | ch;
}
prevHash = uint256(vData[3]);
if (vData.size() == 4)
{
dest = CTxDestination();
}
else if (vData[4].size() == 20)
{
dest = CTxDestination(CKeyID(uint160(vData[4])));
}
else if (vData[4].size() == 33)
{
CPubKey pk = CPubKey(vData[4]);
if (pk.IsValid())
{
dest = pk;
}
else
{
// invalidate
srcHeight = 0;
}
}
else
{
// invalidate
srcHeight = 0;
}
}
}
// this validates everything, except the PoS eligibility and the actual stake spend. the only time it matters
// is to validate a properly formed stake transaction for either pre-check before PoS validity check, or to
// validate the stake transaction on a fork that will be used to spend a winning stake that cheated by being posted
// on two fork chains
bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams)
{
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
// a valid stake transaction has one input and two outputs, one output is the monetary value and one is an op_ret with CStakeParams
// stake output #1 must be P2PK or P2PKH, unless a delegate for the coinbase is specified
bool isValid = false;;
if (stakeTx.vin.size() == 1 &&
stakeTx.vout.size() == 2 &&
stakeTx.vout[0].nValue > 0 &&
stakeTx.vout[1].scriptPubKey.IsOpReturn() &&
UnpackStakeOpRet(stakeTx, vData))
{
stakeParams = CStakeParams(vData);
if (stakeParams.IsValid())
{
// if we have gotten this far and are still valid, we need to validate everything else
// even if the utxo is spent, this can succeed, as it only checks that is was ever valid
CTransaction srcTx = CTransaction();
uint256 blkHash = uint256();
txnouttype txType;
CBlockIndex *pindex;
if (isValid && myGetTransaction(stakeTx.vin[0].prevout.hash, srcTx, blkHash))
{
isValid = false;
if ((pindex = mapBlockIndex[blkHash]) != NULL)
{
std::vector<std::vector<unsigned char>> vAddr = std::vector<std::vector<unsigned char>>();
if (stakeParams.srcHeight == pindex->GetHeight() &&
(stakeParams.blkHeight - stakeParams.srcHeight >= VERUS_MIN_STAKEAGE) &&
Solver(srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey, txType, vAddr))
{
if (txType == TX_PUBKEY)
{
if (stakeParams.dest.which() == 0)
{
stakeParams.dest = CPubKey(vAddr[0]);
}
}
else if (txType == TX_PUBKEYHASH)
{
if (stakeParams.dest.which() == 0)
{
stakeParams.dest = CKeyID(uint160(vAddr[0]));
}
}
if ((txType == TX_PUBKEY) && (txType == TX_PUBKEYHASH))
{
auto consensusBranchId = CurrentEpochBranchId(stakeParams.blkHeight, Params().GetConsensus());
isValid = VerifyScript(stakeTx.vin[0].scriptSig,
srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey,
STANDARD_SCRIPT_VERIFY_FLAGS + SCRIPT_VERIFY_SIGPUSHONLY,
BaseSignatureChecker(),
consensusBranchId);
}
}
}
}
else
{
isValid = false;
}
}
}
return isValid;
}
bool MakeGuardedOutput(CAmount value, CPubKey &dest, CTransaction &stakeTx, CTxOut &vout)
{
CCcontract_info *cp, C;
cp = CCinit(&C,EVAL_COINBASEGUARD);
CPubKey ccAddress = CPubKey(ParseHex(cp->CChexstr));
// return an output that is bound to the stake transaction and can be spent by presenting either a signed condition by the original
// destination address or a properly signed stake transaction of the same utxo on a fork
vout = MakeCC1of2vout(EVAL_COINBASEGUARD, value, dest, ccAddress);
// add parameters to scriptPubKey
COptCCParams p = COptCCParams(COptCCParams::VERSION, EVAL_COINBASEGUARD, 1, 2);
std::vector<unsigned char> a1, a2;
CKeyID id1 = dest.GetID();
CKeyID id2 = ccAddress.GetID();
a1 = std::vector<unsigned char>(id1.begin(), id1.end());
a2 = std::vector<unsigned char>(id2.begin(), id2.end());
// version
// utxo source hash
// utxo source output
// hashed address of destination's pubkey
CKeyID key = dest.GetID();
vout.scriptPubKey << p.AsVector() << OP_DROP
<< a1 << OP_DROP << a2 << OP_DROP
<< std::vector<unsigned char>(stakeTx.vin[0].prevout.hash.begin(), stakeTx.vin[0].prevout.hash.end()) << OP_DROP
<< stakeTx.vin[0].prevout.n << OP_DROP;
return false;
}
// This is only needed to create a spend for cheating. normal spend and signing should work
// for vins
bool MakeGuardedSpend(CTxIn &vin, CPubKey &dest, CTransaction *pCheater)
{
CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_COINBASEGUARD);
CC cc;
vin.scriptSig = CCPubKey(MakeCCcond1of2(EVAL_COINBASEGUARD, dest, CPubKey(ParseHex(cp->CChexstr))));
}
bool CoinbaseGuardValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
{
// This also supports a variable blockstomaturity option for backward feature compatibility
// validate this spend of a transaction with it being past any applicable time lock and one of the following statements being true:
// 1. the spend is signed by the original output destination's private key and normal payment requirements, spends as normal
// 2. the spend is signed by the private key of the CoinbaseGuard contract and pushes a signed stake transaction
// with the same exact utxo source, a target block height of later than that of this tx that is also targeting a fork
// of the chain
// first, check to see if the spending contract is signed by the default destination address
// if so, success and we are done
// get preConditions and parameters
std::vector<std::vector<unsigned char>> preConditions = std::vector<std::vector<unsigned char>>();
std::vector<std::vector<unsigned char>> params = std::vector<std::vector<unsigned char>>();
if (GetCCParams(eval, tx, nIn, preConditions, params))
{
CC *cc = GetCryptoCondition(tx.vin[nIn].scriptSig);
printf("CryptoCondition code %x\n", *cc->code);
// check any applicable time lock
// determine who signed
// if from receiver's priv key, success
// if from contract priv key:
// if data provided is valid stake spend of same utxo targeting same or later block height on a fork:
// return success
// endif
// endif
// return fail
cc_free(cc);
}
}
UniValue CoinbaseGuardInfo()
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx;
CPubKey pk;
CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_COINBASEGUARD);
result.push_back(Pair("result","success"));
result.push_back(Pair("name","CoinbaseGuard"));
// all UTXOs to the contract address that are to any of the wallet addresses are to us
// each is spendable as a normal transaction, but the spend may fail if it gets spent out
// from under us
pk = GetUnspendable(cp,0);
return(result);
}

47
src/cc/CoinbaseGuard.h

@ -0,0 +1,47 @@
/********************************************************************
* (C) 2018 Michael Toutonghi
*
* Distributed under the MIT software license, see the accompanying
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
*
* This crypto-condition eval solves the problem of nothing-at-stake
* in a proof of stake consensus system.
*
*/
#ifndef CC_COINBASEGUARD_H
#define CC_COINBASEGUARD_H
#include <vector>
#include "CCinclude.h"
#include "streams.h"
#include "script/script.h"
class CStakeParams
{
public:
static const uint32_t STAKE_MINPARAMS = 4;
static const uint32_t STAKE_MAXPARAMS = 5;
uint32_t srcHeight;
uint32_t blkHeight;
uint256 prevHash;
CTxDestination dest;
CStakeParams() : srcHeight(0), blkHeight(0), prevHash(), dest() {}
CStakeParams(std::vector<std::vector<unsigned char>> vData);
bool IsValid() { return srcHeight != 0; }
};
bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams);
bool MakeGuardedOutput(CAmount value, CPubKey &dest, CTransaction &stakeTx, CTxOut &vout);
bool CoinbaseGuardValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
UniValue CoinbaseGuardInfo();
#endif

2
src/cc/MofN.cpp

@ -85,7 +85,7 @@ bool MofNExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &
else return(true);
}
bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return(false);

2
src/cc/assets.cpp

@ -129,7 +129,7 @@
vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey]
*/
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
static uint256 zero;
CTxDestination address; CTransaction vinTx,createTx; uint256 hashBlock,assetid,assetid2; int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector<uint8_t> origpubkey,tmporigpubkey,ignorepubkey; uint8_t funcid; char destaddr[64],origaddr[64],CCaddr[64];

2
src/cc/auction.cpp

@ -70,7 +70,7 @@ bool AuctionExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransactio
else return(true);
}
bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
return(false); // reject any auction CC for now

2
src/cc/channels.cpp

@ -111,7 +111,7 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti
else return(true);
}
bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return(false);

2
src/cc/dice.cpp

@ -439,7 +439,7 @@ bool DiceVerifyTimeout(CTransaction &betTx,int32_t timeoutblocks)
return(numblocks >= timeoutblocks);
}
bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn)
{
uint256 txid,fundingtxid,vinfundingtxid,vinhentropy,vinproof,hashBlock,hash,proof,entropy; int64_t minbet,maxbet,maxodds,timeoutblocks,odds,winnings; uint64_t vinsbits,sbits,amount,inputs,outputs,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,iswin; uint8_t funcid; CScript fundingPubKey; CTransaction fundingTx,vinTx,vinofvinTx; char CCaddr[64];
numvins = tx.vin.size();

11
src/cc/eval.cpp

@ -34,9 +34,6 @@ extern pthread_mutex_t KOMODO_CC_mutex;
bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
{
// DISABLE CRYPTO CONDITIONS FOR NOW
return false;
EvalRef eval;
pthread_mutex_lock(&KOMODO_CC_mutex);
bool out = eval->Dispatch(cond, tx, nIn);
@ -77,15 +74,17 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
switch ( ecode )
{
case EVAL_IMPORTPAYOUT:
return ImportPayout(vparams, txTo, nIn);
//return ImportPayout(vparams, txTo, nIn);
break;
case EVAL_IMPORTCOIN:
return ImportCoin(vparams, txTo, nIn);
//return ImportCoin(vparams, txTo, nIn);
break;
default:
return(ProcessCC(cp,this, vparams, txTo, nIn));
// only support coinbase guard for now
if (ecode == EVAL_COINBASEGUARD)
return(ProcessCC(cp,this, vparams, txTo, nIn));
break;
}
return Invalid("invalid-code, dont forget to add EVAL_NEWCC to Eval::Dispatch");

1
src/cc/eval.h

@ -38,6 +38,7 @@
* after the code is interpreted as a bitcoin script.
*/
#define FOREACH_EVAL(EVAL) \
EVAL(EVAL_COINBASEGUARD, 0x1) \
EVAL(EVAL_IMPORTPAYOUT, 0xe1) \
EVAL(EVAL_IMPORTCOIN, 0xe2) \
EVAL(EVAL_ASSETS, 0xe3) \

2
src/cc/faucet.cpp

@ -77,7 +77,7 @@ bool FaucetExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
else return(true);
}
bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;

2
src/cc/fsm.cpp

@ -72,7 +72,7 @@ bool FSMExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
else return(true);
}
bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
return(false); // reject any FSM CC for now

2
src/cc/gateways.cpp

@ -239,7 +239,7 @@ bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti
else return(true);
}
bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;

2
src/cc/lotto.cpp

@ -112,7 +112,7 @@ bool LottoExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
else return(true);
}
bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
return(false); // reject any lotto CC for now

2
src/cc/oracles.cpp

@ -593,7 +593,7 @@ bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransactio
else return(true);
}
bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
uint256 txid,oracletxid,batontxid; uint64_t txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts; uint8_t *script; std::vector<uint8_t> vopret,data; CScript scriptPubKey; CPubKey publisher;
numvins = tx.vin.size();

2
src/cc/payments.cpp

@ -72,7 +72,7 @@ bool PaymentsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti
else return(true);
}
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return(false);

2
src/cc/pegs.cpp

@ -79,7 +79,7 @@ bool PegsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &
else return(true);
}
bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return(false);

2
src/cc/prices.cpp

@ -91,7 +91,7 @@ bool PricesExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
else return(true);
}
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return(false);

2
src/cc/rewards.cpp

@ -192,7 +192,7 @@ bool RewardsExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransactio
else return(true);
}
bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
uint256 txid,fundingtxid,hashBlock,vinfundingtxid; uint64_t vinsbits,sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx;
numvins = tx.vin.size();

2
src/cc/triggers.cpp

@ -71,7 +71,7 @@ bool TriggersExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti
else return(true);
}
bool TriggersValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
bool TriggersValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return(false);

2
src/crypto/verus_hash.h

@ -1,4 +1,4 @@
// (C) 2018 The Verus Developers
// (C) 2018 Michael Toutonghi
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

8
src/script/cc.cpp

@ -86,6 +86,14 @@ CScript CCSig(const CC *cond)
return CScript() << ffill;
}
std::vector<unsigned char> CCSigVec(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 ffill;
}
std::string CCShowStructure(CC *cond)
{

6
src/script/cc.h

@ -57,6 +57,12 @@ CScript CCPubKey(const CC *cond);
*/
CScript CCSig(const CC *cond);
/*
* Turn a condition into a scriptSig
*
* Note: This will fail in undefined ways if the condition is missing signatures
*/
std::vector<unsigned char> CCSigVec(const CC *cond);
/*
* Produces a string showing the structure of a CC condition

2
src/script/interpreter.cpp

@ -952,7 +952,7 @@ bool EvalScript(
if (stack.size() < 2)
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
//fprintf(stderr,"check cryptocondition\n");
//fprintf(stderr,"check cryptocondition\n");
int fResult = checker.CheckCryptoCondition(stacktop(-1), stacktop(-2), script, consensusBranchId);
if (fResult == -1) {
return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT);

81
src/script/script.cpp

@ -245,9 +245,64 @@ bool CScript::IsPayToScriptHash() const
(*this)[22] == OP_EQUAL);
}
bool CScript::IsPayToCryptoCondition() const
// this returns true if either there is nothing left and pc points at the end, or
// all instructions from the pc to the end of the script are balanced pushes and pops
// if there is data, it also returns all the values as byte vectors in a list of vectors
bool CScript::GetBalancedData(const_iterator& pc, std::vector<std::vector<unsigned char>>& vSolutions) const
{
int netPushes = 0;
vSolutions.clear();
while (pc < end())
{
vector<unsigned char> data;
opcodetype opcode;
if (this->GetOp(pc, opcode, data))
{
if (opcode == OP_DROP)
{
// this should never pop what it hasn't pushed (like a success code)
if (--netPushes < 0)
return false;
}
if (opcode < 1 || opcode > OP_PUSHDATA4)
return false;
netPushes++;
vSolutions.push_back(data);
}
else
return false;
}
return netPushes == 0;
}
// this returns true if either there is nothing left and pc points at the end, or
// all instructions from the pc to the end of the script are balanced pushes and pops
// if there is data, it also returns all the values as byte vectors in a list of vectors
bool CScript::GetOpretData(std::vector<std::vector<unsigned char>>& vData) const
{
const_iterator pc = this->begin();
vector<unsigned char> data;
opcodetype opcode;
const_iterator pc = begin();
vData.clear();
if (GetOp(pc, opcode, data) && opcode == OP_RETURN)
{
while (pc < end())
{
if (GetOp(pc, opcode, data))
{
vData.push_back(data);
}
}
return vData.size() != 0;
}
}
bool CScript::IsPayToCryptoCondition(CScript *pCCSubScript, std::vector<std::vector<unsigned char>>& vSolutions) const
{
const_iterator pc = begin();
vector<unsigned char> data;
opcodetype opcode;
if (this->GetOp(pc, opcode, data))
@ -255,9 +310,27 @@ bool CScript::IsPayToCryptoCondition() const
if (opcode > OP_0 && opcode < OP_PUSHDATA1)
if (this->GetOp(pc, opcode, data))
if (opcode == OP_CHECKCRYPTOCONDITION)
if (pc == this->end())
{
const_iterator pcCCEnd = pc;
if (GetBalancedData(pc, vSolutions))
{
if (pCCSubScript)
*pCCSubScript = CScript(begin(),pc);
return 1;
return 0;
}
}
return false;
}
bool CScript::IsPayToCryptoCondition(CScript *pCCSubScript) const
{
std::vector<std::vector<unsigned char>> vSolutions;
return IsPayToCryptoCondition(pCCSubScript, vSolutions);
}
bool CScript::IsPayToCryptoCondition() const
{
return IsPayToCryptoCondition(NULL);
}
bool CScript::MayAcceptCryptoCondition() const

7
src/script/script.h

@ -19,6 +19,7 @@
#include <vector>
#define OPRETTYPE_TIMELOCK 1
#define OPRETTYPE_STAKEPARAMS 2
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
@ -381,6 +382,7 @@ protected:
}
return *this;
}
bool GetBalancedData(const_iterator& pc, std::vector<std::vector<unsigned char>>& vSolutions) const;
public:
CScript() { }
CScript(const CScript& b) : CScriptBase(b.begin(), b.end()) { }
@ -574,6 +576,11 @@ public:
bool IsPayToPublicKey() const;
bool IsPayToScriptHash() const;
bool IsOpReturn() const { return size() > 0 && (*this)[0] == OP_RETURN; }
bool GetOpretData(std::vector<std::vector<unsigned char>>& vData) const;
bool IsPayToCryptoCondition(CScript *ccSubScript, std::vector<std::vector<unsigned char>>& vSolutions) const;
bool IsPayToCryptoCondition(CScript *ccSubScript) const;
bool IsPayToCryptoCondition() const;
bool IsCoinImport() const;
bool MayAcceptCryptoCondition() const;

226
src/script/sign.cpp

@ -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');

12
src/script/sign.h

@ -8,6 +8,7 @@
#include "script/interpreter.h"
class CKey;
class CKeyID;
class CKeyStore;
class CScript;
@ -27,7 +28,12 @@ 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, uint32_t consensusBranchId) const =0;
virtual bool CreateSig(std::vector<unsigned char>& vchSig,
const CKeyID& keyid,
const CScript& scriptCode,
uint32_t consensusBranchId,
CKey *key = NULL,
void *extraData = NULL) const = 0;
};
/** A signature creator for transactions. */
@ -41,7 +47,7 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
public:
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, uint32_t consensusBranchId) const;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId, CKey *key = NULL, void *extraData = NULL) const;
};
class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
@ -56,7 +62,7 @@ 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, uint32_t consensusBranchId) const;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId, CKey *key = NULL, void *extraData = NULL) const;
};
struct SignatureData {

34
src/script/standard.cpp

@ -73,19 +73,37 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
if (IsCryptoConditionsEnabled()) {
// Shortcut for pay-to-crypto-condition
if (scriptPubKey.IsPayToCryptoCondition())
CScript ccSubScript = CScript();
std::vector<std::vector<unsigned char>> vParams;
if (scriptPubKey.IsPayToCryptoCondition(&ccSubScript, vParams))
{
if (scriptPubKey.MayAcceptCryptoCondition())
{
typeRet = TX_CRYPTOCONDITION;
vector<unsigned char> hashBytes; uint160 x; int32_t i; uint8_t hash20[20],*ptr;;
x = Hash160(scriptPubKey);
x = Hash160(ccSubScript);
memcpy(hash20,&x,20);
hashBytes.resize(20);
ptr = hashBytes.data();
for (i=0; i<20; i++)
ptr[i] = hash20[i];
vSolutionsRet.push_back(hashBytes);
if (vParams.size())
{
COptCCParams cp = COptCCParams(vParams[0]);
if (cp.IsValid() && vParams.size() > cp.m)
{
// all addresses that should be there must be 20 byte keyIDs
for (int i = 1; i <= cp.m; i++)
{
if (vParams[i].size() != 20)
{
// we accept no errors
return false;
}
}
}
}
return true;
}
return false;
@ -331,6 +349,18 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
if (addressRet.empty())
return false;
}
else if (IsCryptoConditionsEnabled() != 0 && typeRet == TX_CRYPTOCONDITION)
{
nRequiredRet = vSolutions.front()[0];
for (unsigned int i = 1; i < vSolutions.size()-1; i++)
{
CTxDestination address = CKeyID(uint160(vSolutions[i]));
addressRet.push_back(address);
}
if (addressRet.empty())
return false;
}
else
{
nRequiredRet = 1;

38
src/script/standard.h

@ -83,6 +83,44 @@ public:
*/
typedef boost::variant<CNoDestination, CPubKey, CKeyID, CScriptID> CTxDestination;
class COptCCParams
{
public:
static const uint8_t VERSION = 1;
uint8_t version;
uint8_t evalCode;
uint8_t n, m; // for n of m sigs required, m addresses for sigs will follow
COptCCParams() : version(0), evalCode(0), n(0), m(0) {}
COptCCParams(uint8_t ver, uint8_t code, uint8_t _n, uint8_t _m) : version(ver), evalCode(code), n(_n), m(_m) {}
COptCCParams(std::vector<unsigned char> &vch)
{
version = 0;
if (vch.size() == 4)
{
version = vch[0];
evalCode = vch[1];
n = vch[2];
m = vch[3];
if (version != VERSION && n == 1 && (m == 1 || m == 2))
{
// we only support one version, and 1 of 1 or 1 of 2 now, so set invalid
version = 0;
}
}
}
bool IsValid() { return version != 0; }
std::vector<unsigned char> AsVector()
{
std::vector<unsigned char> vch = std::vector<unsigned char>({version, evalCode, n, m});
}
};
/** Check whether a CTxDestination is a CNoDestination. */
bool IsValidDestination(const CTxDestination& dest);

44
src/wallet/wallet.cpp

@ -1254,10 +1254,9 @@ int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNe
std::vector<std::vector<unsigned char>> vSolutions;
CBlockIndex *tipindex;
{
LOCK(cs_main);
tipindex = chainActive.Tip();
}
tipindex = chainActive.LastTip();
bool extendedStake = tipindex->GetHeight() >= Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight;
bnTarget = lwmaGetNextPOSRequired(tipindex, Params().GetConsensus());
if (!VerusSelectStakeOutput(pBlock, hashResult, stakeSource, voutNum, tipindex->GetHeight() + 1, bnTarget) ||
@ -1275,21 +1274,56 @@ int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNe
const CKeyStore& keystore = *pwalletMain;
txNew.vin.resize(1);
txNew.vout.resize(1);
txfee = 0;
txfee = extendedStake ? 10000 : 0; // extended stakes will always be rebroadcast, so they require a fee to make it fast
txNew.vin[0].prevout.hash = stakeSource.GetHash();
txNew.vin[0].prevout.n = voutNum;
CPubKey pk = CPubKey();
if (whichType == TX_PUBKEY)
{
txNew.vout[0].scriptPubKey << ToByteVector(vSolutions[0]) << OP_CHECKSIG;
pk = CPubKey(vSolutions[0]);
}
else if (whichType == TX_PUBKEYHASH)
{
txNew.vout[0].scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(vSolutions[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
if (extendedStake)
{
// we need a pubkey, so try to get one from the key ID, if not there, fail
if (!keystore.GetPubKey(CKeyID(uint160(vSolutions[0])), pk))
return 0;
}
}
else
return 0;
// if we are staking with the extended format, add the opreturn data required
//if (extendedStake)
{
uint256 srcBlock = uint256();
CBlockIndex *pSrcIndex;
txNew.vout.push_back(CTxOut());
CTxOut &txOut1 = txNew.vout[1];
txOut1.nValue = 0;
if (!GetTransaction(stakeSource.GetHash(), stakeSource, srcBlock))
return 0;
if ((pSrcIndex = mapBlockIndex[srcBlock]) == 0)
return 0;
txOut1.scriptPubKey << OP_RETURN
<< (int8_t)OPRETTYPE_STAKEPARAMS
<< pSrcIndex->GetHeight() << tipindex->GetHeight()
<< std::vector<unsigned char>(pBlock->hashPrevBlock.begin(), pBlock->hashPrevBlock.end())
<< std::vector<unsigned char>(pk.begin(), pk.end());
// need to decide how to decide, but then we can add a delegated source here for the coinbase output
//if (USE_EXTERNAL_PUBKEY)
// txOut1.scriptPubKey << ParseHex(NOTARY_PUBKEY);
}
nValue = txNew.vout[0].nValue = stakeSource.vout[voutNum].nValue - txfee;
txNew.nLockTime = 0;
CTransaction txNewConst(txNew);

Loading…
Cancel
Save