Skip to content

Commit

Permalink
2WP: QA: Introduce -con_parent_chain_signblockscript
Browse files Browse the repository at this point in the history
This allows other elements chains as parent chains for pegs, for testing purposes

for now it also assumes that the parent chain has CT/CA tx format,
which is orthogonal to the parent chain having pow or signed blocks

It would be nice to also test bitcoin-like chains with signed blocks
instead of pow by adding another parameter -con_parent_chain_has_CT or
similar and decouple the logic

CT: Introduce GetAmountFromParentChainPegin for CT txs
RPC: Adapt rpcwallet to initial -con_parent_chain_has_pow
Introduce CheckProofGeneric
Introduce pow::CheckProofParent
  • Loading branch information
jtimon committed Aug 10, 2018
1 parent 781953b commit 75d24ab
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 26 deletions.
2 changes: 2 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ class CCustomParams : public CChainParams {
consensus.defaultAssumeValid = uint256S(GetArg("-con_defaultassumevalid", "0x00"));
consensus.pegin_min_depth = GetArg("-peginconfirmationdepth", DEFAULT_PEGIN_CONFIRMATION_DEPTH);
consensus.mandatory_coinbase_destination = StrHexToScriptWithDefault(GetArg("-con_mandatorycoinbase", ""), CScript()); // Blank script allows any coinbase destination
consensus.parent_chain_signblockscript = StrHexToScriptWithDefault(GetArg("-con_parent_chain_signblockscript", ""), CScript());

// bitcoin regtest is the parent chain by default
parentGenesisBlockHash = uint256S(GetArg("-parentgenesisblockhash", "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
initialFreeCoins = GetArg("-initialfreecoins", 0);
Expand Down
2 changes: 2 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ struct Params {
CScript mandatory_coinbase_destination;
CScript signblockscript;
bool has_parent_chain;
CScript parent_chain_signblockscript;
bool ParentChainHasPow() const { return parent_chain_signblockscript == CScript();}
};
} // namespace Consensus

Expand Down
4 changes: 2 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-defaultpeggedassetname", strprintf("The name of the default asset created in the genesis block. (default: bitcoin)"));
strUsage += HelpMessageOpt("-parentpubkeyprefix", strprintf(_("The byte prefix, in decimal, of the parent chain's base58 pubkey address. (default: %d)"), 111));
strUsage += HelpMessageOpt("-parentscriptprefix", strprintf(_("The byte prefix, in decimal, of the parent chain's base58 script address. (default: %d)"), 196));

strUsage += HelpMessageOpt("-con_parent_chain_signblockscript", _("Whether parent chain uses pow or signed blocks. If the parent chain uses signed blocks, the challenge (scriptPubKey) script. If not, an empty string. (default: empty script [ie parent uses pow])"));
}
strUsage += HelpMessageOpt("-validatepegin", strprintf(_("Validate pegin claims. All functionaries must run this. (default: %u)"), DEFAULT_VALIDATE_PEGIN));
strUsage += HelpMessageOpt("-mainchainrpchost=<addr>", strprintf("The address which the daemon will try to connect to validate peg-ins, if enabled. (default: cookie auth)"));
Expand Down Expand Up @@ -1024,7 +1024,7 @@ bool AppInitParameterInteraction()
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;

policyAsset = CAsset(uint256S(GetArg("-feeasset", chainparams.GetConsensus().pegged_asset.GetHex())));

// Fee-per-kilobyte amount considered the same as "free"
// If you are mining, be careful setting this:
// if you set it to zero then
Expand Down
14 changes: 12 additions & 2 deletions src/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ bool CheckBitcoinProof(uint256 hash, unsigned int nBits)
return true;
}

bool CheckProof(const CBlockHeader& block, const Consensus::Params& params)
static bool CheckProofGeneric(const CBlockHeader& block, const Consensus::Params& params, const CScript& challenge)
{
if (block.GetHash() == params.hashGenesisBlock)
return true;
Expand All @@ -82,7 +82,17 @@ bool CheckProof(const CBlockHeader& block, const Consensus::Params& params)
| SCRIPT_VERIFY_LOW_S // Stop easiest signature fiddling
| SCRIPT_VERIFY_WITNESS // Required for cleanstack eval in VerifyScript
| SCRIPT_NO_SIGHASH_BYTE; // non-Check(Multi)Sig signatures will not have sighash byte
return GenericVerifyScript(block.proof.solution, params.signblockscript, proof_flags, block);
return GenericVerifyScript(block.proof.solution, challenge, proof_flags, block);
}

bool CheckProofSignedParent(const CBlockHeader& block, const Consensus::Params& params)
{
return CheckProofGeneric(block, params, params.parent_chain_signblockscript);
}

bool CheckProof(const CBlockHeader& block, const Consensus::Params& params)
{
return CheckProofGeneric(block, params, params.signblockscript);
}

