mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-13 12:33:42 +02:00
2WP: QA: Introduce -con_parent_chain_signblockscript
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 Introduce -con_parent_pegged_asset option to check the asset in the peg-in txs from the parent chains. CT: Introduce GetAmountFromParentChainPegin for CT txs RPC: Adapt rpcwallet to initial -con_parent_chain_has_pow Introduce CheckProofGeneric Introduce pow::CheckProofParent
This commit is contained in:
parent
781953b6bd
commit
2de576525b
9 changed files with 116 additions and 27 deletions
|
|
@ -130,6 +130,9 @@ protected:
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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])"));
|
||||
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)"));
|
||||
|
|
@ -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
|
||||
|
|
|
|||
14
src/pow.cpp
14
src/pow.cpp
|
|
@ -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;
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
@ -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()));
|
||||
|
|
@ -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", "")
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -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)) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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(
|
||||
|
|
@ -3552,18 +3554,16 @@ 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;
|
||||
}
|
||||
|
|
@ -3571,8 +3571,9 @@ UniValue createrawpegin(const JSONRPCRequest& request)
|
|||
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;
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue