Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions qa/rpc-tests/test_framework/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ def initialize_datadir(dirname, n):
os.makedirs(datadir)
rpc_u, rpc_p = rpc_auth_pair(n)
with open(os.path.join(datadir, "elements.conf"), 'w', encoding='utf8') as f:
f.write("regtest=1\n")
f.write("rpcuser=" + rpc_u + "\n")
f.write("rpcpassword=" + rpc_p + "\n")
f.write("port="+str(p2p_port(n))+"\n")
Expand Down Expand Up @@ -334,14 +333,14 @@ def _rpchost_to_args(rpchost):
rv += ['-rpcport=' + rpcport]
return rv

def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, chain='elementsregtest'):
"""
Start a bitcoind and return RPC connection to it
"""
datadir = os.path.join(dirname, "node"+str(i))
if binary is None:
binary = os.getenv("ELEMENTSD", "elementsd")
args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-mocktime="+str(get_mocktime()) ]
args = [ binary, '-chain='+chain, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-mocktime="+str(get_mocktime()) ]
if extra_args is not None: args.extend(extra_args)
bitcoind_processes[i] = subprocess.Popen(args)
if os.getenv("PYTHON_DEBUG", ""):
Expand All @@ -357,7 +356,7 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=

return proxy

def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, chain='elementsregtest'):
"""
Start multiple bitcoinds, return RPC connections to them
"""
Expand All @@ -366,7 +365,7 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None
rpcs = []
try:
for i in range(num_nodes):
rpcs.append(start_node(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i]))
rpcs.append(start_node(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], chain=chain))
except: # If one node failed to start, stop the others
stop_nodes(rpcs)
raise
Expand Down
3 changes: 3 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ 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());
consensus.parent_pegged_asset.SetHex(GetArg("-con_parent_pegged_asset", "0x00"));

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

Expand Down
5 changes: 3 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,8 @@ 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])"));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should expose this via getsidechaininfo, including a binary saying if it's PoW for ease of reading

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

strUsage += HelpMessageOpt("-con_parent_pegged_asset=<hex>", _("Asset ID (hex) for pegged asset for when parent chain has CA. (default: 0x00)"));
}
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 +1025,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
16 changes: 13 additions & 3 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 @@ -1105,10 +1105,14 @@ UniValue getsidechaininfo(const JSONRPCRequest& request)
"Returns an object containing various state info regarding sidechain functionality.\n"
"\nResult:\n"
"{\n"
" \"fedpegscript\": \"xxxx\", (string) The fedpegscript in hex\n"
" \"fedpegscript\": \"xxxx\", (string) The fedpegscript in hex\n"
" \"pegged_asset\" : \"xxxx\", (string) Pegged asset type in hex\n"
" \"min_peg_diff\" : \"xxxx\", (string) The minimum difficulty parent chain header target. Peg-in headers that have less work will be rejected as an anti-Dos measure.\n"
" \"parent_blockhash\" : \"xxxx\", (string) The parent genesis blockhash as source of pegged-in funds.\n"
" \"parent_chain_has_pow\": \"xxxx\", (boolean) Whether parent chain has pow or signed blocks.\n"
" \"parent_chain_signblockscript_asm\": \"xxxx\", (string) If the parent chain has signed blocks, its signblockscript in ASM.\n"
" \"parent_chain_signblockscript_hex\": \"xxxx\", (string) If the parent chain has signed blocks, its signblockscript in hex.\n"
" \"parent_pegged_asset\": \"xxxx\", (boolean) If the parent chain has Confidential Assets, the asset id of the pegged asset in that chain.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getsidechaininfo", "")
Expand All @@ -1125,6 +1129,12 @@ 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)));
obj.push_back(Pair("parent_pegged_asset", HexStr(consensus.parent_pegged_asset)));
}
return obj;
}

Expand Down
56 changes: 44 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,21 @@ 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;
}
if (!txBTC.vout[nOut].nAsset.IsExplicit()) {
return false;
}
if (txBTC.vout[nOut].nAsset.GetAsset() != Params().GetConsensus().parent_pegged_asset) {
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 +2513,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)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we have two very similar things with different naming conventions, CheckBitcoinProof and CheckProofParent.

Can we just abstract this out to CheckProofParent with a boolean arg switch?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I just wanted to avoid changing CheckProof since it is called a few times. I could use a boolean that defaults to false, but I tend to dislike default arguments in C++. I find CheckProofParent(merkle_block.header, Params().GetConsensus()) more clear than CheckProof(merkle_block.header, Params().GetConsensus(), true), which forces me to go to the function and see what the boolean is about. If it was python, CheckProof(merkle_block.header, Params().GetConsensus(), use_parent_chain_script=True) is fine. Perhaps I can just add a comment when using the boolean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough, perhaps a minor renaming then to make them obviously related

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or heck just comment what it's doing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to CheckProofSignedParent as discussed on chat.

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
44 changes: 36 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))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we dropping this check?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,11 @@ 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, strprintf("Amounts to pegin must be explicit and asset must be %s",
Params().GetConsensus().parent_pegged_asset.GetHex()));
}

CDataStream stream(0, 0);
try {
Expand Down Expand Up @@ -3703,6 +3708,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