bool MaybeGenerateProof(const Consensus::Params& params, CBlockHeader *pblock, CWallet *pwallet)
Expand Down
1 change: 1 addition & 0 deletions src/pow.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class uint256;

/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
bool CheckBitcoinProof(uint256 hash, unsigned int nBits);
bool CheckProofSignedParent(const CBlockHeader& block, const Consensus::Params& params);
bool CheckProof(const CBlockHeader& block, const Consensus::Params&);
/** Scans nonces looking for a hash with at least some zero bits */
bool MaybeGenerateProof(const Consensus::Params& params, CBlockHeader* pblock, CWallet* pwallet);
Expand Down
9 changes: 7 additions & 2 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
result.push_back(Pair("time", (int64_t)blockindex->nTime));
result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
result.push_back(Pair("signblock_witness_asm", ScriptToAsmStr(blockindex->proof.solution)));
result.push_back(Pair("signblock_witness_hex", HexStr(blockindex->proof.solution.begin(), blockindex->proof.solution.end())));
result.push_back(Pair("signblock_witness_hex", HexStr(blockindex->proof.solution)));

if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
Expand Down Expand Up @@ -105,7 +105,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("time", block.GetBlockTime()));
result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
result.push_back(Pair("signblock_witness_asm", ScriptToAsmStr(blockindex->proof.solution)));
result.push_back(Pair("signblock_witness_hex", HexStr(blockindex->proof.solution.begin(), blockindex->proof.solution.end())));
result.push_back(Pair("signblock_witness_hex", HexStr(blockindex->proof.solution)));

if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
Expand Down Expand Up @@ -1125,6 +1125,11 @@ UniValue getsidechaininfo(const JSONRPCRequest& request)
obj.push_back(Pair("pegged_asset", consensus.pegged_asset.GetHex()));
obj.push_back(Pair("min_peg_diff", consensus.parentChainPowLimit.GetHex()));
obj.push_back(Pair("parent_blockhash", parent_blockhash.GetHex()));
obj.push_back(Pair("parent_chain_has_pow", consensus.ParentChainHasPow()));
if (!consensus.ParentChainHasPow()) {
obj.push_back(Pair("parent_chain_signblockscript_asm", ScriptToAsmStr(consensus.parent_chain_signblockscript)));
obj.push_back(Pair("parent_chain_signblockscript_hex", HexStr(consensus.parent_chain_signblockscript)));
}
return obj;
}

Expand Down
50 changes: 38 additions & 12 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "crypto/hmac_sha256.h"
#include "init.h"
#include "issuance.h"
#include "merkleblock.h"
#include "policy/fees.h"
#include "policy/policy.h"
#include "pow.h"
Expand Down Expand Up @@ -2374,6 +2375,15 @@ bool GetAmountFromParentChainPegin(CAmount& amount, const Sidechain::Bitcoin::CT
return true;
}

bool GetAmountFromParentChainPegin(CAmount& amount, const CTransaction& txBTC, unsigned int nOut)
{
if (!txBTC.vout[nOut].nValue.IsExplicit()) {
return false;
}
amount = txBTC.vout[nOut].nValue.GetAmount();
return true;
}

template<typename T>
static bool GetBlockAndTxFromMerkleBlock(uint256& block_hash, uint256& tx_hash, T& merkle_block, const std::vector<unsigned char>& merkle_block_raw)
{
Expand Down Expand Up @@ -2497,20 +2507,36 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p

uint256 block_hash;
uint256 tx_hash;

// Get txout proof
Sidechain::Bitcoin::CMerkleBlock merkle_block;
if (!GetBlockAndTxFromMerkleBlock(block_hash, tx_hash, merkle_block, stack[5])) {
return false;
}
if (!CheckBitcoinProof(block_hash, merkle_block.header.nBits)) {
return false;
}
if (Params().GetConsensus().ParentChainHasPow()) {

// Get serialized transaction
Sidechain::Bitcoin::CTransactionRef pegtx;
if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script)) {
return false;
Sidechain::Bitcoin::CMerkleBlock merkle_block_pow;
if (!GetBlockAndTxFromMerkleBlock(block_hash, tx_hash, merkle_block_pow, stack[5])) {
return false;
}
if (!CheckBitcoinProof(block_hash, merkle_block_pow.header.nBits)) {
return false;
}

Sidechain::Bitcoin::CTransactionRef pegtx;
if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script)) {
return false;
}
} else {

CMerkleBlock merkle_block;
if (!GetBlockAndTxFromMerkleBlock(block_hash, tx_hash, merkle_block, stack[5])) {
return false;
}

if (!CheckProofSignedParent(merkle_block.header, Params().GetConsensus())) {
return false;
}

CTransactionRef pegtx;
if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script)) {
return false;
}
}

