Browse Source

WIP: getblocktemplate for cn style return.

cn_merge
Jianping Wu 6 years ago
parent
commit
aa97d9938c
  1. 16
      src/chainparams.cpp
  2. 18
      src/cn_utils/cnutils.cpp
  3. 6
      src/cn_utils/cnutils.h
  4. 3
      src/cn_utils/cryptonote_core/tx_extra.h
  5. 3
      src/consensus/consensus.h
  6. 121
      src/rpc/mining.cpp

16
src/chainparams.cpp

@ -203,16 +203,25 @@ public: @@ -203,16 +203,25 @@ public:
pchMessageStart[3] = 0xe4;
nDefaultPort = 19335;
nPruneAfterHeight = 1000;
genesis = CreateGenesisBlock(0x5c4fd388, 0x80003898, 0x1e0fffff, 1, 500 * COIN);
#if 1
genesis = CreateGenesisBlock(1543789622, 1592, 0x1f0ffff0, 1, 500 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("7dc62041b90482eafe70fb1e1f6c8973a8c46b7f9f12b966e101c2bae126b5d4"));
assert(consensus.hashGenesisBlock == uint256S("860764b471430b96f15c145a44fd854f89d3be6f9ae054ef46e4c8473259bae3"));
assert(genesis.hashMerkleRoot == uint256S("3cf6c3b6da3f4058853ee70369ee43d473aca91ae8fc8f44a645beb21c392d80"));
#else
genesis = CreateGenesisBlock(1550900037, 3033, 0x1f0fffff, 1, 500 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("584a067cf7ea6daf30c351a46c6b7403d6fdc0e6e953cf7531d11eb7d834546c"));
assert(genesis.hashMerkleRoot == uint256S("3cf6c3b6da3f4058853ee70369ee43d473aca91ae8fc8f44a645beb21c392d80"));
#endif
vFixedSeeds.clear();
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
#if 0
vSeeds.emplace_back("testnet-seed.kevacoin.org");
vSeeds.emplace_back("testnet-seed.honourchat.com");
#endif
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,55); // P
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
@ -223,8 +232,9 @@ public: @@ -223,8 +232,9 @@ public:
base58Prefixes[KEVA_NAMESPACE] = std::vector<unsigned char>(1,53); // N
bech32_hrp = "tkva";
#if 0
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
#endif
fDefaultConsistencyChecks = false;
fRequireStandard = false;

18
src/cn_utils/cnutils.cpp

