From f84555931b2c711bb4b3bdb271693223a94ba969 Mon Sep 17 00:00:00 2001 From: wqking Date: Wed, 30 Jan 2019 16:40:53 +0800 Subject: [PATCH 01/11] Added UTXO dumper and merkle tree build --- src/init.cpp | 6 + src/synapseswap.cpp | 288 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 src/synapseswap.cpp diff --git a/src/init.cpp b/src/init.cpp index b766433b588d2..2e2d3834c818f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -6,6 +6,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "synapseswap.cpp" + #if defined(HAVE_CONFIG_H) #include "config/phore-config.h" #endif @@ -731,6 +733,10 @@ bool AppInitServers(boost::thread_group& threadGroup) */ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) { + SynapseSwap synapseSwap; + synapseSwap.debugTest(); + return false; + // ********************************************************* Step 1: setup #ifdef _MSC_VER // Turn off Microsoft heap dump noise diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp new file mode 100644 index 0000000000000..0b0673d0a1965 --- /dev/null +++ b/src/synapseswap.cpp @@ -0,0 +1,288 @@ +// This file is included in init.cpp directly to avoid touching the build system + +#include "leveldbwrapper.h" +#include "uint256.h" +#include "coins.h" +#include "hash.h" + +#include +#include + +#include + +struct UtxoIteratorItem +{ + uint256 txid; + CCoins coins; + + bool isValid() const { + return ! txid.IsNull(); + } +}; + +struct UtxoProofNode +{ + bool left; + uint256 hash; +}; +using ProofList = std::vector; + +class UtxoIterator +{ +public: + UtxoIterator(); + + UtxoIteratorItem next(); + +private: + CLevelDBWrapper db; + std::unique_ptr iterator; + int debugCounter; +}; + +UtxoIterator::UtxoIterator() + : + db(GetDataDir() / "chainstate", 50 * 1024 * 1024, false, false), + iterator(db.NewIterator()) +{ + iterator->SeekToFirst(); + + debugCounter = 0; +} + +UtxoIteratorItem UtxoIterator::next() +{ + for(; iterator->Valid(); iterator->Next()) { + if(iterator->key().size() != 33) { + continue; + } + + //++debugCounter; if(debugCounter > 4) break; + + CDataStream keyStream(iterator->key().data(), iterator->key().data() + iterator->key().size(), SER_DISK, CLIENT_VERSION); + std::pair keyPair; + keyStream >> keyPair; + + CDataStream valueStream(iterator->value().data(), iterator->value().data() + iterator->value().size(), SER_DISK, CLIENT_VERSION); + CCoins coins; + valueStream >> coins; + + iterator->Next(); + + return UtxoIteratorItem { + keyPair.second, + coins + }; + } + + return UtxoIteratorItem(); +} + + +class SynapseSwap +{ +private: + using HashList = std::vector; + +public: + SynapseSwap(); + + void debugTest(); + void dumpUtxo(); + uint256 computeMerkleRoot(); + ProofList getProof(const uint256 & tx); + uint256 computeProofRoot(const uint256 & tx, const ProofList & proof); + +private: + uint256 computeHash(const uint256 & left, const uint256 & right); + int firstRound(HashList & txList, const uint256 & txToProof, uint256 * proofHash); + void moveUp(HashList & txList); + +private: +}; + +SynapseSwap::SynapseSwap() +{ +} + +uint256 SynapseSwap::computeHash(const uint256 & left, const uint256 & right) +{ + return Hash(left.begin(), left.end(), right.begin(), right.end()); +} + +int SynapseSwap::firstRound(HashList & txList, const uint256 & txToProof, uint256 * proofHash) +{ + UtxoIterator iterator; + int indexToProof = -1; + int index = 0; + + for(;;) { + UtxoIteratorItem leftItem = iterator.next(); + if(! leftItem.isValid()) { + break; + } + if(leftItem.txid == txToProof) { + indexToProof = index; + } + ++index; + + UtxoIteratorItem rightItem = iterator.next(); + if(rightItem.isValid()) { + if(rightItem.txid == txToProof) { + indexToProof = index; + } + if(proofHash != nullptr) { + if(indexToProof + 1 == index) { + *proofHash = rightItem.txid; + } + if(indexToProof == index) { + *proofHash = leftItem.txid; + } + } + + ++index; + txList.push_back(computeHash(leftItem.txid, rightItem.txid)); + } + else { + if(proofHash != nullptr) { + if(indexToProof + 1 == index) { + *proofHash = rightItem.txid; + } + } + + txList.push_back(computeHash(leftItem.txid, leftItem.txid)); + break; + } + } + + return indexToProof; +} + +void SynapseSwap::moveUp(HashList & txList) +{ + int count = (int)txList.size(); + int halfCount = (count + 1) / 2; + + for(int i = 0; i < halfCount; ++i) { + int leftIndex = i * 2; + int rightIndex = leftIndex + 1; + if(rightIndex >= count) { + rightIndex = leftIndex; + } + txList[i] = computeHash(txList[leftIndex], txList[rightIndex]); + } + + txList.resize(halfCount); +} + +uint256 SynapseSwap::computeMerkleRoot() +{ + HashList txList; + firstRound(txList, uint256(), nullptr); + + while(txList.size() > 1) { + moveUp(txList); + } + + if(txList.empty()) { + return uint256(); + } + + return txList.front(); +} + +ProofList SynapseSwap::getProof(const uint256 & tx) +{ + HashList txList; + uint256 proofHash; + int index = firstRound(txList, tx, &proofHash); + if(index < 0) { + return ProofList(); + } + + ProofList proof; + + proof.push_back({ + (index & 1) > 0, + proofHash + }); + + for(;;) { + index >>= 1; + if((index & 1) == 0) { + proofHash = (index + 1 >= (int)txList.size() ? txList[index] : txList[index + 1]); + } + else { + proofHash = txList[index - 1]; + } + + proof.push_back({ + (index & 1) > 0, + proofHash + }); + + moveUp(txList); + + if(txList.size() == 1) { + break; + } + } + return proof; +} + +uint256 SynapseSwap::computeProofRoot(const uint256 & tx, const ProofList & proof) +{ + uint256 hash = tx; + + for(const auto node : proof) { + if(node.left) { + hash = computeHash(node.hash, hash); + } + else { + hash = computeHash(hash, node.hash); + } + } + + return hash; +} + +void SynapseSwap::debugTest() +{ + //HashList txList; + //uint256 proofHash; + //firstRound(txList, uint256("f21ea46ab91c0f7fa7829aaf3f96787c742f8ecfa709ba41ebf74d50a32e0000"), &proofHash); + //std::cout << "proofHash: " << proofHash.GetHex() << std::endl; + + auto hash12 = computeHash(uint256("f365fec31f803294d96ad2dde5f3e847addc69c62f89828a11c6f0d1c30c0000"), uint256("04a0f88eb2f4588a6ee970c7342b2d3e52b038d4b6bb5d4f8a49ac3e9a110000")); + auto hash34 = computeHash(uint256("2438cf72cbc602738daf645564b0015df2ccf3497c98d25600c6be6d001c0000"), uint256("f21ea46ab91c0f7fa7829aaf3f96787c742f8ecfa709ba41ebf74d50a32e0000")); + std::cout << "Hash12: " << hash12.GetHex() << std::endl; + std::cout << "Hash34: " << hash34.GetHex() << std::endl; + std::cout << "Hash1234: " << computeHash(hash12, hash34).GetHex() << std::endl; + + uint256 tx("f21ea46ab91c0f7fa7829aaf3f96787c742f8ecfa709ba41ebf74d50a32e0000"); + ProofList proof = getProof(tx); + for(const auto & node : proof) { + std::cout << "path: " << node.hash.GetHex() << " " << (node.left ? "left" : "right") << std::endl; + } + uint256 proofRoot = computeProofRoot(tx, proof); + std::cout << "proofRoot: " << proofRoot.GetHex() << std::endl; + + std::cout << "Root: " << computeMerkleRoot().GetHex() << std::endl; +} + +void SynapseSwap::dumpUtxo() +{ + UtxoIterator iterator; + int count = 0; + for(;;) { + UtxoIteratorItem item = iterator.next(); + if(! item.isValid()) { + break; + } + ++count; + if(count <= 100) { + std::cout << item.txid.GetHex() << " " << item.coins.vout.size() << std::endl; + } + } + std::cout << "Count: " << count << std::endl; +} From 5f55cd9b782890c1b0438a4d2bca4fa3f3dbb24c Mon Sep 17 00:00:00 2001 From: wqking Date: Sun, 10 Feb 2019 10:55:24 +0800 Subject: [PATCH 02/11] Include coin amount in dumped merkle tree --- src/init.cpp | 2 +- src/synapseswap.cpp | 182 +++++++++++++++++++++++--------------------- 2 files changed, 95 insertions(+), 89 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 2e2d3834c818f..546de41cab217 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -733,7 +733,7 @@ bool AppInitServers(boost::thread_group& threadGroup) */ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) { - SynapseSwap synapseSwap; + synapseswap::SynapseSwap synapseSwap; synapseSwap.debugTest(); return false; diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index 0b0673d0a1965..439714771468d 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -7,9 +7,12 @@ #include #include +#include #include +namespace synapseswap { + struct UtxoIteratorItem { uint256 txid; @@ -40,6 +43,37 @@ class UtxoIterator int debugCounter; }; +CAmount getUnspentAmount(const CCoins & coin) +{ + CAmount amount = 0; + + for(const auto & txOut : coin.vout) { + if(! txOut.IsNull() && txOut.nValue > 0) { + amount += txOut.nValue; + } + } + + return amount; +} + +uint256 computeHashes(const uint256 & left, const uint256 & right) +{ + return Hash(left.begin(), left.end(), right.begin(), right.end()); +} + +uint256 computeHashAmount(const uint256 & txID, const CAmount amount) +{ + CDataStream stream(0, 0); + stream << txID; + stream << amount; + return Hash(stream.begin(), stream.end()); +} + +uint256 computeHashCoins(const uint256 & txID, const CCoins & coins) +{ + return computeHashAmount(txID, getUnspentAmount(coins)); +} + UtxoIterator::UtxoIterator() : db(GetDataDir() / "chainstate", 50 * 1024 * 1024, false, false), @@ -69,6 +103,10 @@ UtxoIteratorItem UtxoIterator::next() iterator->Next(); + if(getUnspentAmount(coins) <= 0) { + continue; + } + return UtxoIteratorItem { keyPair.second, coins @@ -94,9 +132,9 @@ class SynapseSwap uint256 computeProofRoot(const uint256 & tx, const ProofList & proof); private: - uint256 computeHash(const uint256 & left, const uint256 & right); - int firstRound(HashList & txList, const uint256 & txToProof, uint256 * proofHash); - void moveUp(HashList & txList); + uint256 getProofHash(const HashList & hashList, const int index); + int buildHashList(HashList & hashList, const uint256 * txToProof); + void moveUp(HashList & hashList); private: }; @@ -105,62 +143,45 @@ SynapseSwap::SynapseSwap() { } -uint256 SynapseSwap::computeHash(const uint256 & left, const uint256 & right) + +uint256 SynapseSwap::getProofHash(const HashList & hashList, const int index) { - return Hash(left.begin(), left.end(), right.begin(), right.end()); + if((index & 1) == 0) { + return (index + 1 >= (int)hashList.size() ? hashList[index] : hashList[index + 1]); + } + else { + return hashList[index - 1]; + } } -int SynapseSwap::firstRound(HashList & txList, const uint256 & txToProof, uint256 * proofHash) +int SynapseSwap::buildHashList(HashList & hashList, const uint256 * hashToProof) { UtxoIterator iterator; - int indexToProof = -1; - int index = 0; for(;;) { - UtxoIteratorItem leftItem = iterator.next(); - if(! leftItem.isValid()) { + UtxoIteratorItem item = iterator.next(); + if(! item.isValid()) { break; } - if(leftItem.txid == txToProof) { - indexToProof = index; - } - ++index; - - UtxoIteratorItem rightItem = iterator.next(); - if(rightItem.isValid()) { - if(rightItem.txid == txToProof) { - indexToProof = index; - } - if(proofHash != nullptr) { - if(indexToProof + 1 == index) { - *proofHash = rightItem.txid; - } - if(indexToProof == index) { - *proofHash = leftItem.txid; - } - } - - ++index; - txList.push_back(computeHash(leftItem.txid, rightItem.txid)); - } - else { - if(proofHash != nullptr) { - if(indexToProof + 1 == index) { - *proofHash = rightItem.txid; - } - } - - txList.push_back(computeHash(leftItem.txid, leftItem.txid)); - break; + hashList.push_back(computeHashCoins(item.txid, item.coins)); + } + + std::sort(hashList.begin(), hashList.end()); + + int indexToProof = -1; + if(hashToProof != nullptr) { + auto it = std::find(hashList.begin(), hashList.end(), *hashToProof); + if(it != hashList.end()) { + indexToProof = it - hashList.begin(); } } return indexToProof; } -void SynapseSwap::moveUp(HashList & txList) +void SynapseSwap::moveUp(HashList & hashList) { - int count = (int)txList.size(); + int count = (int)hashList.size(); int halfCount = (count + 1) / 2; for(int i = 0; i < halfCount; ++i) { @@ -169,63 +190,54 @@ void SynapseSwap::moveUp(HashList & txList) if(rightIndex >= count) { rightIndex = leftIndex; } - txList[i] = computeHash(txList[leftIndex], txList[rightIndex]); + hashList[i] = computeHashes(hashList[leftIndex], hashList[rightIndex]); } - txList.resize(halfCount); + hashList.resize(halfCount); } uint256 SynapseSwap::computeMerkleRoot() { - HashList txList; - firstRound(txList, uint256(), nullptr); + HashList hashList; + buildHashList(hashList, nullptr); - while(txList.size() > 1) { - moveUp(txList); + while(hashList.size() > 1) { + moveUp(hashList); } - if(txList.empty()) { + if(hashList.empty()) { return uint256(); } - return txList.front(); + return hashList.front(); } ProofList SynapseSwap::getProof(const uint256 & tx) { - HashList txList; + HashList hashList; uint256 proofHash; - int index = firstRound(txList, tx, &proofHash); + int index = buildHashList(hashList, &tx); if(index < 0) { return ProofList(); } ProofList proof; - proof.push_back({ - (index & 1) > 0, - proofHash - }); - for(;;) { - index >>= 1; - if((index & 1) == 0) { - proofHash = (index + 1 >= (int)txList.size() ? txList[index] : txList[index + 1]); - } - else { - proofHash = txList[index - 1]; - } + proofHash = getProofHash(hashList, index); proof.push_back({ (index & 1) > 0, proofHash }); - moveUp(txList); + moveUp(hashList); - if(txList.size() == 1) { + if(hashList.size() == 1) { break; } + + index >>= 1; } return proof; } @@ -236,10 +248,10 @@ uint256 SynapseSwap::computeProofRoot(const uint256 & tx, const ProofList & proo for(const auto node : proof) { if(node.left) { - hash = computeHash(node.hash, hash); + hash = computeHashes(node.hash, hash); } else { - hash = computeHash(hash, node.hash); + hash = computeHashes(hash, node.hash); } } @@ -248,23 +260,14 @@ uint256 SynapseSwap::computeProofRoot(const uint256 & tx, const ProofList & proo void SynapseSwap::debugTest() { - //HashList txList; - //uint256 proofHash; - //firstRound(txList, uint256("f21ea46ab91c0f7fa7829aaf3f96787c742f8ecfa709ba41ebf74d50a32e0000"), &proofHash); - //std::cout << "proofHash: " << proofHash.GetHex() << std::endl; - - auto hash12 = computeHash(uint256("f365fec31f803294d96ad2dde5f3e847addc69c62f89828a11c6f0d1c30c0000"), uint256("04a0f88eb2f4588a6ee970c7342b2d3e52b038d4b6bb5d4f8a49ac3e9a110000")); - auto hash34 = computeHash(uint256("2438cf72cbc602738daf645564b0015df2ccf3497c98d25600c6be6d001c0000"), uint256("f21ea46ab91c0f7fa7829aaf3f96787c742f8ecfa709ba41ebf74d50a32e0000")); - std::cout << "Hash12: " << hash12.GetHex() << std::endl; - std::cout << "Hash34: " << hash34.GetHex() << std::endl; - std::cout << "Hash1234: " << computeHash(hash12, hash34).GetHex() << std::endl; - - uint256 tx("f21ea46ab91c0f7fa7829aaf3f96787c742f8ecfa709ba41ebf74d50a32e0000"); - ProofList proof = getProof(tx); - for(const auto & node : proof) { - std::cout << "path: " << node.hash.GetHex() << " " << (node.left ? "left" : "right") << std::endl; - } - uint256 proofRoot = computeProofRoot(tx, proof); + dumpUtxo(); + + uint256 tx("a0aeae14bba0d7c6f542cd8bdde7dd01bbf5b74e98003cd89ec9a7afc4940a00"); + auto hash = computeHashAmount(tx, 420000000); + ProofList proof = getProof(hash); + for(const auto & node : proof) std::cout << "path: " << node.hash.GetHex() << " " << (node.left ? "left" : "right") << std::endl; + + uint256 proofRoot = computeProofRoot(hash, proof); std::cout << "proofRoot: " << proofRoot.GetHex() << std::endl; std::cout << "Root: " << computeMerkleRoot().GetHex() << std::endl; @@ -280,9 +283,12 @@ void SynapseSwap::dumpUtxo() break; } ++count; - if(count <= 100) { - std::cout << item.txid.GetHex() << " " << item.coins.vout.size() << std::endl; + if(count <= 10) { + std::cout << item.txid.GetHex() << " " << getUnspentAmount(item.coins) << std::endl; } } std::cout << "Count: " << count << std::endl; } + + +} //namespace synapseswap From 47e26e703edd683cb530fb5468ef05807a628a07 Mon Sep 17 00:00:00 2001 From: wqking Date: Tue, 12 Feb 2019 14:16:14 +0800 Subject: [PATCH 03/11] Improved utxo dumper tool --- src/init.cpp | 7 +- src/synapseswap.cpp | 198 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 173 insertions(+), 32 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 546de41cab217..766c3c2150717 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -733,9 +733,6 @@ bool AppInitServers(boost::thread_group& threadGroup) */ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) { - synapseswap::SynapseSwap synapseSwap; - synapseSwap.debugTest(); - return false; // ********************************************************* Step 1: setup #ifdef _MSC_VER @@ -2009,5 +2006,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif + synapseswap::SynapseSwap synapseSwap(pcoinsdbview); + synapseSwap.debugTest(); + return false; + return !fRequestShutdown; } diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index 439714771468d..293d475835ebe 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -4,6 +4,8 @@ #include "uint256.h" #include "coins.h" #include "hash.h" +#include "wallet.h" +#include "txdb.h" #include #include @@ -11,6 +13,8 @@ #include +extern CWallet* pwalletMain; + namespace synapseswap { struct UtxoIteratorItem @@ -33,16 +37,44 @@ using ProofList = std::vector; class UtxoIterator { public: - UtxoIterator(); + explicit UtxoIterator(CLevelDBWrapper * db); UtxoIteratorItem next(); private: - CLevelDBWrapper db; + CLevelDBWrapper * db; std::unique_ptr iterator; int debugCounter; }; +std::string binToHex(const void * p, const size_t length) +{ + char psz[1024 * 2 + 1]; + for(size_t i = 0; i < length; i++) + sprintf(psz + i * 2, "%02x", ((unsigned char*)p)[i]); + return std::string(psz, psz + length * 2); +} + +std::string binToReversedHex(const void * p, const size_t length) +{ + char psz[1024 * 2 + 1]; + for(size_t i = 0; i < length; i++) + sprintf(psz + i * 2, "%02x", ((unsigned char*)p)[length - i - 1]); + return std::string(psz, psz + length * 2); +} + +template +std::string binToHex(const C & c) +{ + return binToHex(&c[0], c.size()); +} + +template +std::string binToReversedHex(const C & c) +{ + return binToReversedHex(&c[0], c.size()); +} + CAmount getUnspentAmount(const CCoins & coin) { CAmount amount = 0; @@ -61,23 +93,27 @@ uint256 computeHashes(const uint256 & left, const uint256 & right) return Hash(left.begin(), left.end(), right.begin(), right.end()); } -uint256 computeHashAmount(const uint256 & txID, const CAmount amount) +uint256 computeHashTxOut(const CTxOut & out) { CDataStream stream(0, 0); - stream << txID; - stream << amount; + stream << out.scriptPubKey; + stream << out.nValue; return Hash(stream.begin(), stream.end()); } -uint256 computeHashCoins(const uint256 & txID, const CCoins & coins) +uint256 checkedComputeHashTxOut(const CTxOut & out) { - return computeHashAmount(txID, getUnspentAmount(coins)); + if(out.IsNull()) { + return uint256(); + } + + return computeHashTxOut(out); } -UtxoIterator::UtxoIterator() +UtxoIterator::UtxoIterator(CLevelDBWrapper * db) : - db(GetDataDir() / "chainstate", 50 * 1024 * 1024, false, false), - iterator(db.NewIterator()) + db(db), + iterator(db->NewIterator()) { iterator->SeekToFirst(); @@ -96,6 +132,10 @@ UtxoIteratorItem UtxoIterator::next() CDataStream keyStream(iterator->key().data(), iterator->key().data() + iterator->key().size(), SER_DISK, CLIENT_VERSION); std::pair keyPair; keyStream >> keyPair; + + if(keyPair.first != 'c') { + continue; + } CDataStream valueStream(iterator->value().data(), iterator->value().data() + iterator->value().size(), SER_DISK, CLIENT_VERSION); CCoins coins; @@ -116,6 +156,22 @@ UtxoIteratorItem UtxoIterator::next() return UtxoIteratorItem(); } +// This is a hack to access protected member 'db' in CCoinsViewDB +// It's UB according to C++ standard, but it should work in all compilers. +class HackCoinsViewDB : public CCoinsViewDB +{ +public: + CLevelDBWrapper * getDb() { + return &db; + } +}; + +struct KeyItem +{ + CKeyID id; + CPubKey publicKey; + CKey key; +}; class SynapseSwap { @@ -123,27 +179,32 @@ class SynapseSwap using HashList = std::vector; public: - SynapseSwap(); + SynapseSwap(CCoinsViewDB * coinsViewDB); void debugTest(); void dumpUtxo(); + void dumpSignatures(); uint256 computeMerkleRoot(); - ProofList getProof(const uint256 & tx); - uint256 computeProofRoot(const uint256 & tx, const ProofList & proof); + ProofList getProof(const uint256 & hash); + uint256 computeProofRoot(const uint256 & h, const ProofList & proof); private: + bool getUtxoCoins(const uint256 & txid, CCoins & coins) const; uint256 getProofHash(const HashList & hashList, const int index); - int buildHashList(HashList & hashList, const uint256 * txToProof); + int buildHashList(HashList & hashList, const uint256 * hashToProof); void moveUp(HashList & hashList); + std::vector getKeys(); + CWallet * getWallet() const; private: + CLevelDBWrapper * utxoDb; }; -SynapseSwap::SynapseSwap() +SynapseSwap::SynapseSwap(CCoinsViewDB * coinsViewDB) + : utxoDb(static_cast(coinsViewDB)->getDb()) { } - uint256 SynapseSwap::getProofHash(const HashList & hashList, const int index) { if((index & 1) == 0) { @@ -156,14 +217,19 @@ uint256 SynapseSwap::getProofHash(const HashList & hashList, const int index) int SynapseSwap::buildHashList(HashList & hashList, const uint256 * hashToProof) { - UtxoIterator iterator; + UtxoIterator iterator(utxoDb); for(;;) { UtxoIteratorItem item = iterator.next(); if(! item.isValid()) { break; } - hashList.push_back(computeHashCoins(item.txid, item.coins)); + for(const auto & out : item.coins.vout) { + uint256 hash = checkedComputeHashTxOut(out); + if(!hash.IsNull()) { + hashList.push_back(hash); + } + } } std::sort(hashList.begin(), hashList.end()); @@ -212,11 +278,11 @@ uint256 SynapseSwap::computeMerkleRoot() return hashList.front(); } -ProofList SynapseSwap::getProof(const uint256 & tx) +ProofList SynapseSwap::getProof(const uint256 & hash) { HashList hashList; uint256 proofHash; - int index = buildHashList(hashList, &tx); + int index = buildHashList(hashList, &hash); if(index < 0) { return ProofList(); } @@ -242,9 +308,9 @@ ProofList SynapseSwap::getProof(const uint256 & tx) return proof; } -uint256 SynapseSwap::computeProofRoot(const uint256 & tx, const ProofList & proof) +uint256 SynapseSwap::computeProofRoot(const uint256 & h, const ProofList & proof) { - uint256 hash = tx; + uint256 hash = h; for(const auto node : proof) { if(node.left) { @@ -258,24 +324,44 @@ uint256 SynapseSwap::computeProofRoot(const uint256 & tx, const ProofList & proo return hash; } +bool SynapseSwap::getUtxoCoins(const uint256 & txid, CCoins & coins) const +{ + return utxoDb->Read(make_pair('c', txid), coins); +} + void SynapseSwap::debugTest() { dumpUtxo(); - uint256 tx("a0aeae14bba0d7c6f542cd8bdde7dd01bbf5b74e98003cd89ec9a7afc4940a00"); - auto hash = computeHashAmount(tx, 420000000); - ProofList proof = getProof(hash); - for(const auto & node : proof) std::cout << "path: " << node.hash.GetHex() << " " << (node.left ? "left" : "right") << std::endl; + uint256 tx("cc3995305ff73fe1d7faeda0ec8c9f977fe96526d7f6b4d835c783eecdb50b00"); + CCoins coins; + if(!getUtxoCoins(tx, coins)) { + std::cout << "Can't find coins for " << tx.GetHex() << std::endl; + } + else { + for(const auto & out : coins.vout) { + auto hash = checkedComputeHashTxOut(out); + if(hash.IsNull()) continue; + + ProofList proof = getProof(hash); + for(const auto & node : proof) std::cout << "path: " << node.hash.GetHex() << " " << (node.left ? "left" : "right") << std::endl; - uint256 proofRoot = computeProofRoot(hash, proof); - std::cout << "proofRoot: " << proofRoot.GetHex() << std::endl; + uint256 proofRoot = computeProofRoot(hash, proof); + std::cout << "proofRoot: " << proofRoot.GetHex() << std::endl; + + break; + } + } std::cout << "Root: " << computeMerkleRoot().GetHex() << std::endl; + + dumpSignatures(); + getKeys(); } void SynapseSwap::dumpUtxo() { - UtxoIterator iterator; + UtxoIterator iterator(utxoDb); int count = 0; for(;;) { UtxoIteratorItem item = iterator.next(); @@ -290,5 +376,59 @@ void SynapseSwap::dumpUtxo() std::cout << "Count: " << count << std::endl; } +void SynapseSwap::dumpSignatures() +{ + CWallet * wallet = getWallet(); + + int txCount = 0; + LOCK2(cs_main, wallet->cs_wallet); + for (map::const_iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it) { + const uint256& wtxid = it->first; + const CWalletTx* pcoin = &(*it).second; + + if(!utxoDb->Exists(make_pair('c', wtxid))) { + continue; + } + + CCoins coins; + bool hasCoins = getUtxoCoins(wtxid, coins); + + if(! hasCoins) { + continue; + } + + ++txCount; + std::cout << "wtxid: " << wtxid.GetHex() << std::endl; + } + std::cout << "txCount: " << txCount << std::endl; +} + +std::vector SynapseSwap::getKeys() +{ + CWallet * wallet = getWallet(); + std::set keyIdSet; + wallet->GetKeys(keyIdSet); + + std::vector keys; + for(const CKeyID & keyId : keyIdSet) { + KeyItem item; + item.id = keyId; + if(wallet->GetPubKey(keyId, item.publicKey)) { + if(wallet->GetKey(keyId, item.key)) { + keys.push_back(item); +/*std::cout << "item.publicKey: " + //<< binToHex(item.publicKey.Raw()) + << item.publicKey.GetHash().GetHex() + << std::endl;*/ + } + } + } + return keys; +} + +CWallet * SynapseSwap::getWallet() const +{ + return pwalletMain; +} } //namespace synapseswap From 52d25322cdc79038701a514039139ecf01c22e09 Mon Sep 17 00:00:00 2001 From: wqking Date: Wed, 13 Feb 2019 19:24:59 +0800 Subject: [PATCH 04/11] Added coin swap signature --- src/synapseswap.cpp | 156 ++++++++++++++++++++++++++++++++------------ 1 file changed, 114 insertions(+), 42 deletions(-) diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index 293d475835ebe..9c1259c03da64 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -6,6 +6,7 @@ #include "hash.h" #include "wallet.h" #include "txdb.h" +#include "script/sign.h" #include #include @@ -16,6 +17,16 @@ extern CWallet* pwalletMain; namespace synapseswap { + +constexpr int maxUtxoBlockHeight = 999999999; +constexpr int minUtxoBlockHeight = 0; + +struct UtxoProofNode +{ + bool left; + uint256 hash; +}; +using ProofList = std::vector; struct UtxoIteratorItem { @@ -27,13 +38,6 @@ struct UtxoIteratorItem } }; -struct UtxoProofNode -{ - bool left; - uint256 hash; -}; -using ProofList = std::vector; - class UtxoIterator { public: @@ -93,23 +97,6 @@ uint256 computeHashes(const uint256 & left, const uint256 & right) return Hash(left.begin(), left.end(), right.begin(), right.end()); } -uint256 computeHashTxOut(const CTxOut & out) -{ - CDataStream stream(0, 0); - stream << out.scriptPubKey; - stream << out.nValue; - return Hash(stream.begin(), stream.end()); -} - -uint256 checkedComputeHashTxOut(const CTxOut & out) -{ - if(out.IsNull()) { - return uint256(); - } - - return computeHashTxOut(out); -} - UtxoIterator::UtxoIterator(CLevelDBWrapper * db) : db(db), @@ -146,6 +133,10 @@ UtxoIteratorItem UtxoIterator::next() if(getUnspentAmount(coins) <= 0) { continue; } + + if(coins.nHeight < minUtxoBlockHeight || coins.nHeight > maxUtxoBlockHeight) { + continue; + } return UtxoIteratorItem { keyPair.second, @@ -173,6 +164,13 @@ struct KeyItem CKey key; }; +struct UnlockItem +{ + CScript scriptPubKey; + CAmount amount; + CScript redeemScript; +}; + class SynapseSwap { private: @@ -182,11 +180,34 @@ class SynapseSwap SynapseSwap(CCoinsViewDB * coinsViewDB); void debugTest(); - void dumpUtxo(); - void dumpSignatures(); + + // Compute a merkle tree leaf hash from a CTxOut + uint256 computeHashTxOut(const CTxOut & out); + + // Compute a merkle tree leaf hash from a CTxOut + // If the CTxOut is spent, an empty uint256 is returned; + uint256 checkedComputeHashTxOut(const CTxOut & out); + + // Compute the merkle tree of all valid UTXOs + // A valid UTXO has coins, and the block height is within [minUtxoBlockHeight, maxUtxoBlockHeight] uint256 computeMerkleRoot(); + + // Compute a proof path (ProofList) of a give hash. + // The hash can be obtained by checkedComputeHashTxOut ProofList getProof(const uint256 & hash); - uint256 computeProofRoot(const uint256 & h, const ProofList & proof); + + // Compute the merkle root from a proof path (ProofList) of a give hash. + // The hash can be obtained by checkedComputeHashTxOut + // The result can be compared to the result of `computeMerkleRoot()` + uint256 computeProofRoot(uint256 hash, const ProofList & proof); + + // Get a list of UnlockItem. The result can be used to transfer coins from old chain to new chain. + // The contract on the new chain will very the UnlockItem against the merkle tree. + std::vector getUnlockItems(); + +private: // test functions + void debugDumpUtxo(); + void debugDumpSignatures(); private: bool getUtxoCoins(const uint256 & txid, CCoins & coins) const; @@ -195,6 +216,7 @@ class SynapseSwap void moveUp(HashList & hashList); std::vector getKeys(); CWallet * getWallet() const; + SignatureData signTxOut(const int nOut, const CWalletTx* pcoin); private: CLevelDBWrapper * utxoDb; @@ -205,6 +227,23 @@ SynapseSwap::SynapseSwap(CCoinsViewDB * coinsViewDB) { } +uint256 SynapseSwap::computeHashTxOut(const CTxOut & out) +{ + CDataStream stream(0, 0); + stream << out.scriptPubKey; + stream << out.nValue; + return Hash(stream.begin(), stream.end()); +} + +uint256 SynapseSwap::checkedComputeHashTxOut(const CTxOut & out) +{ + if(out.IsNull()) { + return uint256(); + } + + return computeHashTxOut(out); +} + uint256 SynapseSwap::getProofHash(const HashList & hashList, const int index) { if((index & 1) == 0) { @@ -308,10 +347,8 @@ ProofList SynapseSwap::getProof(const uint256 & hash) return proof; } -uint256 SynapseSwap::computeProofRoot(const uint256 & h, const ProofList & proof) +uint256 SynapseSwap::computeProofRoot(uint256 hash, const ProofList & proof) { - uint256 hash = h; - for(const auto node : proof) { if(node.left) { hash = computeHashes(node.hash, hash); @@ -331,7 +368,7 @@ bool SynapseSwap::getUtxoCoins(const uint256 & txid, CCoins & coins) const void SynapseSwap::debugTest() { - dumpUtxo(); + debugDumpUtxo(); uint256 tx("cc3995305ff73fe1d7faeda0ec8c9f977fe96526d7f6b4d835c783eecdb50b00"); CCoins coins; @@ -355,11 +392,11 @@ void SynapseSwap::debugTest() std::cout << "Root: " << computeMerkleRoot().GetHex() << std::endl; - dumpSignatures(); + debugDumpSignatures(); getKeys(); } -void SynapseSwap::dumpUtxo() +void SynapseSwap::debugDumpUtxo() { UtxoIterator iterator(utxoDb); int count = 0; @@ -376,20 +413,42 @@ void SynapseSwap::dumpUtxo() std::cout << "Count: " << count << std::endl; } -void SynapseSwap::dumpSignatures() +void SynapseSwap::debugDumpSignatures() { + std::vector itemList = getUnlockItems(); + for(const UnlockItem & item : itemList) { + } + + std::cout << "unlockItemCount: " << itemList.size() << std::endl; +} + +SignatureData SynapseSwap::signTxOut(const int nOut, const CWalletTx* pcoin) +{ + CTransaction tx; + tx.vin.push_back(CTxIn(pcoin->GetHash(), nOut)); + const auto & out = pcoin->vout[nOut]; + tx.vout.push_back(CTxOut(out.nValue, out.scriptPubKey)); + SignatureData sigData; + if(!ProduceSignature(TransactionSignatureCreator(getWallet(), &tx, nOut, out.nValue, SIGHASH_ALL), out.scriptPubKey, sigData)) { + std::cout << "signTxOut failed " << std::endl; + } + else { + std::cout << "signTxOut succeeded " << std::endl; + } + return sigData; +} + +std::vector SynapseSwap::getUnlockItems() +{ + std::vector itemList; + CWallet * wallet = getWallet(); - int txCount = 0; LOCK2(cs_main, wallet->cs_wallet); for (map::const_iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it) { const uint256& wtxid = it->first; const CWalletTx* pcoin = &(*it).second; - if(!utxoDb->Exists(make_pair('c', wtxid))) { - continue; - } - CCoins coins; bool hasCoins = getUtxoCoins(wtxid, coins); @@ -397,10 +456,23 @@ void SynapseSwap::dumpSignatures() continue; } - ++txCount; - std::cout << "wtxid: " << wtxid.GetHex() << std::endl; + int nOut = -1; + for(const auto & out : coins.vout) { + ++nOut; + if(out.IsNull()) { + continue; + } + UnlockItem item; + item.scriptPubKey = out.scriptPubKey; + item.amount = out.nValue; + auto sigData = signTxOut(nOut, pcoin); + item.redeemScript = sigData.scriptSig; + + itemList.push_back(item); + } } - std::cout << "txCount: " << txCount << std::endl; + + return itemList; } std::vector SynapseSwap::getKeys() From 5966503e3bd057f6e4bdb45fc2502b53a1c863ae Mon Sep 17 00:00:00 2001 From: wqking Date: Thu, 18 Apr 2019 17:17:15 +0800 Subject: [PATCH 05/11] Added txid in dumped UTXO hash --- doc/Doxyfile | 2 +- src/init.cpp | 1 + src/synapseswap.cpp | 42 ++++++++++++++++++++++++++++++------------ 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index 254703e9e5340..758828a6a93eb 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Phore Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.3 +PROJECT_NUMBER = 1.6.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/src/init.cpp b/src/init.cpp index 766c3c2150717..d296bb8d22bf3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2008,6 +2008,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) synapseswap::SynapseSwap synapseSwap(pcoinsdbview); synapseSwap.debugTest(); + synapseSwap.saveHashList("/home/wangqi/temp/utxo.txt"); return false; return !fRequestShutdown; diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index 9c1259c03da64..d4bd0ea2ad2e3 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -11,13 +11,14 @@ #include #include #include - +#include #include extern CWallet* pwalletMain; namespace synapseswap { - + +// Only UTXOs in the blocks between the two values are included constexpr int maxUtxoBlockHeight = 999999999; constexpr int minUtxoBlockHeight = 0; @@ -166,6 +167,7 @@ struct KeyItem struct UnlockItem { + uint256 txid; CScript scriptPubKey; CAmount amount; CScript redeemScript; @@ -182,11 +184,11 @@ class SynapseSwap void debugTest(); // Compute a merkle tree leaf hash from a CTxOut - uint256 computeHashTxOut(const CTxOut & out); + uint256 computeHashTxOut(const uint256 & txid, const CTxOut & out); // Compute a merkle tree leaf hash from a CTxOut // If the CTxOut is spent, an empty uint256 is returned; - uint256 checkedComputeHashTxOut(const CTxOut & out); + uint256 checkedComputeHashTxOut(const uint256 & txid, const CTxOut & out); // Compute the merkle tree of all valid UTXOs // A valid UTXO has coins, and the block height is within [minUtxoBlockHeight, maxUtxoBlockHeight] @@ -201,10 +203,12 @@ class SynapseSwap // The result can be compared to the result of `computeMerkleRoot()` uint256 computeProofRoot(uint256 hash, const ProofList & proof); - // Get a list of UnlockItem. The result can be used to transfer coins from old chain to new chain. - // The contract on the new chain will very the UnlockItem against the merkle tree. + // Get a list of UnlockItem. The result can be used to transfer coins in current wallet from old chain to new chain. + // The contract on the new chain will verify the UnlockItem against the merkle tree. std::vector getUnlockItems(); + void saveHashList(const std::string & fileName); + private: // test functions void debugDumpUtxo(); void debugDumpSignatures(); @@ -227,21 +231,22 @@ SynapseSwap::SynapseSwap(CCoinsViewDB * coinsViewDB) { } -uint256 SynapseSwap::computeHashTxOut(const CTxOut & out) +uint256 SynapseSwap::computeHashTxOut(const uint256 & txid, const CTxOut & out) { CDataStream stream(0, 0); + stream << txid; stream << out.scriptPubKey; stream << out.nValue; return Hash(stream.begin(), stream.end()); } -uint256 SynapseSwap::checkedComputeHashTxOut(const CTxOut & out) +uint256 SynapseSwap::checkedComputeHashTxOut(const uint256 & txid, const CTxOut & out) { if(out.IsNull()) { return uint256(); } - return computeHashTxOut(out); + return computeHashTxOut(txid, out); } uint256 SynapseSwap::getProofHash(const HashList & hashList, const int index) @@ -264,7 +269,7 @@ int SynapseSwap::buildHashList(HashList & hashList, const uint256 * hashToProof) break; } for(const auto & out : item.coins.vout) { - uint256 hash = checkedComputeHashTxOut(out); + uint256 hash = checkedComputeHashTxOut(item.txid, out); if(!hash.IsNull()) { hashList.push_back(hash); } @@ -366,18 +371,30 @@ bool SynapseSwap::getUtxoCoins(const uint256 & txid, CCoins & coins) const return utxoDb->Read(make_pair('c', txid), coins); } +void SynapseSwap::saveHashList(const std::string & fileName) +{ + HashList hashList; + buildHashList(hashList, nullptr); + + std::ofstream file(fileName); + for(const auto & hash : hashList) { + file << binToHex(hash.begin(), hash.size()) << std::endl; + } + file.close(); +} + void SynapseSwap::debugTest() { debugDumpUtxo(); - uint256 tx("cc3995305ff73fe1d7faeda0ec8c9f977fe96526d7f6b4d835c783eecdb50b00"); + uint256 tx("661c371db32258c14a5c58ef8547de7740d69929c62b3c4e6b02ceeabaf30100"); CCoins coins; if(!getUtxoCoins(tx, coins)) { std::cout << "Can't find coins for " << tx.GetHex() << std::endl; } else { for(const auto & out : coins.vout) { - auto hash = checkedComputeHashTxOut(out); + auto hash = checkedComputeHashTxOut(tx, out); if(hash.IsNull()) continue; ProofList proof = getProof(hash); @@ -463,6 +480,7 @@ std::vector SynapseSwap::getUnlockItems() continue; } UnlockItem item; + item.txid = wtxid; item.scriptPubKey = out.scriptPubKey; item.amount = out.nValue; auto sigData = signTxOut(nOut, pcoin); From 5936817d80ce0589fee534d82af6cbaaf926c5ce Mon Sep 17 00:00:00 2001 From: wqking Date: Fri, 19 Apr 2019 09:28:36 +0800 Subject: [PATCH 06/11] Added comment --- src/synapseswap.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index d4bd0ea2ad2e3..de1aa471423e5 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -165,6 +165,12 @@ struct KeyItem CKey key; }; +/* +To verify an UnlockItem, +1. Use txid, scriptPubKey and amount to calculate the leaf hash, similar how SynapseSwap::computeHashTxOut does +2. Verify the hash in the merkle tree. +3. Verify the signature of redeemScript, similar as SynapseSwap::signTxOut +*/ struct UnlockItem { uint256 txid; From cc0cb0532402dc9a4ef0effc713b88c8a837c36d Mon Sep 17 00:00:00 2001 From: wqking Date: Sat, 20 Apr 2019 16:23:58 +0800 Subject: [PATCH 07/11] Added proofListToText --- src/synapseswap.cpp | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index de1aa471423e5..cad75342bf15f 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -98,6 +98,11 @@ uint256 computeHashes(const uint256 & left, const uint256 & right) return Hash(left.begin(), left.end(), right.begin(), right.end()); } +std::string getHashString(const uint256 & hash) +{ + return hash.ToStringReverseEndian(); +} + UtxoIterator::UtxoIterator(CLevelDBWrapper * db) : db(db), @@ -203,6 +208,8 @@ class SynapseSwap // Compute a proof path (ProofList) of a give hash. // The hash can be obtained by checkedComputeHashTxOut ProofList getProof(const uint256 & hash); + + std::string proofListToText(const ProofList & proofList); // Compute the merkle root from a proof path (ProofList) of a give hash. // The hash can be obtained by checkedComputeHashTxOut @@ -358,6 +365,18 @@ ProofList SynapseSwap::getProof(const uint256 & hash) return proof; } +std::string SynapseSwap::proofListToText(const ProofList & proofList) +{ + std::string result; + + for(const auto & proof : proofList) { + result += (proof.left ? 'L' : 'R'); + result += getHashString(proof.hash); + } + + return result; +} + uint256 SynapseSwap::computeProofRoot(uint256 hash, const ProofList & proof) { for(const auto node : proof) { @@ -389,14 +408,21 @@ void SynapseSwap::saveHashList(const std::string & fileName) file.close(); } +uint256 hashFromReversedString(const std::string & text) +{ + uint256 hash(text); + std::reverse(hash.begin(), hash.end()); + return hash; +} + void SynapseSwap::debugTest() { debugDumpUtxo(); - uint256 tx("661c371db32258c14a5c58ef8547de7740d69929c62b3c4e6b02ceeabaf30100"); + uint256 tx = hashFromReversedString("00013a9407f671e11e2b81369d788dd8c5144f58ddcb9ee9c185274bc4f4a778"); CCoins coins; if(!getUtxoCoins(tx, coins)) { - std::cout << "Can't find coins for " << tx.GetHex() << std::endl; + std::cout << "Can't find coins for " << getHashString(tx) << std::endl; } else { for(const auto & out : coins.vout) { @@ -404,16 +430,20 @@ void SynapseSwap::debugTest() if(hash.IsNull()) continue; ProofList proof = getProof(hash); - for(const auto & node : proof) std::cout << "path: " << node.hash.GetHex() << " " << (node.left ? "left" : "right") << std::endl; + if(proof.empty()) { + continue; + } + std::cout << "Proof text: " << proofListToText(proof) << std::endl; + for(const auto & node : proof) std::cout << "path: " << getHashString(node.hash) << " " << (node.left ? "left" : "right") << std::endl; uint256 proofRoot = computeProofRoot(hash, proof); - std::cout << "proofRoot: " << proofRoot.GetHex() << std::endl; + std::cout << "proofRoot: " << getHashString(proofRoot) << std::endl; break; } } - std::cout << "Root: " << computeMerkleRoot().GetHex() << std::endl; + std::cout << "Root: " << getHashString(computeMerkleRoot()) << std::endl; debugDumpSignatures(); getKeys(); @@ -430,7 +460,7 @@ void SynapseSwap::debugDumpUtxo() } ++count; if(count <= 10) { - std::cout << item.txid.GetHex() << " " << getUnspentAmount(item.coins) << std::endl; + std::cout << getHashString(item.txid) << " " << getUnspentAmount(item.coins) << std::endl; } } std::cout << "Count: " << count << std::endl; @@ -514,7 +544,7 @@ std::vector SynapseSwap::getKeys() keys.push_back(item); /*std::cout << "item.publicKey: " //<< binToHex(item.publicKey.Raw()) - << item.publicKey.GetHash().GetHex() + << getHashString(item.publicKey.GetHash()) << std::endl;*/ } } From ed39a411cae02071c3be3a8a6382bef08bd19606 Mon Sep 17 00:00:00 2001 From: wqking Date: Sun, 21 Apr 2019 09:26:37 +0800 Subject: [PATCH 08/11] Added more debug code --- src/synapseswap.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index cad75342bf15f..d7a77c9ee7daa 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -100,7 +100,8 @@ uint256 computeHashes(const uint256 & left, const uint256 & right) std::string getHashString(const uint256 & hash) { - return hash.ToStringReverseEndian(); + return hash.GetHex(); + //return hash.ToStringReverseEndian(); } UtxoIterator::UtxoIterator(CLevelDBWrapper * db) @@ -379,12 +380,17 @@ std::string SynapseSwap::proofListToText(const ProofList & proofList) uint256 SynapseSwap::computeProofRoot(uint256 hash, const ProofList & proof) { + //std::cout << "===== computeProofRoot" << std::endl; for(const auto node : proof) { if(node.left) { + //std::cout << "Input L: " << node.hash.GetHex() << " R: " << hash.GetHex() << std::endl; hash = computeHashes(node.hash, hash); + //std::cout << "L compute: " << hash.GetHex() << std::endl; } else { + //std::cout << "Input L: " << hash.GetHex() << " R: " << node.hash.GetHex() << std::endl; hash = computeHashes(hash, node.hash); + //std::cout << "R compute: " << std::endl; } } @@ -418,8 +424,13 @@ uint256 hashFromReversedString(const std::string & text) void SynapseSwap::debugTest() { debugDumpUtxo(); + + // Hash is d8f244c159278ea8cfffcbe1c463edef33d92d11d36ac3c62efd3eb7ff3a5dbf + const char * b = "a"; + std::cout << Hash(b, b + 1).GetHex() << std::endl; - uint256 tx = hashFromReversedString("00013a9407f671e11e2b81369d788dd8c5144f58ddcb9ee9c185274bc4f4a778"); + //uint256 tx = hashFromReversedString("00013a9407f671e11e2b81369d788dd8c5144f58ddcb9ee9c185274bc4f4a778"); + uint256 tx("78a7f4c44b2785c1e99ecbdd584f14c5d88d789d36812b1ee171f607943a0100"); CCoins coins; if(!getUtxoCoins(tx, coins)) { std::cout << "Can't find coins for " << getHashString(tx) << std::endl; @@ -445,8 +456,10 @@ void SynapseSwap::debugTest() std::cout << "Root: " << getHashString(computeMerkleRoot()) << std::endl; - debugDumpSignatures(); - getKeys(); + std::cout << "Test: " << getHashString(computeHashes(tx, tx)) << std::endl; + + //debugDumpSignatures(); + //getKeys(); } void SynapseSwap::debugDumpUtxo() From e0c7b4c5da834d1e3075cd69f3c4338d47e5010e Mon Sep 17 00:00:00 2001 From: wqking Date: Mon, 22 Apr 2019 10:53:07 +0800 Subject: [PATCH 09/11] Use JSON for coin swap data format --- src/synapseswap.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index d7a77c9ee7daa..0bab2b3dd4edd 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -7,6 +7,7 @@ #include "wallet.h" #include "txdb.h" #include "script/sign.h" +#include "univalue.h" #include #include @@ -368,6 +369,15 @@ ProofList SynapseSwap::getProof(const uint256 & hash) std::string SynapseSwap::proofListToText(const ProofList & proofList) { + UniValue value(UniValue::VARR); + for(const auto & proof : proofList) { + UniValue item(UniValue::VOBJ); + item.pushKV("left", proof.left); + item.pushKV("hash", getHashString(proof.hash)); + value.push_back(item); + } + return value.write(); + std::string result; for(const auto & proof : proofList) { @@ -380,7 +390,7 @@ std::string SynapseSwap::proofListToText(const ProofList & proofList) uint256 SynapseSwap::computeProofRoot(uint256 hash, const ProofList & proof) { - //std::cout << "===== computeProofRoot" << std::endl; + std::cout << "===== computeProofRoot hash = " << hash.GetHex() << std::endl; for(const auto node : proof) { if(node.left) { //std::cout << "Input L: " << node.hash.GetHex() << " R: " << hash.GetHex() << std::endl; From bb9dfd1e8c4d8c2fbe9c94bf32712137a9d0ebb0 Mon Sep 17 00:00:00 2001 From: wqking Date: Wed, 24 Apr 2019 12:19:44 +0800 Subject: [PATCH 10/11] Improved UnlockItem --- src/init.cpp | 3 ++- src/synapseswap.cpp | 62 ++++++++++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index d296bb8d22bf3..d73b72ead07f3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2006,10 +2006,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif + //return !fRequestShutdown; + synapseswap::SynapseSwap synapseSwap(pcoinsdbview); synapseSwap.debugTest(); synapseSwap.saveHashList("/home/wangqi/temp/utxo.txt"); return false; - return !fRequestShutdown; } diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index 0bab2b3dd4edd..2a80f194e9e0f 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -18,6 +18,8 @@ extern CWallet* pwalletMain; namespace synapseswap { + +constexpr bool debug = true; // Only UTXOs in the blocks between the two values are included constexpr int maxUtxoBlockHeight = 999999999; @@ -181,6 +183,7 @@ To verify an UnlockItem, struct UnlockItem { uint256 txid; + int out; CScript scriptPubKey; CAmount amount; CScript redeemScript; @@ -377,15 +380,22 @@ std::string SynapseSwap::proofListToText(const ProofList & proofList) value.push_back(item); } return value.write(); +} - std::string result; - - for(const auto & proof : proofList) { - result += (proof.left ? 'L' : 'R'); - result += getHashString(proof.hash); - } - - return result; +UniValue unlockItemToJson(const UnlockItem & item) +{ + UniValue json(UniValue::VOBJ); + json.pushKV("txid", item.txid.GetHex()); + json.pushKV("out", item.out); + json.pushKV("scriptPubKey", binToHex(item.scriptPubKey)); + json.pushKV("amount", item.amount); + json.pushKV("redeemScript", binToHex(item.redeemScript)); + return json; +} + +std::string unlockItemToText(const UnlockItem & item) +{ + return unlockItemToJson(item).write(); } uint256 SynapseSwap::computeProofRoot(uint256 hash, const ProofList & proof) @@ -424,23 +434,11 @@ void SynapseSwap::saveHashList(const std::string & fileName) file.close(); } -uint256 hashFromReversedString(const std::string & text) -{ - uint256 hash(text); - std::reverse(hash.begin(), hash.end()); - return hash; -} - void SynapseSwap::debugTest() { debugDumpUtxo(); - // Hash is d8f244c159278ea8cfffcbe1c463edef33d92d11d36ac3c62efd3eb7ff3a5dbf - const char * b = "a"; - std::cout << Hash(b, b + 1).GetHex() << std::endl; - - //uint256 tx = hashFromReversedString("00013a9407f671e11e2b81369d788dd8c5144f58ddcb9ee9c185274bc4f4a778"); - uint256 tx("78a7f4c44b2785c1e99ecbdd584f14c5d88d789d36812b1ee171f607943a0100"); + uint256 tx("277de02a6b71ea455061ae3e9898b74cb9142750d5966268aaa5bdb317f7380b"); CCoins coins; if(!getUtxoCoins(tx, coins)) { std::cout << "Can't find coins for " << getHashString(tx) << std::endl; @@ -454,6 +452,7 @@ void SynapseSwap::debugTest() if(proof.empty()) { continue; } + std::cout << "Proof hash: " << hash.GetHex() << std::endl; std::cout << "Proof text: " << proofListToText(proof) << std::endl; for(const auto & node : proof) std::cout << "path: " << getHashString(node.hash) << " " << (node.left ? "left" : "right") << std::endl; @@ -468,6 +467,10 @@ void SynapseSwap::debugTest() std::cout << "Test: " << getHashString(computeHashes(tx, tx)) << std::endl; + std::vector itemList = getUnlockItems(); + if(! itemList.empty()) { + std::cout << "UnlockItem: " << unlockItemToText(itemList.front()) << std::endl; + } //debugDumpSignatures(); //getKeys(); } @@ -500,16 +503,20 @@ void SynapseSwap::debugDumpSignatures() SignatureData SynapseSwap::signTxOut(const int nOut, const CWalletTx* pcoin) { - CTransaction tx; + CMutableTransaction tx; + tx.nVersion = CTransaction::CURRENT_VERSION; + tx.nLockTime = 0; tx.vin.push_back(CTxIn(pcoin->GetHash(), nOut)); const auto & out = pcoin->vout[nOut]; + tx.vout.push_back(CTxOut(out.nValue, out.scriptPubKey)); SignatureData sigData; - if(!ProduceSignature(TransactionSignatureCreator(getWallet(), &tx, nOut, out.nValue, SIGHASH_ALL), out.scriptPubKey, sigData)) { - std::cout << "signTxOut failed " << std::endl; + CTransaction ntx(tx); + if(!ProduceSignature(TransactionSignatureCreator(getWallet(), &ntx, nOut, out.nValue, SIGHASH_ALL), out.scriptPubKey, sigData)) { + //std::cout << "signTxOut failed " << std::endl; } else { - std::cout << "signTxOut succeeded " << std::endl; + //std::cout << "signTxOut succeeded " << std::endl; } return sigData; } @@ -529,7 +536,9 @@ std::vector SynapseSwap::getUnlockItems() bool hasCoins = getUtxoCoins(wtxid, coins); if(! hasCoins) { - continue; + if(! debug) { + continue; + } } int nOut = -1; @@ -540,6 +549,7 @@ std::vector SynapseSwap::getUnlockItems() } UnlockItem item; item.txid = wtxid; + item.out = nOut; item.scriptPubKey = out.scriptPubKey; item.amount = out.nValue; auto sigData = signTxOut(nOut, pcoin); From 975293ab0c07355c328fc81a3f005f90531e8885 Mon Sep 17 00:00:00 2001 From: wqking Date: Mon, 29 Apr 2019 09:10:42 +0800 Subject: [PATCH 11/11] Cleaned code --- src/synapseswap.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/synapseswap.cpp b/src/synapseswap.cpp index 2a80f194e9e0f..e3ecbbf35b01a 100644 --- a/src/synapseswap.cpp +++ b/src/synapseswap.cpp @@ -19,8 +19,6 @@ extern CWallet* pwalletMain; namespace synapseswap { -constexpr bool debug = true; - // Only UTXOs in the blocks between the two values are included constexpr int maxUtxoBlockHeight = 999999999; constexpr int minUtxoBlockHeight = 0; @@ -124,8 +122,6 @@ UtxoIteratorItem UtxoIterator::next() continue; } - //++debugCounter; if(debugCounter > 4) break; - CDataStream keyStream(iterator->key().data(), iterator->key().data() + iterator->key().size(), SER_DISK, CLIENT_VERSION); std::pair keyPair; keyStream >> keyPair; @@ -403,14 +399,10 @@ uint256 SynapseSwap::computeProofRoot(uint256 hash, const ProofList & proof) std::cout << "===== computeProofRoot hash = " << hash.GetHex() << std::endl; for(const auto node : proof) { if(node.left) { - //std::cout << "Input L: " << node.hash.GetHex() << " R: " << hash.GetHex() << std::endl; hash = computeHashes(node.hash, hash); - //std::cout << "L compute: " << hash.GetHex() << std::endl; } else { - //std::cout << "Input L: " << hash.GetHex() << " R: " << node.hash.GetHex() << std::endl; hash = computeHashes(hash, node.hash); - //std::cout << "R compute: " << std::endl; } } @@ -529,16 +521,14 @@ std::vector SynapseSwap::getUnlockItems() LOCK2(cs_main, wallet->cs_wallet); for (map::const_iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it) { - const uint256& wtxid = it->first; + const uint256 & wtxid = it->first; const CWalletTx* pcoin = &(*it).second; CCoins coins; bool hasCoins = getUtxoCoins(wtxid, coins); if(! hasCoins) { - if(! debug) { - continue; - } + continue; } int nOut = -1; @@ -575,10 +565,6 @@ std::vector SynapseSwap::getKeys() if(wallet->GetPubKey(keyId, item.publicKey)) { if(wallet->GetKey(keyId, item.key)) { keys.push_back(item); -/*std::cout << "item.publicKey: " - //<< binToHex(item.publicKey.Raw()) - << getHashString(item.publicKey.GetHash()) - << std::endl;*/ } } }