Skip to content

Commit

Permalink
Add option to return non-segwit serialization via rpc
Browse files Browse the repository at this point in the history
Github-Pull: bitcoin#9194
Rebased-From: 835c75acaac004c3315395dcd7d1f193dfb9e5da
  • Loading branch information
instagibbs authored and laanwj committed Dec 5, 2016
1 parent a710a43 commit 21ccb9f
Show file tree
Hide file tree
Showing 9 changed files with 40 additions and 9 deletions.
20 changes: 17 additions & 3 deletions qa/rpc-tests/segwit.py
Expand Up @@ -13,6 +13,7 @@
from test_framework.address import script_to_p2sh, key_to_p2pkh
from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG
from io import BytesIO
from test_framework.mininode import FromHex

NODE_0 = 0
NODE_1 = 1
Expand Down Expand Up @@ -83,8 +84,8 @@ def setup_chain(self):

def setup_network(self):
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness"]))
self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]))
self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness", "-rpcserialversion=0"]))
self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=2"]))
self.nodes.append(start_node(2, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]))
connect_nodes(self.nodes[1], 0)
connect_nodes(self.nodes[2], 1)
Expand Down Expand Up @@ -210,7 +211,20 @@ def run_test(self):
block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3)
sync_blocks(self.nodes)
assert_equal(len(self.nodes[2].getrawmempool()), 0)
assert_equal(len(self.nodes[2].getblock(block[0])["tx"]), 5)
segwit_tx_list = self.nodes[2].getblock(block[0])["tx"]
assert_equal(len(segwit_tx_list), 5)

print("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
# Note: node1 has version 2, which is simply >0 and will catch future upgrades in tests
assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False))
assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False))
for i in range(len(segwit_tx_list)):
tx = FromHex(CTransaction(), self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
assert(self.nodes[2].getrawtransaction(segwit_tx_list[i]) != self.nodes[0].getrawtransaction(segwit_tx_list[i]))
assert(self.nodes[1].getrawtransaction(segwit_tx_list[i], 0) == self.nodes[2].getrawtransaction(segwit_tx_list[i]))
assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) != self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness()))

print("Verify witness txs without witness data are invalid after the fork")
self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False)
Expand Down
2 changes: 1 addition & 1 deletion src/core_io.h
Expand Up @@ -25,7 +25,7 @@ extern std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::strin

// core_write.cpp
extern std::string FormatScript(const CScript& script);
extern std::string EncodeHexTx(const CTransaction& tx);
extern std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
extern void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry);

Expand Down
4 changes: 2 additions & 2 deletions src/core_write.cpp
Expand Up @@ -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());
}
Expand Down
4 changes: 4 additions & 0 deletions src/init.cpp
Expand Up @@ -364,6 +364,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort()));
strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy"));
strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE));
strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(>0) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION));
strUsage += HelpMessageOpt("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect"));
strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL));
Expand Down Expand Up @@ -982,6 +983,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);

if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0)
return InitError("rpcserialversion must be non-negative.");

nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);

fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT);
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/blockchain.cpp
Expand Up @@ -607,7 +607,7 @@ UniValue getblock(const UniValue& params, bool fHelp)

if (!fVerbose)
{
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
return strHex;
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/rawtransaction.cpp
Expand Up @@ -209,7 +209,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");

string strHex = EncodeHexTx(tx);
string strHex = EncodeHexTx(tx, RPCSerializationFlags());

if (!fVerbose)
return strHex;
Expand Down
8 changes: 8 additions & 0 deletions src/rpc/server.cpp
Expand Up @@ -495,4 +495,12 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6
deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))));
}

int RPCSerializationFlags()
{
int flag = 0;
if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0)
flag |= SERIALIZE_TRANSACTION_NO_WITNESS;
return flag;
}

CRPCTable tableRPC;
5 changes: 5 additions & 0 deletions src/rpc/server.h
Expand Up @@ -19,6 +19,8 @@

#include <univalue.h>

static const unsigned int DEFAULT_RPC_SERIALIZE_VERSION = 1;

class CRPCCommand;

namespace RPCServer
Expand Down Expand Up @@ -195,4 +197,7 @@ void InterruptRPC();
void StopRPC();
std::string JSONRPCExecBatch(const UniValue& vReq);

// Retrieves any serialization flags requested in command line argument
int RPCSerializationFlags();

#endif // BITCOIN_RPCSERVER_H
2 changes: 1 addition & 1 deletion src/wallet/rpcwallet.cpp
Expand Up @@ -1780,7 +1780,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
ListTransactions(wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));

string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
entry.push_back(Pair("hex", strHex));

return entry;
Expand Down

0 comments on commit 21ccb9f

Please sign in to comment.