diff --git a/qa/rpc-tests/pegging.py b/qa/rpc-tests/pegging.py index ae61964d83..e21208dabd 100755 --- a/qa/rpc-tests/pegging.py +++ b/qa/rpc-tests/pegging.py @@ -153,7 +153,7 @@ try: pegtxid = sidechain.claimpegin(raw, proof, sidechain.getnewaddress()) raise Exception("Peg-in with non-matching claim_script should fail.") except JSONRPCException as e: - assert("Given claim_script is not a valid v0 witness program" in e.error["message"]) + assert("Given claim_script does not match the given Bitcoin transaction." in e.error["message"]) pass # 12 confirms allows in mempool diff --git a/src/script/script.h b/src/script/script.h index da376c3ae5..ca3343016d 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -325,12 +325,6 @@ public: return m_value; } - // Only used for peg-in witness values - int64_t getint64() const - { - return m_value; - } - std::vector getvch() const { return serialize(m_value); diff --git a/src/validation.cpp b/src/validation.cpp index 1ce0569f51..c3f133c24c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2375,8 +2375,17 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p return false; } - // Get output value. Special 8 byte length to capture possible bitcoin values - CAmount value = CScriptNum(stack[0], true, 8).getint64(); + CDataStream stream(stack[0], SER_NETWORK, PROTOCOL_VERSION); + CAmount value; + try { + stream >> value; + } catch (...) { + return false; + } + + if (!MoneyRange(value)) { + return false; + } // Get asset type if (stack[1].size() != 32) { @@ -2473,7 +2482,11 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p // Constructs unblinded output to be used in amount and scriptpubkey checks during pegin CTxOut GetPeginOutputFromWitness(const CScriptWitness& pegin_witness) { - return CTxOut(CAsset(pegin_witness.stack[1]), CScriptNum(pegin_witness.stack[0], true, 8).getint64(), CScript(pegin_witness.stack[3].begin(), pegin_witness.stack[3].end())); + CDataStream stream(pegin_witness.stack[0], SER_NETWORK, PROTOCOL_VERSION); + CAmount value; + stream >> value; + + return CTxOut(CAsset(pegin_witness.stack[1]), value, CScript(pegin_witness.stack[3].begin(), pegin_witness.stack[3].end())); } // Protected by cs_main diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 68fcdd097a..f53d0a1841 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3579,6 +3579,9 @@ UniValue createrawpegin(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "Given claim_script is not a valid v0 witness program."); } nOut = GetPeginTxnOutputIndex(txBTC, witnessProgScript); + if (nOut == txBTC.vout.size()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Given claim_script does not match the given Bitcoin transaction."); + } } else { // Look through address book for pegin contract value by extracting the unlderlying witness program from p2sh-p2wpkh @@ -3611,6 +3614,17 @@ UniValue createrawpegin(const JSONRPCRequest& request) CAmount value = txBTC.vout[nOut].nValue; + CDataStream stream(0, 0); + try { + stream << value; + } catch (...) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Amount serialization is invalid."); + } + // Need to reinterpret bytes as unsigned chars before adding to witness + char* buf = stream.data(); + unsigned char* membuf = reinterpret_cast(buf); + std::vector value_bytes(membuf, membuf + stream.size()); + uint256 genesisBlockHash = Params().ParentGenesisBlockHash(); // Manually construct peg-in transaction, sign it, and send it off. @@ -3639,7 +3653,7 @@ UniValue createrawpegin(const JSONRPCRequest& request) // Construct pegin proof CScriptWitness pegin_witness; std::vector >& stack = pegin_witness.stack; - stack.push_back(CScriptNum::serialize(value)); + stack.push_back(value_bytes); stack.push_back(std::vector(Params().GetConsensus().pegged_asset.begin(), Params().GetConsensus().pegged_asset.end())); stack.push_back(std::vector(genesisBlockHash.begin(), genesisBlockHash.end())); stack.push_back(std::vector(witnessProgScript.begin(), witnessProgScript.end()));