aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xqa/rpc-tests/getauxblock.py123
-rwxr-xr-xqa/rpc-tests/rest.py20
-rw-r--r--qa/rpc-tests/test_framework/auxpow.py111
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/auxpow.cpp192
-rw-r--r--src/auxpow.h185
-rw-r--r--src/chain.cpp27
-rw-r--r--src/chain.h17
-rw-r--r--src/chainparams.cpp11
-rw-r--r--src/chainparams.h1
-rw-r--r--src/consensus/params.h17
-rw-r--r--src/init.cpp3
-rw-r--r--src/main.cpp95
-rw-r--r--src/main.h10
-rw-r--r--src/miner.cpp9
-rw-r--r--src/miner.h3
-rw-r--r--src/primitives/block.cpp22
-rw-r--r--src/primitives/block.h58
-rw-r--r--src/primitives/pureheader.cpp31
-rw-r--r--src/primitives/pureheader.h197
-rw-r--r--src/rpcblockchain.cpp34
-rw-r--r--src/rpcmining.cpp179
-rw-r--r--src/rpcserver.cpp3
-rw-r--r--src/rpcserver.h1
-rw-r--r--src/test/auxpow_tests.cpp442
-rw-r--r--src/test/miner_tests.cpp2
-rw-r--r--src/txdb.cpp6
-rw-r--r--src/wallet/wallet.cpp85
-rw-r--r--src/wallet/wallet.h60
30 files changed, 1720 insertions, 229 deletions
diff --git a/qa/rpc-tests/getauxblock.py b/qa/rpc-tests/getauxblock.py
new file mode 100755
index 000000000..dfb57be8d
--- /dev/null
+++ b/qa/rpc-tests/getauxblock.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+# Copyright (c) 2014-2015 Daniel Kraft
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+# Test the "getauxblock" merge-mining RPC interface.
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+from test_framework import auxpow
+
+class GetAuxBlockTest (BitcoinTestFramework):
+
+ def run_test (self):
+ BitcoinTestFramework.run_test (self)
+
+ # Generate a block so that we are not "downloading blocks".
+ self.nodes[0].generate (1)
+
+ # Compare basic data of getauxblock to getblocktemplate.
+ auxblock = self.nodes[0].getauxblock ()
+ blocktemplate = self.nodes[0].getblocktemplate ()
+ assert_equal (auxblock['coinbasevalue'], blocktemplate['coinbasevalue'])
+ assert_equal (auxblock['bits'], blocktemplate['bits'])
+ assert_equal (auxblock['height'], blocktemplate['height'])
+ assert_equal (auxblock['previousblockhash'], blocktemplate['previousblockhash'])
+
+ # Compare target and take byte order into account.
+ target = auxblock['_target']
+ reversedTarget = auxpow.reverseHex (target)
+ assert_equal (reversedTarget, blocktemplate['target'])
+
+ # Verify data that can be found in another way.
+ assert_equal (auxblock['chainid'], 1)
+ assert_equal (auxblock['height'], self.nodes[0].getblockcount () + 1)
+ assert_equal (auxblock['previousblockhash'], self.nodes[0].getblockhash (auxblock['height'] - 1))
+
+ # Calling again should give the same block.
+ auxblock2 = self.nodes[0].getauxblock ()
+ assert_equal (auxblock2, auxblock)
+
+ # If we receive a new block, the old hash will be replaced.
+ self.sync_all ()
+ self.nodes[1].generate (1)
+ self.sync_all ()
+ auxblock2 = self.nodes[0].getauxblock ()
+ assert auxblock['hash'] != auxblock2['hash']
+ try:
+ self.nodes[0].getauxblock (auxblock['hash'], "x")
+ raise AssertionError ("invalid block hash accepted")
+ except JSONRPCException as exc:
+ assert_equal (exc.error['code'], -8)
+
+ # Invalid format for auxpow.
+ try:
+ self.nodes[0].getauxblock (auxblock2['hash'], "x")
+ raise AssertionError ("malformed auxpow accepted")
+ except JSONRPCException as exc:
+ assert_equal (exc.error['code'], -1)
+
+ # Invalidate the block again, send a transaction and query for the
+ # auxblock to solve that contains the transaction.
+ self.nodes[0].generate (1)
+ addr = self.nodes[1].getnewaddress ()
+ txid = self.nodes[0].sendtoaddress (addr, 1)
+ self.sync_all ()
+ assert_equal (self.nodes[1].getrawmempool (), [txid])
+ auxblock = self.nodes[0].getauxblock ()
+ blocktemplate = self.nodes[0].getblocktemplate ()
+ target = blocktemplate['target']
+
+ # Compute invalid auxpow.
+ apow = auxpow.computeAuxpow (auxblock['hash'], target, False)
+ res = self.nodes[0].getauxblock (auxblock['hash'], apow)
+ assert not res
+
+ # Compute and submit valid auxpow.
+ apow = auxpow.computeAuxpow (auxblock['hash'], target, True)
+ res = self.nodes[0].getauxblock (auxblock['hash'], apow)
+ assert res
+
+ # Make sure that the block is indeed accepted.
+ self.sync_all ()
+ assert_equal (self.nodes[1].getrawmempool (), [])
+ height = self.nodes[1].getblockcount ()
+ assert_equal (height, auxblock['height'])
+ assert_equal (self.nodes[1].getblockhash (height), auxblock['hash'])
+
+ # Call getblock and verify the auxpow field.
+ data = self.nodes[1].getblock (auxblock['hash'])
+ assert 'auxpow' in data
+ auxJson = data['auxpow']
+ assert_equal (auxJson['index'], 0)
+ assert_equal (auxJson['parentblock'], apow[-160:])
+
+ # Check that previous blocks don't have 'auxpow' in their getblock JSON.
+ oldHash = self.nodes[1].getblockhash (100)
+ data = self.nodes[1].getblock (oldHash)
+ assert 'auxpow' not in data
+
+ # Check that it paid correctly to the first node.
+ t = self.nodes[0].listtransactions ("", 1)
+ assert_equal (len (t), 1)
+ t = t[0]
+ assert_equal (t['category'], "immature")
+ assert_equal (t['blockhash'], auxblock['hash'])
+ assert t['generated']
+ assert t['amount'] >= Decimal ("25")
+ assert_equal (t['confirmations'], 1)
+
+ # Verify the coinbase script. Ensure that it includes the block height
+ # to make the coinbase tx unique. The expected block height is around
+ # 200, so that the serialisation of the CScriptNum ends in an extra 00.
+ # The vector has length 2, which makes up for 02XX00 as the serialised
+ # height. Check this.
+ blk = self.nodes[1].getblock (auxblock['hash'])
+ tx = self.nodes[1].getrawtransaction (blk['tx'][0], 1)
+ coinbase = tx['vin'][0]['coinbase']
+ assert_equal ("02%02x00" % auxblock['height'], coinbase[0 : 6])
+
+if __name__ == '__main__':
+ GetAuxBlockTest ().main ()
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
index 6c51b2fcd..f5eda9968 100755
--- a/qa/rpc-tests/rest.py
+++ b/qa/rpc-tests/rest.py
@@ -14,6 +14,7 @@ from struct import *
import binascii
import json
import StringIO
+import auxpow
try:
import http.client as httplib
@@ -57,6 +58,9 @@ class RESTTest (BitcoinTestFramework):
self.sync_all()
def run_test(self):
+ auxpow.mineAuxpowBlock(self.nodes[0])
+ self.sync_all()
+
url = urlparse.urlparse(self.nodes[0].url)
print "Mining blocks..."
@@ -215,24 +219,26 @@ class RESTTest (BitcoinTestFramework):
# compare with block header
response_header = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"bin", "", True)
assert_equal(response_header.status, 200)
- assert_equal(int(response_header.getheader('content-length')), 80)
+ headerLen = int(response_header.getheader('content-length'))
+ assert_greater_than(headerLen, 80)
response_header_str = response_header.read()
- assert_equal(response_str[0:80], response_header_str)
+ assert_equal(response_str[0:headerLen], response_header_str)
# check block hex format
response_hex = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"hex", "", True)
assert_equal(response_hex.status, 200)
assert_greater_than(int(response_hex.getheader('content-length')), 160)
- response_hex_str = response_hex.read()
- assert_equal(response_str.encode("hex")[0:160], response_hex_str[0:160])
+ response_hex_str = response_hex.read().strip()
+ assert_equal(response_str.encode("hex"), response_hex_str)
# compare with hex block header
response_header_hex = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"hex", "", True)
assert_equal(response_header_hex.status, 200)
assert_greater_than(int(response_header_hex.getheader('content-length')), 160)
- response_header_hex_str = response_header_hex.read()
- assert_equal(response_hex_str[0:160], response_header_hex_str[0:160])
- assert_equal(response_header_str.encode("hex")[0:160], response_header_hex_str[0:160])
+ response_header_hex_str = response_header_hex.read().strip()
+ headerLen = len (response_header_hex_str)
+ assert_equal(response_hex_str[0:headerLen], response_header_hex_str)
+ assert_equal(response_header_str.encode("hex"), response_header_hex_str)
# check json format
json_string = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+'json')
diff --git a/qa/rpc-tests/test_framework/auxpow.py b/qa/rpc-tests/test_framework/auxpow.py
new file mode 100644
index 000000000..7027a712b
--- /dev/null
+++ b/qa/rpc-tests/test_framework/auxpow.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 Daniel Kraft
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+# General code for auxpow testing. This includes routines to
+# solve an auxpow and to generate auxpow blocks.
+
+import binascii
+import hashlib
+
+def computeAuxpow (block, target, ok):
+ """
+ Build an auxpow object (serialised as hex string) that solves
+ (ok = True) or doesn't solve (ok = False) the block.
+ """
+
+ # Start by building the merge-mining coinbase. The merkle tree
+ # consists only of the block hash as root.
+ coinbase = "fabe" + binascii.hexlify ("m" * 2)
+ coinbase += block
+ coinbase += "01000000" + ("00" * 4)
+
+ # Construct "vector" of transaction inputs.
+ vin = "01"
+ vin += ("00" * 32) + ("ff" * 4)
+ vin += ("%02x" % (len (coinbase) / 2)) + coinbase
+ vin += ("ff" * 4)
+
+ # Build up the full coinbase transaction. It consists only
+ # of the input and has no outputs.
+ tx = "01000000" + vin + "00" + ("00" * 4)
+ txHash = doubleHashHex (tx)
+
+ # Construct the parent block header. It need not be valid, just good
+ # enough for auxpow purposes.
+ header = "01000000"
+ header += "00" * 32
+ header += reverseHex (txHash)
+ header += "00" * 4
+ header += "00" * 4
+ header += "00" * 4
+
+ # Mine the block.
+ (header, blockhash) = mineBlock (header, target, ok)
+
+ # Build the MerkleTx part of the auxpow.
+ auxpow = tx
+ auxpow += blockhash
+ auxpow += "00"
+ auxpow += "00" * 4
+
+ # Extend to full auxpow.
+ auxpow += "00"
+ auxpow += "00" * 4
+ auxpow += header
+
+ return auxpow
+
+def mineAuxpowBlock (node):
+ """
+ Mine an auxpow block on the given RPC connection.
+ """
+
+ auxblock = node.getauxblock ()
+ target = reverseHex (auxblock['_target'])
+ apow = computeAuxpow (auxblock['hash'], target, True)
+ res = node.getauxblock (auxblock['hash'], apow)
+ assert res
+
+def mineBlock (header, target, ok):
+ """
+ Given a block header, update the nonce until it is ok (or not)
+ for the given target.
+ """
+
+ data = bytearray (binascii.unhexlify (header))
+ while True:
+ assert data[79] < 255
+ data[79] += 1
+ hexData = binascii.hexlify (data)
+
+ blockhash = doubleHashHex (hexData)
+ if (ok and blockhash < target) or ((not ok) and blockhash > target):
+ break
+
+ return (hexData, blockhash)
+
+def doubleHashHex (data):
+ """
+ Perform Bitcoin's Double-SHA256 hash on the given hex string.
+ """
+
+ hasher = hashlib.sha256 ()
+ hasher.update (binascii.unhexlify (data))
+ data = hasher.digest ()
+
+ hasher = hashlib.sha256 ()
+ hasher.update (data)
+
+ return reverseHex (hasher.hexdigest ())
+
+def reverseHex (data):
+ """
+ Flip byte order in the given data (hex string).
+ """
+
+ b = bytearray (binascii.unhexlify (data))
+ b.reverse ()
+
+ return binascii.hexlify (b)
diff --git a/src/Makefile.am b/src/Makefile.am
index d0d5137b7..7d92f0dfb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -72,6 +72,7 @@ endif
BITCOIN_CORE_H = \
addrman.h \
alert.h \
+ auxpow.h \
amount.h \
arith_uint256.h \
base58.h \
@@ -115,6 +116,7 @@ BITCOIN_CORE_H = \
policy/fees.h \
pow.h \
primitives/block.h \
+ primitives/pureheader.h \
primitives/transaction.h \
protocol.h \
pubkey.h \
@@ -250,6 +252,7 @@ libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_common_a_SOURCES = \
amount.cpp \
arith_uint256.cpp \
+ auxpow.cpp \
base58.cpp \
chainparams.cpp \
coins.cpp \
@@ -263,6 +266,7 @@ libbitcoin_common_a_SOURCES = \
keystore.cpp \
netbase.cpp \
primitives/block.cpp \
+ primitives/pureheader.cpp \
primitives/transaction.cpp \
protocol.cpp \
pubkey.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index f45364e7f..e75a0a0d8 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -36,6 +36,7 @@ BITCOIN_TESTS =\
test/bignum.h \
test/alert_tests.cpp \
test/allocator_tests.cpp \
+ test/auxpow_tests.cpp \
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
diff --git a/src/auxpow.cpp b/src/auxpow.cpp
new file mode 100644
index 000000000..3c350a67a
--- /dev/null
+++ b/src/auxpow.cpp
@@ -0,0 +1,192 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2011 Vince Durham
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Copyright (c) 2014-2015 Daniel Kraft
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+
+#include "auxpow.h"
+
+#include "consensus/validation.h"
+#include "main.h"
+#include "script/script.h"
+#include "util.h"
+
+#include <algorithm>
+
+/* Moved from wallet.cpp. CMerkleTx is necessary for auxpow, independent
+ of an enabled (or disabled) wallet. Always include the code. */
+
+int CMerkleTx::SetMerkleBranch(const CBlock& block)
+{
+ AssertLockHeld(cs_main);
+ CBlock blockTmp;
+
+ // Update the tx's hashBlock
+ hashBlock = block.GetHash();
+
+ // Locate the transaction
+ for (nIndex = 0; nIndex < (int)block.vtx.size(); nIndex++)
+ if (block.vtx[nIndex] == *(CTransaction*)this)
+ break;
+ if (nIndex == (int)block.vtx.size()) {
+ vMerkleBranch.clear();
+ nIndex = -1;
+ LogPrintf("ERROR: SetMerkleBranch(): couldn't find tx in block\n");
+ return 0;
+ }
+
+ // Fill in merkle branch
+ vMerkleBranch = block.GetMerkleBranch(nIndex);
+
+ // Is the tx in a block that's in the main chain
+ BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi == mapBlockIndex.end())
+ return 0;
+ const CBlockIndex* pindex = (*mi).second;
+ if (!pindex || !chainActive.Contains(pindex))
+ return 0;
+
+ return chainActive.Height() - pindex->nHeight + 1;
+}
+
+int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex*& pindexRet) const
+{
+ if (hashBlock.IsNull() || nIndex == -1)
+ return 0;
+ AssertLockHeld(cs_main);
+
+ // Find the block it claims to be in
+ BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi == mapBlockIndex.end())
+ return 0;
+ CBlockIndex* pindex = (*mi).second;
+ if (!pindex || !chainActive.Contains(pindex))
+ return 0;
+
+ // Make sure the merkle branch connects to this block
+ if (!fMerkleVerified) {
+ if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
+ return 0;
+ fMerkleVerified = true;
+ }
+
+ pindexRet = pindex;
+ return chainActive.Height() - pindex->nHeight + 1;
+}
+
+int CMerkleTx::GetDepthInMainChain(const CBlockIndex*& pindexRet) const
+{
+ AssertLockHeld(cs_main);
+ int nResult = GetDepthInMainChainINTERNAL(pindexRet);
+ if (nResult == 0 && !mempool.exists(GetHash()))
+ return -1; // Not in chain, not in mempool
+
+ return nResult;
+}
+
+int CMerkleTx::GetBlocksToMaturity() const
+{
+ if (!IsCoinBase())
+ return 0;
+ return std::max(0, (COINBASE_MATURITY + 1) - GetDepthInMainChain());
+}
+
+
+bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
+{
+ CValidationState state;
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
+}
+
+/* ************************************************************************** */
+
+bool
+CAuxPow::check(const uint256& hashAuxBlock, int nChainId, const Consensus::Params& params) const
+{
+ if (nIndex != 0)
+ return error("AuxPow is not a generate");
+
+ if (params.fStrictChainId && parentBlock.nVersion.GetChainId() == nChainId)
+ return error("Aux POW parent has our chain ID");
+
+ if (vChainMerkleBranch.size() > 30)
+ return error("Aux POW chain merkle branch too long");
+
+ // Check that the chain merkle root is in the coinbase
+ const uint256 nRootHash = CBlock::CheckMerkleBranch(hashAuxBlock, vChainMerkleBranch, nChainIndex);
+ std::vector<unsigned char> vchRootHash(nRootHash.begin(), nRootHash.end());
+ std::reverse(vchRootHash.begin(), vchRootHash.end()); // correct endian
+
+ // Check that we are in the parent block merkle tree
+ if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != parentBlock.hashMerkleRoot)
+ return error("Aux POW merkle root incorrect");
+
+ const CScript script = vin[0].scriptSig;
+
+ // Check that the same work is not submitted twice to our chain.
+ //
+
+ CScript::const_iterator pcHead =
+ std::search(script.begin(), script.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader));
+
+ CScript::const_iterator pc =
+ std::search(script.begin(), script.end(), vchRootHash.begin(), vchRootHash.end());
+
+ if (pc == script.end())
+ return error("Aux POW missing chain merkle root in parent coinbase");
+
+ if (pcHead != script.end()) {
+ // Enforce only one chain merkle root by checking that a single instance of the merged
+ // mining header exists just before.
+ if (script.end() != std::search(pcHead + 1, script.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader)))
+ return error("Multiple merged mining headers in coinbase");
+ if (pcHead + sizeof(pchMergedMiningHeader) != pc)
+ return error("Merged mining header is not just before chain merkle root");
+ } else {
+ // For backward compatibility.
+ // Enforce only one chain merkle root by checking that it starts early in the coinbase.
+ // 8-12 bytes are enough to encode extraNonce and nBits.
+ if (pc - script.begin() > 20)
+ return error("Aux POW chain merkle root must start in the first 20 bytes of the parent coinbase");
+ }
+
+
+ // Ensure we are at a deterministic point in the merkle leaves by hashing
+ // a nonce and our chain ID and comparing to the index.
+ pc += vchRootHash.size();
+ if (script.end() - pc < 8)
+ return error("Aux POW missing chain merkle tree size and nonce in parent coinbase");
+
+ int nSize;
+ memcpy(&nSize, &pc[0], 4);
+ const unsigned merkleHeight = vChainMerkleBranch.size();
+ if (nSize != (1 << merkleHeight))
+ return error("Aux POW merkle branch size does not match parent coinbase");
+
+ int nNonce;
+ memcpy(&nNonce, &pc[4], 4);
+
+ if (nChainIndex != getExpectedIndex(nNonce, nChainId, merkleHeight))
+ return error("Aux POW wrong index");
+
+ return true;
+}
+
+int
+CAuxPow::getExpectedIndex(int nNonce, int nChainId, unsigned h)
+{
+ // Choose a pseudo-random slot in the chain merkle tree
+ // but have it be fixed for a size/nonce/chain combination.
+ //
+ // This prevents the same work from being used twice for the
+ // same chain while reducing the chance that two chains clash
+ // for the same slot.
+
+ unsigned rand = nNonce;
+ rand = rand * 1103515245 + 12345;
+ rand += nChainId;
+ rand = rand * 1103515245 + 12345;
+
+ return rand % (1 << h);
+}
diff --git a/src/auxpow.h b/src/auxpow.h
new file mode 100644
index 000000000..26cc05f98
--- /dev/null
+++ b/src/auxpow.h
@@ -0,0 +1,185 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Copyright (c) 2014-2015 Daniel Kraft
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_AUXPOW_H
+#define BITCOIN_AUXPOW_H
+
+#include "consensus/params.h"
+#include "primitives/pureheader.h"
+#include "primitives/transaction.h"
+#include "serialize.h"
+#include "uint256.h"
+
+#include <vector>
+
+class CBlock;
+class CBlockIndex;
+
+/** Header for merge-mining data in the coinbase. */
+static const unsigned char pchMergedMiningHeader[] = {0xfa, 0xbe, 'm', 'm'};
+
+/* Because it is needed for auxpow, the definition of CMerkleTx is moved
+ here from wallet.h. */
+
+/** A transaction with a merkle branch linking it to the block chain. */
+class CMerkleTx : public CTransaction
+{
+private:
+ int GetDepthInMainChainINTERNAL(const CBlockIndex*& pindexRet) const;
+
+public:
+ uint256 hashBlock;
+ std::vector<uint256> vMerkleBranch;
+ int nIndex;
+
+ // memory only
+ mutable bool fMerkleVerified;
+
+
+ CMerkleTx()
+ {
+ Init();
+ }
+
+ CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
+ {
+ Init();
+ }
+
+ void Init()
+ {
+ hashBlock = uint256();
+ nIndex = -1;
+ fMerkleVerified = false;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ {
+ READWRITE(*(CTransaction*)this);
+ nVersion = this->nVersion;
+ READWRITE(hashBlock);
+ READWRITE(vMerkleBranch);
+ READWRITE(nIndex);
+ }
+
+ int SetMerkleBranch(const CBlock& block);
+
+
+ /**
+ * Return depth of transaction in blockchain:
+ * -1 : not in blockchain, and not in memory pool (conflicted transaction)
+ * 0 : in memory pool, waiting to be included in a block
+ * >=1 : this many blocks deep in the main chain
+ */
+ int GetDepthInMainChain(const CBlockIndex*& pindexRet) const;
+ int GetDepthInMainChain() const
+ {
+ const CBlockIndex* pindexRet;
+ return GetDepthInMainChain(pindexRet);
+ }
+ bool IsInMainChain() const
+ {
+ const CBlockIndex* pindexRet;
+ return GetDepthInMainChainINTERNAL(pindexRet) > 0;
+ }
+ int GetBlocksToMaturity() const;
+ bool AcceptToMemoryPool(bool fLimitFree = true, bool fRejectAbsurdFee = true);
+};
+
+/**
+ * Data for the merge-mining auxpow. This is a merkle tx (the parent block's
+ * coinbase tx) that can be verified to be in the parent block, and this
+ * transaction's input (the coinbase script) contains the reference
+ * to the actual merge-mined block.
+ */
+class CAuxPow : public CMerkleTx
+{
+ /* Public for the unit tests. */
+public:
+ /** The merkle branch connecting the aux block to our coinbase. */
+ std::vector<uint256> vChainMerkleBranch;
+
+ /** Merkle tree index of the aux block header in the coinbase. */
+ int nChainIndex;
+
+ /** Parent block header (on which the real PoW is done). */
+ CPureBlockHeader parentBlock;
+
+public:
+ /* Prevent accidental conversion. */
+ inline explicit CAuxPow(const CTransaction& txIn)
+ : CMerkleTx(txIn)
+ {
+ }
+
+ inline CAuxPow()
+ : CMerkleTx()
+ {
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void
+ SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ {
+ READWRITE(*static_cast<CMerkleTx*>(this));
+ nVersion = this->nVersion;
+
+ READWRITE(vChainMerkleBranch);
+ READWRITE(nChainIndex);
+ READWRITE(parentBlock);
+ }
+
+ /**
+ * Check the auxpow, given the merge-mined block's hash and our chain ID.
+ * Note that this does not verify the actual PoW on the parent block! It
+ * just confirms that all the merkle branches are valid.
+ * @param hashAuxBlock Hash of the merge-mined block.
+ * @param nChainId The auxpow chain ID of the block to check.
+ * @param params Consensus parameters.
+ * @return True if the auxpow is valid.
+ */
+ bool check(const uint256& hashAuxBlock, int nChainId, const Consensus::Params& params) const;
+
+ /**
+ * Get the parent block's hash. This is used to verify that it
+ * satisfies the PoW requirement.
+ * @return The parent block hash.
+ */
+ inline uint256
+ getParentBlockHash() const
+ {
+ return parentBlock.GetHash();
+ }
+
+ /**
+ * Return parent block. This is only used for the temporary parentblock
+ * auxpow version check.
+ * @return The parent block.
+ */
+ /* FIXME: Remove after the hardfork. */
+ inline const CPureBlockHeader&
+ getParentBlock() const
+ {
+ return parentBlock;
+ }
+
+ /**
+ * Calculate the expected index in the merkle tree. This is also used
+ * for the test-suite.
+ * @param nNonce The coinbase's nonce value.
+ * @param nChainId The chain ID.
+ * @param h The merkle block height.
+ * @return The expected index for the aux hash.
+ */
+ static int getExpectedIndex(int nNonce, int nChainId, unsigned h);
+};
+
+#endif // BITCOIN_AUXPOW_H
diff --git a/src/chain.cpp b/src/chain.cpp
index 719256106..e76073674 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -5,8 +5,35 @@
#include "chain.h"
+#include "main.h"
+
using namespace std;
+/* Moved here from the header, because we need auxpow and the logic
+ becomes more involved. */
+CBlockHeader CBlockIndex::GetBlockHeader() const
+{
+ CBlockHeader block;
+
+ /* The CBlockIndex object's block header is missing the auxpow.
+ So if this is an auxpow block, read it from disk instead. We only
+ have to read the actual *header*, not the full block. */
+ if (nVersion.IsAuxpow())
+ {
+ ReadBlockHeaderFromDisk(block, this);
+ return block;
+ }
+
+ block.nVersion = nVersion;
+ if (pprev)
+ block.hashPrevBlock = pprev->GetBlockHash();
+ block.hashMerkleRoot = hashMerkleRoot;
+ block.nTime = nTime;
+ block.nBits = nBits;
+ block.nNonce = nNonce;
+ return block;
+}
+
/**
* CChain implementation
*/
diff --git a/src/chain.h b/src/chain.h
index 01be2d6e5..c735f6a70 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -139,7 +139,7 @@ public:
unsigned int nStatus;
//! block header
- int nVersion;
+ CBlockVersion nVersion;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
@@ -163,7 +163,7 @@ public:
nStatus = 0;
nSequenceId = 0;
- nVersion = 0;
+ nVersion.SetNull();
hashMerkleRoot = uint256();
nTime = 0;
nBits = 0;
@@ -204,18 +204,7 @@ public:
return ret;
}
- CBlockHeader GetBlockHeader() const
- {
- CBlockHeader block;
- block.nVersion = nVersion;
- if (pprev)
- block.hashPrevBlock = pprev->GetBlockHash();
- block.hashMerkleRoot = hashMerkleRoot;
- block.nTime = nTime;
- block.nBits = nBits;
- block.nNonce = nNonce;
- return block;
- }
+ CBlockHeader GetBlockHeader() const;
uint256 GetBlockHash() const
{
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index cabff98c6..b573aa80a 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -39,6 +39,10 @@ public:
consensus.nPowTargetTimespan = 4 * 60 * 60; // pre-digishield: 4 hours
consensus.nPowTargetSpacing = 60; // 1 minute
consensus.fPowAllowMinDifficultyBlocks = false;
+ consensus.nAuxpowChainId = 0x0001;
+ consensus.nAuxpowStartHeight = 19200;
+ consensus.fStrictChainId = true;
+ consensus.nLegacyBlocksBefore = 19200;
/**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
@@ -74,7 +78,7 @@ public:
genesis.vtx.push_back(txNew);
genesis.hashPrevBlock.SetNull();
genesis.hashMerkleRoot = genesis.BuildMerkleTree();
- genesis.nVersion = 1;
+ genesis.nVersion.SetGenesisVersion(1);
genesis.nTime = 1386325540;
genesis.nBits = 0x1e0ffff0;
genesis.nNonce = 99943;
@@ -148,6 +152,9 @@ public:
consensus.nMajorityRejectBlockOutdated = 75;
consensus.nMajorityWindow = 100;
consensus.fPowAllowMinDifficultyBlocks = true;
+ consensus.nAuxpowStartHeight = 0;
+ consensus.fStrictChainId = false;
+ consensus.nLegacyBlocksBefore = -1;
pchMessageStart[0] = 0xfc;
pchMessageStart[1] = 0xc1;
@@ -209,6 +216,8 @@ public:
consensus.nMajorityRejectBlockOutdated = 950;
consensus.nMajorityWindow = 1000;
consensus.powLimit = uint256S("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1;
+ consensus.fStrictChainId = true;
+ consensus.nLegacyBlocksBefore = 0;
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
diff --git a/src/chainparams.h b/src/chainparams.h
index 8044b553e..b9d1c1758 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -71,6 +71,7 @@ public:
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
const Checkpoints::CCheckpointData& Checkpoints() const { return checkpointData; }
+
protected:
CChainParams() {}
diff --git a/src/consensus/params.h b/src/consensus/params.h
index c480a1cce..873a93d78 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -25,6 +25,23 @@ struct Params {
int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan;
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
+ /** Auxpow parameters */
+ int32_t nAuxpowChainId;
+ int nAuxpowStartHeight;
+ bool fStrictChainId;
+ int nLegacyBlocksBefore; // -1 for "always allow"
+
+ /**
+ * Check whether or not to allow legacy blocks at the given height.
+ * @param nHeight Height of the block to check.
+ * @return True if it is allowed to have a legacy version.
+ */
+ bool AllowLegacyBlocks(unsigned nHeight) const
+ {
+ if (nLegacyBlocksBefore < 0)
+ return true;
+ return static_cast<int> (nHeight) < nLegacyBlocksBefore;
+ }
};
} // namespace Consensus
diff --git a/src/init.cpp b/src/init.cpp
index 987b527ae..7bb7b183f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -154,6 +154,7 @@ void Shutdown()
mempool.AddTransactionsUpdated(1);
StopRPCThreads();
#ifdef ENABLE_WALLET
+ ShutdownRPCMining();
if (pwalletMain)
pwalletMain->Flush(false);
GenerateBitcoins(false, NULL, 0);
@@ -1431,6 +1432,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Generate coins in the background
if (pwalletMain)
GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1));
+
+ InitRPCMining ();
#endif
// ********************************************************* Step 11: finished
diff --git a/src/main.cpp b/src/main.cpp
index 91d89cea7..4046330e9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -8,6 +8,7 @@
#include "addrman.h"
#include "alert.h"
#include "arith_uint256.h"
+#include "auxpow.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
@@ -1138,6 +1139,51 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
// CBlock and CBlockIndex
//
+bool CheckProofOfWork(const CBlockHeader& block, const Consensus::Params& params)
+{
+ /* Except for legacy blocks with full version 1, ensure that
+ the chain ID is correct. Legacy blocks are not allowed since
+ the merge-mining start, which is checked in AcceptBlockHeader
+ where the height is known. */
+ if (!block.nVersion.IsLegacy() && params.fStrictChainId
+ && block.nVersion.GetChainId() != params.nAuxpowChainId)
+ return error("%s : block does not have our chain ID"
+ " (got %d, expected %d, full nVersion %d)",
+ __func__, block.nVersion.GetChainId(),
+ params.nAuxpowChainId, block.nVersion.GetFullVersion());
+
+ /* If there is no auxpow, just check the block hash. */
+ if (!block.auxpow)
+ {
+ if (block.nVersion.IsAuxpow())
+ return error("%s : no auxpow on block with auxpow version",
+ __func__);
+
+ if (!CheckProofOfWork(block.GetHash(), block.nBits, params))
+ return error("%s : non-AUX proof of work failed", __func__);
+
+ return true;
+ }
+
+ /* We have auxpow. Check it. */
+
+ if (!block.nVersion.IsAuxpow())
+ return error("%s : auxpow on block with non-auxpow version", __func__);
+
+ /* Temporary check: Disallow parent blocks with auxpow version. This is
+ for compatibility with the old client. */
+ /* FIXME: Remove this check with a hardfork later on. */
+ if (block.auxpow->getParentBlock().nVersion.IsAuxpow())
+ return error("%s : auxpow parent block has auxpow version", __func__);
+
+ if (!block.auxpow->check(block.GetHash(), block.nVersion.GetChainId(), params))
+ return error("%s : AUX POW is not valid", __func__);
+ if (!CheckProofOfWork(block.auxpow->getParentBlockHash(), block.nBits, params))
+ return error("%s : AUX proof of work failed", __func__);
+
+ return true;
+}
+
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
@@ -1159,7 +1205,11 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::M
return true;
}
-bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
+/* Generic implementation of block reading that can handle
+ both a block and its header. */
+
+template<typename T>
+static bool ReadBlockOrHeader(T& block, const CDiskBlockPos& pos)
{
block.SetNull();
@@ -1177,15 +1227,16 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
}
// Check the header
- if (!CheckProofOfWork(block.GetPoWHash(), block.nBits, Params().GetConsensus()))
+ if (!CheckProofOfWork(block, Params().GetConsensus()))
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
return true;
}
-bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
+template<typename T>
+static bool ReadBlockOrHeader(T& block, const CBlockIndex* pindex)
{
- if (!ReadBlockFromDisk(block, pindex->GetBlockPos()))
+ if (!ReadBlockOrHeader(block, pindex->GetBlockPos()))
return false;
if (block.GetHash() != pindex->GetBlockHash())
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s",
@@ -1193,6 +1244,21 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
return true;
}
+bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
+{
+ return ReadBlockOrHeader(block, pos);
+}
+
+bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
+{
+ return ReadBlockOrHeader(block, pindex);
+}
+
+bool ReadBlockHeaderFromDisk(CBlockHeader& block, const CBlockIndex* pindex)
+{
+ return ReadBlockOrHeader(block, pindex);
+}
+
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
{
int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
@@ -1829,7 +1895,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
// Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, when 75% of the network has upgraded:
- if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) {
+ if (block.nVersion.GetBaseVersion() >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) {
flags |= SCRIPT_VERIFY_DERSIG;
}
@@ -2091,7 +2157,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
const CBlockIndex* pindex = chainActive.Tip();
for (int i = 0; i < 100 && pindex != NULL; i++)
{
- if (pindex->nVersion > CBlock::CURRENT_VERSION)
+ if (pindex->nVersion.GetBaseVersion() > CBlock::CURRENT_VERSION)
++nUpgraded;
pindex = pindex->pprev;
}
@@ -2646,7 +2712,7 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW)
{
// Check proof of work matches claimed amount
- if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits, Params().GetConsensus()))
+ if (fCheckPOW && !CheckProofOfWork(block, Params().GetConsensus()))
return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),
REJECT_INVALID, "high-hash");
@@ -2730,6 +2796,13 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
int nHeight = pindexPrev->nHeight+1;
+ // Disallow legacy blocks after merge-mining start.
+ if (!Params().GetConsensus().AllowLegacyBlocks(nHeight)
+ && block.nVersion.IsLegacy())
+ return state.DoS(100, error("%s : legacy block after auxpow start",
+ __func__),
+ REJECT_INVALID, "late-legacy-block");
+
// Check proof of work
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, error("%s: incorrect proof of work", __func__),
@@ -2754,12 +2827,12 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
}
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
- if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
+ if (block.nVersion.GetBaseVersion() < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
return state.Invalid(error("%s: rejected nVersion=1 block", __func__),
REJECT_OBSOLETE, "bad-version");
// Reject block.nVersion=2 blocks when 95% (75% on testnet) of the network has upgraded:
- if (block.nVersion < 3 && IsSuperMajority(3, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
+ if (block.nVersion.GetBaseVersion() < 3 && IsSuperMajority(3, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
return state.Invalid(error("%s : rejected nVersion=2 block", __func__),
REJECT_OBSOLETE, "bad-version");
@@ -2779,7 +2852,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
- if (block.nVersion >= 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams))
+ if (block.nVersion.GetBaseVersion() >= 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams))
{
CScript expect = CScript() << nHeight;
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
@@ -2897,7 +2970,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
unsigned int nFound = 0;
for (int i = 0; i < consensusParams.nMajorityWindow && nFound < nRequired && pstart != NULL; i++)
{
- if (pstart->nVersion >= minVersion)
+ if (pstart->nVersion.GetBaseVersion() >= minVersion)
++nFound;
pstart = pstart->pprev;
}
diff --git a/src/main.h b/src/main.h
index 58c717c27..2cb3752ef 100644
--- a/src/main.h
+++ b/src/main.h
@@ -378,8 +378,8 @@ public:
/** Functions for disk access for blocks */
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
-bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos);
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
+bool ReadBlockHeaderFromDisk(CBlockHeader& block, const CBlockIndex* pindex);
/** Functions for validating blocks and updating the block tree */
@@ -404,6 +404,14 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
+/**
+ * Check proof-of-work of a block header, taking auxpow into account.
+ * @param block The block header.
+ * @param params Consensus parameters.
+ * @return True iff the PoW is correct.
+ */
+bool CheckProofOfWork(const CBlockHeader& block, const Consensus::Params& params);
+
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
diff --git a/src/miner.cpp b/src/miner.cpp
index 3e06e877c..a6ed42d00 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -101,10 +101,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
return NULL;
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
+ /* Initialise the block version. */
+ pblock->nVersion.SetBaseVersion(CBlockHeader::CURRENT_VERSION);
+
// -regtest only: allow overriding block.nVersion with
// -blockversion=N to test forking scenarios
if (Params().MineBlocksOnDemand())
- pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
+ pblock->nVersion.SetBaseVersion(GetArg("-blockversion", pblock->nVersion.GetBaseVersion()));
// Create coinbase tx
CMutableTransaction txNew;
@@ -345,7 +348,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
return pblocktemplate.release();
}
-void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
+void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{
// Update nExtraNonce
static uint256 hashPrevBlock;
@@ -417,7 +420,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
return CreateNewBlock(scriptPubKey);
}
-static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
+bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
{
LogPrintf("%s\n", pblock->ToString());
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
diff --git a/src/miner.h b/src/miner.h
index 96a6b70ec..46bed944d 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -29,7 +29,8 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads);
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey);
/** Modify the extranonce in a block */
-void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
+void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
+bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
#endif // BITCOIN_MINER_H
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index 7d2bc26dd..7bd64d77c 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -6,21 +6,21 @@
#include "primitives/block.h"
#include "hash.h"
-#include "crypto/scrypt.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
#include "crypto/common.h"
-uint256 CBlockHeader::GetHash() const
+void CBlockHeader::SetAuxpow (CAuxPow* apow)
{
- return SerializeHash(*this);
-}
-
-uint256 CBlockHeader::GetPoWHash() const
-{
- uint256 thash;
- scrypt_1024_1_1_256(BEGIN(nVersion), BEGIN(thash));
- return thash;
+ if (apow)
+ {
+ auxpow.reset(apow);
+ nVersion.SetAuxpow(true);
+ } else
+ {
+ auxpow.reset();
+ nVersion.SetAuxpow(false);
+ }
}
uint256 CBlock::BuildMerkleTree(bool* fMutated) const
@@ -122,7 +122,7 @@ std::string CBlock::ToString() const
std::stringstream s;
s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
GetHash().ToString(),
- nVersion,
+ nVersion.GetFullVersion(),
hashPrevBlock.ToString(),
hashMerkleRoot.ToString(),
nTime, nBits, nNonce,
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 21eb82273..ef2b19010 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -6,10 +6,14 @@
#ifndef BITCOIN_PRIMITIVES_BLOCK_H
#define BITCOIN_PRIMITIVES_BLOCK_H
+#include "auxpow.h"
#include "primitives/transaction.h"
+#include "primitives/pureheader.h"
#include "serialize.h"
#include "uint256.h"
+#include <boost/shared_ptr.hpp>
+
/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block
@@ -17,17 +21,11 @@
* in the block is a special one that creates a new coin owned by the creator
* of the block.
*/
-class CBlockHeader
+class CBlockHeader : public CPureBlockHeader
{
public:
- // header
- static const int32_t CURRENT_VERSION=3;
- int32_t nVersion;
- uint256 hashPrevBlock;
- uint256 hashMerkleRoot;
- uint32_t nTime;
- uint32_t nBits;
- uint32_t nNonce;
+ // auxpow (if this is a merge-minded block)
+ boost::shared_ptr<CAuxPow> auxpow;
CBlockHeader()
{
@@ -38,38 +36,35 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(hashPrevBlock);
- READWRITE(hashMerkleRoot);
- READWRITE(nTime);
- READWRITE(nBits);
- READWRITE(nNonce);
+ READWRITE(*(CPureBlockHeader*)this);
+ nVersion = this->nVersion.GetBaseVersion();
+
+ if (this->nVersion.IsAuxpow()) {
+ if (ser_action.ForRead())
+ auxpow.reset(new CAuxPow());
+ assert(auxpow);
+ READWRITE(*auxpow);
+ } else if (ser_action.ForRead())
+ auxpow.reset();
}
void SetNull()
{
- nVersion = CBlockHeader::CURRENT_VERSION;
- hashPrevBlock.SetNull();
- hashMerkleRoot.SetNull();
- nTime = 0;
- nBits = 0;
- nNonce = 0;
- }
-
- bool IsNull() const
- {
- return (nBits == 0);
+ CPureBlockHeader::SetNull();
+ auxpow.reset();
}
- uint256 GetHash() const;
-
- uint256 GetPoWHash() const;
-
int64_t GetBlockTime() const
{
return (int64_t)nTime;
}
+
+ /**
+ * Set the block's auxpow (or unset it). This takes care of updating
+ * the version accordingly.
+ * @param apow Pointer to the auxpow to use or NULL.
+ */
+ void SetAuxpow(CAuxPow* apow);
};
@@ -117,6 +112,7 @@ public:
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
+ block.auxpow = auxpow;
return block;
}
diff --git a/src/primitives/pureheader.cpp b/src/primitives/pureheader.cpp
new file mode 100644
index 000000000..c90d5fd8e
--- /dev/null
+++ b/src/primitives/pureheader.cpp
@@ -0,0 +1,31 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "primitives/pureheader.h"
+
+#include "chainparams.h"
+#include "crypto/scrypt.h"
+#include "hash.h"
+#include "utilstrencodings.h"
+
+void CBlockVersion::SetBaseVersion(int32_t nBaseVersion)
+{
+ assert(nBaseVersion >= 1 && nBaseVersion < VERSION_AUXPOW);
+ assert(!IsAuxpow());
+ const int32_t nChainId = Params().GetConsensus().nAuxpowChainId;
+ nVersion = nBaseVersion | (nChainId * VERSION_CHAIN_START);
+}
+
+uint256 CPureBlockHeader::GetHash() const
+{
+ return SerializeHash(*this);
+}
+
+uint256 CPureBlockHeader::GetPoWHash() const
+{
+ uint256 thash;
+ scrypt_1024_1_1_256(BEGIN(nVersion), BEGIN(thash));
+ return thash;
+}
diff --git a/src/primitives/pureheader.h b/src/primitives/pureheader.h
new file mode 100644
index 000000000..449ebbff0
--- /dev/null
+++ b/src/primitives/pureheader.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_PRIMITIVES_PUREHEADER_H
+#define BITCOIN_PRIMITIVES_PUREHEADER_H
+
+#include "serialize.h"
+#include "uint256.h"
+
+/**
+ * Encapsulate a block version. This takes care of building it up
+ * from a base version, the modifier flags (like auxpow) and
+ * also the auxpow chain ID.
+ */
+class CBlockVersion
+{
+private:
+ /* Modifiers to the version. */
+ static const int32_t VERSION_AUXPOW = (1 << 8);
+
+ /** Bits above are reserved for the auxpow chain ID. */
+ static const int32_t VERSION_CHAIN_START = (1 << 16);
+
+ /** The version as integer. Should not be accessed directly. */
+ int32_t nVersion;
+
+public:
+ inline CBlockVersion()
+ {
+ SetNull();
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ {
+ READWRITE(this->nVersion);
+ }
+
+ inline void SetNull()
+ {
+ nVersion = 0;
+ }
+
+ /**
+ * Extract the base version (without modifiers and chain ID).
+ * @return The base version./
+ */
+ inline int32_t GetBaseVersion() const
+ {
+ return nVersion % VERSION_AUXPOW;
+ }
+
+ /**
+ * Set the base version (apart from chain ID and auxpow flag) to
+ * the one given. This should only be called when auxpow is not yet
+ * set, to initialise a block!
+ * @param nBaseVersion The base version.
+ */
+ void SetBaseVersion(int32_t nBaseVersion);
+
+ /**
+ * Extract the chain ID.
+ * @return The chain ID encoded in the version.
+ */
+ inline int32_t GetChainId() const
+ {
+ return nVersion / VERSION_CHAIN_START;
+ }
+
+ /**
+ * Set the chain ID. This is used for the test suite.
+ * @param ch The chain ID to set.
+ */
+ inline void SetChainId(int32_t chainId)
+ {
+ nVersion %= VERSION_CHAIN_START;
+ nVersion |= chainId * VERSION_CHAIN_START;
+ }
+
+ /**
+ * Extract the full version. Used for RPC results and debug prints.
+ * @return The full version.
+ */
+ inline int32_t GetFullVersion() const
+ {
+ return nVersion;
+ }
+
+ /**
+ * Set the genesis block version. This must be a literal write
+ * through, to get the correct historic version.
+ * @param nGenesisVersion The version to set.
+ */
+ inline void SetGenesisVersion(int32_t nGenesisVersion)
+ {
+ nVersion = nGenesisVersion;
+ }
+
+ /**
+ * Check if the auxpow flag is set in the version.
+ * @return True iff this block version is marked as auxpow.
+ */
+ inline bool IsAuxpow() const
+ {
+ return nVersion & VERSION_AUXPOW;
+ }
+
+ /**
+ * Set the auxpow flag. This is used for testing.
+ * @param auxpow Whether to mark auxpow as true.
+ */
+ inline void SetAuxpow(bool auxpow)
+ {
+ if (auxpow)
+ nVersion |= VERSION_AUXPOW;
+ else
+ nVersion &= ~VERSION_AUXPOW;
+ }
+
+ /**
+ * Check whether this is a "legacy" block without chain ID.
+ * @return True iff it is.
+ */
+ inline bool IsLegacy() const
+ {
+ return nVersion == 1;
+ }
+};
+
+/**
+ * A block header without auxpow information. This "intermediate step"
+ * in constructing the full header is useful, because it breaks the cyclic
+ * dependency between auxpow (referencing a parent block header) and
+ * the block header (referencing an auxpow). The parent block header
+ * does not have auxpow itself, so it is a pure header.
+ */
+class CPureBlockHeader
+{
+public:
+ // header
+ static const int32_t CURRENT_VERSION = 3;
+ CBlockVersion nVersion;
+ uint256 hashPrevBlock;
+ uint256 hashMerkleRoot;
+ uint32_t nTime;
+ uint32_t nBits;
+ uint32_t nNonce;
+
+ CPureBlockHeader()
+ {
+ SetNull();
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ {
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion.GetBaseVersion();
+ READWRITE(hashPrevBlock);
+ READWRITE(hashMerkleRoot);
+ READWRITE(nTime);
+ READWRITE(nBits);
+ READWRITE(nNonce);
+ }
+
+ void SetNull()
+ {
+ nVersion.SetNull();
+ hashPrevBlock.SetNull();
+ hashMerkleRoot.SetNull();
+ nTime = 0;
+ nBits = 0;
+ nNonce = 0;
+ }
+
+ bool IsNull() const
+ {
+ return (nBits == 0);
+ }
+
+ uint256 GetHash() const;
+
+ uint256 GetPoWHash() const;
+
+ int64_t GetBlockTime() const
+ {
+ return (int64_t)nTime;
+ }
+};
+
+#endif // BITCOIN_PRIMITIVES_PUREHEADER_H
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 79528db2f..3d4cfcd21 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -5,6 +5,7 @@
#include "checkpoints.h"
#include "consensus/validation.h"
+#include "core_io.h"
#include "main.h"
#include "primitives/transaction.h"
#include "rpcserver.h"
@@ -52,6 +53,34 @@ double GetDifficulty(const CBlockIndex* blockindex)
return dDiff;
}
+static Object AuxpowToJSON(const CAuxPow& auxpow)
+{
+ Object tx;
+ tx.push_back(Pair("hex", EncodeHexTx(auxpow)));
+ TxToJSON(auxpow, auxpow.parentBlock.GetHash(), tx);
+
+ Object result;
+ result.push_back(Pair("tx", tx));
+ result.push_back(Pair("index", auxpow.nIndex));
+ result.push_back(Pair("chainindex", auxpow.nChainIndex));
+
+ Array branch;
+ BOOST_FOREACH(const uint256& node, auxpow.vMerkleBranch)
+ branch.push_back(node.GetHex());
+ result.push_back(Pair("merklebranch", branch));
+
+ branch.clear();
+ BOOST_FOREACH(const uint256& node, auxpow.vChainMerkleBranch)
+ branch.push_back(node.GetHex());
+ result.push_back(Pair("chainmerklebranch", branch));
+
+ CDataStream ssParent(SER_NETWORK, PROTOCOL_VERSION);
+ ssParent << auxpow.parentBlock;
+ const std::string strHex = HexStr(ssParent.begin(), ssParent.end());
+ result.push_back(Pair("parentblock", strHex));
+
+ return result;
+}
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
{
@@ -64,7 +93,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe
result.push_back(Pair("confirmations", confirmations));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("height", blockindex->nHeight));
- result.push_back(Pair("version", block.nVersion));
+ result.push_back(Pair("version", block.nVersion.GetFullVersion()));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
Array txs;
BOOST_FOREACH(const CTransaction&tx, block.vtx)
@@ -85,6 +114,9 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
+ if (block.auxpow)
+ result.push_back(Pair("auxpow", AuxpowToJSON(*block.auxpow)));
+
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
CBlockIndex *pnext = chainActive.Next(blockindex);
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 528d5406f..3639ac931 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -30,6 +30,30 @@
using namespace json_spirit;
using namespace std;
+#ifdef ENABLE_WALLET
+// Key used by getwork miners.
+// Allocated in InitRPCMining, free'd in ShutdownRPCMining
+static CReserveKey* pminingKey = NULL;
+
+void InitRPCMining()
+{
+ if (!pwalletMain)
+ return;
+
+ // getwork/getblocktemplate mining rewards paid here:
+ pminingKey = new CReserveKey(pwalletMain);
+}
+
+void ShutdownRPCMining()
+{
+ if (!pminingKey)
+ return;
+
+ delete pminingKey;
+ pminingKey = NULL;
+}
+#endif // ENABLE_WALLET
+
/**
* Return average network hashes per second based on the last 'lookup' blocks,
* or from the last difficulty change if 'lookup' is nonpositive.
@@ -569,7 +593,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
Object result;
result.push_back(Pair("capabilities", aCaps));
- result.push_back(Pair("version", pblock->nVersion));
+ result.push_back(Pair("version", pblock->nVersion.GetFullVersion()));
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
result.push_back(Pair("transactions", transactions));
result.push_back(Pair("coinbaseaux", aux));
@@ -726,3 +750,156 @@ Value estimatepriority(const Array& params, bool fHelp)
return mempool.estimatePriority(nBlocks);
}
+
+/* ************************************************************************** */
+/* Merge mining. */
+
+#ifdef ENABLE_WALLET
+Value getauxblock(const Array& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 0 && params.size() != 2))
+ throw std::runtime_error(
+ "getauxblock (hash auxpow)\n"
+ "\nCreate or submit a merge-mined block.\n"
+ "\nWithout arguments, create a new block and return information\n"
+ "required to merge-mine it. With arguments, submit a solved\n"
+ "auxpow for a previously returned block.\n"
+ "\nArguments:\n"
+ "1. \"hash\" (string, optional) hash of the block to submit\n"
+ "2. \"auxpow\" (string, optional) serialised auxpow found\n"
+ "\nResult (without arguments):\n"
+ "{\n"
+ " \"hash\" (string) hash of the created block\n"
+ " \"chainid\" (numeric) chain ID for this block\n"
+ " \"previousblockhash\" (string) hash of the previous block\n"
+ " \"coinbasevalue\" (numeric) value of the block's coinbase\n"
+ " \"bits\" (string) compressed target of the block\n"
+ " \"height\" (numeric) height of the block\n"
+ " \"_target\" (string) target in reversed byte order, deprecated\n"
+ "}\n"
+ "\nResult (with arguments):\n"
+ "xxxxx (boolean) whether the submitted block was correct\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getauxblock", "")
+ + HelpExampleCli("getauxblock", "\"hash\" \"serialised auxpow\"")
+ + HelpExampleRpc("getauxblock", "")
+ );
+
+ if (pwalletMain == NULL)
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
+ assert (pminingKey);
+
+ if (vNodes.empty() && !Params().MineBlocksOnDemand())
+ throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED,
+ "Namecoin is not connected!");
+
+ if (IsInitialBlockDownload() && !Params().MineBlocksOnDemand())
+ throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
+ "Namecoin is downloading blocks...");
+
+ /* This should never fail, since the chain is already
+ past the point of merge-mining start. Check nevertheless. */
+ {
+ LOCK(cs_main);
+ if (chainActive.Height() + 1 < Params().GetConsensus().nAuxpowStartHeight)
+ throw std::runtime_error("getauxblock method is not yet available");
+ }
+
+ /* The variables below are used to keep track of created and not yet
+ submitted auxpow blocks. Lock them, just in case. In principle
+ there's only one RPC thread, so it should be fine without locking
+ as well. But it cannot hurt to be safe. */
+ static CCriticalSection cs_auxblockCache;
+ LOCK(cs_auxblockCache);
+ static std::map<uint256, CBlock*> mapNewBlock;
+ static std::vector<CBlockTemplate*> vNewBlockTemplate;
+
+ /* Create a new block? */
+ if (params.size() == 0)
+ {
+ static unsigned nTransactionsUpdatedLast;
+ static const CBlockIndex* pindexPrev = NULL;
+ static uint64_t nStart;
+ static CBlockTemplate* pblocktemplate;
+ static unsigned nExtraNonce = 0;
+
+ // Update block
+ {
+ LOCK(cs_main);
+ if (pindexPrev != chainActive.Tip()
+ || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast
+ && GetTime() - nStart > 60))
+ {
+ if (pindexPrev != chainActive.Tip())
+ {
+ // Deallocate old blocks since they're obsolete now
+ mapNewBlock.clear();
+ BOOST_FOREACH(CBlockTemplate* pbt, vNewBlockTemplate)
+ delete pbt;
+ vNewBlockTemplate.clear();
+ }
+
+ // Create new block with nonce = 0 and extraNonce = 1
+ pblocktemplate = CreateNewBlockWithKey(*pminingKey);
+ if (!pblocktemplate)
+ throw JSONRPCError(RPC_OUT_OF_MEMORY, "out of memory");
+
+ // Update state only when CreateNewBlock succeeded
+ nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
+ pindexPrev = chainActive.Tip();
+ nStart = GetTime();
+
+ // Finalise it by setting the version and building the merkle root
+ CBlock* pblock = &pblocktemplate->block;
+ IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
+ pblock->nVersion.SetAuxpow(true);
+ pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+
+ // Save
+ mapNewBlock[pblock->GetHash()] = pblock;
+ vNewBlockTemplate.push_back(pblocktemplate);
+ }
+ }
+
+ const CBlock& block = pblocktemplate->block;
+
+ arith_uint256 target;
+ bool fNegative, fOverflow;
+ target.SetCompact(block.nBits, &fNegative, &fOverflow);
+ if (fNegative || fOverflow || target == 0)
+ throw std::runtime_error("invalid difficulty bits in block");
+
+ json_spirit::Object result;
+ result.push_back(Pair("hash", block.GetHash().GetHex()));
+ result.push_back(Pair("chainid", block.nVersion.GetChainId()));
+ result.push_back(Pair("previousblockhash", block.hashPrevBlock.GetHex()));
+ result.push_back(Pair("coinbasevalue", (int64_t)block.vtx[0].vout[0].nValue));
+ result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
+ result.push_back(Pair("height", static_cast<int64_t> (pindexPrev->nHeight + 1)));
+ result.push_back(Pair("_target", HexStr(BEGIN(target), END(target))));
+
+ return result;
+ }
+
+ /* Submit a block instead. Note that this need not lock cs_main,
+ since ProcessBlockFound below locks it instead. */
+
+ assert(params.size() == 2);
+ uint256 hash;
+ hash.SetHex(params[0].get_str());
+
+ const std::map<uint256, CBlock*>::iterator mit = mapNewBlock.find(hash);
+ if (mit == mapNewBlock.end())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "block hash unknown");
+ CBlock& block = *mit->second;
+
+ const std::vector<unsigned char> vchAuxPow = ParseHex(params[1].get_str());
+ CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION);
+ CAuxPow pow;
+ ss >> pow;
+ block.SetAuxpow(new CAuxPow(pow));
+ assert(block.GetHash() == hash);
+
+ return ProcessBlockFound(&block, *pwalletMain, *pminingKey);
+}
+#endif // ENABLE_WALLET
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 3f74517a6..f5902d2e5 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -304,6 +304,9 @@ static const CRPCCommand vRPCCommands[] =
{ "mining", "getnetworkhashps", &getnetworkhashps, true },
{ "mining", "prioritisetransaction", &prioritisetransaction, true },
{ "mining", "submitblock", &submitblock, true },
+#ifdef ENABLE_WALLET
+ { "mining", "getauxblock", &getauxblock, true },
+#endif // ENABLE_WALLET
#ifdef ENABLE_WALLET
/* Coin generation */
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 30a5b28db..94f666a3b 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -169,6 +169,7 @@ extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, boo
extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value estimatefee(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value estimatepriority(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value getauxblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp);
diff --git a/src/test/auxpow_tests.cpp b/src/test/auxpow_tests.cpp
new file mode 100644
index 000000000..1630d000d
--- /dev/null
+++ b/src/test/auxpow_tests.cpp
@@ -0,0 +1,442 @@
+// Copyright (c) 2014-2015 Daniel Kraft
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "auxpow.h"
+#include "chainparams.h"
+#include "coins.h"
+#include "main.h"
+#include "uint256.h"
+#include "primitives/block.h"
+#include "script/script.h"
+
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+#include <algorithm>
+#include <vector>
+
+BOOST_FIXTURE_TEST_SUITE(auxpow_tests, BasicTestingSetup)
+
+/* ************************************************************************** */
+
+/**
+ * Tamper with a uint256 (modify it).
+ * @param num The number to modify.
+ */
+static void
+tamperWith(uint256& num)
+{
+ arith_uint256 modifiable = UintToArith256(num);
+ modifiable += 1;
+ num = ArithToUint256(modifiable);
+}
+
+/**
+ * Utility class to construct auxpow's and manipulate them. This is used
+ * to simulate various scenarios.
+ */
+class CAuxpowBuilder
+{
+public:
+ /** The parent block (with coinbase, not just header). */
+ CBlock parentBlock;
+
+ /** The auxpow's merkle branch (connecting it to the coinbase). */
+ std::vector<uint256> auxpowChainMerkleBranch;
+ /** The auxpow's merkle tree index. */
+ int auxpowChainIndex;
+
+ /**
+ * Initialise everything.
+ * @param baseVersion The parent block's base version to use.
+ * @param chainId The parent block's chain ID to use.
+ */
+ CAuxpowBuilder(int baseVersion, int chainId);
+
+ /**
+ * Set the coinbase's script.
+ * @param scr Set it to this script.
+ */
+ void setCoinbase(const CScript& scr);
+
+ /**
+ * Build the auxpow merkle branch. The member variables will be
+ * set accordingly. This has to be done before constructing the coinbase
+ * itself (which must contain the root merkle hash). When we have the
+ * coinbase afterwards, the member variables can be used to initialise
+ * the CAuxPow object from it.
+ * @param hashAux The merge-mined chain's block hash.
+ * @param h Height of the merkle tree to build.
+ * @param index Index to use in the merkle tree.
+ * @return The root hash, with reversed endian.
+ */
+ std::vector<unsigned char> buildAuxpowChain(const uint256& hashAux, unsigned h, int index);
+
+ /**
+ * Build the finished CAuxPow object. We assume that the auxpowChain
+ * member variables are already set. We use the passed in transaction
+ * as the base. It should (probably) be the parent block's coinbase.
+ * @param tx The base tx to use.
+ * @return The constructed CAuxPow object.
+ */
+ CAuxPow get(const CTransaction& tx) const;
+
+ /**
+ * Build the finished CAuxPow object from the parent block's coinbase.
+ * @return The constructed CAuxPow object.
+ */
+ inline CAuxPow
+ get() const
+ {
+ assert(!parentBlock.vtx.empty());
+ return get(parentBlock.vtx[0]);
+ }
+
+ /**
+ * Build a data vector to be included in the coinbase. It consists
+ * of the aux hash, the merkle tree size and the nonce. Optionally,
+ * the header can be added as well.
+ * @param header Add the header?
+ * @param hashAux The aux merkle root hash.
+ * @param h Height of the merkle tree.
+ * @param nonce The nonce value to use.
+ * @return The constructed data.
+ */
+ static std::vector<unsigned char> buildCoinbaseData(bool header, const std::vector<unsigned char>& auxRoot, unsigned h, int nonce);
+};
+
+CAuxpowBuilder::CAuxpowBuilder(int baseVersion, int chainId)
+ : auxpowChainIndex(-1)
+{
+ parentBlock.nVersion.SetBaseVersion(baseVersion);
+ parentBlock.nVersion.SetChainId(chainId);
+}
+
+void
+CAuxpowBuilder::setCoinbase(const CScript& scr)
+{
+ CMutableTransaction mtx;
+ mtx.vin.resize(1);
+ mtx.vin[0].prevout.SetNull();
+ mtx.vin[0].scriptSig = scr;
+
+ parentBlock.vtx.clear();
+ parentBlock.vtx.push_back(mtx);
+ parentBlock.hashMerkleRoot = parentBlock.BuildMerkleTree();
+}
+
+std::vector<unsigned char>
+CAuxpowBuilder::buildAuxpowChain(const uint256& hashAux, unsigned h, int index)
+{
+ auxpowChainIndex = index;
+
+ /* Just use "something" for the branch. Doesn't really matter. */
+ auxpowChainMerkleBranch.clear();
+ for (unsigned i = 0; i < h; ++i)
+ auxpowChainMerkleBranch.push_back(ArithToUint256(arith_uint256(i)));
+
+ const uint256 hash = CBlock::CheckMerkleBranch(hashAux, auxpowChainMerkleBranch, index);
+
+ std::vector<unsigned char> res = ToByteVector(hash);
+ std::reverse(res.begin(), res.end());
+
+ return res;
+}
+
+CAuxPow
+CAuxpowBuilder::get(const CTransaction& tx) const
+{
+ LOCK(cs_main);
+ CAuxPow res(tx);
+ res.SetMerkleBranch(parentBlock);
+
+ res.vChainMerkleBranch = auxpowChainMerkleBranch;
+ res.nChainIndex = auxpowChainIndex;
+ res.parentBlock = parentBlock;
+
+ return res;
+}
+
+std::vector<unsigned char>
+CAuxpowBuilder::buildCoinbaseData(bool header, const std::vector<unsigned char>& auxRoot, unsigned h, int nonce)
+{
+ std::vector<unsigned char> res;
+
+ if (header)
+ res.insert(res.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader));
+ res.insert(res.end(), auxRoot.begin(), auxRoot.end());
+
+ const int size = (1 << h);
+ res.insert(res.end(), UBEGIN(size), UEND(size));
+ res.insert(res.end(), UBEGIN(nonce), UEND(nonce));
+
+ return res;
+}
+
+/* ************************************************************************** */
+
+BOOST_AUTO_TEST_CASE(check_auxpow)
+{
+ const Consensus::Params& params = Params().GetConsensus();
+ CAuxpowBuilder builder(5, 42);
+ CAuxPow auxpow;
+
+ const uint256 hashAux = ArithToUint256(arith_uint256(12345));
+ const int32_t ourChainId = params.nAuxpowChainId;
+ const unsigned height = 30;
+ const int nonce = 7;
+ int index;
+
+ std::vector<unsigned char> auxRoot, data;
+ CScript scr;
+
+ /* Build a correct auxpow. The height is the maximally allowed one. */
+ index = CAuxPow::getExpectedIndex(nonce, ourChainId, height);
+ auxRoot = builder.buildAuxpowChain(hashAux, height, index);
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce);
+ scr = (CScript() << 2809 << 2013) + COINBASE_FLAGS;
+ scr = (scr << OP_2 << data);
+ builder.setCoinbase(scr);
+ BOOST_CHECK(builder.get().check(hashAux, ourChainId, params));
+
+ /* Check that the auxpow is invalid if we change either the aux block's
+ hash or the chain ID. */
+ uint256 modifiedAux(hashAux);
+ tamperWith(modifiedAux);
+ BOOST_CHECK(!builder.get().check(modifiedAux, ourChainId, params));
+ BOOST_CHECK(!builder.get().check(hashAux, ourChainId + 1, params));
+
+ /* Non-coinbase parent tx should fail. Note that we can't just copy
+ the coinbase literally, as we have to get a tx with different hash. */
+ const CTransaction oldCoinbase = builder.parentBlock.vtx[0];
+ builder.setCoinbase(scr << 5);
+ builder.parentBlock.vtx.push_back(oldCoinbase);
+ builder.parentBlock.hashMerkleRoot = builder.parentBlock.BuildMerkleTree();
+ auxpow = builder.get(builder.parentBlock.vtx[0]);
+ BOOST_CHECK(auxpow.check(hashAux, ourChainId, params));
+ auxpow = builder.get(builder.parentBlock.vtx[1]);
+ BOOST_CHECK(!auxpow.check(hashAux, ourChainId, params));
+
+ /* The parent chain can't have the same chain ID. */
+ CAuxpowBuilder builder2(builder);
+ builder2.parentBlock.nVersion.SetChainId(100);
+ BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params));
+ builder2.parentBlock.nVersion.SetChainId(ourChainId);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ /* Disallow too long merkle branches. */
+ builder2 = builder;
+ index = CAuxPow::getExpectedIndex(nonce, ourChainId, height + 1);
+ auxRoot = builder2.buildAuxpowChain(hashAux, height + 1, index);
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height + 1, nonce);
+ scr = (CScript() << 2809 << 2013) + COINBASE_FLAGS;
+ scr = (scr << OP_2 << data);
+ builder2.setCoinbase(scr);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ /* Verify that we compare correctly to the parent block's merkle root. */
+ builder2 = builder;
+ BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params));
+ tamperWith(builder2.parentBlock.hashMerkleRoot);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ /* Build a non-header legacy version and check that it is also accepted. */
+ builder2 = builder;
+ index = CAuxPow::getExpectedIndex(nonce, ourChainId, height);
+ auxRoot = builder2.buildAuxpowChain(hashAux, height, index);
+ data = CAuxpowBuilder::buildCoinbaseData(false, auxRoot, height, nonce);
+ scr = (CScript() << 2809 << 2013) + COINBASE_FLAGS;
+ scr = (scr << OP_2 << data);
+ builder2.setCoinbase(scr);
+ BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params));
+
+ /* However, various attempts at smuggling two roots in should be detected. */
+
+ const std::vector<unsigned char> wrongAuxRoot = builder2.buildAuxpowChain(modifiedAux, height, index);
+ std::vector<unsigned char> data2 = CAuxpowBuilder::buildCoinbaseData(false, wrongAuxRoot, height, nonce);
+ builder2.setCoinbase(CScript() << data << data2);
+ BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params));
+ builder2.setCoinbase(CScript() << data2 << data);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ data2 = CAuxpowBuilder::buildCoinbaseData(true, wrongAuxRoot, height, nonce);
+ builder2.setCoinbase(CScript() << data << data2);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+ builder2.setCoinbase(CScript() << data2 << data);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce);
+ builder2.setCoinbase(CScript() << data << data2);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+ builder2.setCoinbase(CScript() << data2 << data);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ data2 = CAuxpowBuilder::buildCoinbaseData(false, wrongAuxRoot, height, nonce);
+ builder2.setCoinbase(CScript() << data << data2);
+ BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params));
+ builder2.setCoinbase(CScript() << data2 << data);
+ BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params));
+
+ /* Verify that the appended nonce/size values are checked correctly. */
+
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce);
+ builder2.setCoinbase(CScript() << data);
+ BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params));
+
+ data.pop_back();
+ builder2.setCoinbase(CScript() << data);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height - 1, nonce);
+ builder2.setCoinbase(CScript() << data);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce + 3);
+ builder2.setCoinbase(CScript() << data);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ /* Put the aux hash in an invalid merkle tree position. */
+
+ auxRoot = builder.buildAuxpowChain(hashAux, height, index + 1);
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce);
+ builder2.setCoinbase(CScript() << data);
+ BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params));
+
+ auxRoot = builder.buildAuxpowChain(hashAux, height, index);
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce);
+ builder2.setCoinbase(CScript() << data);
+ BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params));
+}
+
+/* ************************************************************************** */
+
+/**
+ * Mine a block (assuming minimal difficulty) that either matches
+ * or doesn't match the difficulty target specified in the block header.
+ * @param block The block to mine (by updating nonce).
+ * @param ok Whether the block should be ok for PoW.
+ * @param nBits Use this as difficulty if specified.
+ */
+static void
+mineBlock(CBlockHeader& block, bool ok, int nBits = -1)
+{
+ if (nBits == -1)
+ nBits = block.nBits;
+
+ arith_uint256 target;
+ target.SetCompact(nBits);
+
+ block.nNonce = 0;
+ while (true) {
+ const bool nowOk = (UintToArith256(block.GetHash()) <= target);
+ if ((ok && nowOk) || (!ok && !nowOk))
+ break;
+
+ ++block.nNonce;
+ }
+
+ if (ok)
+ BOOST_CHECK(CheckProofOfWork(block.GetHash(), nBits, Params().GetConsensus()));
+ else
+ BOOST_CHECK(!CheckProofOfWork(block.GetHash(), nBits, Params().GetConsensus()));
+}
+
+BOOST_AUTO_TEST_CASE(auxpow_pow)
+{
+ /* Use regtest parameters to allow mining with easy difficulty. */
+ SelectParams(CBaseChainParams::REGTEST);
+ const Consensus::Params& params = Params().GetConsensus();
+
+ const arith_uint256 target = (~arith_uint256(0) >> 1);
+ CBlockHeader block;
+ block.nBits = target.GetCompact();
+
+ /* Verify the block version checks. */
+
+ block.nVersion.SetGenesisVersion(1);
+ mineBlock(block, true);
+ BOOST_CHECK(CheckProofOfWork(block, params));
+
+ block.nVersion.SetGenesisVersion(2);
+ mineBlock(block, true);
+ BOOST_CHECK(!CheckProofOfWork(block, params));
+
+ block.nVersion.SetBaseVersion(2);
+ block.nVersion.SetChainId(params.nAuxpowChainId);
+ mineBlock(block, true);
+ BOOST_CHECK(CheckProofOfWork(block, params));
+
+ block.nVersion.SetChainId(params.nAuxpowChainId + 1);
+ mineBlock(block, true);
+ BOOST_CHECK(!CheckProofOfWork(block, params));
+
+ /* Check the case when the block does not have auxpow (this is true
+ right now). */
+
+ block.nVersion.SetChainId(params.nAuxpowChainId);
+ block.nVersion.SetAuxpow(true);
+ mineBlock(block, true);
+ BOOST_CHECK(!CheckProofOfWork(block, params));
+
+ block.nVersion.SetAuxpow(false);
+ mineBlock(block, true);
+ BOOST_CHECK(CheckProofOfWork(block, params));
+ mineBlock(block, false);
+ BOOST_CHECK(!CheckProofOfWork(block, params));
+
+ /* ****************************************** */
+ /* Check the case that the block has auxpow. */
+
+ CAuxpowBuilder builder(5, 42);
+ CAuxPow auxpow;
+ const int32_t ourChainId = params.nAuxpowChainId;
+ const unsigned height = 3;
+ const int nonce = 7;
+ const int index = CAuxPow::getExpectedIndex(nonce, ourChainId, height);
+ std::vector<unsigned char> auxRoot, data;
+
+ /* Valid auxpow, PoW check of parent block. */
+ block.nVersion.SetAuxpow(true);
+ auxRoot = builder.buildAuxpowChain(block.GetHash(), height, index);
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce);
+ builder.setCoinbase(CScript() << data);
+ mineBlock(builder.parentBlock, false, block.nBits);
+ block.SetAuxpow(new CAuxPow(builder.get()));
+ BOOST_CHECK(!CheckProofOfWork(block, params));
+ mineBlock(builder.parentBlock, true, block.nBits);
+ block.SetAuxpow(new CAuxPow(builder.get()));
+ BOOST_CHECK(CheckProofOfWork(block, params));
+
+ /* Mismatch between auxpow being present and block.nVersion. Note that
+ block.SetAuxpow sets also the version and that we want to ensure
+ that the block hash itself doesn't change due to version changes.
+ This requires some work arounds. */
+ block.nVersion.SetAuxpow(false);
+ const uint256 hashAux = block.GetHash();
+ auxRoot = builder.buildAuxpowChain(hashAux, height, index);
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce);
+ builder.setCoinbase(CScript() << data);
+ mineBlock(builder.parentBlock, true, block.nBits);
+ block.SetAuxpow(new CAuxPow(builder.get()));
+ BOOST_CHECK(hashAux != block.GetHash());
+ block.nVersion.SetAuxpow(false);
+ BOOST_CHECK(hashAux == block.GetHash());
+ BOOST_CHECK(!CheckProofOfWork(block, params));
+
+ /* Modifying the block invalidates the PoW. */
+ block.nVersion.SetAuxpow(true);
+ auxRoot = builder.buildAuxpowChain(block.GetHash(), height, index);
+ data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce);
+ builder.setCoinbase(CScript() << data);
+ mineBlock(builder.parentBlock, true, block.nBits);
+ block.SetAuxpow(new CAuxPow(builder.get()));
+ BOOST_CHECK(CheckProofOfWork(block, params));
+ tamperWith(block.hashMerkleRoot);
+ BOOST_CHECK(!CheckProofOfWork(block, params));
+}
+
+/* ************************************************************************** */
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index a4fffdcf8..e8fbaad2b 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
- pblock->nVersion = 1;
+ pblock->nVersion.SetGenesisVersion(1);
// Replaced chainActive.Tip()->GetMedianTimePast()+1 with an actual 60 second block
// interval because median([1,2,2,3,3,3,4,4,4,4]) will eventually be problematic re:
diff --git a/src/txdb.cpp b/src/txdb.cpp
index df9ff8d8c..bdc67a049 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -225,8 +225,10 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
pindexNew->nStatus = diskindex.nStatus;
pindexNew->nTx = diskindex.nTx;
- if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus()))
- return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());
+ /* Bitcoin checks the PoW here. We don't do this because
+ the CDiskBlockIndex does not contain the auxpow.
+ This check isn't important, since the data on disk should
+ already be valid and can be trusted. */
pcursor->Next();
} else {
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 36baf930a..c4562badd 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2672,88 +2672,3 @@ CWalletKey::CWalletKey(int64_t nExpires)
nTimeCreated = (nExpires ? GetTime() : 0);
nTimeExpires = nExpires;
}
-
-int CMerkleTx::SetMerkleBranch(const CBlock& block)
-{
- AssertLockHeld(cs_main);
- CBlock blockTmp;
-
- // Update the tx's hashBlock
- hashBlock = block.GetHash();
-
- // Locate the transaction
- for (nIndex = 0; nIndex < (int)block.vtx.size(); nIndex++)
- if (block.vtx[nIndex] == *(CTransaction*)this)
- break;
- if (nIndex == (int)block.vtx.size())
- {
- vMerkleBranch.clear();
- nIndex = -1;
- LogPrintf("ERROR: SetMerkleBranch(): couldn't find tx in block\n");
- return 0;
- }
-
- // Fill in merkle branch
- vMerkleBranch = block.GetMerkleBranch(nIndex);
-
- // Is the tx in a block that's in the main chain
- BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi == mapBlockIndex.end())
- return 0;
- const CBlockIndex* pindex = (*mi).second;
- if (!pindex || !chainActive.Contains(pindex))
- return 0;
-
- return chainActive.Height() - pindex->nHeight + 1;
-}
-
-int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const
-{
- if (hashBlock.IsNull() || nIndex == -1)
- return 0;
- AssertLockHeld(cs_main);
-
- // Find the block it claims to be in
- BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi == mapBlockIndex.end())
- return 0;
- CBlockIndex* pindex = (*mi).second;
- if (!pindex || !chainActive.Contains(pindex))
- return 0;
-
- // Make sure the merkle branch connects to this block
- if (!fMerkleVerified)
- {
- if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
- return 0;
- fMerkleVerified = true;
- }
-
- pindexRet = pindex;
- return chainActive.Height() - pindex->nHeight + 1;
-}
-
-int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
-{
- AssertLockHeld(cs_main);
- int nResult = GetDepthInMainChainINTERNAL(pindexRet);
- if (nResult == 0 && !mempool.exists(GetHash()))
- return -1; // Not in chain, not in mempool
-
- return nResult;
-}
-
-int CMerkleTx::GetBlocksToMaturity() const
-{
- if (!IsCoinBase())
- return 0;
- return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
-}
-
-
-bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
-{
- CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
-}
-
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index b0da92cfd..e1ce6f795 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -7,6 +7,7 @@
#define BITCOIN_WALLET_WALLET_H
#include "amount.h"
+#include "auxpow.h"
#include "key.h"
#include "keystore.h"
#include "primitives/block.h"
@@ -144,65 +145,6 @@ struct COutputEntry
int vout;
};
-/** A transaction with a merkle branch linking it to the block chain. */
-class CMerkleTx : public CTransaction
-{
-private:
- int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const;
-
-public:
- uint256 hashBlock;
- std::vector<uint256> vMerkleBranch;
- int nIndex;
-
- // memory only
- mutable bool fMerkleVerified;
-
-
- CMerkleTx()
- {
- Init();
- }
-
- CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
- {
- Init();
- }
-
- void Init()
- {
- hashBlock = uint256();
- nIndex = -1;
- fMerkleVerified = false;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(*(CTransaction*)this);
- nVersion = this->nVersion;
- READWRITE(hashBlock);
- READWRITE(vMerkleBranch);
- READWRITE(nIndex);
- }
-
- int SetMerkleBranch(const CBlock& block);
-
-
- /**
- * Return depth of transaction in blockchain:
- * -1 : not in blockchain, and not in memory pool (conflicted transaction)
- * 0 : in memory pool, waiting to be included in a block
- * >=1 : this many blocks deep in the main chain
- */
- int GetDepthInMainChain(const CBlockIndex* &pindexRet) const;
- int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
- bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
- int GetBlocksToMaturity() const;
- bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true);
-};
-
/**
* A transaction with a bunch of additional info that only the owner cares about.
* It includes any unrecorded transactions needed to link it back to the block chain.