@ -34,4 +34,22 @@ bool validate_address(const char *addr, size_t len) { @@ -34,4 +34,22 @@ bool validate_address(const char *addr, size_t len) {
std::string output = "";
uint64_t prefix;
return tools::base58::decode_addr(addr, prefix, output);
}
//------------------------------------------------------------------------------------------------------------------------------
// equivalent of strstr, but with arbitrary bytes (ie, NULs)
// This does not differentiate between "not found" and "found at offset 0"
uint64_t slow_memmem(const void* start_buff, size_t buflen,const void* pat,size_t patlen)
{
const void* buf = start_buff;
const void* end=(const char*)buf+buflen;
if (patlen > buflen || patlen == 0) return 0;
while(buflen>0 && (buf=memchr(buf,((const char*)pat)[0],buflen-patlen+1)))
{
if(memcmp(buf,pat,patlen)==0)
return (const char*)buf - (const char*)start_buff;
buf=(const char*)buf+1;
buflen = (const char*)end - (const char*)buf;
}
return 0;
}

6
src/cn_utils/cnutils.h

@ -1,4 +1,8 @@ @@ -1,4 +1,8 @@
#pragma once
#include <cryptonote_core/cryptonote_basic.h>
#include <cryptonote_core/cryptonote_format_utils.h>
uint32_t convert_blob(const char *blob, size_t len, char *out);
bool validate_address(const char *addr, size_t len);
bool validate_address(const char *addr, size_t len);
uint64_t slow_memmem(const void* start_buff, size_t buflen,const void* pat,size_t patlen);

3
src/cn_utils/cryptonote_core/tx_extra.h

@ -13,6 +13,9 @@ @@ -13,6 +13,9 @@
#define TX_EXTRA_NONCE 0x02
#define TX_EXTRA_MERGE_MINING_TAG 0x03
#define TX_EXTRA_KEVA_BLOCKHASH_TAG 0xc1
#define TX_EXTRA_KEVA_TX_LIST_TAG 0xc2
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
namespace cryptonote

3
src/consensus/consensus.h

@ -16,7 +16,8 @@ static const unsigned int MAX_BLOCK_WEIGHT = 6000000; @@ -16,7 +16,8 @@ static const unsigned int MAX_BLOCK_WEIGHT = 6000000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const int64_t MAX_BLOCK_SIGOPS_COST = 80000;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
//static const int COINBASE_MATURITY = 100;
static const int COINBASE_MATURITY = 7;
static const int WITNESS_SCALE_FACTOR = 4;

121
src/rpc/mining.cpp

@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
#include <consensus/consensus.h>
#include <consensus/params.h>
#include <consensus/validation.h>
#include <consensus/merkle.h>
#include <core_io.h>
#include <init.h>
#include <validation.h>
@ -29,9 +30,11 @@ @@ -29,9 +30,11 @@
#include <memory>
#include <stdint.h>
#include <cryptonote_core/cryptonote_basic.h>
#include <cryptonote_core/cryptonote_format_utils.h>
#include <cnutils.h>
#include <string_tools.h>
#define MAX_RESERVE_SIZE 16
const std::string CN_DUMMY_ADDRESS = "44234234234";
unsigned int ParseConfirmTarget(const UniValue& value)
{
@ -689,7 +692,19 @@ UniValue getblocktemplate(const JSONRPCRequest& request) @@ -689,7 +692,19 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
UniValue getblocktemplate(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
// JSON-RPC2 request
// {reserve_size: 8, wallet_address: config.poolServer.poolAddress}
std::map<std::string, UniValue> kv;
request.params.getObjMap(kv);
int reserve_size = kv["reserve_size"].get_int();
bool fValidReserveSize = reserve_size > 0 && reserve_size <= MAX_RESERVE_SIZE;
std::vector<unsigned char> data;
std::string wallet_address = kv["wallet_address"].get_str();
CTxDestination walletDest = DecodeDestination(wallet_address);
bool fValidWalletAddress = walletDest.which() == 4; // Expect WitnessV0KeyHash
bool fInvalidInput = !fValidReserveSize || !fValidWalletAddress;
if (request.fHelp || fInvalidInput)
throw std::runtime_error(
"getblocktemplate ( TemplateRequest )\n"
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
@ -795,8 +810,8 @@ UniValue getblocktemplate(const JSONRPCRequest& request) @@ -795,8 +810,8 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
nStart = GetTime();
// Create new block
CScript scriptDummy = CScript() << OP_TRUE;
pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy, fSupportsSegwit);
CScript scriptPubKey = GetScriptForDestination(walletDest);
pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptPubKey, fSupportsSegwit);
if (!pblocktemplate)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
@ -854,8 +869,6 @@ UniValue getblocktemplate(const JSONRPCRequest& request) @@ -854,8 +869,6 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
aMutable.push_back("transactions");
aMutable.push_back("prevblock");
UniValue result(UniValue::VOBJ);
UniValue aRules(UniValue::VARR);
UniValue vbavailable(UniValue::VOBJ);
for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
@ -885,6 +898,13 @@ UniValue getblocktemplate(const JSONRPCRequest& request) @@ -885,6 +898,13 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
}
}
}
// Update witness commitment after adding the transactions.
pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, consensusParams);
BlockMerkleRoot(*pblock);
uint256 blockHash = pblock->GetHash();
#if 0
result.push_back(Pair("version", pblock->nVersion));
result.push_back(Pair("rules", aRules));
result.push_back(Pair("vbavailable", vbavailable));
@ -911,6 +931,93 @@ UniValue getblocktemplate(const JSONRPCRequest& request) @@ -911,6 +931,93 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) {
result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end())));
}
#endif
cryptonote::block cn_block;
// block_header
// const int cn_variant = b.major_version >= 7 ? b.major_version - 6 : 0;
cn_block.major_version = 8; // cn variant 2
cn_block.minor_version = 0;
cn_block.timestamp = pblock->GetBlockTime();
memcpy(&(cn_block.prev_id), pblock->hashPrevBlock.begin(), sizeof(pblock->hashPrevBlock));
cn_block.nonce = 0;
// block
// Coinbase transaction.
const uint32_t height = pindexPrev->nHeight+1;
const size_t miner_height = 10000;
const size_t median_size = 20000;
const uint64_t already_generated_coins = 10000;
const size_t current_block_size = 20000;
const uint64_t fee = 0;
const size_t max_outs = 1;
cryptonote::account_public_address miner_address;
cryptonote::transaction miner_tx;
cryptonote::blobdata extra_nonce;
// The reserve_offset is the offset for extra_nonce
extra_nonce.resize(reserve_size, 0);
if(!cryptonote::get_account_address_from_str(miner_address, CN_DUMMY_ADDRESS)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal error: failed to parse wallet address");
}
if (!construct_miner_tx(miner_height, median_size, already_generated_coins, current_block_size,
fee, miner_address, miner_tx, extra_nonce, max_outs)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal error: failed to construct miner tx");
}
cn_block.miner_tx = miner_tx;
cryptonote::blobdata block_blob = cryptonote::t_serializable_object_to_blob(cn_block);
crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(cn_block.miner_tx);
if(tx_pub_key == cryptonote::null_pkey) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal error: failed to tx pub key in coinbase extra");
}
uint32_t reserved_offset = slow_memmem((void*)block_blob.data(), block_blob.size(), &tx_pub_key, sizeof(tx_pub_key));
if(!reserved_offset) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal error: Failed to find tx pub key in blockblob");
}
reserved_offset += sizeof(tx_pub_key) + 2; //2 bytes: tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte)
if(reserved_offset + reserve_size > block_blob.size())
{
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal error: Failed to calculate offset");
}
// No transactions other than base one.
cn_block.tx_hashes.clear();
// Copy kevacoin block hash to the extra field, as a proof that the work has
// been done for the block.
// Copy all the txs to extra so that later we can use them to
// reconstruct the block.
const uint32_t blockHashSize = blockHash.size();
const uint32_t txTotalSize = 1 + blockHashSize + 1 + 4 + pblock->vtx.size() * sizeof(CTransaction);
cn_block.miner_tx.extra.resize(cn_block.miner_tx.extra.size() + txTotalSize, 0);
size_t lastOffset = cn_block.miner_tx.extra.size();
uint8_t miningTag = TX_EXTRA_KEVA_BLOCKHASH_TAG;
memcpy(cn_block.miner_tx.extra.data() + lastOffset, &miningTag, 1);
lastOffset ++;
memcpy(cn_block.miner_tx.extra.data() + lastOffset, blockHash.begin(), blockHashSize);
lastOffset += blockHashSize;
uint8_t kevaTxsTag = TX_EXTRA_KEVA_TX_LIST_TAG;
memcpy(cn_block.miner_tx.extra.data() + lastOffset, &kevaTxsTag, 1);
lastOffset ++;
uint32_t txsSize = ;
// This is not right! Need to serialize the transactions.
// Maybe using SerializationOp of CBlock to serialize the all block instead?
memcpy(cn_block.miner_tx.extra.data() + lastOffset, pblock->vtx.data(), pblock->vtx.size() * sizeof(CTransaction));
UniValue result(UniValue::VOBJ);
cryptonote::blobdata hashing_blob;
cryptonote::get_block_hashing_blob(cn_block, hashing_blob);
//res.prev_hash = epee::string_tools::pod_to_hex(cn_block.prev_id);
//res.blocktemplate_blob = epee::string_tools::buff_to_hex_nodelimer(block_blob);
//res.blockhashing_blob = epee::string_tools::buff_to_hex_nodelimer(hashing_blob);
result.push_back(Pair("blocktemplate_blob", pblock->hashPrevBlock.GetHex()));
result.push_back(Pair("difficulty", pblock->hashPrevBlock.GetHex()));
result.push_back(Pair("height", std::to_string(height)));
result.push_back(Pair("reserved_offset", std::to_string(reserved_offset)));
return result;
}

Loading…
Cancel
Save