// Check that the merkle proof corresponds to the txid
Expand Down
1 change: 1 addition & 0 deletions src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ void ThreadScriptCheck();
/** Check if bitcoind connection via RPC is correctly working*/
bool BitcoindRPCCheck(bool init);
bool GetAmountFromParentChainPegin(CAmount& amount, const Sidechain::Bitcoin::CTransaction& txBTC, unsigned int nOut);
bool GetAmountFromParentChainPegin(CAmount& amount, const CTransaction& txBTC, unsigned int nOut);
/** Checks pegin witness for validity */
bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& prevout, bool check_depth = true);
/** Extracts an output from pegin witness for evaluation as a normal output */
Expand Down
43 changes: 35 additions & 8 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2082,7 +2082,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
" \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
" 'send' category of transactions.\n"
" \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
" 'send' category of transactions.\n"
" 'send' category of transactions.\n"
" }\n"
" ,...\n"
" ],\n"
Expand Down Expand Up @@ -3512,7 +3512,8 @@ UniValue sendtomainchain(const JSONRPCRequest& request)
extern UniValue signrawtransaction(const JSONRPCRequest& request);
extern UniValue sendrawtransaction(const JSONRPCRequest& request);

unsigned int GetPeginTxnOutputIndex(const Sidechain::Bitcoin::CTransaction& txn, const CScript& witnessProgram)
template<typename T_tx>
unsigned int GetPeginTxnOutputIndex(const T_tx& txn, const CScript& witnessProgram)
{
unsigned int nOut = 0;
//Call contracthashtool
Expand All @@ -3523,7 +3524,8 @@ unsigned int GetPeginTxnOutputIndex(const Sidechain::Bitcoin::CTransaction& txn,
return nOut;
}

UniValue createrawpegin(const JSONRPCRequest& request)
template<typename T_tx_ref, typename T_tx, typename T_merkle_block>
static UniValue createrawpegin(const JSONRPCRequest& request, T_tx_ref& txBTCRef, T_tx& tx_aux, T_merkle_block& merkleBlock)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
throw std::runtime_error(
Expand Down Expand Up @@ -3552,27 +3554,26 @@ UniValue createrawpegin(const JSONRPCRequest& request)

std::vector<unsigned char> txData = ParseHex(request.params[0].get_str());
CDataStream ssTx(txData, SER_NETWORK, PROTOCOL_VERSION);
Sidechain::Bitcoin::CTransactionRef txBTCRef;
try {
ssTx >> txBTCRef;
}
catch (...) {
throw JSONRPCError(RPC_TYPE_ERROR, "The included bitcoinTx is malformed. Are you sure that is the whole string?");
}
Sidechain::Bitcoin::CTransaction txBTC(*txBTCRef);
T_tx txBTC(*txBTCRef);

std::vector<unsigned char> txOutProofData = ParseHex(request.params[1].get_str());
CDataStream ssTxOutProof(txOutProofData, SER_NETWORK, PROTOCOL_VERSION);
Sidechain::Bitcoin::CMerkleBlock merkleBlock;
try {
ssTxOutProof >> merkleBlock;
}
catch (...) {
throw JSONRPCError(RPC_TYPE_ERROR, "The included txoutproof is malformed. Are you sure that is the whole string?");
}

if (!ssTxOutProof.empty() || !CheckBitcoinProof(merkleBlock.header.GetHash(), merkleBlock.header.nBits))
if (!ssTxOutProof.empty()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid tx out proof");
}

std::vector<uint256> txHashes;
std::vector<unsigned int> txIndices;
Expand Down Expand Up @@ -3622,7 +3623,10 @@ UniValue createrawpegin(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Given or recovered script is not a witness program.");
}

CAmount value = txBTC.vout[nOut].nValue;
CAmount value = 0;
if (!GetAmountFromParentChainPegin(value, txBTC, nOut)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Amounts to pegin must be explicit");
}

CDataStream stream(0, 0);
try {
Expand Down Expand Up @@ -3703,6 +3707,29 @@ UniValue createrawpegin(const JSONRPCRequest& request)
return ret;
}

UniValue createrawpegin(const JSONRPCRequest& request)
{
UniValue ret(UniValue::VOBJ);
if (Params().GetConsensus().ParentChainHasPow()) {
Sidechain::Bitcoin::CTransactionRef txBTCRef;
Sidechain::Bitcoin::CTransaction tx_aux;
Sidechain::Bitcoin::CMerkleBlock merkleBlock;
ret = createrawpegin(request, txBTCRef, tx_aux, merkleBlock);
if (!CheckBitcoinProof(merkleBlock.header.GetHash(), merkleBlock.header.nBits)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid tx out proof");
}
} else {
CTransactionRef txBTCRef;
CTransaction tx_aux;
CMerkleBlock merkleBlock;
ret = createrawpegin(request, txBTCRef, tx_aux, merkleBlock);
if (!CheckProofSignedParent(merkleBlock.header, Params().GetConsensus())) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid tx out proof");
}
}
return ret;
}

UniValue claimpegin(const JSONRPCRequest& request)
{

Expand Down

0 comments on commit 75d24ab

Please sign in to comment.