From af3208bfa6967d6b35aecf0ba35d9d6bf0f8317e Mon Sep 17 00:00:00 2001 From: mruddy Date: Thu, 30 Jul 2015 19:56:00 -0400 Subject: Resolve issue 3166. These changes decode valid SIGHASH types on signatures in assembly (asm) representations of scriptSig scripts. This squashed commit incorporates substantial helpful feedback from jtimon, laanwj, and sipa. --- src/core_write.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) (limited to 'src/core_write.cpp') diff --git a/src/core_write.cpp b/src/core_write.cpp index c3babec2f..2ad42badd 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -15,6 +15,7 @@ #include "utilmoneystr.h" #include "utilstrencodings.h" +#include #include using namespace std; @@ -54,6 +55,67 @@ string FormatScript(const CScript& script) return ret.substr(0, ret.size() - 1); } +const map mapSigHashTypes = + boost::assign::map_list_of + (static_cast(SIGHASH_ALL), string("ALL")) + (static_cast(SIGHASH_ALL|SIGHASH_ANYONECANPAY), string("ALL|ANYONECANPAY")) + (static_cast(SIGHASH_NONE), string("NONE")) + (static_cast(SIGHASH_NONE|SIGHASH_ANYONECANPAY), string("NONE|ANYONECANPAY")) + (static_cast(SIGHASH_SINGLE), string("SINGLE")) + (static_cast(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), string("SINGLE|ANYONECANPAY")) + ; + +/** + * Create the assembly string representation of a CScript object. + * @param[in] script CScript object to convert into the asm string representation. + * @param[in] fAttemptSighashDecode Whether to attempt to decode sighash types on data within the script that matches the format + * of a signature. Only pass true for scripts you believe could contain signatures. For example, + * pass false, or omit the this argument (defaults to false), for scriptPubKeys. + */ +string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) +{ + string str; + opcodetype opcode; + vector vch; + CScript::const_iterator pc = script.begin(); + while (pc < script.end()) { + if (!str.empty()) { + str += " "; + } + if (!script.GetOp(pc, opcode, vch)) { + str += "[error]"; + return str; + } + if (0 <= opcode && opcode <= OP_PUSHDATA4) { + if (vch.size() <= static_cast::size_type>(4)) { + str += strprintf("%d", CScriptNum(vch, false).getint()); + } else { + // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature + if (fAttemptSighashDecode && !script.IsUnspendable()) { + string strSigHashDecode; + // goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig. + // this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to + // the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the + // checks in CheckSignatureEncoding. + if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, NULL)) { + const unsigned char chSigHashType = vch.back(); + if (mapSigHashTypes.count(chSigHashType)) { + strSigHashDecode = "[" + mapSigHashTypes.find(chSigHashType)->second + "]"; + vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode. + } + } + str += HexStr(vch) + strSigHashDecode; + } else { + str += HexStr(vch); + } + } + } else { + str += GetOpName(opcode); + } + } + return str; +} + string EncodeHexTx(const CTransaction& tx) { CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -68,7 +130,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, vector addresses; int nRequired; - out.pushKV("asm", scriptPubKey.ToString()); + out.pushKV("asm", ScriptToAsmStr(scriptPubKey)); if (fIncludeHex) out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())); @@ -101,7 +163,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) in.pushKV("txid", txin.prevout.hash.GetHex()); in.pushKV("vout", (int64_t)txin.prevout.n); UniValue o(UniValue::VOBJ); - o.pushKV("asm", txin.scriptSig.ToString()); + o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); in.pushKV("scriptSig", o); } -- cgit v1.2.3 From 9623e934732ba0f0a5176cd3d993ebcda327b413 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 4 Sep 2015 16:11:34 +0200 Subject: [Univalue] add univalue over subtree similar to secp256k1 include and compile univalue over a subtree --- src/core_write.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core_write.cpp') diff --git a/src/core_write.cpp b/src/core_write.cpp index 2ad42badd..533fedfe7 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -10,7 +10,7 @@ #include "script/standard.h" #include "serialize.h" #include "streams.h" -#include "univalue/univalue.h" +#include #include "util.h" #include "utilmoneystr.h" #include "utilstrencodings.h" -- cgit v1.2.3 From fa24439ff3d8ab5b9efaf66ef4dae6713b88cb35 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 13 Dec 2015 17:58:29 +0100 Subject: Bump copyright headers to 2015 --- src/core_write.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core_write.cpp') diff --git a/src/core_write.cpp b/src/core_write.cpp index 533fedfe7..b660e86c3 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -- cgit v1.2.3 From d03e46625ac95954bb9ecbc2cf73ffd8de6b8a13 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 5 Apr 2016 14:26:01 +0200 Subject: Fix formatting of NOPs for generated script tests --- src/core_write.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core_write.cpp') diff --git a/src/core_write.cpp b/src/core_write.cpp index b660e86c3..6f9e2266a 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -35,7 +35,7 @@ string FormatScript(const CScript& script) } else if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) { ret += strprintf("%i ", op - OP_1NEGATE - 1); continue; - } else if (op >= OP_NOP && op <= OP_CHECKMULTISIGVERIFY) { + } else if (op >= OP_NOP && op <= OP_NOP10) { string str(GetOpName(op)); if (str.substr(0, 3) == string("OP_")) { ret += str.substr(3, string::npos) + " "; @@ -45,7 +45,7 @@ string FormatScript(const CScript& script) if (vch.size() > 0) { ret += strprintf("0x%x 0x%x ", HexStr(it2, it - vch.size()), HexStr(it - vch.size(), it)); } else { - ret += strprintf("0x%x", HexStr(it2, it)); + ret += strprintf("0x%x ", HexStr(it2, it)); } continue; } -- cgit v1.2.3 From 4408558843c6c2b7abeb4160f641dfdbf5be5eb4 Mon Sep 17 00:00:00 2001 From: jonnynewbs Date: Wed, 21 Sep 2016 10:52:53 -0400 Subject: Update bitcoin-tx to output witness data. --- src/core_write.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/core_write.cpp') diff --git a/src/core_write.cpp b/src/core_write.cpp index 6f9e2266a..ea01ddc10 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -151,11 +151,13 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) { entry.pushKV("txid", tx.GetHash().GetHex()); + entry.pushKV("hash", tx.GetWitnessHash().GetHex()); entry.pushKV("version", tx.nVersion); entry.pushKV("locktime", (int64_t)tx.nLockTime); UniValue vin(UniValue::VARR); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + for (unsigned int i = 0; i < tx.vin.size(); i++) { + const CTxIn& txin = tx.vin[i]; UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); @@ -166,6 +168,13 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); in.pushKV("scriptSig", o); + if (!tx.wit.IsNull() && i < tx.wit.vtxinwit.size() && !tx.wit.vtxinwit[i].IsNull()) { + UniValue txinwitness(UniValue::VARR); + for (const auto& item : tx.wit.vtxinwit[i].scriptWitness.stack) { + txinwitness.push_back(HexStr(item.begin(), item.end())); + } + in.pushKV("txinwitness", txinwitness); + } } in.pushKV("sequence", (int64_t)txin.nSequence); vin.push_back(in); -- cgit v1.2.3 From f6fb7acda4aefd01b8ef6cd77063bfc0c4f4ab36 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 4 Aug 2016 02:49:16 +0200 Subject: Move CTxInWitness inside CTxIn --- src/core_write.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core_write.cpp') diff --git a/src/core_write.cpp b/src/core_write.cpp index ea01ddc10..112571859 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -168,9 +168,9 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); in.pushKV("scriptSig", o); - if (!tx.wit.IsNull() && i < tx.wit.vtxinwit.size() && !tx.wit.vtxinwit[i].IsNull()) { + if (!tx.vin[i].scriptWitness.IsNull()) { UniValue txinwitness(UniValue::VARR); - for (const auto& item : tx.wit.vtxinwit[i].scriptWitness.stack) { + for (const auto& item : tx.vin[i].scriptWitness.stack) { txinwitness.push_back(HexStr(item.begin(), item.end())); } in.pushKV("txinwitness", txinwitness); -- cgit v1.2.3 From bc7ff8db99dbc28f8b2d7a22f4650fa5349cb23b Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Sun, 20 Nov 2016 09:54:51 -0500 Subject: Add option to return non-segwit serialization via rpc --- src/core_write.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core_write.cpp') diff --git a/src/core_write.cpp b/src/core_write.cpp index ea01ddc10..9f859ba9e 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -116,9 +116,9 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) return str; } -string EncodeHexTx(const CTransaction& tx) +string EncodeHexTx(const CTransaction& tx, const int serialFlags) { - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serialFlags); ssTx << tx; return HexStr(ssTx.begin(), ssTx.end()); } -- cgit v1.2.3 From 27765b6403cece54320374b37afb01a0cfe571c3 Mon Sep 17 00:00:00 2001 From: isle2983 Date: Sat, 31 Dec 2016 11:01:21 -0700 Subject: Increment MIT Licence copyright header year on files modified in 2016 Edited via: $ contrib/devtools/copyright_header.py update . --- src/core_write.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core_write.cpp') diff --git a/src/core_write.cpp b/src/core_write.cpp index 9eed2270d..ee8a897ca 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2015 The Bitcoin Core developers +// Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -- cgit v1.2.3 From b7b48c8bbdf7a90861610b035d8b0a247ef78c45 Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Fri, 27 Jan 2017 17:43:41 +0900 Subject: Refactor: Remove using namespace from src/*.cpp. --- src/core_write.cpp | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'src/core_write.cpp') diff --git a/src/core_write.cpp b/src/core_write.cpp index ee8a897ca..b0993a131 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -18,16 +18,14 @@ #include #include -using namespace std; - -string FormatScript(const CScript& script) +std::string FormatScript(const CScript& script) { - string ret; + std::string ret; CScript::const_iterator it = script.begin(); opcodetype op; while (it != script.end()) { CScript::const_iterator it2 = it; - vector vch; + std::vector vch; if (script.GetOp2(it, op, &vch)) { if (op == OP_0) { ret += "0 "; @@ -36,9 +34,9 @@ string FormatScript(const CScript& script) ret += strprintf("%i ", op - OP_1NEGATE - 1); continue; } else if (op >= OP_NOP && op <= OP_NOP10) { - string str(GetOpName(op)); - if (str.substr(0, 3) == string("OP_")) { - ret += str.substr(3, string::npos) + " "; + std::string str(GetOpName(op)); + if (str.substr(0, 3) == std::string("OP_")) { + ret += str.substr(3, std::string::npos) + " "; continue; } } @@ -55,14 +53,14 @@ string FormatScript(const CScript& script) return ret.substr(0, ret.size() - 1); } -const map mapSigHashTypes = +const std::map mapSigHashTypes = boost::assign::map_list_of - (static_cast(SIGHASH_ALL), string("ALL")) - (static_cast(SIGHASH_ALL|SIGHASH_ANYONECANPAY), string("ALL|ANYONECANPAY")) - (static_cast(SIGHASH_NONE), string("NONE")) - (static_cast(SIGHASH_NONE|SIGHASH_ANYONECANPAY), string("NONE|ANYONECANPAY")) - (static_cast(SIGHASH_SINGLE), string("SINGLE")) - (static_cast(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), string("SINGLE|ANYONECANPAY")) + (static_cast(SIGHASH_ALL), std::string("ALL")) + (static_cast(SIGHASH_ALL|SIGHASH_ANYONECANPAY), std::string("ALL|ANYONECANPAY")) + (static_cast(SIGHASH_NONE), std::string("NONE")) + (static_cast(SIGHASH_NONE|SIGHASH_ANYONECANPAY), std::string("NONE|ANYONECANPAY")) + (static_cast(SIGHASH_SINGLE), std::string("SINGLE")) + (static_cast(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), std::string("SINGLE|ANYONECANPAY")) ; /** @@ -72,11 +70,11 @@ const map mapSigHashTypes = * of a signature. Only pass true for scripts you believe could contain signatures. For example, * pass false, or omit the this argument (defaults to false), for scriptPubKeys. */ -string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) +std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) { - string str; + std::string str; opcodetype opcode; - vector vch; + std::vector vch; CScript::const_iterator pc = script.begin(); while (pc < script.end()) { if (!str.empty()) { @@ -87,12 +85,12 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) return str; } if (0 <= opcode && opcode <= OP_PUSHDATA4) { - if (vch.size() <= static_cast::size_type>(4)) { + if (vch.size() <= static_cast::size_type>(4)) { str += strprintf("%d", CScriptNum(vch, false).getint()); } else { // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature if (fAttemptSighashDecode && !script.IsUnspendable()) { - string strSigHashDecode; + std::string strSigHashDecode; // goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig. // this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to // the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the @@ -116,7 +114,7 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) return str; } -string EncodeHexTx(const CTransaction& tx, const int serialFlags) +std::string EncodeHexTx(const CTransaction& tx, const int serialFlags) { CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serialFlags); ssTx << tx; @@ -127,7 +125,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex) { txnouttype type; - vector addresses; + std::vector addresses; int nRequired; out.pushKV("asm", ScriptToAsmStr(scriptPubKey)); -- cgit v1.2.3