Permalink
Browse files

Merge #7558: [RPC] Add import/removeprunedfunds rpc call

f1bb13c Added companion removeprunedfunds call. (instagibbs)
7eb7029 Add importprunedfunds rpc call (instagibbs)
  • Loading branch information...
laanwj committed Mar 29, 2016
2 parents 2676e12 + f1bb13c commit b35a59179359709df21eb026d35f4124ce90fbd1
@@ -116,6 +116,7 @@
'invalidtxrequest.py',
'abandonconflict.py',
'p2p-versionbits-warning.py',
'importprunedfunds.py',
]
testScriptsExt = [
'bip65-cltv.py',
@@ -127,6 +128,7 @@
'getblocktemplate_proposals.py',
'txn_doublespend.py',
'txn_clone.py --mineblock',
'pruning.py',
'forknotify.py',
'invalidateblock.py',
# 'rpcbind_test.py', #temporary, bug in libevent, see #6655
@@ -0,0 +1,140 @@
#!/usr/bin/env python2
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
import decimal
class ImportPrunedFundsTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def setup_network(self, split=False):
self.nodes = start_nodes(2, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
self.is_network_split=False
self.sync_all()
def run_test (self):
import time
begintime = int(time.time())
print "Mining blocks..."
self.nodes[0].generate(101)
# sync
self.sync_all()
# address
address1 = self.nodes[0].getnewaddress()
# pubkey
address2 = self.nodes[0].getnewaddress()
address2_pubkey = self.nodes[0].validateaddress(address2)['pubkey'] # Using pubkey
# privkey
address3 = self.nodes[0].getnewaddress()
address3_privkey = self.nodes[0].dumpprivkey(address3) # Using privkey
#Check only one address
address_info = self.nodes[0].validateaddress(address1)
assert_equal(address_info['ismine'], True)
self.sync_all()
#Node 1 sync test
assert_equal(self.nodes[1].getblockcount(),101)
#Address Test - before import
address_info = self.nodes[1].validateaddress(address1)
assert_equal(address_info['iswatchonly'], False)
assert_equal(address_info['ismine'], False)
address_info = self.nodes[1].validateaddress(address2)
assert_equal(address_info['iswatchonly'], False)
assert_equal(address_info['ismine'], False)
address_info = self.nodes[1].validateaddress(address3)
assert_equal(address_info['iswatchonly'], False)
assert_equal(address_info['ismine'], False)
#Send funds to self
txnid1 = self.nodes[0].sendtoaddress(address1, 0.1)
self.nodes[0].generate(1)
rawtxn1 = self.nodes[0].gettransaction(txnid1)['hex']
proof1 = self.nodes[0].gettxoutproof([txnid1])
txnid2 = self.nodes[0].sendtoaddress(address2, 0.05)
self.nodes[0].generate(1)
rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex']
proof2 = self.nodes[0].gettxoutproof([txnid2])
txnid3 = self.nodes[0].sendtoaddress(address3, 0.025)
self.nodes[0].generate(1)
rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex']
proof3 = self.nodes[0].gettxoutproof([txnid3])
self.sync_all()
#Import with no affiliated address
try:
result1 = self.nodes[1].importprunedfunds(rawtxn1, proof1, "")
except JSONRPCException,e:
errorString = e.error['message']
assert('No addresses' in errorString)
balance1 = self.nodes[1].getbalance("", 0, True)
assert_equal(balance1, Decimal(0))
#Import with affiliated address with no rescan
self.nodes[1].importaddress(address2, "", False)
result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2, "")
balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
assert_equal(balance2, Decimal('0.05'))
#Import with private key with no rescan
self.nodes[1].importprivkey(address3_privkey, "", False)
result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3, "")
balance3 = Decimal(self.nodes[1].getbalance("", 0, False))
assert_equal(balance3, Decimal('0.025'))
balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
assert_equal(balance3, Decimal('0.075'))
#Addresses Test - after import
address_info = self.nodes[1].validateaddress(address1)
assert_equal(address_info['iswatchonly'], False)
assert_equal(address_info['ismine'], False)
address_info = self.nodes[1].validateaddress(address2)
assert_equal(address_info['iswatchonly'], True)
assert_equal(address_info['ismine'], False)
address_info = self.nodes[1].validateaddress(address3)
assert_equal(address_info['iswatchonly'], False)
assert_equal(address_info['ismine'], True)
#Remove transactions
try:
self.nodes[1].removeprunedfunds(txnid1)
except JSONRPCException,e:
errorString = e.error['message']
assert('does not exist' in errorString)
balance1 = Decimal(self.nodes[1].getbalance("", 0, True))
assert_equal(balance1, Decimal('0.075'))
self.nodes[1].removeprunedfunds(txnid2)
balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
assert_equal(balance2, Decimal('0.025'))
self.nodes[1].removeprunedfunds(txnid3)
balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
assert_equal(balance3, Decimal('0.0'))
if __name__ == '__main__':
ImportPrunedFundsTest ().main ()
View
@@ -95,7 +95,7 @@ void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const st
}
}
uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch) {
uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex) {
if (nBitsUsed >= vBits.size()) {
// overflowed the bits array - failure
fBad = true;
@@ -110,14 +110,16 @@ uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, uns
return uint256();
}
const uint256 &hash = vHash[nHashUsed++];
if (height==0 && fParentOfMatch) // in case of height 0, we have a matched txid
if (height==0 && fParentOfMatch) { // in case of height 0, we have a matched txid
vMatch.push_back(hash);
vnIndex.push_back(pos);
}
return hash;
} else {
// otherwise, descend into the subtrees to extract matched txids and hashes
uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch), right;
uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch, vnIndex), right;
if (pos*2+1 < CalcTreeWidth(height-1)) {
right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch);
right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch, vnIndex);
if (right == left) {
// The left and right branches should never be identical, as the transaction
// hashes covered by them must each be unique.
@@ -147,7 +149,7 @@ CPartialMerkleTree::CPartialMerkleTree(const std::vector<uint256> &vTxid, const
CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {}
uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex) {
vMatch.clear();
// An empty set will not work
if (nTransactions == 0)
@@ -167,7 +169,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
nHeight++;
// traverse the partial tree
unsigned int nBitsUsed = 0, nHashUsed = 0;
uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch);
uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch, vnIndex);
// verify that no problems occurred during the tree traversal
if (fBad)
return uint256();
View
@@ -75,9 +75,9 @@ class CPartialMerkleTree
/**
* recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
* it returns the hash of the respective node.
* it returns the hash of the respective node and its respective index.
*/
uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch);
uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);
public:
@@ -110,10 +110,11 @@ class CPartialMerkleTree
CPartialMerkleTree();
/**
* extract the matching txid's represented by this partial merkle tree.
* extract the matching txid's represented by this partial merkle tree
* and their respective indices within the partial tree.
* returns the merkle root, or 0 in case of failure
*/
uint256 ExtractMatches(std::vector<uint256> &vMatch);
uint256 ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);
};
@@ -303,7 +303,8 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
UniValue res(UniValue::VARR);
vector<uint256> vMatch;
if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot)
vector<unsigned int> vIndex;
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)
return res;
LOCK(cs_main);
View
@@ -204,7 +204,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_1)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8);
vector<uint256> vMatched;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -221,7 +222,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_1)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"));
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7);
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -249,7 +250,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_2)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
vector<uint256> vMatched;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -275,7 +277,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2)
BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3);
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -303,7 +305,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
vector<uint256> vMatched;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -326,7 +329,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none)
BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3);
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -353,7 +356,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
vector<uint256> vMatched;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -392,7 +396,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_4)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6);
vector<uint256> vMatched;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -409,7 +414,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_4)
BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair);
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
View
@@ -88,7 +88,8 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
// extract merkle root and matched txids from copy
std::vector<uint256> vMatchTxid2;
uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2);
std::vector<unsigned int> vIndex;
uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2, vIndex);
// check that it has the same merkle root as the original, and a valid one
BOOST_CHECK(merkleRoot1 == merkleRoot2);
@@ -102,7 +103,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
CPartialMerkleTreeTester pmt3(pmt2);
pmt3.Damage();
std::vector<uint256> vMatchTxid3;
uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3);
uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3, vIndex);
BOOST_CHECK(merkleRoot3 != merkleRoot1);
}
}
@@ -122,7 +123,8 @@ BOOST_AUTO_TEST_CASE(pmt_malleability)
CPartialMerkleTree tree(vTxid, vMatch);
std::vector<uint256> vTxid2;
BOOST_CHECK(tree.ExtractMatches(vTxid).IsNull());
std::vector<unsigned int> vIndex;
BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull());
}
BOOST_AUTO_TEST_SUITE_END()
Oops, something went wrong.

0 comments on commit b35a591

Please sign in to comment.