Merge #753: getnewblockhex: Take data push for arbitrary data in block coinbase c…

6d9639b21 getnewblockhex: Take data push for arbitrary data in block coinbase commitment (Gregory Sanders)

Pull request description:

  …ommitment

  Useful for non-consensus proof of publication of data.

Tree-SHA512: 8967238c97b5188db50f99d7a8d8a1b26712a6b4c02812880502b5eb9572f7ca6a509a2020cb9661b2931f7d2b06f0580baa8652516b529b2386e92e73767a73
This commit is contained in:
Steven Roose 2019-10-28 16:09:41 +01:00
commit 1ff3a39d11
No known key found for this signature in database
GPG key ID: 2F2A88D7F8D68E87
4 changed files with 33 additions and 5 deletions

View file

@ -102,7 +102,7 @@ void BlockAssembler::resetBlock()
Optional<int64_t> BlockAssembler::m_last_block_num_txs{nullopt};
Optional<int64_t> BlockAssembler::m_last_block_weight{nullopt};
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, int min_tx_age, DynaFedParamEntry* proposed_entry)
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, int min_tx_age, DynaFedParamEntry* proposed_entry, CScript const* commit_script)
{
assert(min_tx_age >= 0);
int64_t nTimeStart = GetTimeMicros();
@ -195,6 +195,10 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
}
}
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
// Non-consensus commitment output before finishing coinbase transaction
if (commit_script) {
coinbaseTx.vout.insert(coinbaseTx.vout.begin(), CTxOut(policyAsset, 0, *commit_script));
}
pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
pblocktemplate->vTxFees[0] = -nFees;

View file

@ -159,7 +159,7 @@ public:
BlockAssembler(const CChainParams& params, const Options& options);
/** Construct a new block template with coinbase to scriptPubKeyIn. min_tx_age is in seconds */
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, int min_tx_age=0, DynaFedParamEntry* = nullptr);
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, int min_tx_age=0, DynaFedParamEntry* = nullptr, CScript const* commit_script = nullptr);
static Optional<int64_t> m_last_block_num_txs;
static Optional<int64_t> m_last_block_weight;

View file

@ -999,7 +999,7 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
UniValue getnewblockhex(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 2)
if (request.fHelp || request.params.size() > 3)
throw std::runtime_error(
RPCHelpMan{"getnewblockhex",
"\nGets hex representation of a proposed, unmined new block\n",
@ -1017,6 +1017,7 @@ UniValue getnewblockhex(const JSONRPCRequest& request)
},
},
"proposed_parameters"},
{"commit_data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Data in hex to be committed to in an additional coinbase output."},
},
RPCResult{
"blockhex (hex) The block hex\n"
@ -1071,9 +1072,17 @@ UniValue getnewblockhex(const JSONRPCRequest& request)
proposed.m_serialize_type = 2;
}
// Any commitment required for non-consensus reasons.
// This will be placed in the first coinbase output.
CScript data_commitment;
if (!request.params[2].isNull()) {
std::vector<unsigned char> data_bytes = ParseHex(request.params[2].get_str());
data_commitment = CScript() << OP_RETURN << data_bytes;
}
CScript feeDestinationScript = Params().GetConsensus().mandatory_coinbase_destination;
if (feeDestinationScript == CScript()) feeDestinationScript = CScript() << OP_TRUE;
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(feeDestinationScript, required_wait, &proposed));
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(feeDestinationScript, required_wait, &proposed, data_commitment.empty() ? nullptr : &data_commitment));
if (!pblocktemplate.get()) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
}
@ -1474,7 +1483,7 @@ static const CRPCCommand commands[] =
{ "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
{ "generating", "combineblocksigs", &combineblocksigs, {"blockhex","signatures"} },
{ "mining", "submitheader", &submitheader, {"hexdata"} },
{ "generating", "getnewblockhex", &getnewblockhex, {"min_tx_age", "proposed_parameters"} },
{ "generating", "getnewblockhex", &getnewblockhex, {"min_tx_age", "proposed_parameters", "commit_data"} },
{ "generating", "getcompactsketch", &getcompactsketch, {"block_hex"} },
{ "generating", "consumecompactsketch", &consumecompactsketch, {"sketch"} },
{ "generating", "consumegetblocktxn", &consumegetblocktxn, {"full_block", "block_tx_req"} },

View file

@ -10,6 +10,13 @@ from test_framework import (
address,
key,
)
from test_framework.messages import (
FromHex,
CBlock,
)
from test_framework.script import (
CScript
)
# Generate wallet import format from private key.
def wif(pk):
@ -115,6 +122,14 @@ class BlockSignTest(BitcoinTestFramework):
miner.sendtoaddress(miner_next.getnewaddress(), int(miner.getbalance()['bitcoin']/10), "", "", True)
# miner makes a block
block = miner.getnewblockhex()
block_struct = FromHex(CBlock(), block)
# make another block with the commitment field filled out
dummy_block = miner.getnewblockhex(commit_data="deadbeef")
dummy_struct = FromHex(CBlock(), dummy_block)
assert_equal(len(dummy_struct.vtx[0].vout), len(block_struct.vtx[0].vout) + 1)
# OP_RETURN deadbeef
assert_equal(CScript(dummy_struct.vtx[0].vout[0].scriptPubKey).hex(), '6a04deadbeef')
# All nodes get compact blocks, first node may get complete
# block in 0.5 RTT even with transactions thanks to p2p connection