diff --git a/.gitignore b/.gitignore index cfc3d4e7c..e30fcd0b9 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.bak *.swp *.pyc *~ @@ -48,6 +49,7 @@ stamp-h1 .dirstamp 1 .vs +client_cookie Makefile ArmoryDB @@ -93,6 +95,7 @@ _CppBlockUtils.* /cppForSwig/gtest/*.lmdb* /cppForSwig/gtest/DB1kIterTest /cppForSwig/gtest/SignerTests +/cppForSwig/gtest/fakehomedir/* /cppForSwig/libbtc/bitcoin-spv @@ -178,7 +181,7 @@ test-driver /cppForSwig/protobuf/*.pb.* /cppForSwig/x64/*.* CppBridge -armoryengine/ClientProto_pb2.py +armoryengine/BridgeProto_pb2.py cppForSwig/gtest/UtilsTests cppForSwig/gtest/ZeroConfTests c20p1305_cffi/c20p1305.c diff --git a/Makefile.am b/Makefile.am index cec9ba7cc..9f1816c5a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,9 +16,9 @@ copy-script: cp cppForSwig/BIP150KeyManager ./BIP150KeyManager cp cppForSwig/CppBridge ./CppBridge -# SWIG code and requirements. +# protobuf formas for python if BUILD_CLIENT - protoc --python_out=armoryengine --proto_path=cppForSwig/protobuf cppForSwig/protobuf/ClientProto.proto + protoc --python_out=$(srcdir)/armoryengine --proto_path=$(srcdir)/cppForSwig/protobuf $(srcdir)/cppForSwig/protobuf/BridgeProto.proto #TODO: build c20p1305 CFFI python lib endif diff --git a/PublicKeys/goatpig-signing-key.asc b/PublicKeys/goatpig-signing-key.asc deleted file mode 100644 index e0458ad92..000000000 --- a/PublicKeys/goatpig-signing-key.asc +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: SKS 1.1.5 - -mQINBFZRUpgBEADN/akS+sMnPqG4VigcipiLUmdQIElf2Uj1KTIgR21ifR0xT1EddPtUTIxx -eHAYZQN1yanrmtBJmR6NeF7qkROJ4mAisLzrtW/UaIj868fnQv0y+mbcVGg+NP947E8pRF36 -8cN0RJELDOrKmY2lfyZ5ueq/gC04jFHBgjYfaqEIu8sd16nAC5ir0ilNGV+FvXjP4BP3fZgh -TM4y2d69mA+VN4DKBbZce7BVl586ODKUU8flvrsAN8uDmomIF+DVjPiH/+t0KOizLy8NxoLd -zGpJOSktUQF0vhW9EwBkpGp9vVh8PUPUWjI6orjyoAGQRQvD/oZu4iZCXXNRSHouMMClo9Jo -ZlfbkplZ4EYXJZIlAYpUGoljYoWf9I4GQHCn3nqcoG7E7u6u+2+thiTQG0QxTl7VE+cnlBAs -Pg1D86WhPzWzHueAlvtwlChLCXlZifJFi7MlD3+ijg8o3V8qWMm+cwKJDR8gOvJ0AZ9t11TL -Pb15o63dQKcDd++FAc1etCazZnvPH8pjo0+0FZtd870JRkCn9N8yqxlWccCmjaS1hbgYZd1W -8T8rtKDLCW0isZzzB74SpaHiMlcQOlIz2K6WGHqb6Fr2evpzX80LjqANaGXjjEJyU7HYcT9f -fOxm7Idisj6QbW5Y9s135YYg+LR55N/P3cm2FWg09IHVZjd/FwARAQABtEtnb2F0cGlnIChP -ZmZsaW5lIHNpZ25pbmcga2V5IGZvciBBcm1vcnkgcmVsZWFzZXMpIDxtb290aGVjb3dsb3Jk -QGdtYWlsLmNvbT6JAjgEEwECACIFAlZRUpgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheA -AAoJEIxSEXZJIliadfIQAKsqhFZ3TyXsu6M0iu6TMYzXcLhRclzxF3i6gsBk2QOn0/d4AOIm -uPj1lP2BwlH2WuMuej5ZcnJ7s6xpDNi85AIO5ffq87P6PyX4uCp4mZKD/W9OGhHRBwwEwh3Y -eyN5nosDQS0kY2hRZ8nidzIk2mtyeHBgV6jZlG+g3VkzXymmQ5TNMb1syL+MrNlZPnoFdaYW -2xtwF8hBCANry9JaN+F4sKLdewysegQBodkwQyepOsPlavJ+2I3bd0qqSKGmT3rrGmVGzm5g -h3TBHFJl6LAeqrxAegRnpcOnUrxphfnlT8pg7VLkj8lns2MmaZ9t8naQBAvOcGxpLlXb7U+S -04/fxde3TjFSd1WoK0c+XxBfc1p4w47pWaQ0pgQ4d13vuO8/XmqeUXxWLnWR7Q9eNyPcEqwr -RlI5RYAjHGJsYpWvkDx3WYLWMgCD57j9vU/40YX2BPxpKhbNsngBMfToC49AHI4RDn9+Mc9P -rhAjiB+DldTO3zFuJuBMd1EMUmr479i0y5/kzZFt+Q2Kebyn8I1IVEXvrkQ4gfRiWKAhtOHQ -GvmviqGEyAhjrKYLRRJWWONbX6P1JC7/l3L3cnu6PXMGS7XuaqhJqaslpmQrS1h9cMN4uCiU -NmERgjQbbUOblzZhhGzeH5+Q0zAMTm3hJr8ZYJXGRtrAiTAUSVhjJ/eX -=+0ll ------END PGP PUBLIC KEY BLOCK----- diff --git a/PublicKeys/laanwj-releases.asc b/PublicKeys/laanwj-releases.asc deleted file mode 100755 index c5b500833..000000000 --- a/PublicKeys/laanwj-releases.asc +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 - -mQINBFWKlBcBEACgZJd/6LrSgNSVxiyq5N9h0E7zgSHG/ahuWAnWeFtxaxHeukH+ -Q2Zq6F8FLbq40PphyroRylMBpzPBcyxjee7mDj1DpJ9ayv6GGPTyQzOImhChEV8p -bA42dvXnB5ju0rPh2GxctbiZZD1kiPH4jlmDIgomvupAj9OFntA5jfkuSFBekZrw -QyZowz/paMBIe24YH2LyaZjC2DqLy8Znh78OfAZxZsWSdZxK5LsbkCE9l8Li3gQa -rxm4aEMBHhvns+s8Ufa47sdJAYAfVnAWb5Dfe4oVFh70PvB8GSGFS9qeib0eEQBD -71c9MN+REDTSOYO2VnUSFbu7IrKsPsClqwfT9KzI/uz5fpHSKdCp5AO7oDZiU36s -LsSOBbukTmFQfVrAniFEZxHLCBufXCsAwp07xtUH9ytbW0Y/eHYlZojoWJJPT//1 -cQ/A2Ix/nxbSkSPq8wpCUhBxvTQoU9BXeQIbSy0yUmj5nS+3DR7IK2Q7ACyVClr7 -LVQOGxgZhHr9Kq87RDqc1wlvbCxb+KTJQhJySpOVoiaME6jLBzgE7G+5N6IXTK5u -OriOsQwcLdeBu7TPgft79uBYnmYeaNVdovlBB//7H7UvY0kAxAg4NPgK6eYRdzn+ -8ZtbntNXi/23RJvzeZJVBqQ7bYt4fjmHmRYrbM4jWKJEoJOE6wzpmELUowARAQAB -tFVXbGFkaW1pciBKLiB2YW4gZGVyIExhYW4gKEJpdGNvaW4gQ29yZSBiaW5hcnkg -cmVsZWFzZSBzaWduaW5nIGtleSkgPGxhYW53akBnbWFpbC5jb20+iQI+BBMBAgAo -BQJVipQXAhsDBQkDFwQABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCQyAGe -NsLpZOBRD/wLfujEC4ZYMFwPXnhvOGEWAPeuOg06iXhEqJ1biOvxhFfwwjPoXGMQ -i/pdfGck5xZVFcxObpdHBp0p9ardos1aRXAS8JTnTQXTX0qs0QNxnLTBz+5DrIc4 -l7r5DAlr/FapUKNSbjobOrbv+F371b7XhLJ7oob5XXo+IS7kEY+Si5BXb0uVy8ms -SaKDooO2RfByrFI3LTHW3VESuuNnXgH6309yeGORgBazKtnxZPPlD2raTNXe9q7U -dF2Xv6Rr53iCGGN5xncL5A6nF3fou0tGvqLFBkrs4BqeNNwC6/jQLfpOfqiQ+XGR -q1KmT9E5E1qRXOb1Fc2koIUt/mSzRzxfxaEjI1UR0I4QtPsF2aP11sOJ1MJXyrEi -Kx1Nb0eUAYw0ZLTfm+uToUUTXzaB5gZqxmyY/eRFddCuGn+UwZnCiUImCWuk5yLq -ivyNbPfD1nwiZqNd879DkwFovNQfbOes4gfZyS28FXuYD/3mNN2WqGeJHZBGpglR -8EbiuJcgo7wPVC7aiIG0deSe6Flw04f2JE75zBKbzWccydtk16GzUBorbhJ4+Q7V -ikss1m4O/hDCU32t9V02+666l0ewM3H7AlTGxmWPWcaeADkywDHGb3frZU8Wh7to -e8I7ST0ap2vf11stL4Ejeyymcy2Xx1S7C57GuBSBCMJv962YIalk+4kBHAQQAQoA -BgUCVYqVFgAKCRB0gQsBI0bJpmthB/9tHtBEUuR9Ce1HBWin8AG18FDhw+019GvK -uMysu004imrPQRnH+I780W3htFBFhiZ+yhSllb4sJrW5awitIQxxe3V+xcDjyidh -32GjKDXvb4GHHuDC6uK2Hj0PB8XfqT1O1eCN3E/tn00al6qx/SvLnhW0BlqWwvVh -cJpQE5pa7E97Gw+arD1/XPy0WRX8SuEphdZ+sN1tP8yZZK8Bvi0rz+p0n5aop6Z6 -6Fj2buJnVQK6xDfXwt6/F5s7lyx1QKC4wF0MiMA8jv2KkbFEuiuiteNynrsGV7UZ -0VNvCdXe1cDKPnC64HP7nPluFRMLZbWq4DESbfGCCrmzz7f7eAEn -=mufP ------END PGP PUBLIC KEY BLOCK----- diff --git a/configure.ac b/configure.ac index 52a05e721..b6bcd7415 100644 --- a/configure.ac +++ b/configure.ac @@ -80,8 +80,8 @@ AC_CONFIG_MACRO_DIR([build-aux/m4]) m4_include([build-aux/m4/ax_check_compile_flag.m4]) m4_include([build-aux/m4/ax_cxx_compile_stdcxx.m4]) -#check for c++11 -AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault]) +#check for c++17 +AX_CXX_COMPILE_STDCXX_17([noext], [mandatory]) # Make the compilation flags quiet unless V=1 is used. m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/cppForSwig/ArmoryBackups.cpp b/cppForSwig/ArmoryBackups.cpp deleted file mode 100644 index 7f0d34459..000000000 --- a/cppForSwig/ArmoryBackups.cpp +++ /dev/null @@ -1,1188 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// // -// Copyright (C) 2020, goatpig // -// Distributed under the MIT license // -// See LICENSE-MIT or https://opensource.org/licenses/MIT // -// // -//////////////////////////////////////////////////////////////////////////////// - -#include "ArmoryBackups.h" -#include "EncryptionUtils.h" -#include "BtcUtils.h" -#include "Wallets/WalletIdTypes.h" - -constexpr uint32_t EASY16_CHECKSUM_LEN = 2; -constexpr uint32_t EASY16_INDEX_MAX = 15; -constexpr uint32_t EASY16_LINE_LENGTH = 16; - -constexpr uint32_t WALLET_RESTORE_LOOKUP = 1000; - -using namespace std; -using namespace Armory::Backups; -using namespace Armory::Assets; -using namespace Armory::Wallets; - -//////////////////////////////////////////////////////////////////////////////// -const vector BackupEasy16::e16chars_ = -{ - 'a', 's', 'd', 'f', - 'g', 'h', 'j', 'k', - 'w', 'e', 'r', 't', - 'u', 'i', 'o', 'n' -}; - -//////////////////////////////////////////////////////////////////////////////// -const set BackupEasy16::eligibleIndexes_ = -{ - (uint8_t)BackupType::Armory135, - (uint8_t)BackupType::BIP32_Seed_Structured, - (uint8_t)BackupType::BIP32_Root, - (uint8_t)BackupType::BIP32_Seed_Virgin, -}; - - -//////////////////////////////////////////////////////////////////////////////// - -/* -Nothing up my sleeve! Need some hardcoded random numbers to use for -encryption IV and salt. Using the first 256 digits of Pi for the -the IV, and first 256 digits of e for the salt (hashed) -*/ - -const string SecurePrint::digits_pi_ = -{ - "ARMORY_ENCRYPTION_INITIALIZATION_VECTOR_" - "1415926535897932384626433832795028841971693993751058209749445923" - "0781640628620899862803482534211706798214808651328230664709384460" - "9550582231725359408128481117450284102701938521105559644622948954" - "9303819644288109756659334461284756482337867831652712019091456485" -}; - -const string SecurePrint::digits_e_ = -{ - "ARMORY_KEY_DERIVATION_FUNCTION_SALT_" - "7182818284590452353602874713526624977572470936999595749669676277" - "2407663035354759457138217852516642742746639193200305992181741359" - "6629043572900334295260595630738132328627943490763233829880753195" - "2510190115738341879307021540891499348841675092447614606680822648" -}; - -const uint32_t SecurePrint::kdfBytes_ = 16 * 1024 * 1024; - -//////////////////////////////////////////////////////////////////////////////// -//// -//// BackupEasy16 -//// -//////////////////////////////////////////////////////////////////////////////// -BinaryData BackupEasy16::getHash(const BinaryDataRef& data, uint8_t hint) -{ - if (hint == 0) - { - return BtcUtils::getHash256(data); - } - else - { - SecureBinaryData dataCopy(data.getSize() + 1); - memcpy(dataCopy.getPtr(), data.getPtr(), data.getSize()); - dataCopy.getPtr()[data.getSize()] = hint; - - return BtcUtils::getHash256(dataCopy); - } -} - -//////////////////////////////////////////////////////////////////////////////// -uint8_t BackupEasy16::verifyChecksum( - const BinaryDataRef& data, const BinaryDataRef& checksum) -{ - for (const auto& indexCandidate : eligibleIndexes_) - { - auto hash = getHash(data, indexCandidate); - if (hash.getSliceRef(0, EASY16_CHECKSUM_LEN) == checksum) - return indexCandidate; - } - - return EASY16_INVALID_CHECKSUM_INDEX; -} - -//////////////////////////////////////////////////////////////////////////////// -vector BackupEasy16::encode(const BinaryDataRef data, uint8_t index) -{ - if (index > EASY16_INDEX_MAX) - { - LOGERR << "index is too large"; - throw runtime_error("index is too large"); - } - - auto encodeByte = [](stringstream& ss, uint8_t c)->void - { - uint8_t val1 = c >> 4; - uint8_t val2 = c & 0x0F; - ss << e16chars_[val1] << e16chars_[val2]; - }; - - auto encodeValue = [&encodeByte, &index]( - const BinaryDataRef& chunk16)->string - { - //get hash - auto h256 = getHash(chunk16, index); - - //encode the chunk - stringstream ss; - unsigned charCount = 0; - auto ptr = chunk16.getPtr(); - for (unsigned i=0; i result; - BinaryRefReader brr(data); - - uint32_t count = - ((uint32_t)data.getSize() + EASY16_LINE_LENGTH - 1) / EASY16_LINE_LENGTH; - for (unsigned i=0; i& lines) -{ - vector refVec; - for (const auto& line : lines) - refVec.emplace_back((const uint8_t*)line.c_str(), line.size()); - - return decode(refVec); -} - -//////////////////////////////////////////////////////////////////////////////// -BackupEasy16DecodeResult BackupEasy16::decode(const vector& lines) -{ - if (lines.size() == 0) - throw runtime_error("empty easy16 code"); - - //setup character to value lookup map - map easy16Vals; - for (unsigned i=0; ibool - { - if (str[0] == ' ') - return false; - - return true; - }; - - auto decodeCharacters = [&easy16Vals]( - uint8_t& result, const char* str)->void - { - //convert characters to value, ignore effect of invalid ones - result = 0; - auto iter1 = easy16Vals.find(str[0]); - if (iter1 != easy16Vals.end()) - result = iter1->second << 4; - - auto iter2 = easy16Vals.find(str[1]); - if (iter2 != easy16Vals.end()) - result += iter2->second; - }; - - /* - Converts line to binary, appends into result. - Returns the hash index matching the checksum. - - Error values: - . -1: checksum mismatch - . -2: invalid checksum data - . -3: not enough room in the result buffer - */ - auto decodeLine = [&checkSpace, &decodeCharacters]( - uint8_t* result, size_t& len, - const BinaryDataRef& line, BinaryData& checksum)->int - { - auto maxlen = len; - len = 0; - auto ptr = line.toCharPtr(); - - unsigned i=0; - for (; i= maxlen) - return -3; - - decodeCharacters(result[len], ptr + i); - - //increment result length - ++len; - - //increment i to skip 2 characters - ++i; - } - - //grab checksum - checksum.resize(EASY16_CHECKSUM_LEN); - uint8_t* checksumPtr = checksum.getPtr(); - size_t checksumLen = 0; - for (; i= EASY16_CHECKSUM_LEN) - return -2; - - decodeCharacters(*(checksumPtr + checksumLen), ptr + i); - ++checksumLen; - ++i; - } - - if (checksumLen != EASY16_CHECKSUM_LEN) - return -2; - - //hash data - BinaryDataRef decodedChunk(result, len); - return verifyChecksum(decodedChunk, checksum); - }; - - size_t fullSize = lines.size() * EASY16_LINE_LENGTH; - SecureBinaryData data(fullSize); - vector checksumIndexes; - vector checksums(lines.size()); - - auto dataPtr = data.getPtr(); - size_t pos = 0; - for (unsigned i=0; i EASY16_LINE_LENGTH) - { - throw runtime_error("easy16 line is too long"); - } - else if (len < EASY16_LINE_LENGTH) - { - if (i != lines.size() - 1) - throw runtime_error("easy16 line is too short"); - - //last line doesn't have to be EASY16_LINE_LENGTH bytes long - data.resize(pos); - } - } - - BackupEasy16DecodeResult result; - result.checksumIndexes_ = move(checksumIndexes); - result.checksums_ = move(checksums); - result.data_ = move(data); - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -bool BackupEasy16::repair(BackupEasy16DecodeResult& faultyBackup) -{ - //sanity check - if (faultyBackup.data_.empty() || faultyBackup.checksums_.empty() || - faultyBackup.checksums_.size() != faultyBackup.checksumIndexes_.size()) - { - throw Easy16RepairError("invalid arugments"); - } - - //is there an error? - bool hasError = false; - set validIndexes; - for (auto index : faultyBackup.checksumIndexes_) - { - auto indexIter = eligibleIndexes_.find(index); - if (indexIter == eligibleIndexes_.end()) - { - if (index == EASY16_INVALID_CHECKSUM_INDEX) - { - hasError = true; - continue; - } - else - { - //these errors cannot be repaired - throw Easy16RepairError("fatal checksum error"); - } - } - - validIndexes.insert(index); - } - - if (!hasError && validIndexes.size() == 1) - return true; - - /* checksum search function */ - auto searchChecksum = []( - const BinaryDataRef& data, const BinaryData& checksum, uint8_t hint) - ->map>> - { - map>> result; - - //copy the data - SecureBinaryData copied(data); - - //run through each byte of data - for (unsigned i=0; i 1) - { - //there's more than one checksum index, cannot proceed - throw Easy16RepairError("checksum results mismatch"); - } - else if (validIndexes.size() == 1) - { - /* - Some lines are invalid but we have at least one that is valid. This - allows us to search for the expected checksum index in the invalid - lines (they should all match) - */ - unsigned hint = *validIndexes.begin(); - - BinaryRefReader brr(faultyBackup.data_); - for (unsigned i=0; isecond.size() != 1) - return false; - - const auto& repairPair = *repairIter->second.begin(); - if (repairPair.second.size() != 1) - return false; - - //apply repair on the fly - auto ptr = (uint8_t*)(dataRef.getPtr() + repairPair.first); - *ptr = *repairPair.second.begin(); - - //update the repaired line checksum result - faultyBackup.repairedIndexes_.push_back(hint); - } - } - else - { - /* - All lines are invalid. There is no indication of what the checksum index - ought to be. We have to search all lines for a matching index. - */ - vector>>> resultMap; - - BinaryRefReader brr(faultyBackup.data_); - for (unsigned i=0; i> chksumIndexes; - for (unsigned i=0; isecond.size() != 1) - continue; - - auto& chkValueSet = chksumIndexes[lineData.first]; - chkValueSet.insert(i); - } - } - - //only those indexes represented across all lines are eligible - auto iter = chksumIndexes.begin(); - while (iter != chksumIndexes.end()) - { - if (iter->second.size() != faultyBackup.checksumIndexes_.size()) - { - chksumIndexes.erase(iter++); - continue; - } - - ++iter; - } - - //fail if we have several repair candidates - if (chksumIndexes.size() != 1) - return false; - - //repair the data - brr.resetPosition(); - auto repairIndex = chksumIndexes.begin()->first; - for (unsigned i=0; isecond.size() != 1) - return false; - - auto valIter = lineIter->second.begin(); - if (valIter->second.size() != 1) - return false; - - auto dataRef = brr.get_BinaryDataRef( - std::min(EASY16_LINE_LENGTH, (uint32_t)brr.getSizeRemaining())); - - auto ptr = (uint8_t*)(dataRef.getPtr() + valIter->first); - *ptr = *valIter->second.begin(); - - //update the repaired line checksum result - faultyBackup.repairedIndexes_.push_back(repairIndex); - } - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -//// -//// SecurePrint -//// -//////////////////////////////////////////////////////////////////////////////// -SecurePrint::SecurePrint() -{ - //setup aes IV and kdf - auto iv32 = BtcUtils::getHash256( - (const uint8_t*)digits_pi_.c_str(), (uint32_t)digits_pi_.size()); - iv16_ = move(iv32.getSliceCopy(0, AES_BLOCK_SIZE)); - - salt_ = move(BtcUtils::getHash256( - (const uint8_t*)digits_e_.c_str(), (uint32_t)digits_e_.size())); - kdf_.usePrecomputedKdfParams(kdfBytes_, 1, salt_); -} - -//////////////////////////////////////////////////////////////////////////////// -pair SecurePrint::encrypt( - const SecureBinaryData& root, const SecureBinaryData& chaincode) -{ - /* - 1. generate passphrase from root and chaincode - */ - - //sanity check - if (root.getSize() != 32) - { - LOGERR << "invalid root size for secureprint"; - throw runtime_error("invalid root size for secureprint"); - } - - SecureBinaryData hmacPhrase(64); - if (chaincode.empty()) - { - /* - The passphrase is the hmac of the root and the chaincode. If the - chaincode is empty, we only hmac the root. - */ - - auto rootHash = BtcUtils::getHash256(root); - BtcUtils::getHMAC512( - rootHash.getPtr(), rootHash.getSize(), - salt_.getPtr(), salt_.getSize(), - hmacPhrase.getPtr()); - } - else - { - /* - Concatenate root and chaincode then hmac - */ - - SecureBinaryData rootCopy = root; - rootCopy.append(chaincode); - - auto rootHash = BtcUtils::getHash256(rootCopy); - BtcUtils::getHMAC512( - rootHash.getPtr(), rootHash.getSize(), - salt_.getPtr(), salt_.getSize(), - hmacPhrase.getPtr()); - } - - //passphrase is first 7 bytes of the hmac - BinaryWriter bw; - bw.put_BinaryDataRef(hmacPhrase.getSliceRef(0, 7)); - auto passChecksum = BtcUtils::getHash256(bw.getData()); - bw.put_uint8_t(passChecksum[0]); - - passphrase_ = SecureBinaryData::fromString( - BtcUtils::base58_encode(bw.getData())); - - /* - 2. extend the passphrase - */ - - auto encryptionKey = kdf_.DeriveKey(passphrase_); - - /* - 3. Encrypt the data. We use the libbtc call directly because - we do not want padding - */ - - auto encrypt = [this, &encryptionKey]( - const SecureBinaryData& cleartext, SecureBinaryData& result)->bool - { - //this exclusively encrypt 32 bytes of data - if (cleartext.getSize() != 32) - return false; - - //make sure result buffer is large enough - result.resize(32); - - //encrypt with CBC - auto encrLen = aes256_cbc_encrypt( - encryptionKey.getPtr(), iv16_.getPtr(), - cleartext.getPtr(), (int)cleartext.getSize(), - 0, //no padding - result.getPtr()); - - if (encrLen != 32) - return false; - - return true; - }; - - pair result; - if (!encrypt(root, result.first)) - { - LOGERR << "SecurePrint encryption failure"; - throw runtime_error("SecurePrint encryption failure"); - } - - if (!chaincode.empty()) - { - if (!encrypt(chaincode, result.second)) - { - LOGERR << "SecurePrint encryption failure"; - throw runtime_error("SecurePrint encryption failure"); - } - } - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -SecureBinaryData SecurePrint::decrypt( - const SecureBinaryData& ciphertext, const BinaryDataRef passphrase) const -{ - //check passphrase checksum - string passStr(passphrase.toCharPtr(), passphrase.getSize()); - BinaryData passBin; - try - { - passBin = move(BtcUtils::base58_decode(passStr)); - } - catch (const exception&) - { - LOGERR << "invalid SecurePrint passphrase"; - throw runtime_error("invalid SecurePrint passphrase"); - } - - if (passBin.getSize() != 8) - { - LOGERR << "invalid SecurePrint passphrase"; - throw runtime_error("invalid SecurePrint passphrase"); - } - - BinaryRefReader brr(passBin); - auto passBase = brr.get_BinaryDataRef(7); - auto checksum = brr.get_uint8_t(); - - auto passHash = BtcUtils::getHash256(passBase); - if (passHash[0] != checksum) - { - LOGERR << "invalid SecurePrint passphrase"; - throw runtime_error("invalid SecurePrint passphrase"); - } - - if (ciphertext.getSize() < 32) - { - LOGERR << "invalid ciphertext size for SecurePrint"; - throw runtime_error("invalid ciphertext size for SecurePrint"); - } - - //kdf the passphrase - auto encryptionKey = kdf_.DeriveKey(passphrase); - - // - auto decrypt = [this, &encryptionKey]( - const BinaryDataRef& ciphertext, SecureBinaryData& result)->bool - { - //works exclusively on 32 byte packets - if (ciphertext.getSize() != 32) - return false; - - result.resize(32); - - auto size = aes256_cbc_decrypt( - encryptionKey.getPtr(), iv16_.getPtr(), - ciphertext.getPtr(), (int)ciphertext.getSize(), - 0, //no padding - result.getPtr()); - - if (size != 32) - return false; - - return true; - }; - - //decrypt the root - SecureBinaryData result; - if (!decrypt(ciphertext, result)) - { - LOGERR << "failed to decrypt SecurePrint string"; - throw runtime_error("failed to decrypt SecurePrint string"); - } - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -//// -//// Helpers -//// -//////////////////////////////////////////////////////////////////////////////// -WalletRootData Helpers::getRootData( - shared_ptr wltSingle) -{ - WalletRootData rootData; - rootData.wltId_ = wltSingle->getID(); - auto root = dynamic_pointer_cast( - wltSingle->getRoot()); - - //lock wallet - auto lock = wltSingle->lockDecryptedContainer(); - - //check root - auto rootBip32 = dynamic_pointer_cast(root); - if (rootBip32 == nullptr) - { - /* - This isn't a bip32 root, therefor it's an Armory root. It may carry a - dedicated chaincode, let's check for that. - */ - - auto root135 = dynamic_pointer_cast(root); - if (root135 == nullptr) - { - LOGERR << "unexpected wallet root type"; - throw runtime_error("unexpected wallet root type"); - } - - rootData.root_ = wltSingle->getDecryptedPrivateKeyForAsset(root); - rootData.type_ = BackupType::Armory135; - - const auto& wltChaincode = root135->getChaincode(); - if (!wltChaincode.empty()) - { - /* - If the root carries a chaincode, it may be non deterministic. Let's - check. - */ - - auto computedChaincode = - BtcUtils::computeChainCode_Armory135(rootData.root_); - - if (computedChaincode != wltChaincode) - rootData.secondaryData_ = wltChaincode; - } - } - else - { - //bip32 wallet, grab the seed instead - auto seedPtr = wltSingle->getEncryptedSeed(); - if (seedPtr == nullptr) - { - /* - For now, abort if bip32 wallet is missing its seed. May implement - root backups for bip32 wallets (privkey + chaincode) in the future. - */ - rootData.type_ = BackupType::BIP32_Root; - return rootData; - } - - rootData.type_ = BackupType::BIP32_Seed_Structured; - - //decrypt the seed - rootData.root_ = wltSingle->getDecryptedValue(seedPtr); - } - - return rootData; -} - -//////////////////////////////////////////////////////////////////////////////// -WalletRootData Helpers::getRootData_Multisig( - shared_ptr) -{ - throw runtime_error("TODO: needs implementation"); -} - -//////////////////////////////////////////////////////////////////////////////// -WalletBackup Helpers::getWalletBackup( - std::shared_ptr wltPtr, BackupType type) -{ - auto rootData = getRootData(wltPtr); - return getWalletBackup(rootData, type); -} - -//////////////////////////////////////////////////////////////////////////////// -WalletBackup Helpers::getWalletBackup(WalletRootData& rootData, - BackupType forceBackupType) -{ - //apply secureprint - SecurePrint sp; - auto encrRoot = sp.encrypt(rootData.root_, rootData.secondaryData_); - - WalletBackup backup; - - if (forceBackupType != BackupType::Invalid) - rootData.type_ = forceBackupType; - - unsigned mode = UINT32_MAX; - switch (rootData.type_) - { - case BackupType::Armory135: - case BackupType::BIP32_Seed_Structured: - case BackupType::BIP32_Root: - case BackupType::BIP32_Seed_Virgin: - { - mode = unsigned(rootData.type_); - break; - } - - default: - break; - } - - if (mode == UINT32_MAX) - { - LOGERR << "cannot create backup for unknown wallet type"; - throw runtime_error("cannot create backup for unknown wallet type"); - } - - //cleartext root easy16 - backup.rootClear_ = move(BackupEasy16::encode(rootData.root_, mode)); - - //encrypted root easy16 - backup.rootEncr_ = move(BackupEasy16::encode(encrRoot.first,mode)); - - if (!rootData.secondaryData_.empty()) - { - //cleartext chaincode easy16 - backup.chaincodeClear_ = move(BackupEasy16::encode( - rootData.secondaryData_, mode)); - - //encrypted chaincode easy16 - backup.chaincodeEncr_ = move(BackupEasy16::encode( - encrRoot.second, mode)); - } - - backup.spPass_ = sp.getPassphrase(); - backup.wltId_ = rootData.wltId_; - - return backup; -} - -//////////////////////////////////////////////////////////////////////////////// -shared_ptr Helpers::restoreFromBackup( - const vector& data, const BinaryDataRef passphrase, - const string& homedir, const UserPrompt& callerPrompt) -{ - vector bdrVec; - for (const auto& str : data) - bdrVec.emplace_back((const uint8_t*)str.c_str(), str.size()); - - return restoreFromBackup(bdrVec, passphrase, homedir, callerPrompt); -} - -//////////////////////////////////////////////////////////////////////////////// -shared_ptr Helpers::restoreFromBackup( - const vector& data, const BinaryDataRef passphrase, - const string& homedir, const UserPrompt& callerPrompt) -{ - SecureBinaryData promptDummy; - bool hasSecondaryData = false; - - //decode the data - BackupEasy16DecodeResult primaryData, secondaryData; - if (data.size() == 2) - { - primaryData = BackupEasy16::decode(data); - } - else if (data.size() > 2) - { - vector primarySlice; - primarySlice.insert(primarySlice.end(), data.begin(), data.begin() + 2); - primaryData = BackupEasy16::decode(primarySlice); - - vector secondarySlice; - secondarySlice.insert(secondarySlice.end(), data.begin() + 2, data.end()); - secondaryData = BackupEasy16::decode(secondarySlice); - - hasSecondaryData = true; - } - else - { - callerPrompt(RestorePromptType::FormatError, {}, promptDummy); - return nullptr; - } - - if (primaryData.checksumIndexes_.empty() || - (hasSecondaryData && secondaryData.checksumIndexes_.empty())) - { - callerPrompt(RestorePromptType::Failure, {}, promptDummy); - return nullptr; - } - - //sanity check - auto checksumIndexes = primaryData.checksumIndexes_; - if (hasSecondaryData) - { - checksumIndexes.insert(checksumIndexes.end(), - secondaryData.checksumIndexes_.begin(), - secondaryData.checksumIndexes_.end()); - } - - bool checksumErrors; - int firstIndex; - - auto processChecksumIndexes = [&checksumErrors, &firstIndex]( - const vector& checksumValues) - { - /* - Set the common checksum result value and make sure all lines - carry the same value. - */ - - checksumErrors = false; - firstIndex = checksumValues[0]; - for (const auto& result : checksumValues) - { - if (result < 0 || result != firstIndex) - { - checksumErrors = true; - break; - } - } - }; - processChecksumIndexes(checksumIndexes); - - if (checksumErrors) - { - auto reportError = [&callerPrompt, &checksumIndexes](void) - { - //prompt caller if we can't repair the error and throw - SecureBinaryData dummy; - callerPrompt( - RestorePromptType::ChecksumError, checksumIndexes, dummy); - throw RestoreUserException("checksum error"); - }; - - vector repairedIndexes; - - auto repairData = [&reportError, &repairedIndexes]( - BackupEasy16DecodeResult& data) - { - //attempt to repair the data - auto result = BackupEasy16::repair(data); - if (!result) - reportError(); - - if (data.repairedIndexes_.size() != - data.checksumIndexes_.size()) - reportError(); - - repairedIndexes.insert(repairedIndexes.end(), - data.repairedIndexes_.begin(), - data.repairedIndexes_.end()); - }; - - //found some checksum errors, attempt to auto repair - repairData(primaryData); - if (hasSecondaryData) - repairData(secondaryData); - - //check the repaired checksum result values - processChecksumIndexes(repairedIndexes); - - if (checksumErrors) - reportError(); - } - - //check for encryption - if (!passphrase.empty()) - { - try - { - SecurePrint sp; - auto decryptedData = sp.decrypt(primaryData.data_, passphrase); - primaryData.data_ = move(decryptedData); - - if (hasSecondaryData) - { - auto decryptedData = sp.decrypt(secondaryData.data_, passphrase); - secondaryData.data_ = move(decryptedData); - } - } - catch (const exception&) - { - //prompt caller on decrypt error and return - callerPrompt(RestorePromptType::DecryptError, {}, promptDummy); - throw RestoreUserException("invalid SP pass"); - } - } - - auto computeWalletId = []( - const SecureBinaryData& root, const SecureBinaryData& chaincode) - ->string - { - auto chaincodeCopy = chaincode; - if (chaincodeCopy.empty()) - chaincodeCopy = BtcUtils::computeChainCode_Armory135(root); - - auto derScheme = - make_shared(chaincodeCopy); - - auto pubkey = CryptoECDSA().ComputePublicKey(root); - auto asset_single = make_shared( - Armory::Wallets::AssetId::getRootAssetId(), pubkey, nullptr); - - return AssetWallet_Single::computeWalletID(derScheme, asset_single); - }; - - auto promptForPassphrase = [&callerPrompt]( - SecureBinaryData& passphrase, SecureBinaryData& control)->bool - { - //prompt for wallet passphrase - if (!callerPrompt(RestorePromptType::Passphrase, {}, passphrase)) - return false; - - //prompt for control passphrase - if (!callerPrompt(RestorePromptType::Control, {}, control)) - return false; - - return true; - }; - - //generate wallet - shared_ptr wallet; - switch (firstIndex) - { - case BackupType::Armory135: - { - /*legacy armory wallet*/ - - auto id = SecureBinaryData::fromString( - computeWalletId(primaryData.data_, secondaryData.data_)); - if (!callerPrompt(RestorePromptType::Id, checksumIndexes, id)) - throw RestoreUserException("user rejected id"); - - //prompt for passwords - SecureBinaryData pass, control; - if (!promptForPassphrase(pass, control)) - throw RestoreUserException("user did not provide passphrase"); - - //create wallet - wallet = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir, - primaryData.data_, - secondaryData.data_, - pass, control, - WALLET_RESTORE_LOOKUP); - - break; - } - - //bip32 wallets - case BackupType::BIP32_Seed_Structured: - { - /*BIP32 wallet with BIP44/49/84 accounts*/ - - //create root node from seed - BIP32_Node rootNode; - rootNode.initFromSeed(primaryData.data_); - - //compute id and present to caller - auto id = SecureBinaryData::fromString( - computeWalletId(rootNode.getPrivateKey(), rootNode.getChaincode())); - if (!callerPrompt(RestorePromptType::Id, checksumIndexes, id)) - throw RestoreUserException("user rejected id"); - - //prompt for passwords - SecureBinaryData pass, control; - if (!promptForPassphrase(pass, control)) - throw RestoreUserException("user did not provide passphrase"); - - //create wallet - wallet = AssetWallet_Single::createFromSeed_BIP32( - homedir, - primaryData.data_, - pass, control, - WALLET_RESTORE_LOOKUP); - - break; - } - - case BIP32_Seed_Virgin: - { - /*empty BIP32 wallet*/ - - //create root node from seed - BIP32_Node rootNode; - rootNode.initFromSeed(primaryData.data_); - - //compute id and present to caller - auto id = SecureBinaryData::fromString( - computeWalletId(rootNode.getPrivateKey(), rootNode.getChaincode())); - if (!callerPrompt(RestorePromptType::Id, checksumIndexes, id)) - throw RestoreUserException("user rejected id"); - - //prompt for passwords - SecureBinaryData pass, control; - if (!promptForPassphrase(pass, control)) - throw RestoreUserException("user did not provide passphrase"); - - //create wallet - wallet = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir, - primaryData.data_, - pass, control); - - break; - } - - //case BackupType::BIP32_Root: - - default: - callerPrompt(RestorePromptType::TypeError, {}, promptDummy); - } - - return wallet; -} \ No newline at end of file diff --git a/cppForSwig/ArmoryBackups.h b/cppForSwig/ArmoryBackups.h deleted file mode 100644 index 9140dce32..000000000 --- a/cppForSwig/ArmoryBackups.h +++ /dev/null @@ -1,228 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// // -// Copyright (C) 2020, goatpig // -// Distributed under the MIT license // -// See LICENSE-MIT or https://opensource.org/licenses/MIT // -// // -//////////////////////////////////////////////////////////////////////////////// - -#ifndef _SECURE_PRINT_H -#define _SECURE_PRINT_H - -#include -#include -#include "SecureBinaryData.h" -#include "EncryptionUtils.h" - -#include "Wallets.h" - -#define EASY16_INVALID_CHECKSUM_INDEX UINT8_MAX - -namespace Armory -{ - namespace Backups - { - //// - class RestoreUserException : public std::runtime_error - { - public: - RestoreUserException(const std::string& errMsg) : - std::runtime_error(errMsg) - {} - }; - - class Easy16RepairError : public std::runtime_error - { - public: - Easy16RepairError(const std::string& errMsg) : - std::runtime_error(errMsg) - {} - }; - - //// - enum BackupType - { - /* - Armory135: - For wallets using the Armory specific derivation scheme. - */ - Armory135 = 0, - - /* - BIP32_Seed_Structured: - For wallets carrying BIP44/49/84 accounts. Restores to a bip32 wallet - with all these accounts. - */ - BIP32_Seed_Structured = 1, - - /* - BIP32_Root: - For bip32 wallets that do not carry their own seed. Support for this is - not implemented at the moment. This type of backup would have to carry - the root privkey and chaincode generated through the seed's hmac. - - May implement support in the future. - */ - BIP32_Root = 2, - - /* - BIP32_Seed_Virgin: - No info is provided about the wallet's structure, restores to an empt - bip32 wallet. - */ - BIP32_Seed_Virgin = 15, - - /* - Default marker value. - */ - Invalid = UINT32_MAX - }; - - //// - struct WalletRootData - { - SecureBinaryData root_; - SecureBinaryData secondaryData_; - - BackupType type_; - std::string wltId_; - }; - - //// - struct BackupEasy16DecodeResult - { - std::vector checksumIndexes_; - std::vector repairedIndexes_; - std::vector checksums_; - SecureBinaryData data_; - }; - - //// - struct BackupEasy16 - { - public: - /*** - Checksum indexes are an byte appended to the 16 byte line that is passed - through the hash256 function to generate the checksum. That byte value - designates the type of wallet this backup was generated from. - - For index 0 (Armory 1.35 wallets), the byte is not appended. - The indexes for each line in a multiple line easy16 code need to match - one another. - ***/ - - static const std::set eligibleIndexes_; - - private: - static BinaryData getHash(const BinaryDataRef&, uint8_t); - static uint8_t verifyChecksum(const BinaryDataRef&, const BinaryDataRef&); - - public: - const static std::vector e16chars_; - - static std::vector encode(const BinaryDataRef, uint8_t); - static BackupEasy16DecodeResult decode(const std::vector&); - static BackupEasy16DecodeResult decode(const std::vector&); - static bool repair(BackupEasy16DecodeResult&); - }; - - //// - class SecurePrint - { - private: - const static std::string digits_pi_; - const static std::string digits_e_; - const static uint32_t kdfBytes_; - - BinaryData iv16_; - BinaryData salt_; - mutable KdfRomix kdf_; - - SecureBinaryData passphrase_; - - public: - SecurePrint(void); - - std::pair encrypt( - const SecureBinaryData&, const SecureBinaryData&); - SecureBinaryData decrypt( - const SecureBinaryData&, const BinaryDataRef) const; - - const SecureBinaryData& getPassphrase(void) const { return passphrase_; } - }; - - //// - struct WalletBackup - { - std::vector rootClear_; - std::vector chaincodeClear_; - - std::vector rootEncr_; - std::vector chaincodeEncr_; - - SecureBinaryData spPass_; - std::string wltId_; - }; - - //// - enum RestorePromptType - { - //invalid backup format - FormatError = 1, - - //failed to decode backup string - Failure = 2, - - ChecksumError = 3, - - //failed to decrypt secure print string - DecryptError = 4, - - //requesting wallet's new passphrase - Passphrase = 5, - - //requesting wallet's new control passphrase - Control = 6, - - //present restored wallet's id - Id = 7, - - //unknown wallet type - TypeError = 8, - }; - - //// - struct Helpers - { - using UserPrompt = std::function&, - SecureBinaryData&)>; - - //getting root data from wallets - static WalletRootData getRootData( - std::shared_ptr); - static WalletRootData getRootData_Multisig( - std::shared_ptr); - - //backup methods - static WalletBackup getWalletBackup( - std::shared_ptr, - BackupType bType = BackupType::Invalid); - - static WalletBackup getWalletBackup( - WalletRootData&, - BackupType bType = BackupType::Invalid); - - //restore methods - static std::shared_ptr restoreFromBackup( - const std::vector&, const BinaryDataRef, - const std::string&, const UserPrompt&); - - static std::shared_ptr restoreFromBackup( - const std::vector&, const BinaryDataRef, - const std::string&, const UserPrompt&); - }; - }; //namespace Backups -}; //namespace Armory -#endif diff --git a/cppForSwig/ArmoryConfig.cpp b/cppForSwig/ArmoryConfig.cpp index b3e7ed359..8a53e2aa2 100755 --- a/cppForSwig/ArmoryConfig.cpp +++ b/cppForSwig/ArmoryConfig.cpp @@ -131,6 +131,7 @@ const string& Armory::Config::getDataDir() void Armory::Config::parseArgs(int argc, char* argv[], ProcessType procType) { vector lines; + lines.reserve(argc); for (int i=1; i& args) @@ -537,6 +539,10 @@ void DBSettings::processArgs(const map& args) if (iter != args.end()) clearMempool_ = true; + iter = args.find("check-txhints"); + if (iter != args.end()) + checkTxHints_ = true; + //db type iter = args.find("db-type"); if (iter != args.end()) @@ -1052,7 +1058,7 @@ void Pathing::processArgs(const map& args, ProcessType procType) return; } - //create dbdir if was set automatically + //create dbdir if set automatically if (autoDbDir) { if (!testPath(dbDir_, 0)) @@ -1068,8 +1074,7 @@ void Pathing::processArgs(const map& args, ProcessType procType) //now for the regular test, let it throw if it fails if (!testPath(dbDir_, 6)) { - string errMsg = Armory::Config::getDataDir() + - " is not a valid db path"; + string errMsg = dbDir_ + " is not a valid db path"; throw DbErrorMsg(errMsg); } @@ -1082,8 +1087,7 @@ void Pathing::processArgs(const map& args, ProcessType procType) { if (!testPath(blkFilePath_, 2)) { - string errMsg = Armory::Config::getDataDir() + - " is not a valid blockchain data path"; + string errMsg = blkFilePath_ + " is not a valid blockchain data path"; throw DbErrorMsg(errMsg); } } diff --git a/cppForSwig/ArmoryConfig.h b/cppForSwig/ArmoryConfig.h index ae4942cee..9fdb11089 100755 --- a/cppForSwig/ArmoryConfig.h +++ b/cppForSwig/ArmoryConfig.h @@ -126,6 +126,7 @@ namespace Armory static bool reportProgress_; static bool checkChain_; static bool clearMempool_; + static bool checkTxHints_; private: static void processArgs(const std::map&); @@ -158,6 +159,7 @@ namespace Armory static BDM_INIT_MODE initMode(void) { return initMode_; } static bool clearMempool(void) { return clearMempool_; } static bool reportProgress(void) { return reportProgress_; } + static bool checkTxHints(void) { return checkTxHints_; } }; ////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/AsyncClient.cpp b/cppForSwig/AsyncClient.cpp index a019b0f12..1ea64b41b 100755 --- a/cppForSwig/AsyncClient.cpp +++ b/cppForSwig/AsyncClient.cpp @@ -10,13 +10,17 @@ #include "AsyncClient.h" #include "EncryptionUtils.h" #include "BDVCodec.h" +#ifdef BUILD_PROTOBUF #include "google/protobuf/io/zero_copy_stream_impl_lite.h" #include "google/protobuf/text_format.h" +#endif #include "ArmoryErrors.h" using namespace std; using namespace AsyncClient; +#ifdef BUILD_PROTOBUF using namespace Codec_BDVCommand; +#endif using namespace DBClientClasses; /////////////////////////////////////////////////////////////////////////////// @@ -24,6 +28,7 @@ using namespace DBClientClasses; // BlockDataViewer // /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF unique_ptr BlockDataViewer::make_payload(Methods method) { auto payload = make_unique(); @@ -45,6 +50,7 @@ unique_ptr BlockDataViewer::make_payload( payload->message_ = move(message); return payload; } +#endif /////////////////////////////////////////////////////////////////////////////// bool BlockDataViewer::hasRemoteDB(void) @@ -100,10 +106,11 @@ void BlockDataViewer::registerWithDB(BinaryData magic_word) //get bdvID try { +#ifdef BUILD_PROTOBUF auto payload = make_payload(StaticMethods::registerBDV); auto command = dynamic_cast(payload->message_.get()); command->set_magicword(magic_word.getPtr(), magic_word.getSize()); - +#endif //registration is always blocking as it needs to guarantee the bdvID auto promPtr = make_shared>(); @@ -124,8 +131,9 @@ void BlockDataViewer::registerWithDB(BinaryData magic_word) auto read_payload = make_shared(); read_payload->callbackReturn_ = make_unique(getResult); +#ifdef BUILD_PROTOBUF sock_->pushPayload(move(payload), read_payload); - +#endif bdvID_ = move(fut.get()); } catch (runtime_error &e) @@ -150,16 +158,19 @@ void BlockDataViewer::unregisterFromDB() sockws->shutdown(); return; } - +#ifdef BUILD_PROTOBUF auto payload = make_payload(StaticMethods::unregisterBDV); sock_->pushPayload(move(payload), nullptr); +#endif } /////////////////////////////////////////////////////////////////////////////// void BlockDataViewer::goOnline() { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::goOnline); sock_->pushPayload(move(payload), nullptr); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -182,6 +193,7 @@ BlockDataViewer::~BlockDataViewer() /////////////////////////////////////////////////////////////////////////////// void BlockDataViewer::shutdown(const string& cookie) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(StaticMethods::shutdown); auto command = dynamic_cast(payload->message_.get()); @@ -189,11 +201,13 @@ void BlockDataViewer::shutdown(const string& cookie) command->set_cookie(cookie); sock_->pushPayload(move(payload), nullptr); +#endif } /////////////////////////////////////////////////////////////////////////////// void BlockDataViewer::shutdownNode(const string& cookie) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(StaticMethods::shutdownNode); auto command = dynamic_cast(payload->message_.get()); @@ -201,6 +215,7 @@ void BlockDataViewer::shutdownNode(const string& cookie) command->set_cookie(cookie); sock_->pushPayload(move(payload), nullptr); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -219,22 +234,26 @@ Lockbox BlockDataViewer::instantiateLockbox(const string& id) void BlockDataViewer::getLedgerDelegateForWallets( function)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getLedgerDelegateForWallets); auto read_payload = make_shared(); read_payload->callbackReturn_ = make_unique(sock_, bdvID_, callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void BlockDataViewer::getLedgerDelegateForLockboxes( function)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getLedgerDelegateForLockboxes); auto read_payload = make_shared(); read_payload->callbackReturn_ = make_unique(sock_, bdvID_, callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -248,7 +267,7 @@ string BlockDataViewer::broadcastZC(const BinaryData& rawTx) { auto tx = make_shared(rawTx); cache_->insertTx(tx); - +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::broadcastZC); auto command = dynamic_cast(payload->message_.get()); command->add_bindata(rawTx.getPtr(), rawTx.getSize()); @@ -259,11 +278,15 @@ string BlockDataViewer::broadcastZC(const BinaryData& rawTx) sock_->pushPayload(move(payload), nullptr); return broadcastId; +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// string BlockDataViewer::broadcastZC(const vector& rawTxVec) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::broadcastZC); auto command = dynamic_cast(payload->message_.get()); @@ -281,6 +304,9 @@ string BlockDataViewer::broadcastZC(const vector& rawTxVec) sock_->pushPayload(move(payload), nullptr); return broadcastId; +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -288,7 +314,7 @@ string BlockDataViewer::broadcastThroughRPC(const BinaryData& rawTx) { auto tx = make_shared(rawTx); cache_->insertTx(tx); - +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::broadcastThroughRPC); auto command = dynamic_cast(payload->message_.get()); command->add_bindata(rawTx.getPtr(), rawTx.getSize()); @@ -299,6 +325,9 @@ string BlockDataViewer::broadcastThroughRPC(const BinaryData& rawTx) sock_->pushPayload(move(payload), nullptr); return broadcastId; +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -353,7 +382,7 @@ void BlockDataViewer::getTxByHash( } catch(NoMatch&) {} - +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getTxByHash); auto command = dynamic_cast(payload->message_.get()); command->set_hash(bdRef.getPtr(), bdRef.getSize()); @@ -363,6 +392,7 @@ void BlockDataViewer::getTxByHash( read_payload->callbackReturn_ = make_unique(cache_, txHash, callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -370,9 +400,10 @@ void BlockDataViewer::getTxBatchByHash( const set& hashes, const TxBatchCallback& callback) { //only accepts hashes in binary format +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getTxBatchByHash); auto command = dynamic_cast(payload->message_.get()); - +#endif map hashesToFetch; TxBatchResult cachedTxs; for (auto& hash : hashes) @@ -407,6 +438,7 @@ void BlockDataViewer::getTxBatchByHash( return; } +#ifdef BUILD_PROTOBUF for (auto& hash : hashesToFetch) { if (!hash.second) @@ -427,6 +459,7 @@ void BlockDataViewer::getTxBatchByHash( make_unique( cache_, cachedTxs, hashesToFetch, callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -456,6 +489,7 @@ void BlockDataViewer::getRawHeaderForTxHash(const BinaryData& txHash, catch(NoMatch&) { } +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getHeaderByHash); auto command = dynamic_cast(payload->message_.get()); command->add_bindata(txHash.getPtr(), txHash.getSize()); @@ -465,6 +499,7 @@ void BlockDataViewer::getRawHeaderForTxHash(const BinaryData& txHash, make_unique( cache_, UINT32_MAX, txHash, callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -480,6 +515,7 @@ void BlockDataViewer::getHeaderByHeight(unsigned height, catch(NoMatch&) { } +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getHeaderByHeight); auto command = dynamic_cast(payload->message_.get()); command->set_height(height); @@ -490,6 +526,7 @@ void BlockDataViewer::getHeaderByHeight(unsigned height, make_unique( cache_, height, txhash, callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -497,6 +534,7 @@ void BlockDataViewer::getLedgerDelegateForScrAddr( const string& walletID, BinaryDataRef scrAddr, function)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getLedgerDelegateForScrAddr); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID); @@ -506,29 +544,34 @@ void BlockDataViewer::getLedgerDelegateForScrAddr( read_payload->callbackReturn_ = make_unique(sock_, bdvID_, callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void BlockDataViewer::updateWalletsLedgerFilter( const vector& wltIdVec) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::updateWalletsLedgerFilter); auto command = dynamic_cast(payload->message_.get()); for (auto bd : wltIdVec) command->add_bindata(bd.getPtr(), bd.getSize()); sock_->pushPayload(move(payload), nullptr); +#endif } /////////////////////////////////////////////////////////////////////////////// void BlockDataViewer::getNodeStatus(function< void(ReturnMessage>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getNodeStatus); auto read_payload = make_shared(); read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -536,6 +579,7 @@ void BlockDataViewer::estimateFee(unsigned blocksToConfirm, const string& strategy, function)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::estimateFee); auto command = dynamic_cast(payload->message_.get()); command->set_value(blocksToConfirm); @@ -545,12 +589,14 @@ void BlockDataViewer::estimateFee(unsigned blocksToConfirm, read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void BlockDataViewer::getFeeSchedule(const string& strategy, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getFeeSchedule); auto command = dynamic_cast(payload->message_.get()); command->add_bindata(strategy); @@ -559,6 +605,7 @@ void BlockDataViewer::getFeeSchedule(const string& strategy, functioncallbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } @@ -567,6 +614,7 @@ void BlockDataViewer::getHistoryForWalletSelection( const vector& wldIDs, const string& orderingStr, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getHistoryForWalletSelection); auto command = dynamic_cast(payload->message_.get()); if (orderingStr == "ascending") @@ -583,6 +631,7 @@ void BlockDataViewer::getHistoryForWalletSelection( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -591,6 +640,7 @@ void BlockDataViewer::getSpentnessForOutputs( function>>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getSpentnessForOutputs); auto command = dynamic_cast(payload->message_.get()); @@ -610,6 +660,7 @@ void BlockDataViewer::getSpentnessForOutputs( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -618,6 +669,7 @@ void BlockDataViewer::getSpentnessForZcOutputs( function>>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getSpentnessForZcOutputs); auto command = dynamic_cast(payload->message_.get()); @@ -637,6 +689,7 @@ void BlockDataViewer::getSpentnessForZcOutputs( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -655,6 +708,7 @@ void BlockDataViewer::getOutputsForOutpoints( const map>& outpoints, bool withZc, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = make_payload(Methods::getOutputsForOutpoints); auto command = dynamic_cast(payload->message_.get()); @@ -676,6 +730,7 @@ void BlockDataViewer::getOutputsForOutpoints( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -692,6 +747,7 @@ LedgerDelegate::LedgerDelegate(shared_ptr sock, void LedgerDelegate::getHistoryPage(uint32_t id, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getHistoryPage); auto command = dynamic_cast(payload->message_.get()); command->set_delegateid(delegateID_); @@ -701,12 +757,14 @@ void LedgerDelegate::getHistoryPage(uint32_t id, read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void LedgerDelegate::getPageCount( function)> callback) const { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload( Methods::getPageCountForLedgerDelegate); auto command = dynamic_cast(payload->message_.get()); @@ -716,6 +774,7 @@ void LedgerDelegate::getPageCount( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -731,6 +790,7 @@ AsyncClient::BtcWallet::BtcWallet(const BlockDataViewer& bdv, const string& id) string AsyncClient::BtcWallet::registerAddresses( const vector& addrVec, bool isNew) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::registerWallet); auto command = dynamic_cast(payload->message_.get()); command->set_flag(isNew); @@ -745,11 +805,15 @@ string AsyncClient::BtcWallet::registerAddresses( sock_->pushPayload(move(payload), nullptr); return registrationId; +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// string AsyncClient::BtcWallet::setUnconfirmedTarget(unsigned confTarget) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::setWalletConfTarget); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -761,12 +825,16 @@ string AsyncClient::BtcWallet::setUnconfirmedTarget(unsigned confTarget) sock_->pushPayload(move(payload), nullptr); return registrationId; +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// string AsyncClient::BtcWallet::unregisterAddresses( const set& addrSet) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::unregisterAddresses); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -780,6 +848,9 @@ string AsyncClient::BtcWallet::unregisterAddresses( sock_->pushPayload(move(payload), nullptr); return registrationId; +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -792,6 +863,7 @@ string AsyncClient::BtcWallet::unregister() void AsyncClient::BtcWallet::getBalancesAndCount(uint32_t blockheight, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getBalancesAndCount); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -801,12 +873,14 @@ void AsyncClient::BtcWallet::getBalancesAndCount(uint32_t blockheight, read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void AsyncClient::BtcWallet::getSpendableTxOutListForValue(uint64_t val, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload( Methods::getSpendableTxOutListForValue); auto command = dynamic_cast(payload->message_.get()); @@ -817,12 +891,14 @@ void AsyncClient::BtcWallet::getSpendableTxOutListForValue(uint64_t val, read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void AsyncClient::BtcWallet::getSpendableZCList( function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getSpendableZCList); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -831,12 +907,14 @@ void AsyncClient::BtcWallet::getSpendableZCList( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void AsyncClient::BtcWallet::getRBFTxOutList( function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getRBFTxOutList); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -845,12 +923,14 @@ void AsyncClient::BtcWallet::getRBFTxOutList( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void AsyncClient::BtcWallet::getAddrTxnCountsFromDB( function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getAddrTxnCounts); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -859,12 +939,14 @@ void AsyncClient::BtcWallet::getAddrTxnCountsFromDB( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void AsyncClient::BtcWallet::getAddrBalancesFromDB( function>>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getAddrBalances); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -873,12 +955,14 @@ void AsyncClient::BtcWallet::getAddrBalancesFromDB( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void AsyncClient::BtcWallet::getHistoryPage(uint32_t id, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getHistoryPage); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -888,6 +972,7 @@ void AsyncClient::BtcWallet::getHistoryPage(uint32_t id, read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -897,7 +982,7 @@ void AsyncClient::BtcWallet::getLedgerEntryForTxHash( { //get history page with a hash as argument instead of an int will return //the ledger entry for the tx instead of a page - +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getHistoryPage); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -907,6 +992,7 @@ void AsyncClient::BtcWallet::getLedgerEntryForTxHash( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -921,6 +1007,7 @@ ScrAddrObj AsyncClient::BtcWallet::getScrAddrObjByKey(const BinaryData& scrAddr, void AsyncClient::BtcWallet::createAddressBook( function>)> callback) const { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::createAddressBook); auto command = dynamic_cast(payload->message_.get()); command->set_walletid(walletID_); @@ -929,6 +1016,7 @@ void AsyncClient::BtcWallet::createAddressBook( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -958,6 +1046,7 @@ void Lockbox::getBalancesAndCountFromDB(uint32_t topBlockHeight) string AsyncClient::Lockbox::registerAddresses( const vector& addrVec, bool isNew) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::registerLockbox); auto command = dynamic_cast(payload->message_.get()); command->set_flag(isNew); @@ -972,6 +1061,9 @@ string AsyncClient::Lockbox::registerAddresses( sock_->pushPayload(move(payload), nullptr); return registrationId; +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1001,6 +1093,7 @@ ScrAddrObj::ScrAddrObj(AsyncClient::BtcWallet* wlt, const BinaryData& scrAddr, void ScrAddrObj::getSpendableTxOutList( function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload( Methods::getSpendableTxOutListForAddr); auto command = dynamic_cast(payload->message_.get()); @@ -1011,6 +1104,7 @@ void ScrAddrObj::getSpendableTxOutList( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1026,6 +1120,7 @@ AsyncClient::Blockchain::Blockchain(const BlockDataViewer& bdv) : void AsyncClient::Blockchain::getHeaderByHash(const BinaryData& hash, function)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getHeaderByHash); auto command = dynamic_cast(payload->message_.get()); command->set_hash(hash.getPtr(), hash.getSize()); @@ -1034,12 +1129,14 @@ void AsyncClient::Blockchain::getHeaderByHash(const BinaryData& hash, read_payload->callbackReturn_ = make_unique(UINT32_MAX, callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// void AsyncClient::Blockchain::getHeaderByHeight(unsigned height, function)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getHeaderByHeight); auto command = dynamic_cast(payload->message_.get()); command->set_height(height); @@ -1048,6 +1145,7 @@ void AsyncClient::Blockchain::getHeaderByHeight(unsigned height, read_payload->callbackReturn_ = make_unique(height, callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1065,6 +1163,7 @@ void AsyncClient::BlockDataViewer::getCombinedBalances( const vector& wltIDs, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload(Methods::getCombinedBalances); auto command = dynamic_cast(payload->message_.get()); @@ -1075,6 +1174,7 @@ void AsyncClient::BlockDataViewer::getCombinedBalances( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1082,6 +1182,7 @@ void AsyncClient::BlockDataViewer::getCombinedAddrTxnCounts( const vector& wltIDs, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload( Methods::getCombinedAddrTxnCounts); auto command = dynamic_cast(payload->message_.get()); @@ -1093,6 +1194,7 @@ void AsyncClient::BlockDataViewer::getCombinedAddrTxnCounts( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1100,6 +1202,7 @@ void AsyncClient::BlockDataViewer::getCombinedSpendableTxOutListForValue( const vector& wltIDs, uint64_t value, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload( Methods::getCombinedSpendableTxOutListForValue); auto command = dynamic_cast(payload->message_.get()); @@ -1113,6 +1216,7 @@ void AsyncClient::BlockDataViewer::getCombinedSpendableTxOutListForValue( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1120,6 +1224,7 @@ void AsyncClient::BlockDataViewer::getCombinedSpendableZcOutputs( const vector& wltIDs, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload( Methods::getCombinedSpendableZcOutputs); auto command = dynamic_cast(payload->message_.get()); @@ -1131,6 +1236,7 @@ void AsyncClient::BlockDataViewer::getCombinedSpendableZcOutputs( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1138,6 +1244,7 @@ void AsyncClient::BlockDataViewer::getCombinedRBFTxOuts( const vector& wltIDs, function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload( Methods::getCombinedRBFTxOuts); auto command = dynamic_cast(payload->message_.get()); @@ -1149,6 +1256,7 @@ void AsyncClient::BlockDataViewer::getCombinedRBFTxOuts( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1157,6 +1265,7 @@ void AsyncClient::BlockDataViewer::getOutpointsForAddresses( unsigned startHeight, unsigned zcIndexCutoff, std::function)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload( Methods::getOutpointsForAddresses); auto command = dynamic_cast(payload->message_.get()); @@ -1171,6 +1280,7 @@ void AsyncClient::BlockDataViewer::getOutpointsForAddresses( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1178,6 +1288,7 @@ void AsyncClient::BlockDataViewer::getUTXOsForAddress( const BinaryData& scrAddr, bool withZc, std::function>)> callback) { +#ifdef BUILD_PROTOBUF auto payload = BlockDataViewer::make_payload( Methods::getUTXOsForAddress); auto command = dynamic_cast(payload->message_.get()); @@ -1189,6 +1300,7 @@ void AsyncClient::BlockDataViewer::getUTXOsForAddress( read_payload->callbackReturn_ = make_unique(callback); sock_->pushPayload(move(payload), read_payload); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1196,6 +1308,7 @@ void AsyncClient::BlockDataViewer::getUTXOsForAddress( // CallbackReturn children // /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void AsyncClient::deserialize( google::protobuf::Message* ptr, const WebSocketMessagePartial& partialMsg) { @@ -1208,11 +1321,13 @@ void AsyncClient::deserialize( throw ClientMessageError(errorMsg.errstr(), errorMsg.code()); } } +#endif /////////////////////////////////////////////////////////////////////////////// void CallbackReturn_BinaryDataRef::callback( const WebSocketMessagePartial& partialMsg) { +#ifdef BUILD_PROTOBUF auto msg = make_shared<::Codec_CommonTypes::BinaryData>(); AsyncClient::deserialize(msg.get(), partialMsg); @@ -1234,6 +1349,7 @@ void CallbackReturn_BinaryDataRef::callback( if (thr.joinable()) thr.detach(); } +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1242,6 +1358,7 @@ void CallbackReturn_String::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_CommonTypes::Strings msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1262,6 +1379,7 @@ void CallbackReturn_String::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1276,6 +1394,7 @@ void CallbackReturn_LedgerDelegate::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_CommonTypes::Strings msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1298,6 +1417,7 @@ void CallbackReturn_LedgerDelegate::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1312,6 +1432,7 @@ void CallbackReturn_Tx::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_CommonTypes::TxWithMetaData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1352,6 +1473,7 @@ void CallbackReturn_Tx::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1366,6 +1488,7 @@ void CallbackReturn_TxBatch::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_CommonTypes::ManyTxWithMetaData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1443,6 +1566,7 @@ void CallbackReturn_TxBatch::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1457,6 +1581,7 @@ void CallbackReturn_RawHeader::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_CommonTypes::BinaryData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1484,6 +1609,7 @@ void CallbackReturn_RawHeader::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1504,6 +1630,7 @@ void CallbackReturn_NodeStatus::callback( { try { +#ifdef BUILD_PROTOBUF auto msg = make_shared(); AsyncClient::deserialize(msg.get(), partialMsg); @@ -1521,6 +1648,7 @@ void CallbackReturn_NodeStatus::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1535,6 +1663,7 @@ void CallbackReturn_FeeEstimateStruct::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_FeeEstimate::FeeEstimate msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1553,6 +1682,7 @@ void CallbackReturn_FeeEstimateStruct::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1567,6 +1697,7 @@ void CallbackReturn_FeeSchedule::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_FeeEstimate::FeeSchedule msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1594,6 +1725,7 @@ void CallbackReturn_FeeSchedule::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1608,10 +1740,10 @@ void CallbackReturn_VectorLedgerEntry::callback( { try { +#ifdef BUILD_PROTOBUF auto msg = make_shared<::Codec_LedgerEntry::ManyLedgerEntry>(); AsyncClient::deserialize(msg.get(), partialMsg); - vector lev; for (int i = 0; i < msg->values_size(); i++) @@ -1632,6 +1764,7 @@ void CallbackReturn_VectorLedgerEntry::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1646,6 +1779,7 @@ void CallbackReturn_UINT64::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_CommonTypes::OneUnsigned msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1663,6 +1797,7 @@ void CallbackReturn_UINT64::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1677,6 +1812,7 @@ void CallbackReturn_VectorUTXO::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_Utxo::ManyUtxo utxos; AsyncClient::deserialize(&utxos, partialMsg); @@ -1700,6 +1836,7 @@ void CallbackReturn_VectorUTXO::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1714,6 +1851,7 @@ void CallbackReturn_VectorUINT64::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_CommonTypes::ManyUnsigned msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1733,6 +1871,7 @@ void CallbackReturn_VectorUINT64::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1747,6 +1886,7 @@ void CallbackReturn_Map_BD_U32::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_AddressData::ManyAddressData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1777,6 +1917,7 @@ void CallbackReturn_Map_BD_U32::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1791,6 +1932,7 @@ void CallbackReturn_Map_BD_VecU64::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_AddressData::ManyAddressData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1819,6 +1961,7 @@ void CallbackReturn_Map_BD_VecU64::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1833,6 +1976,7 @@ void CallbackReturn_LedgerEntry::callback( { try { +#ifdef BUILD_PROTOBUF auto msg = make_shared<::Codec_LedgerEntry::LedgerEntry>(); AsyncClient::deserialize(msg.get(), partialMsg); @@ -1850,6 +1994,7 @@ void CallbackReturn_LedgerEntry::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1864,6 +2009,7 @@ void CallbackReturn_VectorAddressBookEntry::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_AddressBook::AddressBook addressBook; AsyncClient::deserialize(&addressBook, partialMsg); @@ -1896,6 +2042,7 @@ void CallbackReturn_VectorAddressBookEntry::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1909,6 +2056,7 @@ void CallbackReturn_Bool::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_CommonTypes::OneUnsigned msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1924,6 +2072,7 @@ void CallbackReturn_Bool::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1938,6 +2087,7 @@ void CallbackReturn_BlockHeader::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_CommonTypes::BinaryData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -1959,6 +2109,7 @@ void CallbackReturn_BlockHeader::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -1971,10 +2122,12 @@ void CallbackReturn_BlockHeader::callback( void CallbackReturn_BDVCallback::callback( const WebSocketMessagePartial& partialMsg) { +#ifdef BUILD_PROTOBUF auto msg = make_shared<::Codec_BDVCommand::BDVCallback>(); AsyncClient::deserialize(msg.get(), partialMsg); userCallbackLambda_(msg); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1983,6 +2136,7 @@ void CallbackReturn_CombinedBalances::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_AddressData::ManyCombinedData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -2025,6 +2179,7 @@ void CallbackReturn_CombinedBalances::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -2039,6 +2194,7 @@ void CallbackReturn_CombinedCounts::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_AddressData::ManyCombinedData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -2075,6 +2231,7 @@ void CallbackReturn_CombinedCounts::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -2089,6 +2246,7 @@ void CallbackReturn_AddrOutpoints::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_Utxo::AddressOutpointsData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -2132,6 +2290,7 @@ void CallbackReturn_AddrOutpoints::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { @@ -2146,6 +2305,7 @@ void CallbackReturn_SpentnessData::callback( { try { +#ifdef BUILD_PROTOBUF ::Codec_Utxo::Spentness_BatchData msg; AsyncClient::deserialize(&msg, partialMsg); @@ -2194,6 +2354,7 @@ void CallbackReturn_SpentnessData::callback( if (thr.joinable()) thr.detach(); } +#endif } catch (ClientMessageError& e) { diff --git a/cppForSwig/AsyncClient.h b/cppForSwig/AsyncClient.h index 4d97a5409..753d79245 100755 --- a/cppForSwig/AsyncClient.h +++ b/cppForSwig/AsyncClient.h @@ -97,11 +97,11 @@ template class ReturnMessage error_ = std::make_shared(err); } - U get(void) + U get(void) { if (error_ != nullptr) throw *error_; - + return std::move(value_); } }; @@ -403,11 +403,12 @@ namespace AsyncClient ~BlockDataViewer(void); //utility +#ifdef BUILD_PROTOBUF static std::unique_ptr make_payload( ::Codec_BDVCommand::Methods); static std::unique_ptr make_payload( ::Codec_BDVCommand::StaticMethods); - +#endif BtcWallet instantiateWallet(const std::string& id); Lockbox instantiateLockbox(const std::string& id); @@ -527,9 +528,10 @@ namespace AsyncClient }; //////////////////////////////////////////////////////////////////////////// - void deserialize(::google::protobuf::Message*, +#ifdef BUILD_PROTOBUF + void deserialize(::google::protobuf::Message*, const WebSocketMessagePartial&); - +#endif /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// //// callback structs for async networking @@ -863,16 +865,18 @@ namespace AsyncClient /////////////////////////////////////////////////////////////////////////////// struct CallbackReturn_BDVCallback : public CallbackReturn_WebSocket { +#ifdef BUILD_PROTOBUF private: std::function)> userCallbackLambda_; - +#endif public: +#ifdef BUILD_PROTOBUF CallbackReturn_BDVCallback( std::function)> lbd) : userCallbackLambda_(lbd) {} - +#endif //virtual void callback(const WebSocketMessagePartial&); }; diff --git a/cppForSwig/BDM_Server.cpp b/cppForSwig/BDM_Server.cpp index c70ee7e8b..81f11701b 100644 --- a/cppForSwig/BDM_Server.cpp +++ b/cppForSwig/BDM_Server.cpp @@ -10,8 +10,10 @@ #include "ArmoryErrors.h" using namespace std; +#ifdef BUILD_PROTOBUF using namespace ::google::protobuf; using namespace ::Codec_BDVCommand; +#endif using namespace ::Armory::Threading; /////////////////////////////////////////////////////////////////////////////// @@ -19,6 +21,7 @@ using namespace ::Armory::Threading; // BDV_Server_Object // /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF BDVCommandProcessingResultType BDV_Server_Object::processCommand( shared_ptr command, shared_ptr& resultingPayload) { @@ -1804,6 +1807,7 @@ BDVCommandProcessingResultType BDV_Server_Object::processCommand( return BDVCommandProcess_Success; } +#endif /////////////////////////////////////////////////////////////////////////////// shared_ptr Clients::get(const string& id) const @@ -1918,6 +1922,7 @@ void BDV_Server_Object::init() //fill with addresses from protobuf payloads for (auto& wlt : wltMap) { +#ifdef BUILD_PROTOBUF for (int i = 0; i < wlt.second.command_->bindata_size(); i++) { auto& addrStr = wlt.second.command_->bindata(i); @@ -1927,6 +1932,7 @@ void BDV_Server_Object::init() BinaryDataRef addrRef; addrRef.setRef(addrStr); batch->scrAddrSet_.insert(move(addrRef)); } +#endif } //callback only serves to wait on the registration event @@ -1964,7 +1970,7 @@ void BDV_Server_Object::init() //mark bdv object as ready isReadyPromise_->set_value(true); - +#ifdef BUILD_PROTOBUF //callback client with BDM_Ready packet auto message = make_shared(); auto notif = message->add_notification(); @@ -1972,6 +1978,7 @@ void BDV_Server_Object::init() auto newBlockNotif = notif->mutable_newblock(); newBlockNotif->set_height(blockchain().top()->getBlockHeight()); cb_->callback(message); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -1987,7 +1994,7 @@ void BDV_Server_Object::processNotification( } scanWallets(notifPtr); - +#ifdef BUILD_PROTOBUF auto callbackPtr = make_shared(); switch (action) @@ -2130,9 +2137,11 @@ void BDV_Server_Object::processNotification( if(callbackPtr->notification_size() > 0) cb_->callback(callbackPtr); +#endif } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void BDV_Server_Object::registerWallet( shared_ptr<::Codec_BDVCommand::BDVCommand> command) { @@ -2192,6 +2201,7 @@ void BDV_Server_Object::registerLockbox( auto bdvPtr = (BlockDataViewer*)this; bdvPtr->registerLockbox(command); } +#endif /////////////////////////////////////////////////////////////////////////////// void BDV_Server_Object::populateWallets(map& wltMap) @@ -2201,6 +2211,8 @@ void BDV_Server_Object::populateWallets(map& wltMap) for (auto& wlt : wltMap) { + map> newAddrMap; +#ifdef BUILD_PROTOBUF auto& walletId = wlt.second.command_->walletid(); shared_ptr theWallet; @@ -2215,7 +2227,6 @@ void BDV_Server_Object::populateWallets(map& wltMap) continue; } - map> newAddrMap; for (int i = 0; i < wlt.second.command_->bindata_size(); i++) { auto& addrStr = wlt.second.command_->bindata(i); @@ -2232,11 +2243,12 @@ void BDV_Server_Object::populateWallets(map& wltMap) db_, &blockchain(), zeroConfCont_.get(), iter->first); newAddrMap.insert(move(make_pair(iter->first, addrObj))); } - +#endif if (newAddrMap.size() == 0) continue; - +#ifdef BUILD_PROTOBUF theWallet->scrAddrMap_.update(newAddrMap); +#endif } } @@ -2255,6 +2267,7 @@ void BDV_Server_Object::flagRefresh( } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF BDVCommandProcessingResultType BDV_Server_Object::processPayload( shared_ptr& packet, shared_ptr& result) { @@ -2373,9 +2386,9 @@ BDVCommandProcessingResultType BDV_Server_Object::processPayload( result = errMsg; } - return BDVCommandProcess_Failure; } +#endif /////////////////////////////////////////////////////////////////////////////// // @@ -2525,6 +2538,7 @@ void Clients::bdvMaintenanceThread() } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void Clients::processShutdownCommand(shared_ptr command) { const auto& thisCookie = Armory::Config::NetworkSettings::cookie(); @@ -2573,6 +2587,7 @@ void Clients::processShutdownCommand(shared_ptr command) LOGWARN << "unexpected command in processShutdownCommand"; } } +#endif /////////////////////////////////////////////////////////////////////////////// void Clients::shutdown() @@ -2646,6 +2661,7 @@ void Clients::unregisterAllBDVs() } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF shared_ptr Clients::registerBDV( shared_ptr command, string bdvID) { @@ -2689,6 +2705,7 @@ shared_ptr Clients::registerBDV( response->set_data(newID); return response; } +#endif /////////////////////////////////////////////////////////////////////////////// void Clients::unregisterBDV(std::string bdvId) @@ -2838,8 +2855,9 @@ void Clients::messageParserThread(void) the object's process mutex */ unique_lock lock(bdvPtr->processPacketMutex_); +#ifdef BUILD_PROTOBUF auto result = processCommand(payloadPtr); - +#endif //check if the map has the next message { auto msgIter = bdvPtr->messageMap_.find( @@ -2869,10 +2887,12 @@ void Clients::messageParserThread(void) lock.unlock(); bdvPtr->packetProcess_threadLock_.store(0); +#ifdef BUILD_PROTOBUF //write return value if any if (result != nullptr) WebSocketServer::write( payloadPtr->bdvID_, payloadPtr->messageID_, result); +#endif } } @@ -3043,6 +3063,7 @@ void Clients::broadcastThroughRPC() } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF shared_ptr Clients::processCommand(shared_ptr payload) { //clear bdvPtr from the payload to avoid circular ownership @@ -3420,6 +3441,7 @@ shared_ptr Clients::processUnregisteredCommand(const uint64_t& bdvId, return nullptr; } +#endif /////////////////////////////////////////////////////////////////////////////// // @@ -3430,6 +3452,7 @@ Callback::~Callback() {} /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void WS_Callback::callback(shared_ptr command) { //write to socket @@ -3455,6 +3478,7 @@ shared_ptr<::Codec_BDVCommand::BDVCallback> UnitTest_Callback::getNotification() return nullptr; } +#endif /////////////////////////////////////////////////////////////////////////////// // @@ -3480,6 +3504,7 @@ void BDV_PartialMessage::reset() } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF bool BDV_PartialMessage::getMessage(shared_ptr msgPtr) { if (!isReady()) @@ -3487,6 +3512,7 @@ bool BDV_PartialMessage::getMessage(shared_ptr msgPtr) return partialMessage_.getMessage(msgPtr.get()); } +#endif /////////////////////////////////////////////////////////////////////////////// size_t BDV_PartialMessage::topId() const @@ -3502,4 +3528,4 @@ size_t BDV_PartialMessage::topId() const unsigned BDV_PartialMessage::getMessageId(shared_ptr packet) { return WebSocketMessagePartial::getMessageId(packet->packetData_.getRef()); -} \ No newline at end of file +} diff --git a/cppForSwig/BDM_Server.h b/cppForSwig/BDM_Server.h index c4932c311..457e51c32 100644 --- a/cppForSwig/BDM_Server.h +++ b/cppForSwig/BDM_Server.h @@ -52,8 +52,10 @@ class BDV_Server_Object; namespace DBTestUtils { +#ifdef BUILD_PROTOBUF std::tuple, unsigned> waitOnSignal( Clients*, const std::string&, ::Codec_BDVCommand::NotificationType); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -97,7 +99,9 @@ class Callback virtual ~Callback() = 0; +#ifdef BUILD_PROTOBUF virtual void callback(std::shared_ptr<::Codec_BDVCommand::BDVCallback>) = 0; +#endif virtual bool isValid(void) = 0; virtual void shutdown(void) = 0; }; @@ -113,7 +117,9 @@ class WS_Callback : public Callback bdvID_(bdvid) {} +#ifdef BUILD_PROTOBUF void callback(std::shared_ptr<::Codec_BDVCommand::BDVCallback>); +#endif bool isValid(void) { return true; } void shutdown(void) {} }; @@ -121,26 +127,32 @@ class WS_Callback : public Callback /////////////////////////////////////////////////////////////////////////////// class UnitTest_Callback : public Callback { +#ifdef BUILD_PROTOBUF private: Armory::Threading::BlockingQueue< std::shared_ptr<::Codec_BDVCommand::BDVCallback>> notifQueue_; - +#endif public: +#ifdef BUILD_PROTOBUF void callback(std::shared_ptr<::Codec_BDVCommand::BDVCallback>); +#endif bool isValid(void) { return true; } void shutdown(void) {} +#ifdef BUILD_PROTOBUF std::shared_ptr<::Codec_BDVCommand::BDVCallback> getNotification(void); +#endif }; /////////////////////////////////////////////////////////////////////////////// class BDV_Server_Object : public BlockDataViewer { friend class Clients; +#ifdef BUILD_PROTOBUF friend std::tuple, unsigned> DBTestUtils::waitOnSignal( Clients*, const std::string&, ::Codec_BDVCommand::NotificationType); - +#endif private: std::atomic started_; std::thread initT_; @@ -153,7 +165,9 @@ class BDV_Server_Object : public BlockDataViewer struct walletRegStruct { +#ifdef BUILD_PROTOBUF std::shared_ptr<::Codec_BDVCommand::BDVCommand> command_; +#endif WalletType type_; }; @@ -173,13 +187,17 @@ class BDV_Server_Object : public BlockDataViewer private: BDV_Server_Object(BDV_Server_Object&) = delete; //no copies +#ifdef BUILD_PROTOBUF BDVCommandProcessingResultType processCommand( std::shared_ptr<::Codec_BDVCommand::BDVCommand>, std::shared_ptr<::google::protobuf::Message>&); +#endif void startThreads(void); +#ifdef BUILD_PROTOBUF void registerWallet(std::shared_ptr<::Codec_BDVCommand::BDVCommand>); void registerLockbox(std::shared_ptr<::Codec_BDVCommand::BDVCommand>); +#endif void populateWallets(std::map&); void setup(void); @@ -255,10 +273,12 @@ class Clients std::shared_ptr get(const std::string& id) const; +#ifdef BUILD_PROTOBUF void processShutdownCommand( std::shared_ptr<::Codec_BDVCommand::StaticCommand>); std::shared_ptr<::google::protobuf::Message> registerBDV( std::shared_ptr<::Codec_BDVCommand::StaticCommand>, std::string bdvID); +#endif void unregisterBDV(std::string bdvId); void shutdown(void); void exitRequestLoop(void); @@ -267,12 +287,13 @@ class Clients { packetQueue_.push_back(move(payload)); } - +#ifdef BUILD_PROTOBUF std::shared_ptr<::google::protobuf::Message> processUnregisteredCommand( const uint64_t& bdvId, std::shared_ptr<::Codec_BDVCommand::StaticCommand>); std::shared_ptr<::google::protobuf::Message> processCommand( std::shared_ptr); +#endif }; #endif diff --git a/cppForSwig/BDM_mainthread.cpp b/cppForSwig/BDM_mainthread.cpp index 1b8a21b21..8efcda65d 100644 --- a/cppForSwig/BDM_mainthread.cpp +++ b/cppForSwig/BDM_mainthread.cpp @@ -12,7 +12,6 @@ //////////////////////////////////////////////////////////////////////////////// #include "BDM_mainthread.h" -#include "BlockUtils.h" #include "BlockDataViewer.h" #include "nodeRPC.h" diff --git a/cppForSwig/BDM_mainthread.h b/cppForSwig/BDM_mainthread.h index dd30c7b15..58831f271 100644 --- a/cppForSwig/BDM_mainthread.h +++ b/cppForSwig/BDM_mainthread.h @@ -19,7 +19,7 @@ #include "UniversalTimer.h" #include "bdmenums.h" -#include "BlockUtils.h" +#include "BlockchainDatabase/BlockUtils.h" #include "BDM_Server.h" struct BlockDataManagerConfig; diff --git a/cppForSwig/BDVCodec.h b/cppForSwig/BDVCodec.h index 95dda046a..3e09cb9f5 100644 --- a/cppForSwig/BDVCodec.h +++ b/cppForSwig/BDVCodec.h @@ -29,6 +29,7 @@ #endif #endif // __GNUC__ +#ifdef BUILD_PROTOBUF #include "protobuf/AddressBook.pb.h" #include "protobuf/AddressData.pb.h" #include "protobuf/CommonTypes.pb.h" @@ -37,6 +38,7 @@ #include "protobuf/Utxo.pb.h" #include "protobuf/NodeStatus.pb.h" #include "protobuf/BDVCommand.pb.h" +#endif #ifdef _MSC_VER #pragma warning(pop) diff --git a/cppForSwig/BDV_Notification.h b/cppForSwig/BDV_Notification.h index f37a83179..5fdbf09a6 100644 --- a/cppForSwig/BDV_Notification.h +++ b/cppForSwig/BDV_Notification.h @@ -13,7 +13,7 @@ #include "log.h" #include "bdmenums.h" -#include "Blockchain.h" +#include "BlockchainDatabase/Blockchain.h" #include "LedgerEntry.h" #include "ZeroConf.h" #include "nodeRPC.h" diff --git a/cppForSwig/BinaryData.h b/cppForSwig/BinaryData.h index df3f0b9b4..d1bb1913f 100644 --- a/cppForSwig/BinaryData.h +++ b/cppForSwig/BinaryData.h @@ -108,7 +108,7 @@ class BinaryData ///////////////////////////////////////////////////////////////////////////// BinaryData(void) : data_(0) { } explicit BinaryData(size_t sz) { alloc(sz); } - BinaryData(uint8_t const * inData, size_t sz) + BinaryData(uint8_t const * inData, size_t sz) { copyFrom(inData, sz); } BinaryData(char const * inData, size_t sz) { copyFrom(inData, sz); } BinaryData(uint8_t const * dstart, uint8_t const * dend ) @@ -561,16 +561,14 @@ class BinaryData std::vector data_; private: - void alloc(size_t sz) + void alloc(size_t sz) { if(sz != getSize()) { data_.clear(); data_.resize(sz); } - } - }; @@ -1460,13 +1458,13 @@ class BinaryWriter void put_BitPacker(BitPacker & bp) { put_BinaryData(bp.getBinaryData()); } ///////////////////////////////////////////////////////////////////////////// - BinaryData const & getData(void) + BinaryData const & getData(void) const { return theString_; } ///////////////////////////////////////////////////////////////////////////// - size_t getSize(void) + size_t getSize(void) const { return theString_.getSize(); } @@ -1478,13 +1476,13 @@ class BinaryWriter } ///////////////////////////////////////////////////////////////////////////// - std::string toString(void) + std::string toString(void) const { return theString_.toBinStr(); } ///////////////////////////////////////////////////////////////////////////// - std::string toHex(void) + std::string toHex(void) const { return theString_.toHexStr(); } diff --git a/cppForSwig/BlockDataViewer.cpp b/cppForSwig/BlockDataViewer.cpp index 3cb15b299..88dc409b6 100644 --- a/cppForSwig/BlockDataViewer.cpp +++ b/cppForSwig/BlockDataViewer.cpp @@ -33,6 +33,7 @@ BlockDataViewer::~BlockDataViewer() } ///////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void BlockDataViewer::registerWallet( shared_ptr<::Codec_BDVCommand::BDVCommand> msg) { @@ -45,6 +46,7 @@ void BlockDataViewer::registerLockbox( { groups_[group_lockbox].registerAddresses(msg); } +#endif ///////////////////////////////////////////////////////////////////////////// void BlockDataViewer::unregisterWallet(const string& IDstr) @@ -224,6 +226,7 @@ bool BlockDataViewer::hasWallet(const string& ID) const } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void BlockDataViewer::registerAddresses( shared_ptr<::Codec_BDVCommand::BDVCommand> msg) { @@ -234,6 +237,7 @@ void BlockDataViewer::registerAddresses( group.registerAddresses(msg); } } +#endif //////////////////////////////////////////////////////////////////////////////// Tx BlockDataViewer::getTxByHash(BinaryData const & txhash) const @@ -1197,6 +1201,7 @@ void WalletGroup::unregisterWallet(const string& id) } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void WalletGroup::registerAddresses( shared_ptr<::Codec_BDVCommand::BDVCommand> msg) { @@ -1299,6 +1304,7 @@ void WalletGroup::registerAddresses( saf_->pushAddressBatch(batch); theWallet->resetCounters(); } +#endif //////////////////////////////////////////////////////////////////////////////// bool WalletGroup::hasID(const string& ID) const diff --git a/cppForSwig/BlockDataViewer.h b/cppForSwig/BlockDataViewer.h index 96fcce4e7..61a727814 100644 --- a/cppForSwig/BlockDataViewer.h +++ b/cppForSwig/BlockDataViewer.h @@ -17,8 +17,8 @@ #include #include -#include "BlockUtils.h" -#include "txio.h" +#include "BlockchainDatabase/BlockUtils.h" +#include "BlockchainDatabase/txio.h" #include "BDV_Notification.h" #include "ZeroConf.h" #include "util.h" @@ -72,9 +72,11 @@ class BlockDataViewer // blockchain in RAM, each scan will take 30-120 seconds. Registering makes // sure that the intial blockchain scan picks up wallet-relevant stuff as // it goes, and does a full [re-]scan of the blockchain only if necessary. +#ifdef BUILD_PROTOBUF void registerWallet(std::shared_ptr<::Codec_BDVCommand::BDVCommand>); void registerLockbox(std::shared_ptr<::Codec_BDVCommand::BDVCommand>); void registerAddresses(std::shared_ptr<::Codec_BDVCommand::BDVCommand>); +#endif void unregisterWallet(const std::string& ID); void unregisterLockbox(const std::string& ID); @@ -265,7 +267,9 @@ class WalletGroup ~WalletGroup(); std::shared_ptr getOrSetWallet(const std::string&); +#ifdef BUILD_PROTOBUF void registerAddresses(std::shared_ptr<::Codec_BDVCommand::BDVCommand>); +#endif void unregisterWallet(const std::string& IDstr); bool hasID(const std::string &ID) const; diff --git a/cppForSwig/BlockDataMap.cpp b/cppForSwig/BlockchainDatabase/BlockDataMap.cpp similarity index 87% rename from cppForSwig/BlockDataMap.cpp rename to cppForSwig/BlockchainDatabase/BlockDataMap.cpp index 77c8d64cc..7c67f2967 100644 --- a/cppForSwig/BlockDataMap.cpp +++ b/cppForSwig/BlockchainDatabase/BlockDataMap.cpp @@ -24,8 +24,8 @@ BlockData::BlockData(uint32_t blockid) //////////////////////////////////////////////////////////////////////////////// shared_ptr BlockData::deserialize(const uint8_t* data, size_t size, const shared_ptr blockHeader, - function getID, - bool checkMerkle, bool keepHashes) + function getID, + BlockData::CheckHashes mode) { //deser header from raw block and run a quick sanity check if (size < HEADER_SIZE) @@ -73,26 +73,39 @@ shared_ptr BlockData::deserialize(const uint8_t* data, size_t size, result->data_ = data; result->size_ = size; - if (!checkMerkle) - return result; - - //let's check the merkle root - vector allhashes; - for (auto& txn : result->txns_) + vector allHashes; + switch (mode) { - if (!keepHashes) + case CheckHashes::NoChecks: + return result; + + case CheckHashes::MerkleOnly: + case CheckHashes::TxFilters: { - auto txhash = txn->moveHash(); - allhashes.push_back(move(txhash)); + allHashes.reserve(result->txns_.size()); + for (auto& txn : result->txns_) + { + auto txhash = txn->moveHash(); + allHashes.emplace_back(move(txhash)); + } + break; } - else + + case CheckHashes::FullHints: { - auto& txhash = txn->getHash(); - allhashes.push_back(txhash); + allHashes.reserve(result->txns_.size()); + for (auto& txn : result->txns_) + { + const auto& txhash = txn->getHash(); + allHashes.emplace_back(txhash); + } + break; } } - auto&& merkleroot = BtcUtils::calculateMerkleRoot(allhashes); + //any form of later txhash filtering implies we check the merkle + //root, otherwise we would have no guarantees the hashes are valid + auto&& merkleroot = BtcUtils::calculateMerkleRoot(allHashes); if (merkleroot != bh.getMerkleRoot()) { LOGERR << "merkle root mismatch!"; @@ -101,7 +114,8 @@ shared_ptr BlockData::deserialize(const uint8_t* data, size_t size, throw BlockDeserializingException("invalid merkle root"); } - result->computeTxFilter(allhashes); + if (mode == CheckHashes::TxFilters) + result->computeTxFilter(allHashes); return result; } diff --git a/cppForSwig/BlockDataMap.h b/cppForSwig/BlockchainDatabase/BlockDataMap.h similarity index 98% rename from cppForSwig/BlockDataMap.h rename to cppForSwig/BlockchainDatabase/BlockDataMap.h index 58d6873d6..2d88c308e 100644 --- a/cppForSwig/BlockDataMap.h +++ b/cppForSwig/BlockchainDatabase/BlockDataMap.h @@ -199,6 +199,15 @@ class BlockData BinaryData blockHash_; +public: + enum class CheckHashes + { + NoChecks, + MerkleOnly, + TxFilters, + FullHints + }; + public: BlockData(uint32_t); @@ -206,7 +215,7 @@ class BlockData const uint8_t*, size_t, const std::shared_ptr, std::function getID, - bool checkMerkle, bool keepHashes); + CheckHashes); bool isInitialized(void) const { diff --git a/cppForSwig/BlockObj.cpp b/cppForSwig/BlockchainDatabase/BlockObj.cpp similarity index 100% rename from cppForSwig/BlockObj.cpp rename to cppForSwig/BlockchainDatabase/BlockObj.cpp diff --git a/cppForSwig/BlockObj.h b/cppForSwig/BlockchainDatabase/BlockObj.h similarity index 100% rename from cppForSwig/BlockObj.h rename to cppForSwig/BlockchainDatabase/BlockObj.h diff --git a/cppForSwig/BlockUtils.cpp b/cppForSwig/BlockchainDatabase/BlockUtils.cpp similarity index 100% rename from cppForSwig/BlockUtils.cpp rename to cppForSwig/BlockchainDatabase/BlockUtils.cpp diff --git a/cppForSwig/BlockUtils.h b/cppForSwig/BlockchainDatabase/BlockUtils.h similarity index 100% rename from cppForSwig/BlockUtils.h rename to cppForSwig/BlockchainDatabase/BlockUtils.h index 81f2bcff1..2cfeda921 100644 --- a/cppForSwig/BlockUtils.h +++ b/cppForSwig/BlockchainDatabase/BlockUtils.h @@ -22,12 +22,12 @@ #include #include "Blockchain.h" +#include "StoredBlockObj.h" +#include "lmdb_wrapper.h" #include "BinaryData.h" #include "BtcUtils.h" #include "BlockObj.h" -#include "StoredBlockObj.h" #include "ArmoryConfig.h" -#include "lmdb_wrapper.h" #include "ScrAddrObj.h" #include "bdmenums.h" diff --git a/cppForSwig/Blockchain.cpp b/cppForSwig/BlockchainDatabase/Blockchain.cpp similarity index 100% rename from cppForSwig/Blockchain.cpp rename to cppForSwig/BlockchainDatabase/Blockchain.cpp diff --git a/cppForSwig/Blockchain.h b/cppForSwig/BlockchainDatabase/Blockchain.h similarity index 100% rename from cppForSwig/Blockchain.h rename to cppForSwig/BlockchainDatabase/Blockchain.h diff --git a/cppForSwig/BlockchainScanner.cpp b/cppForSwig/BlockchainDatabase/BlockchainScanner.cpp similarity index 99% rename from cppForSwig/BlockchainScanner.cpp rename to cppForSwig/BlockchainDatabase/BlockchainScanner.cpp index 90d7f0595..208910900 100644 --- a/cppForSwig/BlockchainScanner.cpp +++ b/cppForSwig/BlockchainDatabase/BlockchainScanner.cpp @@ -460,7 +460,7 @@ shared_ptr BlockchainScanner::getBlockData( auto bdata = BlockData::deserialize( filemap->getPtr() + blockheader->getOffset(), blockheader->getBlockSize(), - blockheader, getID, false, false); + blockheader, getID, BlockData::CheckHashes::NoChecks); return bdata; } @@ -1225,7 +1225,7 @@ void BlockchainScanner::undo(Blockchain::ReorganizationState& reorgState) auto bdata = BlockData::deserialize( filemap.get()->getPtr() + blockPtr->getOffset(), blockPtr->getBlockSize(), blockPtr, - getID, false, false); + getID, BlockData::CheckHashes::NoChecks); const auto& txns = bdata->getTxns(); for (unsigned i = 0; i < txns.size(); i++) @@ -1461,7 +1461,7 @@ void BlockchainScanner::processFilterHitsThread( bdata = BlockData::deserialize( fileptr->getPtr() + headerPtr->getOffset(), headerPtr->getBlockSize(), - headerPtr, getID, false, false); + headerPtr, getID, BlockData::CheckHashes::NoChecks); } catch (const BlockDeserializingException& e) { diff --git a/cppForSwig/BlockchainScanner.h b/cppForSwig/BlockchainDatabase/BlockchainScanner.h similarity index 100% rename from cppForSwig/BlockchainScanner.h rename to cppForSwig/BlockchainDatabase/BlockchainScanner.h diff --git a/cppForSwig/BlockchainScanner_Super.cpp b/cppForSwig/BlockchainDatabase/BlockchainScanner_Super.cpp similarity index 99% rename from cppForSwig/BlockchainScanner_Super.cpp rename to cppForSwig/BlockchainDatabase/BlockchainScanner_Super.cpp index 0635ed785..c88e91c37 100644 --- a/cppForSwig/BlockchainScanner_Super.cpp +++ b/cppForSwig/BlockchainDatabase/BlockchainScanner_Super.cpp @@ -1268,7 +1268,7 @@ void BlockchainScanner_Super::undo(Blockchain::ReorganizationState& reorgState) auto bdata = BlockData::deserialize( filemap.get()->getPtr() + blockPtr->getOffset(), blockPtr->getBlockSize(), blockPtr, getID, - false, false); + BlockData::CheckHashes::NoChecks); const auto& txns = bdata->getTxns(); for (unsigned i = 0; i < txns.size(); i++) @@ -1443,7 +1443,7 @@ shared_ptr BlockDataBatch::getBlockData(unsigned height) auto bdata = BlockData::deserialize( filemap->getPtr() + blockheader->getOffset(), blockheader->getBlockSize(), - blockheader, getID, false, false); + blockheader, getID, BlockData::CheckHashes::NoChecks); if (!bdata->isInitialized()) { diff --git a/cppForSwig/BlockchainScanner_Super.h b/cppForSwig/BlockchainDatabase/BlockchainScanner_Super.h similarity index 100% rename from cppForSwig/BlockchainScanner_Super.h rename to cppForSwig/BlockchainDatabase/BlockchainScanner_Super.h diff --git a/cppForSwig/DatabaseBuilder.cpp b/cppForSwig/BlockchainDatabase/DatabaseBuilder.cpp similarity index 91% rename from cppForSwig/DatabaseBuilder.cpp rename to cppForSwig/BlockchainDatabase/DatabaseBuilder.cpp index 9d16e7a83..b015198d8 100644 --- a/cppForSwig/DatabaseBuilder.cpp +++ b/cppForSwig/BlockchainDatabase/DatabaseBuilder.cpp @@ -125,6 +125,9 @@ void DatabaseBuilder::init() double updatetime = TIMER_READ_SEC("updateblocksindb"); LOGINFO << "updated HEADERS db in " << updatetime << "s"; + if (DBSettings::checkTxHints()) + checkTxHintsIntegrity(); + cycleDatabases(); int scanFrom = -1; @@ -315,7 +318,6 @@ Blockchain::ReorganizationState DatabaseBuilder::updateBlocksInDB( baseID); } - auto addblocks = [&](uint16_t fileID, size_t startOffset, shared_ptr bo, bool _verbose)->void { @@ -388,7 +390,7 @@ bool DatabaseBuilder::addBlocksToDB(BlockDataLoader& bdl, uint16_t fileID, size_t startOffset, shared_ptr bo, bool fullHints) { - auto&& blockfilemappointer = bdl.get(fileID); + auto blockfilemappointer = bdl.get(fileID); auto ptr = blockfilemappointer->getPtr(); //ptr is null if we're out of block files @@ -413,7 +415,9 @@ bool DatabaseBuilder::addBlocksToDB(BlockDataLoader& bdl, { bd = BlockData::deserialize( data, size, nullptr, - getID, true, fullHints); + getID, fullHints ? + BlockData::CheckHashes::FullHints : + BlockData::CheckHashes::TxFilters); } catch (const BlockDeserializingException &e) { @@ -791,7 +795,8 @@ map> DatabaseBuilder::assessBlkFile( try { bd = BlockData::deserialize( - data, size, nullptr, getID, true, false); + data, size, nullptr, getID, + BlockData::CheckHashes::TxFilters); } catch (...) { @@ -1129,7 +1134,7 @@ void DatabaseBuilder::verifyTransactions() auto bdata = BlockData::deserialize( fileMap->getPtr() + bhPtr->getOffset(), bhPtr->getBlockSize(), - bhPtr, getID, false, false); + bhPtr, getID, BlockData::CheckHashes::NoChecks); const auto& txns = bdata->getTxns(); if (txid > txns.size()) @@ -1185,7 +1190,7 @@ void DatabaseBuilder::verifyTransactions() auto bdata = BlockData::deserialize( fileMap->getPtr() + blockheader->getOffset(), blockheader->getBlockSize(), - blockheader, getID, false, false); + blockheader, getID, BlockData::CheckHashes::NoChecks); const auto& txns = bdata->getTxns(); for (unsigned i = 1; i < txns.size(); i++) @@ -1525,3 +1530,114 @@ void DatabaseBuilder::cycleDatabases() db_->closeDatabases(); db_->openDatabases(Pathing::dbDir()); } + +///////////////////////////////////////////////////////////////////////////// +void DatabaseBuilder::checkTxHintsIntegrity() +{ + BlockDataLoader bdl(blockFiles_.folderPath()); + unsigned threadcount = min(DBSettings::threadCount(), + blockFiles_.fileCount()); + + auto fileID = std::make_shared>(); + fileID->store(0, std::memory_order_relaxed); + + auto parserThread = [this, fileID, &bdl]() + { + while (true) { + auto counter = fileID->fetch_add(1, std::memory_order_relaxed); + if (counter % 25 == 0) + LOGINFO << "checking txhints for file " << counter; + + auto blockfilemappointer = bdl.get(counter); + auto ptr = blockfilemappointer->getPtr(); + if (ptr == nullptr) + return; + + //tally all blocks in file + std::list> bdList; + parseBlockFile(ptr, blockfilemappointer->size(), + 0, [&bdList](const uint8_t* data, size_t size, size_t)->bool + { + try + { + auto bd = BlockData::deserialize( + data, size, nullptr, + nullptr, BlockData::CheckHashes::FullHints); + bdList.emplace_back(bd); + return true; + } + catch (...) + { + return false; + } + } + ); + + //check hashes can be resolved via tx hints db + int missedCount = 0; + auto dbtx = db_->beginTransaction(TXHINTS, LMDB::ReadOnly); + for (const auto& blockData : bdList) + { + //skip blocks not in the main chain + auto headerPtr = blockchain_->getHeaderByHash(blockData->getHash()); + if (headerPtr == nullptr || !headerPtr->isMainBranch()) + continue; + + const auto& txns = blockData->getTxns(); + for (const auto& txn : txns) + { + auto hash4 = txn->getHash().getSliceRef(0, 4); + BinaryRefReader brrHints = db_->getValueRef( + TXHINTS, DB_PREFIX_TXHINTS, hash4); + + uint32_t valSize = brrHints.getSize(); + if (valSize < 6) + { + ++missedCount; + return; + } + + bool hit = false; + uint32_t numHints = (uint32_t)brrHints.get_var_int(); + for (uint32_t i = 0; i < numHints; i++) + { + BinaryDataRef hint = brrHints.get_BinaryDataRef(6); + + //check this key is on the main branch + auto hintRef = hint.getSliceRef(0, 4); + auto blockId = DBUtils::hgtxToHeight(hintRef); + if (blockId == headerPtr->getThisID()) + { + hit = true; + break; + } + } + + if (!hit) + ++missedCount; + } + } + + if (missedCount != 0) + { + LOGERR << "missed " << missedCount << " hashes" << + " in file " << counter; + } + } + }; + + std::vector threads; + LOGINFO << "checking txhints for " << blockFiles_.fileCount() << + " files on " << threadcount << " threads"; + threads.reserve(threadcount); + for (unsigned i=0; i +#ifdef BUILD_PROTOBUF #include - +#endif using namespace std; diff --git a/cppForSwig/ScrAddrFilter.h b/cppForSwig/BlockchainDatabase/ScrAddrFilter.h similarity index 100% rename from cppForSwig/ScrAddrFilter.h rename to cppForSwig/BlockchainDatabase/ScrAddrFilter.h diff --git a/cppForSwig/SshParser.cpp b/cppForSwig/BlockchainDatabase/SshParser.cpp similarity index 100% rename from cppForSwig/SshParser.cpp rename to cppForSwig/BlockchainDatabase/SshParser.cpp diff --git a/cppForSwig/SshParser.h b/cppForSwig/BlockchainDatabase/SshParser.h similarity index 100% rename from cppForSwig/SshParser.h rename to cppForSwig/BlockchainDatabase/SshParser.h diff --git a/cppForSwig/StoredBlockObj.cpp b/cppForSwig/BlockchainDatabase/StoredBlockObj.cpp similarity index 100% rename from cppForSwig/StoredBlockObj.cpp rename to cppForSwig/BlockchainDatabase/StoredBlockObj.cpp diff --git a/cppForSwig/StoredBlockObj.h b/cppForSwig/BlockchainDatabase/StoredBlockObj.h similarity index 100% rename from cppForSwig/StoredBlockObj.h rename to cppForSwig/BlockchainDatabase/StoredBlockObj.h diff --git a/cppForSwig/TxHashFilters.cpp b/cppForSwig/BlockchainDatabase/TxHashFilters.cpp similarity index 100% rename from cppForSwig/TxHashFilters.cpp rename to cppForSwig/BlockchainDatabase/TxHashFilters.cpp diff --git a/cppForSwig/TxHashFilters.h b/cppForSwig/BlockchainDatabase/TxHashFilters.h similarity index 100% rename from cppForSwig/TxHashFilters.h rename to cppForSwig/BlockchainDatabase/TxHashFilters.h diff --git a/cppForSwig/lmdb_wrapper.cpp b/cppForSwig/BlockchainDatabase/lmdb_wrapper.cpp similarity index 99% rename from cppForSwig/lmdb_wrapper.cpp rename to cppForSwig/BlockchainDatabase/lmdb_wrapper.cpp index a4952ab88..f768e8926 100644 --- a/cppForSwig/lmdb_wrapper.cpp +++ b/cppForSwig/BlockchainDatabase/lmdb_wrapper.cpp @@ -39,17 +39,17 @@ using namespace Armory::Config; const set LMDBBlockDatabase::supernodeDBs_({}); const map LMDBBlockDatabase::mapSizes_ = { - {"headers", 4 * 1024 * 1024 * 1024ULL}, - {"blkdata", 1024 * 1024ULL}, - {"history", 1024 * 1024ULL}, - {"txhints", 20 * 1024 * 1024 * 1024ULL}, - {"ssh", 500 * 1024 * 1024 * 1024ULL}, + {"headers", 50 * 1024 * 1024 * 1024ULL}, + {"blkdata", 50 * 1024 * 1024ULL}, + {"history", 50 * 1024 * 1024ULL}, + {"txhints", 50 * 1024 * 1024 * 1024ULL}, + {"ssh", 2000 * 1024 * 1024 * 1024ULL}, {"subssh", 2000 * 1024 * 1024 * 1024ULL}, - {"subssh_meta", 100 * 1024 * 1024ULL}, + {"subssh_meta", 1024 * 1024 * 1024ULL}, {"stxo", 2000 * 1024 * 1024 * 1024ULL}, {"zeroconf", 10 * 1024 * 1024 * 1024ULL}, - {"txfilters", 10 * 1024 * 1024 * 1024ULL}, - {"spentness", 500 * 1024 * 1024 * 1024ULL}, + {"txfilters", 100 * 1024 * 1024 * 1024ULL}, + {"spentness", 2000 * 1024 * 1024 * 1024ULL}, }; //////////////////////////////////////////////////////////////////////////////// @@ -678,7 +678,7 @@ BinaryData LMDBBlockDatabase::getDBKeyForHash(const BinaryData& txhash, return BinaryData(); } - BinaryData hash4(txhash.getSliceRef(0, 4)); + auto hash4 = txhash.getSliceRef(0, 4); auto&& txHints = beginTransaction(TXHINTS, LMDB::ReadOnly); BinaryRefReader brrHints = getValueRef(TXHINTS, DB_PREFIX_TXHINTS, hash4); @@ -1740,8 +1740,10 @@ Tx LMDBBlockDatabase::getFullTxCopy( auto getID = [bhPtr] (const BinaryData&)->uint32_t {return bhPtr->getThisID(); }; - auto block = BlockData::deserialize(dataPtr + bhPtr->getOffset(), - bhPtr->getBlockSize(), bhPtr, getID, false, false); + auto block = BlockData::deserialize( + dataPtr + bhPtr->getOffset(), + bhPtr->getBlockSize(), bhPtr, getID, + BlockData::CheckHashes::NoChecks); const auto& bctx = block->getTxns()[txIndex]; BinaryRefReader brr(bctx->data_, bctx->size_); diff --git a/cppForSwig/lmdb_wrapper.h b/cppForSwig/BlockchainDatabase/lmdb_wrapper.h similarity index 100% rename from cppForSwig/lmdb_wrapper.h rename to cppForSwig/BlockchainDatabase/lmdb_wrapper.h diff --git a/cppForSwig/txio.cpp b/cppForSwig/BlockchainDatabase/txio.cpp similarity index 100% rename from cppForSwig/txio.cpp rename to cppForSwig/BlockchainDatabase/txio.cpp diff --git a/cppForSwig/txio.h b/cppForSwig/BlockchainDatabase/txio.h similarity index 100% rename from cppForSwig/txio.h rename to cppForSwig/BlockchainDatabase/txio.h diff --git a/cppForSwig/BridgeAPI/BridgeMain.cpp b/cppForSwig/BridgeAPI/BridgeMain.cpp index f8561e057..e1a0530ac 100644 --- a/cppForSwig/BridgeAPI/BridgeMain.cpp +++ b/cppForSwig/BridgeAPI/BridgeMain.cpp @@ -1,11 +1,12 @@ //////////////////////////////////////////////////////////////////////////////// // // -// Copyright (C) 2019-20, goatpig // +// Copyright (C) 2019-23, goatpig // // Distributed under the MIT license // // See LICENSE-MIT or https://opensource.org/licenses/MIT // // // //////////////////////////////////////////////////////////////////////////////// +#include #include "BridgeSocket.h" #include "CppBridge.h" @@ -16,14 +17,25 @@ int main(int argc, char* argv[]) startupBIP151CTX(); startupBIP150CTX(4); + unsigned count = argc + 1; + auto args = new char*[count]; + for (int i=0; i( @@ -32,8 +44,6 @@ int main(int argc, char* argv[]) Armory::Config::NetworkSettings::oneWayAuth(), Armory::Config::NetworkSettings::isOffline()); - bridge->startThreads(); - //setup the socket auto sockPtr = std::make_shared( "127.0.0.1", "46122", bridge); @@ -56,8 +66,6 @@ int main(int argc, char* argv[]) //block main thread till socket dies sockPtr->blockUntilClosed(); - bridge->stopThreads(); - //done LOGINFO << "exiting"; diff --git a/cppForSwig/BridgeAPI/BridgeSocket.cpp b/cppForSwig/BridgeAPI/BridgeSocket.cpp index 371dfcc8d..8e99dc554 100755 --- a/cppForSwig/BridgeAPI/BridgeSocket.cpp +++ b/cppForSwig/BridgeAPI/BridgeSocket.cpp @@ -328,21 +328,18 @@ void WritePayload_Bridge::serialize(std::vector& data) return; auto msgSize = message_->ByteSizeLong(); - data.resize(msgSize + 9 + POLY1305MACLEN); + data.resize(msgSize + 5 + POLY1305MACLEN); //set packet size - uint32_t sizeVal = msgSize + 5; + uint32_t sizeVal = msgSize + 1; memcpy(&data[0], &sizeVal, sizeof(uint32_t)); - //set id - memcpy(&data[5], &id_, sizeof(uint32_t)); - //serialize protobuf message - message_->SerializeToArray(&data[9], msgSize); + message_->SerializeToArray(&data[5], msgSize); } //////////////////////////////////////////////////////////////////////////////// size_t WritePayload_Bridge::getSerializedSize(void) const { - return message_->ByteSizeLong() + 9 + POLY1305MACLEN; + return message_->ByteSizeLong() + 5 + POLY1305MACLEN; } diff --git a/cppForSwig/BridgeAPI/CppBridge.cpp b/cppForSwig/BridgeAPI/CppBridge.cpp index 0634da091..7ecc22a07 100755 --- a/cppForSwig/BridgeAPI/CppBridge.cpp +++ b/cppForSwig/BridgeAPI/CppBridge.cpp @@ -10,7 +10,7 @@ #include "BridgeSocket.h" #include "TerminalPassphrasePrompt.h" #include "PassphrasePrompt.h" -#include "../ArmoryBackups.h" +#include "../Wallets/Seeds/Backups.h" #include "ProtobufConversions.h" #include "ProtobufCommandParser.h" #include "../Signer/ResolverFeed_Wallets.h" @@ -19,7 +19,7 @@ using namespace std; using namespace ::google::protobuf; -using namespace ::Codec_ClientProto; +using namespace ::BridgeProto; using namespace Armory::Threading; using namespace Armory::Signer; using namespace Armory::Wallets; @@ -32,9 +32,9 @@ enum CppBridgeState CppBridge_Registered }; -#define BRIDGE_CALLBACK_BDM UINT32_MAX -#define BRIDGE_CALLBACK_PROGRESS UINT32_MAX - 1 -#define DISCONNECTED_CALLBACK_ID 0xff543ad8 +#define BRIDGE_CALLBACK_BDM "bdm_callback" +#define BRIDGE_CALLBACK_PROGRESS "progress" +#define DISCONNECTED_CALLBACK_ID "disconnected" //////////////////////////////////////////////////////////////////////////////// //// @@ -45,30 +45,7 @@ CppBridge::CppBridge(const string& path, const string& dbAddr, const string& dbPort, bool oneWayAuth, bool offline) : path_(path), dbAddr_(dbAddr), dbPort_(dbPort), dbOneWayAuth_(oneWayAuth), dbOffline_(offline) -{ - commandWithCallbackQueue_ = make_shared< - Armory::Threading::BlockingQueue>(); -} - -//////////////////////////////////////////////////////////////////////////////// -void CppBridge::startThreads() -{ - auto commandLbd = [this]() - { - this->processCommandWithCallbackThread(); - }; - - commandWithCallbackProcessThread_ = thread(commandLbd); -} - -//////////////////////////////////////////////////////////////////////////////// -void CppBridge::stopThreads() -{ - commandWithCallbackQueue_->terminate(); - - if (commandWithCallbackProcessThread_.joinable()) - commandWithCallbackProcessThread_.join(); -} +{} //////////////////////////////////////////////////////////////////////////////// bool CppBridge::processData(BinaryDataRef socketData) @@ -77,165 +54,37 @@ bool CppBridge::processData(BinaryDataRef socketData) } //////////////////////////////////////////////////////////////////////////////// -void CppBridge::queueCommandWithCallback(ClientCommand msg) -{ - commandWithCallbackQueue_->push_back(move(msg)); -} - -//////////////////////////////////////////////////////////////////////////////// -void CppBridge::processCommandWithCallbackThread() -{ - /*** - This class of methods needs to interact several times with the user in the - course of their lifetime. A dedicated callback object to keep track of the - methods running thread and set of callbacks awaiting a return. - ***/ - - while (true) - { - ClientCommand msg; - try - { - msg = move(commandWithCallbackQueue_->pop_front()); - } - catch (const StopBlockingLoop&) - { - break; - } - - BinaryDataRef opaqueRef; - if (msg.byteargs_size() < 2) - { - //msg has to carry a callback id - if (msg.byteargs_size() == 0) - throw runtime_error("malformed command"); - } - else - { - //grab opaque data - opaqueRef.setRef(msg.byteargs(1)); - } - - //grab callback id - BinaryDataRef callbackId; - callbackId.setRef(msg.byteargs(0)); - - auto getCallbackHandler = [this, &callbackId]()-> - shared_ptr - { - //grab the callback handler, add to map if missing - auto iter = callbackHandlerMap_.find(callbackId); - if (iter == callbackHandlerMap_.end()) - { - auto insertIter = callbackHandlerMap_.emplace( - callbackId, make_shared( - callbackId, commandWithCallbackQueue_)); - - iter = insertIter.first; - } - - return iter->second; - }; - - auto deleteCallbackHandler = [this, &callbackId]() - { - callbackHandlerMap_.erase(callbackId); - }; - - //process the commands - try - { - switch (msg.methodwithcallback()) - { - case MethodsWithCallback::followUp: - { - //this is a reply to an existing callback - if (msg.intargs_size() == 0) - throw runtime_error("missing callback arguments"); - - auto handler = getCallbackHandler(); - handler->processCallbackReply(msg.intargs(0), opaqueRef); - break; - } - - case MethodsWithCallback::cleanup: - { - //caller is done, cleanup callbacks entry from map - deleteCallbackHandler(); - break; - } - - /* - Entry point to the methods, they will populate their respective - callbacks object with lambdas to process the returned values - */ - case MethodsWithCallback::restoreWallet: - { - auto handler = getCallbackHandler(); - restoreWallet(opaqueRef, handler); - break; - } - - default: - throw runtime_error("unknown command"); - } - } - catch (const exception& e) - { - //make sure to cleanup the callback map entry on throws - deleteCallbackHandler(); - - //rethrow so that the caller can handle the error - throw e; - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -void CppBridge::writeToClient(BridgeReply msgPtr, unsigned id) const +void CppBridge::writeToClient(BridgePayload msgPtr) const { auto payload = make_unique(); payload->message_ = move(msgPtr); - payload->id_ = id; writeLambda_(move(payload)); } //////////////////////////////////////////////////////////////////////////////// -PassphraseLambda CppBridge::createPassphrasePrompt(UnlockPromptType promptType) +void CppBridge::callbackWriter(ServerPushWrapper& wrapper) { - unique_lock lock(passPromptMutex_); - auto&& id = fortuna_.generateRandom(6).toHexStr(); - auto passPromptObj = make_shared(id, writeLambda_); - - promptMap_.insert(make_pair(id, passPromptObj)); - return passPromptObj->getLambda(promptType); + setCallbackHandler(wrapper); + writeToClient(move(wrapper.payload)); } //////////////////////////////////////////////////////////////////////////////// -bool CppBridge::returnPassphrase( - const string& promptId, const string& passphrase) -{ - unique_lock lock(passPromptMutex_); - auto iter = promptMap_.find(promptId); - if (iter == promptMap_.end()) - return false; - - iter->second->setReply(passphrase); - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -void CppBridge::loadWallets(unsigned id) +void CppBridge::loadWallets(const string& callbackId, unsigned referenceId) { if (wltManager_ != nullptr) return; - auto thrLbd = [this, id](void)->void + auto thrLbd = [this, callbackId, referenceId](void)->void { - auto lbd = createPassphrasePrompt(UnlockPromptType::migrate); + auto passPromptObj = make_shared( + callbackId, [this](ServerPushWrapper wrapper){ + this->callbackWriter(wrapper); + }); + auto lbd = passPromptObj->getLambda(); wltManager_ = make_shared(path_, lbd); - auto response = move(createWalletsPacket()); - writeToClient(move(response), id); + auto response = createWalletsPacket(); + response->mutable_reply()->set_reference_id(referenceId); + writeToClient(move(response)); }; thread thr(thrLbd); @@ -244,9 +93,20 @@ void CppBridge::loadWallets(unsigned id) } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::createWalletsPacket() +WalletPtr CppBridge::getWalletPtr(const string& wltId) const { - auto response = make_unique(); + auto wai = WalletAccountIdentifier::deserialize(wltId); + auto wltContainer = wltManager_->getWalletContainer( + wai.walletId, wai.accountId); + return wltContainer->getWalletPtr(); +} + +//////////////////////////////////////////////////////////////////////////////// +BridgePayload CppBridge::createWalletsPacket() +{ + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + auto walletProto = reply->mutable_wallet()->mutable_multiple_wallets(); //grab wallet map auto accountIdMap = wltManager_->getAccountIdMap(); @@ -265,12 +125,13 @@ BridgeReply CppBridge::createWalletsPacket() auto wltContainer = wltManager_->getWalletContainer( idIt.first, accId); - auto payload = response->add_wallets(); + auto payload = walletProto->add_wallet(); CppToProto::wallet(payload, wltPtr, accId, commentMap); } } - return response; + reply->set_success(true); + return payload; } //////////////////////////////////////////////////////////////////////////////// @@ -309,9 +170,9 @@ void CppBridge::setupDB() throw runtime_error("wallet manager is not initialized"); //lambda to push notifications over to the gui socket - auto pushNotif = [this](BridgeReply msg, unsigned id)->void + auto pushNotif = [this](BridgePayload msg)->void { - this->writeToClient(move(msg), id); + this->writeToClient(move(msg)); }; //setup bdv obj @@ -396,63 +257,102 @@ void CppBridge::registerWallet(const string& id, bool isNew) } //////////////////////////////////////////////////////////////////////////////// -void CppBridge::createBackupStringForWallet( - const string& id, unsigned msgId) +void CppBridge::createBackupStringForWallet(const string& waaId, + const string& callbackId, unsigned msgId) { - auto passLbd = createPassphrasePrompt(UnlockPromptType::decrypt); - auto wai = WalletAccountIdentifier::deserialize(id); + auto wai = WalletAccountIdentifier::deserialize(waaId); const auto& walletId = wai.walletId; - auto backupStringLbd = [this, walletId, msgId, passLbd]()->void + auto backupStringLbd = [this, walletId, msgId, callbackId]()->void { - Armory::Backups::WalletBackup backupData; + auto passPromptObj = make_shared( + callbackId, [this](ServerPushWrapper wrapper){ + this->callbackWriter(wrapper); + }); + auto lbd = passPromptObj->getLambda(); + + unique_ptr backupData = nullptr; try { //grab wallet auto wltContainer = wltManager_->getWalletContainer(walletId); //grab root - backupData = move(wltContainer->getBackupStrings(passLbd)); + backupData = move(wltContainer->getBackupStrings(lbd)); } catch (const exception&) {} //wind down passphrase prompt - passLbd({BridgePassphrasePrompt::concludeKey}); + passPromptObj->cleanup(); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_reference_id(msgId); - if (backupData.rootClear_.empty()) + if (backupData == nullptr) { //return on error - auto result = make_unique(); - result->set_isvalid(false); - writeToClient(move(result), msgId); + reply->set_success(false); + writeToClient(move(payload)); return; } - auto backupStringProto = make_unique(); - - for (auto& line : backupData.rootClear_) - backupStringProto->add_rootclear(line); + auto backupE16 = dynamic_cast( + backupData.get()); + if (backupE16 == nullptr) + { + throw runtime_error("[createBackupStringForWallet]" + " invalid backup type"); + } - for (auto& line : backupData.rootEncr_) - backupStringProto->add_rootencr(line); + auto backupStringProto = reply->mutable_wallet()->mutable_backup_string(); - if (!backupData.chaincodeClear_.empty()) + //cleartext root { - for (auto& line : backupData.chaincodeClear_) - backupStringProto->add_chainclear(line); + auto line1 = backupE16->getRoot( + Armory::Seeds::Backup_Easy16::LineIndex::One, false); + backupStringProto->add_root_clear(line1.data(), line1.size()); + auto line2 = backupE16->getRoot( + Armory::Seeds::Backup_Easy16::LineIndex::Two, false); + backupStringProto->add_root_clear(line2.data(), line2.size()); + + //encrypted root + auto line3 = backupE16->getRoot( + Armory::Seeds::Backup_Easy16::LineIndex::One, true); + backupStringProto->add_root_encr(line3.data(), line3.size()); + auto line4 = backupE16->getRoot( + Armory::Seeds::Backup_Easy16::LineIndex::Two, true); + backupStringProto->add_root_encr(line3.data(), line3.size()); + } - for (auto& line : backupData.chaincodeEncr_) - backupStringProto->add_chainencr(line); + if (backupE16->hasChaincode()) + { + //cleartext chaincode + auto line1 = backupE16->getChaincode( + Armory::Seeds::Backup_Easy16::LineIndex::One, false); + backupStringProto->add_chain_clear(line1.data(), line1.size()); + + auto line2 = backupE16->getChaincode( + Armory::Seeds::Backup_Easy16::LineIndex::Two, false); + backupStringProto->add_chain_clear(line2.data(), line2.size()); + + //encrypted chaincode + auto line3 = backupE16->getChaincode( + Armory::Seeds::Backup_Easy16::LineIndex::One, true); + backupStringProto->add_chain_encr(line3.data(), line3.size()); + + auto line4 = backupE16->getChaincode( + Armory::Seeds::Backup_Easy16::LineIndex::Two, true); + backupStringProto->add_chain_encr(line4.data(), line4.size()); } //secure print passphrase - backupStringProto->set_sppass( - backupData.spPass_.toCharPtr(), backupData.spPass_.getSize()); - - //return to client - backupStringProto->set_isvalid(true); - writeToClient(move(backupStringProto), msgId); + auto spPass = backupE16->getSpPass(); + backupStringProto->set_sp_pass(spPass.data(), spPass.size()); + + reply->set_success(true); + writeToClient(move(payload)); }; thread thr(backupStringLbd); @@ -461,8 +361,7 @@ void CppBridge::createBackupStringForWallet( } //////////////////////////////////////////////////////////////////////////////// -void CppBridge::restoreWallet( - const BinaryDataRef& msgRef, shared_ptr handler) +void CppBridge::restoreWallet(const BinaryDataRef& msgRef) { /* Needs 2 lines for the root, possibly another 2 for the chaincode, possibly @@ -480,12 +379,13 @@ void CppBridge::restoreWallet( throw runtime_error("[restoreWallet] invalid root lines count"); // - auto restoreLbd = [this, handler](RestoreWalletPayload msg) + #if 0 + auto restoreLbd = [this](RestoreWalletPayload msg) { - auto createCallbackMessage = [handler]( - int promptType, - const vector chkResults, - SecureBinaryData& extra)->unique_ptr + auto createCallbackMessage = []( + int promptType, + const vector chkResults, + SecureBinaryData& extra)->unique_ptr { RestorePrompt opaqueMsg; opaqueMsg.set_prompttype((RestorePromptType)promptType); @@ -496,26 +396,28 @@ void CppBridge::restoreWallet( opaqueMsg.set_extra(extra.toCharPtr(), extra.getSize()); //wrap in opaque payload - auto callbackMsg = make_unique(); - callbackMsg->set_payloadtype(OpaquePayloadType::commandWithCallback); - callbackMsg->set_uniqueid( - handler->id().getPtr(), handler->id().getSize()); + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id( + handler->id().getCharPtr(), handler->id().getSize()); + + /*callbackMsg->set_payloadtype(OpaquePayloadType::commandWithCallback); string serializedOpaqueData; opaqueMsg.SerializeToString(&serializedOpaqueData); - callbackMsg->set_payload(serializedOpaqueData); + callbackMsg->set_payload(serializedOpaqueData);*/ - return callbackMsg; + return payload; }; auto callback = [this, handler, createCallbackMessage]( - Armory::Backups::RestorePromptType promptType, - const vector chkResults, + Armory::Backups::RestorePromptType promptType, + const vector chkResults, SecureBinaryData& extra)->bool { //convert prompt args to protobuf - auto callbackMsg = - createCallbackMessage(promptType, chkResults, extra); + auto callbackMsg = createCallbackMessage( + promptType, chkResults, extra); //setup reply lambda auto prom = make_shared>(); @@ -526,10 +428,9 @@ void CppBridge::restoreWallet( }; //register reply lambda will callbacks handler - auto callbackId = handler->addCallback(replyLbd); - callbackMsg->set_intid(callbackId); - - writeToClient(move(callbackMsg), BRIDGE_CALLBACK_PROMPTUSER); + //auto callbackId = handler->addCallback(replyLbd); + //callbackMsg->mutable_callback()->set_callback_id(callbackId); + writeToClient(move(callbackMsg)); //wait on reply auto&& data = fut.get(); @@ -580,7 +481,9 @@ void CppBridge::restoreWallet( SecureBinaryData dummy; auto successMsg = createCallbackMessage( RestorePromptType::Success, {}, dummy); - writeToClient(move(successMsg), BRIDGE_CALLBACK_PROMPTUSER); + successMsg->mutable_callback()->set_callback_id( + BRIDGE_CALLBACK_PROMPTUSER); + writeToClient(move(successMsg)); } catch (const Armory::Backups::RestoreUserException& e) { @@ -600,26 +503,32 @@ void CppBridge::restoreWallet( Report error to client. This will catch throws in the callbacks reply handler too. */ - auto errorMsg = make_unique(); + /*auto errorMsg = make_unique(); errorMsg->set_payloadtype(OpaquePayloadType::commandWithCallback); errorMsg->set_uniqueid( handler->id().getPtr(), handler->id().getSize()); errorMsg->set_intid(UINT32_MAX); //error flag - - ReplyStrings errorVerbose; + + BridgeProto::Strings errorVerbose; errorVerbose.add_reply(e.what()); string serializedOpaqueData; errorVerbose.SerializeToString(&serializedOpaqueData); - errorMsg->set_payload(serializedOpaqueData); - - writeToClient(move(errorMsg), BRIDGE_CALLBACK_PROMPTUSER); + errorMsg->set_payload(serializedOpaqueData);*/ + + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id( + handler->id().toCharPtr(), handler->id().getSize()); + callback->set_error(e.what()); + writeToClient(move(payload)); } handler->flagForCleanup(); }; + #endif - handler->methodThr_ = thread(restoreLbd, move(msg)); + //handler->methodThr_ = thread(restoreLbd, move(msg)); } //////////////////////////////////////////////////////////////////////////////// @@ -669,7 +578,7 @@ const string& CppBridge::getLedgerDelegateIdForScrAddr( //////////////////////////////////////////////////////////////////////////////// void CppBridge::getHistoryPageForDelegate( - const std::string& id, unsigned pageId, unsigned msgId) + const string& id, unsigned pageId, unsigned msgId) { auto iter = delegateMap_.find(id); if (iter == delegateMap_.end()) @@ -679,21 +588,52 @@ void CppBridge::getHistoryPageForDelegate( ReturnMessage> result)->void { auto&& leVec = result.get(); - auto msgProto = make_unique(); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); + + auto ledgers = reply->mutable_service()->mutable_ledger_history(); for (auto& le : leVec) { - auto leProto = msgProto->add_le(); + auto leProto = ledgers->add_ledger(); CppToProto::ledger(leProto, le); } - this->writeToClient(move(msgProto), msgId); + this->writeToClient(move(payload)); }; iter->second.getHistoryPage(pageId, lbd); } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getNodeStatus() +void CppBridge::getHistoryForWalletSelection( + const string& order, vector wltIds, unsigned msgId) +{ + auto lbd = [this, msgId]( + ReturnMessage> result)->void + { + auto&& leVec = result.get(); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); + + auto ledgers = reply->mutable_service()->mutable_ledger_history(); + for (auto& le : leVec) + { + auto leProto = ledgers->add_ledger(); + CppToProto::ledger(leProto, le); + } + + this->writeToClient(move(payload)); + }; + + bdvPtr_->getHistoryForWalletSelection(wltIds, order, lbd); +} + +//////////////////////////////////////////////////////////////////////////////// +BridgePayload CppBridge::getNodeStatus() { //grab node status auto promPtr = make_shared< @@ -714,80 +654,97 @@ BridgeReply CppBridge::getNodeStatus() }; bdvPtr_->getNodeStatus(lbd); - auto msg = make_unique(); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); try { auto nodeStatus = fut.get(); - + //create protobuf message - CppToProto::nodeStatus(msg.get(), *nodeStatus); + CppToProto::nodeStatus( + reply->mutable_service()->mutable_node_status(), *nodeStatus); + reply->set_success(true); } - catch(exception&) + catch (const exception&) { - msg->set_isvalid(false); + reply->set_success(false); } - return msg; + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getBalanceAndCount(const string& id) +BridgePayload CppBridge::getBalanceAndCount(const string& id) { auto wai = WalletAccountIdentifier::deserialize(id); auto wltContainer = wltManager_->getWalletContainer( wai.walletId, wai.accountId); - auto msg = make_unique(); - msg->set_full(wltContainer->getFullBalance()); - msg->set_spendable(wltContainer->getSpendableBalance()); - msg->set_unconfirmed(wltContainer->getUnconfirmedBalance()); - msg->set_count(wltContainer->getTxIOCount()); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + + auto balance = reply->mutable_wallet()->mutable_balance_and_count(); + balance->set_full(wltContainer->getFullBalance()); + balance->set_spendable(wltContainer->getSpendableBalance()); + balance->set_unconfirmed(wltContainer->getUnconfirmedBalance()); + balance->set_count(wltContainer->getTxIOCount()); - return msg; + reply->set_success(true); + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getAddrCombinedList(const string& id) +BridgePayload CppBridge::getAddrCombinedList(const string& id) { auto wai = WalletAccountIdentifier::deserialize(id); auto wltContainer = wltManager_->getWalletContainer( wai.walletId, wai.accountId); auto addrMap = wltContainer->getAddrBalanceMap(); - auto msg = make_unique(); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + + auto aabData = reply->mutable_wallet()->mutable_address_and_balance_data(); for (auto& addrPair : addrMap) { - auto data = msg->add_data(); - data->set_full(addrPair.second[0]); - data->set_spendable(addrPair.second[1]); - data->set_unconfirmed(addrPair.second[2]); - data->set_count(addrPair.second[3]); - - msg->add_ids( - addrPair.first.toCharPtr(), addrPair.first.getSize()); + auto addr = aabData->add_balance(); + addr->set_id(addrPair.first.toCharPtr(), addrPair.first.getSize()); + + auto balance = addr->mutable_balance(); + balance->set_full(addrPair.second[0]); + balance->set_spendable(addrPair.second[1]); + balance->set_unconfirmed(addrPair.second[2]); + balance->set_count(addrPair.second[3]); } - auto&& updatedMap = wltContainer->getUpdatedAddressMap(); + auto updatedMap = wltContainer->getUpdatedAddressMap(); auto accPtr = wltContainer->getAddressAccount(); for (auto& addrPair : updatedMap) { - auto newAsset = msg->add_updatedassets(); - CppToProto::addr(newAsset, addrPair.second, accPtr); + auto newAsset = aabData->add_updated_asset(); + CppToProto::addr(newAsset, addrPair.second, accPtr, + wltContainer->getDefaultEncryptionKeyId()); } - return msg; + reply->set_success(true); + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getHighestUsedIndex(const string& id) +BridgePayload CppBridge::getHighestUsedIndex(const string& id) { auto wai = WalletAccountIdentifier::deserialize(id); auto wltContainer = wltManager_->getWalletContainer( wai.walletId, wai.accountId); - auto msg = make_unique(); - msg->add_ints(wltContainer->getHighestUsedIndex()); - return msg; + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_wallet()->set_highest_used_index( + wltContainer->getHighestUsedIndex()); + return payload; } //////////////////////////////////////////////////////////////////////////////// @@ -828,29 +785,42 @@ void CppBridge::extendAddressPool(const string& wltId, reportedTicks = eventCount; float progressFloat = float(tickCount) / float(tickTotal); - auto msg = make_unique(); - msg->set_progress(progressFloat); - msg->set_progressnumeric(tickCount); - msg->add_ids(callbackId); + auto payloadProgess = make_unique(); + auto callbackProgress = payloadProgess->mutable_callback(); + callbackProgress->set_callback_id(BRIDGE_CALLBACK_PROGRESS); - this->writeToClient(move(msg), BRIDGE_CALLBACK_PROGRESS); + auto progressProto = callbackProgress->mutable_progress(); + progressProto->set_progress(progressFloat); + progressProto->set_progress_numeric(tickCount); + progressProto->add_id(callbackId); + + this->writeToClient(move(payloadProgess)); }; //extend chain accPtr->extendPublicChain(wltPtr->getIface(), count, updateProgress); //shutdown progress dialog - auto msgProgress = make_unique(); - msgProgress->set_progress(0); - msgProgress->set_progressnumeric(0); - msgProgress->set_phase(BDMPhase_Completed); - msgProgress->add_ids(callbackId); - this->writeToClient(move(msgProgress), BRIDGE_CALLBACK_PROGRESS); + auto payloadProgess = make_unique(); + auto callbackProgress = payloadProgess->mutable_callback(); + callbackProgress->set_callback_id(BRIDGE_CALLBACK_PROGRESS); + + auto progressProto = callbackProgress->mutable_progress(); + progressProto->set_progress(0); + progressProto->set_progress_numeric(0); + progressProto->set_phase(BDMPhase_Completed); + progressProto->add_id(callbackId); + this->writeToClient(move(payloadProgess)); //complete process - auto msgComplete = make_unique(); - CppToProto::wallet(msgComplete.get(), wltPtr, accId, {}); - this->writeToClient(move(msgComplete), msgId); + auto payloadComplete = make_unique(); + auto reply = payloadComplete->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); + + auto walletProto = reply->mutable_wallet()->mutable_wallet_data(); + CppToProto::wallet(walletProto, wltPtr, accId, {}); + this->writeToClient(move(payloadComplete)); }; thread thr(extendChain); @@ -859,24 +829,18 @@ void CppBridge::extendAddressPool(const string& wltId, } //////////////////////////////////////////////////////////////////////////////// -string CppBridge::createWallet(const ClientCommand& msg) +string CppBridge::createWallet( + const Utils::CreateWalletStruct& createWalletProto) { if (wltManager_ == nullptr) throw runtime_error("wallet manager is not initialized"); - if (msg.byteargs_size() != 1) - throw runtime_error("invalid create wallet payload"); - - BridgeCreateWalletStruct createWalletProto; - if (!createWalletProto.ParseFromString(msg.byteargs(0))) - throw runtime_error("failed to read create wallet protobuf message"); - //extra entropy SecureBinaryData extraEntropy; - if (createWalletProto.has_extraentropy()) + if (createWalletProto.has_extra_entropy()) { extraEntropy = SecureBinaryData::fromString( - createWalletProto.extraentropy()); + createWalletProto.extra_entropy()); } //passphrase @@ -889,10 +853,10 @@ string CppBridge::createWallet(const ClientCommand& msg) //control passphrase SecureBinaryData controlPass; - if (createWalletProto.has_controlpassphrase()) + if (createWalletProto.has_control_passphrase()) { controlPass = SecureBinaryData::fromString( - createWalletProto.controlpassphrase()); + createWalletProto.control_passphrase()); } //lookup @@ -914,22 +878,27 @@ string CppBridge::createWallet(const ClientCommand& msg) } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getWalletPacket(const string& id) const +BridgePayload CppBridge::getWalletPacket(const string& id) const { auto wai = WalletAccountIdentifier::deserialize(id); auto wltContainer = wltManager_->getWalletContainer( wai.walletId, wai.accountId); - auto response = make_unique(); + auto wltPtr = wltContainer->getWalletPtr(); auto commentMap = wltPtr->getCommentMap(); - auto payload = response->add_wallets(); - CppToProto::wallet(payload, wltPtr, wai.accountId, commentMap); - return move(response); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + auto walletProto = reply->mutable_wallet()->mutable_wallet_data(); + CppToProto::wallet(walletProto, wltPtr, wai.accountId, commentMap); + + return move(payload); } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getNewAddress(const string& id, unsigned type) +BridgePayload CppBridge::getNewAddress(const string& id, unsigned type) { auto wai = WalletAccountIdentifier::deserialize(id); auto wltContainer = wltManager_->getWalletContainer( @@ -939,13 +908,18 @@ BridgeReply CppBridge::getNewAddress(const string& id, unsigned type) auto addrPtr = accPtr->getNewAddress( wltPtr->getIface(), (AddressEntryType)type); - auto msg = make_unique(); - CppToProto::addr(msg.get(), addrPtr, accPtr); - return msg; + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + auto addrProto = reply->mutable_wallet()->mutable_address_data(); + CppToProto::addr(addrProto, addrPtr, accPtr, + wltContainer->getDefaultEncryptionKeyId()); + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getChangeAddress(const string& id, unsigned type) +BridgePayload CppBridge::getChangeAddress(const string& id, unsigned type) { auto wai = WalletAccountIdentifier::deserialize(id); auto wltContainer = wltManager_->getWalletContainer( @@ -955,13 +929,18 @@ BridgeReply CppBridge::getChangeAddress(const string& id, unsigned type) auto addrPtr = accPtr->getNewChangeAddress( wltPtr->getIface(), (AddressEntryType)type); - auto msg = make_unique(); - CppToProto::addr(msg.get(), addrPtr, accPtr); - return msg; + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + auto addrProto = reply->mutable_wallet()->mutable_address_data(); + CppToProto::addr(addrProto, addrPtr, accPtr, + wltContainer->getDefaultEncryptionKeyId()); + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::peekChangeAddress(const string& id, unsigned type) +BridgePayload CppBridge::peekChangeAddress(const string& id, unsigned type) { auto wai = WalletAccountIdentifier::deserialize(id); auto wltContainer = wltManager_->getWalletContainer( @@ -971,17 +950,22 @@ BridgeReply CppBridge::peekChangeAddress(const string& id, unsigned type) auto addrPtr = accPtr->getNewChangeAddress( wltPtr->getIface(), (AddressEntryType)type); - auto msg = make_unique(); - CppToProto::addr(msg.get(), addrPtr, accPtr); - return msg; + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + auto addrProto = reply->mutable_wallet()->mutable_address_data(); + CppToProto::addr(addrProto, addrPtr, accPtr, + wltContainer->getDefaultEncryptionKeyId()); + return payload; } //////////////////////////////////////////////////////////////////////////////// -void CppBridge::getTxByHash(const BinaryData& hash, unsigned msgid) +void CppBridge::getTxByHash(const BinaryData& hash, unsigned msgId) { - auto lbd = [this, msgid](ReturnMessage result)->void + auto lbd = [this, msgId](ReturnMessage result)->void { - shared_ptr tx; + shared_ptr tx; bool valid = false; try { @@ -991,124 +975,164 @@ void CppBridge::getTxByHash(const BinaryData& hash, unsigned msgid) } catch(exception&) {} - - auto msg = make_unique(); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_reference_id(msgId); if (valid) { - auto&& txRaw = tx->serialize(); - msg->set_raw(txRaw.getCharPtr(), txRaw.getSize()); - msg->set_isrbf(tx->isRBF()); - msg->set_ischainedzc(tx->isChained()); - msg->set_height(tx->getTxHeight()); - msg->set_txindex(tx->getTxIndex()); - msg->set_isvalid(true); + auto txRaw = tx->serialize(); + + auto txProto = reply->mutable_service()->mutable_tx(); + txProto->set_raw(txRaw.getCharPtr(), txRaw.getSize()); + txProto->set_rbf(tx->isRBF()); + txProto->set_chained_zc(tx->isChained()); + txProto->set_height(tx->getTxHeight()); + txProto->set_tx_index(tx->getTxIndex()); + reply->set_success(true); } else { - msg->set_isvalid(false); + reply->set_success(false); } - - this->writeToClient(move(msg), msgid); + + this->writeToClient(move(payload)); }; bdvPtr_->getTxByHash(hash, lbd); } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getTxInScriptType( +BridgePayload CppBridge::getTxInScriptType( const BinaryData& script, const BinaryData& hash) const { - auto msg = make_unique(); - msg->add_ints(BtcUtils::getTxInScriptTypeInt(script, hash)); - return msg; + auto typeInt = BtcUtils::getTxInScriptTypeInt(script, hash); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_script_utils()->set_txin_script_type(typeInt); + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getTxOutScriptType( - const BinaryData& script) const +BridgePayload CppBridge::getTxOutScriptType(const BinaryData& script) const { - auto msg = make_unique(); - msg->add_ints(BtcUtils::getTxOutScriptTypeInt(script)); - return msg; + auto typeInt = BtcUtils::getTxOutScriptTypeInt(script); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_script_utils()->set_txout_script_type(typeInt); + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getScrAddrForScript( +BridgePayload CppBridge::getScrAddrForScript( const BinaryData& script) const { - auto msg = make_unique(); - auto&& resultBd = BtcUtils::getScrAddrForScript(script); - msg->add_reply(resultBd.toCharPtr(), resultBd.getSize()); - return msg; + auto resultBd = BtcUtils::getScrAddrForScript(script); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_script_utils()->set_scraddr( + resultBd.toCharPtr(), resultBd.getSize()); + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getScrAddrForAddrStr(const string& addrStr) const +BridgePayload CppBridge::getScrAddrForAddrStr(const string& addrStr) const { + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + try { - auto msg = make_unique(); auto resultBd = BtcUtils::getScrAddrForAddrStr(addrStr); - msg->add_reply(resultBd.toCharPtr(), resultBd.getSize()); - return msg; + reply->set_success(true); + reply->mutable_utils()->set_scraddr( + resultBd.toCharPtr(), resultBd.getSize()); } catch (const exception& e) { - auto msg = make_unique(); - msg->set_iserror(true); - msg->set_error(e.what()); - return msg; + reply->set_success(false); + reply->set_error(e.what()); } + + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getLastPushDataInScript( - const BinaryData& script) const +BridgePayload CppBridge::getLastPushDataInScript(const BinaryData& script) const { - auto msg = make_unique(); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); auto result = BtcUtils::getLastPushDataInScript(script); - if (!result.empty()) - msg->add_reply(result.getCharPtr(), result.getSize()); - return msg; + if (result.empty()) + { + reply->set_success(false); + } + else + { + reply->set_success(true); + reply->mutable_script_utils()->set_push_data( + result.getCharPtr(), result.getSize()); + } + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getHash160(const BinaryDataRef& dataRef) const +BridgePayload CppBridge::getHash160(const BinaryDataRef& dataRef) const { - auto&& hash = BtcUtils::getHash160(dataRef); - auto msg = make_unique(); - msg->add_reply(hash.getCharPtr(), hash.getSize()); - return msg; + auto hash = BtcUtils::getHash160(dataRef); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_utils()->set_hash(hash.getCharPtr(), hash.getSize()); + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getTxOutScriptForScrAddr( - const BinaryData& script) const +BridgePayload CppBridge::getTxOutScriptForScrAddr(const BinaryData& script) const { - auto msg = make_unique(); - auto&& resultBd = BtcUtils::getTxOutScriptForScrAddr(script); - msg->add_reply(resultBd.toCharPtr(), resultBd.getSize()); - return msg; + auto resultBd = BtcUtils::getTxOutScriptForScrAddr(script); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_script_utils()->set_script_data( + resultBd.toCharPtr(), resultBd.getSize()); + return payload; } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::getAddrStrForScrAddr( - const BinaryData& script) const +BridgePayload CppBridge::getAddrStrForScrAddr(const BinaryData& script) const { + auto payload = make_unique(); try { - auto msg = make_unique(); - auto&& resultStr = BtcUtils::getAddressStrFromScrAddr(script); - msg->add_reply(resultStr); - return msg; + auto addrStr = BtcUtils::getAddressStrFromScrAddr(script); + + auto reply = payload->mutable_reply(); + reply->set_success(true); + auto scriptUtilsReply = reply->mutable_script_utils(); + scriptUtilsReply->set_address_string(addrStr); } catch (const exception& e) { - auto msg = make_unique(); - msg->set_iserror(true); - msg->set_error(e.what()); - return msg; + auto reply = payload->mutable_reply(); + reply->set_success(false); + reply->set_error(e.what()); } + + return payload; } //////////////////////////////////////////////////////////////////////////////// @@ -1175,7 +1199,7 @@ string CppBridge::getNameForAddrType(int addrTypeInt) const } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::setAddressTypeFor( +BridgePayload CppBridge::setAddressTypeFor( const string& walletId, const string& assetIdStr, uint32_t addrType) const { auto wai = WalletAccountIdentifier::deserialize(walletId); @@ -1183,9 +1207,9 @@ BridgeReply CppBridge::setAddressTypeFor( wai.walletId, wai.accountId); auto wltPtr = wltContainer->getWalletPtr(); - BinaryDataRef bdr; bdr.setRef(assetIdStr); + auto idRef = BinaryDataRef::fromString(assetIdStr); auto assetId = Armory::Wallets::AssetId::deserializeKey( - bdr, PROTO_ASSETID_PREFIX); + idRef, PROTO_ASSETID_PREFIX); //set address type in wallet wltPtr->updateAddressEntryType(assetId, (AddressEntryType)addrType); @@ -1195,21 +1219,31 @@ BridgeReply CppBridge::setAddressTypeFor( auto addrPtr = accPtr->getAddressEntryForID(assetId); //return address proto payload - auto result = make_unique(); - CppToProto::addr(result.get(), addrPtr, accPtr); - return result; + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + auto addrProto = reply->mutable_wallet()->mutable_address_data(); + CppToProto::addr(addrProto, addrPtr, accPtr, + wltContainer->getDefaultEncryptionKeyId()); + return payload; } //////////////////////////////////////////////////////////////////////////////// -void CppBridge::getHeaderByHeight(unsigned height, unsigned msgid) +void CppBridge::getHeaderByHeight(unsigned height, unsigned msgId) { - auto lbd = [this, msgid](ReturnMessage result)->void + auto lbd = [this, msgId](ReturnMessage result)->void { auto headerRaw = result.get(); - auto msg = make_unique(); - msg->add_reply(headerRaw.getCharPtr(), headerRaw.getSize()); - - this->writeToClient(move(msg), msgid); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); + + reply->mutable_service()->set_header_data( + headerRaw.getCharPtr(), headerRaw.getSize()); + this->writeToClient(move(payload)); }; bdvPtr_->getHeaderByHeight(height, lbd); @@ -1217,7 +1251,7 @@ void CppBridge::getHeaderByHeight(unsigned height, unsigned msgid) //////////////////////////////////////////////////////////////////////////////// void CppBridge::setupNewCoinSelectionInstance(const string& id, - unsigned height, unsigned msgid) + unsigned height, unsigned msgId) { auto wai = WalletAccountIdentifier::deserialize(id); auto wltContainer = wltManager_->getWalletContainer( @@ -1228,8 +1262,8 @@ void CppBridge::setupNewCoinSelectionInstance(const string& id, make_pair(csId, shared_ptr())).first; auto csPtr = &insertIter->second; - auto lbd = [this, wltContainer, csPtr, csId, height, msgid]( - ReturnMessage> result)->void + auto lbd = [this, wltContainer, csPtr, csId, height, msgId]( + ReturnMessage> result)->void { auto fetchLbd = [wltContainer](uint64_t val)->vector { @@ -1246,13 +1280,16 @@ void CppBridge::setupNewCoinSelectionInstance(const string& id, auto&& aeVec = result.get(); *csPtr = make_shared( - wltContainer->getWalletPtr(), fetchLbd, aeVec, + wltContainer->getWalletPtr(), fetchLbd, aeVec, wltContainer->getSpendableBalance(), height); - auto msg = make_unique(); - msg->add_reply(csId); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); - this->writeToClient(move(msg), msgid); + reply->mutable_wallet()->set_coin_selection_id(csId); + this->writeToClient(move(payload)); }; wltContainer->createAddressBook(lbd); @@ -1265,155 +1302,14 @@ void CppBridge::destroyCoinSelectionInstance(const string& csId) } //////////////////////////////////////////////////////////////////////////////// -void CppBridge::resetCoinSelection(const std::string& csId) -{ - auto iter = csMap_.find(csId); - if (iter == csMap_.end()) - throw runtime_error("invalid cs id"); - - iter->second->resetRecipients(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CppBridge::setCoinSelectionRecipient( - const string& csId, const string& addrStr, uint64_t value, unsigned recId) -{ - auto iter = csMap_.find(csId); - if (iter == csMap_.end()) - { - LOGERR << "[setCoinSelectionRecipient] invalid csId"; - return false; - } - - try - { - iter->second->updateRecipient(recId, addrStr, value); - } - catch (const exception&) - { - return false; - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CppBridge::cs_SelectUTXOs( - const string& csId, uint64_t fee, float feeByte, unsigned flags) +shared_ptr CppBridge::coinSelectionInstance( + const std::string& csId) const { auto iter = csMap_.find(csId); if (iter == csMap_.end()) - throw runtime_error("invalid cs id"); + return nullptr; - return iter->second->selectUTXOs(fee, feeByte, flags); -} - -//////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::cs_getUtxoSelection(const string& csId) -{ - auto iter = csMap_.find(csId); - if (iter == csMap_.end()) - throw runtime_error("invalid cs id"); - - auto&& utxoVec = iter->second->getUtxoSelection(); - - auto msg = make_unique(); - for (auto& utxo : utxoVec) - { - auto utxoProto = msg->add_data(); - CppToProto::utxo(utxoProto, utxo); - } - - return msg; -} - -//////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::cs_getFlatFee(const string& csId) -{ - auto iter = csMap_.find(csId); - if (iter == csMap_.end()) - throw runtime_error("invalid cs id"); - - auto flatFee = iter->second->getFlatFee(); - - auto msg = make_unique(); - msg->add_longs(flatFee); - return msg; -} - -//////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::cs_getFeeByte(const string& csId) -{ - auto iter = csMap_.find(csId); - if (iter == csMap_.end()) - throw runtime_error("invalid cs id"); - - auto flatFee = iter->second->getFeeByte(); - - auto msg = make_unique(); - msg->add_floats(flatFee); - return msg; -} - -//////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::cs_getSizeEstimate(const string& csId) -{ - auto iter = csMap_.find(csId); - if (iter == csMap_.end()) - throw runtime_error("invalid cs id"); - - auto sizeEstimate = iter->second->getSizeEstimate(); - - auto msg = make_unique(); - msg->add_longs(sizeEstimate); - return msg; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CppBridge::cs_ProcessCustomUtxoList(const ClientCommand& msg) -{ - if (msg.stringargs_size() != 1 || - msg.longargs_size() != 1 || - msg.floatargs_size() != 1 || - msg.intargs_size() != 1) - { - throw runtime_error("invalid command cs_ProcessCustomUtxoList"); - } - - auto iter = csMap_.find(msg.stringargs(0)); - if (iter == csMap_.end()) - throw runtime_error("invalid cs id"); - - auto flatFee = msg.longargs(0); - auto feeByte = msg.floatargs(0); - auto flags = msg.intargs(0); - - vector utxos; - for (int i=0; isecond->processCustomUtxoList(utxos, flatFee, feeByte, flags); - return true; - } - catch (CoinSelectionException&) - {} - - return false; + return iter->second; } //////////////////////////////////////////////////////////////////////////////// @@ -1424,44 +1320,51 @@ void CppBridge::createAddressBook(const string& id, unsigned msgId) wai.walletId, wai.accountId); auto lbd = [this, msgId]( - ReturnMessage> result)->void + ReturnMessage> result)->void { - auto msg = make_unique(); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); + auto addressBookProto = reply->mutable_wallet()->mutable_address_book(); auto&& aeVec = result.get(); for (auto& ae : aeVec) { - auto bridgeAe = msg->add_data(); + auto bridgeAe = addressBookProto->add_address(); auto& scrAddr = ae.getScrAddr(); bridgeAe->set_scraddr(scrAddr.getCharPtr(), scrAddr.getSize()); auto& hashList = ae.getTxHashList(); for (auto& hash : hashList) - bridgeAe->add_txhashes(hash.getCharPtr(), hash.getSize()); + bridgeAe->add_tx_hash(hash.getCharPtr(), hash.getSize()); } - this->writeToClient(move(msg), msgId); + this->writeToClient(move(payload)); }; wltContainer->createAddressBook(lbd); } //////////////////////////////////////////////////////////////////////////////// -void CppBridge::setComment(const ClientCommand& msg) +void CppBridge::setComment(const string& walletId, + const BridgeProto::Wallet::SetComment& msg) { - if (msg.stringargs_size() != 2 || msg.byteargs_size() != 1) - throw runtime_error("invalid command: setComment"); - - const auto& walletId = msg.stringargs(0); - auto wai = WalletAccountIdentifier::deserialize(walletId); auto wltContainer = wltManager_->getWalletContainer( wai.walletId, wai.accountId); + wltContainer->setComment(msg.hash_key(), msg.comment()); +} - const auto& hashKey = msg.byteargs(0); - const auto& comment = msg.stringargs(1); - wltContainer->setComment(hashKey, comment); +//////////////////////////////////////////////////////////////////////////////// +void CppBridge::setWalletLabels(const string& walletId, + const BridgeProto::Wallet::SetLabels& msg) +{ + auto wai = WalletAccountIdentifier::deserialize(walletId); + auto wltContainer = wltManager_->getWalletContainer( + wai.walletId, wai.accountId); + wltContainer->setLabels(msg.title(), msg.description()); } //////////////////////////////////////////////////////////////////////////////// @@ -1474,15 +1377,20 @@ void CppBridge::getUtxosForValue(const string& id, auto lbd = [this, msgId](ReturnMessage> result)->void { - auto&& utxoVec = result.get(); - auto msg = make_unique(); - for(auto& utxo : utxoVec) + auto utxoVec = move(result.get()); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); + + auto utxoList = reply->mutable_wallet()->mutable_utxo_list(); + for (auto& utxo : utxoVec) { - auto utxoProto = msg->add_data(); + auto utxoProto = utxoList->add_utxo(); CppToProto::utxo(utxoProto, utxo); } - this->writeToClient(move(msg), msgId); + this->writeToClient(move(payload)); }; wltContainer->getSpendableTxOutListForValue(value, lbd); @@ -1497,15 +1405,20 @@ void CppBridge::getSpendableZCList(const string& id, unsigned msgId) auto lbd = [this, msgId](ReturnMessage> result)->void { - auto&& utxoVec = result.get(); - auto msg = make_unique(); + auto utxoVec = move(result.get()); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); + + auto utxoList = reply->mutable_wallet()->mutable_utxo_list(); for(auto& utxo : utxoVec) { - auto utxoProto = msg->add_data(); + auto utxoProto = utxoList->add_utxo(); CppToProto::utxo(utxoProto, utxo); } - this->writeToClient(move(msg), msgId); + this->writeToClient(move(payload)); }; wltContainer->getSpendableZcTxOutList(lbd); @@ -1520,29 +1433,43 @@ void CppBridge::getRBFTxOutList(const string& id, unsigned msgId) auto lbd = [this, msgId](ReturnMessage> result)->void { - auto&& utxoVec = result.get(); - auto msg = make_unique(); + auto utxoVec = move(result.get()); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); + + auto utxoList = reply->mutable_wallet()->mutable_utxo_list(); for(auto& utxo : utxoVec) { - auto utxoProto = msg->add_data(); + auto utxoProto = utxoList->add_utxo(); CppToProto::utxo(utxoProto, utxo); } - this->writeToClient(move(msg), msgId); + this->writeToClient(move(payload)); }; wltContainer->getRBFTxOutList(lbd); } //////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::initNewSigner() +BridgePayload CppBridge::initNewSigner() { auto id = fortuna_.generateRandom(6).toHexStr(); - signerMap_.emplace(make_pair(id, make_shared())); + signerMap_.emplace(make_pair(id, + make_shared( + [this](const string& wltId)->auto { + return this->getWalletPtr(wltId); }, + [this](ServerPushWrapper wrapper) { + callbackWriter(wrapper); + }) + )); - auto msg = make_unique(); - msg->add_reply(id); - return msg; + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->mutable_signer()->set_signer_id(id); + return payload; } //////////////////////////////////////////////////////////////////////////////// @@ -1552,272 +1479,13 @@ void CppBridge::destroySigner(const string& id) } //////////////////////////////////////////////////////////////////////////////// -bool CppBridge::signer_SetVersion(const string& id, unsigned version) +shared_ptr CppBridge::signerInstance( + const string& id) const { auto iter = signerMap_.find(id); if (iter == signerMap_.end()) - return false; - - iter->second->signer_.setVersion(version); - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CppBridge::signer_SetLockTime(const string& id, unsigned locktime) -{ - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - return false; - - iter->second->signer_.setLockTime(locktime); - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CppBridge::signer_addSpenderByOutpoint( - const string& id, const BinaryDataRef& hash, - unsigned txOutId, unsigned sequence) -{ - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - return false; - - iter->second->signer_.addSpender_ByOutpoint(hash, txOutId, sequence); - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CppBridge::signer_populateUtxo( - const string& id, const BinaryDataRef& hash, - unsigned txOutId, uint64_t value, const BinaryDataRef& script) -{ - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - return false; - - try - { - UTXO utxo(value, UINT32_MAX, UINT32_MAX, txOutId, hash, script); - iter->second->signer_.populateUtxo(utxo); - } - catch(exception&) - { - return false; - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CppBridge::signer_addRecipient( - const std::string& id, const BinaryDataRef& script, uint64_t value) -{ - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - return false; - - try - { - auto&& hash = BtcUtils::getTxOutScrAddr(script); - iter->second->signer_.addRecipient( - CoinSelectionInstance::createRecipient(hash, value)); - } - catch (ScriptRecipientException&) - { - return false; - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::signer_getSerializedState(const string& id) const -{ - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - throw runtime_error("invalid signer id"); - - auto signerState = iter->second->signer_.serializeState(); - string signerStateStr; - if (!signerState.SerializeToString(&signerStateStr)) - throw runtime_error("failed to serialized signer state"); - - auto msg = make_unique(); - msg->add_reply(signerStateStr); - return msg; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CppBridge::signer_unserializeState( - const string& id, const BinaryData& state) -{ - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - throw runtime_error("invalid signer id"); - - try - { - Codec_SignerState::SignerState signerState; - if (!signerState.ParseFromArray(state.getPtr(), state.getSize())) - throw runtime_error("invalid signer state"); - - iter->second->signer_.deserializeState(signerState); - } - catch (exception&) - { - return false; - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -void CppBridge::signer_signTx( - const string& id, const string& wltId, unsigned msgId) -{ - //grab signer - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - throw runtime_error("invalid signer id"); - auto signerPtr = iter->second; - - //grab wallet - auto wai = WalletAccountIdentifier::deserialize(wltId); - auto wltContainer = wltManager_->getWalletContainer( - wai.walletId, wai.accountId); - auto wltPtr = wltContainer->getWalletPtr(); - - auto passLbd = createPassphrasePrompt(UnlockPromptType::decrypt); - - //instantiate and set resolver feed - auto signLbd = [wltPtr, signerPtr, passLbd, msgId, this](void)->void - { - bool success = true; - try - { - auto wltSingle = dynamic_pointer_cast(wltPtr); - auto feed = make_shared(wltSingle); - - signerPtr->signer_.resetFeed(); - signerPtr->signer_.setFeed(feed); - - //create & set wallet lambda - wltPtr->setPassphrasePromptLambda(passLbd); - - //lock wallet - auto lock = wltPtr->lockDecryptedContainer(); - - //sign - signerPtr->signer_.sign(); - } - catch (exception&) - { - success = false; - } - - //signal Python that we're done - auto msg = make_unique(); - msg->add_ints(success); - this->writeToClient(move(msg), msgId); - - //wind down passphrase prompt - passLbd({BridgePassphrasePrompt::concludeKey}); - }; - - thread thr(signLbd); - if (thr.joinable()) - thr.detach(); -} - -//////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::signer_getSignedTx(const string& id) const -{ - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - throw runtime_error("invalid signer id"); - - BinaryDataRef data; - try - { - data = iter->second->signer_.serializeSignedTx(); - } - catch (const exception&) - {} - - auto response = make_unique(); - response->add_reply(data.toCharPtr(), data.getSize()); - return response; -} - -//////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::signer_getUnsignedTx(const string& id) const -{ - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - throw runtime_error("invalid signer id"); - - BinaryDataRef data; - try - { - data = iter->second->signer_.serializeUnsignedTx(); - } - catch (const exception&) - {} - - auto response = make_unique(); - response->add_reply(data.toCharPtr(), data.getSize()); - return response; -} - - -//////////////////////////////////////////////////////////////////////////////// -int CppBridge::signer_resolve( - const string& sId, const string& wltId) const -{ - //grab signer - auto iter = signerMap_.find(sId); - if (iter == signerMap_.end()) - throw runtime_error("invalid signer id"); - auto& signer = iter->second->signer_; - - //grab wallet - auto wai = WalletAccountIdentifier::deserialize(wltId); - auto wltContainer = wltManager_->getWalletContainer( - wai.walletId, wai.accountId); - auto wltPtr = wltContainer->getWalletPtr(); - - //get wallet feed - auto wltSingle = dynamic_pointer_cast(wltPtr); - auto feed = make_shared(wltSingle); - - //set feed & resolve - signer.resetFeed(); - signer.setFeed(feed); - signer.resolvePublicData(); - - return 1; -} - -//////////////////////////////////////////////////////////////////////////////// -BridgeReply CppBridge::signer_getSignedStateForInput( - const string& id, unsigned inputId) -{ - auto iter = signerMap_.find(id); - if (iter == signerMap_.end()) - throw runtime_error("invalid signer id"); - - if (iter->second->signState_ == nullptr) - { - iter->second->signState_ = make_unique( - iter->second->signer_.evaluateSignedState()); - } - - const auto signState = iter->second->signState_.get(); - auto result = make_unique(); - - auto signStateInput = signState->getSignedStateForInput(inputId); - CppToProto::signatureState(result.get(), signStateInput); - return result; + return nullptr; + return iter->second; } //////////////////////////////////////////////////////////////////////////////// @@ -1843,10 +1511,13 @@ void CppBridge::getBlockTimeByHeight(uint32_t height, uint32_t msgId) const " with error: \"" << e.what() << "\""; } - auto result = make_unique(); - result->add_ints(timestamp); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->set_reference_id(msgId); - this->writeToClient(move(result), msgId); + reply->mutable_service()->set_block_time(timestamp); + this->writeToClient(move(payload)); }; bdvPtr_->getHeaderByHeight(height, callback); @@ -1859,28 +1530,55 @@ void CppBridge::estimateFee(uint32_t blocks, auto callback = [this, msgId]( ReturnMessage feeResult) { - auto result = make_unique(); + auto payload = make_unique(); + auto result = payload->mutable_reply(); + result->set_reference_id(msgId); try { auto feeData = feeResult.get(); - result->set_feebyte(feeData.val_); - result->set_smartfee(feeData.isSmart_); - result->set_error(feeData.error_); + result->set_success(true); + auto feeMsg = result->mutable_service()->mutable_fee_estimate(); + feeMsg->set_fee_byte(feeData.val_); + feeMsg->set_smart_fee(feeData.isSmart_); } catch (const ClientMessageError& e) { - result->set_feebyte(0); - result->set_smartfee(false); + result->set_success(false); result->set_error(e.what()); } - this->writeToClient(move(result), msgId); + this->writeToClient(move(payload)); }; bdvPtr_->estimateFee(blocks, strat, callback); } +//////////////////////////////////////////////////////////////////////////////// +void CppBridge::setCallbackHandler(ServerPushWrapper& wrapper) +{ + if (wrapper.referenceId == 0 || wrapper.handler == nullptr) + return; + + unique_lock lock(callbackHandlerMu_); + auto result = callbackHandlers_.emplace( + wrapper.referenceId, move(wrapper.handler)); + if (!result.second) + throw runtime_error("handler collision"); +} + +CallbackHandler CppBridge::getCallbackHandler(uint32_t id) +{ + unique_lock lock(callbackHandlerMu_); + auto handlerIter = callbackHandlers_.find(id); + if (handlerIter == callbackHandlers_.end()) + throw runtime_error("missing handler"); + + auto handler = move(handlerIter->second); + callbackHandlers_.erase(handlerIter); + return handler; +} + //////////////////////////////////////////////////////////////////////////////// //// //// BridgeCallback @@ -1891,22 +1589,20 @@ void BridgeCallback::waitOnId(const string& id) string currentId; while(true) { - { - if (currentId == id) - return; - - unique_lock lock(idMutex_); - auto iter = validIds_.find(id); - if (*iter == id) - { - validIds_.erase(iter); - return; - } + if (currentId == id) + return; - validIds_.insert(currentId); - currentId.clear(); + unique_lock lock(idMutex_); + auto iter = validIds_.find(id); + if (*iter == id) + { + validIds_.erase(iter); + return; } + validIds_.insert(currentId); + currentId.clear(); + //TODO: implement queue wake up logic currentId = move(idQueue_.pop_front()); } @@ -1930,21 +1626,18 @@ void BridgeCallback::run(BdmNotification notif) case BDMAction_ZC: { - BridgeLedgers payload; + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_BDM); + auto zcProto = callback->mutable_zero_conf(); + for (auto& le : notif.ledgers_) { - auto protoLe = payload.add_le(); + auto protoLe = zcProto->add_ledger(); CppToProto::ledger(protoLe, *le); } - vector payloadVec(payload.ByteSizeLong()); - payload.SerializeToArray(&payloadVec[0], payloadVec.size()); - - auto msg = make_unique(); - msg->set_type(BDMAction_ZC); - msg->add_opaque(&payloadVec[0], payloadVec.size()); - - pushNotifLbd_(move(msg), BRIDGE_CALLBACK_BDM); + pushNotifLbd_(move(payload)); break; } @@ -1956,17 +1649,23 @@ void BridgeCallback::run(BdmNotification notif) case BDMAction_Refresh: { + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_BDM); + auto refreshProto = callback->mutable_refresh(); + for (auto& id : notif.ids_) { string idStr(id.toCharPtr(), id.getSize()); - if (idStr == FILTER_CHANGE_FLAG) - { - //notify filter change - } + refreshProto->add_id(idStr); - idQueue_.push_back(move(idStr)); + //TODO: dumb way to watch over the pre bdm_ready wallet + //registration, fix this crap + if (idStr != FILTER_CHANGE_FLAG) + idQueue_.push_back(move(idStr)); } + pushNotifLbd_(move(payload)); break; } @@ -1985,18 +1684,13 @@ void BridgeCallback::run(BdmNotification notif) case BDMAction_NodeStatus: { //notify node status - BridgeNodeStatus nodeStatusMsg; - CppToProto::nodeStatus(&nodeStatusMsg, *notif.nodeStatus_); - vector serializedNodeStatus(nodeStatusMsg.ByteSizeLong()); - nodeStatusMsg.SerializeToArray( - &serializedNodeStatus[0], serializedNodeStatus.size()); - - auto msg = make_unique(); - msg->set_type(BDMAction_NodeStatus); - msg->add_opaque( - &serializedNodeStatus[0], serializedNodeStatus.size()); - - pushNotifLbd_(move(msg), BRIDGE_CALLBACK_BDM); + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_BDM); + auto nodeProto = callback->mutable_node_status(); + CppToProto::nodeStatus(nodeProto, *notif.nodeStatus_); + + pushNotifLbd_(move(payload)); break; } @@ -2022,122 +1716,198 @@ void BridgeCallback::progress( float progress, unsigned secondsRem, unsigned progressNumeric) { - auto msg = make_unique(); - msg->set_phase((uint32_t)phase); - msg->set_progress(progress); - msg->set_etasec(secondsRem); - msg->set_progressnumeric(progressNumeric); + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_PROGRESS); + auto progressMsg = callback->mutable_progress(); - for (auto& id : walletIdVec) - msg->add_ids(id); + progressMsg->set_phase((uint32_t)phase); + progressMsg->set_progress(progress); + progressMsg->set_eta_sec(secondsRem); + progressMsg->set_progress_numeric(progressNumeric); - pushNotifLbd_(move(msg), BRIDGE_CALLBACK_PROGRESS); + for (auto& id : walletIdVec) + progressMsg->add_id(id); + pushNotifLbd_(move(payload)); } //////////////////////////////////////////////////////////////////////////////// void BridgeCallback::notify_SetupDone() { - auto msg = make_unique(); - msg->set_type(CppBridgeState::CppBridge_Ready); + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_BDM); + callback->mutable_setup_done(); - pushNotifLbd_(move(msg), BRIDGE_CALLBACK_BDM); + pushNotifLbd_(move(payload)); } //////////////////////////////////////////////////////////////////////////////// void BridgeCallback::notify_SetupRegistrationDone(const set& ids) { - auto msg = make_unique(); - msg->set_type(CppBridgeState::CppBridge_Registered); - for (auto& id : ids) - msg->add_ids(id); + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_BDM); - pushNotifLbd_(move(msg), BRIDGE_CALLBACK_BDM); + auto registered = callback->mutable_registered(); + for (auto& id : ids) + registered->add_id(id); + pushNotifLbd_(move(payload)); } //////////////////////////////////////////////////////////////////////////////// void BridgeCallback::notify_RegistrationDone(const set& ids) { - auto msg = make_unique(); - msg->set_type(BDMAction_Refresh); + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_BDM); + + auto refresh = callback->mutable_refresh(); for (auto& id : ids) - msg->add_ids(id); + refresh->add_id(id); - pushNotifLbd_(move(msg), BRIDGE_CALLBACK_BDM); + pushNotifLbd_(move(payload)); } //////////////////////////////////////////////////////////////////////////////// void BridgeCallback::notify_NewBlock(unsigned height) { - auto msg = make_unique(); - msg->set_type(BDMAction_NewBlock); - msg->set_height(height); + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_BDM); + callback->mutable_new_block()->set_height(height); - pushNotifLbd_(move(msg), BRIDGE_CALLBACK_BDM); + pushNotifLbd_(move(payload)); } //////////////////////////////////////////////////////////////////////////////// void BridgeCallback::notify_Ready(unsigned height) { - auto msg = make_unique(); - msg->set_type(BDMAction_Ready); - msg->set_height(height); + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_BDM); + callback->mutable_ready()->set_height(height); - pushNotifLbd_(move(msg), BRIDGE_CALLBACK_BDM); + pushNotifLbd_(move(payload)); } //////////////////////////////////////////////////////////////////////////////// void BridgeCallback::disconnected() { - auto msg = make_unique(); - msg->set_type(DISCONNECTED_CALLBACK_ID); + auto payload = make_unique(); + auto callback = payload->mutable_callback(); + callback->set_callback_id(BRIDGE_CALLBACK_BDM); + callback->mutable_disconnected(); - pushNotifLbd_(move(msg), BRIDGE_CALLBACK_BDM); + pushNotifLbd_(move(payload)); } //////////////////////////////////////////////////////////////////////////////// //// -//// MethodCallbacksHandler +//// CppBridgeSignerStruct //// //////////////////////////////////////////////////////////////////////////////// -void MethodCallbacksHandler::processCallbackReply( - unsigned callbackId, BinaryDataRef& dataRef) +CppBridgeSignerStruct::CppBridgeSignerStruct( + function getWalletFunc, + function writeFunc) : + getWalletFunc_(getWalletFunc), writeFunc_(writeFunc) +{} + +//////////////////////////////////////////////////////////////////////////////// +void CppBridgeSignerStruct::signTx(const string& wltId, + const string& callbackId, unsigned referenceId) { - auto iter = callbacks_.find(callbackId); - if (iter == callbacks_.end()) - return; //ignore unknown callbacks ids + //grab wallet + auto wltPtr = getWalletFunc_(wltId); + + //run signature process in its own thread, as it's an async process + auto signLbd = [this, wltPtr, callbackId, referenceId](void)->void + { + bool success = true; + + //create passphrase lambda + auto passPromptObj = make_shared( + callbackId, writeFunc_); + auto passLbd = passPromptObj->getLambda(); + + try + { + //cast wallet & create resolver + auto wltSingle = dynamic_pointer_cast(wltPtr); + auto feed = make_shared(wltSingle); + + //set resolver + signer_.resetFeed(); + signer_.setFeed(feed); - auto callbackLbd = move(iter->second); - callbacks_.erase(iter); - callbackLbd(dataRef); + //create & set passphrase lambda + wltPtr->setPassphrasePromptLambda(passLbd); + + //lock decryption container + auto lock = wltPtr->lockDecryptedContainer(); + + //sign, this will prompt the passphrase lambda on demand + signer_.sign(); + } + catch (const exception&) + { + success = false; + } + catch (...) + { + LOGINFO << "false catch"; + } + + //send reply to caller + auto protoMsg = make_unique(); + auto reply = protoMsg->mutable_reply(); + reply->set_success(success); + reply->set_reference_id(referenceId); + + ServerPushWrapper wrapper{ 0, nullptr, move(protoMsg) }; + writeFunc_(move(wrapper)); + + //wind down passphrase prompt + passPromptObj->cleanup(); + }; + + thread thr(signLbd); + if (thr.joinable()) + thr.detach(); } //////////////////////////////////////////////////////////////////////////////// -void MethodCallbacksHandler::flagForCleanup() +bool CppBridgeSignerStruct::resolve(const string& wltId) { - /* - Mock a shutdown message and queue it up. This message will trigger the - deletion of this callback handler from the callback map; - */ - if (parentCommandQueue_ == nullptr) - return; + //grab wallet + auto wltPtr = getWalletFunc_(wltId); - ClientCommand msg; + //get wallet feed + auto wltSingle = dynamic_pointer_cast(wltPtr); + auto feed = make_shared(wltSingle); - msg.set_method(Methods::methodWithCallback); - msg.set_methodwithcallback(MethodsWithCallback::cleanup); - msg.add_byteargs(id_.toCharPtr(), id_.getSize()); + //set feed & resolve + signer_.resetFeed(); + signer_.setFeed(feed); + signer_.resolvePublicData(); - parentCommandQueue_->push_back(move(msg)); - parentCommandQueue_ = nullptr; + return true; } //////////////////////////////////////////////////////////////////////////////// -unsigned MethodCallbacksHandler::addCallback(const function& cbk) +BridgePayload CppBridgeSignerStruct::getSignedStateForInput(unsigned inputId) { - /* - This method isn't thread safe. - */ - auto id = counter_++; - callbacks_.emplace(id, cbk); - return id; -} \ No newline at end of file + if (signState_ == nullptr) + signState_ = make_unique(signer_.evaluateSignedState()); + + const auto signState = signState_.get(); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + + auto signStateInput = signState->getSignedStateForInput(inputId); + auto inputState = reply->mutable_signer()->mutable_input_signed_state(); + CppToProto::signatureState(inputState, signStateInput); + + reply->set_success(true); + return payload; +} diff --git a/cppForSwig/BridgeAPI/CppBridge.h b/cppForSwig/BridgeAPI/CppBridge.h index 5c9a6a60a..d09a21621 100755 --- a/cppForSwig/BridgeAPI/CppBridge.h +++ b/cppForSwig/BridgeAPI/CppBridge.h @@ -12,18 +12,27 @@ #include "../ArmoryConfig.h" #include "WalletManager.h" #include "btc/ecc.h" -#include "../protobuf/ClientProto.pb.h" +#ifdef BUILD_PROTOBUF +#include "../protobuf/BridgeProto.pb.h" +#endif #include "../AsyncClient.h" +namespace BridgeProto +{ + class CallbackReply; +}; + namespace Armory { namespace Bridge { struct WritePayload_Bridge; + struct ServerPushWrapper; + using BridgePayload = std::unique_ptr; ////////////////////////////////////////////////////////////////////////// typedef std::function, unsigned)> notifLbd; + std::unique_ptr)> notifLbd; //// class BridgeCallback : public RemoteCallback @@ -69,55 +78,29 @@ namespace Armory }; ////////////////////////////////////////////////////////////////////////// - struct CppBridgeSignerStruct - { - Armory::Signer::Signer signer_; - std::unique_ptr signState_; - }; - - ////////////////////////////////////////////////////////////////////////// - using CommandQueue = std::shared_ptr>; - - //// - class CppBridge; - - //// - class MethodCallbacksHandler + using WalletPtr = std::shared_ptr; + class CppBridgeSignerStruct { - friend class CppBridge; - private: - unsigned counter_ = 0; - const BinaryData id_; - std::thread methodThr_; - std::map> callbacks_; - - CommandQueue parentCommandQueue_; + std::unique_ptr signState_{}; + const std::function getWalletFunc_; + const std::function writeFunc_; public: - MethodCallbacksHandler(const BinaryData& id, CommandQueue queue) : - id_(id), parentCommandQueue_(queue) - {} - - ~MethodCallbacksHandler(void) - { - flagForCleanup(); - if (methodThr_.joinable()) - methodThr_.join(); - } + Armory::Signer::Signer signer_{}; - const BinaryData& id(void) const { return id_; } - unsigned addCallback(const std::function&); + public: + CppBridgeSignerStruct(std::function, + std::function); - //startThread - void flagForCleanup(void); - void processCallbackReply(unsigned, BinaryDataRef&); + void signTx(const std::string&, const std::string&, unsigned); + bool resolve(const std::string&); + BridgePayload getSignedStateForInput(unsigned); }; ////////////////////////////////////////////////////////////////////////// + using CallbackHandler = std::function; struct ProtobufCommandParser; - using BridgeReply = std::unique_ptr; class CppBridge { @@ -142,63 +125,57 @@ namespace Armory PRNG_Fortuna fortuna_; - std::mutex passPromptMutex_; - std::map> promptMap_; - std::function)> writeLambda_; const bool dbOneWayAuth_; const bool dbOffline_; - std::map> - callbackHandlerMap_; - CommandQueue commandWithCallbackQueue_; - - std::thread commandWithCallbackProcessThread_; + std::mutex callbackHandlerMu_; + std::map callbackHandlers_; private: - //commands with callback - void queueCommandWithCallback(::Codec_ClientProto::ClientCommand); - void processCommandWithCallbackThread(void); - //wallet setup - void loadWallets(unsigned id); - BridgeReply createWalletsPacket(void); + void loadWallets(const std::string&, unsigned); + BridgePayload createWalletsPacket(void); bool deleteWallet(const std::string&); - BridgeReply getWalletPacket(const std::string&) const; + BridgePayload getWalletPacket(const std::string&) const; //AsyncClient::BlockDataViewer setup void setupDB(void); void registerWallets(void); void registerWallet(const std::string&, bool isNew); - BridgeReply getNodeStatus(void); + BridgePayload getNodeStatus(void); //balance and counts - BridgeReply getBalanceAndCount(const std::string&); - BridgeReply getAddrCombinedList(const std::string&); - BridgeReply getHighestUsedIndex(const std::string&); + BridgePayload getBalanceAndCount(const std::string&); + BridgePayload getAddrCombinedList(const std::string&); + BridgePayload getHighestUsedIndex(const std::string&); //wallet & addresses void extendAddressPool(const std::string&, unsigned, const std::string&, unsigned); - BridgeReply getNewAddress(const std::string&, unsigned); - BridgeReply getChangeAddress(const std::string&, unsigned); - BridgeReply peekChangeAddress(const std::string&, unsigned); - std::string createWallet(const ::Codec_ClientProto::ClientCommand&); - void createBackupStringForWallet(const std::string&, unsigned); - void restoreWallet(const BinaryDataRef&, - std::shared_ptr); + BridgePayload getNewAddress(const std::string&, unsigned); + BridgePayload getChangeAddress(const std::string&, unsigned); + BridgePayload peekChangeAddress(const std::string&, unsigned); + std::string createWallet(const BridgeProto::Utils::CreateWalletStruct&); + void createBackupStringForWallet(const std::string&, + const std::string&, unsigned); + void restoreWallet(const BinaryDataRef&); //ledgers const std::string& getLedgerDelegateIdForWallets(void); const std::string& getLedgerDelegateIdForScrAddr( const std::string&, const BinaryDataRef&); void getHistoryPageForDelegate(const std::string&, unsigned, unsigned); + void getHistoryForWalletSelection(const std::string&, + std::vector, unsigned); void createAddressBook(const std::string&, unsigned); - void setComment(const Codec_ClientProto::ClientCommand&); + void setComment(const std::string&, + const BridgeProto::Wallet::SetComment&); + void setWalletLabels(const std::string&, + const BridgeProto::Wallet::SetLabels&); //txs & headers void getTxByHash(const BinaryData&, unsigned); @@ -213,76 +190,50 @@ namespace Armory void setupNewCoinSelectionInstance( const std::string&, unsigned, unsigned); void destroyCoinSelectionInstance(const std::string&); - void resetCoinSelection(const std::string&); - bool setCoinSelectionRecipient( - const std::string&, const std::string&, uint64_t, unsigned); - bool cs_SelectUTXOs(const std::string&, uint64_t, float, unsigned); - BridgeReply cs_getUtxoSelection(const std::string&); - BridgeReply cs_getFlatFee(const std::string&); - BridgeReply cs_getFeeByte(const std::string&); - BridgeReply cs_getSizeEstimate(const std::string&); - bool cs_ProcessCustomUtxoList(const Codec_ClientProto::ClientCommand&); + std::shared_ptr + coinSelectionInstance(const std::string&) const; //signer - BridgeReply initNewSigner(void); + BridgePayload initNewSigner(void); void destroySigner(const std::string&); - bool signer_SetVersion(const std::string&, unsigned); - bool signer_SetLockTime(const std::string&, unsigned); - - bool signer_addSpenderByOutpoint( - const std::string&, const BinaryDataRef&, unsigned, unsigned); - bool signer_populateUtxo( - const std::string&, const BinaryDataRef&, unsigned, uint64_t, - const BinaryDataRef&); - - bool signer_addRecipient( - const std::string&, const BinaryDataRef&, uint64_t); - BridgeReply signer_getSerializedState(const std::string&) const; - bool signer_unserializeState(const std::string&, const BinaryData&); - void signer_signTx(const std::string&, const std::string&, unsigned); - BridgeReply signer_getSignedTx(const std::string&) const; - BridgeReply signer_getUnsignedTx(const std::string&) const; - BridgeReply signer_getSignedStateForInput( - const std::string&, unsigned); - int signer_resolve(const std::string&, const std::string&) const; + std::shared_ptr signerInstance( + const std::string&) const; + WalletPtr getWalletPtr(const std::string&) const; //utils - BridgeReply getTxInScriptType( + BridgePayload getTxInScriptType( const BinaryData&, const BinaryData&) const; - BridgeReply getTxOutScriptType(const BinaryData&) const; - BridgeReply getScrAddrForScript(const BinaryData&) const; - BridgeReply getScrAddrForAddrStr(const std::string&) const; - BridgeReply getLastPushDataInScript(const BinaryData&) const; - BridgeReply getHash160(const BinaryDataRef&) const; + BridgePayload getTxOutScriptType(const BinaryData&) const; + BridgePayload getScrAddrForScript(const BinaryData&) const; + BridgePayload getScrAddrForAddrStr(const std::string&) const; + BridgePayload getLastPushDataInScript(const BinaryData&) const; + BridgePayload getHash160(const BinaryDataRef&) const; void broadcastTx(const std::vector&); - BridgeReply getTxOutScriptForScrAddr(const BinaryData&) const; - BridgeReply getAddrStrForScrAddr(const BinaryData&) const; + BridgePayload getTxOutScriptForScrAddr(const BinaryData&) const; + BridgePayload getAddrStrForScrAddr(const BinaryData&) const; std::string getNameForAddrType(int) const; - BridgeReply setAddressTypeFor( + BridgePayload setAddressTypeFor( const std::string&, const std::string&, uint32_t) const; void getBlockTimeByHeight(uint32_t, uint32_t) const; void estimateFee(uint32_t, const std::string&, uint32_t) const; - //passphrase prompt - PassphraseLambda createPassphrasePrompt( - ::Codec_ClientProto::UnlockPromptType); - bool returnPassphrase(const std::string&, const std::string&); + //custom callback handlers + void callbackWriter(ServerPushWrapper&); + void setCallbackHandler(ServerPushWrapper&); + CallbackHandler getCallbackHandler(uint32_t); public: CppBridge(const std::string&, const std::string&, const std::string&, bool, bool); bool processData(BinaryDataRef socketData); - void writeToClient(BridgeReply msgPtr, unsigned id) const; + void writeToClient(BridgePayload msgPtr) const; void setWriteLambda( std::function)> lbd) { writeLambda_ = lbd; } - - void startThreads(void); - void stopThreads(void); }; }; //namespace Bridge }; //namespace Armory diff --git a/cppForSwig/BridgeAPI/PassphrasePrompt.cpp b/cppForSwig/BridgeAPI/PassphrasePrompt.cpp index 930dcd7dd..a293d582d 100644 --- a/cppForSwig/BridgeAPI/PassphrasePrompt.cpp +++ b/cppForSwig/BridgeAPI/PassphrasePrompt.cpp @@ -6,106 +6,102 @@ // // //////////////////////////////////////////////////////////////////////////////// +#include "log.h" +#ifdef BUILD_PROTOBUF +#include "../protobuf/BridgeProto.pb.h" +#endif #include "PassphrasePrompt.h" -#include "BridgeSocket.h" using namespace Armory::Bridge; using namespace std; -using namespace Codec_ClientProto; +using namespace BridgeProto; + +uint32_t BridgePassphrasePrompt::referenceCounter_ = 1; //////////////////////////////////////////////////////////////////////////////// //// //// BridgePassphrasePrompt //// //////////////////////////////////////////////////////////////////////////////// -const Armory::Wallets::EncryptionKeyId - BridgePassphrasePrompt::concludeKey("concludePrompt"); +BridgePassphrasePrompt::BridgePassphrasePrompt(const std::string& id, + std::function func) : + promptId_(id), writeFunc_(move(func)) +{} -PassphraseLambda BridgePassphrasePrompt::getLambda(UnlockPromptType type) +//////////////////////////////////////////////////////////////////////////////// +SecureBinaryData BridgePassphrasePrompt::processFeedRequest( + const set& ids) { - auto lbd = [this, type] - (const set& ids) - ->SecureBinaryData + if (ids.empty()) { - UnlockPromptState promptState = UnlockPromptState::cycle; - if (encryptionKeyIds_.empty()) - { - if (ids.empty()) - throw runtime_error("malformed command"); + //exit condition + cleanup(); + return {}; + } - encryptionKeyIds_ = ids; - promptState = UnlockPromptState::start; - } - - //cycle the promise & future - promPtr_ = make_unique>(); - futPtr_ = make_unique>( - promPtr_->get_future()); + //cycle the promise & future + auto promPtr = make_shared>(); + auto fut = promPtr->get_future(); - //create protobuf payload - UnlockPromptCallback opaque; - opaque.set_promptid(promptId_); - opaque.set_prompttype(type); + auto refId = referenceCounter_++; - switch (type) - { - case UnlockPromptType::decrypt: - { - opaque.set_verbose("Unlock Wallet"); - break; - } + //create protobuf payload + auto protoPtr = make_unique(); + auto pushPtr = protoPtr->mutable_callback(); + pushPtr->set_callback_id(promptId_); + pushPtr->set_reference_id(refId); - case UnlockPromptType::migrate: - { - opaque.set_verbose("Migrate Wallet"); - break; - } + auto unlockPtr = pushPtr->mutable_unlock_request(); + for (const auto& id : ids) + unlockPtr->add_encryption_key_ids(id.toHexStr()); - default: - opaque.set_verbose("undefined prompt type"); + //reply handler + auto replyHandler = [promPtr](const CallbackReply& reply)->bool + { + if (!reply.success() || + reply.reply_payload_case() != CallbackReply::kPassphrase) + { + promPtr->set_exception(make_exception_ptr(runtime_error(""))); } - - bool exit = false; - if (!ids.empty()) + else { - auto iter = ids.begin(); - if (*iter == concludeKey) - { - promptState = UnlockPromptState::stop; - exit = true; - } - - opaque.set_walletid(iter->toHexStr()); + promPtr->set_value(SecureBinaryData::fromString(reply.passphrase())); } - opaque.set_state(promptState); - - auto msg = make_unique(); - msg->set_payloadtype(OpaquePayloadType::prompt); - - string serializedOpaqueData; - opaque.SerializeToString(&serializedOpaqueData); - msg->set_payload(serializedOpaqueData); - - //push over socket - auto payload = make_unique(); - payload->message_ = move(msg); - payload->id_ = BRIDGE_CALLBACK_PROMPTUSER; - writeLambda_(move(payload)); + return true; + }; - if (exit) - return {}; + //push over socket + ServerPushWrapper wrapper{ refId, replyHandler, move(protoPtr) }; + writeFunc_(move(wrapper)); - //wait on future - return futPtr_->get(); - }; + //wait on future + try + { + return fut.get(); + } + catch (const exception&) + { + LOGINFO << "cancelled wallet unlock"; + return {}; + } +} - return lbd; +//////////////////////////////////////////////////////////////////////////////// +void BridgePassphrasePrompt::cleanup() +{ + auto protoPtr = make_unique(); + auto pushPtr = protoPtr->mutable_callback(); + pushPtr->set_callback_id(promptId_); + pushPtr->set_cleanup(true); + writeFunc_(ServerPushWrapper{0, nullptr, move(protoPtr)}); } //////////////////////////////////////////////////////////////////////////////// -void BridgePassphrasePrompt::setReply(const string& passphrase) +PassphraseLambda BridgePassphrasePrompt::getLambda() { - auto&& passSBD = SecureBinaryData::fromString(passphrase); - promPtr_->set_value(passSBD); + return [this](const set& ids)->SecureBinaryData + { + return processFeedRequest(ids); + }; } diff --git a/cppForSwig/BridgeAPI/PassphrasePrompt.h b/cppForSwig/BridgeAPI/PassphrasePrompt.h index b994607cc..51704c907 100644 --- a/cppForSwig/BridgeAPI/PassphrasePrompt.h +++ b/cppForSwig/BridgeAPI/PassphrasePrompt.h @@ -11,41 +11,48 @@ #include -#include "../protobuf/ClientProto.pb.h" #include "../Wallets/WalletIdTypes.h" #include "../Wallets/PassphraseLambda.h" -#define BRIDGE_CALLBACK_PROMPTUSER UINT32_MAX - 2 +namespace BridgeProto +{ + class Payload; + class CallbackReply; +}; namespace Armory { namespace Bridge { - struct WritePayload_Bridge; + using CallbackHandler = std::function; + + ////////////////////////////////////////////////////////////////////////// + struct ServerPushWrapper + { + const uint32_t referenceId; + CallbackHandler handler = nullptr; + std::unique_ptr payload; + }; ////////////////////////////////////////////////////////////////////////// class BridgePassphrasePrompt { - private: - std::unique_ptr> promPtr_; - std::unique_ptr> futPtr_; + static uint32_t referenceCounter_; + private: const std::string promptId_; - std::function)> writeLambda_; - - std::set encryptionKeyIds_; + std::function writeFunc_; - public: - static const Wallets::EncryptionKeyId concludeKey; + private: + SecureBinaryData processFeedRequest( + const std::set&); public: - BridgePassphrasePrompt(const std::string& id, - std::function)> lbd) : - promptId_(id), writeLambda_(lbd) - {} + BridgePassphrasePrompt(const std::string&, + std::function); - PassphraseLambda getLambda(::Codec_ClientProto::UnlockPromptType); - void setReply(const std::string&); + PassphraseLambda getLambda(); + void cleanup(void); }; }; //namespace Bridge }; //namespace Armory diff --git a/cppForSwig/BridgeAPI/ProtobufCommandParser.cpp b/cppForSwig/BridgeAPI/ProtobufCommandParser.cpp index c88f94626..190964fdc 100644 --- a/cppForSwig/BridgeAPI/ProtobufCommandParser.cpp +++ b/cppForSwig/BridgeAPI/ProtobufCommandParser.cpp @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // // -// Copyright (C) 2020-21, goatpig // +// Copyright (C) 2020-23, goatpig // // Distributed under the MIT license // // See LICENSE-MIT or https://opensource.org/licenses/MIT // // // @@ -8,740 +8,980 @@ #include "ProtobufCommandParser.h" #include "CppBridge.h" -#include "../protobuf/ClientProto.pb.h" +#include "../protobuf/BridgeProto.pb.h" +#include "ProtobufConversions.h" using namespace std; using namespace Armory::Bridge; using namespace ::google::protobuf; -using namespace ::Codec_ClientProto; +using namespace ::BridgeProto; //////////////////////////////////////////////////////////////////////////////// -bool ProtobufCommandParser::processData( - CppBridge* bridge, BinaryDataRef socketData) +bool ProtobufCommandParser::processBlockchainServiceCommands(CppBridge* bridge, + unsigned referenceId, const BridgeProto::BlockchainService& msg) { - ClientCommand msg; - if (!msg.ParseFromArray(socketData.getPtr() + 1, socketData.getSize() - 1)) + BridgePayload response; + switch (msg.method_case()) { - LOGERR << "failed to parse protobuf msg"; - return false; - } + case BridgeProto::BlockchainService::kEstimateFee: + { + const auto& estimateFeeMsg = msg.estimate_fee(); + bridge->estimateFee(estimateFeeMsg.blocks(), + estimateFeeMsg.strat(), referenceId); + break; + } - auto id = msg.payloadid(); - BridgeReply response; + case BridgeProto::BlockchainService::kLoadWallets: + { + bridge->loadWallets(msg.load_wallets().callback_id(), + referenceId); + break; + } - switch (msg.method()) - { - case Methods::methodWithCallback: - { - try + case BridgeProto::BlockchainService::kSetupDb: { - bridge->queueCommandWithCallback(move(msg)); + bridge->setupDB(); + break; } - catch (const exception& e) + + case BridgeProto::BlockchainService::kGoOnline: { - LOGERR << "[methodWithCallback] " << e.what(); - auto errMsg = make_unique(); - errMsg->set_iserror(true); - errMsg->set_error(e.what()); + if (bridge->bdvPtr_ == nullptr) + throw runtime_error("null bdv ptr"); + bridge->bdvPtr_->goOnline(); + break; + } - response = move(errMsg); + case BridgeProto::BlockchainService::kShutdown: + { + if (bridge->bdvPtr_ != nullptr) + { + bridge->bdvPtr_->unregisterFromDB(); + bridge->bdvPtr_.reset(); + bridge->callbackPtr_.reset(); + } + return false; } - break; - } + case BridgeProto::BlockchainService::kRegisterWallets: + { + bridge->registerWallets(); + break; + } - case Methods::loadWallets: - { - bridge->loadWallets(id); - break; - } + case BridgeProto::BlockchainService::kRegisterWallet: + { + const auto& registerWalletMsg = msg.register_wallet(); + bridge->registerWallet(registerWalletMsg.id(), + registerWalletMsg.is_new()); + break; + } - case Methods::setupDB: - { - bridge->setupDB(); - break; - } + case BridgeProto::BlockchainService::kGetLedgerDelegateIdForWallets: + { + auto& delegateId = bridge->getLedgerDelegateIdForWallets(); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_service()->set_ledger_delegate_id(delegateId); + response = move(payload); + break; + } - case Methods::registerWallets: - { - bridge->registerWallets(); - break; - } + case BridgeProto::BlockchainService::kUpdateWalletsLedgerFilter: + { + vector idVec; + const auto& updateWalletsMsg = msg.update_wallets_ledger_filter(); + idVec.reserve(updateWalletsMsg.wallet_id_size()); + + for (int i=0; ibdvPtr_->updateWalletsLedgerFilter(idVec); + break; + } - case Methods::registerWallet: - { - if (msg.stringargs_size() != 1 || msg.intargs_size() != 1) - throw runtime_error("invalid command: registerWallet"); - bridge->registerWallet(msg.stringargs(0), msg.intargs(0)); - break; - } + case BridgeProto::BlockchainService::kGetHistoryPageForDelegate: + { + const auto& getHistoryPageMsg = msg.get_history_page_for_delegate(); + bridge->getHistoryPageForDelegate(getHistoryPageMsg.delegate_id(), + getHistoryPageMsg.page_id(), referenceId); + break; + } - case Methods::createBackupStringForWallet: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: getRootData"); - bridge->createBackupStringForWallet(msg.stringargs(0), id); - break; - } + case BridgeProto::BlockchainService::kGetHistoryForWalletSelection: + { + const auto& getHistoryMsg = msg.get_history_for_wallet_selection(); + vector wltIdVec; + wltIdVec.reserve(getHistoryMsg.wallet_id_size()); - case Methods::goOnline: - { - if (bridge->bdvPtr_ == nullptr) - throw runtime_error("null bdv ptr"); - bridge->bdvPtr_->goOnline(); - break; - } + for (int i=1; ibdvPtr_ != nullptr) + bridge->getHistoryForWalletSelection(getHistoryMsg.order(), + wltIdVec, referenceId); + break; + } + + case BridgeProto::BlockchainService::kGetNodeStatus: { - bridge->bdvPtr_->unregisterFromDB(); - bridge->bdvPtr_.reset(); - bridge->callbackPtr_.reset(); + response = move(bridge->getNodeStatus()); + break; } - return false; - } + case BridgeProto::BlockchainService::kGetHeaderByHeight: + { + bridge->getHeaderByHeight(msg.get_header_by_height().height(), + referenceId); + break; + } - case Methods::getLedgerDelegateIdForWallets: - { - auto& delegateId = bridge->getLedgerDelegateIdForWallets(); - auto replyMsg = make_unique(); - replyMsg->add_reply(delegateId); - response = move(replyMsg); - break; + case BridgeProto::BlockchainService::kGetTxByHash: + { + const auto& hash = BinaryData::fromString( + msg.get_tx_by_hash().tx_hash()); + bridge->getTxByHash(hash, referenceId); + break; + } + + case BridgeProto::BlockchainService::kBroadcastTx: + { + const auto& broadcastMsg = msg.broadcast_tx(); + vector bdVec; + bdVec.reserve(broadcastMsg.raw_tx_size()); + for (int i=0; ibroadcastTx(bdVec); + break; + } + + case BridgeProto::BlockchainService::kGetBlockTimeByHeight: + { + bridge->getBlockTimeByHeight( + msg.get_block_time_by_height().height(), referenceId); + break; + } } - case Methods::updateWalletsLedgerFilter: + if (response != nullptr) { - vector idVec; - for (int i=0; ibdvPtr_->updateWalletsLedgerFilter(idVec); - break; + //write response to socket + response->mutable_reply()->set_reference_id(referenceId); + bridge->writeToClient(move(response)); } + return true; +} - case Methods::getLedgerDelegateIdForScrAddr: +//////////////////////////////////////////////////////////////////////////////// +bool ProtobufCommandParser::processWalletCommands(CppBridge* bridge, + unsigned referenceId, const BridgeProto::Wallet& msg) +{ + BridgePayload response; + switch (msg.method_case()) { - if (msg.stringargs_size() == 0 || msg.byteargs_size() == 0) - throw runtime_error("invalid command: getLedgerDelegateIdForScrAddr"); + case BridgeProto::Wallet::kCreateBackupString: + { + bridge->createBackupStringForWallet(msg.id(), + msg.create_backup_string().callback_id(), referenceId); + break; + } - auto addrHashRef = BinaryDataRef::fromString(msg.byteargs(0)); - auto& delegateId = bridge->getLedgerDelegateIdForScrAddr( - msg.stringargs(0), addrHashRef); + case BridgeProto::Wallet::kGetLedgerDelegateIdForScraddr: + { + auto addrHashRef = BinaryDataRef::fromString( + msg.get_ledger_delegate_id_for_scraddr().hash()); + const auto& delegateId = bridge->getLedgerDelegateIdForScrAddr( + msg.id(), addrHashRef); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_wallet()->set_ledger_delegate_id(delegateId); + response = move(payload); + break; + } - auto replyMsg = make_unique(); - replyMsg->add_reply(delegateId); - response = move(replyMsg); - break; - } + case BridgeProto::Wallet::kGetBalanceAndCount: + { + response = move(bridge->getBalanceAndCount(msg.id())); + break; + } - case Methods::getHistoryPageForDelegate: - { - if (msg.stringargs_size() == 0 || msg.intargs_size() == 0) - throw runtime_error("invalid command: getHistoryPageForDelegate"); - bridge->getHistoryPageForDelegate(msg.stringargs(0), msg.intargs(0), id); - break; - } + case BridgeProto::Wallet::kSetupNewCoinSelectionInstance: + { + bridge->setupNewCoinSelectionInstance(msg.id(), + msg.setup_new_coin_selection_instance().height(), referenceId); + break; + } - case Methods::getNodeStatus: - { - response = move(bridge->getNodeStatus()); - break; - } + case BridgeProto::Wallet::kGetAddrCombinedList: + { + response = move(bridge->getAddrCombinedList(msg.id())); + break; + } - case Methods::getBalanceAndCount: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: getBalanceAndCount"); - response = move(bridge->getBalanceAndCount(msg.stringargs(0))); - break; - } + case BridgeProto::Wallet::kGetHighestUsedIndex: + { + response = move(bridge->getHighestUsedIndex(msg.id())); + break; + } - case Methods::getAddrCombinedList: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: getAddrCombinedList"); - response = move(bridge->getAddrCombinedList(msg.stringargs(0))); - break; - } + case BridgeProto::Wallet::kExtendAddressPool: + { + const auto& extendMsg = msg.extend_address_pool(); + bridge->extendAddressPool(msg.id(), extendMsg.count(), + extendMsg.callback_id(), referenceId); + break; + } - case Methods::getHighestUsedIndex: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: getHighestUsedIndex"); - response = move(bridge->getHighestUsedIndex(msg.stringargs(0))); - break; - } + case BridgeProto::Wallet::kDelete: + { + auto result = bridge->deleteWallet(msg.id()); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(result); + response = move(payload); + break; + } - case Methods::extendAddressPool: - { - if (msg.stringargs_size() != 2 || msg.intargs_size() != 1) - throw runtime_error("invalid command: extendAddressPool"); - bridge->extendAddressPool( - msg.stringargs(0), msg.intargs(0), msg.stringargs(1), id); - break; - } + case BridgeProto::Wallet::kGetData: + { + response = move(bridge->getWalletPacket(msg.id())); + break; + } - case Methods::createWallet: - { - auto&& wltId = bridge->createWallet(msg); - auto replyMsg = make_unique(); - replyMsg->add_reply(wltId); - response = move(replyMsg); - break; - } + case BridgeProto::Wallet::kSetAddressTypeFor: + { + const auto& setAddrMsg = msg.set_address_type_for(); + response = bridge->setAddressTypeFor( + msg.id(), setAddrMsg.asset_id(), setAddrMsg.address_type()); + response->mutable_reply()->set_reference_id(referenceId); + break; + } - case Methods::deleteWallet: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: deleteWallet"); - auto result = bridge->deleteWallet(msg.stringargs(0)); - - auto replyMsg = make_unique(); - replyMsg->add_ints(result); - response = move(replyMsg); - break; - } + case BridgeProto::Wallet::kCreateAddressBook: + { + bridge->createAddressBook(msg.id(), referenceId); + break; + } - case Methods::getWalletData: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: deleteWallet"); - response = move(bridge->getWalletPacket(msg.stringargs(0))); - break; - } + case BridgeProto::Wallet::kSetComment: + { + bridge->setComment(msg.id(), msg.set_comment()); + break; + } - case Methods::getTxByHash: - { - if (msg.byteargs_size() != 1) - throw runtime_error("invalid command: getTxByHash"); - auto& byteargs = msg.byteargs(0); - BinaryData hash((uint8_t*)byteargs.c_str(), byteargs.size()); - bridge->getTxByHash(hash, id); - break; - } + case BridgeProto::Wallet::kSetLabels: + { + bridge->setWalletLabels(msg.id(), msg.set_labels()); + break; + } - case Methods::getTxInScriptType: - { - if (msg.byteargs_size() != 2) - throw runtime_error("invalid command: getTxInScriptType"); + case BridgeProto::Wallet::kGetUtxosForValue: + { + bridge->getUtxosForValue(msg.id(), + msg.get_utxos_for_value().value(), referenceId); + break; + } - const auto& script = msg.byteargs(0); - BinaryData scriptBd((uint8_t*)script.c_str(), script.size()); + case BridgeProto::Wallet::kGetSpendableZcList: + { + bridge->getSpendableZCList(msg.id(), referenceId); + break; + } - const auto& hash = msg.byteargs(1); - BinaryData hashBd((uint8_t*)hash.c_str(), hash.size()); + case BridgeProto::Wallet::kGetRbfTxoutList: + { + bridge->getRBFTxOutList(msg.id(), referenceId); + break; + } - response = bridge->getTxInScriptType(scriptBd, hashBd); - break; - } + case BridgeProto::Wallet::kGetNewAddress: + { + response = bridge->getNewAddress(msg.id(), + msg.get_new_address().type()); + break; + } - case Methods::getTxOutScriptType: - { - if (msg.byteargs_size() != 1) - throw runtime_error("invalid command: getTxOutScriptType"); - const auto& byteargs = msg.byteargs(0); - BinaryData script((uint8_t*)byteargs.c_str(), byteargs.size()); - response = bridge->getTxOutScriptType(script); - break; + case BridgeProto::Wallet::kGetChangeAddress: + { + response = bridge->getChangeAddress(msg.id(), + msg.get_change_address().type()); + break; + } + + case BridgeProto::Wallet::kPeekChangeAddress: + { + response = bridge->peekChangeAddress(msg.id(), + msg.peek_change_address().type()); + break; + } } - case Methods::getScrAddrForScript: + if (response != nullptr) { - if (msg.byteargs_size() != 1) - throw runtime_error("invalid command: getScrAddrForScript"); - const auto& byteargs = msg.byteargs(0); - BinaryData script((uint8_t*)byteargs.c_str(), byteargs.size()); - response = bridge->getScrAddrForScript(script); - break; + //write response to socket + response->mutable_reply()->set_reference_id(referenceId); + bridge->writeToClient(move(response)); } + return true; +} - case Methods::getScrAddrForAddrStr: +//////////////////////////////////////////////////////////////////////////////// +bool ProtobufCommandParser::processCoinSelectionCommands(CppBridge* bridge, + unsigned referenceId, const BridgeProto::CoinSelection& msg) +{ + auto cs = bridge->coinSelectionInstance(msg.id()); + if (cs == nullptr) { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: getScrAddrForScript"); - response = bridge->getScrAddrForAddrStr(msg.stringargs(0)); - break; + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(false); + bridge->writeToClient(move(payload)); + return true; } - case Methods::getLastPushDataInScript: + BridgePayload response; + switch (msg.method_case()) { - if (msg.byteargs_size() != 1) - throw runtime_error("invalid command: getLastPushDataInScript"); + case BridgeProto::CoinSelection::kCleanup: + { + bridge->destroyCoinSelectionInstance(msg.id()); + break; + } - const auto& script = msg.byteargs(0); - BinaryData scriptBd((uint8_t*)script.c_str(), script.size()); + case BridgeProto::CoinSelection::kReset: + { + cs->resetRecipients(); + break; + } - response = bridge->getLastPushDataInScript(scriptBd); - break; - } + case BridgeProto::CoinSelection::kSetRecipient: + { + const auto& setRecipientMsg = msg.set_recipient(); + cs->updateRecipient(setRecipientMsg.id(), + setRecipientMsg.address(), setRecipientMsg.value()); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + response = move(payload); + break; + } - case Methods::getTxOutScriptForScrAddr: - { - if (msg.byteargs_size() != 1) - throw runtime_error("invalid command: getTxOutScriptForScrAddr"); + case BridgeProto::CoinSelection::kSelectUtxos: + { + const auto& selectMsg = msg.select_utxos(); + uint64_t flatFee = 0; + float feeByte = 0; + switch (selectMsg.fee_case()) + { + case BridgeProto::CoinSelection::SelectUTXOs::kFlatFee: + flatFee = selectMsg.flat_fee(); + break; + + case BridgeProto::CoinSelection::SelectUTXOs::kFeeByte: + feeByte = selectMsg.fee_byte(); + break; + } + cs->selectUTXOs(flatFee, feeByte, selectMsg.flags()); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + response = move(payload); + break; + } - const auto& script = msg.byteargs(0); - BinaryData scriptBd((uint8_t*)script.c_str(), script.size()); + case BridgeProto::CoinSelection::kGetUtxoSelection: + { + auto&& utxoVec = cs->getUtxoSelection(); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + auto utxoList = reply->mutable_coin_selection()->mutable_utxo_list(); + for (auto& utxo : utxoVec) + { + auto utxoProto = utxoList->add_utxo(); + CppToProto::utxo(utxoProto, utxo); + } + response = move(payload); + break; + } - response = bridge->getTxOutScriptForScrAddr(scriptBd); - break; - } + case BridgeProto::CoinSelection::kGetFlatFee: + { + auto flatFee = cs->getFlatFee(); - case Methods::getAddrStrForScrAddr: - { - if (msg.byteargs_size() != 1) - throw runtime_error("invalid command: getAddrStrForScrAddr"); - const auto& byteargs = msg.byteargs(0); - BinaryData script((uint8_t*)byteargs.c_str(), byteargs.size()); - response = bridge->getAddrStrForScrAddr(script); - break; - } + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); - case Methods::getNameForAddrType: - { - if (msg.intargs_size() != 1) - throw runtime_error("invalid command: getNameForAddrType"); - auto addrTypeInt = msg.intargs(0); - auto typeName = bridge->getNameForAddrType(addrTypeInt); - - auto replyMsg = make_unique(); - replyMsg->add_reply(typeName); - response = move(replyMsg); - break; - } + reply->mutable_coin_selection()->set_flat_fee(flatFee); + response = move(payload); + break; + } - case Methods::setAddressTypeFor: - { - if (msg.intargs_size() != 1 || msg.stringargs_size() != 1 || - msg.byteargs_size() != 1) + case BridgeProto::CoinSelection::kGetFeeByte: { - throw runtime_error("invalid command: setAddressTypeFor"); + auto feeByte = cs->getFeeByte(); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_coin_selection()->set_fee_byte(feeByte); + response = move(payload); + break; } - response = bridge->setAddressTypeFor( - msg.stringargs(0), msg.byteargs(0), msg.intargs(0)); - break; - } - case Methods::getHeaderByHeight: - { - if (msg.intargs_size() != 1) - throw runtime_error("invalid command: getHeaderByHeight"); - auto intArgs = msg.intargs(0); - bridge->getHeaderByHeight(intArgs, id); - break; - } + case BridgeProto::CoinSelection::kGetSizeEstimate: + { + auto sizeEstimate = cs->getSizeEstimate(); - case Methods::setupNewCoinSelectionInstance: - { - if (msg.intargs_size() != 1 || msg.stringargs_size() != 1) - throw runtime_error("invalid command: setupNewCoinSelectionInstance"); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); - bridge->setupNewCoinSelectionInstance( - msg.stringargs(0), msg.intargs(0), id); - break; - } + reply->mutable_coin_selection()->set_size_estimate(sizeEstimate); + response = move(payload); + break; + } - case Methods::destroyCoinSelectionInstance: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: destroyCoinSelectionInstance"); + case BridgeProto::CoinSelection::kProcessCustomUtxoList: + { + const auto& processMsg = msg.process_custom_utxo_list(); + + vector utxos; + utxos.reserve(processMsg.utxos_size()); + for (int i=0; iprocessCustomUtxoList(utxos, flatFee, feeByte, processMsg.flags()); + } + catch (exception&) + { + success = false; + } + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(success); + response = move(payload); + break; + } - bridge->destroyCoinSelectionInstance(msg.stringargs(0)); - break; + case BridgeProto::CoinSelection::kGetFeeForMaxVal: + { + const auto& getFeeMsg = msg.get_fee_for_max_val(); + auto feeByte = getFeeMsg.fee_byte(); + + float flatFee = 0; + if (getFeeMsg.utxos_size() == 0) + { + flatFee = cs->getFeeForMaxVal(feeByte); + } + else + { + vector serUtxos; + serUtxos.reserve(getFeeMsg.utxos_size()); + for (int i=0; igetFeeForMaxValUtxoVector(serUtxos, feeByte); + } + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_coin_selection()->set_flat_fee(flatFee); + response = move(payload); + break; + } } - case Methods::resetCoinSelection: + if (response != nullptr) { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: resetCoinSelection"); - bridge->resetCoinSelection(msg.stringargs(0)); - break; + //write response to socket + response->mutable_reply()->set_reference_id(referenceId); + bridge->writeToClient(move(response)); } + return true; +} - case Methods::setCoinSelectionRecipient: +//////////////////////////////////////////////////////////////////////////////// +bool ProtobufCommandParser::processSignerCommands(CppBridge* bridge, + unsigned referenceId, const BridgeProto::Signer& msg) +{ + auto signer = bridge->signerInstance(msg.id()); + if (signer == nullptr) { - if (msg.longargs_size() != 1 || - msg.stringargs_size() != 2 || - msg.intargs_size() != 1) + if (msg.id().empty()) { - throw runtime_error("invalid command: setCoinSelectionRecipient"); + auto response = bridge->initNewSigner(); + response->mutable_reply()->set_reference_id(referenceId); + + bridge->writeToClient(move(response)); + return true; } - auto success = bridge->setCoinSelectionRecipient(msg.stringargs(0), - msg.stringargs(1), msg.longargs(0), msg.intargs(0)); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(false); + reply->set_reference_id(referenceId); - auto responseProto = make_unique(); - responseProto->add_ints(success); - response = move(responseProto); - break; + bridge->writeToClient(move(payload)); + return true; } - case Methods::cs_SelectUTXOs: + BridgePayload response; + switch (msg.method_case()) { - if (msg.longargs_size() != 1 || - msg.stringargs_size() != 1 || - msg.intargs_size() != 1 || - msg.floatargs_size() != 1) + case BridgeProto::Signer::kGetNew: { - throw runtime_error("invalid command: cs_SelectUTXOs"); + throw runtime_error("invalid get_new request"); } - auto success = bridge->cs_SelectUTXOs(msg.stringargs(0), - msg.longargs(0), msg.floatargs(0), msg.intargs(0)); - - auto responseProto = make_unique(); - responseProto->add_ints(success); - response = move(responseProto); - break; - } - - case Methods::cs_getUtxoSelection: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: cs_getUtxoSelection"); - - response = bridge->cs_getUtxoSelection(msg.stringargs(0)); - break; - } - - case Methods::cs_getFlatFee: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: cs_getFlatFee"); + case BridgeProto::Signer::kCleanup: + { + bridge->destroySigner(msg.id()); + break; + } - response = bridge->cs_getFlatFee(msg.stringargs(0)); - break; - } + case BridgeProto::Signer::kSetVersion: + { + signer->signer_.setVersion(msg.set_version().version()); - case Methods::cs_getFeeByte: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: cs_getFeeByte"); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + response = move(payload); + break; + } - response = bridge->cs_getFeeByte(msg.stringargs(0)); - break; - } + case BridgeProto::Signer::kSetLockTime: + { + signer->signer_.setLockTime(msg.set_lock_time().lock_time()); - case Methods::cs_getSizeEstimate: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: cs_getSizeEstimate"); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + response = move(payload); + break; + } - response = bridge->cs_getSizeEstimate(msg.stringargs(0)); - break; - } + case BridgeProto::Signer::kAddSpenderByOutpoint: + { + const auto& addSpenderMsg = msg.add_spender_by_outpoint(); + const auto& hash = BinaryData::fromString(addSpenderMsg.hash()); + signer->signer_.addSpender_ByOutpoint(hash, + addSpenderMsg.tx_out_id(), addSpenderMsg.sequence()); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + response = move(payload); + break; + } - case Methods::cs_ProcessCustomUtxoList: - { - auto success = bridge->cs_ProcessCustomUtxoList(msg); + case BridgeProto::Signer::kPopulateUtxo: + { + const auto& populateUtxoMsg = msg.populate_utxo(); + const auto& hash = BinaryData::fromString(populateUtxoMsg.hash()); + const auto& script = BinaryData::fromString(populateUtxoMsg.script()); + UTXO utxo(populateUtxoMsg.value(), UINT32_MAX, UINT32_MAX, + populateUtxoMsg.tx_out_id(), hash, script); + + signer->signer_.populateUtxo(utxo); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + response = move(payload); + break; + } - auto responseProto = make_unique(); - responseProto->add_ints(success); - response = move(responseProto); - break; - } + case BridgeProto::Signer::kAddSupportingTx: + { + BinaryDataRef rawTxData; rawTxData.setRef( + msg.add_supporting_tx().raw_tx()); + signer->signer_.addSupportingTx(rawTxData); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + response = move(payload); + break; + } - case Methods::generateRandomHex: - { - if (msg.intargs_size() != 1) - throw runtime_error("invalid command: generateRandomHex"); - auto size = msg.intargs(0); - auto&& str = bridge->fortuna_.generateRandom(size).toHexStr(); - - auto msg = make_unique(); - msg->add_reply(str); - response = move(msg); - break; - } + case BridgeProto::Signer::kAddRecipient: + { + const auto& addMsg = msg.add_recipient(); + const auto& script = BinaryDataRef::fromString(addMsg.script()); + const auto hash = BtcUtils::getTxOutScrAddr(script); + signer->signer_.addRecipient( + Armory::CoinSelection::CoinSelectionInstance::createRecipient( + hash, addMsg.value())); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + response = move(payload); + break; + } - case Methods::createAddressBook: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: createAddressBook"); - bridge->createAddressBook(msg.stringargs(0), id); - break; - } + case BridgeProto::Signer::kToTxSigCollect: + { + auto txSigCollect = signer->signer_.toString( + static_cast( + msg.to_tx_sig_collect().ustx_type())); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + reply->mutable_signer()->set_tx_sig_collect(txSigCollect); + response = move(payload); + break; + } - case Methods::setComment: - { - bridge->setComment(msg); - break; - } + case BridgeProto::Signer::kFromTxSigCollect: + { + signer->signer_ = Armory::Signer::Signer::fromString( + msg.from_tx_sig_collect().tx_sig_collect()); + + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + response = move(payload); + break; + } - case Methods::getUtxosForValue: - { - if (msg.stringargs_size() != 1 || msg.longargs_size() != 1) - throw runtime_error("invalid command: getUtxosForValue"); - bridge->getUtxosForValue(msg.stringargs(0), msg.longargs(0), id); - break; - } + case BridgeProto::Signer::kSignTx: + { + signer->signTx(msg.sign_tx().wallet_id(), + msg.sign_tx().callback_id(), referenceId); + break; + } - case Methods::getSpendableZCList: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command getSpendableZCList"); - bridge->getSpendableZCList(msg.stringargs(0), id); - break; - } + case BridgeProto::Signer::kGetSignedTx: + { + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + try + { + auto data = signer->signer_.serializeSignedTx(); + reply->mutable_signer()->set_tx_data( + data.toCharPtr(), data.getSize()); + reply->set_success(true); + } + catch (const exception&) + { + reply->set_success(false); + } + + response = move(payload); + break; + } - case Methods::getRBFTxOutList: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: getRBFTxOutList"); - bridge->getRBFTxOutList(msg.stringargs(0), id); - break; - } + case BridgeProto::Signer::kGetUnsignedTx: + { + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + try + { + auto data = signer->signer_.serializeUnsignedTx(); + reply->mutable_signer()->set_tx_data( + data.toCharPtr(), data.getSize()); + reply->set_success(true); + } + catch (const exception&) + { + reply->set_success(false); + } + + response = move(payload); + break; + } - case Methods::getNewAddress: - { - if (msg.stringargs_size() != 1 || msg.intargs_size() != 1) - throw runtime_error("invalid command: getNewAddress"); - response = bridge->getNewAddress(msg.stringargs(0), msg.intargs(0)); - break; - } + case BridgeProto::Signer::kResolve: + { + auto result = signer->resolve(msg.resolve().wallet_id()); - case Methods::getChangeAddress: - { - if (msg.stringargs_size() != 1 || msg.intargs_size() != 1) - throw runtime_error("invalid command: getChangeAddress"); - response = bridge->getChangeAddress(msg.stringargs(0), msg.intargs(0)); - break; - } + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(result); + response = move(payload); + break; + } - case Methods::peekChangeAddress: - { - if (msg.stringargs_size() != 1 || msg.intargs_size() != 1) - throw runtime_error("invalid command: peekChangeAddress"); - response = bridge->peekChangeAddress(msg.stringargs(0), msg.intargs(0)); - break; - } + case BridgeProto::Signer::kGetSignedStateForInput: + { + response = signer->getSignedStateForInput( + msg.get_signed_state_for_input().input_id()); + break; + } - case Methods::getHash160: - { - if (msg.byteargs_size() != 1) - throw runtime_error("invalid command: getHash160"); - BinaryDataRef bdRef; bdRef.setRef(msg.byteargs(0)); - response = bridge->getHash160(bdRef); - break; - } + case BridgeProto::Signer::kFromType: + { + auto result = signer->signer_.deserializedFromType(); - case Methods::initNewSigner: - { - response = bridge->initNewSigner(); - break; - } + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); - case Methods::destroySigner: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: destroySigner"); - bridge->destroySigner(msg.stringargs(0)); - break; - } - - case Methods::signer_SetVersion: - { - if (msg.stringargs_size() != 1 || msg.intargs_size() != 1) - throw runtime_error("invalid command: signer_SetVersion"); - auto success = bridge->signer_SetVersion(msg.stringargs(0), msg.intargs(0)); - auto resultProto = make_unique(); - resultProto->add_ints(success); - response = move(resultProto); - break; - } + reply->mutable_signer()->set_from_type((int)result); + response = move(payload); + break; + } - case Methods::signer_SetLockTime: - { - if (msg.stringargs_size() != 1 || msg.intargs_size() != 1) - throw runtime_error("invalid command: signer_SetLockTime"); - auto result = bridge->signer_SetLockTime(msg.stringargs(0), msg.intargs(0)); - auto resultProto = make_unique(); - resultProto->add_ints(result); - response = move(resultProto); - break; + case BridgeProto::Signer::kCanLegacySerialize: + { + auto result = signer->signer_.canLegacySerialize(); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(result); + response = move(payload); + break; + } } - case Methods::signer_addSpenderByOutpoint: + if (response != nullptr) { - if (msg.stringargs_size() != 1 || msg.intargs_size() != 2 || - msg.byteargs_size() != 1) - throw runtime_error("invalid command: signer_addSpenderByOutpoint"); - - BinaryDataRef hash; hash.setRef(msg.byteargs(0)); - auto result = bridge->signer_addSpenderByOutpoint(msg.stringargs(0), - hash, msg.intargs(0), msg.intargs(1)); - - auto resultProto = make_unique(); - resultProto->add_ints(result); - response = move(resultProto); - break; + //write response to socket + response->mutable_reply()->set_reference_id(referenceId); + bridge->writeToClient(move(response)); } + return true; +} - case Methods::signer_populateUtxo: +//////////////////////////////////////////////////////////////////////////////// +bool ProtobufCommandParser::processUtilsCommands(CppBridge* bridge, + unsigned referenceId, const BridgeProto::Utils& msg) +{ + BridgePayload response; + switch (msg.method_case()) { - if (msg.stringargs_size() != 1 || msg.intargs_size() != 1 || - msg.byteargs_size() != 2 || msg.longargs_size() != 1) - throw runtime_error("invalid command: signer_populateUtxo"); + case BridgeProto::Utils::kCreateWallet: + { + auto wltId = bridge->createWallet(msg.create_wallet()); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); + + reply->mutable_utils()->set_wallet_id(wltId); + response = move(payload); + break; + } - BinaryDataRef hash; hash.setRef(msg.byteargs(0)); - BinaryDataRef script; script.setRef(msg.byteargs(1)); + case BridgeProto::Utils::kGenerateRandomHex: + { + auto size = msg.generate_random_hex().length(); + auto str = bridge->fortuna_.generateRandom(size).toHexStr(); - auto result = bridge->signer_populateUtxo(msg.stringargs(0), - hash, msg.intargs(0), msg.longargs(0), script); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); - auto resultProto = make_unique(); - resultProto->add_ints(result); - response = move(resultProto); - break; - } + reply->mutable_utils()->set_random_hex(str); + response = move(payload); + break; + } - case Methods::signer_addRecipient: - { - if (msg.stringargs_size() != 1 || - msg.byteargs_size() != 1 || msg.longargs_size() != 1) - throw runtime_error("invalid command: signer_addRecipient"); - - BinaryDataRef script; script.setRef(msg.byteargs(0)); - auto result = bridge->signer_addRecipient(msg.stringargs(0), - script, msg.longargs(0)); - - auto resultProto = make_unique(); - resultProto->add_ints(result); - response = move(resultProto); - break; - } + case BridgeProto::Utils::kGetHash160: + { + const auto& getHashMsg = msg.get_hash_160(); + const auto& data = BinaryDataRef::fromString(getHashMsg.data()); + response = bridge->getHash160(data); + break; + } - case Methods::signer_getSerializedState: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: signer_getSerializedState"); - response = bridge->signer_getSerializedState(msg.stringargs(0)); - break; - } + case BridgeProto::Utils::kGetScraddrForAddrstr: + { + response = bridge->getScrAddrForAddrStr( + msg.get_scraddr_for_addrstr().address()); + break; + } - case Methods::signer_unserializeState: - { - if (msg.stringargs_size() != 1 || msg.byteargs_size() != 1) - throw runtime_error("invalid command: signer_unserializeState"); + case BridgeProto::Utils::kGetNameForAddrType: + { + auto addrTypeInt = msg.get_name_for_addr_type().address_type(); + auto typeName = bridge->getNameForAddrType(addrTypeInt); - auto result = bridge->signer_unserializeState( - msg.stringargs(0), BinaryData::fromString(msg.byteargs(0))); + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(true); - auto resultProto = make_unique(); - resultProto->add_ints(result); - response = move(resultProto); - break; + reply->mutable_utils()->set_address_type_name(typeName); + response = move(payload); + break; + } } - case Methods::signer_signTx: + if (response != nullptr) { - if (msg.stringargs_size() != 2) - throw runtime_error("invalid command: signer_signTx"); - bridge->signer_signTx(msg.stringargs(0), msg.stringargs(1), id); - break; + //write response to socket + response->mutable_reply()->set_reference_id(referenceId); + bridge->writeToClient(move(response)); } + return true; +} - case Methods::signer_getSignedTx: - { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: signer_getSignedTx"); - - response = bridge->signer_getSignedTx(msg.stringargs(0)); - break; - } +//////////////////////////////////////////////////////////////////////////////// +bool ProtobufCommandParser::processScriptUtilsCommands(CppBridge* bridge, + unsigned referenceId, const BridgeProto::ScriptUtils& msg) +{ + BridgePayload response; + const auto& script = BinaryDataRef::fromString(msg.script()); - case Methods::signer_getUnsignedTx: + switch (msg.method_case()) { - if (msg.stringargs_size() != 1) - throw runtime_error("invalid command: signer_getUnsignedTx"); + case BridgeProto::ScriptUtils::kGetTxinScriptType: + { + const auto& getTxInMsg = msg.get_txin_script_type(); + const auto& hash = BinaryDataRef::fromString(getTxInMsg.hash()); - response = bridge->signer_getUnsignedTx(msg.stringargs(0)); - break; - } + response = bridge->getTxInScriptType(script, hash); + break; + } - case Methods::signer_resolve: - { - if (msg.stringargs_size() != 2) - throw runtime_error("invalid command: signer_resolve"); + case BridgeProto::ScriptUtils::kGetTxoutScriptType: + { + response = bridge->getTxOutScriptType(script); + break; + } - auto result = bridge->signer_resolve( - msg.stringargs(0), msg.stringargs(1)); + case BridgeProto::ScriptUtils::kGetScraddrForScript: + { + response = bridge->getScrAddrForScript(script); + break; + } - auto resultProto = make_unique(); - resultProto->add_ints(result); - response = move(resultProto); - break; - } + case BridgeProto::ScriptUtils::kGetLastPushDataInScript: + { + response = bridge->getLastPushDataInScript(script); + break; + } - case Methods::signer_getSignedStateForInput: - { - if (msg.stringargs_size() != 1 || msg.intargs_size() != 1) + case BridgeProto::ScriptUtils::kGetTxoutScriptForScraddr: { - throw runtime_error( - "invalid command: signer_getSignedStateForInput"); + response = bridge->getTxOutScriptForScrAddr(script); + break; } - response = bridge->signer_getSignedStateForInput( - msg.stringargs(0), msg.intargs(0)); - break; + case BridgeProto::ScriptUtils::kGetAddrstrForScraddr: + { + response = bridge->getAddrStrForScrAddr(script); + break; + } } - case Methods::returnPassphrase: + if (response != nullptr) { - if (msg.stringargs_size() != 2) - throw runtime_error("invalid command: returnPassphrase"); - - auto result = bridge->returnPassphrase(msg.stringargs(0), msg.stringargs(1)); - - auto resultProto = make_unique(); - resultProto->add_ints(result); - response = move(resultProto); - break; + //write response to socket + response->mutable_reply()->set_reference_id(referenceId); + bridge->writeToClient(move(response)); } + return true; +} - case Methods::broadcastTx: +//////////////////////////////////////////////////////////////////////////////// +bool ProtobufCommandParser::processCallbackReply(CppBridge* bridge, + const BridgeProto::CallbackReply& msg) +{ + try { - if (msg.byteargs_size() == 0) - throw runtime_error("invalid command: broadcastTx"); - - vector bdVec; - for (int i=0; ibroadcastTx(bdVec); - break; + auto handler = bridge->getCallbackHandler(msg.reference_id()); + return handler(msg); } - - case Methods::getBlockTimeByHeight: + catch (const std::runtime_error&) { - if (msg.intargs_size() != 1) - throw runtime_error("invalid command: getBlockTimeByHeight"); - bridge->getBlockTimeByHeight(msg.intargs(0), id); - break; + return false; } +} - case Methods::estimateFee: +//////////////////////////////////////////////////////////////////////////////// +bool ProtobufCommandParser::processData( + CppBridge* bridge, BinaryDataRef socketData) +{ + BridgeProto::Request msg; + if (!msg.ParseFromArray(socketData.getPtr() + 1, socketData.getSize() - 1)) { - if (msg.intargs_size() != 1 || msg.stringargs_size() != 1) - throw runtime_error("invalid command: estimateFee"); - bridge->estimateFee(msg.intargs(0), msg.stringargs(0), id); - break; - } - - default: - stringstream ss; - ss << "unknown client method: " << msg.method(); - throw runtime_error(ss.str()); + LOGERR << "failed to parse protobuf msg"; + return false; } - if (response != nullptr) - { - //write response to socket - bridge->writeToClient(move(response), id); + const auto& id = msg.reference_id(); + switch (msg.method_case()) + { + case BridgeProto::Request::kService: + return processBlockchainServiceCommands(bridge, id, msg.service()); + case BridgeProto::Request::kWallet: + return processWalletCommands(bridge, id, msg.wallet()); + case BridgeProto::Request::kCoinSelection: + return processCoinSelectionCommands(bridge, id, msg.coin_selection()); + case BridgeProto::Request::kSigner: + return processSignerCommands(bridge, id, msg.signer()); + case BridgeProto::Request::kUtils: + return processUtilsCommands(bridge, id, msg.utils()); + case BridgeProto::Request::kScriptUtils: + return processScriptUtilsCommands(bridge, id, msg.script_utils()); + case BridgeProto::Request::kCallbackReply: + return processCallbackReply(bridge, msg.callback_reply()); + + case BridgeProto::Request::METHOD_NOT_SET: + { + auto payload = make_unique(); + auto reply = payload->mutable_reply(); + reply->set_success(false); + reply->set_reference_id(id); + bridge->writeToClient(move(payload)); + return false; + } } return true; diff --git a/cppForSwig/BridgeAPI/ProtobufCommandParser.h b/cppForSwig/BridgeAPI/ProtobufCommandParser.h index 313979489..6084406a6 100644 --- a/cppForSwig/BridgeAPI/ProtobufCommandParser.h +++ b/cppForSwig/BridgeAPI/ProtobufCommandParser.h @@ -11,14 +11,42 @@ #include "BinaryData.h" +namespace BridgeProto +{ + class BlockchainService; + class Wallet; + class CoinSelection; + class Signer; + class Utils; + class ScriptUtils; + class CallbackReply; +}; + namespace Armory { namespace Bridge { class CppBridge; - struct ProtobufCommandParser + class ProtobufCommandParser { + private: + static bool processBlockchainServiceCommands(CppBridge*, unsigned, + const BridgeProto::BlockchainService&); + static bool processWalletCommands(CppBridge*, unsigned, + const BridgeProto::Wallet&); + static bool processCoinSelectionCommands(CppBridge*, unsigned, + const BridgeProto::CoinSelection&); + static bool processSignerCommands(CppBridge*, unsigned, + const BridgeProto::Signer&); + static bool processUtilsCommands(CppBridge*, unsigned, + const BridgeProto::Utils&); + static bool processScriptUtilsCommands(CppBridge*, unsigned, + const BridgeProto::ScriptUtils&); + static bool processCallbackReply(CppBridge*, + const BridgeProto::CallbackReply&); + + public: static bool processData(CppBridge*, BinaryDataRef); }; }; //namespace Bridge diff --git a/cppForSwig/BridgeAPI/ProtobufConversions.cpp b/cppForSwig/BridgeAPI/ProtobufConversions.cpp index b931c9a32..91343e5d3 100644 --- a/cppForSwig/BridgeAPI/ProtobufConversions.cpp +++ b/cppForSwig/BridgeAPI/ProtobufConversions.cpp @@ -8,6 +8,7 @@ #include "ProtobufConversions.h" #include "../Wallets/WalletIdTypes.h" +#include "../Wallets/AssetEncryption.h" #include "DBClientClasses.h" #include "TxEvalState.h" @@ -18,7 +19,7 @@ using namespace Armory::Bridge; using namespace Armory::Accounts; using namespace Armory::Wallets; -using namespace Codec_ClientProto; +using namespace BridgeProto; /*** TODO: use the same protobuf as the DB for all things regarding wallet balance @@ -26,8 +27,8 @@ TODO: use the same protobuf as the DB for all things regarding wallet balance ***/ //////////////////////////////////////////////////////////////////////////////// -void CppToProto::ledger( - BridgeLedger* ledgerProto, const DBClientClasses::LedgerEntry& ledgerCpp) +void CppToProto::ledger(Ledger* ledgerProto, + const DBClientClasses::LedgerEntry& ledgerCpp) { ledgerProto->set_value(ledgerCpp.getValue()); @@ -36,22 +37,23 @@ void CppToProto::ledger( ledgerProto->set_id(ledgerCpp.getID()); ledgerProto->set_height(ledgerCpp.getBlockNum()); - ledgerProto->set_txindex(ledgerCpp.getIndex()); - ledgerProto->set_txtime(ledgerCpp.getTxTime()); - ledgerProto->set_iscoinbase(ledgerCpp.isCoinbase()); - ledgerProto->set_issenttoself(ledgerCpp.isSentToSelf()); - ledgerProto->set_ischangeback(ledgerCpp.isChangeBack()); - ledgerProto->set_ischainedzc(ledgerCpp.isChainedZC()); - ledgerProto->set_iswitness(ledgerCpp.isWitness()); - ledgerProto->set_isrbf(ledgerCpp.isOptInRBF()); + ledgerProto->set_tx_index(ledgerCpp.getIndex()); + ledgerProto->set_tx_time(ledgerCpp.getTxTime()); + ledgerProto->set_coinbase(ledgerCpp.isCoinbase()); + ledgerProto->set_sent_to_self(ledgerCpp.isSentToSelf()); + ledgerProto->set_change_back(ledgerCpp.isChangeBack()); + ledgerProto->set_chained_zc(ledgerCpp.isChainedZC()); + ledgerProto->set_witness(ledgerCpp.isWitness()); + ledgerProto->set_rbf(ledgerCpp.isOptInRBF()); for (auto& scrAddr : ledgerCpp.getScrAddrList()) - ledgerProto->add_scraddrlist(scrAddr.getCharPtr(), scrAddr.getSize()); + ledgerProto->add_scraddr(scrAddr.getCharPtr(), scrAddr.getSize()); } //////////////////////////////////////////////////////////////////////////////// -void CppToProto::addr(WalletAsset* assetPtr, - shared_ptr addrPtr, shared_ptr accPtr) +bool CppToProto::addr(WalletReply::AddressData* assetPtr, + shared_ptr addrPtr, shared_ptr accPtr, + const EncryptionKeyId& defaultEncryptionKeyId) { if (accPtr == nullptr) throw runtime_error("[CppToProto::addr] null acc ptr"); @@ -61,51 +63,89 @@ void CppToProto::addr(WalletAsset* assetPtr, //address auto& addrHash = addrPtr->getPrefixedHash(); - assetPtr->set_prefixedhash(addrHash.toCharPtr(), addrHash.getSize()); + assetPtr->set_prefixed_hash(addrHash.toCharPtr(), addrHash.getSize()); //address type & pubkey BinaryDataRef pubKeyRef; + std::shared_ptr addrWithAssetPtr = nullptr; uint32_t addrType = (uint32_t)addrPtr->getType(); + auto addrNested = dynamic_pointer_cast(addrPtr); if (addrNested != nullptr) { addrType |= (uint32_t)addrNested->getPredecessor()->getType(); - pubKeyRef = addrNested->getPredecessor()->getPreimage().getRef(); + auto pred = addrNested->getPredecessor(); + pubKeyRef = pred->getPreimage().getRef(); + + addrWithAssetPtr = dynamic_pointer_cast(pred); } else { pubKeyRef = addrPtr->getPreimage().getRef(); + addrWithAssetPtr = dynamic_pointer_cast(addrPtr); } - assetPtr->set_addrtype(addrType); - assetPtr->set_publickey(pubKeyRef.toCharPtr(), pubKeyRef.getSize()); + assetPtr->set_addr_type(addrType); + assetPtr->set_public_key(pubKeyRef.toCharPtr(), pubKeyRef.getSize()); //index assetPtr->set_id(wltAsset->getIndex()); const auto& serAssetId = assetID.getSerializedKey(PROTO_ASSETID_PREFIX); - assetPtr->set_assetid(serAssetId.getCharPtr(), serAssetId.getSize()); + assetPtr->set_asset_id(serAssetId.getCharPtr(), serAssetId.getSize()); //address string const auto& addrStr = addrPtr->getAddress(); - assetPtr->set_addressstring(addrStr); + assetPtr->set_address_string(addrStr); auto isUsed = accPtr->isAssetInUse(addrPtr->getID()); - assetPtr->set_isused(isUsed); + assetPtr->set_is_used(isUsed); //resolve change status bool isChange = accPtr->isAssetChange(addrPtr->getID()); - assetPtr->set_ischange(isChange); + assetPtr->set_is_change(isChange); + + //priv key & encryption status + bool isLocked = false; + bool hasPrivKey = false; + if (addrWithAssetPtr != nullptr) + { + auto theAsset = addrWithAssetPtr->getAsset(); + if (theAsset != nullptr) + { + if (theAsset->hasPrivateKey()) + { + hasPrivKey = true; + try + { + //the privkey is considered locked if it's encrypted by + //something else than the default encryption key, which + //lays in clear text in the wallet header + auto encryptionKeyId = theAsset->getPrivateEncryptionKeyId(); + isLocked = (encryptionKeyId != defaultEncryptionKeyId); + } + catch (const runtime_error&) + { + //nothing to do, address has no encryption key + } + } + } + } + assetPtr->set_has_priv_key(hasPrivKey); + assetPtr->set_use_encryption(isLocked); //precursor, if any if (addrNested == nullptr) - return; + return isLocked; auto& precursor = addrNested->getPredecessor()->getScript(); - assetPtr->set_precursorscript(precursor.getCharPtr(), precursor.getSize()); + assetPtr->set_precursor_script(precursor.getCharPtr(), precursor.getSize()); + + return isLocked; } //////////////////////////////////////////////////////////////////////////////// -void CppToProto::wallet(WalletData* wltProto, shared_ptr wltPtr, +void CppToProto::wallet(WalletReply::WalletData* wltProto, + shared_ptr wltPtr, const Armory::Wallets::AddressAccountId& accId, const map& commentMap) { @@ -117,7 +157,7 @@ void CppToProto::wallet(WalletData* wltProto, shared_ptr wltPtr, auto wltSingle = dynamic_pointer_cast(wltPtr); if (wltSingle != nullptr) isWO = wltSingle->isWatchingOnly(); - wltProto->set_watchingonly(isWO); + wltProto->set_watching_only(isWO); //the address account auto accPtr = wltSingle->getAccountForID(accId); @@ -125,22 +165,35 @@ void CppToProto::wallet(WalletData* wltProto, shared_ptr wltPtr, //address types const auto& addrTypes = accPtr->getAddressTypeSet(); for (const auto& addrType : addrTypes) - wltProto->add_addresstypes(addrType); - wltProto->set_defaultaddresstype((uint32_t)accPtr->getDefaultAddressType()); + wltProto->add_address_type(addrType); + wltProto->set_default_address_type((uint32_t)accPtr->getDefaultAddressType()); //use index auto assetAccountPtr = accPtr->getOuterAccount(); - wltProto->set_lookupcount(assetAccountPtr->getLastComputedIndex()); - wltProto->set_usecount(assetAccountPtr->getHighestUsedIndex()); + wltProto->set_lookup_count(assetAccountPtr->getLastComputedIndex()); + wltProto->set_use_count(assetAccountPtr->getHighestUsedIndex()); //address map auto addrMap = accPtr->getUsedAddressMap(); + bool useEncryption = true; for (auto& addrPair : addrMap) { - auto assetPtr = wltProto->add_assets(); - CppToProto::addr(assetPtr, addrPair.second, accPtr); + auto assetPtr = wltProto->add_address_data(); + useEncryption &= CppToProto::addr(assetPtr, addrPair.second, accPtr, + wltPtr->getDefaultEncryptionKeyId()); } + //encryption info + wltProto->set_use_encryption(useEncryption); + + uint32_t kdfMem = 0; + auto kdfPtr = wltPtr->getDefaultKdf(); + auto kdfRomix = dynamic_pointer_cast< + Encryption::KeyDerivationFunction_Romix>(kdfPtr); + if (kdfRomix != nullptr) + kdfMem = kdfRomix->memTarget(); + wltProto->set_kdf_mem_req(kdfMem); + //labels wltProto->set_label(wltPtr->getLabel()); wltProto->set_desc(wltPtr->getDescription()); @@ -156,15 +209,15 @@ void CppToProto::wallet(WalletData* wltProto, shared_ptr wltPtr, } //////////////////////////////////////////////////////////////////////////////// -void CppToProto::utxo(BridgeUtxo* utxoProto, const UTXO& utxo) +void CppToProto::utxo(Utxo* utxoProto, const UTXO& utxo) { auto& hash = utxo.getTxHash(); - utxoProto->set_txhash(hash.getCharPtr(), hash.getSize()); - utxoProto->set_txoutindex(utxo.getTxOutIndex()); + utxoProto->set_tx_hash(hash.getCharPtr(), hash.getSize()); + utxoProto->set_txout_index(utxo.getTxOutIndex()); utxoProto->set_value(utxo.getValue()); - utxoProto->set_txheight(utxo.getHeight()); - utxoProto->set_txindex(utxo.getTxIndex()); + utxoProto->set_tx_height(utxo.getHeight()); + utxoProto->set_tx_index(utxo.getTxIndex()); auto& script = utxo.getScript(); utxoProto->set_script(script.getCharPtr(), script.getSize()); @@ -174,40 +227,41 @@ void CppToProto::utxo(BridgeUtxo* utxoProto, const UTXO& utxo) } //////////////////////////////////////////////////////////////////////////////// -void CppToProto::nodeStatus( - BridgeNodeStatus* nsProto, const DBClientClasses::NodeStatus& nsCpp) +void CppToProto::nodeStatus(NodeStatus* nsProto, + const DBClientClasses::NodeStatus& nsCpp) { auto chainStatus = nsCpp.chainStatus(); - nsProto->set_isvalid(true); - nsProto->set_nodestate(nsCpp.state()); - nsProto->set_issegwitenabled(nsCpp.isSegWitEnabled()); - nsProto->set_rpcstate(nsCpp.rpcState()); + nsProto->set_is_valid(true); + nsProto->set_node_state(nsCpp.state()); + nsProto->set_is_segwit_enabled(nsCpp.isSegWitEnabled()); + nsProto->set_rpc_state(nsCpp.rpcState()); - auto chainStatusProto = nsProto->mutable_chainstatus(); + auto chainStatusProto = nsProto->mutable_chain_status(); - chainStatusProto->set_chainstate(chainStatus.state()); - chainStatusProto->set_blockspeed(chainStatus.getBlockSpeed()); - chainStatusProto->set_progresspct(chainStatus.getProgressPct()); + chainStatusProto->set_chain_state(chainStatus.state()); + chainStatusProto->set_block_speed(chainStatus.getBlockSpeed()); + chainStatusProto->set_progress_pct(chainStatus.getProgressPct()); chainStatusProto->set_eta(chainStatus.getETA()); - chainStatusProto->set_blocksleft(chainStatus.getBlocksLeft()); + chainStatusProto->set_blocks_left(chainStatus.getBlocksLeft()); } //////////////////////////////////////////////////////////////////////////////// void CppToProto::signatureState( - BridgeInputSignedState* ssProto, const Armory::Signer::TxInEvalState& ssCpp) + SignerReply::InputSignedState* ssProto, + const Armory::Signer::TxInEvalState& ssCpp) { - ssProto->set_isvalid(ssCpp.isValid()); + ssProto->set_is_valid(ssCpp.isValid()); ssProto->set_m(ssCpp.getM()); ssProto->set_n(ssCpp.getN()); - ssProto->set_sigcount(ssCpp.getSigCount()); + ssProto->set_sig_count(ssCpp.getSigCount()); const auto& pubKeyMap = ssCpp.getPubKeyMap(); for (auto& pubKeyPair : pubKeyMap) { - auto keyData = ssProto->add_signstatelist(); - keyData->set_pubkey( + auto keyData = ssProto->add_sign_state(); + keyData->set_pub_key( pubKeyPair.first.getCharPtr(), pubKeyPair.first.getSize()); - keyData->set_hassig(pubKeyPair.second); + keyData->set_has_sig(pubKeyPair.second); } } diff --git a/cppForSwig/BridgeAPI/ProtobufConversions.h b/cppForSwig/BridgeAPI/ProtobufConversions.h index e5717a28c..87e4339ee 100644 --- a/cppForSwig/BridgeAPI/ProtobufConversions.h +++ b/cppForSwig/BridgeAPI/ProtobufConversions.h @@ -10,13 +10,14 @@ #define _BRIDGE_PROTOBUF_CONVERSION_H #include - -#include "../protobuf/ClientProto.pb.h" +#ifdef BUILD_PROTOBUF +#include "../protobuf/BridgeProto.pb.h" +#endif #define PROTO_ASSETID_PREFIX 0xAFu //forward declarations -class UTXO; +struct UTXO; class AddressEntry; class BinaryData; @@ -37,6 +38,7 @@ namespace Armory { class AddressAccountId; class AssetWallet; + class EncryptionKeyId; }; namespace Signer @@ -50,30 +52,31 @@ namespace Armory struct CppToProto { static void ledger( - Codec_ClientProto::BridgeLedger*, + BridgeProto::Ledger*, const DBClientClasses::LedgerEntry&); - static void addr( - Codec_ClientProto::WalletAsset*, + static bool addr( + BridgeProto::WalletReply::AddressData*, std::shared_ptr, - std::shared_ptr); + std::shared_ptr, + const Wallets::EncryptionKeyId&); static void wallet( - Codec_ClientProto::WalletData*, + BridgeProto::WalletReply::WalletData*, std::shared_ptr, const Wallets::AddressAccountId&, const std::map&); static void utxo( - Codec_ClientProto::BridgeUtxo*, + BridgeProto::Utxo*, const UTXO& utxo); static void nodeStatus( - Codec_ClientProto::BridgeNodeStatus*, + BridgeProto::NodeStatus*, const DBClientClasses::NodeStatus&); static void signatureState( - Codec_ClientProto::BridgeInputSignedState*, + BridgeProto::SignerReply::InputSignedState*, const Signer::TxInEvalState&); }; }; //namespace Bridge diff --git a/cppForSwig/BridgeAPI/WalletManager.cpp b/cppForSwig/BridgeAPI/WalletManager.cpp index 527a61676..45f6021fa 100644 --- a/cppForSwig/BridgeAPI/WalletManager.cpp +++ b/cppForSwig/BridgeAPI/WalletManager.cpp @@ -1,14 +1,15 @@ //////////////////////////////////////////////////////////////////////////////// // // -// Copyright (C) 2016-20, goatpig // +// Copyright (C) 2016-2023, goatpig // // Distributed under the MIT license // // See LICENSE-MIT or https://opensource.org/licenses/MIT // // // //////////////////////////////////////////////////////////////////////////////// #include "WalletManager.h" -#include "ArmoryBackups.h" +#include "Wallets/Seeds/Backups.h" #include "PassphrasePrompt.h" +#include "../Wallets/Seeds/Seeds.h" #ifdef _WIN32 #include "leveldb_windows_port\win32_posix\dirent_win32.h" @@ -20,6 +21,7 @@ using namespace std; using namespace Armory::Signer; using namespace Armory::Accounts; using namespace Armory::Wallets; +using namespace Armory::Seeds; #define WALLET_135_HEADER "\xbaWALLET\x00" #define PYBTC_ADDRESS_SIZE 237 @@ -151,8 +153,11 @@ shared_ptr WalletManager::createNewWallet( if (extraEntropy.getSize() >= 32) root.XOR(extraEntropy); - auto wallet = AssetWallet_Single::createFromPrivateRoot_Armory135( - path_, root, {}, pass, controlPass, lookup); + unique_ptr seed(new ClearTextSeed_Armory135(root, + ClearTextSeed_Armory135::LegacyType::Armory200)); + auto wallet = AssetWallet_Single::createFromSeed(move(seed), + pass, controlPass, + path_, lookup); return addWallet(wallet, wallet->getMainAccountID()); } @@ -635,7 +640,7 @@ map> WalletContainer::getUpdatedAddressMap( } //////////////////////////////////////////////////////////////////////////////// -Armory::Backups::WalletBackup WalletContainer::getBackupStrings( +unique_ptr WalletContainer::getBackupStrings( const PassphraseLambda& passLbd) const { auto wltSingle = dynamic_pointer_cast(wallet_); @@ -647,7 +652,7 @@ Armory::Backups::WalletBackup WalletContainer::getBackupStrings( } wltSingle->setPassphrasePromptLambda(passLbd); - auto backupStrings = Armory::Backups::Helpers::getWalletBackup(wltSingle); + auto backupStrings = Armory::Seeds::Helpers::getWalletBackup(wltSingle); wltSingle->resetPassphrasePromptLambda(); return backupStrings; @@ -668,6 +673,19 @@ void WalletContainer::setComment(const string& key, const string& val) wallet_->setComment(keyBd, val); } +//////////////////////////////////////////////////////////////////////////////// +void WalletContainer::setLabels(const string& title, const string& desc) +{ + wallet_->setLabel(title); + wallet_->setDescription(desc); +} + +//////////////////////////////////////////////////////////////////////////////// +const EncryptionKeyId& WalletContainer::getDefaultEncryptionKeyId() const +{ + return wallet_->getDefaultEncryptionKeyId(); +} + //////////////////////////////////////////////////////////////////////////////// //// //// Armory135Header @@ -868,7 +886,7 @@ shared_ptr Armory135Header::migrate( { //decrypt lbd auto decryptPrivKey = [this, &privKeyPass]( - const PassphraseLambda& passLbd, + const PassphraseLambda& passLbd, const Armory135Address& rootAddrObj)->SecureBinaryData { set idSet = { BinaryData::fromString(walletID_) }; @@ -904,7 +922,8 @@ shared_ptr Armory135Header::migrate( decryptedRoot = move(decryptPrivKey(passLbd, rootAddrObj)); } - passLbd({Armory::Bridge::BridgePassphrasePrompt::concludeKey}); + //cleanup + passLbd({}); } //create wallet @@ -918,9 +937,11 @@ shared_ptr Armory135Header::migrate( } else { - wallet = AssetWallet_Single::createFromPrivateRoot_Armory135( - folder, decryptedRoot, chaincodeCopy, - privKeyPass, controlPass, highestIndex); + unique_ptr seed(new ClearTextSeed_Armory135( + decryptedRoot, chaincodeCopy)); + wallet = AssetWallet_Single::createFromSeed(move(seed), + privKeyPass, controlPass, + folder, highestIndex); } //main account id, check it matches armory wallet id diff --git a/cppForSwig/BridgeAPI/WalletManager.h b/cppForSwig/BridgeAPI/WalletManager.h index 8d2d581fe..d2b654b5a 100644 --- a/cppForSwig/BridgeAPI/WalletManager.h +++ b/cppForSwig/BridgeAPI/WalletManager.h @@ -27,7 +27,7 @@ namespace Armory { - namespace Backups + namespace Seeds { struct WalletBackup; }; @@ -41,6 +41,7 @@ namespace Armory { class AddressAccountId; class AssetWallet; + class EncryptionKeyId; }; }; @@ -214,9 +215,13 @@ class WalletContainer Armory::Wallets::AssetKeyType getHighestUsedIndex(void) const; std::map> getUpdatedAddressMap(); - Armory::Backups::WalletBackup getBackupStrings(const PassphraseLambda&) const; + std::unique_ptr getBackupStrings( + const PassphraseLambda&) const; void setComment(const std::string&, const std::string&); + void setLabels(const std::string&, const std::string&); + + const Armory::Wallets::EncryptionKeyId& getDefaultEncryptionKeyId() const; }; //////////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/BtcUtils.cpp b/cppForSwig/BtcUtils.cpp index 6a49acb63..68e82b26b 100644 --- a/cppForSwig/BtcUtils.cpp +++ b/cppForSwig/BtcUtils.cpp @@ -7,7 +7,6 @@ //////////////////////////////////////////////////////////////////////////////// #include "BtcUtils.h" -#include "EncryptionUtils.h" #include "ArmoryConfig.h" #include "btc/segwit_addr.h" #include "TxOutScrRef.h" @@ -188,6 +187,40 @@ void BtcUtils::getHMAC512(const void* keyptr, size_t keylen, CryptoSHA2::getHMAC512(key_bdr, msg_bdr, (uint8_t*)digest); } +//////////////////////////////////////////////////////////////////////////////// +BinaryData BtcUtils::getBotchedArmoryHMAC256( + const BinaryData& key, const BinaryData& msg) +{ + BinaryData hmacKey; + if (key.getSize() > 32) + { + hmacKey = BtcUtils::getSha256(key); + } + else if (key.getSize() <= 32) + { + hmacKey.resize(32); + memcpy(hmacKey.getPtr(), key.getPtr(), key.getSize()); + memset(hmacKey.getPtr() + key.getSize(), 0, 32 - key.getSize()); + } + + BinaryData oxor(32), ixor(32); + for (int i=0; i<32; i++) + { + oxor.getPtr()[i] = hmacKey.getPtr()[i] ^ 0x5c; + ixor.getPtr()[i] = hmacKey.getPtr()[i] ^ 0x36; + } + + ixor.append(msg); + auto iHash = BtcUtils::getSha256(ixor); + + BinaryWriter bw; + bw.put_BinaryData(oxor); + bw.put_BinaryData(iHash); + + return BtcUtils::getSha256(bw.getData()); + +} + //////////////////////////////////////////////////////////////////////////////// SecureBinaryData BtcUtils::computeChainCode_Armory135( const SecureBinaryData& privateRoot) @@ -197,18 +230,16 @@ SecureBinaryData BtcUtils::computeChainCode_Armory135( key: double SHA256 of the root key message: 'Derive Chaincode from Root Key' - TODO: The Armory Python code uses a botched self implemented HMAC256, + TODO: The Armory Python code uses a botched self implemented HMAC256, reproduce it here. */ - auto&& hmacKey = BtcUtils::hash256(privateRoot); - string hmacMsg("Derive Chaincode from Root Key"); - SecureBinaryData chainCode(32); - - getHMAC256(hmacKey.getPtr(), hmacKey.getSize(), - hmacMsg.c_str(), hmacMsg.size(), chainCode.getPtr()); + auto hmacKey = BtcUtils::hash256(privateRoot); + auto hmacMsg = BinaryData::fromString("Derive Chaincode from Root Key"); - return chainCode; + //use key as is for invalid armory hmac256: armory erroneously uses the + //output size for sha256 (32 bytes) instead of the block size (64 bytes) + return getBotchedArmoryHMAC256(hmacKey, hmacMsg); } //////////////////////////////////////////////////////////////////////////////// @@ -239,13 +270,13 @@ BinaryData BtcUtils::getScrAddrForAddrStr(const string& addrStr) try { - scrAddr = move(base58toScrAddr(addrStr)); + scrAddr = base58toScrAddr(addrStr); } catch (const exception&) { - auto scrAddrPair = move(BtcUtils::segWitAddressToScrAddr(addrStr)); + auto scrAddrPair = BtcUtils::segWitAddressToScrAddr(addrStr); if (scrAddrPair.second != 0) - throw runtime_error("[createRecipient] unsupported sw version"); + throw runtime_error("[getScrAddrForAddrStr] unsupported sw version"); switch (scrAddrPair.first.getSize()) { @@ -438,28 +469,28 @@ TxOutScriptRef BtcUtils::getTxOutScrAddrNoCopy(BinaryDataRef script) case(TXOUT_SCRIPT_STDHASH160) : { outputRef.type_ = p2pkh_prefix; - outputRef.scriptRef_ = move(script.getSliceRef(3, 20)); + outputRef.scriptRef_ = script.getSliceRef(3, 20); break; } case(TXOUT_SCRIPT_P2WPKH) : { outputRef.type_ = SCRIPT_PREFIX_P2WPKH; - outputRef.scriptRef_ = move(script.getSliceRef(2, 20)); + outputRef.scriptRef_ = script.getSliceRef(2, 20); break; } case(TXOUT_SCRIPT_P2WSH) : { outputRef.type_ = SCRIPT_PREFIX_P2WSH; - outputRef.scriptRef_ = move(script.getSliceRef(2, 32)); + outputRef.scriptRef_ = script.getSliceRef(2, 32); break; } case(TXOUT_SCRIPT_STDPUBKEY65) : { outputRef.type_ = p2pkh_prefix; - outputRef.scriptCopy_ = move(getHash160(script.getSliceRef(1, 65))); + outputRef.scriptCopy_ = getHash160(script.getSliceRef(1, 65)); outputRef.scriptRef_.setRef(outputRef.scriptCopy_); break; } @@ -467,7 +498,7 @@ TxOutScriptRef BtcUtils::getTxOutScrAddrNoCopy(BinaryDataRef script) case(TXOUT_SCRIPT_STDPUBKEY33) : { outputRef.type_ = p2pkh_prefix; - outputRef.scriptCopy_ = move(getHash160(script.getSliceRef(1, 33))); + outputRef.scriptCopy_ = getHash160(script.getSliceRef(1, 33)); outputRef.scriptRef_.setRef(outputRef.scriptCopy_); break; } @@ -475,14 +506,14 @@ TxOutScriptRef BtcUtils::getTxOutScrAddrNoCopy(BinaryDataRef script) case(TXOUT_SCRIPT_P2SH) : { outputRef.type_ = p2sh_prefix; - outputRef.scriptRef_ = move(script.getSliceRef(2, 20)); + outputRef.scriptRef_ = script.getSliceRef(2, 20); break; } case(TXOUT_SCRIPT_NONSTANDARD) : { outputRef.type_ = SCRIPT_PREFIX_NONSTD; - outputRef.scriptCopy_ = move(getHash160(script)); + outputRef.scriptCopy_ = getHash160(script); outputRef.scriptRef_.setRef(outputRef.scriptCopy_); break; } @@ -490,7 +521,7 @@ TxOutScriptRef BtcUtils::getTxOutScrAddrNoCopy(BinaryDataRef script) case(TXOUT_SCRIPT_MULTISIG) : { outputRef.type_ = SCRIPT_PREFIX_MULTISIG; - outputRef.scriptCopy_ = move(getMultisigUniqueKey(script)); + outputRef.scriptCopy_ = getMultisigUniqueKey(script); outputRef.scriptRef_.setRef(outputRef.scriptCopy_); break; } diff --git a/cppForSwig/BtcUtils.h b/cppForSwig/BtcUtils.h index 3e829abaa..317147d40 100644 --- a/cppForSwig/BtcUtils.h +++ b/cppForSwig/BtcUtils.h @@ -1739,23 +1739,18 @@ class BtcUtils { //sanity checks if (b58.size() == 0) - throw std::range_error("empty BinaryData"); + throw std::range_error("empty b58 string"); size_t size = b58.size(); - uint8_t* result = new uint8_t[size]; + BinaryData result(size); - if (!btc_base58_decode(result, &size, b58.c_str()) || + if (!btc_base58_decode(result.getPtr(), &size, b58.c_str()) || size > b58.size()) { - delete[] result; throw std::runtime_error("failed to decode b58 string"); } - BinaryData result_bd(size); - memcpy(result_bd.getPtr(), result + b58.size() - size, size); - - delete[] result; - return result_bd; + return result.getSliceCopy(b58.size() - size, size); } static BinaryData extractRSFromDERSig(BinaryDataRef bdr) @@ -1857,6 +1852,7 @@ class BtcUtils static std::string computeID(const SecureBinaryData& pubkey); + //HMAC static BinaryData getHMAC256( const SecureBinaryData& key, const SecureBinaryData& message); @@ -1864,7 +1860,6 @@ class BtcUtils const SecureBinaryData& key, const SecureBinaryData& message); - static BinaryData getHMAC256( const BinaryData& key, const std::string& message); @@ -1876,13 +1871,15 @@ class BtcUtils const std::string& key, const SecureBinaryData& message); - - static void getHMAC256(const uint8_t* keyptr, size_t keylen, const char* msg, size_t msglen, uint8_t* digest); static void getHMAC512(const void* keyptr, size_t keylen, const void* msg, size_t msglen, void* digest); + static BinaryData getBotchedArmoryHMAC256( + const BinaryData& key, const BinaryData& msg); + + static SecureBinaryData computeChainCode_Armory135( const SecureBinaryData& privateRoot); diff --git a/cppForSwig/BtcWallet.cpp b/cppForSwig/BtcWallet.cpp index 497a5f68b..5224e2d61 100644 --- a/cppForSwig/BtcWallet.cpp +++ b/cppForSwig/BtcWallet.cpp @@ -11,8 +11,8 @@ // // //////////////////////////////////////////////////////////////////////////////// #include "BtcWallet.h" -#include "BlockUtils.h" -#include "txio.h" +#include "BlockchainDatabase/BlockUtils.h" +#include "BlockchainDatabase/txio.h" #include "BlockDataViewer.h" #include "TxOutScrRef.h" diff --git a/cppForSwig/BtcWallet.h b/cppForSwig/BtcWallet.h index 9a15ec8c6..69da41d2f 100644 --- a/cppForSwig/BtcWallet.h +++ b/cppForSwig/BtcWallet.h @@ -14,9 +14,9 @@ #define _BTCWALLET_H #include "BinaryData.h" -#include "BlockObj.h" +#include "BlockchainDatabase/BlockObj.h" +#include "BlockchainDatabase/StoredBlockObj.h" #include "ScrAddrObj.h" -#include "StoredBlockObj.h" #include "bdmenums.h" #include "ThreadSafeClasses.h" #include "TxClasses.h" diff --git a/cppForSwig/CMakeLists.txt b/cppForSwig/CMakeLists.txt index da66c7204..2e1514275 100644 --- a/cppForSwig/CMakeLists.txt +++ b/cppForSwig/CMakeLists.txt @@ -197,6 +197,7 @@ endif() file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/protobuf) +IF (BUILD_PROTOBUF) foreach(proto ${PROTOBUF_FILES}) string(REGEX REPLACE "\\.proto$" ".pb.cc" proto_cc ${proto}) @@ -208,6 +209,7 @@ foreach(proto ${PROTOBUF_FILES}) list(APPEND LIBARMORYCOMMON_SOURCES ${PROJECT_BINARY_DIR}/protobuf/${proto_cc}) endforeach() +ENDIF (BUILD_PROTOBUF) add_library(ArmoryCommon STATIC diff --git a/cppForSwig/CoinSelection.cpp b/cppForSwig/CoinSelection.cpp index 680a63f7d..d3892eee2 100644 --- a/cppForSwig/CoinSelection.cpp +++ b/cppForSwig/CoinSelection.cpp @@ -1472,7 +1472,7 @@ void CoinSelectionInstance::checkSpendVal(uint64_t spendableBalance) const void CoinSelectionInstance::processCustomUtxoList( vector& utxos, uint64_t fee, float fee_byte, unsigned flags) { - if (utxos.size() == 0) + if (utxos.empty()) throw CoinSelectionException("empty custom utxo list!"); selectUTXOs(utxos, fee, fee_byte, flags); diff --git a/cppForSwig/CoinSelection.h b/cppForSwig/CoinSelection.h index 4c1eb263f..c42cf42c4 100644 --- a/cppForSwig/CoinSelection.h +++ b/cppForSwig/CoinSelection.h @@ -7,7 +7,7 @@ //////////////////////////////////////////////////////////////////////////////// #ifndef _H_COINSELECTION -#define _H_COINSELECTOIN +#define _H_COINSELECTION #include #include @@ -321,8 +321,6 @@ namespace Armory unsigned topHeight, unsigned ruleset); }; - #endif - ////////////////////////////////////////////////////////////////////////// struct CoinSubSelection { @@ -447,3 +445,5 @@ namespace Armory }; }; //namespace CoinSelection }; //namespace Armory + +#endif \ No newline at end of file diff --git a/cppForSwig/DBClientClasses.cpp b/cppForSwig/DBClientClasses.cpp index b14f27690..381d471fd 100644 --- a/cppForSwig/DBClientClasses.cpp +++ b/cppForSwig/DBClientClasses.cpp @@ -13,8 +13,9 @@ using namespace std; using namespace DBClientClasses; +#ifdef BUILD_PROTOBUF using namespace Codec_BDVCommand; - +#endif /////////////////////////////////////////////////////////////////////////////// void initLibrary() @@ -54,28 +55,35 @@ void DBClientClasses::BlockHeader::unserialize(uint8_t const * ptr, uint32_t siz // LedgerEntry // /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF LedgerEntry::LedgerEntry(shared_ptr<::Codec_LedgerEntry::LedgerEntry> msg) : msgPtr_(msg), ptr_(msg.get()) {} +#endif /////////////////////////////////////////////////////////////////////////////// LedgerEntry::LedgerEntry(BinaryDataRef bdr) { +#ifdef BUILD_PROTOBUF auto msg = make_shared<::Codec_LedgerEntry::LedgerEntry>(); msg->ParseFromArray(bdr.getPtr(), (int)bdr.getSize()); ptr_ = msg.get(); msgPtr_ = msg; +#endif } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF LedgerEntry::LedgerEntry( shared_ptr<::Codec_LedgerEntry::ManyLedgerEntry> msg, unsigned index) : msgPtr_(msg) { ptr_ = &msg->values(index); } +#endif /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF LedgerEntry::LedgerEntry( shared_ptr<::Codec_BDVCommand::BDVCallback> msg, unsigned i, unsigned y) : msgPtr_(msg) @@ -84,107 +92,153 @@ LedgerEntry::LedgerEntry( auto& ledgers = notif.ledgers(); ptr_ = &ledgers.values(y); } - +#endif /////////////////////////////////////////////////////////////////////////////// string LedgerEntry::getID() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); if (ptr_->has_id()) return ptr_->id(); +#endif return string(); } /////////////////////////////////////////////////////////////////////////////// int64_t LedgerEntry::getValue() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->balance(); +#else + return 0; +#endif } /////////////////////////////////////////////////////////////////////////////// uint32_t LedgerEntry::getBlockNum() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->txheight(); +#else + return 0; +#endif } /////////////////////////////////////////////////////////////////////////////// BinaryDataRef LedgerEntry::getTxHash() const { +#if 0 if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); auto& val = ptr_->txhash(); BinaryDataRef bdr; bdr.setRef(val); return bdr; +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// uint32_t LedgerEntry::getIndex() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->index(); +#else + return 0; +#endif } /////////////////////////////////////////////////////////////////////////////// uint32_t LedgerEntry::getTxTime() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->txtime(); +#else + return 0; +#endif } /////////////////////////////////////////////////////////////////////////////// bool LedgerEntry::isCoinbase() const { +#if 0 if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->iscoinbase(); +#else + return false; +#endif } /////////////////////////////////////////////////////////////////////////////// bool LedgerEntry::isSentToSelf() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->issts(); +#else + return false; +#endif } /////////////////////////////////////////////////////////////////////////////// bool LedgerEntry::isChangeBack() const { +#if 0 if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->ischangeback(); +#else + return false; +#endif } /////////////////////////////////////////////////////////////////////////////// bool LedgerEntry::isOptInRBF() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->optinrbf(); +#else + return false; +#endif } /////////////////////////////////////////////////////////////////////////////// bool LedgerEntry::isChainedZC() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->ischainedzc(); +#else + return false; +#endif } /////////////////////////////////////////////////////////////////////////////// bool LedgerEntry::isWitness() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); return ptr_->iswitness(); +#else + return false; +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -202,6 +256,7 @@ bool LedgerEntry::operator==(const LedgerEntry& rhs) /////////////////////////////////////////////////////////////////////////////// vector LedgerEntry::getScrAddrList() const { +#ifdef BUILD_PROTOBUF if (ptr_ == nullptr) throw runtime_error("uninitialized ledger entry"); @@ -215,6 +270,9 @@ vector LedgerEntry::getScrAddrList() const } return addrList; +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -226,6 +284,7 @@ RemoteCallback::~RemoteCallback(void) {} /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF bool RemoteCallback::processNotifications( shared_ptr callback) { @@ -398,6 +457,7 @@ bool RemoteCallback::processNotifications( return true; } +#endif /////////////////////////////////////////////////////////////////////////////// // @@ -406,14 +466,17 @@ bool RemoteCallback::processNotifications( /////////////////////////////////////////////////////////////////////////////// NodeStatus::NodeStatus(BinaryDataRef bdr) { +#ifdef BUILD_PROTOBUF auto msg = make_shared(); if (!msg->ParseFromArray(bdr.getPtr(), (int)bdr.getSize())) throw runtime_error("invalid node status protobuf msg"); ptr_ = msg.get(); msgPtr_ = move(msg); +#endif } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF NodeStatus::NodeStatus( shared_ptr msg) { @@ -429,36 +492,50 @@ NodeStatus::NodeStatus( auto& notif = msg->notification(i); ptr_ = ¬if.nodestatus(); } +#endif /////////////////////////////////////////////////////////////////////////////// CoreRPC::NodeState NodeStatus::state() const { +#ifdef BUILD_PROTOBUF return (CoreRPC::NodeState)ptr_->state(); +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// bool NodeStatus::isSegWitEnabled() const { +#ifdef BUILD_PROTOBUF if (ptr_->has_segwitenabled()) return ptr_->segwitenabled(); +#endif return false; } /////////////////////////////////////////////////////////////////////////////// CoreRPC::RpcState NodeStatus::rpcState() const { +#ifdef BUILD_PROTOBUF if (ptr_->has_rpcstate()) return (CoreRPC::RpcState)ptr_->rpcstate(); +#endif return CoreRPC::RpcState::RpcState_Disabled; } /////////////////////////////////////////////////////////////////////////////// NodeChainStatus NodeStatus::chainStatus() const { +#ifdef BUILD_PROTOBUF return NodeChainStatus(ptr_); +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF shared_ptr NodeStatus::make_new( shared_ptr msg, unsigned i) { @@ -475,35 +552,56 @@ NodeChainStatus::NodeChainStatus( const Codec_NodeStatus::NodeStatus* ptr) : ptr_(&ptr->chainstatus()) {} +#endif /////////////////////////////////////////////////////////////////////////////// CoreRPC::ChainState NodeChainStatus::state() const { +#ifdef BUILD_PROTOBUF return (CoreRPC::ChainState)ptr_->state(); +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// float NodeChainStatus::getBlockSpeed() const { +#ifdef BUILD_PROTOBUF return ptr_->blockspeed(); +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// float NodeChainStatus::getProgressPct() const { +#ifdef BUILD_PROTOBUF return ptr_->pct(); +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// uint64_t NodeChainStatus::getETA() const { +#ifdef BUILD_PROTOBUF return ptr_->eta(); +#else + return 0; +#endif } /////////////////////////////////////////////////////////////////////////////// unsigned NodeChainStatus::getBlocksLeft() const { +#ifdef BUILD_PROTOBUF return ptr_->blocksleft(); +#else + return 0; +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -513,12 +611,15 @@ unsigned NodeChainStatus::getBlocksLeft() const /////////////////////////////////////////////////////////////////////////////// ProgressData::ProgressData(BinaryDataRef) { +#ifdef BUILD_PROTOBUF auto msg = make_shared<::Codec_NodeStatus::ProgressData>(); ptr_ = msg.get(); msgPtr_ = msg; +#endif } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF ProgressData::ProgressData( shared_ptr<::Codec_BDVCommand::BDVCallback> msg, unsigned i) : msgPtr_(msg) @@ -526,46 +627,65 @@ ProgressData::ProgressData( auto& notif = msg->notification(i); ptr_ = ¬if.progress(); } +#endif /////////////////////////////////////////////////////////////////////////////// BDMPhase ProgressData::phase() const { +#ifdef BUILD_PROTOBUF return (BDMPhase)ptr_->phase(); +#else + return {}; +#endif } /////////////////////////////////////////////////////////////////////////////// double ProgressData::progress() const { +#ifdef BUILD_PROTOBUF return ptr_->progress(); +#else + return 0; +#endif } /////////////////////////////////////////////////////////////////////////////// unsigned ProgressData::time() const { +#ifdef BUILD_PROTOBUF return ptr_->time(); +#else + return 0; +#endif } /////////////////////////////////////////////////////////////////////////////// unsigned ProgressData::numericProgress() const { +#ifdef BUILD_PROTOBUF return ptr_->numericprogress(); +#else + return 0; +#endif } /////////////////////////////////////////////////////////////////////////////// vector ProgressData::wltIDs() const { vector vec; +#ifdef BUILD_PROTOBUF for (int i = 0; i < ptr_->id_size(); i++) vec.push_back(ptr_->id(i)); - +#endif return vec; } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF std::shared_ptr ProgressData::make_new( std::shared_ptr<::Codec_BDVCommand::BDVCallback> msg, unsigned i) { auto pd = make_shared(ProgressData(msg, i)); return pd; } - +#endif diff --git a/cppForSwig/DBClientClasses.h b/cppForSwig/DBClientClasses.h index 0f768eae5..8eceea992 100644 --- a/cppForSwig/DBClientClasses.h +++ b/cppForSwig/DBClientClasses.h @@ -122,18 +122,20 @@ namespace DBClientClasses //////////////////////////////////////////////////////////////////////////// class LedgerEntry { +#ifdef BUILD_PROTOBUF private: std::shared_ptr<::google::protobuf::Message> msgPtr_; const ::Codec_LedgerEntry::LedgerEntry* ptr_ = nullptr; - +#endif public: LedgerEntry(BinaryDataRef bdr); +#ifdef BUILD_PROTOBUF LedgerEntry(std::shared_ptr<::Codec_LedgerEntry::LedgerEntry>); LedgerEntry(std::shared_ptr<::Codec_LedgerEntry::ManyLedgerEntry>, unsigned); LedgerEntry(std::shared_ptr<::Codec_BDVCommand::BDVCallback>, unsigned, unsigned); - +#endif std::string getID(void) const; int64_t getValue(void) const; uint32_t getBlockNum(void) const; @@ -155,13 +157,15 @@ namespace DBClientClasses //////////////////////////////////////////////////////////////////////////// class NodeChainStatus { +#ifdef BUILD_PROTOBUF private: std::shared_ptr<::google::protobuf::Message> msgPtr_; const Codec_NodeStatus::NodeChainStatus* ptr_; - +#endif public: +#ifdef BUILD_PROTOBUF NodeChainStatus(const Codec_NodeStatus::NodeStatus*); - +#endif CoreRPC::ChainState state(void) const; float getBlockSpeed(void) const; @@ -173,36 +177,39 @@ namespace DBClientClasses //////////////////////////////////////////////////////////////////////////// class NodeStatus { +#ifdef BUILD_PROTOBUF private: std::shared_ptr<::google::protobuf::Message> msgPtr_; const Codec_NodeStatus::NodeStatus* ptr_; - private: NodeStatus(std::shared_ptr, unsigned); - +#endif public: NodeStatus(BinaryDataRef); +#ifdef BUILD_PROTOBUF NodeStatus(std::shared_ptr); - +#endif CoreRPC::NodeState state(void) const; bool isSegWitEnabled(void) const; CoreRPC::RpcState rpcState(void) const; NodeChainStatus chainStatus(void) const; - +#ifdef BUILD_PROTOBUF static std::shared_ptr make_new( std::shared_ptr, unsigned); +#endif }; //////////////////////////////////////////////////////////////////////////// class ProgressData { +#ifdef BUILD_PROTOBUF private: std::shared_ptr<::google::protobuf::Message> msgPtr_; const ::Codec_NodeStatus::ProgressData* ptr_; private: ProgressData(std::shared_ptr<::Codec_BDVCommand::BDVCallback>, unsigned); - +#endif public: ProgressData(BinaryDataRef); @@ -211,9 +218,10 @@ namespace DBClientClasses unsigned time(void) const; unsigned numericProgress(void) const; std::vector wltIDs(void) const; - +#ifdef BUILD_PROTOBUF static std::shared_ptr make_new( std::shared_ptr<::Codec_BDVCommand::BDVCallback>, unsigned); +#endif }; }; //namespace DBClientClasses @@ -255,8 +263,9 @@ class RemoteCallback unsigned progressNumeric ) = 0; virtual void disconnected(void) = 0; - +#ifdef BUILD_PROTOBUF bool processNotifications(std::shared_ptr<::Codec_BDVCommand::BDVCallback>); +#endif }; #endif diff --git a/cppForSwig/HistoryPager.h b/cppForSwig/HistoryPager.h index afaa447bf..75f8bdda2 100644 --- a/cppForSwig/HistoryPager.h +++ b/cppForSwig/HistoryPager.h @@ -15,7 +15,7 @@ #include "ThreadSafeClasses.h" #include "BinaryData.h" #include "LedgerEntry.h" -#include "BlockObj.h" +#include "BlockchainDatabase/BlockObj.h" class AlreadyPagedException {}; diff --git a/cppForSwig/LedgerEntry.cpp b/cppForSwig/LedgerEntry.cpp index 22ed3f483..03b550297 100644 --- a/cppForSwig/LedgerEntry.cpp +++ b/cppForSwig/LedgerEntry.cpp @@ -348,6 +348,7 @@ map LedgerEntry::computeLedgerMap( } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void LedgerEntry::fillMessage(::Codec_LedgerEntry::LedgerEntry* msg) const { if (msg == nullptr) @@ -376,3 +377,4 @@ void LedgerEntry::fillMessage(::Codec_LedgerEntry::LedgerEntry* msg) const for (auto& scrAddr : scrAddrSet_) msg->add_scraddr(scrAddr.getPtr(), scrAddr.getSize()); } +#endif diff --git a/cppForSwig/LedgerEntry.h b/cppForSwig/LedgerEntry.h index c6826592d..3da075959 100644 --- a/cppForSwig/LedgerEntry.h +++ b/cppForSwig/LedgerEntry.h @@ -15,9 +15,9 @@ #include "BinaryData.h" #include "BtcUtils.h" -#include "BlockObj.h" -#include "Blockchain.h" -#include "StoredBlockObj.h" +#include "BlockchainDatabase/BlockObj.h" +#include "BlockchainDatabase/Blockchain.h" +#include "BlockchainDatabase/StoredBlockObj.h" #include "BDVCodec.h" #include "ZeroConf.h" @@ -144,8 +144,9 @@ class LedgerEntry const std::set& getScrAddrList(void) const { return scrAddrSet_; } - +#ifdef BUILD_PROTOBUF void fillMessage(::Codec_LedgerEntry::LedgerEntry* msg) const; +#endif public: diff --git a/cppForSwig/Makefile.am b/cppForSwig/Makefile.am index a0f99d474..8f5b4683d 100644 --- a/cppForSwig/Makefile.am +++ b/cppForSwig/Makefile.am @@ -8,17 +8,19 @@ BUILT_SOURCES = LIBBTC = $(LIBBTC_LIBDIR)/libbtc.la LIBCHACHA20POLY1305 = chacha20poly1305/libchacha20poly1305.la +LIBHKDF = hkdf/libhkdf.la +LIBTREZORCRYPTO = libTrezorCrypto.la LIBARMORYWALLETS = libArmoryWallets.la LIBARMORYSIGNER = libArmorySigner.la +LIBBLOCKCHAINDB = libBlockchainDb.la LIBARMORYCOMMON = libArmoryCommon.la LIBARMORYGUI = libArmoryGUI.la LIBARMORYCLI = libArmoryCLI.la LIBLMDBPP = liblmdbpp.la -LIBHKDF = hkdf/libhkdf.la LIBSECP256K1 = $(LIBBTC_LIBDIR)/src/secp256k1/libsecp256k1.la LIBWEBSOCKETS_STATIC = $(WEBSOCKETS_LIBDIR)/libwebsockets.a -LIBPROTOBUF_STATIC = $(PROTOBUF_LIBDIR)/libprotobuf.so +LIBPROTOBUF_STATIC = -lprotobuf if BUILD_OPENSSL_SUPPORT LIBCRYPTO_STATIC = $(CRYPTO_LIBDIR)/libcrypto.a LIBSSL_STATIC = $(SSL_LIBDIR)/libssl.a @@ -56,12 +58,11 @@ AM_CXXFLAGS = #LDFLAGS += -Wl,-rpath,. -Wl,-rpath,'$$ORIGIN/../more/libs/here' -Wl,-z,origin protobuf/%.pb.cc protobuf/%.pb.h: protobuf/%.proto -# @test -f proto - protoc --cpp_out=protobuf --proto_path=protobuf $< + protoc --cpp_out=protobuf --proto_path=$(srcdir)/protobuf $< -INCLUDE_FILES = -Ibech32/ref/c++ -Ilmdbpp \ - -Ichacha20poly1305 -I$(LIBBTC_LIBDIR)/src/secp256k1/include \ - -I$(LIBBTC_LIBDIR)/include $(LWS_CFLAGS) -Ihkdf -IWallets -ISigner +INCLUDE_FILES = -I$(srcdir)/lmdbpp \ + -I$(srcdir)/chacha20poly1305 -I$(LIBBTC_LIBDIR)/src/secp256k1/include -I$(LIBBTC_LIBDIR)/src \ + -I$(LIBBTC_LIBDIR)/include $(LWS_CFLAGS) -I$(srcdir)/hkdf -I$(srcdir)/Wallets -I$(srcdir)/Signer # Files should *not* be marked as "common" if at all possible. Also, a refactor # might not hurt one of these days. Some of the "common" files could be GUI/CLI @@ -77,6 +78,13 @@ CPPBRIDGE_SOURCE_FILES = BridgeAPI/CppBridge.cpp \ BridgeAPI/ProtobufCommandParser.cpp \ BridgeAPI/PassphrasePrompt.cpp +LIBTREZORCRYPTO_SOURCE_FILES = $(LIBBTC_LIBDIR)/src/trezor-crypto/bip39.c \ + $(LIBBTC_LIBDIR)/src/trezor-crypto/pbkdf2.c \ + $(LIBBTC_LIBDIR)/src/trezor-crypto/memzero.c \ + $(LIBBTC_LIBDIR)/src/trezor-crypto/hmac.c \ + $(LIBBTC_LIBDIR)/src/trezor-crypto/sha2.c \ + $(LIBBTC_LIBDIR)/src/trezor-crypto/rand.c + ARMORYWALLETS_SOURCE_FILES = Wallets/BIP32_Node.cpp \ Wallets/Addresses.cpp \ Wallets/DecryptedDataContainer.cpp \ @@ -92,16 +100,33 @@ ARMORYWALLETS_SOURCE_FILES = Wallets/BIP32_Node.cpp \ Wallets/WalletFileInterface.cpp \ Wallets/AssetEncryption.cpp \ Wallets/Wallets.cpp \ - Wallets/AuthorizedPeers.cpp + Wallets/AuthorizedPeers.cpp \ + Wallets/Seeds/Backups.cpp \ + Wallets/Seeds/Seeds.cpp ARMORYSIGNER_SOURCE_FILES = Signer/Script.cpp \ Signer/ScriptRecipient.cpp \ Signer/Signer.cpp \ + Signer/LegacySigner.cpp \ Signer/ResolverFeed.cpp \ Signer/ResolverFeed_Wallets.cpp \ Signer/Transactions.cpp \ Signer/TxEvalState.cpp +BLOCKCHAINDB_SOURCE_FILES = BlockchainDatabase/Blockchain.cpp \ + BlockchainDatabase/BlockchainScanner.cpp \ + BlockchainDatabase/BlockchainScanner_Super.cpp \ + BlockchainDatabase/BlockDataMap.cpp \ + BlockchainDatabase/BlockObj.cpp \ + BlockchainDatabase/BlockUtils.cpp \ + BlockchainDatabase/DatabaseBuilder.cpp \ + BlockchainDatabase/lmdb_wrapper.cpp \ + BlockchainDatabase/ScrAddrFilter.cpp \ + BlockchainDatabase/SshParser.cpp \ + BlockchainDatabase/StoredBlockObj.cpp \ + BlockchainDatabase/TxHashFilters.cpp \ + BlockchainDatabase/txio.cpp + ARMORYDB_SOURCE_FILES = main.cpp ARMORYGUI_SOURCE_FILES = TransactionBatch.cpp ARMORYCLI_SOURCE_FILES = BDM_mainthread.cpp \ @@ -109,30 +134,20 @@ ARMORYCLI_SOURCE_FILES = BDM_mainthread.cpp \ BIP150_151.cpp \ BIP15x_Handshake.cpp \ BitcoinP2P.cpp \ - Blockchain.cpp \ - BlockchainScanner.cpp \ - BlockchainScanner_Super.cpp \ - BlockDataMap.cpp \ BlockDataViewer.cpp \ - BlockObj.cpp \ - BlockUtils.cpp \ BtcWallet.cpp \ DatabaseBuilder.cpp \ + DBUtils.cpp \ HistoryPager.cpp \ HttpMessage.cpp \ JSON_codec.cpp \ LedgerEntry.cpp \ - TxHashFilters.cpp \ - lmdb_wrapper.cpp \ nodeRPC.cpp \ Progress.cpp \ - ScrAddrFilter.cpp \ ScrAddrObj.cpp \ Server.cpp \ SocketService_unix.cpp \ - SshParser.cpp \ StringSockets.cpp \ - txio.cpp \ ZeroConfUtils.cpp \ ZeroConf.cpp \ ZeroConfNotifications.cpp \ @@ -151,11 +166,8 @@ ARMORYCOMMON_SOURCE_FILES = AsyncClient.cpp \ BitcoinSettings.cpp \ ReentrantLock.cpp \ SecureBinaryData.cpp \ - ArmoryBackups.cpp \ SocketObject.cpp \ - StoredBlockObj.cpp \ TxClasses.cpp \ - txio.cpp \ TxOutScrRef.cpp \ UniversalTimer.cpp \ WebSocketClient.cpp \ @@ -164,7 +176,7 @@ ARMORYCOMMON_SOURCE_FILES = AsyncClient.cpp \ PROTOBUF_PROTO = protobuf/AddressBook.proto \ protobuf/AddressData.proto \ protobuf/BDVCommand.proto \ - protobuf/ClientProto.proto \ + protobuf/BridgeProto.proto \ protobuf/CommonTypes.proto \ protobuf/FeeEstimate.proto \ protobuf/LedgerEntry.proto \ @@ -175,7 +187,7 @@ PROTOBUF_PROTO = protobuf/AddressBook.proto \ PROTOBUF_CC = protobuf/AddressBook.pb.cc \ protobuf/AddressData.pb.cc \ protobuf/BDVCommand.pb.cc \ - protobuf/ClientProto.pb.cc \ + protobuf/BridgeProto.pb.cc \ protobuf/CommonTypes.pb.cc \ protobuf/FeeEstimate.pb.cc \ protobuf/LedgerEntry.pb.cc \ @@ -186,7 +198,7 @@ PROTOBUF_CC = protobuf/AddressBook.pb.cc \ PROTOBUF_H = protobuf/AddressBook.pb.h \ protobuf/AddressData.pb.h \ protobuf/BDVCommand.pb.h \ - protobuf/ClientProto.pb.h \ + protobuf/BridgeProto.pb.h \ protobuf/CommonTypes.pb.h \ protobuf/FeeEstimate.pb.h \ protobuf/LedgerEntry.pb.h \ @@ -206,6 +218,13 @@ liblmdbpp_la_CPPFLAGS = -Ilmdbpp -fPIC liblmdbpp_la_LIBADD = -llmdb liblmdbpp_la_LDFLAGS = -static +# libTrezorCrypto +noinst_LTLIBRARIES += $(LIBTREZORCRYPTO) +libTrezorCrypto_la_SOURCES = $(LIBTREZORCRYPTO_SOURCE_FILES) +libTrezorCrypto_la_CPPFLAGS = $(AM_CPPFLAGS) +libTrezorCrypto_la_CXXFLAGS = $(AM_CXXFLAGS) -fPIC +libTrezorCrypto_la_LDFLAGS = $(LDFLAGS) -static + # libArmoryWallets noinst_LTLIBRARIES += $(LIBARMORYWALLETS) libArmoryWallets_la_SOURCES = $(ARMORYWALLETS_SOURCE_FILES) @@ -213,7 +232,8 @@ libArmoryWallets_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) libArmoryWallets_la_CXXFLAGS = $(AM_CXXFLAGS) $(LIBBTC_FLAGS) \ $(UNIT_TEST_CXXFLAGS) -D__STDC_LIMIT_MACROS libArmoryWallets_la_LIBADD = $(LIBBTC) \ - $(LIBSECP256K1) + $(LIBSECP256K1) \ + $(LIBTREZORCRYPTO) libArmoryWallets_la_LDFLAGS = $(LDFLAGS) # libArmorySigner @@ -223,10 +243,22 @@ libArmorySigner_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) libArmorySigner_la_CXXFLAGS = $(AM_CXXFLAGS) $(LIBBTC_FLAGS) \ $(UNIT_TEST_CXXFLAGS) -D__STDC_LIMIT_MACROS libArmorySigner_la_LIBADD = $(LIBBTC) \ - $(LIBSECP256K1) + $(LIBSECP256K1) \ + $(LIBTREZORCRYPTO) libArmorySigner_la_LDFLAGS = $(LDFLAGS) +# libBlockchainDb +noinst_LTLIBRARIES += $(LIBBLOCKCHAINDB) +libBlockchainDb_la_SOURCES = $(BLOCKCHAINDB_SOURCE_FILES) +libBlockchainDb_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) +libBlockchainDb_la_CXXFLAGS = $(AM_CXXFLAGS) $(LIBBTC_FLAGS) \ + $(UNIT_TEST_CXXFLAGS) -D__STDC_LIMIT_MACROS +libBlockchainDb_la_LIBADD = $(LIBBTC) \ + -llmdb \ + -lpthread +libBlockchainDb_la_LDFLAGS = $(LDFLAGS) + # libArmoryCommon - Required by all Armory programs/libraries. # Common functionality across GUI and command line noinst_LTLIBRARIES += $(LIBARMORYCOMMON) @@ -238,8 +270,10 @@ libArmoryCommon_la_CXXFLAGS = $(AM_CXXFLAGS) $(LIBBTC_FLAGS) \ libArmoryCommon_la_LIBADD = $(LIBHKDF) \ $(LIBBTC) \ $(LIBSECP256K1) \ + $(LIBTREZORCRYPTO) \ $(LIBARMORYWALLETS) \ $(LIBARMORYSIGNER) \ + $(LIBBLOCKCHAINDB) \ -lpthread libArmoryCommon_la_LDFLAGS = $(LDFLAGS) $(LWSLDFLAGS) $(PROTOBUF_FLAGS) @@ -253,11 +287,13 @@ libArmoryCLI_la_CXXFLAGS = $(AM_CXXFLAGS) $(LIBBTC_FLAGS) \ libArmoryCLI_la_LIBADD = $(LIBCHACHA20POLY1305) \ $(LIBARMORYWALLETS) \ $(LIBARMORYSIGNER) \ + $(LIBBLOCKCHAINDB) \ $(LIBARMORYCOMMON) \ $(LIBLMDBPP) \ $(LIBHKDF) \ $(LIBBTC) \ $(LIBSECP256K1) \ + $(LIBTREZORCRYPTO) \ -llmdb \ -lpthread libArmoryCLI_la_LDFLAGS = $(LDFLAGS) $(LWSLDFLAGS) @@ -270,11 +306,13 @@ ArmoryDB_CXXFLAGS = $(AM_CXXFLAGS) $(LIBBTC_FLAGS) $(UNIT_TEST_CXXFLAGS) \ ArmoryDB_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) ArmoryDB_LDADD = $(LIBARMORYWALLETS) \ $(LIBARMORYSIGNER) \ + $(LIBBLOCKCHAINDB) \ $(LIBARMORYCOMMON) \ $(LIBARMORYCLI) \ $(LIBHKDF) \ $(LIBBTC) \ $(LIBSECP256K1) \ + $(LIBTREZORCRYPTO) \ $(LIBCHACHA20POLY1305) \ $(LIBLMDBPP) \ -llmdb \ @@ -310,6 +348,7 @@ BIP150KeyManager_LDADD = $(LIBARMORYCOMMON) \ $(LIBHKDF) \ $(LIBBTC) \ $(LIBCHACHA20POLY1305) \ + $(LIBTREZORCRYPTO) \ $(LIBLMDBPP) \ -llmdb \ $(LIBPROTOBUF_STATIC) \ @@ -321,12 +360,13 @@ bin_PROGRAMS += CppBridge CppBridge_SOURCES = $(CPPBRIDGE_SOURCE_FILES) CppBridge_CXXFLAGS = $(AM_CXXFLAGS) $(LIBBTC_FLAGS) $(UNIT_TEST_CXXFLAGS) \ -D__STDC_LIMIT_MACROS -CppBridge_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) +CppBridge_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) -Iprotobuf CppBridge_LDADD = $(LIBARMORYCOMMON) \ $(LIBARMORYCLI) \ $(LIBHKDF) \ $(LIBBTC) \ $(LIBCHACHA20POLY1305) \ + $(LIBTREZORCRYPTO) \ $(LIBLMDBPP) \ -llmdb \ $(LIBPROTOBUF_STATIC) \ diff --git a/cppForSwig/Makefile.tests.include b/cppForSwig/Makefile.tests.include index b94cc05d6..c14c8d5fd 100644 --- a/cppForSwig/Makefile.tests.include +++ b/cppForSwig/Makefile.tests.include @@ -46,6 +46,7 @@ gtest_UtilsTests_LDADD = gtest/libgtest.la \ $(LIBARMORYCLI) \ $(LIBHKDF) \ $(LIBBTC) \ + $(LIBTREZORCRYPTO) \ $(LIBLMDBPP) \ -llmdb \ $(LIBPROTOBUF_STATIC) \ @@ -116,6 +117,7 @@ gtest_SupernodeTests_LDADD = gtest/libgtest.la \ -llmdb \ $(LIBHKDF) \ $(LIBBTC) \ + $(LIBTREZORCRYPTO) \ $(LIBCHACHA20POLY1305) \ $(LIBPROTOBUF_STATIC) \ $(LIBWEBSOCKETS_STATIC) @@ -147,6 +149,7 @@ gtest_CppBlockUtilsTests_LDADD = gtest/libgtest.la \ $(LIBHKDF) \ $(LIBBTC) \ $(LIBLMDBPP) \ + $(LIBTREZORCRYPTO) \ -llmdb \ $(LIBPROTOBUF_STATIC) \ $(LIBWEBSOCKETS_STATIC) @@ -178,6 +181,7 @@ gtest_ZeroConfTests_LDADD = gtest/libgtest.la \ -llmdb \ $(LIBHKDF) \ $(LIBBTC) \ + $(LIBTREZORCRYPTO) \ $(LIBCHACHA20POLY1305) \ $(LIBPROTOBUF_STATIC) \ $(LIBWEBSOCKETS_STATIC) @@ -209,6 +213,7 @@ gtest_WalletTests_LDADD = gtest/libgtest.la \ $(LIBHKDF) \ $(LIBBTC) \ $(LIBLMDBPP) \ + $(LIBTREZORCRYPTO) \ -llmdb \ $(LIBPROTOBUF_STATIC) \ $(LIBWEBSOCKETS_STATIC) @@ -240,6 +245,7 @@ gtest_SignerTests_LDADD = gtest/libgtest.la \ $(LIBBTC) \ $(LIBCHACHA20POLY1305) \ $(LIBLMDBPP) \ + $(LIBTREZORCRYPTO) \ -llmdb \ $(LIBPROTOBUF_STATIC) \ $(LIBWEBSOCKETS_STATIC) diff --git a/cppForSwig/ScrAddrObj.h b/cppForSwig/ScrAddrObj.h index e60172325..b2da1b721 100644 --- a/cppForSwig/ScrAddrObj.h +++ b/cppForSwig/ScrAddrObj.h @@ -14,10 +14,10 @@ #define SCRADDROBJ_H #include "BinaryData.h" -#include "lmdb_wrapper.h" -#include "Blockchain.h" -#include "BlockObj.h" -#include "txio.h" +#include "BlockchainDatabase/lmdb_wrapper.h" +#include "BlockchainDatabase/Blockchain.h" +#include "BlockchainDatabase/txio.h" +#include "BlockchainDatabase/BlockObj.h" #include "ZeroConf.h" #include "LedgerEntry.h" #include "HistoryPager.h" diff --git a/cppForSwig/SecureBinaryData.h b/cppForSwig/SecureBinaryData.h index a47d949c8..e793d0018 100644 --- a/cppForSwig/SecureBinaryData.h +++ b/cppForSwig/SecureBinaryData.h @@ -144,8 +144,21 @@ class SecureBinaryData : public BinaryData static SecureBinaryData fromString(const std::string& str) { + if (str.empty()) + return {}; + SecureBinaryData sbd(str.size()); - memcpy(sbd.getPtr(), str.c_str(), str.size()); + memcpy(sbd.getPtr(), str.data(), str.size()); + return sbd; + } + + static SecureBinaryData fromStringView(const std::string_view& strv) + { + if (strv.empty()) + return {}; + + SecureBinaryData sbd(strv.size()); + memcpy(sbd.getPtr(), strv.data(), strv.size()); return sbd; } }; diff --git a/cppForSwig/Server.cpp b/cppForSwig/Server.cpp index 1c6bc2d96..063d309ac 100644 --- a/cppForSwig/Server.cpp +++ b/cppForSwig/Server.cpp @@ -516,7 +516,11 @@ void WebSocketServer::write(const uint64_t& id, const uint32_t& msgid, if (message == nullptr) return; +#ifdef BUILD_PROTOBUF auto msg = make_unique(id, msgid, message); +#else + auto msg = make_unique(PendingMessage{ id, msgid }); +#endif auto instance = getInstance(); instance->msgQueue_.push_back(move(msg)); } @@ -563,7 +567,7 @@ void WebSocketServer::prepareWriteThread() { bool needs_rekey = false; auto rightnow = chrono::system_clock::now(); - +#ifdef BUILD_PROTOBUF if (statePtr->bip151Connection_->rekeyNeeded(msg->message_->ByteSizeLong())) { needs_rekey = true; @@ -575,7 +579,7 @@ void WebSocketServer::prepareWriteThread() if (time_sec.count() >= AEAD_REKEY_INVERVAL_SECONDS) needs_rekey = true; } - +#endif if (needs_rekey) { //create rekey packet @@ -601,6 +605,7 @@ void WebSocketServer::prepareWriteThread() //serialize arg vector serializedData; +#ifdef BUILD_PROTOBUF if (msg->message_->ByteSizeLong() > 0) { serializedData.resize(msg->message_->ByteSizeLong()); @@ -612,7 +617,7 @@ void WebSocketServer::prepareWriteThread() return; } } - +#endif SerializedMessage ws_msg; ws_msg.construct( serializedData, statePtr->bip151Connection_.get(), @@ -896,7 +901,7 @@ void ClientConnection::processReadQueue(shared_ptr clients) //invalid msg, kill connection continue; } - +#ifdef BUILD_PROTOBUF //process command auto message = make_shared<::Codec_BDVCommand::StaticCommand>(); if (!message->ParseFromArray(messageRef.getPtr(), (int)messageRef.getSize())) @@ -910,6 +915,7 @@ void ClientConnection::processReadQueue(shared_ptr clients) //reply WebSocketServer::write(id_, msgObj.getId(), reply); +#endif } } } diff --git a/cppForSwig/Server.h b/cppForSwig/Server.h index b4317da22..a85f3ee0d 100644 --- a/cppForSwig/Server.h +++ b/cppForSwig/Server.h @@ -27,8 +27,9 @@ #include "AuthorizedPeers.h" #include "BIP150_151.h" +#ifdef BUILD_PROTOBUF #include - +#endif #define SERVER_AUTH_PEER_FILENAME "server.peers" class Clients; @@ -73,12 +74,14 @@ struct PendingMessage { const uint64_t id_; const uint32_t msgid_; +#ifdef BUILD_PROTOBUF std::shared_ptr <::google::protobuf::Message> message_; PendingMessage(uint64_t id, uint32_t msgid, std::shared_ptr<::google::protobuf::Message> msg) : id_(id), msgid_(msgid), message_(msg) {} +#endif }; /////////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/Signer/LegacySigner.cpp b/cppForSwig/Signer/LegacySigner.cpp new file mode 100644 index 000000000..60dafb305 --- /dev/null +++ b/cppForSwig/Signer/LegacySigner.cpp @@ -0,0 +1,357 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright (C) 2022, goatpig // +// Distributed under the MIT license // +// See LICENSE-MIT or https://opensource.org/licenses/MIT // +// // +//////////////////////////////////////////////////////////////////////////////// + +#include "LegacySigner.h" + +using namespace std; +using namespace Armory::LegacySigner; + +#define LEGACY_SIGNERTYPE_DEFAULT 'Default' +#define LEGACY_SIGNERTYPE_LEGACY 'Legacy' +#define LEGACY_SIGNERTYPE_CPP '0.96 C++' +#define LEGACY_SIGNERTYPE_BCH 'Bcash' + +#define SERIALIZED_SCRIPT_PREFIX 0x01 +#define WITNESS_SCRIPT_PREFIX 0x02 +#define LEGACY_STACK_PARTIAL 0x03 +#define WITNESS_STACK_PARTIAL 0x04 +#define PREFIX_UTXO 0x05 +#define PREFIX_OUTPOINT 0x06 +#define USTX_EXT_SIGNERTYPE 0x20 +#define USTX_EXT_SIGNERSTATE 0x30 + +//////////////////////////////////////////////////////////////////////////////// +//// +//// Signer +//// +//////////////////////////////////////////////////////////////////////////////// +Signer Signer::deserExtState(BinaryDataRef data) +{ + Signer signer; + BinaryRefReader brr(data); + + while (brr.getSizeRemaining() != 0) + { + auto extType = brr.get_uint8_t(); + auto extSize = brr.get_var_int(); + auto extRef = brr.get_BinaryDataRef(extSize); + + switch (extType) + { + case USTX_EXT_SIGNERTYPE: + //this isnt useful, it's only here to signify which signer + //code to use, a distinction that is obsolete now + break; + + case USTX_EXT_SIGNERSTATE: + //deser legacy signer state, look for sigs + signer.deser(extRef); + break; + + default: + continue; + } + } + + return signer; +} + +//////////////////////////////////////////////////////////////////////////////// +void Signer::deser(BinaryDataRef data) +{ + /* + We're only here for signatures, we do not care for the tx structure as + the python side of the serialized tx carries that data as well + */ + BinaryRefReader brr(data); + + brr.advance(12); //version + locktime + flags + isSegWit_ = brr.get_uint8_t(); + + auto spenderCount = brr.get_var_int(); + for (unsigned i = 0; i < spenderCount; i++) + { + auto spenderLen = brr.get_var_int(); + auto spenderData = brr.get_BinaryDataRef(spenderLen); + + try + { + auto spenderPtr = ScriptSpender::deserExtState(spenderData); + spenders_.push_back(spenderPtr); + } + catch (const exception &e) + { + LOGWARN << "failed to deser legacy spender"; + LOGWARN << "error: " << e.what(); + } + } + + //ignore recipients +} + +//////////////////////////////////////////////////////////////////////////////// +map Signer::getSigs() const +{ + map result; + for (unsigned i=0; igetSig(); + if (sig.empty()) + continue; + + result.emplace(i, sig); + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +//// +//// ScriptSpender +//// +//////////////////////////////////////////////////////////////////////////////// +shared_ptr ScriptSpender::deserExtState(BinaryDataRef data) +{ + BinaryRefReader brr(data); + + //flags + BitUnpacker bup(brr.get_uint8_t()); + + //sighash type, sequence + brr.advance(5); + + //skip the utxo + auto prefix = brr.get_uint8_t(); + switch (prefix) + { + case PREFIX_UTXO: + { + auto utxoLen = brr.get_var_int(); + brr.advance(utxoLen); + break; + } + + case PREFIX_OUTPOINT: + { + auto outpointLen = brr.get_var_int(); + brr.advance(outpointLen); + brr.advance(8); + break; + } + + default: + throw runtime_error("invalid prefix for utxo/outpoint deser"); + } + + //instantiate spender, set stack state + shared_ptr spender{ new ScriptSpender() }; + spender->legacyStatus_ = (SpenderStatus)bup.getBits(2); + spender->segwitStatus_ = (SpenderStatus)bup.getBits(2); + + //cycle through stack items + while (brr.getSizeRemaining() > 0) + { + auto prefix = brr.get_uint8_t(); + + switch (prefix) + { + case SERIALIZED_SCRIPT_PREFIX: + { + auto len = brr.get_var_int(); + spender->serializedScript_ = move(brr.get_BinaryData(len)); + break; + } + + case WITNESS_SCRIPT_PREFIX: + { + auto len = brr.get_var_int(); + spender->witnessData_ = move(brr.get_BinaryData(len)); + break; + } + + case LEGACY_STACK_PARTIAL: + { + auto count = brr.get_var_int(); + for (unsigned i = 0; i < count; i++) + { + auto len = brr.get_var_int(); + auto stackItem = StackItem::deserialize( + brr.get_BinaryDataRef(len)); + spender->partialStack_.emplace( + stackItem->getId(), stackItem); + } + break; + } + + case WITNESS_STACK_PARTIAL: + { + auto count = brr.get_var_int(); + for (unsigned i = 0; i < count; i++) + { + auto len = brr.get_var_int(); + auto stackItem = StackItem::deserialize( + brr.get_BinaryDataRef(len)); + spender->partialWitnessStack_.emplace( + stackItem->getId(), stackItem); + } + break; + } + + default: + throw LegacyScriptException("invalid spender state"); + } + } + + return spender; +} + +//////////////////////////////////////////////////////////////////////////////// +SecureBinaryData ScriptSpender::getSig() const +{ + if (serializedScript_.empty()) + return {}; + + //expect a straight forward single sig redeem script for now, the sig + //should be the first item of the script + BinaryRefReader brr(serializedScript_.getRef()); + auto sigSize = brr.get_uint8_t(); + return brr.get_SecureBinaryData(sigSize); +} + +//////////////////////////////////////////////////////////////////////////////// +//// +//// StackItem +//// +//////////////////////////////////////////////////////////////////////////////// +StackItem::~StackItem() +{} + +//////////////////////////////////////////////////////////////////////////////// +shared_ptr StackItem::deserialize(const BinaryDataRef& dataRef) +{ + shared_ptr itemPtr; + + BinaryRefReader brr(dataRef); + + auto id = brr.get_uint32_t(); + auto prefix = brr.get_uint8_t(); + + switch (prefix) + { + case STACKITEM_PUSHDATA_PREFIX: + { + auto len = brr.get_var_int(); + auto&& data = brr.get_BinaryData(len); + + itemPtr = make_shared(id, move(data)); + break; + } + + case STACKITEM_SIG_PREFIX: + { + auto len = brr.get_var_int(); + SecureBinaryData data(brr.get_BinaryData(len)); + + itemPtr = make_shared(id, move(data)); + break; + } + + case STACKITEM_MULTISIG_PREFIX: + { + auto m = brr.get_uint16_t(); + auto item_ms = make_shared(id, m); + + auto count = brr.get_var_int(); + for (unsigned i = 0; i < count; i++) + { + auto pos = brr.get_uint16_t(); + auto len = brr.get_var_int(); + SecureBinaryData data(brr.get_BinaryData(len)); + + item_ms->setSig(pos, data); + } + + itemPtr = item_ms; + break; + } + + case STACKITEM_OPCODE_PREFIX: + { + auto opcode = brr.get_uint8_t(); + + itemPtr = make_shared(id, opcode); + break; + } + + case STACKITEM_SERSCRIPT_PREFIX: + { + auto len = brr.get_var_int(); + auto&& data = brr.get_BinaryData(len); + + itemPtr = make_shared(id, move(data)); + break; + } + + default: + throw LegacyScriptException("unexpected stack item prefix"); + } + + return itemPtr; +} + +//////////////////////////////////////////////////////////////////////////////// +bool StackItem_PushData::isSame(const StackItem* obj) const +{ + auto obj_cast = dynamic_cast(obj); + if (obj_cast == nullptr) + return false; + + return data_ == obj_cast->data_; +} + +//////////////////////////////////////////////////////////////////////////////// +bool StackItem_Sig::isSame(const StackItem* obj) const +{ + auto obj_cast = dynamic_cast(obj); + if (obj_cast == nullptr) + return false; + + return data_ == obj_cast->data_; +} + +//////////////////////////////////////////////////////////////////////////////// +bool StackItem_MultiSig::isSame(const StackItem* obj) const +{ + auto obj_cast = dynamic_cast(obj); + if (obj_cast == nullptr) + return false; + + return m_ == obj_cast->m_ && + sigs_ == obj_cast->sigs_; +} + +//////////////////////////////////////////////////////////////////////////////// +bool StackItem_OpCode::isSame(const StackItem* obj) const +{ + auto obj_cast = dynamic_cast(obj); + if (obj_cast == nullptr) + return false; + + return opcode_ == obj_cast->opcode_; +} + +//////////////////////////////////////////////////////////////////////////////// +bool StackItem_SerializedScript::isSame(const StackItem* obj) const +{ + auto obj_cast = dynamic_cast(obj); + if (obj_cast == nullptr) + return false; + + return data_ == obj_cast->data_; +} diff --git a/cppForSwig/Signer/LegacySigner.h b/cppForSwig/Signer/LegacySigner.h new file mode 100644 index 000000000..a1cd633d0 --- /dev/null +++ b/cppForSwig/Signer/LegacySigner.h @@ -0,0 +1,168 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright (C) 2016-2022, goatpig // +// Distributed under the MIT license // +// See LICENSE-MIT or https://opensource.org/licenses/MIT // +// // +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _H_LEGACY_SIGNER +#define _H_LEGACY_SIGNER + +#include "Script.h" + +namespace Armory +{ + namespace LegacySigner + { + ////////////////////////////////////////////////////////////////////////// + class LegacyScriptException : public std::runtime_error + { + public: + LegacyScriptException(const std::string& what) : std::runtime_error(what) + {} + }; + + ////////////////////////////////////////////////////////////////////////// + struct StackItem + { + public: + const Armory::Signer::StackItemType type_; + + protected: + const unsigned id_; + + public: + StackItem(Armory::Signer::StackItemType type, unsigned id) : + type_(type), id_(id) + {} + + virtual ~StackItem(void) = 0; + virtual bool isSame(const StackItem* obj) const = 0; + unsigned getId(void) const { return id_; } + + virtual bool isValid(void) const { return true; } + static std::shared_ptr deserialize(const BinaryDataRef&); + }; + + //// + struct StackItem_PushData : public StackItem + { + const BinaryData data_; + + StackItem_PushData(unsigned id, BinaryData&& data) : + StackItem(Armory::Signer::StackItemType_PushData, id), + data_(std::move(data)) + {} + + bool isSame(const StackItem* obj) const; + }; + + //// + struct StackItem_Sig : public StackItem + { + const SecureBinaryData data_; + + StackItem_Sig(unsigned id, SecureBinaryData&& data) : + StackItem(Armory::Signer::StackItemType_Sig, id), + data_(std::move(data)) + {} + + bool isSame(const StackItem* obj) const; + }; + + //// + struct StackItem_MultiSig : public StackItem + { + std::map sigs_; + const unsigned m_; + + StackItem_MultiSig(unsigned id, unsigned m) : + StackItem(Armory::Signer::StackItemType_MultiSig, id), m_(m) + {} + + void setSig(unsigned id, SecureBinaryData& sig) + { + auto sigpair = std::make_pair(id, std::move(sig)); + sigs_.insert(move(sigpair)); + } + + bool isSame(const StackItem* obj) const; + bool isValid(void) const { return sigs_.size() == m_; } + }; + + //// + struct StackItem_OpCode : public StackItem + { + const uint8_t opcode_; + + StackItem_OpCode(unsigned id, uint8_t opcode) : + StackItem(Armory::Signer::StackItemType_OpCode, id), + opcode_(opcode) + {} + + bool isSame(const StackItem* obj) const; + }; + + //// + struct StackItem_SerializedScript : public StackItem + { + const BinaryData data_; + + StackItem_SerializedScript(unsigned id, BinaryData&& data) : + StackItem(Armory::Signer::StackItemType_SerializedScript, id), + data_(std::move(data)) + {} + + bool isSame(const StackItem* obj) const; + BinaryData serialize(void) const; + }; + + ////////////////////////////////////////////////////////////////////////// + enum class SpenderStatus + { + SpenderStatus_Unkonwn, + SpenderStatus_Partial, + SpenderStatus_Resolved + }; + + ////////////////////////////////////////////////////////////////////////// + class ScriptSpender + { + private: + SpenderStatus legacyStatus_ = SpenderStatus::SpenderStatus_Unkonwn; + SpenderStatus segwitStatus_ = SpenderStatus::SpenderStatus_Unkonwn; + + BinaryData serializedScript_; + BinaryData witnessData_; + + std::map> partialStack_; + std::map> partialWitnessStack_; + + private: + ScriptSpender(void) {} + + public: + static std::shared_ptr deserExtState(BinaryDataRef); + SecureBinaryData getSig(void) const; + }; + + ////////////////////////////////////////////////////////////////////////// + class Signer + { + private: + bool isSegWit_ = false; + std::vector> spenders_; + + private: + Signer(void) {} + void deser(BinaryDataRef); + + public: + static Signer deserExtState(BinaryDataRef); + std::map getSigs(void) const; + }; + }; //namespace LegacySigner +}; //namespace + +#endif //_H_LEGACY_SIGNER \ No newline at end of file diff --git a/cppForSwig/Signer/ResolverFeed.cpp b/cppForSwig/Signer/ResolverFeed.cpp index 0fd4e7e34..d9ad27a01 100644 --- a/cppForSwig/Signer/ResolverFeed.cpp +++ b/cppForSwig/Signer/ResolverFeed.cpp @@ -42,7 +42,9 @@ uint32_t BIP32_PublicDerivedRoot::getThisFingerprint() const if (thisFingerprint_ == UINT32_MAX) { BIP32_Node node; - node.initFromBase58(SecureBinaryData::fromString(xpub_)); + BinaryDataRef xpubRef; + xpubRef.setRef(xpub_); + node.initFromBase58(xpubRef); thisFingerprint_ = node.getThisFingerprint(); } @@ -178,6 +180,7 @@ BIP32_AssetPath BIP32_AssetPath::fromPSBT( } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void BIP32_AssetPath::toProtobuf( Codec_SignerState::PubkeyBIP32Path& protoMsg) const { @@ -198,7 +201,7 @@ BIP32_AssetPath BIP32_AssetPath::fromProtobuf( return BIP32_AssetPath(pubkey, path, protoMsg.fingerprint(), nullptr); } - +#endif //////////////////////////////////////////////////////////////////////////////// //// //// ResolverFeed diff --git a/cppForSwig/Signer/ResolverFeed.h b/cppForSwig/Signer/ResolverFeed.h index edd9be0e7..5fa4450f0 100644 --- a/cppForSwig/Signer/ResolverFeed.h +++ b/cppForSwig/Signer/ResolverFeed.h @@ -16,8 +16,9 @@ #include "../BinaryData.h" #include "../SecureBinaryData.h" #include "../Wallets/BIP32_Node.h" - +#ifdef BUILD_PROTOBUF #include "protobuf/Signer.pb.h" +#endif //// class NoAssetException : public std::runtime_error @@ -102,10 +103,11 @@ namespace Armory static BIP32_AssetPath fromPSBT( const BinaryDataRef&, const BinaryDataRef&); - //// +#ifdef BUILD_PROTOBUF void toProtobuf(Codec_SignerState::PubkeyBIP32Path&) const; static BIP32_AssetPath fromProtobuf( const Codec_SignerState::PubkeyBIP32Path&); +#endif }; ////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/Signer/ResolverFeed_Wallets.cpp b/cppForSwig/Signer/ResolverFeed_Wallets.cpp index 9aff629ac..65a5d51c9 100644 --- a/cppForSwig/Signer/ResolverFeed_Wallets.cpp +++ b/cppForSwig/Signer/ResolverFeed_Wallets.cpp @@ -176,7 +176,7 @@ const SecureBinaryData& Armory::Signer::ResolverFeed_AssetWalletSingle::getPrivK wltPtr_->derivePrivKeyFromPath(pathIter->second.first); } - return wltPtr_->getDecrypedPrivateKeyForId(pathIter->second.second); + return wltPtr_->getDecryptedPrivateKeyForId(pathIter->second.second); } } diff --git a/cppForSwig/Signer/Script.cpp b/cppForSwig/Signer/Script.cpp index b884e2086..4f21ca43b 100644 --- a/cppForSwig/Signer/Script.cpp +++ b/cppForSwig/Signer/Script.cpp @@ -105,6 +105,7 @@ void StackItem_MultiSig::merge(const StackItem* obj) } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void StackItem_PushData::serialize( Codec_SignerState::StackEntryState& protoMsg) const { @@ -255,6 +256,7 @@ shared_ptr StackItem::deserialize( return itemPtr; } +#endif //////////////////////////////////////////////////////////////////////////////// StackItem_MultiSig::StackItem_MultiSig(unsigned id, BinaryData& script) : diff --git a/cppForSwig/Signer/Script.h b/cppForSwig/Signer/Script.h index 7f18717cd..24445704e 100644 --- a/cppForSwig/Signer/Script.h +++ b/cppForSwig/Signer/Script.h @@ -30,9 +30,9 @@ #include "SigHashEnum.h" #include "TxEvalState.h" #include "ResolverFeed.h" - +#ifdef BUILD_PROTOBUF #include "protobuf/Signer.pb.h" - +#endif namespace Armory { @@ -965,10 +965,12 @@ namespace Armory unsigned getId(void) const { return id_; } virtual bool isValid(void) const { return true; } +#ifdef BUILD_PROTOBUF virtual void serialize(Codec_SignerState::StackEntryState&) const = 0; static std::shared_ptr deserialize( const Codec_SignerState::StackEntryState&); +#endif }; //// @@ -981,7 +983,9 @@ namespace Armory {} bool isSame(const StackItem* obj) const override; +#ifdef BUILD_PROTOBUF void serialize(Codec_SignerState::StackEntryState&) const override; +#endif bool isValid(void) const override { return !data_.empty(); } }; @@ -1000,7 +1004,9 @@ namespace Armory bool isSame(const StackItem* obj) const override; void merge(const StackItem* obj); +#ifdef BUILD_PROTOBUF void serialize(Codec_SignerState::StackEntryState&) const override; +#endif void injectSig(SecureBinaryData& sig) { sig_ = std::move(sig); @@ -1032,7 +1038,9 @@ namespace Armory void merge(const StackItem* obj); bool isValid(void) const override { return sigs_.size() == m_; } +#ifdef BUILD_PROTOBUF void serialize(Codec_SignerState::StackEntryState&) const override; +#endif }; //// @@ -1046,7 +1054,9 @@ namespace Armory {} bool isSame(const StackItem* obj) const override; +#ifdef BUILD_PROTOBUF void serialize(Codec_SignerState::StackEntryState&) const override; +#endif }; //// @@ -1060,7 +1070,9 @@ namespace Armory {} bool isSame(const StackItem* obj) const; +#ifdef BUILD_PROTOBUF void serialize(Codec_SignerState::StackEntryState&) const; +#endif }; ////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/Signer/ScriptRecipient.cpp b/cppForSwig/Signer/ScriptRecipient.cpp index 99cf6665b..ad161eefa 100644 --- a/cppForSwig/Signer/ScriptRecipient.cpp +++ b/cppForSwig/Signer/ScriptRecipient.cpp @@ -170,6 +170,7 @@ void ScriptRecipient::toPSBT(BinaryWriter& bw) const } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void ScriptRecipient::toProtobuf( Codec_SignerState::RecipientState& protoMsg, unsigned group) const { @@ -200,6 +201,7 @@ shared_ptr ScriptRecipient::fromProtobuf( return recipient; } +#endif //////////////////////////////////////////////////////////////////////////////// void ScriptRecipient::addBip32Path(const BIP32_AssetPath& bip32Path) diff --git a/cppForSwig/Signer/ScriptRecipient.h b/cppForSwig/Signer/ScriptRecipient.h index 7b0dbe0d0..3e243e428 100644 --- a/cppForSwig/Signer/ScriptRecipient.h +++ b/cppForSwig/Signer/ScriptRecipient.h @@ -13,8 +13,9 @@ #include "BinaryData.h" #include "BtcUtils.h" #include "ResolverFeed.h" - +#ifdef BUILD_PROTOBUF #include "protobuf/Signer.pb.h" +#endif class TxOut; @@ -63,7 +64,7 @@ namespace Armory //virtuals virtual const BinaryData& getSerializedScript(void) const { - if (script_.getSize() == 0) + if (script_.empty()) serialize(); return script_; @@ -83,8 +84,9 @@ namespace Armory void addBip32Path(const BIP32_AssetPath&); const std::map& getBip32Paths(void) const; - +#ifdef BUILD_PROTOBUF void toProtobuf(Codec_SignerState::RecipientState&, unsigned) const; +#endif void toPSBT(BinaryWriter&) const; void merge(std::shared_ptr); @@ -103,8 +105,10 @@ namespace Armory static std::shared_ptr fromScript(BinaryDataRef); static std::shared_ptr fromPSBT( BinaryRefReader& brr, const TxOut&); +#ifdef BUILD_PROTOBUF static std::shared_ptr fromProtobuf( const Codec_SignerState::RecipientState&); +#endif }; ////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/Signer/Signer.cpp b/cppForSwig/Signer/Signer.cpp index 9613053c6..3b1481bf4 100644 --- a/cppForSwig/Signer/Signer.cpp +++ b/cppForSwig/Signer/Signer.cpp @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // // -// Copyright (C) 2016-2021, goatpig // +// Copyright (C) 2016-2022, goatpig // // Distributed under the MIT license // // See LICENSE-MIT or https://opensource.org/licenses/MIT // // // @@ -8,20 +8,30 @@ #include "Signer.h" #include "Script.h" +#include "LegacySigner.h" #include "Transactions.h" -#include "make_unique.h" #include "BIP32_Node.h" #include "Assets.h" #include "Addresses.h" #include "../TxOutScrRef.h" +#include "../BitcoinSettings.h" using namespace std; using namespace Armory::Signer; using namespace Armory::Assets; using namespace Armory::Wallets; +#define TXSIGCOLLECT_VER_LEGACY 1 +#define USTXI_VER_LEGACY 1 +#define USTXO_VER_LEGACY 1 +#define TXSIGCOLLECT_VER_MODERN 2 +#define TXSIGCOLLECT_WIDTH 64 +#define TXSIGCOLLECT_HEADER "=====TXSIGCOLLECT-" + +#define TXIN_EXT_P2SHSCRIPT 0x10 + StackItem::~StackItem() {} @@ -437,9 +447,9 @@ BinaryData ScriptSpender::getAvailableInputScript() const } //////////////////////////////////////////////////////////////////////////////// -BinaryData ScriptSpender::getSerializedInput(bool withSig) const +BinaryData ScriptSpender::getSerializedInput(bool withSig, bool loose) const { - if (legacyStatus_ == SpenderStatus::Unknown) + if (legacyStatus_ == SpenderStatus::Unknown && !loose) { throw SpenderException("unresolved spender"); } @@ -715,6 +725,7 @@ void ScriptSpender::processStacks() } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void ScriptSpender::serializeStateHeader( Codec_SignerState::ScriptSpenderState& protoMsg) const { @@ -744,7 +755,7 @@ void ScriptSpender::serializeStateUtxo( else { auto outpoint = protoMsg.mutable_outpoint(); - + auto outputHashRef = getOutputHash(); outpoint->set_txhash(outputHashRef.getPtr(), outputHashRef.getSize()); outpoint->set_txoutindex(getOutputIndex()); @@ -893,6 +904,7 @@ shared_ptr ScriptSpender::deserializeState( return resultPtr; } +#endif //////////////////////////////////////////////////////////////////////////////// void ScriptSpender::merge(const ScriptSpender& obj) @@ -1514,11 +1526,11 @@ void ScriptSpender::sign(shared_ptr proxy) { signStack(legacyStack_, false); signStack(witnessStack_, true); - - processStacks(); } catch (const exception&) {} + + processStacks(); } //////////////////////////////////////////////////////////////////////////////// @@ -1554,7 +1566,7 @@ void ScriptSpender::injectSignature(SecureBinaryData& sig, unsigned sigId) throw runtime_error("spender is already signed!"); map>* stackPtr = nullptr; - + //grab the stack carrying the sig(s) if (isSegWit()) stackPtr = &witnessStack_; @@ -1614,11 +1626,11 @@ void ScriptSpender::injectSignature(SecureBinaryData& sig, unsigned sigId) BinaryDataRef ScriptSpender::getRedeemScriptFromStack( const map>* stackPtr) const { - if (stackPtr == nullptr) + if (stackPtr == nullptr) return BinaryDataRef(); shared_ptr firstPushData; - + //look for redeem script from sig stack items for (auto stackPair : *stackPtr) { @@ -1801,7 +1813,7 @@ void ScriptSpender::toPSBT(BinaryWriter& bw) const //partial sigs { /* - This section only applies to MS or exotic scripts that can be + This section only applies to MS or exotic scripts that can be partially signed. Single sig scripts go to the finalized section right away. */ @@ -2111,7 +2123,7 @@ shared_ptr ScriptSpender::fromPSBT( try { StackResolver resolver(spender->getOutputScript(), feed); - resolver.setFlags( + resolver.setFlags( SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_SEGWIT | SCRIPT_VERIFY_P2SH_SHA256); @@ -2387,12 +2399,14 @@ void ScriptSpender::prettyPrint(ostream& os) const //// Signer //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF Signer::Signer(const Codec_SignerState::SignerState& protoMsg) : TransactionStub() { supportingTxMap_ = std::make_shared>(); deserializeState(protoMsg); } +#endif //////////////////////////////////////////////////////////////////////////////// BinaryDataRef Signer::getSerializedOutputScripts(void) const @@ -2721,7 +2735,7 @@ BinaryDataRef Signer::serializeSignedTx(void) const //txins for (auto& spender : spenders_) - bw.put_BinaryData(spender->getSerializedInput(true)); + bw.put_BinaryData(spender->getSerializedInput(true, false)); //txout count auto recVector = getRecipientVector(); @@ -2788,7 +2802,7 @@ BinaryDataRef Signer::serializeUnsignedTx(bool loose) //txins for (auto& spender : spenders_) - bw.put_BinaryData(spender->getSerializedInput(false)); + bw.put_BinaryData(spender->getSerializedInput(false, loose)); //txout count auto recVector = getRecipientVector(); @@ -2805,8 +2819,11 @@ BinaryDataRef Signer::serializeUnsignedTx(bool loose) bw.put_BinaryData(recipient->getSerializedScript()); //no witness data for unsigned transactions - for (unsigned i=0; i < spenders_.size(); i++) - bw.put_uint8_t(0); + if (isSW) + { + for (unsigned i=0; i < spenders_.size(); i++) + bw.put_uint8_t(0); + } //lock time bw.put_uint32_t(lockTime_); @@ -2848,7 +2865,7 @@ BinaryData Signer::serializeAvailableResolvedData(void) const { try { - bw.put_BinaryData(spender->getSerializedInput(false)); + bw.put_BinaryData(spender->getSerializedInput(false, false)); } catch (const exception&) { @@ -3002,6 +3019,7 @@ bool Signer::verifyRawTx(const BinaryData& rawTx, } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF Codec_SignerState::SignerState Signer::serializeState() const { Codec_SignerState::SignerState protoMsg; @@ -3127,6 +3145,7 @@ void Signer::deserializeState( merge(new_signer); } +#endif //////////////////////////////////////////////////////////////////////////////// void Signer::merge(const Signer& rhs) @@ -3216,6 +3235,739 @@ void Signer::merge(const Signer& rhs) matchAssetPathsWithRoots(); } +//////////////////////////////////////////////////////////////////////////////// +BinaryData Signer::serializeState_Legacy() const +{ + if (isSegWit()) + throw runtime_error("SW txs cannot be serialized to legacy format"); + + BinaryWriter bw; + auto magicBytes = Armory::Config::BitcoinSettings::getMagicBytes(); + bw.put_BinaryData(magicBytes); + bw.put_uint32_t(0); //4 empty bytes + + //inputs + bw.put_var_int(spenders_.size()); + for (const auto& spender : spenders_) + { + BinaryWriter bwTxIn; + bwTxIn.put_uint32_t(USTXI_VER_LEGACY); + bwTxIn.put_BinaryData(magicBytes); + bwTxIn.put_BinaryData(spender->getOutpoint()); + + //supporting tx + try + { + const auto& tx = spender->getSupportingTx(); + bwTxIn.put_var_int(tx.getSize()); + bwTxIn.put_BinaryData(tx.serialize()); + } + catch (const runtime_error&) + { + bwTxIn.put_var_int(0); + } + + //p2sh map BASE_SCRIPT + if (!spender->isP2SH()) + { + bwTxIn.put_var_int(0); + } + else + { + //we assume the spender is resolved since it's flagged as p2sh + if (spender->isSigned()) + { + //if the spender is signed then the stack is empty, we'll have + //to retrieve the base script from the finalized stack. Let's + //keep it simple for now and look at it later. + throw runtime_error( + "Legacy signing across multiple wallets not supported yet"); + } + + auto script = spender->getRedeemScriptFromStack( + &spender->legacyStack_); + bwTxIn.put_var_int(script.getSize()); + bwTxIn.put_BinaryData(script); + } + + //contribID & label (lockbox fields, leaving them empty) + bwTxIn.put_var_int(0); + bwTxIn.put_var_int(0); + + //sequence + bwTxIn.put_uint32_t(spender->getSequence()); + + //key & sig list + auto pubkeys = spender->getRelevantPubkeys(); + bwTxIn.put_var_int(pubkeys.size()); + + for (const auto& pubkeyIt : pubkeys) + { + //pubkey + bwTxIn.put_var_int(pubkeyIt.second.getSize()); + bwTxIn.put_BinaryData(pubkeyIt.second); + + //sig, skipping for now + bwTxIn.put_var_int(0); + + //wallet locator, skipping for now + bwTxIn.put_var_int(0); + } + + + //rest of p2sh map, for nested SW + //we'll ignore this as we dont allow legacy ser for SW txs + + //finalize + bw.put_var_int(bwTxIn.getSize()); + bw.put_BinaryData(bwTxIn.getData()); + } + + //outputs + list serializedRecipients; + for (const auto& recipientList : recipients_) + { + BinaryWriter bwTxOut; + for (const auto& recipient : recipientList.second) + { + bwTxOut.put_uint32_t(USTXO_VER_LEGACY); + bwTxOut.put_BinaryData(magicBytes); + + auto output = recipient->getSerializedScript(); + auto script = output.getSliceRef(8, output.getSize()-8); + + bwTxOut.put_BinaryData(script); + bwTxOut.put_uint64_t(recipient->getValue()); + + //p2sh script (ignore for now) + bwTxOut.put_var_int(0); + + //wltLocator + bwTxOut.put_var_int(0); + + //auth method & data, ignore + bwTxOut.put_var_int(0); + bwTxOut.put_var_int(0); + + //contrib id & label (lockbox stuff, ignore) + bwTxOut.put_var_int(0); + bwTxOut.put_var_int(0); + + //add to list + serializedRecipients.emplace_back(move(bwTxOut)); + } + } + + //finalize outputs + bw.put_var_int(serializedRecipients.size()); + for (const auto& rec : serializedRecipients) + { + bw.put_var_int(rec.getSize()); + bw.put_BinaryData(rec.getData()); + } + + //locktime + bw.put_uint32_t(lockTime_); + + //done + return bw.getData(); +} + +//////////////////////////////////////////////////////////////////////////////// +void Signer::deserializeState_Legacy(const BinaryDataRef& ref) +{ + BinaryRefReader brr(ref); + + auto magicBytes = Armory::Config::BitcoinSettings::getMagicBytes(); + auto magicBytesRef = brr.get_BinaryDataRef(4); + if (magicBytes != magicBytesRef) + throw SignerDeserializationError("legacy deser: magic bytes mismatch!"); + + auto emptyBytes = brr.get_uint32_t(); + if (emptyBytes != 0) + throw SignerDeserializationError("legacy deser: missing empty bytes"); + + auto spenderCount = brr.get_var_int(); + for (unsigned i=0; i keysAndSigs; + auto keyCount = brrSpender.get_var_int(); + keysAndSigs.resize(keyCount); + + for (unsigned y=0; y p2shExtMap; + while (brrSpender.getSizeRemaining() != 0) + { + auto extFlag = brrSpender.get_uint8_t(); + auto extSize = brrSpender.get_var_int(); + auto extRef = brrSpender.get_BinaryDataRef(extSize); + + switch (extFlag) + { + case TXIN_EXT_P2SHSCRIPT: + { + BinaryRefReader brrExt(extRef); + auto keyCount = brrExt.get_var_int(); + + for (unsigned y=0; y(hashRef, outpointIndex); + addSpender(spender); + + spender->setSupportingTx(supportingTxRaw); + auto supportingTx = spender->getSupportingTx(); + auto output = supportingTx.getTxOutCopy(outpointIndex); + + /*** + Resolve the spender state the legacy way: + + We assume the eligible output types are known. We expect the supporting + tx is present and grab the redeemScript from the relevant output. The + redeemScript is either a base script or a nested script. We expect the + following data is provided in the USTXI depending on the redeemScript: + + base script types: + - P2PKH: input should carry the public key + - P2PK: input should carry pubkey + - Multisig: input should carry the many pubkeys + + nested scripts: + - P2SH: input should carry script preimage. We have to parse the + p2sh preimage as the redeemScript to progress. + + The resolver will be fed the relevant entries at which + point it should have the correct state to setup the spender. + ***/ + + auto feed = make_shared(); + + //grab base script + BinaryDataRef baseScript = output.getScriptRef(); + if (!p2shPreimage.empty()) + { + /* + Output script is p2sh, it embeds a hash and we have the preimage + for it. Grab the hash from the script and add the + pair to the feed + */ + + //grab hash from nested script + auto scriptHash = BtcUtils::getTxOutRecipientAddr(baseScript); + if (scriptHash == BtcUtils::BadAddress()) + throw SignerDeserializationError("invalid nested script"); + + //populate feed + feed->hashMap.emplace(scriptHash, p2shPreimage); + + //set the preimage as the base script + baseScript = p2shPreimage; + } + + //get base script type + auto scriptType = BtcUtils::getTxOutScriptType(baseScript); + auto scriptHash = BtcUtils::getTxOutRecipientAddr(baseScript, scriptType); + switch (scriptType) + { + case TXOUT_SCRIPT_STDHASH160: + { + //p2pkh, we should have a pubkey + if (keysAndSigs.size() == 1) + feed->hashMap.emplace(scriptHash, keysAndSigs.begin()->key); + break; + } + + case TXOUT_SCRIPT_STDPUBKEY33: + case TXOUT_SCRIPT_MULTISIG: + { + //these script types carry the pubkey directly + break; + } + + default: + throw SignerDeserializationError( + "unsupported redeem script for legacy utsxi"); + } + + //resolve the spender + try + { + StackResolver resolver(spender->getOutputScript(), feed); + resolver.setFlags( + SCRIPT_VERIFY_P2SH | + SCRIPT_VERIFY_SEGWIT | + SCRIPT_VERIFY_P2SH_SHA256); + + spender->parseScripts(resolver); + } + catch (const exception&) + {} + + //inject sigs, will throw on failure + for (const auto& kas : keysAndSigs) + { + SecureBinaryData sig(kas.sig); + spender->injectSignature(sig, 0); + } + + //TODO: sighash type + + //sequence + spender->setSequence(sequence); + } + + auto recipientCount = brr.get_var_int(); + for (unsigned i=0; i 4) + lockTime_ = brr.get_uint32_t(); + + //look for legacy signer state in extended data + auto legacySigner = LegacySigner::Signer::deserExtState( + brr.get_BinaryDataRef(brr.getSizeRemaining())); + + //get the sigs if any + auto sigsFromLegacySigner = legacySigner.getSigs(); + + //inject them + for (auto& sigPair : sigsFromLegacySigner) + { + if (sigPair.first >= spenders_.size()) + throw SignerDeserializationError("legacy deser: invalid spender id"); + + auto& spender = spenders_[sigPair.first]; + spender->injectSignature(sigPair.second, 0); + } +} + +//////////////////////////////////////////////////////////////////////////////// +string Signer::getSigCollectID() const +{ + //legacy unsigned serialization with hardcoded version + BinaryWriter bw; + bw.put_uint32_t(1); //version + + //inputs + bw.put_var_int(spenders_.size()); + for (const auto& spender : spenders_) + { + //outpoint + bw.put_BinaryData(spender->getOutpoint()); + + //empty scriptsig + bw.put_uint8_t(0); + + //sequence + bw.put_uint32_t(spender->getSequence()); + } + + //outputs + list serializedRecipients; + for (const auto& recipientList : recipients_) + { + BinaryWriter bwTxOut; + for (const auto& recipient : recipientList.second) + { + auto output = recipient->getSerializedScript(); + auto script = output.getSliceRef(8, output.getSize()-8); + + //value + bwTxOut.put_uint64_t(recipient->getValue()); + + //script + bwTxOut.put_BinaryData(script); + + //add to list + serializedRecipients.emplace_back(move(bwTxOut)); + } + } + + //finalize outputs + bw.put_var_int(serializedRecipients.size()); + for (const auto& rec : serializedRecipients) + bw.put_BinaryData(rec.getData()); + + //locktime + bw.put_uint32_t(0); + + auto serializedTx = bw.getData(); + if (serializedTx.getSize() < 4) + throw runtime_error("invalid serialized tx"); + + auto hashedTxPrefix = BtcUtils::getHash256(serializedTx); + return BtcUtils::base58_encode(hashedTxPrefix).substr(0, 8); +} + +//////////////////////////////////////////////////////////////////////////////// +string Signer::toString(SignerStringFormat ustxFormat) const +{ + string serializedSigner; + switch (ustxFormat) + { + case SignerStringFormat::TxSigCollect_Modern: + { + serializedSigner = toTxSigCollect(false); + break; + } + + case SignerStringFormat::TxSigCollect_Legacy: + { + serializedSigner = toTxSigCollect(true); + break; + } + + case SignerStringFormat::PSBT: + { + auto psbtBin = toPSBT(); + string psbtStr(psbtBin.toCharPtr(), psbtBin.getSize()); + serializedSigner = BtcUtils::base64_encode(psbtStr); + break; + } + + default: + throw runtime_error("unsupported serialization format"); + } + + return serializedSigner; +} + +//////////////////////////////////////////////////////////////////////////////// +string Signer::toTxSigCollect(bool isLegacy) const +{ + BinaryWriter signerState; + if (isLegacy) + { + auto legacyState = serializeState_Legacy(); + + //txsig collect version, hardcoded to 1 for legacy + signerState.put_uint32_t(TXSIGCOLLECT_VER_LEGACY); + signerState.put_BinaryData(legacyState); + } +#ifdef BUILD_PROTOBUF + else + { + auto protoState = serializeState(); + + BinaryData stateBD(protoState.ByteSizeLong()); + if (!protoState.SerializeToArray(stateBD.getPtr(), stateBD.getSize())) + throw runtime_error("failed to serialize signer proto"); + + //txsig collect version, hardcoded to 2 for regular signers + signerState.put_uint32_t(TXSIGCOLLECT_VER_MODERN); + signerState.put_BinaryData(stateBD); + } +#endif + + //get sigcollect b58id + auto legacyB58ID = getSigCollectID(); + + string lsStr(signerState.getDataRef().toCharPtr(), signerState.getSize()); + auto stateB64 = BtcUtils::base64_encode(lsStr); + + stringstream txcollect; + txcollect << "=====TXSIGCOLLECT-"; + txcollect << setw(46) << setfill('=') << std::left; + txcollect << legacyB58ID << endl; + + size_t offset = 0; + size_t width = 64; + while (offset < stateB64.size()) + { + size_t charCount = std::min(stateB64.size() - offset, width); + auto substr = stateB64.substr(offset, charCount); + txcollect << substr << endl; + offset += charCount; + } + txcollect << setw(64) << setfill('=') << std::left << "=" << endl; + + return txcollect.str(); +} + +//////////////////////////////////////////////////////////////////////////////// +Signer Signer::fromString(const string& signerState) +{ + //try a base 64 deser + try + { + auto binState = BtcUtils::base64_decode(signerState); + auto signer = Signer::fromPSBT(binState); + signer.fromType_ = SignerStringFormat::PSBT; + return signer; + } + catch (const runtime_error&) + { + //not a PSBT, try TxSigCollect instead + } + + auto validateHeader = [](const BinaryDataRef& header)->string + { + string headerStr(header.toCharPtr(), strlen(TXSIGCOLLECT_HEADER)); + if (headerStr != TXSIGCOLLECT_HEADER) + return {}; + + unsigned pos=headerStr.size(); + while (header.toCharPtr()[pos] != '=' && pos < header.getSize()) + ++pos; + + if (pos < headerStr.size()) + return {}; + + return string( + header.toCharPtr() + headerStr.size(), + header.toCharPtr() + pos); + }; + + auto validateFooter = [](const BinaryDataRef& footer)->bool + { + if (footer.empty()) + return false; + + //skip line break if present + auto footerLen = footer.getSize(); + if (footer.getPtr()[footerLen - 1] == '\n') + --footerLen; + + //check size + if (footerLen != TXSIGCOLLECT_WIDTH) + return false; + + //footer should be all '=' + for (unsigned i = 0; i sigCollectSize) + throw SignerDeserializationError("invalid TxSigCollect length"); + + //get body and footer ref + auto bodyRef = brr.get_BinaryDataRef( + brr.getSizeRemaining() - footerLength); + auto footerRef = brr.get_BinaryDataRef(footerLength); + + //validate footer + if (!validateFooter(footerRef)) + throw SignerDeserializationError("invalid TxSigCollect footer"); + + //reconstruct base64 string from lines, evict line breaks + string bodyStr; + unsigned pos = 0; + while (pos < bodyRef.getSize()) + { + //grab the line break as well + auto len = std::min((size_t)TXSIGCOLLECT_WIDTH + 1, bodyRef.getSize() - pos); + + //do not copy the line break + bodyStr += string(bodyRef.toCharPtr() + pos, len - 1); + + //assume there's a line break after each 64 characters + pos += len; + } + + //convert to binary + auto bodyBin = BtcUtils::base64_decode(bodyStr); + auto bodyBinRef = BinaryDataRef::fromString(bodyBin); + BinaryRefReader bodyRR(bodyBinRef); + + //version + auto version = bodyRR.get_uint32_t(); + auto signerStateRef = bodyRR.get_BinaryDataRef(bodyRR.getSizeRemaining()); + Signer theSigner; + switch (version) + { + case TXSIGCOLLECT_VER_LEGACY: + { + //legacy txsig collect + theSigner.deserializeState_Legacy(signerStateRef); + theSigner.fromType_ = SignerStringFormat::TxSigCollect_Legacy; + break; + } + + case TXSIGCOLLECT_VER_MODERN: + { +#ifdef BUILD_PROTOBUF + //regular protobuf packet + Codec_SignerState::SignerState signerProto; + if (!signerProto.ParseFromArray( + signerStateRef.toCharPtr(), signerStateRef.getSize())) + { + //could not deser signer proto + throw SignerDeserializationError( + "[fromTxSigCollect] invalid signer proto"); + } + + theSigner.deserializeState(signerProto); + theSigner.fromType_ = SignerStringFormat::TxSigCollect_Modern; +#endif + break; + } + + default: + throw SignerDeserializationError("unsupported TxSigCollect version"); + } + + //check vs signer id + auto signerId = theSigner.getSigCollectID(); + if (signerId != sigCollectId) + { + string errStr("tx sig collect id mismatch, "); + errStr = errStr + "expected: " + sigCollectId + ", got: " + signerId; + throw SignerDeserializationError(errStr); + } + + return theSigner; +} + //////////////////////////////////////////////////////////////////////////////// bool Signer::isResolved() const { @@ -3313,7 +4065,7 @@ BinaryData Signer::getTxId_const() const if (!spender->isSegWit() && !spender->isSigned()) throw runtime_error("cannot get hash for unsigned legacy input"); - bw.put_BinaryData(spender->getSerializedInput(false)); + bw.put_BinaryData(spender->getSerializedInput(false, false)); } //outputs @@ -3959,6 +4711,18 @@ void Signer::prettyPrint() const cout << ss.str(); } +//////////////////////////////////////////////////////////////////////////////// +SignerStringFormat Signer::deserializedFromType() const +{ + return fromType_; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Signer::canLegacySerialize() const +{ + return !isSegWit(); +} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //// SignerProxy diff --git a/cppForSwig/Signer/Signer.h b/cppForSwig/Signer/Signer.h index 957020f40..58e04ad46 100644 --- a/cppForSwig/Signer/Signer.h +++ b/cppForSwig/Signer/Signer.h @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // // -// Copyright (C) 2016-2021, goatpig // +// Copyright (C) 2016-2022, goatpig // // Distributed under the MIT license // // See LICENSE-MIT or https://opensource.org/licenses/MIT // // // @@ -17,8 +17,9 @@ #include "Transactions.h" #include "ScriptRecipient.h" #include "ResolverFeed.h" - +#ifdef BUILD_PROTOBUF #include "protobuf/Signer.pb.h" +#endif #define SCRIPT_SPENDER_VERSION_MAX 1 #define SCRIPT_SPENDER_VERSION_MIN 0 @@ -76,6 +77,14 @@ namespace Armory Signed }; + enum class SignerStringFormat + { + Unknown = 0, + TxSigCollect_Modern, + TxSigCollect_Legacy, + PSBT + }; + ////////////////////////////////////////////////////////////////////////// class ScriptSpender { @@ -132,7 +141,7 @@ namespace Armory BinaryDataRef getRedeemScriptFromStack( const std::map>*) const; std::map getPartialSigs(void) const; - +#ifdef BUILD_PROTOBUF protected: virtual void serializeStateHeader( Codec_SignerState::ScriptSpenderState&) const; @@ -145,7 +154,7 @@ namespace Armory void serializePathData( Codec_SignerState::ScriptSpenderState&) const; - +#endif private: ScriptSpender(void) {} @@ -191,7 +200,7 @@ namespace Armory BinaryDataRef getOutputScript(void) const; BinaryDataRef getOutputHash(void) const; unsigned getOutputIndex(void) const; - BinaryData getSerializedInput(bool) const; + BinaryData getSerializedInput(bool, bool) const; BinaryData getEmptySerializedInput(void) const; BinaryDataRef getFinalizedWitnessData(void) const; BinaryData serializeAvailableWitnessData(void) const; @@ -234,11 +243,11 @@ namespace Armory bool isResolved(void) const; bool isSigned(void) const; bool isInitialized(void) const; - +#ifdef BUILD_PROTOBUF void serializeState(Codec_SignerState::ScriptSpenderState&) const; static std::shared_ptr deserializeState( const Codec_SignerState::ScriptSpenderState&); - +#endif bool canBeResolved(void) const; bool operator==(const ScriptSpender& rhs) @@ -288,6 +297,7 @@ namespace Armory protected: unsigned version_ = 1; unsigned lockTime_ = 0; + SignerStringFormat fromType_ = SignerStringFormat::Unknown; mutable BinaryData serializedSignedTx_; mutable BinaryData serializedUnsignedTx_; @@ -317,9 +327,10 @@ namespace Armory BinaryData serializeAvailableResolvedData(void) const; static Signer createFromState(const std::string&); +#ifdef BUILD_PROTOBUF static Signer createFromState(const Codec_SignerState::SignerState&); void deserializeSupportingTxMap(const Codec_SignerState::SignerState&); - +#endif void parseScripts(bool); void addBip32Root(std::shared_ptr); void matchAssetPathsWithRoots(void); @@ -333,9 +344,9 @@ namespace Armory { supportingTxMap_ = std::make_shared>(); } - +#ifdef BUILD_PROTOBUF Signer(const Codec_SignerState::SignerState&); - +#endif /*sigs*/ //create sigs @@ -371,7 +382,6 @@ namespace Armory BinaryDataRef&, std::shared_ptr); /*spender data getters*/ - std::shared_ptr getSpender(unsigned) const; uint64_t getOutpointValue(unsigned) const override; unsigned getTxInSequence(unsigned) const override; @@ -389,9 +399,20 @@ namespace Armory BinaryData getTxId_const(void) const; //state import/export - Codec_SignerState::SignerState serializeState(void) const; +#ifdef BUILD_PROTOBUF void deserializeState(const Codec_SignerState::SignerState&); +#endif + void deserializeState_Legacy(const BinaryDataRef&); void merge(const Signer& rhs); +#ifdef BUILD_PROTOBUF + Codec_SignerState::SignerState serializeState(void) const; +#endif + BinaryData serializeState_Legacy(void) const; + std::string getSigCollectID(void) const; + + std::string toString(SignerStringFormat) const; + static Signer fromString(const std::string&); + std::string toTxSigCollect(bool) const; //PSBT BinaryData toPSBT(void) const; @@ -413,6 +434,10 @@ namespace Armory bool isSegWit(void) const; bool hasLegacyInputs (void) const; + //string state + SignerStringFormat deserializedFromType(void) const; + bool canLegacySerialize(void) const; + /*signer setup*/ //tx setup diff --git a/cppForSwig/Signer/Transactions.h b/cppForSwig/Signer/Transactions.h index f89be8d62..d0631a63a 100644 --- a/cppForSwig/Signer/Transactions.h +++ b/cppForSwig/Signer/Transactions.h @@ -15,7 +15,7 @@ #include "BinaryData.h" #include "EncryptionUtils.h" #include "BtcUtils.h" -#include "BlockDataMap.h" +#include "BlockchainDatabase/BlockDataMap.h" #include "Script.h" #include "SigHashEnum.h" diff --git a/cppForSwig/SocketObject.cpp b/cppForSwig/SocketObject.cpp index b0c97b021..7da546f53 100644 --- a/cppForSwig/SocketObject.cpp +++ b/cppForSwig/SocketObject.cpp @@ -10,8 +10,9 @@ #include "SocketWritePayload.h" #include #include - +#ifdef BUILD_PROTOBUF #include "google/protobuf/text_format.h" +#endif using namespace std; @@ -1091,6 +1092,7 @@ void WritePayload_Raw::serialize(vector& data) } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF string WritePayload_Protobuf::serializeToText(void) { if (message_ == nullptr) @@ -1110,3 +1112,4 @@ void WritePayload_Protobuf::serialize(vector& data) data.resize(message_->ByteSizeLong()); message_->SerializeToArray(&data[0], (int)data.size()); } +#endif diff --git a/cppForSwig/SocketWritePayload.h b/cppForSwig/SocketWritePayload.h index d6b6e6fcd..42920ab9c 100644 --- a/cppForSwig/SocketWritePayload.h +++ b/cppForSwig/SocketWritePayload.h @@ -10,11 +10,14 @@ #define _SOCKET_WRITE_PAYLOAD_H #include "SocketObject.h" +#ifdef BUILD_PROTOBUF #include +#endif /////////////////////////////////////////////////////////////////////////////// struct WritePayload_Protobuf : public Socket_WritePayload { +#ifdef BUILD_PROTOBUF std::unique_ptr<::google::protobuf::Message> message_; void serialize(std::vector&); @@ -22,6 +25,7 @@ struct WritePayload_Protobuf : public Socket_WritePayload size_t getSerializedSize(void) const { return message_->ByteSizeLong(); } +#endif }; /////////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/TxClasses.cpp b/cppForSwig/TxClasses.cpp index aec4a2b97..f017a6015 100644 --- a/cppForSwig/TxClasses.cpp +++ b/cppForSwig/TxClasses.cpp @@ -680,6 +680,7 @@ unsigned UTXO::getWitnessDataSize(void) const } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void UTXO::toProtobuf(Codec_Utxo::Utxo& utxoProto) const { utxoProto.set_value(value_); @@ -715,6 +716,7 @@ UTXO UTXO::fromProtobuf(const Codec_Utxo::Utxo& utxoProto) return result; } +#endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/TxClasses.h b/cppForSwig/TxClasses.h index b17a69e7d..94bbbec4e 100644 --- a/cppForSwig/TxClasses.h +++ b/cppForSwig/TxClasses.h @@ -17,7 +17,9 @@ #include "BtcUtils.h" #include "DBUtils.h" +#ifdef BUILD_PROTOBUF #include "protobuf/Utxo.pb.h" +#endif //PayStruct flags #define USE_FULL_CUSTOM_LIST 1 @@ -473,9 +475,10 @@ struct UTXO } bool isInitialized(void) const { return !script_.empty(); } - +#ifdef BUILD_PROTOBUF void toProtobuf(Codec_Utxo::Utxo&) const; static UTXO fromProtobuf(const Codec_Utxo::Utxo&); +#endif }; namespace AsyncClient diff --git a/cppForSwig/Wallets/Accounts/AccountTypes.cpp b/cppForSwig/Wallets/Accounts/AccountTypes.cpp index e75c0c6eb..7d69151f4 100644 --- a/cppForSwig/Wallets/Accounts/AccountTypes.cpp +++ b/cppForSwig/Wallets/Accounts/AccountTypes.cpp @@ -320,7 +320,7 @@ AddressAccountId AccountType_ECDH::getAccountID() const } else { - auto&& root_pub = CryptoECDSA().ComputePublicKey(privateKey_); + auto&& root_pub = CryptoECDSA().ComputePublicKey(privateKey_, true); root_pub.getPtr()[0] ^= (uint8_t)type(); auto&& pub_hash160 = BtcUtils::getHash160(root_pub); diff --git a/cppForSwig/Wallets/Accounts/AddressAccounts.cpp b/cppForSwig/Wallets/Accounts/AddressAccounts.cpp index ce2aa746c..b5d5ca757 100644 --- a/cppForSwig/Wallets/Accounts/AddressAccounts.cpp +++ b/cppForSwig/Wallets/Accounts/AddressAccounts.cpp @@ -41,7 +41,7 @@ unique_ptr AddressAccount::make_new( unique_ptr addressAccountPtr; const auto& addressAccountId = accType->getAccountID(); - addressAccountPtr.reset(new AddressAccount(dbName, accType->getAccountID())); + addressAccountPtr.reset(new AddressAccount(dbName, addressAccountId)); //create root asset auto createRootAsset = @@ -286,8 +286,8 @@ unique_ptr AddressAccount::make_new( //create assets auto cipherData = make_unique( encrypted_root, move(cipher_copy)); - auto priv_asset = - make_shared(assetId, move(cipherData)); + auto priv_asset = make_shared( + assetId, move(cipherData)); rootAsset = make_shared( assetId, pubkey, priv_asset); } @@ -918,13 +918,30 @@ AddressAccountPublicData AddressAccount::exportPublicData() const rootData = woRoot->serialize(); SecureBinaryData derData; + std::shared_ptr extended = nullptr; if (assetData->derScheme_ != nullptr) + { derData = assetData->derScheme_->serialize(); + //check for salts + auto derEcdh = dynamic_pointer_cast( + assetData->derScheme_); + if (derEcdh != nullptr) + { + auto saltMap = derEcdh->getSaltMap(); + auto salts = std::make_shared(); + + for (const auto& saltPair : saltMap) + salts->salts_.emplace(saltPair.second, saltPair.first); + extended = salts; + } + } + AssetAccountPublicData assaPD { assetData->id_, rootData, derData, accPtr->getHighestUsedIndex(), accPtr->getLastComputedIndex() }; + assaPD.extendedData = extended; aapd.accountDataMap_.emplace(assetData->id_, move(assaPD)); } @@ -946,6 +963,37 @@ void AddressAccount::importPublicData(const AddressAccountPublicData& aapd) if (accPtr == nullptr) throw AccountException("[importPublicData] missing asset account"); + switch (accPtr->type()) + { + case AssetAccountTypeEnum::AssetAccountTypeEnum_ECDH: + { + //ecdh account, inject the existing salts + auto accEcdh = dynamic_cast(accPtr.get()); + if (accEcdh == nullptr) + throw AccountException("[importPublicData] account isnt ECDH"); + + auto saltMap = dynamic_pointer_cast( + assapd.second.extendedData); + if (saltMap == nullptr) + { + throw AccountException("[importPublicData]" + " imported data missing salt map"); + } + + for (const auto& saltPair : saltMap->salts_) + { + if (accEcdh->addSalt(nullptr, saltPair.second) != saltPair.first) + { + throw AccountException("[importPublicData]" + " injected salt order mismtach"); + } + } + } + + default: + break; + } + //do not allow rollbacks if (assapd.second.lastComputedIndex_ > accPtr->getLastComputedIndex()) { @@ -960,7 +1008,7 @@ void AddressAccount::importPublicData(const AddressAccountPublicData& aapd) //sync address set instantiatedAddressTypes_ = aapd.instantiatedAddressTypes_; - //check the assets for addresses do exist + //TODO: check the assets for addresses do exist } diff --git a/cppForSwig/Wallets/Accounts/AssetAccounts.cpp b/cppForSwig/Wallets/Accounts/AssetAccounts.cpp index e3062948b..6dff24d6f 100644 --- a/cppForSwig/Wallets/Accounts/AssetAccounts.cpp +++ b/cppForSwig/Wallets/Accounts/AssetAccounts.cpp @@ -37,6 +37,9 @@ shared_ptr AssetAccountData::copy( return accDataCopy; } +AssetAccountExtendedData::~AssetAccountExtendedData() {} +AssetAccountSaltMap::~AssetAccountSaltMap() {} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //// AssetAccount @@ -801,7 +804,7 @@ AssetKeyType AssetAccount_ECDH::addSalt( shared_ptr tx, const SecureBinaryData& salt) { - auto derScheme = + auto derScheme = dynamic_pointer_cast(data_->derScheme_); if (derScheme == nullptr) diff --git a/cppForSwig/Wallets/Accounts/AssetAccounts.h b/cppForSwig/Wallets/Accounts/AssetAccounts.h index d2a6f6fd5..cf12b3c18 100644 --- a/cppForSwig/Wallets/Accounts/AssetAccounts.h +++ b/cppForSwig/Wallets/Accounts/AssetAccounts.h @@ -83,6 +83,18 @@ namespace Armory }; ////////////////////////////////////////////////////////////////////////// + struct AssetAccountExtendedData + { + virtual ~AssetAccountExtendedData(void) = 0; + }; + + struct AssetAccountSaltMap : public AssetAccountExtendedData + { + std::map salts_; + ~AssetAccountSaltMap(void) override; + }; + + //// struct AssetAccountPublicData { const Wallets::AssetAccountId id_; @@ -92,6 +104,8 @@ namespace Armory const Wallets::AssetKeyType lastUsedIndex_; const Wallets::AssetKeyType lastComputedIndex_; + + std::shared_ptr extendedData; }; ////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/Wallets/AssetEncryption.cpp b/cppForSwig/Wallets/AssetEncryption.cpp index 5c916949c..ce75b04cb 100644 --- a/cppForSwig/Wallets/AssetEncryption.cpp +++ b/cppForSwig/Wallets/AssetEncryption.cpp @@ -151,6 +151,12 @@ bool KeyDerivationFunction_Romix::isSame(KeyDerivationFunction* const kdf) const salt_ == kdfromix->salt_; } +//////////////////////////////////////////////////////////////////////////////// +unsigned KeyDerivationFunction_Romix::memTarget() const +{ + return memTarget_; +} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //// Cipher @@ -623,6 +629,20 @@ const SecureBinaryData& ClearTextEncryptionKey::getDerivedKey( EncryptedAssetData::~EncryptedAssetData() {} +//////////////////////////////////////////////////////////////////////////////// +bool EncryptedAssetData::hasData() const +{ + return cipherData_ != nullptr; +} + +//////////////////////////////////////////////////////////////////////////////// +const CipherData* EncryptedAssetData::getCipherDataPtr() const +{ + if (!hasData()) + throw runtime_error("no cypher data"); + return cipherData_.get(); +} + //////////////////////////////////////////////////////////////////////////////// unique_ptr EncryptedAssetData::decrypt( const SecureBinaryData& key) const diff --git a/cppForSwig/Wallets/AssetEncryption.h b/cppForSwig/Wallets/AssetEncryption.h index 6b688e622..85c151309 100644 --- a/cppForSwig/Wallets/AssetEncryption.h +++ b/cppForSwig/Wallets/AssetEncryption.h @@ -20,7 +20,6 @@ #define PRIVKEY_BYTE 0x82 #define ENCRYPTIONKEY_BYTE 0x83 -#define WALLET_SEED_BYTE 0x84 #define CIPHER_DATA_VERSION 0x00000001 #define ENCRYPTION_KEY_VERSION 0x00000001 @@ -97,6 +96,7 @@ namespace Armory bool isSame(KeyDerivationFunction* const) const; BinaryData serialize(void) const; const BinaryData& getId(void) const; + unsigned memTarget(void) const; }; /////////////////////////////////////////////////////////////////////// @@ -397,15 +397,8 @@ namespace Armory const EncryptionKeyId& getEncryptionKeyId(void) const; const BinaryData& getKdfId(void) const; - bool hasData(void) const - { - return cipherData_ != nullptr; - } - - const CipherData* getCipherDataPtr() const - { - return cipherData_.get(); - } + bool hasData(void) const; + const CipherData* getCipherDataPtr(void) const; }; }; //namespace Encryption diff --git a/cppForSwig/Wallets/Assets.cpp b/cppForSwig/Wallets/Assets.cpp index 25d4d3fa7..132637951 100644 --- a/cppForSwig/Wallets/Assets.cpp +++ b/cppForSwig/Wallets/Assets.cpp @@ -17,8 +17,6 @@ #define ASSETENTRY_BIP32ROOT_VERSION 0x00000002 #define ASSETENTRY_LEGACYROOT_VERSION 0x00000001 -#define ENCRYPTED_SEED_VERSION 0x00000001 - #define PRIVKEY_VERSION 0x00000002 #define PUBKEY_COMPRESSED_VERSION 0x00000001 #define PUBKEY_UNCOMPRESSED_VERSION 0x00000001 @@ -831,99 +829,6 @@ unique_ptr Asset_PrivateKey::deserialize( return assetPtr; } -//////////////////////////////////////////////////////////////////////////////// -// -//// EncryptedSeed -// -//////////////////////////////////////////////////////////////////////////////// -const AssetId EncryptedSeed::seedAssetId_(0x5EED, 0xDEE5, 0x5EED); - -//////////////////////////////////////////////////////////////////////////////// -BinaryData EncryptedSeed::serialize() const -{ - BinaryWriter bw; - bw.put_uint32_t(ENCRYPTED_SEED_VERSION); - bw.put_uint8_t(WALLET_SEED_BYTE); - - auto&& cipherData = getCipherDataPtr()->serialize(); - bw.put_var_int(cipherData.getSize()); - bw.put_BinaryData(cipherData); - - BinaryWriter finalBw; - finalBw.put_var_int(bw.getSize()); - finalBw.put_BinaryDataRef(bw.getDataRef()); - return finalBw.getData(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool EncryptedSeed::isSame(Encryption::EncryptedAssetData* const seed) const -{ - auto asset_ed = dynamic_cast(seed); - if (asset_ed == nullptr) - return false; - - return Encryption::EncryptedAssetData::isSame(seed); -} - -//////////////////////////////////////////////////////////////////////////////// -const AssetId& EncryptedSeed::getAssetId() const -{ - return seedAssetId_; -} - -//////////////////////////////////////////////////////////////////////////////// -unique_ptr EncryptedSeed::deserialize( - const BinaryDataRef& data) -{ - BinaryRefReader brr(data); - - //return ptr - unique_ptr assetPtr = nullptr; - - //version - auto version = brr.get_uint32_t(); - - //prefix - auto prefix = brr.get_uint8_t(); - - switch (prefix) - { - case WALLET_SEED_BYTE: - { - switch (version) - { - case 0x00000001: - { - const uint32_t len = (uint32_t)brr.get_var_int(); - if (len > (uint32_t)brr.getSizeRemaining()) { - throw runtime_error("invalid serialized encrypted data len"); - } - auto cipherBdr = brr.get_BinaryDataRef(len); - BinaryRefReader cipherBrr(cipherBdr); - auto cipherData = Encryption::CipherData::deserialize(cipherBrr); - - //ptr - assetPtr = make_unique(move(cipherData)); - break; - } - - default: - throw runtime_error("unsupported seed version"); - } - - break; - } - - default: - throw runtime_error("unexpected encrypted data prefix"); - } - - if (assetPtr == nullptr) - throw runtime_error("failed to deserialize encrypted asset"); - - return assetPtr; -} - //////////////////////////////////////////////////////////////////////////////// // //// MetaData diff --git a/cppForSwig/Wallets/Assets.h b/cppForSwig/Wallets/Assets.h index 9ebc481e1..952af7d1b 100644 --- a/cppForSwig/Wallets/Assets.h +++ b/cppForSwig/Wallets/Assets.h @@ -188,30 +188,6 @@ namespace Armory const Wallets::AssetId&, const BinaryDataRef&); }; - ////////////////////////////////////////////////////////////////////////// - class EncryptedSeed : public Wallets::Encryption::EncryptedAssetData - { - public: - static const Wallets::AssetId seedAssetId_; - - public: - //tors - EncryptedSeed( - std::unique_ptr cipher) : - Wallets::Encryption::EncryptedAssetData(move(cipher)) - {} - - //virtual - bool isSame( - Wallets::Encryption::EncryptedAssetData* const) const override; - BinaryData serialize(void) const override; - const Wallets::AssetId& getAssetId(void) const override; - - //static - static std::unique_ptr deserialize( - const BinaryDataRef&); - }; - ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// class AssetEntry diff --git a/cppForSwig/Wallets/AuthorizedPeers.cpp b/cppForSwig/Wallets/AuthorizedPeers.cpp index f3fcc61ce..df0227393 100644 --- a/cppForSwig/Wallets/AuthorizedPeers.cpp +++ b/cppForSwig/Wallets/AuthorizedPeers.cpp @@ -14,6 +14,7 @@ #include "AuthorizedPeers.h" #include "btc/ecc.h" #include "WalletFileInterface.h" +#include "Seeds/Seeds.h" #include "TerminalPassphrasePrompt.h" @@ -21,6 +22,7 @@ using namespace std; using namespace Armory::Assets; using namespace Armory::Accounts; using namespace Armory::Wallets; +using namespace Armory::Seeds; //////////////////////////////////////////////////////////////////////////////// AuthorizedPeers::AuthorizedPeers( @@ -170,10 +172,10 @@ void AuthorizedPeers::createWallet( derPath.push_back(0xF0000000); //generate bip32 node from random seed - auto&& seed = CryptoPRNG::generateRandom(32); - - wallet_ = AssetWallet_Single::createFromSeed_BIP32_Blank( - baseDir, seed, password, controlPassphrase); + wallet_ = AssetWallet_Single::createFromSeed( + make_unique( + CryptoPRNG::generateRandom(32), SeedType::BIP32_Virgin), + password, controlPassphrase, baseDir); auto wltSingle = dynamic_pointer_cast(wallet_); auto rootBip32 = dynamic_pointer_cast( diff --git a/cppForSwig/Wallets/BIP32_Node.cpp b/cppForSwig/Wallets/BIP32_Node.cpp index c7531585a..0400bea07 100644 --- a/cppForSwig/Wallets/BIP32_Node.cpp +++ b/cppForSwig/Wallets/BIP32_Node.cpp @@ -101,8 +101,8 @@ void BIP32_Node::decodeBase58(const char* str) { btc_hdnode node; - //b58 decode - if(!btc_hdnode_deserialize( + //b58 decode + if (!btc_hdnode_deserialize( str, Armory::Config::BitcoinSettings::get_chain_params(), &node)) throw std::runtime_error("invalid bip32 serialized string " + std::string(str)); @@ -120,7 +120,7 @@ void BIP32_Node::initFromSeed(const SecureBinaryData& seed) } //////////////////////////////////////////////////////////////////////////////// -void BIP32_Node::initFromBase58(const SecureBinaryData& b58) +void BIP32_Node::initFromBase58(BinaryDataRef b58) { //sbd doesnt 0 terminate strings as it is not specialized for char strings, //have to set it manually since libbtc b58 code derives string length from diff --git a/cppForSwig/Wallets/BIP32_Node.h b/cppForSwig/Wallets/BIP32_Node.h index 3af9c10da..192034a17 100644 --- a/cppForSwig/Wallets/BIP32_Node.h +++ b/cppForSwig/Wallets/BIP32_Node.h @@ -38,7 +38,7 @@ class BIP32_Node //init void initFromSeed(const SecureBinaryData&); - void initFromBase58(const SecureBinaryData&); + void initFromBase58(BinaryDataRef); void initFromPrivateKey(uint8_t depth, unsigned leaf_id, unsigned fingerprint, const SecureBinaryData& privKey, const SecureBinaryData& chaincode); void initFromPublicKey(uint8_t depth, unsigned leaf_id, unsigned fingerprint, diff --git a/cppForSwig/Wallets/DecryptedDataContainer.cpp b/cppForSwig/Wallets/DecryptedDataContainer.cpp index 18736dd30..15fed862b 100644 --- a/cppForSwig/Wallets/DecryptedDataContainer.cpp +++ b/cppForSwig/Wallets/DecryptedDataContainer.cpp @@ -63,15 +63,42 @@ void DecryptedDataContainer::lockOther( shared_ptr other) { if (!ownsLock()) - throw DecryptedDataContainerException("unlocked/does not own lock"); + { + throw DecryptedDataContainerException( + "[DecryptedDataContainer::lockOther] unlocked/does not own lock"); + } if (lockedDecryptedData_ == nullptr) throw DecryptedDataContainerException( - "nullptr lock! how did we get this far?"); + "nullptr lock! how did we get this far?"); otherLocks_.push_back(OtherLockedContainer(other)); } +//////////////////////////////////////////////////////////////////////////////// +void DecryptedDataContainer::addKdf( + std::shared_ptr kdfPtr) +{ + kdfMap_.insert(std::make_pair(kdfPtr->getId(), kdfPtr)); +} + +//////////////////////////////////////////////////////////////////////////////// +std::shared_ptr DecryptedDataContainer::getKdf( + const SecureBinaryData& kdfId) const +{ + auto iter = kdfMap_.find(kdfId); + if (iter == kdfMap_.end()) + return nullptr; + return iter->second; +} + +//////////////////////////////////////////////////////////////////////////////// +void DecryptedDataContainer::addEncryptionKey( + std::shared_ptr keyPtr) +{ + encryptedKeys_.insert(std::make_pair(keyPtr->getId(), keyPtr)); +} + //////////////////////////////////////////////////////////////////////////////// unique_ptr DecryptedDataContainer::deriveEncryptionKey( unique_ptr decrKey, @@ -79,11 +106,17 @@ unique_ptr DecryptedDataContainer::deriveEncryptionKey( { //sanity check if (!ownsLock()) - throw DecryptedDataContainerException("unlocked/does not own lock"); + { + throw DecryptedDataContainerException( + "[DecryptedDataContainer::deriveEncryptionKey]" + " unlocked/does not own lock"); + } if (lockedDecryptedData_ == nullptr) + { throw DecryptedDataContainerException( - "nullptr lock! how did we get this far?"); + "nullptr lock! how did we get this far?"); + } //does the decryption key have this derivation? auto derivationIter = decrKey->derivedKeys_.find(kdfid); @@ -122,7 +155,11 @@ const SecureBinaryData& DecryptedDataContainer::getClearTextAssetData( //sanity check if (!ownsLock()) - throw DecryptedDataContainerException("unlocked/does not own lock"); + { + throw DecryptedDataContainerException( + "[DecryptedDataContainer::getClearTextAssetData]" + " unlocked/does not own lock"); + } if (lockedDecryptedData_ == nullptr) throw DecryptedDataContainerException( @@ -249,12 +286,12 @@ EncryptionKeyId DecryptedDataContainer::populateEncryptionKey( { /* This method looks for existing encryption keys in the container. It will - return the clear text encryption key if present, or populate the + return if the clear text encryption key is present, or populate the container until it cannot find precursors (an encryption key may be encrypted by another encryption key). At which point, it will prompt the user for a passphrase. - keyMap: for all eligible key|kdf pairs. These are listed by + keyMap: for all eligible {key, kdf} pairs. These are listed by the encrypted data object that you're looking to decrypt. Returns the id of the key from the keyMap used for decryption. @@ -265,7 +302,11 @@ EncryptionKeyId DecryptedDataContainer::populateEncryptionKey( //sanity check if (!ownsLock()) - throw DecryptedDataContainerException("unlocked/does not own lock"); + { + throw DecryptedDataContainerException( + "[DecryptedDataContainer::populateEncryptionKey]" + " unlocked/does not own lock"); + } if (lockedDecryptedData_ == nullptr) throw DecryptedDataContainerException( @@ -413,7 +454,11 @@ SecureBinaryData DecryptedDataContainer::encryptData( throw DecryptedDataContainerException("null cipher"); if (!ownsLock()) - throw DecryptedDataContainerException("unlocked/does not own lock"); + { + throw DecryptedDataContainerException( + "[DecryptedDataContainer::encryptData]" + " unlocked/does not own lock"); + } if (lockedDecryptedData_ == nullptr) throw DecryptedDataContainerException( @@ -549,7 +594,11 @@ void DecryptedDataContainer::deleteFromDisk( { //sanity checks if (!ownsLock()) - throw DecryptedDataContainerException("unlocked/does not own lock"); + { + throw DecryptedDataContainerException( + "[DecryptedDataContainer::deleteFromDisk]" + " unlocked/does not own lock"); + } //erase key, db interface will wipe it from file tx->erase(key); @@ -632,7 +681,11 @@ void DecryptedDataContainer::encryptEncryptionKey( //we have to own the lock on this container before proceeding if (!ownsLock()) - throw DecryptedDataContainerException("unlocked/does not own lock"); + { + throw DecryptedDataContainerException( + "[DecryptedDataContainer::encryptEncryptionKey]" + " unlocked/does not own lock"); + } if (lockedDecryptedData_ == nullptr) { @@ -766,7 +819,11 @@ void DecryptedDataContainer::eraseEncryptionKey( //we have to own the lock on this container before proceeding if (!ownsLock()) - throw DecryptedDataContainerException("unlocked/does not own lock"); + { + throw DecryptedDataContainerException( + "[DecryptedDataContainer::eraseEncryptionKey]" + " unlocked/does not own lock"); + } if (lockedDecryptedData_ == nullptr) { @@ -857,4 +914,4 @@ void DecryptedDataContainer::eraseEncryptionKey( shared_ptr sharedTx(move(tx)); deleteFromDisk(sharedTx, temp_key); } -} \ No newline at end of file +} diff --git a/cppForSwig/Wallets/DecryptedDataContainer.h b/cppForSwig/Wallets/DecryptedDataContainer.h index b46b5a74f..044574859 100644 --- a/cppForSwig/Wallets/DecryptedDataContainer.h +++ b/cppForSwig/Wallets/DecryptedDataContainer.h @@ -129,6 +129,7 @@ namespace Armory void initAfterLock(void); void cleanUpBeforeUnlock(void); + public: const EncryptionKeyId& getDefaultEncryptionKeyId(void) const { return defaultEncryptionKeyId_; @@ -157,15 +158,10 @@ namespace Armory EncryptionKeyId populateEncryptionKey( const std::map&); - void addKdf(std::shared_ptr kdfPtr) - { - kdfMap_.insert(std::make_pair(kdfPtr->getId(), kdfPtr)); - } - - void addEncryptionKey(std::shared_ptr keyPtr) - { - encryptedKeys_.insert(std::make_pair(keyPtr->getId(), keyPtr)); - } + void addKdf(std::shared_ptr); + std::shared_ptr getKdf( + const SecureBinaryData&) const; + void addEncryptionKey(std::shared_ptr); void updateOnDisk(void); void updateOnDisk(std::unique_ptr); diff --git a/cppForSwig/Wallets/DerivationScheme.cpp b/cppForSwig/Wallets/DerivationScheme.cpp index fdbcfba45..a58fbddde 100644 --- a/cppForSwig/Wallets/DerivationScheme.cpp +++ b/cppForSwig/Wallets/DerivationScheme.cpp @@ -577,9 +577,6 @@ BinaryData DerivationScheme_ECDH::serialize() const AssetKeyType DerivationScheme_ECDH::addSalt(const SecureBinaryData& salt, shared_ptr txPtr) { - if (txPtr == nullptr) - throw DerivationSchemeException("addSalt: null tx"); - if (salt.getSize() != 32) throw DerivationSchemeException("salt is too small"); @@ -595,8 +592,9 @@ AssetKeyType DerivationScheme_ECDH::addSalt(const SecureBinaryData& salt, if (!insertIter.second) throw DerivationSchemeException("failed to insert salt"); - //update on disk - putSalt(id, salt, txPtr); + //update on disk if we have a db tx + if (txPtr != nullptr) + putSalt(id, salt, txPtr); //return insert index return id; @@ -615,7 +613,11 @@ void DerivationScheme_ECDH::putSalt(AssetKeyType id, auto dataRef = txPtr->getDataRef(bwKey.getData()); if (!dataRef.empty()) { - if (dataRef != salt) + //read the salt + BinaryRefReader brr(dataRef); + auto size = brr.get_var_int(); + auto saltRef = brr.get_BinaryDataRef(size); + if (saltRef != salt) { throw DerivationSchemeException( "trying to write a salt different from the one on disk"); @@ -849,4 +851,10 @@ AssetKeyType DerivationScheme_ECDH::getIdForSalt( throw DerivationSchemeException("missing salt"); return iter->second; -} \ No newline at end of file +} + +//////////////////////////////////////////////////////////////////////////////// +const map& DerivationScheme_ECDH::getSaltMap() const +{ + return saltMap_; +} diff --git a/cppForSwig/Wallets/DerivationScheme.h b/cppForSwig/Wallets/DerivationScheme.h index 2ea1a8558..922da6a20 100644 --- a/cppForSwig/Wallets/DerivationScheme.h +++ b/cppForSwig/Wallets/DerivationScheme.h @@ -275,6 +275,8 @@ namespace Armory void putAllSalts(std::shared_ptr); void getAllSalts(std::shared_ptr); Wallets::AssetKeyType getIdForSalt(const SecureBinaryData&); + const std::map& + getSaltMap(void) const; }; }; //namespace Assets }; //namespace Armory diff --git a/cppForSwig/Wallets/Seeds/Backups.cpp b/cppForSwig/Wallets/Seeds/Backups.cpp new file mode 100644 index 000000000..28341e433 --- /dev/null +++ b/cppForSwig/Wallets/Seeds/Backups.cpp @@ -0,0 +1,1527 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright (C) 2020 - 2023, goatpig // +// Distributed under the MIT license // +// See LICENSE-MIT or https://opensource.org/licenses/MIT // +// // +//////////////////////////////////////////////////////////////////////////////// + +#include "Backups.h" +#include "EncryptionUtils.h" +#include "BtcUtils.h" +#include "../WalletIdTypes.h" +#include "Seeds.h" +#include "protobuf/BridgeProto.pb.h" +extern "C" { +#include +} + +#define EASY16_CHECKSUM_LEN 2 +#define EASY16_INDEX_MAX 15 +#define EASY16_LINE_LENGTH 16 + +#define WALLET_RESTORE_LOOKUP 1000 + +using namespace std; +using namespace Armory::Seeds; +using namespace Armory::Assets; +using namespace Armory::Wallets; + +//////////////////////////////////////////////////////////////////////////////// +const vector Easy16Codec::e16chars_ = +{ + 'a', 's', 'd', 'f', + 'g', 'h', 'j', 'k', + 'w', 'e', 'r', 't', + 'u', 'i', 'o', 'n' +}; + +//////////////////////////////////////////////////////////////////////////////// +const set Easy16Codec::eligibleIndexes_ = +{ + BackupType::Armory135, + BackupType::Armory200a, + BackupType::Armory200b, + BackupType::Armory200c, + BackupType::Armory200d +}; + +//////////////////////////////////////////////////////////////////////////////// + +/* - comment from etotheipi: - +Nothing up my sleeve! Need some hardcoded random numbers to use for +encryption IV and salt. Using the first 256 digits of Pi for the +the IV, and first 256 digits of e for the salt (hashed) +*/ + +const string SecurePrint::digits_pi_ = +{ + "ARMORY_ENCRYPTION_INITIALIZATION_VECTOR_" + "1415926535897932384626433832795028841971693993751058209749445923" + "0781640628620899862803482534211706798214808651328230664709384460" + "9550582231725359408128481117450284102701938521105559644622948954" + "9303819644288109756659334461284756482337867831652712019091456485" +}; + +const string SecurePrint::digits_e_ = +{ + "ARMORY_KEY_DERIVATION_FUNCTION_SALT_" + "7182818284590452353602874713526624977572470936999595749669676277" + "2407663035354759457138217852516642742746639193200305992181741359" + "6629043572900334295260595630738132328627943490763233829880753195" + "2510190115738341879307021540891499348841675092447614606680822648" +}; + +const uint32_t SecurePrint::kdfBytes_ = 16 * 1024 * 1024; + +//////////////////////////////////////////////////////////////////////////////// +//// +//// Easy16Codec +//// +//////////////////////////////////////////////////////////////////////////////// +BinaryData Easy16Codec::getHash(const BinaryDataRef& data, uint8_t hint) +{ + if (hint == 0) + { + return BtcUtils::getHash256(data); + } + else + { + SecureBinaryData dataCopy(data.getSize() + 1); + memcpy(dataCopy.getPtr(), data.getPtr(), data.getSize()); + dataCopy.getPtr()[data.getSize()] = hint; + + return BtcUtils::getHash256(dataCopy); + } +} + +//////////////////////////////////////////////////////////////////////////////// +uint8_t Easy16Codec::verifyChecksum( + const BinaryDataRef& data, const BinaryDataRef& checksum) +{ + for (const auto& indexCandidate : eligibleIndexes_) + { + auto hash = getHash(data, (uint8_t)indexCandidate); + if (hash.getSliceRef(0, EASY16_CHECKSUM_LEN) == checksum) + return (uint8_t)indexCandidate; + } + + return EASY16_INVALID_CHECKSUM_INDEX; +} + +//////////////////////////////////////////////////////////////////////////////// +vector Easy16Codec::encode( + const BinaryDataRef data, BackupType bType) +{ + //TODO: use index pairs for a given backup type instead (one index per line) + uint8_t index = (uint8_t)bType; + + if (index > EASY16_INDEX_MAX) + { + LOGERR << "index is too large"; + throw runtime_error("index is too large"); + } + + auto encodeByte = [](char* ptr, uint8_t c)->void + { + uint8_t val1 = c >> 4; + uint8_t val2 = c & 0x0F; + ptr[0] = e16chars_[val1]; + ptr[1] = e16chars_[val2]; + }; + + auto encodeValue = [&encodeByte, &index]( + const BinaryDataRef& chunk16)->SecureBinaryData + { + //get hash + auto h256 = getHash(chunk16, index); + SecureBinaryData result(46); + + //encode the chunk + unsigned charCount = 0; + unsigned offset = 0; + auto ptr = chunk16.getPtr(); + for (unsigned i=0; i result; + result.reserve(count); + + for (unsigned i=0; i& lines) +{ + vector refVec; + refVec.reserve(lines.size()); + for (const auto& line : lines) + refVec.emplace_back(line.getRef()); + + return decode(refVec); +} + +//// +BackupEasy16DecodeResult Easy16Codec::decode(const vector& lines) +{ + if (lines.size() == 0) + throw runtime_error("empty easy16 code"); + + //setup character to value lookup map + map easy16Vals; + for (unsigned i=0; ibool + { + return (*str == ' '); + }; + + auto decodeCharacters = [&easy16Vals]( + uint8_t& result, const char* str)->void + { + //convert characters to value, ignore effect of invalid ones + result = 0; + auto iter1 = easy16Vals.find(str[0]); + if (iter1 != easy16Vals.end()) + result = iter1->second << 4; + + auto iter2 = easy16Vals.find(str[1]); + if (iter2 != easy16Vals.end()) + result += iter2->second; + }; + + /* + Converts line to binary, appends into result. + Returns the hash index matching the checksum. + + Error values: + . -1: checksum mismatch + . -2: invalid checksum data + . -3: not enough room in the result buffer + */ + auto decodeLine = [&isSpace, &decodeCharacters]( + uint8_t* result, size_t& len, + const BinaryDataRef& line, BinaryData& checksum)->int + { + auto maxlen = len; + len = 0; + auto ptr = line.toCharPtr(); + + unsigned i=0; + for (; i= maxlen) + return -3; + + decodeCharacters(result[len], ptr + i); + + //increment result length + ++len; + + //increment i to skip 2 characters + ++i; + } + + //grab checksum + checksum.resize(EASY16_CHECKSUM_LEN); + uint8_t* checksumPtr = checksum.getPtr(); + size_t checksumLen = 0; + for (; i= EASY16_CHECKSUM_LEN) + return -2; + + decodeCharacters(*(checksumPtr + checksumLen), ptr + i); + ++checksumLen; + ++i; + } + + if (checksumLen != EASY16_CHECKSUM_LEN) + return -2; + + //hash data + BinaryDataRef decodedChunk(result, len); + return verifyChecksum(decodedChunk, checksum); + }; + + size_t fullSize = lines.size() * EASY16_LINE_LENGTH; + SecureBinaryData data(fullSize); + vector checksumIndexes; + vector checksums(lines.size()); + + auto dataPtr = data.getPtr(); + size_t pos = 0; + for (unsigned i=0; i EASY16_LINE_LENGTH) + { + throw runtime_error("easy16 line is too long"); + } + else if (len < EASY16_LINE_LENGTH) + { + if (i != lines.size() - 1) + throw runtime_error("easy16 line is too short"); + + //last line doesn't have to be EASY16_LINE_LENGTH bytes long + data.resize(pos); + } + } + + BackupEasy16DecodeResult result; + result.checksumIndexes_ = move(checksumIndexes); + result.checksums_ = move(checksums); + result.data_ = move(data); + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Easy16Codec::repair(BackupEasy16DecodeResult& faultyBackup) +{ + //sanity check + if (faultyBackup.data_.empty() || faultyBackup.checksums_.empty() || + faultyBackup.checksums_.size() != faultyBackup.checksumIndexes_.size()) + { + throw Easy16RepairError("invalid arugments"); + } + + //is there an error? + bool hasError = false; + set validIndexes; + for (auto index : faultyBackup.checksumIndexes_) + { + auto indexIter = eligibleIndexes_.find((BackupType)index); + if (indexIter == eligibleIndexes_.end()) + { + if (index == EASY16_INVALID_CHECKSUM_INDEX) + { + hasError = true; + continue; + } + else + { + //these errors cannot be repaired + throw Easy16RepairError("fatal checksum error"); + } + } + + validIndexes.insert(index); + } + + if (!hasError && validIndexes.size() == 1) + return true; + + /* checksum search function */ + auto searchChecksum = []( + const BinaryDataRef& data, const BinaryData& checksum, uint8_t hint) + ->map>> + { + map>> result; + + //copy the data + SecureBinaryData copied(data); + + //run through each byte of data + for (unsigned i=0; i 1) + { + //there's more than one checksum index, cannot proceed + throw Easy16RepairError("checksum results mismatch"); + } + else if (validIndexes.size() == 1) + { + /* + Some lines are invalid but we have at least one that is valid. This + allows us to search for the expected checksum index in the invalid + lines (they should all match) + */ + unsigned hint = *validIndexes.begin(); + + BinaryRefReader brr(faultyBackup.data_); + for (unsigned i=0; isecond.size() != 1) + return false; + + const auto& repairPair = *repairIter->second.begin(); + if (repairPair.second.size() != 1) + return false; + + //apply repair on the fly + auto ptr = (uint8_t*)(dataRef.getPtr() + repairPair.first); + *ptr = *repairPair.second.begin(); + + //update the repaired line checksum result + faultyBackup.repairedIndexes_.push_back(hint); + } + } + else + { + /* + All lines are invalid. There is no indication of what the checksum index + ought to be. We have to search all lines for a matching index. + */ + vector>>> resultMap; + + BinaryRefReader brr(faultyBackup.data_); + for (unsigned i=0; i> chksumIndexes; + for (unsigned i=0; isecond.size() != 1) + continue; + + auto& chkValueSet = chksumIndexes[lineData.first]; + chkValueSet.insert(i); + } + } + + //only those indexes represented across all lines are eligible + auto iter = chksumIndexes.begin(); + while (iter != chksumIndexes.end()) + { + if (iter->second.size() != faultyBackup.checksumIndexes_.size()) + { + chksumIndexes.erase(iter++); + continue; + } + + ++iter; + } + + //fail if we have several repair candidates + if (chksumIndexes.size() != 1) + return false; + + //repair the data + brr.resetPosition(); + auto repairIndex = chksumIndexes.begin()->first; + for (unsigned i=0; isecond.size() != 1) + return false; + + auto valIter = lineIter->second.begin(); + if (valIter->second.size() != 1) + return false; + + auto dataRef = brr.get_BinaryDataRef( + std::min(size_t(EASY16_LINE_LENGTH), brr.getSizeRemaining())); + + auto ptr = (uint8_t*)(dataRef.getPtr() + valIter->first); + *ptr = *valIter->second.begin(); + + //update the repaired line checksum result + faultyBackup.repairedIndexes_.push_back(repairIndex); + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +//// +//// BackupEasy16DecodeResult +//// +//////////////////////////////////////////////////////////////////////////////// +bool BackupEasy16DecodeResult::isInitialized() const +{ + return checksumIndexes_.size() == 2; +} + +//// +int BackupEasy16DecodeResult::getIndex() const +{ + if (!isInitialized()) + return -1; + + if (repairedIndexes_.size() == 2) + { + if (repairedIndexes_[0] == repairedIndexes_[1]) + return repairedIndexes_[0]; + } + else + { + if (checksumIndexes_[0] == checksumIndexes_[1]) + return checksumIndexes_[0]; + } + + return -1; +} + +bool BackupEasy16DecodeResult::isValid() const +{ + if (!isInitialized()) + return false; + + auto iter = Easy16Codec::eligibleIndexes_.find((BackupType)getIndex()); + return (iter != Easy16Codec::eligibleIndexes_.end()); +} + +//////////////////////////////////////////////////////////////////////////////// +//// +//// SecurePrint +//// +//////////////////////////////////////////////////////////////////////////////// +SecurePrint::SecurePrint() +{ + //setup aes IV and kdf + auto iv32 = BtcUtils::getHash256( + (const uint8_t*)digits_pi_.c_str(), digits_pi_.size()); + iv16_ = move(iv32.getSliceCopy(0, AES_BLOCK_SIZE)); + + salt_ = move(BtcUtils::getHash256( + (const uint8_t*)digits_e_.c_str(), digits_e_.size())); + kdf_.usePrecomputedKdfParams(kdfBytes_, 1, salt_); +} + +//////////////////////////////////////////////////////////////////////////////// +pair SecurePrint::encrypt( + BinaryDataRef root, BinaryDataRef chaincode) +{ + /* + 1. generate passphrase from root and chaincode + */ + + //sanity check + if (root.getSize() != 32) + { + LOGERR << "invalid root size for secureprint"; + throw runtime_error("invalid root size for secureprint"); + } + + SecureBinaryData hmacPhrase(64); + if (chaincode.empty()) + { + /* + The passphrase is the hmac of the root and the chaincode. If the + chaincode is empty, we only hmac the root. + */ + + auto rootHash = BtcUtils::getHash256(root); + BtcUtils::getHMAC512( + rootHash.getPtr(), rootHash.getSize(), + salt_.getPtr(), salt_.getSize(), + hmacPhrase.getPtr()); + } + else + { + /* + Concatenate root and chaincode then hmac + */ + + SecureBinaryData rootCopy(64); + rootCopy.append(root); + rootCopy.append(chaincode); + + auto rootHash = BtcUtils::getHash256(rootCopy); + BtcUtils::getHMAC512( + rootHash.getPtr(), rootHash.getSize(), + salt_.getPtr(), salt_.getSize(), + hmacPhrase.getPtr()); + } + + //passphrase is first 7 bytes of the hmac + BinaryWriter bw; + bw.put_BinaryDataRef(hmacPhrase.getSliceRef(0, 7)); + auto passChecksum = BtcUtils::getHash256(bw.getData()); + bw.put_uint8_t(passChecksum[0]); + + passphrase_ = SecureBinaryData::fromString( + BtcUtils::base58_encode(bw.getData())); + + /* + 2. extend the passphrase + */ + + auto encryptionKey = kdf_.DeriveKey(passphrase_); + + /* + 3. Encrypt the data. We use the libbtc call directly because + we do not want padding + */ + + auto encrypt = [this, &encryptionKey]( + const SecureBinaryData& cleartext, SecureBinaryData& result)->bool + { + //this exclusively encrypt 32 bytes of data + if (cleartext.getSize() != 32) + return false; + + //make sure result buffer is large enough + result.resize(32); + + //encrypt with CBC + auto encrLen = aes256_cbc_encrypt( + encryptionKey.getPtr(), iv16_.getPtr(), + cleartext.getPtr(), cleartext.getSize(), + 0, //no padding + result.getPtr()); + + if (encrLen != 32) + return false; + + return true; + }; + + pair result; + if (!encrypt(root, result.first)) + { + LOGERR << "SecurePrint encryption failure"; + throw runtime_error("SecurePrint encryption failure"); + } + + if (!chaincode.empty()) + { + if (!encrypt(chaincode, result.second)) + { + LOGERR << "SecurePrint encryption failure"; + throw runtime_error("SecurePrint encryption failure"); + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +SecureBinaryData SecurePrint::decrypt( + const SecureBinaryData& ciphertext, const BinaryDataRef passphrase) const +{ + //check passphrase checksum + //TODO: try with std::string_view instead + string passStr(passphrase.toCharPtr(), passphrase.getSize()); + BinaryData passBin; + try + { + passBin = move(BtcUtils::base58_decode(passStr)); + } + catch (const exception&) + { + LOGERR << "invalid SecurePrint passphrase"; + throw runtime_error("invalid SecurePrint passphrase"); + } + + if (passBin.getSize() != 8) + { + LOGERR << "invalid SecurePrint passphrase"; + throw runtime_error("invalid SecurePrint passphrase"); + } + + BinaryRefReader brr(passBin); + auto passBase = brr.get_BinaryDataRef(7); + auto checksum = brr.get_uint8_t(); + + auto passHash = BtcUtils::getHash256(passBase); + if (passHash[0] != checksum) + { + LOGERR << "invalid SecurePrint passphrase"; + throw runtime_error("invalid SecurePrint passphrase"); + } + + if (ciphertext.getSize() < 32) + { + LOGERR << "invalid ciphertext size for SecurePrint"; + throw runtime_error("invalid ciphertext size for SecurePrint"); + } + + //kdf the passphrase + auto encryptionKey = kdf_.DeriveKey(passphrase); + + // + auto decrypt = [this, &encryptionKey]( + const BinaryDataRef& ciphertext, SecureBinaryData& result)->bool + { + //works exclusively on 32 byte packets + if (ciphertext.getSize() != 32) + return false; + + result.resize(32); + + auto size = aes256_cbc_decrypt( + encryptionKey.getPtr(), iv16_.getPtr(), + ciphertext.getPtr(), ciphertext.getSize(), + 0, //no padding + result.getPtr()); + + if (size != 32) + return false; + + return true; + }; + + //decrypt the root + SecureBinaryData result; + if (!decrypt(ciphertext, result)) + { + LOGERR << "failed to decrypt SecurePrint string"; + throw runtime_error("failed to decrypt SecurePrint string"); + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +//// +//// Helpers +//// +//////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////// -- backup strings -- /////////////////////////// +unique_ptr Helpers::getWalletBackup( + shared_ptr wltPtr, BackupType bType) +{ + std::unique_ptr clearTextSeed; + + //grab encrypted seed from wallet + auto lock = wltPtr->lockDecryptedContainer(); + auto wltSeed = wltPtr->getEncryptedSeed(); + if (wltSeed != nullptr) + { + const auto& rawClearTextSeed = wltPtr->getDecryptedValue(wltSeed); + clearTextSeed = ClearTextSeed::deserialize(rawClearTextSeed); + } + else + { + //wallet has no seed, maybe it's a legacy Armory wallet, where + //the seed and root are the same + auto root = wltPtr->getRoot(); + auto root135 = dynamic_pointer_cast(root); + if (root135 == nullptr) + return {}; + + const auto& rootPrivKey = wltPtr->getDecryptedPrivateKeyForAsset( + root135); + clearTextSeed = unique_ptr(new ClearTextSeed_Armory135( + rootPrivKey, root135->getChaincode())); + } + + if (clearTextSeed == nullptr) + throw runtime_error("[getWalletBackup] could not get seed from wallet"); + + //pick default backup type for seed if not set explicitly + if (bType == BackupType::Invalid) + bType = clearTextSeed->getPreferedBackupType(); + + auto backup = getWalletBackup(move(clearTextSeed), bType); + backup->wltId_ = wltPtr->getID(); + return backup; +} + +//// +unique_ptr Helpers::getWalletBackup( + unique_ptr seed, BackupType bType) +{ + //sanity check + if (!seed->isBackupTypeEligible(bType)) + throw runtime_error("[getWalletBackup] ineligible backup type"); + + switch (bType) + { + case BackupType::Armory135: + case BackupType::Armory200a: + case BackupType::Armory200b: + case BackupType::Armory200c: + case BackupType::Armory200d: + return getEasy16BackupString(move(seed)); + + case BackupType::Base58: + return getBase58BackupString(move(seed)); + + case BackupType::BIP39: + return getBIP39BackupString(move(seed)); + + default: + throw runtime_error("[getWalletBackup] invalid backup type"); + } +} + +//////// +unique_ptr Helpers::getEasy16BackupString( + unique_ptr seed) +{ + BinaryDataRef primaryData; + BinaryDataRef secondaryData; + BackupType mode = BackupType::Invalid; + + switch (seed->type()) + { + case SeedType::Armory135: + { + auto seed135 = dynamic_cast(seed.get()); + primaryData = seed135->getRoot().getRef(); + secondaryData = seed135->getChaincode().getRef(); + mode = seed->getPreferedBackupType(); + break; + } + + case SeedType::BIP32_Structured: + case SeedType::BIP32_Virgin: + case SeedType::BIP39: + { + auto seedBip32 = dynamic_cast(seed.get()); + primaryData = seedBip32->getRawEntropy().getRef(); + mode = seed->getPreferedBackupType(); + + switch (seed->type()) + { + case SeedType::BIP39: + //force Armory200d for BIP39 seeds + mode = BackupType::Armory200d; + break; + + default: + mode = seed->getPreferedBackupType(); + } + break; + } + + default: + throw runtime_error("[getEasy16BackupString] invalid seed type"); + } + + //apply secureprint to seed data + SecurePrint sp; + auto encrRoot = sp.encrypt(primaryData, secondaryData); + + //set cleartext and encrypted root + auto lines_clear = Easy16Codec::encode(primaryData, mode); + auto lines_encr = Easy16Codec::encode(encrRoot.first, mode); + + auto result = make_unique(mode); + result->rootClear_ = move(lines_clear); + result->rootEncr_ = move(lines_encr); + if (mode == BackupType::Armory135) + { + //if there's a chaincode, set it too + if (!secondaryData.empty()) + { + result->chaincodeClear_ = move(Easy16Codec::encode(secondaryData, mode)); + result->chaincodeEncr_ = move(Easy16Codec::encode(encrRoot.second, mode)); + } + } + result->spPass_ = move(sp.getPassphrase()); + return result; +} + +//////// +unique_ptr Helpers::getBIP39BackupString( + unique_ptr seed) +{ + //sanity check + if (seed->type() != SeedType::BIP39) + throw runtime_error("[getBIP39BackupString] invalid seed type"); + + auto seedBip39 = dynamic_cast(seed.get()); + unique_ptr result; + switch (seedBip39->getDictionnaryId()) + { + case ClearTextSeed_BIP39::Dictionnary::English_Trezor: + { + //clear libbtc/trezor bip39 mnemonic buffer + mnemonic_clear(); + + //convert raw entropy to mnemonic phrase + auto mnemonicPtr = mnemonic_from_data( + seedBip39->getRawEntropy().getPtr(), + seedBip39->getRawEntropy().getSize()); + string_view mnemonicView(mnemonicPtr, strlen(mnemonicPtr)); + + //copy mnemonic phrase + result = Backup_BIP39::fromMnemonicString(mnemonicView); + + //clear libbtc/trezor bip39 mnemonic buffer + mnemonic_clear(); + break; + } + + default: + throw runtime_error("[getBIP39BackupString] invalid dictionnary id"); + } + return result; +} + +//////// +unique_ptr Helpers::getBase58BackupString( + unique_ptr seed) +{ + auto seedBip32 = dynamic_cast(seed.get()); + if (seedBip32 == nullptr) + throw runtime_error("[getBase58BackupString] invalid seed object"); + + if (seedBip32->type() != SeedType::BIP32_base58Root) + throw runtime_error("[getBase58BackupString] invalid seed type"); + + auto node = seedBip32->getRootNode(); + auto result = make_unique(move(node->getBase58())); + return result; +} + +////////////////////////////// -- restore methods -- /////////////////////////// +shared_ptr Helpers::restoreFromBackup( + unique_ptr backup, const std::string& homedir, + const UserPrompt& callback) +{ + unique_ptr seed = nullptr; + auto bType = backup->type(); + switch (bType) + { + //easy16 backups + case BackupType::Armory135: + case BackupType::Armory200a: + case BackupType::Armory200b: + case BackupType::Armory200d: + case BackupType::Easy16_Unkonwn: + seed = restoreFromEasy16(move(backup), callback, bType); + break; + + case BackupType::Base58: + seed = restoreFromBase58(move(backup)); + break; + + case BackupType::BIP39: + seed = restoreFromBIP39(move(backup)); + break; + + default: + break; + } + + if (seed == nullptr) + { + BridgeProto::RestorePrompt prompt; + prompt.mutable_type_error()->set_error( + "failed to create seed from backup"); + callback(move(prompt)); + throw RestoreUserException("failed to create seed from backup"); + } + + //prompt user to verify id + { + BridgeProto::RestorePrompt prompt; + auto checkWltIdMsg = prompt.mutable_check_wallet_id(); + checkWltIdMsg->set_wallet_id(seed->getWalletId()); + checkWltIdMsg->set_backup_type((int)bType); + + auto reply = callback(move(prompt)); + if (!reply.success()) + throw RestoreUserException("user rejected id"); + } + + //prompt for passwords + SecureBinaryData privkey, control; + { + BridgeProto::RestorePrompt prompt; + prompt.set_get_passphrases(true); + auto reply = callback(move(prompt)); + + if (!reply.success()) + throw RestoreUserException("user did not provide a passphrase"); + + privkey = SecureBinaryData::fromString(reply.passphrases().privkey()); + control = SecureBinaryData::fromString(reply.passphrases().control()); + } + + //return wallet + return AssetWallet_Single::createFromSeed( + std::move(seed), privkey, control, homedir); +} + +//////// +unique_ptr Helpers::restoreFromEasy16( + unique_ptr backup, const UserPrompt& callback, + BackupType& bType) +{ + auto backupE16 = dynamic_cast(backup.get()); + if (backupE16 == nullptr) + return nullptr; + bool isEncrypted = !backupE16->getSpPass().empty(); + + /* decode data */ + + //root + vector first2Lines; + first2Lines.reserve(2); + + auto firstLine = backupE16->getRoot( + Backup_Easy16::LineIndex::One, isEncrypted); + first2Lines.emplace_back(BinaryDataRef( + (uint8_t*)firstLine.data(), firstLine.size())); + + auto secondLine = backupE16->getRoot( + Backup_Easy16::LineIndex::Two, isEncrypted); + first2Lines.emplace_back(BinaryDataRef( + (uint8_t*)secondLine.data(), secondLine.size())); + + auto primaryData = Easy16Codec::decode(first2Lines); + if (!primaryData.isInitialized()) + return nullptr; + + //chaincode + BackupEasy16DecodeResult secondaryData; + if (backupE16->hasChaincode()) + { + vector next2Lines; + auto thirdLine = backupE16->getChaincode( + Backup_Easy16::LineIndex::One, isEncrypted); + next2Lines.emplace_back(BinaryDataRef( + (uint8_t*)thirdLine.data(), thirdLine.size())); + + auto fourthLine = backupE16->getChaincode( + Backup_Easy16::LineIndex::Two, isEncrypted); + next2Lines.emplace_back(BinaryDataRef( + (uint8_t*)fourthLine.data(), fourthLine.size())); + + secondaryData = Easy16Codec::decode(next2Lines); + if (!secondaryData.isInitialized()) + return nullptr; + } + + /* checksums & repair */ + + //root + if (!primaryData.isValid()) + { + if (!Easy16Codec::repair(primaryData)) + { + BridgeProto::RestorePrompt prompt; + auto checksumError = prompt.mutable_checksum_error(); + checksumError->add_index(primaryData.checksumIndexes_[0]); + checksumError->add_index(primaryData.checksumIndexes_[1]); + callback(move(prompt)); + return nullptr; + } + + if (!primaryData.isValid()) + { + BridgeProto::RestorePrompt prompt; + auto checksumError = prompt.mutable_checksum_error(); + checksumError->add_index(primaryData.repairedIndexes_[0]); + checksumError->add_index(primaryData.repairedIndexes_[1]); + callback(move(prompt)); + return nullptr; + } + } + + //chaincode + if (secondaryData.isInitialized()) + { + if (!Easy16Codec::repair(secondaryData)) + { + BridgeProto::RestorePrompt prompt; + auto checksumError = prompt.mutable_checksum_error(); + checksumError->add_index(secondaryData.checksumIndexes_[0]); + checksumError->add_index(secondaryData.checksumIndexes_[1]); + callback(move(prompt)); + return nullptr; + } + + if (!secondaryData.isValid()) + { + BridgeProto::RestorePrompt prompt; + auto checksumError = prompt.mutable_checksum_error(); + checksumError->add_index(secondaryData.repairedIndexes_[0]); + checksumError->add_index(secondaryData.repairedIndexes_[1]); + callback(move(prompt)); + return nullptr; + } + + //check chaincode index matches root index + if (primaryData.getIndex() != secondaryData.getIndex()) + { + BridgeProto::RestorePrompt prompt; + auto checksumError = prompt.mutable_checksum_mismatch(); + checksumError->add_index(primaryData.getIndex()); + checksumError->add_index(secondaryData.getIndex()); + callback(move(prompt)); + return nullptr; + } + } + + /* SecurePrint */ + if (isEncrypted) + try + { + SecurePrint sp; + auto pass = backupE16->getSpPass(); + BinaryDataRef passRef((uint8_t*)pass.data(), pass.size()); + primaryData.data_ = move(sp.decrypt(primaryData.data_, passRef)); + + if (secondaryData.isInitialized()) + secondaryData.data_ = move(sp.decrypt(secondaryData.data_, passRef)); + } + catch (const exception&) + { + BridgeProto::RestorePrompt prompt; + prompt.set_decrypt_error(true); + callback(move(prompt)); + throw RestoreUserException("invalid SP pass"); + } + + /* backup type */ + if (bType == BackupType::Easy16_Unkonwn) + { + bType = (BackupType)primaryData.getIndex(); + } + else + { + if ((BackupType)primaryData.getIndex() != bType) + { + //mismatch between easy16 index and backup expected type + BridgeProto::RestorePrompt prompt; + auto checksumError = prompt.mutable_checksum_mismatch(); + checksumError->add_index(primaryData.getIndex()); + checksumError->add_index((int)bType); + callback(move(prompt)); + return nullptr; + } + } + + /* create seed */ + unique_ptr seedPtr = nullptr; + switch (bType) + { + case BackupType::Armory135: + { + /*legacy armory wallet, legacy backup string*/ + seedPtr = std::move(std::make_unique( + primaryData.data_, secondaryData.data_, + ClearTextSeed_Armory135::LegacyType::Armory135)); + break; + } + + case BackupType::Armory200a: + { + /*legacy armory wallet, indexed backup string*/ + seedPtr = std::move(std::make_unique( + primaryData.data_, secondaryData.data_, + ClearTextSeed_Armory135::LegacyType::Armory200)); + break; + } + + //bip32 wallets + case BackupType::Armory200b: + { + /*BIP32 wallet with BIP44/49/84 accounts*/ + seedPtr = std::move(std::make_unique( + primaryData.data_, SeedType::BIP32_Structured)); + break; + } + + case BackupType::Armory200c: + { + //empty BIP32 wallet + seedPtr = std::move(std::make_unique( + primaryData.data_, SeedType::BIP32_Virgin)); + break; + } + + case BackupType::Armory200d: + { + //empty BIP32 wallet + seedPtr = std::move(std::make_unique( + primaryData.data_, + ClearTextSeed_BIP39::Dictionnary::English_Trezor)); + break; + } + + default: + return nullptr; + } + return seedPtr; +} + +//////// +unique_ptr Helpers::restoreFromBase58( + unique_ptr backup) +{ + auto backupB58 = dynamic_cast(backup.get()); + if (backupB58 == nullptr) + return nullptr; + + unique_ptr seed; + try { + auto b58StrView = backupB58->getBase58String(); + BinaryData b58Ref(b58StrView.data(), b58StrView.size()); + return ClearTextSeed_BIP32::fromBase58(b58Ref); + } + catch (const std::exception&) + { + return nullptr; + } +} + +//////// +unique_ptr Helpers::restoreFromBIP39( + unique_ptr backup) +{ + auto backupBIP39 = dynamic_cast(backup.get()); + if (backupBIP39 == nullptr) + return nullptr; + + const char* mnemonic = backupBIP39->getMnemonicString().data(); + + //check mnemonic phrase + if (mnemonic_check(mnemonic) == 0) + return nullptr; + + //convert mnemonic phrase to raw entropy + SecureBinaryData rawEntropy(33); //max entropy size + checksum + auto lenInBits = mnemonic_to_bits(mnemonic, rawEntropy.getPtr()); + + if (lenInBits == 0) + return nullptr; + + //strip out checksum bits + auto lenInBytes = lenInBits / 8; + lenInBytes -= lenInBytes % 8; + rawEntropy.resize(lenInBytes); + + //entropy to seed + return make_unique(rawEntropy, + ClearTextSeed_BIP39::Dictionnary::English_Trezor); +} + +//////////////////////////////////////////////////////////////////////////////// +// +//// WalletBackup +// +//////////////////////////////////////////////////////////////////////////////// +WalletBackup::WalletBackup(BackupType bType) : + type_(bType) +{} + +WalletBackup::~WalletBackup() +{} + +const string& WalletBackup::getWalletId() const +{ + return wltId_; +} + +const BackupType& WalletBackup::type() const +{ + return type_; +} + +///////////////////////////////// Backup_Easy16 //////////////////////////////// +Backup_Easy16::Backup_Easy16(BackupType bType) : + WalletBackup(bType) +{} + +Backup_Easy16::~Backup_Easy16() +{} + +bool Backup_Easy16::hasChaincode() const +{ + if (type() != BackupType::Armory135 && type() != BackupType::Easy16_Unkonwn) + return false; + + return !chaincodeClear_.empty() || !chaincodeEncr_.empty() ; +} + +//// +string_view Backup_Easy16::getRoot(LineIndex li, bool encrypted) const +{ + auto lineIndex = (int)li; + std::vector::const_iterator iter; + if (!encrypted) + { + iter = rootClear_.begin() + lineIndex; + if (iter == rootClear_.end()) + { + throw runtime_error("[Backup_Easy16::getRoot]" + " missing cleartext line"); + } + } + else + { + iter = rootEncr_.begin() + lineIndex; + if (iter == rootEncr_.end()) + { + throw runtime_error("[Backup_Easy16::getRoot]" + " missing encrypted line"); + } + } + + return string_view(iter->toCharPtr(), iter->getSize()); +} + +string_view Backup_Easy16::getChaincode(LineIndex li, bool encrypted) const +{ + auto lineIndex = (int)li; + std::vector::const_iterator iter; + if (!encrypted) + { + iter = chaincodeClear_.begin() + lineIndex; + if (iter == chaincodeClear_.end()) + { + throw runtime_error("[Backup_Easy16::getChaincode]" + " missing cleartext line"); + } + } + else + { + iter = chaincodeEncr_.begin() + lineIndex; + if (iter == chaincodeEncr_.end()) + { + throw runtime_error("[Backup_Easy16::getChaincode]" + " missing encrypted line"); + } + } + + return string_view(iter->toCharPtr(), iter->getSize()); +} + +string_view Backup_Easy16::getSpPass() const +{ + return string_view(spPass_.toCharPtr(), spPass_.getSize()); +} + +//// +unique_ptr Backup_Easy16::fromLines( + const vector& lines, string_view spPass) +{ + if (lines.size() % 2 != 0) + throw runtime_error("[Backup_Easy16::fromLines] invalid line count"); + + auto result = make_unique(BackupType::Easy16_Unkonwn); + unsigned i=0; + + if (spPass.empty()) + { + for (const auto& line : lines) + { + auto lineSBD = SecureBinaryData::fromStringView(line); + if (i<2) + result->rootClear_.emplace_back(move(lineSBD)); + else + result->chaincodeClear_.emplace_back(move(lineSBD)); + ++i; + } + } + else + { + for (const auto& line : lines) + { + auto lineSBD = SecureBinaryData::fromStringView(line); + if (i<2) + result->rootEncr_.emplace_back(move(lineSBD)); + else + result->chaincodeEncr_.emplace_back(move(lineSBD)); + ++i; + } + result->spPass_ = SecureBinaryData::fromStringView(spPass); + } + + return result; +} + +///////////////////////////////// Backup_Base58 //////////////////////////////// +Backup_Base58::Backup_Base58(SecureBinaryData b58String) : + WalletBackup(BackupType::Base58), b58String_(move(b58String)) +{} + +Backup_Base58::~Backup_Base58() +{} + +string_view Backup_Base58::getBase58String() const +{ + return string_view(b58String_.toCharPtr(), b58String_.getSize()); +} + +unique_ptr Backup_Base58::fromString(const string_view& strV) +{ + return make_unique(SecureBinaryData::fromStringView(strV)); +} + +///////////////////////////////// Backup_BIP39 ///////////////////////////////// +Backup_BIP39::Backup_BIP39() : + WalletBackup(BackupType::BIP39), mnemonicString_() +{} + +Backup_BIP39::~Backup_BIP39() +{} + +unique_ptr Backup_BIP39::fromMnemonicString(string_view strV) +{ + //create a SBD with 1 extra byte to account for terminating 0, + //as trezor-crypto expects null terminate strings + SecureBinaryData mnemonicSBD(strV.size() + 1); + memset(mnemonicSBD.getPtr(), 0, strV.size() + 1); + memcpy(mnemonicSBD.getPtr(), strV.data(), strV.size()); + + unique_ptr result(new Backup_BIP39()); + result->mnemonicString_ = move(mnemonicSBD); + return result; +} + +string_view Backup_BIP39::getMnemonicString() const +{ + return string_view(mnemonicString_.toCharPtr(), mnemonicString_.getSize()); +} diff --git a/cppForSwig/Wallets/Seeds/Backups.h b/cppForSwig/Wallets/Seeds/Backups.h new file mode 100644 index 000000000..5df91014d --- /dev/null +++ b/cppForSwig/Wallets/Seeds/Backups.h @@ -0,0 +1,299 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright (C) 2020 - 2023, goatpig // +// Distributed under the MIT license // +// See LICENSE-MIT or https://opensource.org/licenses/MIT // +// // +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _SECURE_PRINT_H +#define _SECURE_PRINT_H + +#include +#include +#include +#include "SecureBinaryData.h" +#include "EncryptionUtils.h" + +#include "Wallets.h" + +#define EASY16_INVALID_CHECKSUM_INDEX UINT8_MAX + +namespace BridgeProto +{ + class RestorePrompt; + class RestoreReply; +} + +namespace Armory +{ + namespace Seeds + { + //forward declarations + class ClearTextSeed; + class ClearTextSeed_BIP39; + + ////////////////////////////////////////////////////////////////////////// + class RestoreUserException : public std::runtime_error + { + public: + RestoreUserException(const std::string& errMsg) : + std::runtime_error(errMsg) + {} + }; + + //// + class Easy16RepairError : public std::runtime_error + { + public: + Easy16RepairError(const std::string& errMsg) : + std::runtime_error(errMsg) + {} + }; + + //// + enum class BackupType : int + { + //easy16, seed (2 or 4 lines), hash index is always 0 + Armory135 = 0, + + /* + easy16, seed (2 lines), hash index defines seed type: + - a: Armory legacy derivation, P2PKH + P2WPK + P2SH-2WPKH + addresses in a single address account + - b: BIP32 with BIP44/49/84 chains, as individual address accounts + - c: BIP32 with no accounts + - d: BIP39 seed with BIP44/49/84 chains, as individual + address accounts, Trezor English dicionnary + */ + Armory200a = 3, + Armory200b = 4, + Armory200c = 5, + + Armory200d = 10, + + //state of an easy16 backup prior to decode + Easy16_Unkonwn = 30, + + //bip32 mnemonic phrase (12~24 words), english dictionnary + BIP39 = 0xFFFF, + + Base58 = 58, + + //raw binary of the seed in hexits, no extra info provided + Raw = INT32_MAX - 1, + + //end marker + Invalid = INT32_MAX + }; + + //// + struct BackupEasy16DecodeResult + { + std::vector checksumIndexes_; + std::vector repairedIndexes_; + std::vector checksums_; + SecureBinaryData data_; + + bool isInitialized(void) const; + bool isValid(void) const; + int getIndex(void) const; + }; + + //// + struct Easy16Codec + { + public: + /*** + Checksum indexes are an byte appended to the 16 byte line that is passed + through the hash256 function to generate the checksum. That byte value + designates the type of wallet this backup was generated from. + + For index 0 (Armory 1.35 wallets), the byte is not appended. + The indexes for each line in a multiple line easy16 code need to match + one another. + ***/ + + static const std::set eligibleIndexes_; + + private: + static BinaryData getHash(const BinaryDataRef&, uint8_t); + static uint8_t verifyChecksum(const BinaryDataRef&, const BinaryDataRef&); + + public: + const static std::vector e16chars_; + + static std::vector encode(const BinaryDataRef, BackupType); + static BackupEasy16DecodeResult decode(const std::vector&); + static BackupEasy16DecodeResult decode(const std::vector&); + static bool repair(BackupEasy16DecodeResult&); + }; + + //// + class SecurePrint + { + private: + const static std::string digits_pi_; + const static std::string digits_e_; + const static uint32_t kdfBytes_; + + BinaryData iv16_; + BinaryData salt_; + mutable KdfRomix kdf_; + + SecureBinaryData passphrase_; + + public: + SecurePrint(void); + + std::pair encrypt( + BinaryDataRef, BinaryDataRef); + SecureBinaryData decrypt( + const SecureBinaryData&, const BinaryDataRef) const; + + const SecureBinaryData& getPassphrase(void) const { return passphrase_; } + }; + + ////////////////////////////////////////////////////////////////////////// + class WalletBackup + { + friend struct Helpers; + + protected: + const BackupType type_; + std::string wltId_; + + public: + WalletBackup(BackupType); + virtual ~WalletBackup(void) = 0; + + const BackupType& type(void) const; + const std::string& getWalletId(void) const; + }; + + //// + class Backup_Easy16 : public WalletBackup + { + friend class Helpers; + + public: + enum class LineIndex : int + { + One = 0, + Two = 1 + }; + + private: + std::vector rootClear_; + std::vector chaincodeClear_; + + std::vector rootEncr_; + std::vector chaincodeEncr_; + + SecureBinaryData spPass_; + + public: + Backup_Easy16(BackupType); + ~Backup_Easy16(void) override; + + bool hasChaincode(void) const; + std::string_view getRoot(LineIndex, bool) const; + std::string_view getChaincode(LineIndex, bool) const; + std::string_view getSpPass(void) const; + + static std::unique_ptr fromLines( + const std::vector&, + std::string_view spPass = {}); + }; + + //// + class Backup_Base58 : public WalletBackup + { + private: + SecureBinaryData b58String_; + + public: + Backup_Base58(SecureBinaryData); + ~Backup_Base58(void) override; + + std::string_view getBase58String(void) const; + static std::unique_ptr fromString( + const std::string_view&); + }; + + //// + class Backup_BIP39 : public WalletBackup + { + private: + SecureBinaryData mnemonicString_; + + private: + Backup_BIP39(void); + + public: + ~Backup_BIP39(void) override; + + std::string_view getMnemonicString(void) const; + static std::unique_ptr fromMnemonicString( + std::string_view); + }; + + //////// + enum RestorePromptType + { + //invalid backup format + FormatError = 1, + + //failed to decode backup string + Failure = 2, + + ChecksumError = 3, + + //failed to decrypt secure print string + DecryptError = 4, + + //requesting wallet's new passphrase + Passphrase = 5, + + //requesting wallet's new control passphrase + Control = 6, + + //present restored wallet's id + Id = 7, + + //unknown wallet type + TypeError = 8, + }; + + //// + struct Helpers + { + using UserPrompt = std::function; + + //backup methods + static std::unique_ptr getWalletBackup( + std::shared_ptr, + BackupType bType = BackupType::Invalid); + static std::unique_ptr getWalletBackup( + std::unique_ptr, BackupType); + static std::unique_ptr getEasy16BackupString( + std::unique_ptr); + static std::unique_ptr getBIP39BackupString( + std::unique_ptr); + static std::unique_ptr getBase58BackupString( + std::unique_ptr); + + //restore methods + static std::shared_ptr restoreFromBackup( + std::unique_ptr, const std::string&, const UserPrompt&); + static std::unique_ptr restoreFromEasy16( + std::unique_ptr, const UserPrompt&, BackupType&); + static std::unique_ptr restoreFromBase58( + std::unique_ptr); + static std::unique_ptr restoreFromBIP39( + std::unique_ptr); + }; + }; //namespace Backups +}; //namespace Armory +#endif diff --git a/cppForSwig/Wallets/Seeds/Seeds.cpp b/cppForSwig/Wallets/Seeds/Seeds.cpp new file mode 100644 index 000000000..5cc43ffc5 --- /dev/null +++ b/cppForSwig/Wallets/Seeds/Seeds.cpp @@ -0,0 +1,748 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright (C) 2023, goatpig // +// Distributed under the MIT license // +// See LICENSE-MIT or https://opensource.org/licenses/MIT // +// // +//////////////////////////////////////////////////////////////////////////////// + +#include "../AssetEncryption.h" +#include "../DecryptedDataContainer.h" +#include "../DerivationScheme.h" +#include "../Assets.h" +#include "../WalletIdTypes.h" +#include "../BIP32_Node.h" +#include "Seeds.h" +#include "Backups.h" +#include "BtcUtils.h" +extern "C" { +#include +} + +using namespace std; +using namespace Armory; +using namespace Armory::Seeds; +using namespace Armory::Wallets; +using namespace Armory::Assets; + +#define ENCRYPTED_SEED_VERSION_1 0x00000001 +#define ENCRYPTED_SEED_VERSION_2 0x00000002 +#define WALLET_SEED_BYTE 0x84 + +//////////////////////////////////////////////////////////////////////////////// +// +//// EncryptedSeed +// +//////////////////////////////////////////////////////////////////////////////// +const Wallets::AssetId EncryptedSeed::seedAssetId_(0x5EED, 0xDEE5, 0x5EED); + +EncryptedSeed::EncryptedSeed(CipherText cipher, SeedType sType) : + Encryption::EncryptedAssetData(move(cipher)), type_(sType) +{} + +EncryptedSeed::~EncryptedSeed() +{} + +SeedType EncryptedSeed::type() const +{ + return type_; +} + +//////////////////////////////-- overrides --/////////////////////////////////// +BinaryData EncryptedSeed::serialize() const +{ + BinaryWriter bw; + bw.put_uint32_t(ENCRYPTED_SEED_VERSION_2); + bw.put_uint8_t(WALLET_SEED_BYTE); + bw.put_int32_t((int32_t)type()); + + auto&& cipherData = getCipherDataPtr()->serialize(); + bw.put_var_int(cipherData.getSize()); + bw.put_BinaryData(cipherData); + + BinaryWriter finalBw; + finalBw.put_var_int(bw.getSize()); + finalBw.put_BinaryDataRef(bw.getDataRef()); + return finalBw.getData(); +} + +//////// +bool EncryptedSeed::isSame(Encryption::EncryptedAssetData* const seed) const +{ + auto asset_ed = dynamic_cast(seed); + if (asset_ed == nullptr) + return false; + + return Encryption::EncryptedAssetData::isSame(seed); +} + +//////////////////////////////-- statics --///////////////////////////////////// +const AssetId& EncryptedSeed::getAssetId() const +{ + return seedAssetId_; +} + +//// +unique_ptr EncryptedSeed::deserialize( + const BinaryDataRef& data) +{ + BinaryRefReader brr(data); + + //return ptr + unique_ptr assetPtr = nullptr; + + //version + auto version = brr.get_uint32_t(); + + //prefix + auto prefix = brr.get_uint8_t(); + + switch (prefix) + { + case WALLET_SEED_BYTE: + { + switch (version) + { + case 0x00000001: + { + //cipher data + auto len = brr.get_var_int(); + if (len > brr.getSizeRemaining()) + throw runtime_error("[EncryptedSeed::deserialize]" + " invalid serialized encrypted data len"); + + auto cipherBdr = brr.get_BinaryDataRef(len); + BinaryRefReader cipherBrr(cipherBdr); + auto cipherData = Encryption::CipherData::deserialize(cipherBrr); + + //seed object + assetPtr = make_unique(move(cipherData), SeedType::Raw); + break; + } + + case 0x00000002: + { + //seed type + auto sType = (SeedType)brr.get_int32_t(); + + //cipher data + auto len = brr.get_var_int(); + if (len > brr.getSizeRemaining()) + throw runtime_error("[EncryptedSeed::deserialize]" + " invalid serialized encrypted data len"); + + auto cipherBdr = brr.get_BinaryDataRef(len); + BinaryRefReader cipherBrr(cipherBdr); + auto cipherData = Encryption::CipherData::deserialize(cipherBrr); + assetPtr = make_unique(move(cipherData), sType); + break; + } + + default: + throw runtime_error("[EncryptedSeed::deserialize]" + " unsupported seed version"); + } + + break; + } + + default: + throw runtime_error("[EncryptedSeed::deserialize]" + " unexpected encrypted data prefix"); + } + + if (assetPtr == nullptr) + { + throw runtime_error("[EncryptedSeed::deserialize]" + " failed to deserialize encrypted asset"); + } + + return assetPtr; +} + +//// +std::unique_ptr EncryptedSeed::fromClearTextSeed( + std::unique_ptr seed, + std::unique_ptr cipher, + std::shared_ptr decrCont) +{ + //sanity checks + if (seed == nullptr) + throw runtime_error("[fromClearTextSeed] null seed"); + + if (cipher == nullptr) + throw runtime_error("[fromClearTextSeed] null cipher"); + + if (decrCont == nullptr) + throw runtime_error("[fromClearTextSeed] null decrypted data container"); + + //copy the cipher to cycle the IV + auto cipherCopy = cipher->getCopy(); + + //serialized clear text seed + BinaryWriter bw; //TODO: need SBD based bw + seed->serialize(bw); + + //encrypt it + auto cipherText = decrCont->encryptData(cipherCopy.get(), bw.getData()); + auto cipherData = make_unique( + cipherText, move(cipherCopy)); + + //instantiate encrypted seed object + return make_unique(move(cipherData), seed->type()); +} + +//////////////////////////////////////////////////////////////////////////////// +// +//// ClearTextSeed +// +//////////////////////////////////////////////////////////////////////////////// +ClearTextSeed::ClearTextSeed(SeedType sType) : + type_(sType) +{} + +ClearTextSeed::~ClearTextSeed() +{} + +SeedType ClearTextSeed::type() const +{ + return type_; +} + +//// +const string& ClearTextSeed::getWalletId() const +{ + if (walletId_.empty()) + walletId_ = computeWalletId(); + return walletId_; +} + +const string& ClearTextSeed::getMasterId() const +{ + if (masterId_.empty()) + masterId_ = computeMasterId(); + return masterId_; +} + +unique_ptr ClearTextSeed::deserialize( + const SecureBinaryData& serializedData) +{ + BinaryRefReader brr(serializedData); + auto type = (SeedType)brr.get_uint8_t(); + + //sanity check + auto len = brr.get_var_int(); + if (len != brr.getSizeRemaining()) + { + throw runtime_error("[ClearTextSeed::deserialize]" + " size mismatch in serialized seed"); + } + + switch (type) + { + case SeedType::Armory135: + { + ClearTextSeed_Armory135::LegacyType lType = + ClearTextSeed_Armory135::LegacyType::Armory200; + BinaryDataRef root; + BinaryDataRef chaincode; + while (!brr.isEndOfStream()) + { + auto prefix = (Prefix)brr.get_uint8_t(); + switch (prefix) + { + case Prefix::LegacyType: + { + lType = + (ClearTextSeed_Armory135::LegacyType)brr.get_uint8_t(); + break; + } + + case Prefix::Root: + { + auto rootLen = brr.get_var_int(); + root = brr.get_BinaryDataRef(rootLen); + break; + } + + case Prefix::Chaincode: + { + auto chLen = brr.get_var_int(); + chaincode = brr.get_BinaryDataRef(chLen); + break; + } + + default: + throw runtime_error("[ClearTextSeed::deserialize]" + " invalid prefix for Armory135 seed"); + } + } + return make_unique(root, chaincode, lType); + } + + case SeedType::BIP32_Structured: + case SeedType::BIP32_Virgin: + { + BinaryDataRef rawEntropy; + while (!brr.isEndOfStream()) + { + auto prefix = (Prefix)brr.get_uint8_t(); + switch (prefix) + { + case Prefix::RawEntropy: + { + auto entLen = brr.get_var_int(); + rawEntropy = brr.get_BinaryDataRef(entLen); + break; + } + + default: + throw runtime_error("[ClearTextSeed::deserialize]" + " invalid prefix for BIP32 seed"); + } + } + return make_unique(rawEntropy, type); + } + + case SeedType::BIP32_base58Root: + { + BinaryDataRef b58root; + while (!brr.isEndOfStream()) + { + auto prefix = (Prefix)brr.get_uint8_t(); + switch (prefix) + { + case Prefix::Base58Root: + { + auto entLen = brr.get_var_int(); + b58root = brr.get_BinaryDataRef(entLen); + break; + } + + default: + throw runtime_error("[ClearTextSeed::deserialize]" + " invalid prefix for BIP32 seed"); + } + } + return ClearTextSeed_BIP32::fromBase58(b58root); + } + + case SeedType::BIP39: + { + BinaryDataRef rawEntropy; + ClearTextSeed_BIP39::Dictionnary dictionnary; + while (!brr.isEndOfStream()) + { + auto prefix = (Prefix)brr.get_uint8_t(); + switch (prefix) + { + case Prefix::RawEntropy: + { + auto entLen = brr.get_var_int(); + rawEntropy = brr.get_BinaryDataRef(entLen); + break; + } + + case Prefix::Dictionnary: + { + dictionnary = + (ClearTextSeed_BIP39::Dictionnary)brr.get_uint32_t(); + break; + } + + default: + throw runtime_error("[ClearTextSeed::deserialize]" + " invalid prefix for BIP39 seed"); + } + } + return make_unique(rawEntropy, dictionnary); + } + + default: + throw runtime_error("[ClearTextSeed::deserialize]" + " unexpected seed type"); + } +} + +//////////////////////////////////////////////////////////////////////////////// +ClearTextSeed_Armory135::ClearTextSeed_Armory135(LegacyType lType) : + ClearTextSeed_Armory135(CryptoPRNG::generateRandom(32), lType) +{} + +ClearTextSeed_Armory135::ClearTextSeed_Armory135( + const SecureBinaryData& root, LegacyType lType) : + ClearTextSeed(SeedType::Armory135), + root_(root), chaincode_({}), + legacyType_(lType) +{} + +ClearTextSeed_Armory135::ClearTextSeed_Armory135(const SecureBinaryData& root, + const SecureBinaryData& chaincode, LegacyType lType) : + ClearTextSeed(SeedType::Armory135), + root_(root), chaincode_(chaincode), + legacyType_(lType) +{} + +ClearTextSeed_Armory135::~ClearTextSeed_Armory135() +{} + +//// +const SecureBinaryData& ClearTextSeed_Armory135::getRoot() const +{ + return root_; +} + +const SecureBinaryData& ClearTextSeed_Armory135::getChaincode() const +{ + return chaincode_; +} + +//// +string ClearTextSeed_Armory135::computeWalletId() const +{ + auto chaincodeCopy = chaincode_; + if (chaincode_.empty()) + chaincodeCopy = BtcUtils::computeChainCode_Armory135(root_); + + auto pubkey = CryptoECDSA().ComputePublicKey(root_); + return Armory::Wallets::generateWalletId(pubkey, chaincodeCopy, type()); +} + +string ClearTextSeed_Armory135::computeMasterId() const +{ + //uncompressed pubkey + auto pubkey = CryptoECDSA().ComputePublicKey(root_); + return generateMasterId(pubkey, chaincode_); +} + +//// +void ClearTextSeed_Armory135::serialize(BinaryWriter& bw) const +{ + /* serialize the seed */ + BinaryWriter inner; + + //legacy type + inner.put_uint8_t((uint8_t)Prefix::LegacyType); + inner.put_uint8_t((uint8_t)legacyType_); + + //root + inner.put_uint8_t((uint8_t)Prefix::Root); + inner.put_var_int(root_.getSize()); + inner.put_BinaryData(root_); + + //chaincode + inner.put_uint8_t((uint8_t)Prefix::Chaincode); + inner.put_var_int(chaincode_.getSize()); + if (!chaincode_.empty()) + inner.put_BinaryData(chaincode_); + + /* append to writer */ + + //seed type + bw.put_uint8_t((uint8_t)type()); + + //packet size + bw.put_var_int(inner.getSize()); + + //packet + bw.put_BinaryData(inner.getData()); +} + +//// +bool ClearTextSeed_Armory135::isBackupTypeEligible(BackupType bType) const +{ + switch (legacyType_) + { + case LegacyType::Armory135: + return bType == BackupType::Armory135; + + case LegacyType::Armory200: + return bType == BackupType::Armory200a; + + default: + break; + } + return false; +} + +BackupType ClearTextSeed_Armory135::getPreferedBackupType() const +{ + switch (legacyType_) + { + case LegacyType::Armory135: + return BackupType::Armory135; + + case LegacyType::Armory200: + return BackupType::Armory200a; + + default: + break; + } + return BackupType::Invalid; +} + +//////////////////////////////////////////////////////////////////////////////// +ClearTextSeed_BIP32::ClearTextSeed_BIP32(SeedType sType) : + ClearTextSeed_BIP32(CryptoPRNG::generateRandom(32), sType) +{} + +ClearTextSeed_BIP32::ClearTextSeed_BIP32(const SecureBinaryData& raw, + SeedType sType) : + ClearTextSeed(sType), rawEntropy_(raw) +{ + switch (sType) + { + case SeedType::BIP32_Structured: + case SeedType::BIP32_Virgin: + case SeedType::BIP32_base58Root: + case SeedType::BIP39: + break; + + default: + throw runtime_error("invalid bip32 seed type"); + } +} + +ClearTextSeed_BIP32::~ClearTextSeed_BIP32() +{} + +unique_ptr ClearTextSeed_BIP32::fromBase58( + const BinaryDataRef& b58) +{ + auto result = make_unique(SeedType::BIP32_base58Root); + result->rootNode_ = make_shared(); + result->rootNode_->initFromBase58(b58); + return move(result); +} + +//// +string ClearTextSeed_BIP32::computeWalletId() const +{ + const auto& rootNode = getRootNode(); + return Armory::Wallets::generateWalletId(rootNode->getPublicKey(), + rootNode->getChaincode(), type()); +} + +string ClearTextSeed_BIP32::computeMasterId() const +{ + //uncompressed pubkey + const auto& rootNode = getRootNode(); + return generateMasterId(rootNode->getPublicKey(), rootNode->getChaincode()); +} + +//// +std::shared_ptr ClearTextSeed_BIP32::getRootNode() const +{ + if (rootNode_ == nullptr) + { + rootNode_ = make_shared(); + rootNode_->initFromSeed(rawEntropy_); + } + return rootNode_; +} + +const SecureBinaryData& ClearTextSeed_BIP32::getRawEntropy() const +{ + return rawEntropy_; +} + +//// +void ClearTextSeed_BIP32::serialize(BinaryWriter& bw) const +{ + /* serialize the seed */ + BinaryWriter inner; + + //root + switch (type()) + { + case SeedType::BIP32_Structured: + case SeedType::BIP32_Virgin: + { + inner.put_uint8_t((uint8_t)Prefix::RawEntropy); + inner.put_var_int(rawEntropy_.getSize()); + inner.put_BinaryData(rawEntropy_); + break; + } + + case SeedType::BIP32_base58Root: + { + inner.put_uint8_t((uint8_t)Prefix::Base58Root); + auto root = getRootNode()->getBase58(); + inner.put_var_int(root.getSize()); + inner.put_BinaryData(root); + break; + } + + default: + throw runtime_error("[ClearTextSeed_BIP32::serialize]" + " unexpected seed type"); + } + + /* append to writer */ + + //seed type + bw.put_uint8_t((uint8_t)type()); + + //packet size + bw.put_var_int(inner.getSize()); + + //packet + bw.put_BinaryData(inner.getData()); +} + +//// +bool ClearTextSeed_BIP32::isBackupTypeEligible(BackupType bType) const +{ + switch (type()) + { + case SeedType::BIP32_Structured: + return bType == BackupType::Armory200b; + + case SeedType::BIP32_Virgin: + return bType == BackupType::Armory200c; + + case SeedType::BIP32_base58Root: + return bType == BackupType::Base58; + + default: + break; + } + + return false; +} + +BackupType ClearTextSeed_BIP32::getPreferedBackupType() const +{ + switch (type()) + { + case SeedType::BIP32_Structured: + return BackupType::Armory200b; + + case SeedType::BIP32_Virgin: + return BackupType::Armory200c; + + case SeedType::BIP32_base58Root: + return BackupType::Base58; + + default: + break; + } + return BackupType::Invalid; +} + +//////////////////////////////////////////////////////////////////////////////// +ClearTextSeed_BIP39::ClearTextSeed_BIP39(const SecureBinaryData& raw, + Dictionnary dictType) : + ClearTextSeed_BIP32(raw, SeedType::BIP39), dictionnary_(dictType) +{} + +ClearTextSeed_BIP39::ClearTextSeed_BIP39(Dictionnary dictType) : + ClearTextSeed_BIP32(CryptoPRNG::generateRandom(32), SeedType::BIP39), + dictionnary_(dictType) +{} + +ClearTextSeed_BIP39::~ClearTextSeed_BIP39() +{} + +//// +std::shared_ptr ClearTextSeed_BIP39::getRootNode() const +{ + if (rootNode_ == nullptr) + setupRootNode(); + return rootNode_; +} + +//// +void ClearTextSeed_BIP39::setupRootNode() const +{ + //sanity checks + if (rawEntropy_.empty()) + { + throw runtime_error("[ClearTextSeed_BIP39::setupRootNode]" + " missing raw entropy"); + } + + if (rootNode_ != nullptr) + { + throw runtime_error("[ClearTextSeed_BIP39::setupRootNode]" + " already have root node"); + } + + switch (dictionnary_) + { + case Dictionnary::English_Trezor: + { + //clear libbtc/trezor bip39 mnemonic buffer + mnemonic_clear(); + + //convert raw entropy to mnemonic phrase + auto mnemonicPtr = mnemonic_from_data( + rawEntropy_.getPtr(), rawEntropy_.getSize()); + + //convert mnemonic phrase to seed + SecureBinaryData seed64(64); + mnemonic_to_seed( + mnemonicPtr, //the mnemonic string + "", //passphrase, null for now + seed64.getPtr(), //result buffer + nullptr); //progress callback, dont care for now + + //clean up libbtc buffer + mnemonic_clear(); + + //setup root node + rootNode_ = make_shared(); + rootNode_->initFromSeed(seed64); + break; + } + + default: + throw runtime_error("[ClearTextSeed_BIP39::setupRootNode]" + " unexpected dictionnary id"); + } +} + +ClearTextSeed_BIP39::Dictionnary ClearTextSeed_BIP39::getDictionnaryId() const +{ + return dictionnary_; +} + +//// +void ClearTextSeed_BIP39::serialize(BinaryWriter& bw) const +{ + /* serialize the seed */ + BinaryWriter inner; + + //root + inner.put_uint8_t((uint8_t)Prefix::RawEntropy); + inner.put_var_int(rawEntropy_.getSize()); + inner.put_BinaryData(rawEntropy_); + + //dictionnary id + inner.put_uint8_t((uint8_t)Prefix::Dictionnary); + inner.put_uint32_t((uint32_t)dictionnary_); + + /* append to writer */ + + //seed type + bw.put_uint8_t((uint8_t)type()); + + //packet size + bw.put_var_int(inner.getSize()); + + //packet + bw.put_BinaryData(inner.getData()); +} + +//// +bool ClearTextSeed_BIP39::isBackupTypeEligible(BackupType bType) const +{ + //BIP39 seeds can be backed up to either the easy16 format or the + //mnemonic phrase, interchangeably + return bType == BackupType::Armory200d || bType == BackupType::BIP39; +} + +BackupType ClearTextSeed_BIP39::getPreferedBackupType() const +{ + return BackupType::BIP39; +} diff --git a/cppForSwig/Wallets/Seeds/Seeds.h b/cppForSwig/Wallets/Seeds/Seeds.h new file mode 100644 index 000000000..59e579ba7 --- /dev/null +++ b/cppForSwig/Wallets/Seeds/Seeds.h @@ -0,0 +1,277 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright (C) 2023, goatpig // +// Distributed under the MIT license // +// See LICENSE-MIT or https://opensource.org/licenses/MIT // +// // +//////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "../AssetEncryption.h" + +class BIP32_Node; +namespace Armory +{ + namespace Wallets + { + namespace Encryption + { + class DecryptedDataContainer; + } + } + + /*** Wallet creation diagram *** + Raw Entropy + | + v + WalletBackup <---> ClearTextSeed <-------- + | | + | | + v | + AssetWallet --> EncryptedSeed + ***/ + + namespace Seeds + { + ////////////////////////////////////////////////////////////////////////// + enum class SeedType : int + { + /* + Armory135: + For wallets using the legacy Armory derivation scheme. + */ + Armory135 = 0, + + /* + BIP32_Structured: + For wallets carrying BIP44/49/84 accounts. Restores to a bip32 wallet + with all these accounts. + */ + BIP32_Structured = 1, + + /* + BIP32_Virgin: + No info is provided about the wallet's structure, restores to an empty + bip32 wallet. + */ + BIP32_Virgin = 15, + + /* + BIP32_base58Root + From a base58 of the wallet root. No info about the wallet structure. + Cannot be extract as easy16. Mostly used to import HW roots. + */ + BIP32_base58Root = 16, + + /* + BIP39: + BIP39 seed. Can be outputed as either Easy16 or BIP39 english + dictionnary mnemonic. Backup string is always converted into the + BIP39 mnemonic then passed through PBKDF2 to generate the seed. + Yield a wallet with BIP44, 49 and 84 accounts. + */ + BIP39 = 8, + + /* + Raw: + Raw entropy. Used for wallet public data encryption and v1 seeds + */ + Raw = INT32_MAX - 1, + }; + enum class BackupType; + + ////////////////////////////////////////////////////////////////////////// + class ClearTextSeed + { + private: + const SeedType type_; + mutable std::string walletId_; + mutable std::string masterId_; + + protected: + enum class Prefix : int + { + Root = 0x11, + Chaincode = 0x22, + PublicKey = 0x33, + RawEntropy = 0x44, + Dictionnary = 0x55, + LegacyType = 0x66, + Base58Root = 0x77 + }; + + virtual std::string computeWalletId(void) const = 0; + virtual std::string computeMasterId(void) const = 0; + + public: + ClearTextSeed(SeedType); + virtual ~ClearTextSeed(void) = 0; + + SeedType type(void) const; + virtual bool isBackupTypeEligible(BackupType) const = 0; + virtual BackupType getPreferedBackupType(void) const = 0; + + const std::string& getWalletId(void) const; + const std::string& getMasterId(void) const; + + virtual void serialize(BinaryWriter&) const = 0; + static std::unique_ptr deserialize( + const SecureBinaryData&); + }; + + //////// + class ClearTextSeed_Armory135 : public ClearTextSeed + { + public: + enum class LegacyType : int + { + /* + Legacy type defines what kinda of backup can be created from this + seed. By default, legacy wallets would be created with a Armory200a + backup type, which would set the hash index to 3. + + A wallet restored from an older backup would then yield backups that + differ from the old paper. To avoid this, we track which legacy type + this seed is from. + + - seed type of LegacyType::Armory135 will generate + BackupType::Armory135 backups + - seed type of LegacyType::Armory200 will generate + BackupType::Armory200a backups + */ + Armory135 = 12, + Armory200 = 34 + }; + + private: + const SecureBinaryData root_; + const SecureBinaryData chaincode_; + const LegacyType legacyType_; + + protected: + std::string computeWalletId(void) const override; + std::string computeMasterId(void) const override; + + public: + //will generate random root + ClearTextSeed_Armory135(LegacyType lType = LegacyType::Armory200); + + //root + ClearTextSeed_Armory135(const SecureBinaryData&, + LegacyType lType = LegacyType::Armory200); + + //root + chaincode + ClearTextSeed_Armory135(const SecureBinaryData&, const SecureBinaryData&, + LegacyType lType = LegacyType::Armory135); + + //overrides + ~ClearTextSeed_Armory135(void) override; + void serialize(BinaryWriter&) const override; + bool isBackupTypeEligible(BackupType) const override; + BackupType getPreferedBackupType(void) const override; + + //local + const SecureBinaryData& getRoot(void) const; + const SecureBinaryData& getChaincode(void) const; + }; + + //////// + class ClearTextSeed_BIP32 : public ClearTextSeed + { + protected: + const SecureBinaryData rawEntropy_; + mutable std::shared_ptr rootNode_; + + protected: + std::string computeWalletId(void) const override; + std::string computeMasterId(void) const override; + + public: + //seed + ClearTextSeed_BIP32(SeedType); + ClearTextSeed_BIP32(const SecureBinaryData&, SeedType); + BackupType getPreferedBackupType(void) const override; + static std::unique_ptr fromBase58( + const BinaryDataRef&); + + //overrides + ~ClearTextSeed_BIP32(void) override; + virtual void serialize(BinaryWriter&) const override; + virtual bool isBackupTypeEligible(BackupType) const override; + + //locals + virtual std::shared_ptr getRootNode(void) const; + const SecureBinaryData& getRawEntropy(void) const; + }; + + //////// + class ClearTextSeed_BIP39 : public ClearTextSeed_BIP32 + { + public: + enum class Dictionnary : int + { + English_Trezor = 1, + }; + + private: + const Dictionnary dictionnary_; + + private: + void setupRootNode(void) const; + + public: + ClearTextSeed_BIP39(const SecureBinaryData&, Dictionnary); + ClearTextSeed_BIP39(Dictionnary); + ~ClearTextSeed_BIP39(void) override; + + void serialize(BinaryWriter&) const override; + bool isBackupTypeEligible(BackupType) const override; + BackupType getPreferedBackupType(void) const override; + + std::shared_ptr getRootNode(void) const override; + Dictionnary getDictionnaryId(void) const; + }; + + ////////////////////////////////////////////////////////////////////////// + class EncryptedSeed : public Wallets::Encryption::EncryptedAssetData + { + /* + Carries the encrypted ClearTextSeed used to generate the wallet. + This class cannot be used to yield wallet seeds on its own, its + main purpose is disk IO. + + Convert to ClearTextSeed for seed/backup manipulations. + To convert, feed the decrypted the cipher text + to ClearTextSeed::deserialize + */ + private: + const SeedType type_; + + public: + using CipherText = std::unique_ptr; + static const Wallets::AssetId seedAssetId_; + + public: + //tors + EncryptedSeed(CipherText, SeedType); + ~EncryptedSeed(void) override; + + //utils + SeedType type(void) const; + bool isSame(Wallets::Encryption::EncryptedAssetData* const) + const override; + const Wallets::AssetId& getAssetId(void) const override; + + //for disk IO + BinaryData serialize(void) const override; + static std::unique_ptr deserialize( + const BinaryDataRef&); + + //used at wallet creation + static std::unique_ptr fromClearTextSeed( + std::unique_ptr, + std::unique_ptr, + std::shared_ptr); + }; + } +} //namespace Armory \ No newline at end of file diff --git a/cppForSwig/Wallets/WalletFileInterface.cpp b/cppForSwig/Wallets/WalletFileInterface.cpp index 7fc1edf52..863210309 100644 --- a/cppForSwig/Wallets/WalletFileInterface.cpp +++ b/cppForSwig/Wallets/WalletFileInterface.cpp @@ -11,10 +11,10 @@ #include "DBUtils.h" #include "WalletHeader.h" #include "DecryptedDataContainer.h" -#include "Assets.h" +#include "Seeds/Seeds.h" using namespace std; -using namespace Armory::Assets; +using namespace Armory::Seeds; using namespace Armory::Wallets::IO; using namespace Armory::Wallets::Encryption; @@ -486,7 +486,8 @@ shared_ptr WalletDBInterface::setupControlDB( auto cipherCopy = keyStruct.cipher_->getCopy(); auto cipherText = decryptedData->encryptData(cipherCopy.get(), seed); auto cipherData = make_unique(cipherText, move(cipherCopy)); - auto encrSeed = make_shared(move(cipherData)); + auto encrSeed = make_shared( + move(cipherData), SeedType::Raw); //write seed to disk auto&& tx = beginWriteTransaction(CONTROL_DB_NAME); diff --git a/cppForSwig/Wallets/WalletFileInterface.h b/cppForSwig/Wallets/WalletFileInterface.h index df7443152..fbce882e3 100644 --- a/cppForSwig/Wallets/WalletFileInterface.h +++ b/cppForSwig/Wallets/WalletFileInterface.h @@ -31,7 +31,7 @@ class PRNG_Fortuna; namespace Armory { - namespace Assets + namespace Seeds { class EncryptedSeed; }; @@ -160,7 +160,7 @@ namespace Armory std::unique_ptr decryptedData_; std::unique_ptr controlLock_; - std::unique_ptr controlSeed_; + std::unique_ptr controlSeed_; unsigned encryptionVersion_ = UINT32_MAX; std::unique_ptr fortuna_; diff --git a/cppForSwig/Wallets/WalletIdTypes.cpp b/cppForSwig/Wallets/WalletIdTypes.cpp index 0a092d03c..709f1bdab 100644 --- a/cppForSwig/Wallets/WalletIdTypes.cpp +++ b/cppForSwig/Wallets/WalletIdTypes.cpp @@ -1,12 +1,15 @@ //////////////////////////////////////////////////////////////////////////////// // // -// Copyright (C) 2021-2021, goatpig // +// Copyright (C) 2021-2023, goatpig // // Distributed under the MIT license // // See LICENSE-MIT or https://opensource.org/licenses/MIT // // // //////////////////////////////////////////////////////////////////////////////// #include "WalletIdTypes.h" +#include "DerivationScheme.h" +#include "Assets.h" +#include "WalletHeader.h" using namespace Armory::Wallets; @@ -655,3 +658,63 @@ EncryptionKeyId EncryptionKeyId::deserializeValue(BinaryRefReader& brr) throw IdException("EncryptionKeyId::deserializeValue"); } } + +///////////////////////// - wallet & master id - /////////////////////////////// +std::string Armory::Wallets::generateWalletId( + std::shared_ptr derScheme, + std::shared_ptr rootEntry, + Armory::Seeds::SeedType sType) +{ + auto addrVec = derScheme->extendPublicChain(rootEntry, + 1, 1 + (int)sType, nullptr); + if (addrVec.size() != (int)sType+1) + throw WalletException("unexpected chain derivation output"); + + auto entry = std::dynamic_pointer_cast( + addrVec[int(sType)]); + if (entry == nullptr) + throw WalletException("unexpected asset entry type"); + + return BtcUtils::computeID(entry->getPubKey()->getUncompressedKey()); +} + +//// +std::string Armory::Wallets::generateWalletId( + SecureBinaryData pubkey, + SecureBinaryData chaincode, + Armory::Seeds::SeedType sType) +{ + //sanity checks + if (pubkey.empty()) + throw WalletException("[generateWalletId] empty pubkey"); + + if (chaincode.empty()) + throw WalletException("[generateWalletId] empty chaincode"); + + //create legacy armory derviation scheme from chaincode + auto derScheme = std::make_shared< + Armory::Assets::DerivationScheme_ArmoryLegacy>(chaincode); + + //create root pubkey asset + auto asset_single = std::make_shared< + Armory::Assets::AssetEntry_Single>( + Armory::Wallets::AssetId::getRootAssetId(), + pubkey, + nullptr); + + //derive '(int)sType' amount of addresses, use last one as id + return Armory::Wallets::generateWalletId(derScheme, asset_single, sType); +} + +//////// +std::string Armory::Wallets::generateMasterId(const SecureBinaryData& pubkey, + const SecureBinaryData& chaincode) +{ + BinaryWriter bw; + bw.put_BinaryData(pubkey); + bw.put_BinaryData(chaincode); + auto hmacMasterMsg = SecureBinaryData::fromString("MetaEntry"); + auto masterID_long = BtcUtils::getHMAC256( + bw.getData(), hmacMasterMsg); + return BtcUtils::computeID(masterID_long); +} diff --git a/cppForSwig/Wallets/WalletIdTypes.h b/cppForSwig/Wallets/WalletIdTypes.h index b1aeaad63..b6c61ebd4 100644 --- a/cppForSwig/Wallets/WalletIdTypes.h +++ b/cppForSwig/Wallets/WalletIdTypes.h @@ -19,7 +19,18 @@ namespace Armory namespace Bridge { class BridgePassphrasePrompt; - }; + } + + namespace Assets + { + class AssetEntry; + class DerivationScheme; + } + + namespace Seeds + { + enum class SeedType; + } namespace Wallets { @@ -183,6 +194,15 @@ namespace Armory BinaryData getSerializedKey(uint8_t) const; static EncryptionKeyId deserializeValue(BinaryRefReader&); }; - }; -}; + + //////////////////////////////////////////////////////////////////////// + std::string generateWalletId(std::shared_ptr, + std::shared_ptr, Seeds::SeedType); + std::string generateWalletId(SecureBinaryData, SecureBinaryData, + Seeds::SeedType); + std::string generateMasterId(const SecureBinaryData&, + const SecureBinaryData&); + + }// namespace Wallets +} #endif \ No newline at end of file diff --git a/cppForSwig/Wallets/Wallets.cpp b/cppForSwig/Wallets/Wallets.cpp index 2d5442c5f..eec26fc19 100644 --- a/cppForSwig/Wallets/Wallets.cpp +++ b/cppForSwig/Wallets/Wallets.cpp @@ -10,6 +10,8 @@ #include "BitcoinSettings.h" #include "Wallets.h" #include "WalletFileInterface.h" +#include "Seeds/Seeds.h" +#include "Seeds/Backups.h" using namespace std; using namespace Armory::Config; @@ -17,6 +19,7 @@ using namespace Armory::Signer; using namespace Armory::Assets; using namespace Armory::Accounts; using namespace Armory::Wallets; +using namespace Armory::Seeds; namespace { @@ -118,9 +121,11 @@ shared_ptr AssetWallet::createAccount( dbName_, accountType, decryptedData_, move(cipher), getRootLbd); auto accID = account_ptr->getID(); - if (accounts_.find(accID) != accounts_.end()) - throw WalletException("already have an address account with this path"); - + const auto& itAccount = accounts_.find(accID); + if (itAccount != accounts_.end()) { + //throw WalletException("already have an address account with path " + accID.toHexStr()); + return itAccount->second; + } //commit to disk account_ptr->commit(iface_); @@ -592,6 +597,22 @@ const Armory::Wallets::AddressAccountId& AssetWallet::getMainAccountID() const return mainAccount_; } +//////////////////////////////////////////////////////////////////////////////// +const EncryptionKeyId& AssetWallet::getDefaultEncryptionKeyId() const +{ + if (decryptedData_ == nullptr) + throw WalletException("[getDefaultEncryptionKeyId] unexpected error"); + + return decryptedData_->getDefaultEncryptionKeyId(); +} + +//////////////////////////////////////////////////////////////////////////////// +std::shared_ptr + AssetWallet::getDefaultKdf() const +{ + return decryptedData_->getKdf(decryptedData_->getDefaultKdfId()); +} + //////////////////////////////////////////////////////////////////////////////// shared_ptr AssetWallet::getAccountForID( const AddressAccountId& id) const @@ -915,7 +936,7 @@ string AssetWallet::forkWatchingOnly( if (DBUtils::fileExists(newname, 0)) throw WalletException("WO wallet filename already exists"); - //open original wallet db & new + //open original wallet db & new auto originIface = getIfaceFromFile(filename, true, passLbd); auto masterID = getMasterID(originIface); @@ -1130,36 +1151,71 @@ const AddressAccountId& AssetWallet_Single::createBIP32Account( return accountPtr->getID(); } +/////////////////////////////-- wallet creation --////////////////////////////// +shared_ptr AssetWallet_Single::createFromSeed( + std::unique_ptr seed, + const SecureBinaryData& passphrase, + const SecureBinaryData& controlPassphrase, + const string& folder, unsigned lookup) +{ + //sanity check + if (seed == nullptr) + throw WalletException("[AssetWallet_Single::createFromSeed] null seed"); + + //determine wallet type from seed type + shared_ptr result; + switch (seed->type()) + { + case Seeds::SeedType::Armory135: + { + auto seedA135 = dynamic_cast(seed.get()); + result = createFromSeed( + folder, seedA135, + passphrase, controlPassphrase, + lookup); + break; + } + + case Seeds::SeedType::BIP32_Structured: + case Seeds::SeedType::BIP32_Virgin: + case Seeds::SeedType::BIP32_base58Root: + case Seeds::SeedType::BIP39: + { + auto seedBip32 = dynamic_cast(seed.get()); + result = createFromSeed( + folder, seedBip32, + passphrase, controlPassphrase, + lookup); + break; + } + + default: + throw WalletException("[AssetWallet_Single::createFromSeed]" + " unexpected seed type"); + } + + //set the seed + result->setSeed(std::move(seed), passphrase); + return result; +} + //////////////////////////////////////////////////////////////////////////////// -shared_ptr AssetWallet_Single:: - createFromPrivateRoot_Armory135( +shared_ptr AssetWallet_Single::createFromSeed( const string& folder, - const SecureBinaryData& privateRoot, - SecureBinaryData chaincode, + ClearTextSeed_Armory135* seed, const SecureBinaryData& passphrase, const SecureBinaryData& controlPassphrase, unsigned lookup) { - /* - Pass the chaincode as it may be non deterministic for older Armory wallets. - To generate the chaincode from the private root, leave it empty. - */ + if (seed == nullptr) + throw WalletException("[createFromSeed] null root"); + const auto& privateRoot = seed->getRoot(); if (privateRoot.getSize() != 32) - throw WalletException("invalid root size"); - auto&& pubkey = CryptoECDSA().ComputePublicKey(privateRoot); + throw WalletException("[createFromSeed] invalid root size"); - //compute wallet ID - BinaryWriter masterIdPreimage; - masterIdPreimage.put_BinaryData(pubkey); - if (!chaincode.empty()) - masterIdPreimage.put_BinaryData(chaincode); - - //compute master ID as hmac256(root pubkey + chaincode, "MetaEntry") - auto hmacMasterMsg = SecureBinaryData::fromString("MetaEntry"); - auto&& masterID_long = BtcUtils::getHMAC256( - masterIdPreimage.getData(), hmacMasterMsg); - auto&& masterID = BtcUtils::computeID(masterID_long); + //TODO: need ID/backup pair tests (wallet ID should use fragments + //from derivation scheme, backup type should to different walletID) /* Create control passphrase lambda. It gets wiped after the wallet is setup @@ -1171,30 +1227,22 @@ shared_ptr AssetWallet_Single:: }; //create wallet file and dbenv - const std::string path = walletFileName(folder, masterID, "wallet"); + const auto& masterId = seed->getMasterId(); + const std::string path = walletFileName(folder, masterId, "wallet"); auto iface = getIfaceFromFile(path, false, controlPassLbd); - string walletID; + auto chaincode = seed->getChaincode(); + if (chaincode.empty()) { - //generate chaincode if it's not provided - if (chaincode.empty()) - chaincode = BtcUtils::computeChainCode_Armory135(privateRoot); - - auto chaincodeCopy = chaincode; - auto derScheme = make_shared( - chaincodeCopy); - - auto asset_single = make_shared( - AssetId::getRootAssetId(), - pubkey, nullptr); - - walletID = move(computeWalletID(derScheme, asset_single)); + //seed has no chaincode, generate deterministic one + chaincode = BtcUtils::computeChainCode_Armory135(privateRoot); } //create empty wallet + const auto& walletId = seed->getWalletId(); auto walletPtr = initWalletDb( iface, - masterID, walletID, + masterId, walletId, passphrase, controlPassphrase, privateRoot, @@ -1202,7 +1250,7 @@ shared_ptr AssetWallet_Single:: 0); //pass 0 for the fingerprint to signal legacy wallet //set as main - setMainWallet(iface, walletID); + setMainWallet(iface, walletId); //create account auto account135 = make_shared(); @@ -1228,82 +1276,65 @@ shared_ptr AssetWallet_Single:: return walletPtr; } -//////////////////////////////////////////////////////////////////////////////// -shared_ptr - AssetWallet_Single::createFromPublicRoot_Armory135( - const string& folder, - SecureBinaryData& pubRoot, - SecureBinaryData& chainCode, - const SecureBinaryData& controlPassphrase, - unsigned lookup) +/* substitutes variables from vars into tmpl with syntax "" -> "var_value" +* Available var names: +* * master_id +* * wallet_id +* * is_public = WatchingOnly if this flag is set +*/ +static string substFileTemplate(const string& tmpl + , const unordered_map& vars) { - //compute master ID as hmac256(root pubkey, "MetaEntry") - auto hmacMasterMsg = SecureBinaryData::fromString("MetaEntry"); - auto&& masterID_long = BtcUtils::getHMAC256(pubRoot, hmacMasterMsg); - auto&& masterID = BtcUtils::computeID(masterID_long); - - /* - Create control passphrase lambda. It gets wiped after the wallet is setup - */ - auto controlPassLbd = - [&controlPassphrase](const set&)->SecureBinaryData - { - return controlPassphrase; - }; - - //create wallet file and dbenv - const std::string path = walletFileName(folder, masterID, "WatchingOnly"); - auto iface = getIfaceFromFile(path, false, controlPassLbd); - - string walletID; - shared_ptr rootPtr; - { - //walletID - auto chainCode_copy = chainCode; - auto derScheme = make_shared( - chainCode_copy); - - rootPtr = make_shared( - AssetId::getRootAssetId(), - pubRoot, nullptr, chainCode); - - walletID = move(computeWalletID(derScheme, rootPtr)); + if (tmpl.empty()) { + return {}; } - - //create wallet - auto walletPtr = initWalletDbWithPubRoot( - iface, - controlPassphrase, - masterID, walletID, - rootPtr); - - //set as main - setMainWallet(iface, walletID); - - //add account - auto account135 = make_shared(); - account135->setMain(true); - - auto accountPtr = walletPtr->createAccount(account135); - accountPtr->extendPublicChain(iface, lookup - 1); - - return walletPtr; + if (tmpl[tmpl.size() - 1] == '/') { // compatibility mode - folder only + string result = tmpl; + string masterId; + const bool isPublic = (vars.find("is_public") != vars.end()); + try { + masterId = vars.at("master_id"); + } + catch (const exception&) {} + if (!isPublic) { + result += "armory_" + masterId + "_wallet.lmdb"; + } + else { + result += "armory_" + masterId + "_" + vars.at("is_public") + ".lmdb"; + } + return result; + } + string str = tmpl; + size_t itStart = string::npos; + while ((itStart = str.find('<')) != string::npos) { + const auto itEnd = str.find('>', itStart); + if (itEnd == string::npos) { + break; + } + const auto& key = str.substr(itStart + 1, itEnd - itStart - 1); + string value; + try { + value = vars.at(key); + } + catch (const exception&) { + value = "_"; + } + str.replace(itStart, itEnd - itStart + 1, value); + } + return str; } //////////////////////////////////////////////////////////////////////////////// -shared_ptr AssetWallet_Single::createFromSeed_BIP32( - const string& folder, - const SecureBinaryData& seed, +shared_ptr AssetWallet_Single::createFromSeed( + const string& fileTmpl, + Seeds::ClearTextSeed_BIP32* seed, const SecureBinaryData& passphrase, const SecureBinaryData& controlPassphrase, unsigned lookup) { - if (seed.empty()) - throw WalletException("[createFromSeed_BIP32] empty seed"); - - BIP32_Node rootNode; - rootNode.initFromSeed(seed); - + if (seed == nullptr) + throw WalletException("[createFromSeed] null seed"); + auto rootNode = seed->getRootNode(); auto coinType = Armory::Config::BitcoinSettings::getCoinType(); //address accounts @@ -1313,7 +1344,7 @@ shared_ptr AssetWallet_Single::createFromSeed_BIP32( //legacy account: 44 vector path = { 0x8000002C, coinType, 0x80000000 }; auto legacyAcc = AccountType_BIP32::makeFromDerPaths( - rootNode.getThisFingerprint(), {path}); + rootNode->getThisFingerprint(), {path}); //nodes legacyAcc->setNodes({ @@ -1341,7 +1372,7 @@ shared_ptr AssetWallet_Single::createFromSeed_BIP32( //nested sw account: 49 vector path = { 0x80000031, coinType, 0x80000000 }; auto nestedAcc = AccountType_BIP32::makeFromDerPaths( - rootNode.getThisFingerprint(), {path}); + rootNode->getThisFingerprint(), {path}); //nodes nestedAcc->setNodes({ @@ -1368,7 +1399,7 @@ shared_ptr AssetWallet_Single::createFromSeed_BIP32( //sw account: 84 vector path = { 0x80000054, coinType, 0x80000000 }; auto segwitAcc = AccountType_BIP32::makeFromDerPaths( - rootNode.getThisFingerprint(), {path}); + rootNode->getThisFingerprint(), {path}); //nodes segwitAcc->setNodes({ @@ -1389,146 +1420,92 @@ shared_ptr AssetWallet_Single::createFromSeed_BIP32( accountTypes.insert(segwitAcc); } + //create wallet file and dbenv + if (rootNode->isPublic()) + { + throw WalletException("[createFromSeed]" + " BIP32 seeds cannot lead to WO wallets"); + } - auto walletPtr = createFromBIP32Node( - rootNode, - accountTypes, - passphrase, - controlPassphrase, - folder); - - //save the seed - walletPtr->setSeed(seed, passphrase); - - return walletPtr; -} - -//////////////////////////////////////////////////////////////////////////////// -shared_ptr AssetWallet_Single::createFromSeed_BIP32_Blank( - const string& fileTmpl, - const SecureBinaryData& seed, - const SecureBinaryData& passphrase, - const SecureBinaryData& controlPassphrase) -{ - BIP32_Node rootNode; - if (seed.getSize() == 0) - throw WalletException("empty seed"); - rootNode.initFromSeed(seed); - - //address accounts - set> accountTypes; + auto controlPassLbd = + [&controlPassphrase](const set&)->SecureBinaryData + { + return controlPassphrase; + }; - /* - no accounts are setup for a blank wallet - */ + //db env + auto masterId = seed->getMasterId(); + auto walletId = seed->getWalletId(); + //string path = folder + "/armory_" + masterId + "_wallet.lmdb"; + const unordered_map tmplVars{ {"master_id", masterId}, {"wallet_id", walletId} }; + const auto& walletPathName = substFileTemplate(fileTmpl, tmplVars); + if (walletPathName.empty()) { + throw runtime_error("invalid wallet pathname"); + } + auto iface = getIfaceFromFile(walletPathName, false, controlPassLbd); - auto walletPtr = createFromBIP32Node( - rootNode, - accountTypes, - passphrase, - controlPassphrase, - fileTmpl); + //wallet object + auto walletPtr = initWalletDb(iface, + masterId, walletId, + passphrase, controlPassphrase, + rootNode->getPrivateKey(), + rootNode->getChaincode(), + rootNode->getThisFingerprint()); - //save the seed - walletPtr->setSeed(seed, passphrase); + //set as main + setMainWallet(iface, walletId); - return walletPtr; -} + //add accounts + auto passLbd =[&passphrase]( + const set&)->SecureBinaryData + { + return passphrase; + }; + walletPtr->setPassphrasePromptLambda(passLbd); -/* substitutes variables from vars into tmpl with syntax "" -> "var_value" -* Available var names: -* * master_id -* * wallet_id -* * is_public = WatchingOnly if this flag is set -*/ -static string substFileTemplate(const string& tmpl - , const unordered_map& vars) -{ - if (tmpl.empty()) { - return {}; - } - if (tmpl[tmpl.size() - 1] == '/') { // compatibility mode - folder only - string result = tmpl; - string masterId; - const bool isPublic = (vars.find("is_public") != vars.end()); - try { - masterId = vars.at("master_id"); - } - catch (const exception&) {} - if (!isPublic) { - result += "armory_" + masterId + "_wallet.lmdb"; - } else { - result += "armory_" + masterId + "_" + vars.at("is_public") + ".lmdb"; - } - return result; - } - string str = tmpl; - size_t itStart = string::npos; - while ((itStart = str.find('<')) != string::npos) { - const auto itEnd = str.find('>', itStart); - if (itEnd == string::npos) { + switch (seed->type()) + { + case SeedType::BIP32_Structured: + case SeedType::BIP39: + { + for (auto accountPtr : accountTypes) + walletPtr->createBIP32Account(accountPtr); break; } - const auto& key = str.substr(itStart + 1, itEnd - itStart - 1); - string value; - try { - value = vars.at(key); - } - catch (const exception&) { - value = "_"; - } - str.replace(itStart, itEnd - itStart + 1, value); + + default: + //no accounts structure for these seeds + break; } - return str; + + walletPtr->resetPassphrasePromptLambda(); + return walletPtr; } //////////////////////////////////////////////////////////////////////////////// -shared_ptr AssetWallet_Single::createFromBIP32Node( - const BIP32_Node& node, - set> accountTypes, - const SecureBinaryData& passphrase, +shared_ptr + AssetWallet_Single::createFromPublicRoot_Armory135( + const string& fileTmpl, + SecureBinaryData& pubRoot, + SecureBinaryData& chainCode, const SecureBinaryData& controlPassphrase, - const string& fileTmpl) + unsigned lookup) { - bool isPublic = false; - if (node.isPublic()) - isPublic = true; - - //compute wallet ID - auto pubkey = node.getPublicKey(); - - //compute master ID as hmac256(root pubkey, "MetaEntry") - auto hmacMasterMsg = SecureBinaryData::fromString("MetaEntry"); - auto&& masterID_long = BtcUtils::getHMAC256(pubkey, hmacMasterMsg); - auto&& masterID = BtcUtils::computeID(masterID_long); + auto masterID = generateMasterId(pubRoot, chainCode); /* Create control passphrase lambda. It gets wiped after the wallet is setup */ - auto controlPassLbd = + auto controlPassLbd = [&controlPassphrase](const set&)->SecureBinaryData { return controlPassphrase; }; unordered_map tmplVars{ {"master_id", masterID} }; - if (isPublic) { - tmplVars["is_public"] = "WatchingOnly"; - } - string walletID; - { - //walletID - auto chaincode_copy = node.getChaincode(); - auto derScheme = - make_shared(chaincode_copy); - - auto asset_single = make_shared( - AssetId::getRootAssetId(), - pubkey, nullptr); - - walletID = move(computeWalletID(derScheme, asset_single)); - tmplVars["wallet_id"] = walletID; - } + tmplVars["is_public"] = "WatchingOnly"; + const auto walletID = generateWalletId(pubRoot, chainCode, SeedType::Armory135); + tmplVars["wallet_id"] = walletID; const auto& walletPathName = substFileTemplate(fileTmpl, tmplVars); if (walletPathName.empty()) { @@ -1536,41 +1513,26 @@ shared_ptr AssetWallet_Single::createFromBIP32Node( } //create wallet file and dbenv auto iface = getIfaceFromFile(walletPathName, false, controlPassLbd); + auto rootPtr = make_shared( + AssetId::getRootAssetId(), pubRoot, nullptr, chainCode); //create wallet - shared_ptr walletPtr = nullptr; - - if (!isPublic) - { - walletPtr = initWalletDb( - iface, - masterID, walletID, - passphrase, - controlPassphrase, - node.getPrivateKey(), - node.getChaincode(), - node.getThisFingerprint()); - } - else - { - throw runtime_error("invalid for bip32 wallets"); - } + auto walletPtr = initWalletDbWithPubRoot( + iface, + controlPassphrase, + masterID, walletID, + rootPtr); //set as main setMainWallet(iface, walletID); - //add accounts - auto passLbd = - [&passphrase](const set&)->SecureBinaryData - { - return passphrase; - }; - walletPtr->setPassphrasePromptLambda(passLbd); + //add account + auto account135 = make_shared(); + account135->setMain(true); - for (auto accountPtr : accountTypes) - walletPtr->createBIP32Account(accountPtr); + auto accountPtr = walletPtr->createAccount(account135); + accountPtr->extendPublicChain(iface, lookup - 1); - walletPtr->resetPassphrasePromptLambda(); return walletPtr; } @@ -1584,7 +1546,7 @@ shared_ptr AssetWallet_Single::createBlank( /* Create control passphrase lambda. It gets wiped after the wallet is setup */ - auto controlPassLbd = + auto controlPassLbd = [&controlPassphrase](const set&)->SecureBinaryData { return controlPassphrase; @@ -1610,22 +1572,6 @@ shared_ptr AssetWallet_Single::createBlank( return walletPtr; } -//////////////////////////////////////////////////////////////////////////////// -string AssetWallet_Single::computeWalletID( - shared_ptr derScheme, - shared_ptr rootEntry) -{ - auto&& addrVec = derScheme->extendPublicChain(rootEntry, 1, 1, nullptr); - if (addrVec.size() != 1) - throw WalletException("unexpected chain derivation output"); - - auto firstEntry = dynamic_pointer_cast(addrVec[0]); - if (firstEntry == nullptr) - throw WalletException("unexpected asset entry type"); - - return BtcUtils::computeID(firstEntry->getPubKey()->getUncompressedKey()); -} - //////////////////////////////////////////////////////////////////////////////// shared_ptr AssetWallet_Single::initWalletDb( shared_ptr iface, @@ -1781,7 +1727,7 @@ shared_ptr AssetWallet_Single::initWalletDbWithPubRoot( return walletPtr; } -//////////////////////////////////////////////////////////////////////////////// +//////////////// -- decrypt private key methods -- ///////////////////////////// const SecureBinaryData& AssetWallet_Single::getDecryptedValue( shared_ptr assetPtr) { @@ -1789,7 +1735,7 @@ const SecureBinaryData& AssetWallet_Single::getDecryptedValue( return decryptedData_->getClearTextAssetData(assetPtr); } -//////////////////////////////////////////////////////////////////////////////// +//////// const SecureBinaryData& AssetWallet_Single::getDecryptedPrivateKeyForAsset( std::shared_ptr assetPtr) { @@ -1801,10 +1747,23 @@ const SecureBinaryData& AssetWallet_Single::getDecryptedPrivateKeyForAsset( assetPrivKey = account->fillPrivateKey(iface_, decryptedData_, assetPtr->getID()); } - + return getDecryptedValue(assetPrivKey); } +//////// +const SecureBinaryData& AssetWallet_Single::getDecryptedPrivateKeyForId( + const AssetId& id) const +{ + return decryptedData_->getClearTextAssetData(id); +} + +//////// +std::shared_ptr AssetWallet_Single::getEncryptedSeed() const +{ + return seed_; +} + //////////////////////////////////////////////////////////////////////////////// const AssetId& AssetWallet_Single::derivePrivKeyFromPath( const BIP32_AssetPath& path) @@ -1841,13 +1800,6 @@ const AssetId& AssetWallet_Single::derivePrivKeyFromPath( hdNode.private_key, BTC_ECKEY_PKEY_LENGTH); } -//////////////////////////////////////////////////////////////////////////////// -const SecureBinaryData& AssetWallet_Single::getDecrypedPrivateKeyForId( - const AssetId& id) const -{ - return decryptedData_->getClearTextAssetData(id); -} - //////////////////////////////////////////////////////////////////////////////// void AssetWallet_Single::changePrivateKeyPassphrase( const std::function& newPassLbd) @@ -1912,8 +1864,8 @@ const SecureBinaryData& AssetWallet_Single::getArmory135Chaincode() const } //////////////////////////////////////////////////////////////////////////////// -void AssetWallet_Single::importPublicData( - const WalletPublicData& wpd, std::shared_ptr iface) +void AssetWallet_Single::importPublicData(const WalletPublicData& wpd, + std::shared_ptr iface) { //TODO: merging from exported data @@ -2099,7 +2051,7 @@ void AssetWallet_Single::importPublicData( "Failed to resolve address account type"); } - //address account main flag + //flag main account if (accData.ID_ == wpd.mainAccountID_) accTypePtr->setMain(true); @@ -2184,19 +2136,15 @@ WalletPublicData AssetWallet_Single::exportPublicData( //////////////////////////////////////////////////////////////////////////////// -void AssetWallet_Single::setSeed( - const SecureBinaryData& seed, +void AssetWallet_Single::setSeed(unique_ptr seedPtr, const SecureBinaryData& passphrase) { //copy root node cipher - auto rootPtr = dynamic_pointer_cast(root_); - if (rootPtr == nullptr) - throw WalletException("expected BIP32 root object"); - auto cipherCopy = - rootPtr->getPrivKey()->getCipherDataPtr()->cipher_->getCopy(); + auto cipherCopy = + root_->getPrivKey()->getCipherDataPtr()->cipher_->getCopy(); //if custom passphrase, set prompt lambda prior to encryption - if (passphrase.getSize() > 0) + if (!passphrase.empty()) { auto passphraseLambda = [&passphrase](const set&)->SecureBinaryData @@ -2210,11 +2158,8 @@ void AssetWallet_Single::setSeed( //create encrypted seed object { auto lock = lockDecryptedContainer(); - - auto cipherText = decryptedData_->encryptData(cipherCopy.get(), seed); - auto cipherData = make_unique( - cipherText, move(cipherCopy)); - seed_ = make_shared(move(cipherData)); + seed_ = EncryptedSeed::fromClearTextSeed(std::move(seedPtr), + std::move(cipherCopy), decryptedData_); } //write to disk diff --git a/cppForSwig/Wallets/Wallets.h b/cppForSwig/Wallets/Wallets.h index 5a4f2e28d..fd119d8ee 100644 --- a/cppForSwig/Wallets/Wallets.h +++ b/cppForSwig/Wallets/Wallets.h @@ -38,7 +38,15 @@ namespace Armory namespace Signer { class BIP32_AssetPath; - }; + } + + namespace Seeds + { + class EncryptedSeed; + class ClearTextSeed; + class ClearTextSeed_Armory135; + class ClearTextSeed_BIP32; + } namespace Wallets { @@ -211,6 +219,9 @@ namespace Armory void deleteComment(const BinaryData&); const AddressAccountId& getMainAccountID(void) const; + const EncryptionKeyId& getDefaultEncryptionKeyId(void) const; + std::shared_ptr + getDefaultKdf(void) const; void setLabel(const std::string&); void setDescription(const std::string&); @@ -248,7 +259,7 @@ namespace Armory protected: std::shared_ptr root_ = nullptr; - std::shared_ptr seed_ = nullptr; + std::shared_ptr seed_ = nullptr; protected: //virtual @@ -276,7 +287,23 @@ namespace Armory static void importPublicData(const WalletPublicData&, std::shared_ptr); - void setSeed(const SecureBinaryData&, const SecureBinaryData&); + void setSeed(std::unique_ptr, + const SecureBinaryData&); + + //wallet creation private statics + static std::shared_ptr createFromSeed( + const std::string&, //folder + Seeds::ClearTextSeed_Armory135*, + const SecureBinaryData&, //pass + const SecureBinaryData&, //control pass + unsigned); //lookup + + static std::shared_ptr createFromSeed( + const std::string&, //folder + Seeds::ClearTextSeed_BIP32*, + const SecureBinaryData&, //pass + const SecureBinaryData&, //control pass + unsigned); //lookup public: //tors @@ -305,11 +332,10 @@ namespace Armory std::shared_ptr); const AssetId& derivePrivKeyFromPath( const Signer::BIP32_AssetPath&); - const SecureBinaryData& getDecrypedPrivateKeyForId( + const SecureBinaryData& getDecryptedPrivateKeyForId( const AssetId&) const; - std::shared_ptr getEncryptedSeed(void) const - { return seed_; } + std::shared_ptr getEncryptedSeed(void) const; Signer::BIP32_AssetPath getBip32PathForAsset( std::shared_ptr) const; @@ -325,21 +351,11 @@ namespace Armory std::shared_ptr); //static - static std::shared_ptr createFromBIP32Node( - const BIP32_Node& node, - std::set> accountTypes, - const SecureBinaryData& passphrase, - const SecureBinaryData& controlPassphrase, - const std::string& folder); - - static std::shared_ptr - createFromPrivateRoot_Armory135( - const std::string& folder, - const SecureBinaryData& privateRoot, - SecureBinaryData chaincode, - const SecureBinaryData& passphrase, - const SecureBinaryData& controlPassphrase, - unsigned lookup); + static std::shared_ptr createFromSeed( + std::unique_ptr, + const SecureBinaryData&, + const SecureBinaryData&, + const std::string&, unsigned lookup = 1000); static std::shared_ptr createFromPublicRoot_Armory135( @@ -349,28 +365,10 @@ namespace Armory const SecureBinaryData& controlPassphrase, unsigned lookup); - static std::shared_ptr createFromSeed_BIP32( - const std::string& folder, - const SecureBinaryData& seed, - const SecureBinaryData& passphrase, - const SecureBinaryData& controlPassphrase, - unsigned lookup); - - static std::shared_ptr - createFromSeed_BIP32_Blank( - const std::string& folder, - const SecureBinaryData& seed, - const SecureBinaryData& passphrase, - const SecureBinaryData& controlPassphrase); - static std::shared_ptr createBlank( const std::string& folder, const std::string& walletID, const SecureBinaryData& controlPassphrase); - - static std::string computeWalletID( - std::shared_ptr, - std::shared_ptr); }; ////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/WebSocketClient.cpp b/cppForSwig/WebSocketClient.cpp index 8df1b8af6..a1c51f1b5 100644 --- a/cppForSwig/WebSocketClient.cpp +++ b/cppForSwig/WebSocketClient.cpp @@ -302,6 +302,7 @@ void WebSocketClient::cleanUp() readPackets_.clear(); //create error message to send to all outsanding read callbacks +#ifdef BUILD_PROTOBUF ::Codec_BDVCommand::BDV_Error errMsg; errMsg.set_code(-1); errMsg.set_errstr("LWS client disconnected"); @@ -350,7 +351,7 @@ void WebSocketClient::cleanUp() if (thr.joinable()) thr.join(); } - +#endif LOGINFO << "lws client cleaned up"; } @@ -557,7 +558,7 @@ void WebSocketClient::readService() currentReadMessage_.reset(); continue; } - +#ifdef BUILD_PROTOBUF auto msgptr = make_shared<::Codec_BDVCommand::BDVCallback>(); if (!currentReadMessage_.message_.getMessage(msgptr.get())) { @@ -566,8 +567,8 @@ void WebSocketClient::readService() } callbackPtr_->processNotifications(msgptr); +#endif currentReadMessage_.reset(); - break; } diff --git a/cppForSwig/WebSocketMessage.cpp b/cppForSwig/WebSocketMessage.cpp index 76795714c..754db18c8 100644 --- a/cppForSwig/WebSocketMessage.cpp +++ b/cppForSwig/WebSocketMessage.cpp @@ -9,11 +9,15 @@ #include "BtcUtils.h" #include "WebSocketMessage.h" #include "libwebsockets.h" +#ifdef BUILD_PROTOBUF #include +#endif #include "BIP15x_Handshake.h" using namespace std; +#ifdef BUILD_PROTOBUF using namespace ::google::protobuf::io; +#endif //////////////////////////////////////////////////////////////////////////////// // @@ -249,6 +253,7 @@ vector WebSocketMessageCodec::serialize( } //////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF bool WebSocketMessageCodec::reconstructFragmentedMessage( const map& payloadMap, ::google::protobuf::Message* msg) @@ -293,6 +298,7 @@ bool WebSocketMessageCodec::reconstructFragmentedMessage( return result; } +#endif //////////////////////////////////////////////////////////////////////////////// uint32_t WebSocketMessageCodec::getMessageId(const BinaryDataRef& packet) @@ -509,6 +515,7 @@ bool WebSocketMessagePartial::parseMessageWithoutId(const BinaryDataRef& bdr) } /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF bool WebSocketMessagePartial::getMessage( ::google::protobuf::Message* msgPtr) const { @@ -525,6 +532,7 @@ bool WebSocketMessagePartial::getMessage( return WebSocketMessageCodec::reconstructFragmentedMessage(packets_, msgPtr); } } +#endif /////////////////////////////////////////////////////////////////////////////// bool WebSocketMessagePartial::isReady() const diff --git a/cppForSwig/WebSocketMessage.h b/cppForSwig/WebSocketMessage.h index d798b3a8d..b0a238d73 100644 --- a/cppForSwig/WebSocketMessage.h +++ b/cppForSwig/WebSocketMessage.h @@ -14,7 +14,9 @@ #include #include "BinaryData.h" +#ifdef BUILD_PROTOBUF #include +#endif #include "SocketObject.h" #include "BIP150_151.h" @@ -56,10 +58,11 @@ class WebSocketMessageCodec ArmoryAEAD::BIP151_PayloadType); static uint32_t getMessageId(const BinaryDataRef&); - +#ifdef BUILD_PROTOBUF static bool reconstructFragmentedMessage( const std::map&, ::google::protobuf::Message*); +#endif }; /////////////////////////////////////////////////////////////////////////////// @@ -106,7 +109,9 @@ class WebSocketMessagePartial void reset(void); bool parsePacket(const BinaryDataRef&); bool isReady(void) const; +#ifdef BUILD_PROTOBUF bool getMessage(::google::protobuf::Message*) const; +#endif BinaryDataRef getSingleBinaryMessage(void) const; const uint32_t& getId(void) const { return id_; } ArmoryAEAD::BIP151_PayloadType getType(void) const { return type_; } diff --git a/cppForSwig/ZeroConf.cpp b/cppForSwig/ZeroConf.cpp index c1a5ba561..2fabe6f24 100644 --- a/cppForSwig/ZeroConf.cpp +++ b/cppForSwig/ZeroConf.cpp @@ -12,7 +12,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "ZeroConf.h" -#include "BlockDataMap.h" +#include "BlockchainDatabase/BlockDataMap.h" #include "ArmoryErrors.h" using namespace std; @@ -162,7 +162,7 @@ map> ZeroConfContainer::purgeToBranchpoint( auto block = BlockData::deserialize( rawBlock.getPtr(), rawBlock.getSize(), currentHeader, nullptr, - false, false); + BlockData::CheckHashes::NoChecks); const auto& txns = block->getTxns(); for (unsigned txid = 0; txid < txns.size(); txid++) @@ -268,7 +268,7 @@ map> ZeroConfContainer::purge( auto block = BlockData::deserialize( rawBlock.getPtr(), rawBlock.getSize(), currentHeader, nullptr, - false, false); + BlockData::CheckHashes::NoChecks); const auto& txns = block->getTxns(); //gather all outpoints spent by this block diff --git a/cppForSwig/ZeroConf.h b/cppForSwig/ZeroConf.h index dfb8ad217..00bc428b9 100644 --- a/cppForSwig/ZeroConf.h +++ b/cppForSwig/ZeroConf.h @@ -21,9 +21,9 @@ #include "ThreadSafeClasses.h" #include "BitcoinP2p.h" -#include "lmdb_wrapper.h" -#include "Blockchain.h" -#include "ScrAddrFilter.h" +#include "BlockchainDatabase/lmdb_wrapper.h" +#include "BlockchainDatabase/Blockchain.h" +#include "BlockchainDatabase/ScrAddrFilter.h" #include "ArmoryErrors.h" #include "ZeroConfUtils.h" #include "ZeroConfNotifications.h" diff --git a/cppForSwig/ZeroConfNotifications.cpp b/cppForSwig/ZeroConfNotifications.cpp index 10898718c..093a12615 100644 --- a/cppForSwig/ZeroConfNotifications.cpp +++ b/cppForSwig/ZeroConfNotifications.cpp @@ -13,10 +13,12 @@ #include "ZeroConf.h" #include "BDM_Server.h" #include "LedgerEntry.h" -#include "txio.h" +#include "BlockchainDatabase/txio.h" using namespace std; +#ifdef BUILD_PROTOBUF using namespace ::Codec_BDVCommand; +#endif /////////////////////////////////////////////////////////////////////////////// // @@ -258,6 +260,7 @@ ZeroConfCallbacks_BDV::ZcNotifRequest::~ZcNotifRequest() // ZcNotificationPacket // /////////////////////////////////////////////////////////////////////////////// +#ifdef BUILD_PROTOBUF void ZcNotificationPacket::toProtobufNotification( std::shared_ptr<::Codec_BDVCommand::BDVCallback> protoPtr, const std::vector& leVec) const @@ -317,4 +320,5 @@ void ZcNotificationPacket::toProtobufNotification( idPtr->set_data(id.second.getPtr(), id.second.getSize()); } } -} \ No newline at end of file +} +#endif diff --git a/cppForSwig/ZeroConfNotifications.h b/cppForSwig/ZeroConfNotifications.h index 166689600..523365a14 100644 --- a/cppForSwig/ZeroConfNotifications.h +++ b/cppForSwig/ZeroConfNotifications.h @@ -212,10 +212,11 @@ struct ZcNotificationPacket ZcNotificationPacket(const std::string& bdvID) : bdvID_(bdvID) {} - +#ifdef BUILD_PROTOBUF void toProtobufNotification( std::shared_ptr<::Codec_BDVCommand::BDVCallback>, const std::vector&) const; +#endif }; //////////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/ZeroConfUtils.cpp b/cppForSwig/ZeroConfUtils.cpp index 23ef3277c..de391dc4e 100644 --- a/cppForSwig/ZeroConfUtils.cpp +++ b/cppForSwig/ZeroConfUtils.cpp @@ -8,8 +8,8 @@ #include "ZeroConfUtils.h" #include "ZeroConfNotifications.h" -#include "ScrAddrFilter.h" -#include "lmdb_wrapper.h" +#include "BlockchainDatabase/ScrAddrFilter.h" +#include "BlockchainDatabase/lmdb_wrapper.h" using namespace std; using namespace Armory::Config; diff --git a/cppForSwig/ZeroConfUtils.h b/cppForSwig/ZeroConfUtils.h index 61525b57a..8c04aa3cc 100644 --- a/cppForSwig/ZeroConfUtils.h +++ b/cppForSwig/ZeroConfUtils.h @@ -12,7 +12,7 @@ #include #include #include "BinaryData.h" -#include "txio.h" +#include "BlockchainDatabase/txio.h" class LMDBBlockDatabase; diff --git a/cppForSwig/chacha20poly1305/Makefile.am b/cppForSwig/chacha20poly1305/Makefile.am index 6b81633d8..af66d209a 100644 --- a/cppForSwig/chacha20poly1305/Makefile.am +++ b/cppForSwig/chacha20poly1305/Makefile.am @@ -10,7 +10,6 @@ CHACHA20POLY1305_SOURCE_FILES = poly1305.c chacha.c chachapoly_aead.c libchacha20poly1305_la_SOURCES = $(CHACHA20POLY1305_SOURCE_FILES) libchacha20poly1305_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) -fPIC libchacha20poly1305_la_CFLAGS = $(AM_CFLAGS) -libchacha20poly1305_la_LIBADD = $(LIBCHACHAPOLY1305) libchacha20poly1305_la_LDFLAGS = $(LDFLAGS) -static if BUILD_TESTS @@ -19,7 +18,6 @@ TESTS += chacha20poly1305tests chacha20poly1305tests_SOURCES = $(CHACHA20POLY1305_SOURCE_FILES) tests.c chacha20poly1305tests_CFLAGS = $(AM_CFLAGS) chacha20poly1305tests_CPPFLAGS = $(AM_CPPFLAGS) -fPIC -chacha20poly1305tests_LDADD = $(LIBCHACHA20POLY1305) chacha20poly1305tests_LDFLAGS = $(LDFLAGS) -static endif @@ -29,6 +27,5 @@ BENCH += chacha20poly1305bench chacha20poly1305bench_SOURCES = $(CHACHA20POLY1305_SOURCE_FILES) bench.c chacha20poly1305bench_CFLAGS = $(AM_CFLAGS) chacha20poly1305bench_CPPFLAGS = $(AM_CPPFLAGS) -fPIC -chacha20poly1305bench_LDADD = $(LIBCHACHA20POLY1305) chacha20poly1305bench_LDFLAGS = $(LDFLAGS) -static endif diff --git a/cppForSwig/gtest/NodeUnitTest.cpp b/cppForSwig/gtest/NodeUnitTest.cpp index 4d5d412f3..2bfb06fbb 100644 --- a/cppForSwig/gtest/NodeUnitTest.cpp +++ b/cppForSwig/gtest/NodeUnitTest.cpp @@ -7,7 +7,6 @@ //////////////////////////////////////////////////////////////////////////////// #include "NodeUnitTest.h" -#include "../BlockUtils.h" #include "../Signer/Signer.h" using namespace std; diff --git a/cppForSwig/gtest/NodeUnitTest.h b/cppForSwig/gtest/NodeUnitTest.h index 77c70fd5c..d39c124aa 100644 --- a/cppForSwig/gtest/NodeUnitTest.h +++ b/cppForSwig/gtest/NodeUnitTest.h @@ -16,11 +16,11 @@ #include "../BinaryData.h" #include "../BtcUtils.h" -#include "../BlockUtils.h" +#include "../BlockchainDatabase/BlockUtils.h" #include "../BitcoinP2p.h" -#include "../Blockchain.h" +#include "../BlockchainDatabase/Blockchain.h" #include "../Signer/ScriptRecipient.h" -#include "../BlockDataMap.h" +#include "../BlockchainDatabase/BlockDataMap.h" #include "../nodeRPC.h" //////////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/gtest/SignerTests.cpp b/cppForSwig/gtest/SignerTests.cpp index e1000e267..caa14db01 100644 --- a/cppForSwig/gtest/SignerTests.cpp +++ b/cppForSwig/gtest/SignerTests.cpp @@ -9,6 +9,7 @@ #include "TestUtils.h" #include "CoinSelection.h" +#include "../Wallets/Seeds/Seeds.h" using namespace std; using namespace Armory::Signer; @@ -388,14 +389,13 @@ TEST_F(SignerTest, SpendTest_SizeEstimates) //// create assetWlt //// - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), + {}, {}, homedir_, - move(wltRoot), //root as a r value - {}, - SecureBinaryData(), - SecureBinaryData(), - 5); //set lookup computation to 5 entries + 5); //register with db vector addrVec; @@ -790,13 +790,11 @@ TEST_F(SignerTest, SpendTest_P2WPKH) //// create assetWlt //// - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - move(wltRoot), //root as a rvalue - SecureBinaryData(), - SecureBinaryData(), - 5); //set lookup computation to 5 entries + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt = AssetWallet_Single::createFromSeed(move(seed), + {}, {}, homedir_, 5); //register with db vector> addrVec; @@ -1039,16 +1037,16 @@ TEST_F(SignerTest, SpendTest_MixedInputTypes) //// create assetWlt //// - auto&& wltRoot = CryptoPRNG::generateRandom(32); + auto rawEntropy = CryptoPRNG::generateRandom(32); BIP32_Node node; - node.initFromSeed(wltRoot); + node.initFromSeed(rawEntropy); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135(rawEntropy)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), + {}, {}, homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), 5); //set lookup computation to 3 entries //add a bip32 account @@ -1304,33 +1302,23 @@ TEST_F(SignerTest, SpendTest_MultipleSigners_1of3) scrAddrVec.push_back(TestChain::scrAddrE); //// create 3 assetWlt //// - - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt_1 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), - 3); //set lookup computation to 3 entries - - wltRoot = move(CryptoPRNG::generateRandom(32)); - auto assetWlt_2 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), - 3); //set lookup computation to 3 entries - - wltRoot = move(CryptoPRNG::generateRandom(32)); - auto assetWlt_3 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), - 3); //set lookup computation to 3 entries + unique_ptr seed1( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_1 = AssetWallet_Single::createFromSeed( + move(seed1), {}, {}, homedir_, 3); + + unique_ptr seed2( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_2 = AssetWallet_Single::createFromSeed( + move(seed2), {}, {}, homedir_, 3); + + unique_ptr seed3( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_3 = AssetWallet_Single::createFromSeed( + move(seed3), {}, {}, homedir_, 3); //create 1-of-3 multisig asset entry from 3 different wallets map> asset_single_map; @@ -1598,33 +1586,23 @@ TEST_F(SignerTest, SpendTest_MultipleSigners_2of3_NativeP2WSH) scrAddrVec.push_back(TestChain::scrAddrE); //// create 3 assetWlt //// - - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt_1 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), - 3); //set lookup computation to 3 entries - - wltRoot = move(CryptoPRNG::generateRandom(32)); - auto assetWlt_2 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), - 3); //set lookup computation to 3 entries - - wltRoot = move(CryptoPRNG::generateRandom(32)); - auto assetWlt_3 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), - 3); //set lookup computation to 3 entries + unique_ptr seed1( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_1 = AssetWallet_Single::createFromSeed( + move(seed1), {}, {}, homedir_, 3); + + unique_ptr seed2( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_2 = AssetWallet_Single::createFromSeed( + move(seed2), {}, {}, homedir_, 3); + + unique_ptr seed3( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_3 = AssetWallet_Single::createFromSeed( + move(seed3), {}, {}, homedir_, 3); //create 2-of-3 multisig asset entry from 3 different wallets map> asset_single_map; @@ -1992,22 +1970,15 @@ TEST_F(SignerTest, SpendTest_MultipleSigners_DifferentInputs) scrAddrVec.push_back(TestChain::scrAddrE); //// create 2 assetWlt //// + unique_ptr seed1( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_1 = AssetWallet_Single::createFromSeed( + move(seed1), {}, {}, homedir_, 3); - auto assetWlt_1 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - CryptoPRNG::generateRandom(32), //root as rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), - 3); //set lookup computation to 3 entries - - auto assetWlt_2 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(CryptoPRNG::generateRandom(32)), //root as rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), - 3); //set lookup computation to 3 entries + unique_ptr seed2( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_2 = AssetWallet_Single::createFromSeed( + move(seed2), {}, {}, homedir_, 3); //register with db vector> addrVec_1; @@ -2289,22 +2260,15 @@ TEST_F(SignerTest, SpendTest_MultipleSigners_ParallelSigning) scrAddrVec.push_back(TestChain::scrAddrE); //// create 2 assetWlt //// + unique_ptr seed1( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_1 = AssetWallet_Single::createFromSeed( + move(seed1), {}, {}, homedir_, 3); - auto assetWlt_1 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - CryptoPRNG::generateRandom(32), //root as rvalue - {}, - SecureBinaryData(), //empty passphrase - SecureBinaryData(), - 3); //set lookup computation to 3 entries - - auto assetWlt_2 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(CryptoPRNG::generateRandom(32)), //root as rvalue - {}, - SecureBinaryData(), //empty passphrase - SecureBinaryData(), - 3); //set lookup computation to 3 entries + unique_ptr seed2( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_2 = AssetWallet_Single::createFromSeed( + move(seed2), {}, {}, homedir_, 3); //register with db vector> addrVec_1; @@ -2622,19 +2586,17 @@ TEST_F(SignerTest, SpendTest_MultipleSigners_ParallelSigning_GetUnsignedTx) scrAddrVec.push_back(TestChain::scrAddrE); //// create 2 assetWlt //// - auto assetWlt_1 = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - CryptoPRNG::generateRandom(32), //root as rvalue - SecureBinaryData(), //empty passphrase - SecureBinaryData(), - 3); //set lookup computation to 3 entries - - auto assetWlt_2 = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - move(CryptoPRNG::generateRandom(32)), //root as rvalue - SecureBinaryData(), //empty passphrase - SecureBinaryData(), - 3); //set lookup computation to 3 entries + unique_ptr seed1( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_1 = AssetWallet_Single::createFromSeed( + move(seed1), {}, {}, homedir_, 3); + + unique_ptr seed2( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_2 = AssetWallet_Single::createFromSeed( + move(seed2), {}, {}, homedir_, 3); //register with db vector> addrVec_1; @@ -2988,20 +2950,16 @@ TEST_F(SignerTest, SpendTest_MultipleSigners_ParallelSigning_GetUnsignedTx_Neste scrAddrVec.push_back(TestChain::scrAddrE); //// create 2 assetWlt //// - auto assetWlt_1 = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - CryptoPRNG::generateRandom(32), //root as rvalue - SecureBinaryData(), //empty passphrase - SecureBinaryData(), - 3); //set lookup computation to 3 entries + unique_ptr seed1( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_1 = AssetWallet_Single::createFromSeed( + move(seed1), {}, {}, homedir_, 3); - auto assetWlt_2 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(CryptoPRNG::generateRandom(32)), //root as rvalue - {}, - SecureBinaryData(), //empty passphrase - SecureBinaryData(), - 3); //set lookup computation to 3 entries + unique_ptr seed2( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_2 = AssetWallet_Single::createFromSeed( + move(seed2), {}, {}, homedir_, 3); //register with db auto addr_type_nested_p2sh = AddressEntryType(AddressEntryType_P2WPKH | AddressEntryType_P2SH); @@ -3395,6 +3353,7 @@ TEST_F(SignerTest, SpendTest_MultipleSigners_ParallelSigning_GetUnsignedTx_Neste //////////////////////////////////////////////////////////////////////////////// TEST_F(SignerTest, GetUnsignedTxId) { + auto locktime = 1946132849; TestUtils::setBlocks({ "0", "1", "2", "3" }, blk0dat_); initBDM(); @@ -3411,20 +3370,16 @@ TEST_F(SignerTest, GetUnsignedTxId) scrAddrVec.push_back(TestChain::scrAddrE); //// create 2 assetWlt //// - auto assetWlt_1 = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - CryptoPRNG::generateRandom(32), //root as rvalue - SecureBinaryData(), //empty passphrase - SecureBinaryData(), - 3); //set lookup computation to 3 entries + unique_ptr seed1( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt_1 = AssetWallet_Single::createFromSeed( + move(seed1), {}, {}, homedir_, 3); - auto assetWlt_2 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(CryptoPRNG::generateRandom(32)), //root as rvalue - {}, - SecureBinaryData(), //empty passphrase - SecureBinaryData(), - 3); //set lookup computation to 3 entries + unique_ptr seed2( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_2 = AssetWallet_Single::createFromSeed( + move(seed2), {}, {}, homedir_, 3); //register with db vector> addrVec_1; @@ -3540,9 +3495,23 @@ TEST_F(SignerTest, GetUnsignedTxId) signer.getTxId(); EXPECT_TRUE(false); } - catch (exception&) + catch (const exception&) {} + try + { + //set a lock time, check it's encoded correctly + signer.setLockTime(locktime); + auto unsignedTx = signer.serializeUnsignedTx(); + + Tx tx(unsignedTx); + EXPECT_EQ(tx.getLockTime(), locktime); + } + catch (const exception&) + { + EXPECT_TRUE(false); + } + //sign, verify then broadcast signer.sign(); EXPECT_TRUE(signer.verify()); @@ -3610,6 +3579,14 @@ TEST_F(SignerTest, GetUnsignedTxId) signer2.addRecipient(addrVec_1[1]->getRecipient(total - spendVal)); } + //locktime deser test + { + signer2.setLockTime(++locktime); + auto unsignedTx = signer2.serializeUnsignedTx(true); + + Tx tx(unsignedTx); + EXPECT_EQ(tx.getLockTime(), locktime); + } serializedSignerState = move(signer2.serializeState()); } @@ -3636,6 +3613,13 @@ TEST_F(SignerTest, GetUnsignedTxId) signer3.addRecipient(addrVec_2[1]->getRecipient(total - spendVal)); } + //locktime deser test + { + auto unsignedTx = signer3.serializeUnsignedTx(true); + + Tx tx(unsignedTx); + EXPECT_EQ(tx.getLockTime(), locktime); + } serializedSignerState = move(signer3.serializeState()); } @@ -3649,6 +3633,11 @@ TEST_F(SignerTest, GetUnsignedTxId) signer4.setFeed(assetFeed2); { + auto unsignedTx = signer4.serializeUnsignedTx(true); + + Tx tx(unsignedTx); + EXPECT_EQ(tx.getLockTime(), locktime); + auto lock = assetWlt_1->lockDecryptedContainer(); signer4.sign(); } @@ -3714,6 +3703,11 @@ TEST_F(SignerTest, GetUnsignedTxId) BinaryData txid; try { + auto unsignedTx = signer5.serializeUnsignedTx(); + + Tx tx(unsignedTx); + EXPECT_EQ(tx.getLockTime(), locktime); + txid = signer5.getTxId(); } catch (...) @@ -3756,12 +3750,11 @@ TEST_F(SignerTest, Wallet_SpendTest_Nested_P2WPKH) //// create assetWlt //// //create empty bip32 wallet - auto&& wltSeed = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, - wltSeed, - SecureBinaryData(), - SecureBinaryData()); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Virgin)); + auto assetWlt = AssetWallet_Single::createFromSeed(move(seed), + {}, {}, homedir_); //add p2sh-p2wpkh account vector derPath = { 0x800061a5, 0x80000000 }; @@ -4013,17 +4006,17 @@ TEST_F(SignerTest, Wallet_SpendTest_Nested_P2WPKH_WOResolution_fromWOCopy) //// create assetWlt //// - auto&& wltSeed = CryptoPRNG::generateRandom(32); + auto rawEntropy = CryptoPRNG::generateRandom(32); string woPath, wltPath; Signer signer3; { //create bip32 wallet - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, - wltSeed, - SecureBinaryData(), - SecureBinaryData()); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Virgin)); + auto assetWlt = AssetWallet_Single::createFromSeed(move(seed), + {}, {}, homedir_); //add p2sh-p2wpkh account vector derPath = { 0x800061a5, 0x80000000 }; @@ -4052,11 +4045,11 @@ TEST_F(SignerTest, Wallet_SpendTest_Nested_P2WPKH_WOResolution_fromWOCopy) AssetWallet::loadMainWalletFromFile(woPath, nullptr)); //recreate empty bip32 wallet - auto emptyWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, - wltSeed, - SecureBinaryData(), - SecureBinaryData()); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Virgin)); + auto emptyWlt = AssetWallet_Single::createFromSeed(move(seed), + {}, {}, homedir_); //// register with db //// vector addrVec; @@ -4303,12 +4296,12 @@ TEST_F(SignerTest, Wallet_SpendTest_Nested_P2WPKH_WOResolution_fromXPub) //// create assetWlt //// //create empty bip32 wallet - auto&& wltSeed = CryptoPRNG::generateRandom(32); - auto emptyWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, - wltSeed, - SecureBinaryData(), - SecureBinaryData()); + auto rawEntropy = CryptoPRNG::generateRandom(32); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Virgin)); + auto emptyWlt = AssetWallet_Single::createFromSeed(move(seed), + {}, {}, homedir_); //create empty WO wallet auto wltWO = AssetWallet_Single::createBlank( @@ -4317,7 +4310,7 @@ TEST_F(SignerTest, Wallet_SpendTest_Nested_P2WPKH_WOResolution_fromXPub) //derive public root vector derPath = { 0x800061a5, 0x80000000 }; BIP32_Node seedNode; - seedNode.initFromSeed(wltSeed); + seedNode.initFromSeed(rawEntropy); auto seedFingerprint = seedNode.getThisFingerprint(); for (auto& derId : derPath) seedNode.derivePrivate(derId); @@ -4573,15 +4566,13 @@ TEST_F(SignerTest, Wallet_SpendTest_Nested_P2PK) scrAddrVec.push_back(TestChain::scrAddrE); //// create assetWlt //// - - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), + {}, {}, homedir_, - move(wltRoot), //root as a r value - {}, - SecureBinaryData(), - SecureBinaryData(), - 3); //lookup computation + 3); //set lookup computation to 3 entries //register with db vector addrVec; @@ -4809,13 +4800,11 @@ TEST_F(SignerTest, SpendTest_FromAccount_Reload) scrAddrVec.push_back(TestChain::scrAddrE); //// create assetWlt //// - - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, - move(wltRoot), //root as a rvalue - SecureBinaryData(), - SecureBinaryData()); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Virgin)); + auto assetWlt = AssetWallet_Single::createFromSeed(move(seed), + {}, {}, homedir_); //add a bip32 account { @@ -5206,12 +5195,11 @@ TEST_F(SignerTest, SpendTest_BIP32_Accounts) //// create assetWlt //// auto passphrase = SecureBinaryData::fromString("test"); - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, - wltRoot, //root as a rvalue - SecureBinaryData(), - passphrase); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Virgin)); + auto assetWlt = AssetWallet_Single::createFromSeed(move(seed), + passphrase, {}, homedir_); auto rootBip32 = dynamic_pointer_cast< AssetEntry_BIP32Root>(assetWlt->getRoot()); @@ -5488,14 +5476,14 @@ TEST_F(SignerTest, SpendTest_FromExtendedAddress_Armory135) //// create assetWlt //// auto passphrase = SecureBinaryData::fromString("test"); - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, SecureBinaryData::fromString("control"), - 5); //set lookup computation to 5 entries + homedir_, + 5); //set lookup computation to 3 entries //register with db DBTestUtils::registerWallet(clients_, bdvID, scrAddrVec, "wallet1"); @@ -5737,13 +5725,11 @@ TEST_F(SignerTest, SpendTest_FromExtendedAddress_BIP32) //// create assetWlt //// auto passphrase = SecureBinaryData::fromString("test"); - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - move(wltRoot), //root as a rvalue - passphrase, - SecureBinaryData::fromString("control"), - 5); //set lookup computation to 5 entries + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt = AssetWallet_Single::createFromSeed(move(seed), + passphrase, SecureBinaryData::fromString("control"), homedir_, 5); //register with db DBTestUtils::registerWallet(clients_, bdvID, scrAddrVec, "wallet1"); @@ -5985,12 +5971,11 @@ TEST_F(SignerTest, SpendTest_FromExtendedAddress_Salted) //// create assetWlt //// auto passphrase = SecureBinaryData::fromString("test"); - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, - wltRoot, //root as a rvalue - passphrase, - SecureBinaryData::fromString("control")); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Virgin)); + auto assetWlt = AssetWallet_Single::createFromSeed(move(seed), + passphrase, SecureBinaryData::fromString("control"), homedir_); auto rootBip32 = dynamic_pointer_cast< AssetEntry_BIP32Root>(assetWlt->getRoot()); @@ -6265,12 +6250,11 @@ TEST_F(SignerTest, SpendTest_FromExtendedAddress_ECDH) //// create assetWlt //// auto passphrase = SecureBinaryData::fromString("test"); - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, - wltRoot, //root as a rvalue - passphrase, - SecureBinaryData::fromString("control")); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Virgin)); + auto assetWlt = AssetWallet_Single::createFromSeed(move(seed), + passphrase, SecureBinaryData::fromString("control"), homedir_); auto ecdhAccType = make_shared(privKey, pubKey); ecdhAccType->setDefaultAddressType( @@ -6536,14 +6520,11 @@ TEST_F(SignerTest, SpendTest_InjectSignature) scrAddrVec.push_back(TestChain::scrAddrE); //// create assetWlt //// - - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - move(wltRoot), //root as a rvalue - SecureBinaryData(), - SecureBinaryData(), - 5); //set lookup computation to 3 entries + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), {}, {}, homedir_, 5); //register with db vector> addrVec; @@ -6923,31 +6904,28 @@ TEST_F(SignerTest, SpendTest_InjectSignature_Multisig) //// create 3 assetWlt //// - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt_1 = AssetWallet_Single::createFromPrivateRoot_Armory135( + unique_ptr seed1( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_1 = AssetWallet_Single::createFromSeed( + move(seed1), + {}, {}, homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), 3); //set lookup computation to 3 entries - wltRoot = move(CryptoPRNG::generateRandom(32)); - auto assetWlt_2 = AssetWallet_Single::createFromPrivateRoot_Armory135( + unique_ptr seed2( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_2 = AssetWallet_Single::createFromSeed( + move(seed2), + {}, {}, homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), 3); //set lookup computation to 3 entries - wltRoot = move(CryptoPRNG::generateRandom(32)); - auto assetWlt_3 = AssetWallet_Single::createFromPrivateRoot_Armory135( + unique_ptr seed3( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_3 = AssetWallet_Single::createFromSeed( + move(seed3), + {}, {}, homedir_, - move(wltRoot), //root as a rvalue - {}, - SecureBinaryData(), - SecureBinaryData(), 3); //set lookup computation to 3 entries //create 2-of-3 multisig asset entry from 3 different wallets @@ -8612,8 +8590,8 @@ TEST_F(ExtrasTest, PSBT) auto txOut = tx.getTxOutCopy(index); UTXO utxo( - txOut.getValue(), - UINT32_MAX, UINT32_MAX, index, + txOut.getValue(), + UINT32_MAX, UINT32_MAX, index, hash, txOut.getScript()); return utxo; @@ -8673,16 +8651,17 @@ TEST_F(ExtrasTest, PSBT) auto b58seed = SecureBinaryData::fromString( "tprv8ZgxMBicQKsPd9TeAdPADNnSyH9SSUUbTVeFszDE23Ki6TBB5nCefAdHkK8Fm3qMQR6sHwA56zqRmKmxnHk37JkiFzvncDqoKmPWubu7hDF"); + //create a wallet from that seed to test bip32 on the fly derivation + auto wallet = AssetWallet_Single::createFromSeed( + Armory::Seeds::ClearTextSeed_BIP32::fromBase58(b58seed), + SecureBinaryData(), SecureBinaryData(), + homedir_); + + //create node BIP32_Node node; node.initFromBase58(b58seed); auto masterFingerprint = node.getThisFingerprint(); - //create a wallet from that seed to test bip32 on the fly derivation - auto wallet = AssetWallet_Single::createFromBIP32Node( - node, {}, - SecureBinaryData(), SecureBinaryData(), - homedir_); - // 0'/0' node.derivePrivate(0x80000000); node.derivePrivate(0x80000000); @@ -8724,7 +8703,7 @@ TEST_F(ExtrasTest, PSBT) EXPECT_EQ(psbtTestVal, signer2.toPSBT()); Signer signer3(signer.serializeState()); - EXPECT_EQ(psbtTestVal, signer3.toPSBT()); + EXPECT_EQ(psbtTestVal, signer3.toPSBT()); } //resolve scripts @@ -8957,7 +8936,7 @@ TEST_F(ExtrasTest, PSBT) EXPECT_EQ(psbtHalf2, signer2.toPSBT()); Signer signer3(signer.serializeState()); - EXPECT_EQ(psbtHalf2, signer3.toPSBT()); + EXPECT_EQ(psbtHalf2, signer3.toPSBT()); } //combine sigs & finalize inputs @@ -9118,10 +9097,10 @@ class ExtrasTest_Mainnet : public ::testing::Test //////////////////////////////////////////////////////////////////////////////// TEST_F(ExtrasTest_Mainnet, Bip32PathDiscovery) { - auto seed = CryptoPRNG::generateRandom(32); + auto rawEntropy = CryptoPRNG::generateRandom(32); BIP32_Node node; - node.initFromSeed(seed); + node.initFromSeed(rawEntropy); auto masterFingerprint = node.getThisFingerprint(); vector derPath = { 0x8000002C, 0x80000000, 0x80000000 }; @@ -9151,10 +9130,11 @@ TEST_F(ExtrasTest_Mainnet, Bip32PathDiscovery) string wltPath; { - auto wallet = AssetWallet_Single::createFromSeed_BIP32( - homedir_, seed, - SecureBinaryData(), SecureBinaryData(), - 10); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Structured)); + auto wallet = AssetWallet_Single::createFromSeed( + move(seed), {}, {}, homedir_, 10); wltPath = wallet->getDbFilename(); auto woWalletPath = wallet->forkWatchingOnly(wltPath, passLbd); diff --git a/cppForSwig/gtest/SupernodeTests.cpp b/cppForSwig/gtest/SupernodeTests.cpp index 7689d6313..db28f45b2 100644 --- a/cppForSwig/gtest/SupernodeTests.cpp +++ b/cppForSwig/gtest/SupernodeTests.cpp @@ -12,6 +12,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "TestUtils.h" +#include "../Wallets/Seeds/Seeds.h" using namespace std; using namespace Armory::Signer; using namespace Armory::Config; @@ -1762,31 +1763,31 @@ TEST_F(BlockUtilsWithWalletTest, MultipleSigners_2of3_NativeP2WSH) //// create 3 assetWlt //// //create a root private key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt_1 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, + unique_ptr seed1( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_1 = AssetWallet_Single::createFromSeed( + move(seed1), + SecureBinaryData(), SecureBinaryData(), - SecureBinaryData(), + homedir_, 3); //set lookup computation to 3 entries - wltRoot = move(CryptoPRNG::generateRandom(32)); - auto assetWlt_2 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, + unique_ptr seed2( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_2 = AssetWallet_Single::createFromSeed( + move(seed2), + SecureBinaryData(), SecureBinaryData(), - SecureBinaryData(), + homedir_, 3); //set lookup computation to 3 entries - wltRoot = move(CryptoPRNG::generateRandom(32)); - auto assetWlt_3 = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, + unique_ptr seed3( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt_3 = AssetWallet_Single::createFromSeed( + move(seed3), SecureBinaryData(), - SecureBinaryData(), + SecureBinaryData(), + homedir_, 3); //set lookup computation to 3 entries //create 2-of-3 multisig asset entry from 3 different wallets @@ -2243,7 +2244,7 @@ class WebSocketTests : public ::testing::Test }; //////////////////////////////////////////////////////////////////////////////// -TEST_F(WebSocketTests, WebSocketStack_ParallelAsync) +TEST_F(WebSocketTests, DISABLED_WebSocketStack_ParallelAsync) { // TestUtils::setBlocks({ "0", "1", "2", "3", "4", "5" }, blk0dat_); diff --git a/cppForSwig/gtest/TestUtils.h b/cppForSwig/gtest/TestUtils.h index 1244c5382..22892ae19 100644 --- a/cppForSwig/gtest/TestUtils.h +++ b/cppForSwig/gtest/TestUtils.h @@ -21,12 +21,13 @@ #include "../log.h" #include "../BinaryData.h" #include "../BtcUtils.h" -#include "../BlockObj.h" -#include "../StoredBlockObj.h" +#include "../BlockchainDatabase/BlockObj.h" +#include "../BlockchainDatabase/lmdb_wrapper.h" +#include "../BlockchainDatabase/BlockUtils.h" +#include "../BlockchainDatabase/txio.h" +#include "../BlockchainDatabase/StoredBlockObj.h" #include "../PartialMerkle.h" #include "../EncryptionUtils.h" -#include "../lmdb_wrapper.h" -#include "../BlockUtils.h" #include "../ScrAddrObj.h" #include "../BtcWallet.h" #include "../BlockDataViewer.h" @@ -36,7 +37,6 @@ #include "../reorgTest/blkdata.h" #include "../BDM_Server.h" #include "../TxClasses.h" -#include "../txio.h" #include "../bdmenums.h" #include "../Signer/Script.h" #include "../Signer/Signer.h" diff --git a/cppForSwig/gtest/UtilsTests.cpp b/cppForSwig/gtest/UtilsTests.cpp index eb1ec871d..0e1919ab9 100644 --- a/cppForSwig/gtest/UtilsTests.cpp +++ b/cppForSwig/gtest/UtilsTests.cpp @@ -13,7 +13,7 @@ #include #include "TestUtils.h" #include "hkdf.h" -#include "TxHashFilters.h" +#include "BlockchainDatabase/TxHashFilters.h" using namespace std; using namespace Armory::Signer; @@ -2014,7 +2014,7 @@ TEST_F(BinaryDataTest, Contains) EXPECT_FALSE(bd4_.contains(d, 8)); } -TEST_F(BinaryDataTest, CompareBench) +TEST_F(BinaryDataTest, DISABLED_CompareBench) { auto start = chrono::system_clock::now(); @@ -2839,9 +2839,7 @@ class BtcUtilsTest : public ::testing::Test string homedir_; }; - - - +//////////////////////////////////////////////////////////////////////////////// TEST_F(BtcUtilsTest, ReadVarInt) { BinaryData vi0 = READHEX("00"); @@ -2898,7 +2896,7 @@ TEST_F(BtcUtilsTest, ReadVarInt) EXPECT_EQ(BtcUtils::calcVarIntSize(z), 9ULL); } - +//////////////////////////////////////////////////////////////////////////////// TEST_F(BtcUtilsTest, Num2Str) { EXPECT_EQ(BtcUtils::numToStrWCommas(0), string("0")); @@ -2911,8 +2909,7 @@ TEST_F(BtcUtilsTest, Num2Str) EXPECT_EQ(BtcUtils::numToStrWCommas(-12345678), string("-12,345,678")); } - - +//////////////////////////////////////////////////////////////////////////////// TEST_F(BtcUtilsTest, PackBits) { list::iterator iter, iter2; @@ -3000,14 +2997,12 @@ TEST_F(BtcUtilsTest, PackBits) EXPECT_EQ(packed, READHEX("0170")); } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(BtcUtilsTest, SimpleHash) { - BinaryData hashOut; + BinaryData hashOut; - // sha256(sha256(X)); + // sha256(sha256(X)) BtcUtils::getHash256(rawHead_.getPtr(), rawHead_.getSize(), hashOut); EXPECT_EQ(hashOut, headHashLE_); EXPECT_EQ(hashOut, headHashBE_.copySwapEndian()); @@ -3028,8 +3023,7 @@ TEST_F(BtcUtilsTest, SimpleHash) hashOut = BtcUtils::getHash256(rawHead_); EXPECT_EQ(hashOut, headHashLE_); - - // ripemd160(sha256(X)); + // ripemd160(sha256(X)) BtcUtils::getHash160(satoshiPubKey_.getPtr(), satoshiPubKey_.getSize(), hashOut); EXPECT_EQ(hashOut, satoshiHash160_); @@ -3049,7 +3043,20 @@ TEST_F(BtcUtilsTest, SimpleHash) EXPECT_EQ(hashOut, satoshiHash160_); } +//////////////////////////////////////////////////////////////////////////////// +TEST_F(BtcUtilsTest, BotchedArmoryHMAC) +{ + auto sha_abcd = READHEX("88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589"); + auto sha_efgh = READHEX("e5e088a0b66163a0a26a5e053d2a4496dc16ab6e0e3dd1adf2d16aa84a078c9d"); + auto hmac_1 = READHEX("edd2c945dc57a5eecdb4dbb2db8ae4f33f9669046e47acb517c8f6bcdf6ee591"); + auto abcd = BinaryData::fromString("abcd"); + auto efgh = BinaryData::fromString("efgh"); + + EXPECT_EQ(BtcUtils::getSha256(abcd), sha_abcd); + EXPECT_EQ(BtcUtils::getSha256(efgh), sha_efgh); + EXPECT_EQ(BtcUtils::getBotchedArmoryHMAC256(abcd, efgh), hmac_1); +} //////////////////////////////////////////////////////////////////////////////// TEST_F(BtcUtilsTest, TxOutScriptID_Hash160) @@ -3202,18 +3209,6 @@ TEST_F(BtcUtilsTest, TxOutScriptID_MultiList) EXPECT_EQ(pkList[1], pub1); } - -//TEST_F(BtcUtilsTest, TxInScriptID) -//{ - //TXIN_SCRIPT_STDUNCOMPR, - //TXIN_SCRIPT_STDCOMPR, - //TXIN_SCRIPT_COINBASE, - //TXIN_SCRIPT_SPENDPUBKEY, - //TXIN_SCRIPT_SPENDMULTI, - //TXIN_SCRIPT_SPENDP2SH, - //TXIN_SCRIPT_NONSTANDARD -//} - //////////////////////////////////////////////////////////////////////////////// TEST_F(BtcUtilsTest, TxInScriptID_StdUncompr) { @@ -3285,8 +3280,6 @@ TEST_F(BtcUtilsTest, TxInScriptID_SpendPubKey) //txInHash160s.push_back( READHEX("957efec6af757ccbbcf9a436f0083c5ddaa3bf1d")); // this one can't be determined } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(BtcUtilsTest, TxInScriptID_SpendMultisig) { @@ -3350,8 +3343,6 @@ TEST_F(BtcUtilsTest, TxInScriptID_SpendP2SH) EXPECT_EQ(BtcUtils::getTxInAddrFromType(script, scrType), a160); } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(BtcUtilsTest, BitsToDifficulty) { @@ -3359,13 +3350,12 @@ TEST_F(BtcUtilsTest, BitsToDifficulty) double a = BtcUtils::convertDiffBitsToDouble(READHEX("ffff001d")); double b = BtcUtils::convertDiffBitsToDouble(READHEX("be2f021a")); double c = BtcUtils::convertDiffBitsToDouble(READHEX("3daa011a")); - + EXPECT_DOUBLE_EQ(a, 1.0); EXPECT_DOUBLE_EQ(b, 7672999.920164138); EXPECT_DOUBLE_EQ(c, 10076292.883418716); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(BtcUtilsTest, ScriptToOpCodes) { @@ -3423,8 +3413,6 @@ TEST_F(BtcUtilsTest, ScriptToOpCodes) EXPECT_EQ(output[i], opstr[i]); } - - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// class BlockObjTest : public ::testing::Test @@ -3558,8 +3546,6 @@ class BlockObjTest : public ::testing::Test Tx tx2_; }; - - //////////////////////////////////////////////////////////////////////////////// TEST_F(BlockObjTest, HeaderNoInit) { @@ -3569,7 +3555,6 @@ TEST_F(BlockObjTest, HeaderNoInit) EXPECT_EQ(bh.getBlockSize(), UINT32_MAX); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(BlockObjTest, HeaderUnserialize) { @@ -3609,8 +3594,6 @@ TEST_F(BlockObjTest, HeaderProperties) EXPECT_EQ(BlockHeader(rawHead_).serialize(), rawHead_); } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(BlockObjTest, OutPointProperties) { @@ -3639,7 +3622,6 @@ TEST_F(BlockObjTest, OutPointProperties) EXPECT_EQ(op.getTxHashRef(), prevHash.getRef()); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(BlockObjTest, OutPointSerialize) { @@ -3728,7 +3710,6 @@ TEST_F(BlockObjTest, DISABLED_FullBlock) BinaryRefReader brr(rawBlock_); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(BlockObjTest, DISABLED_TxIOPairStuff) { @@ -3741,8 +3722,6 @@ TEST_F(BlockObjTest, DISABLED_RegisteredTxStuff) EXPECT_TRUE(false); } - - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// class StoredBlockObjTest : public ::testing::Test @@ -3938,7 +3917,6 @@ class StoredBlockObjTest : public ::testing::Test StoredHeader sbh_; }; - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, StoredObjNoInit) { @@ -4023,8 +4001,6 @@ TEST_F(StoredBlockObjTest, GetDBKeys) EXPECT_EQ(sths.getDBKey( false ), key); } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, LengthUnfrag) { @@ -4047,8 +4023,6 @@ TEST_F(StoredBlockObjTest, LengthUnfrag) EXPECT_EQ(offout[2], 434ULL); } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, LengthFragged) { @@ -4236,7 +4210,7 @@ TEST_F(StoredBlockObjTest, ReadBlkKeyData) EXPECT_EQ( txi, 7); EXPECT_EQ( brr.getSizeRemaining(), 0ULL); EXPECT_EQ( bdtype, BLKDATA_TX); - + brr.setNewData(key7); bdtype = DBUtils::readBlkDataKeyNoPrefix(brr, hgt, dup, txi, txo); EXPECT_EQ( hgt, 123000ULL); @@ -4263,7 +4237,7 @@ TEST_F(StoredBlockObjTest, ReadBlkKeyData) EXPECT_EQ( txi, 7); EXPECT_EQ( brr.getSizeRemaining(), 0ULL); EXPECT_EQ( bdtype, BLKDATA_TXOUT); - + brr.setNewData(key9); bdtype = DBUtils::readBlkDataKeyNoPrefix(brr, hgt, dup, txi, txo); EXPECT_EQ( hgt, 123000ULL); @@ -4309,7 +4283,6 @@ TEST_F(StoredBlockObjTest, SHeaderDBSerFull_H) EXPECT_EQ(serializeDBValue(sbh_, HEADERS, ARMORY_DB_FULL), rawHead_ + last4); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, SHeaderDBSerFull_B1) { @@ -4352,7 +4325,6 @@ TEST_F(StoredBlockObjTest, SHeaderDBUnserFull_H) EXPECT_EQ(sbh_.duplicateID_, 1); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, SHeaderDBUnserFull_B1) { @@ -4376,7 +4348,6 @@ TEST_F(StoredBlockObjTest, SHeaderDBUnserFull_B1) EXPECT_EQ(sbh_.unserMkType_, MERKLE_SER_NONE); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, SHeaderDBUnserFull_B2) { @@ -4477,8 +4448,6 @@ TEST_F(StoredBlockObjTest, STxUnserFragged) EXPECT_EQ( stx.stxoMap_[1].txOutIndex_, 1); } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, STxReconstruct) { @@ -4607,8 +4576,6 @@ TEST_F(StoredBlockObjTest, STxUnserDBValue_2) EXPECT_EQ( stx.fragBytes_, 370ULL); } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, STxOutUnserialize) { @@ -4657,7 +4624,6 @@ TEST_F(StoredBlockObjTest, STxOutSerDBValue_1) EXPECT_EQ(serializeDBValue(stxo0), READHEX("1400") + rawTxOut0_); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, STxOutSerDBValue_2) @@ -4681,8 +4647,6 @@ TEST_F(StoredBlockObjTest, STxOutSerDBValue_2) ); } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, STxOutSerDBValue_3) { @@ -4705,7 +4669,6 @@ TEST_F(StoredBlockObjTest, STxOutSerDBValue_3) ); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, STxOutUnserDBValue_1) { @@ -4726,6 +4689,7 @@ TEST_F(StoredBlockObjTest, STxOutUnserDBValue_1) EXPECT_FALSE(stxo.isCoinbase_); EXPECT_EQ( stxo.unserArmVer_, 0ULL); } + //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, STxOutUnserDBValue_2) { @@ -4747,7 +4711,6 @@ TEST_F(StoredBlockObjTest, STxOutUnserDBValue_2) EXPECT_EQ( stxo.unserArmVer_, 0ULL); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, STxOutUnserDBValue_3) { @@ -4769,7 +4732,6 @@ TEST_F(StoredBlockObjTest, STxOutUnserDBValue_3) EXPECT_EQ( stxo.unserArmVer_, 0ULL); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, SHeaderFullBlock) { @@ -4783,7 +4745,6 @@ TEST_F(StoredBlockObjTest, SHeaderFullBlock) EXPECT_EQ(bw.getDataRef(), rawBlock_.getRef()); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, SUndoDataSer) { @@ -4845,8 +4806,6 @@ TEST_F(StoredBlockObjTest, SUndoDataSer) EXPECT_EQ(serializeDBValue(sud), answer); } - - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, SUndoDataUnser) { @@ -4905,7 +4864,6 @@ TEST_F(StoredBlockObjTest, SUndoDataUnser) EXPECT_EQ(sud.stxOutsRemovedByBlock_[1].txIndex_, 17ULL); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, STxHintsSer) { @@ -5082,7 +5040,6 @@ TEST_F(StoredBlockObjTest, SHeadHgtListSer) EXPECT_EQ(testHHL.serializeDBValue(), expectOut.getData()); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(StoredBlockObjTest, SHeadHgtListUnser) { @@ -5355,7 +5312,6 @@ TEST_F(StoredBlockObjTest, SScriptHistoryUnser) EXPECT_EQ( subref.txioMap_[txio1key].getValue(), val1); EXPECT_EQ( subref.txioMap_[txio0key].getDBKeyOfOutput(), txio0key); EXPECT_EQ( subref.txioMap_[txio1key].getDBKeyOfOutput(), txio1key); - ///////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/gtest/WalletTests.cpp b/cppForSwig/gtest/WalletTests.cpp index 066756bba..f2f76ebbf 100644 --- a/cppForSwig/gtest/WalletTests.cpp +++ b/cppForSwig/gtest/WalletTests.cpp @@ -9,8 +9,12 @@ #include "TestUtils.h" #include "../Wallets/PassphraseLambda.h" -#include "../ArmoryBackups.h" +#include "../Wallets/Seeds/Backups.h" +#include "../Wallets/Seeds/Seeds.h" #include "../Wallets/WalletFileInterface.h" +#ifdef BUILD_PROTOBUF +#include "protobuf/BridgeProto.pb.h" +#endif using namespace std; using namespace Armory::Signer; @@ -19,6 +23,7 @@ using namespace Armory::Assets; using namespace Armory::Accounts; using namespace Armory::Wallets; using namespace Armory::Wallets::Encryption; +using namespace Armory::Seeds; //////////////////////////////////////////////////////////////////////////////// #define METHOD_ASSERT_EQ(a, b) \ @@ -4146,14 +4151,14 @@ TEST_F(WalletsTest, CreateCloseOpen_Test) //create 3 wallets for (unsigned i = 0; i < 1; i++) { - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("passphrase"), controlPass_, - 4); //set lookup computation to 4 entries + homedir_, + 4); //set lookup computation to 3 entries //get AddrVec auto&& hashSet = assetWlt->getAddrHashSet(); @@ -4195,14 +4200,14 @@ TEST_F(WalletsTest, CreateCloseOpen_Test) TEST_F(WalletsTest, CreateWOCopy_Test) { //create 1 wallet from priv key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), - 4); //set lookup computation to 4 entries + homedir_, + 4); //set lookup computation to 3 entries auto filename = assetWlt->getDbFilename(); //get AddrVec @@ -4274,35 +4279,24 @@ TEST_F(WalletsTest, CreateWOCopy_Test) //////////////////////////////////////////////////////////////////////////////// TEST_F(WalletsTest, IDs) { - auto computeId = []( - const SecureBinaryData& root, const SecureBinaryData& chaincode)->string + auto rawEntropy = CryptoPRNG::generateRandom(32); + auto rawPubkey = CryptoECDSA().ComputePublicKey(rawEntropy); + string id; { - auto ccCopy = chaincode; - if (chaincode.empty()) - ccCopy = BtcUtils::computeChainCode_Armory135(root); - - auto derScheme = - make_shared(ccCopy); - - auto pubkey = CryptoECDSA().ComputePublicKey(root); - auto asset_single = make_shared( - AssetId::getRootAssetId(), pubkey, nullptr); - - return AssetWallet_Single::computeWalletID(derScheme, asset_single); - }; - - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto id = computeId(wltRoot, {}); + auto chaincode = BtcUtils::computeChainCode_Armory135(rawEntropy); + id = generateWalletId(rawPubkey, chaincode, SeedType::Armory135); + } ASSERT_FALSE(id.empty()); //legacy wallet { - auto wlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135(rawEntropy)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries EXPECT_EQ(wlt->getID(), id); @@ -4310,18 +4304,23 @@ TEST_F(WalletsTest, IDs) //bip32 wallet { - auto wlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - wltRoot, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, + Armory::Seeds::SeedType::BIP32_Structured)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries //wallet id BIP32_Node node; - node.initFromSeed(wltRoot); + node.initFromSeed(rawEntropy); - auto idBip32 = computeId(node.getPrivateKey(), node.getChaincode()); + auto idBip32 = generateWalletId(node.getPublicKey(), node.getChaincode(), + SeedType::BIP32_Structured); EXPECT_EQ(wlt->getID(), idBip32); //account ids @@ -4401,41 +4400,105 @@ TEST_F(WalletsTest, IDs) //legacy with chaincode auto chaincode = CryptoPRNG::generateRandom(32); - auto idcc = computeId(wltRoot, chaincode); + auto idcc = generateWalletId(rawPubkey, chaincode, + SeedType::Armory135); ASSERT_NE(id, idcc); { - auto wlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, - chaincode, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135( + rawEntropy, chaincode)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries EXPECT_EQ(wlt->getID(), idcc); } } +//////////////////////////////////////////////////////////////////////////////// +TEST_F(WalletsTest, ID_fromSeeds) +{ + auto rawSBD = SecureBinaryData::CreateFromHex( + "0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20"); + + //Armory135 + { + auto seed135 = make_unique( + rawSBD, ClearTextSeed_Armory135::LegacyType::Armory135); + EXPECT_EQ(seed135->getWalletId(), "2vrVAxyHR"); + EXPECT_EQ(seed135->getMasterId(), "LZxsEgeT"); + } + + //Armory200a + { + auto seed135 = make_unique( + rawSBD, ClearTextSeed_Armory135::LegacyType::Armory200); + EXPECT_EQ(seed135->getWalletId(), "2vrVAxyHR"); + EXPECT_EQ(seed135->getMasterId(), "LZxsEgeT"); + } + + //BIP32 structured + { + auto bip32 = make_unique( + rawSBD, SeedType::BIP32_Structured); + EXPECT_EQ(bip32->getWalletId(), "2BuhCGwV9"); + EXPECT_EQ(bip32->getMasterId(), "2d9H95rzK"); + } + + //BIP32 virgin + { + auto bip32 = make_unique( + rawSBD, SeedType::BIP32_Virgin); + EXPECT_EQ(bip32->getWalletId(), "22bd31PB5"); + EXPECT_EQ(bip32->getMasterId(), "2d9H95rzK"); + } + + //xpriv + { + BIP32_Node node; + node.initFromSeed(rawSBD); + auto xpriv = node.getBase58(); + + auto base58 = ClearTextSeed_BIP32::fromBase58(xpriv); + EXPECT_EQ(base58->getWalletId(), "33qBfTB51"); + EXPECT_EQ(base58->getMasterId(), "2d9H95rzK"); + } + + + //BIP39 + { + auto bip32 = make_unique(rawSBD, + ClearTextSeed_BIP39::Dictionnary::English_Trezor); + EXPECT_EQ(bip32->getWalletId(), "vUXT83m9"); + EXPECT_EQ(bip32->getMasterId(), "WLKZBhnX"); + } +} + //////////////////////////////////////////////////////////////////////////////// TEST_F(WalletsTest, Encryption_Test) { //#1: check deriving from an encrypted root yield correct chain //create 1 wallet from priv key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, - {}, + auto rawEntropy = CryptoPRNG::generateRandom(32); + + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135(rawEntropy)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries //derive private chain from root - auto&& chaincode = BtcUtils::computeChainCode_Armory135(wltRoot); + auto&& chaincode = BtcUtils::computeChainCode_Armory135(rawEntropy); vector privateKeys; - auto currentPrivKey = &wltRoot; + auto currentPrivKey = &rawEntropy; for (int i = 0; i < 4; i++) { @@ -4527,21 +4590,28 @@ TEST_F(WalletsTest, SeedEncryption) auto&& passphrase = SecureBinaryData::fromString("password"); //create regular wallet - auto&& seed = CryptoPRNG::generateRandom(32); - auto wlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, seed, passphrase, - SecureBinaryData::fromString("control"), 10); + auto rawEntropy = CryptoPRNG::generateRandom(32); + + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Structured)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), + passphrase, + SecureBinaryData::fromString("control"), + homedir_, + 10); //check clear text seed does not exist on disk auto filename = wlt->getDbFilename(); - ASSERT_FALSE(TestUtils::searchFile(filename, seed)); + ASSERT_FALSE(TestUtils::searchFile(filename, rawEntropy)); //grab without passphrase lbd, should fail try { auto lock = wlt->lockDecryptedContainer(); auto decryptedSeed = wlt->getDecryptedValue(wlt->getEncryptedSeed()); - EXPECT_EQ(decryptedSeed, seed); + EXPECT_EQ(decryptedSeed, rawEntropy); ASSERT_TRUE(false); } catch (DecryptedDataContainerException&) @@ -4560,7 +4630,7 @@ TEST_F(WalletsTest, SeedEncryption) try { auto decryptedSeed = wlt->getDecryptedValue(wlt->getEncryptedSeed()); - EXPECT_EQ(decryptedSeed, seed); + EXPECT_EQ(decryptedSeed, rawEntropy); ASSERT_TRUE(false); } catch (DecryptedDataContainerException&) @@ -4570,8 +4640,10 @@ TEST_F(WalletsTest, SeedEncryption) try { auto lock = wlt->lockDecryptedContainer(); - auto decryptedSeed = wlt->getDecryptedValue(wlt->getEncryptedSeed()); - EXPECT_EQ(decryptedSeed, seed); + auto clearTextSeed = ClearTextSeed::deserialize( + wlt->getDecryptedValue(wlt->getEncryptedSeed())); + auto seedBip32 = dynamic_cast(clearTextSeed.get()); + EXPECT_EQ(seedBip32->getRawEntropy(), rawEntropy); } catch (DecryptedDataContainerException&) { @@ -4584,7 +4656,7 @@ TEST_F(WalletsTest, SeedEncryption) { auto lock = wlt->lockDecryptedContainer(); auto decryptedSeed = wlt->getDecryptedValue(wlt->getEncryptedSeed()); - EXPECT_EQ(decryptedSeed, seed); + EXPECT_EQ(decryptedSeed, rawEntropy); ASSERT_TRUE(false); } catch (DecryptedDataContainerException&) @@ -4614,8 +4686,10 @@ TEST_F(WalletsTest, SeedEncryption) try { auto lock = wlt->lockDecryptedContainer(); - auto decryptedSeed = wlt->getDecryptedValue(wlt->getEncryptedSeed()); - EXPECT_EQ(decryptedSeed, seed); + auto clearTextSeed = ClearTextSeed::deserialize( + wlt->getDecryptedValue(wlt->getEncryptedSeed())); + auto seedBip32 = dynamic_cast(clearTextSeed.get()); + EXPECT_EQ(seedBip32->getRawEntropy(), rawEntropy); } catch (DecryptedDataContainerException&) { @@ -4627,13 +4701,15 @@ TEST_F(WalletsTest, SeedEncryption) TEST_F(WalletsTest, LockAndExtend_Test) { //create wallet from priv key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, //root as a r value - {}, + auto rawEntropy = CryptoPRNG::generateRandom(32); + + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135(rawEntropy)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), //root as a r value SecureBinaryData::fromString("passphrase"), //set passphrase to "test" controlPass_, + homedir_, 4); //set lookup computation to 4 entries auto passLbd = [] @@ -4645,10 +4721,10 @@ TEST_F(WalletsTest, LockAndExtend_Test) assetWlt->setPassphrasePromptLambda(passLbd); //derive private chain from root - auto&& chaincode = BtcUtils::computeChainCode_Armory135(wltRoot); + auto&& chaincode = BtcUtils::computeChainCode_Armory135(rawEntropy); vector privateKeys; - auto currentPrivKey = &wltRoot; + auto currentPrivKey = &rawEntropy; for (int i = 0; i < 10; i++) { @@ -4838,13 +4914,13 @@ TEST_F(WalletsTest, ControlPassphrase_Test) string filename; set addrSet; { - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("test"), //set passphrase to "test" SecureBinaryData::fromString("control"), //control passphrase + homedir_, 4); //set lookup computation to 4 entries filename = assetWlt->getDbFilename(); addrSet = assetWlt->getAddrHashSet(); @@ -5009,12 +5085,14 @@ TEST_F(WalletsTest, ControlPassphrase_Test) string filename2; { - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - wltRoot, //root as a r value + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("test"), //set passphrase to "test" SecureBinaryData(), //empty control passphrase + homedir_, 4); //set lookup computation to 4 entries filename2 = assetWlt->getDbFilename(); addrSet = assetWlt->getAddrHashSet(); @@ -5175,13 +5253,15 @@ TEST_F(WalletsTest, ControlPassphrase_Test) TEST_F(WalletsTest, SignPassphrase_Test) { //create wallet from priv key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, //root as a r value - {}, + auto rawEntropy = CryptoPRNG::generateRandom(32); + + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135(rawEntropy)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("test"), //set passphrase to "test" SecureBinaryData::fromString("control"), //control passphrase + homedir_, 4); //set lookup computation to 4 entries unsigned passphraseCount = 0; @@ -5245,9 +5325,9 @@ TEST_F(WalletsTest, SignPassphrase_Test) auto& privkey = assetWlt->getDecryptedValue(asset_single->getPrivKey()); //make sure decrypted privkey is valid - auto&& chaincode = BtcUtils::computeChainCode_Armory135(wltRoot); + auto&& chaincode = BtcUtils::computeChainCode_Armory135(rawEntropy); auto&& privkey_ex = - CryptoECDSA().ComputeChainedPrivateKey(wltRoot, chaincode); + CryptoECDSA().ComputeChainedPrivateKey(rawEntropy, chaincode); ASSERT_EQ(privkey, privkey_ex); } @@ -5263,13 +5343,16 @@ TEST_F(WalletsTest, SignPassphrase_Test) TEST_F(WalletsTest, WrongPassphrase_BIP32_Test) { //create wallet from priv key - auto&& wltRoot = CryptoPRNG::generateRandom(32); + auto rawEntropy = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - wltRoot, //root as a r value + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), //root as a r value SecureBinaryData::fromString("test"), //set passphrase to "test" SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries unsigned passphraseCount = 0; @@ -5334,7 +5417,7 @@ TEST_F(WalletsTest, WrongPassphrase_BIP32_Test) //make sure decrypted privkey is valid BIP32_Node node; - node.initFromSeed(wltRoot); + node.initFromSeed(rawEntropy); node.derivePrivate(0x8000002C); node.derivePrivate(0x80000000); @@ -5405,7 +5488,7 @@ TEST_F(WalletsTest, WrongPassphrase_BIP32_Test) //make sure decrypted privkey is valid BIP32_Node node; - node.initFromSeed(wltRoot); + node.initFromSeed(rawEntropy); for (auto& der : derPath2) node.derivePrivate(der); @@ -5426,18 +5509,20 @@ TEST_F(WalletsTest, WrongPassphrase_BIP32_Test) TEST_F(WalletsTest, ChangePassphrase_Test) { //create wallet from priv key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, //root as a r value - {}, + auto rawEntropy = CryptoPRNG::generateRandom(32); + + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135(rawEntropy)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("test"), //set passphrase to "test" controlPass_, + homedir_, 4); //set lookup computation to 4 entries - auto&& chaincode = BtcUtils::computeChainCode_Armory135(wltRoot); + auto&& chaincode = BtcUtils::computeChainCode_Armory135(rawEntropy); auto&& privkey_ex = - CryptoECDSA().ComputeChainedPrivateKey(wltRoot, chaincode); + CryptoECDSA().ComputeChainedPrivateKey(rawEntropy, chaincode); auto filename = assetWlt->getDbFilename(); @@ -5732,18 +5817,20 @@ TEST_F(WalletsTest, ChangePassphrase_Test) TEST_F(WalletsTest, ChangePassphrase_FromUnencryptedWallet_Test) { //create wallet from priv key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, //root as a r value - {}, + auto rawEntropy = CryptoPRNG::generateRandom(32); + + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135(rawEntropy)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData(), //set passphrase to "test" SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries - auto&& chaincode = BtcUtils::computeChainCode_Armory135(wltRoot); + auto&& chaincode = BtcUtils::computeChainCode_Armory135(rawEntropy); auto&& privkey_ex = - CryptoECDSA().ComputeChainedPrivateKey(wltRoot, chaincode); + CryptoECDSA().ComputeChainedPrivateKey(rawEntropy, chaincode); auto filename = assetWlt->getDbFilename(); auto newPass = SecureBinaryData::fromString("newpass"); @@ -5935,18 +6022,20 @@ TEST_F(WalletsTest, ChangePassphrase_FromUnencryptedWallet_Test) //////////////////////////////////////////////////////////////////////////////// TEST_F(WalletsTest, ChangeControlPassphrase_Test) { - + auto&& newPass = SecureBinaryData::fromString("newpass"); //create wallet string filename; { - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - wltRoot, //root as a r value + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), //root as a r value SecureBinaryData::fromString("test"), //set passphrase to "test" SecureBinaryData::fromString("control"), + homedir_, 40); //set lookup computation to 4 entries filename = assetWlt->getDbFilename(); @@ -6090,13 +6179,13 @@ TEST_F(WalletsTest, ChangeControlPassphrase_Test) TEST_F(WalletsTest, MultiplePassphrase_Test) { //create wallet from priv key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("test"), //set passphrase to "test" controlPass_, + homedir_, 4); //set lookup computation to 4 entries auto passLbd1 = [](const set&)->SecureBinaryData @@ -6199,9 +6288,14 @@ TEST_F(WalletsTest, BIP32_Chain) account->setMain(true); account->setAddressLookup(4); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, wltSeed, - SecureBinaryData::fromString("test"), controlPass_); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + wltSeed, Armory::Seeds::SeedType::BIP32_Virgin)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), + SecureBinaryData::fromString("test"), + controlPass_, + homedir_); { auto passphraseLbd = [] @@ -6280,7 +6374,7 @@ TEST_F(WalletsTest, BIP32_Public_Chain) ASSERT_NE(assetSingle, nullptr); BIP32_Node pubNode; - auto&& pub_b58 = + auto&& pub_b58 = SecureBinaryData::fromString("xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); pubNode.initFromBase58(pub_b58); @@ -6290,19 +6384,22 @@ TEST_F(WalletsTest, BIP32_Public_Chain) //////////////////////////////////////////////////////////////////////////////// TEST_F(WalletsTest, BIP32_ArmoryDefault) { - vector derivationPath = + vector derivationPath = { 0x8000002C, 0x80000000, 0x80000000 }; - auto&& seed = CryptoPRNG::generateRandom(32); + auto rawEntropy = CryptoPRNG::generateRandom(32); //create empty wallet auto&& passphrase = SecureBinaryData::fromString("password"); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, seed, passphrase, controlPass_, 5); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass_, homedir_, 5); auto mainAcc = assetWlt->getAccountForID(assetWlt->getMainAccountID()); auto outerAcc = mainAcc->getOuterAccount(); @@ -6310,7 +6407,7 @@ TEST_F(WalletsTest, BIP32_ArmoryDefault) outerAcc->getRoot()); BIP32_Node node; - node.initFromSeed(seed); + node.initFromSeed(rawEntropy); for (auto id : derivationPath) node.derivePrivate(id); node.derivePrivate(0); @@ -6342,12 +6439,15 @@ TEST_F(WalletsTest, BIP32_Chain_AddAccount) }; //random seed - auto&& seed = CryptoPRNG::generateRandom(32); + auto rawEntropy = CryptoPRNG::generateRandom(32); //create empty wallet - auto&& passphrase = SecureBinaryData::fromString("password"); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, seed, passphrase, controlPass_); + auto passphrase = SecureBinaryData::fromString("password"); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Virgin)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass_, homedir_); //this is a hard derivation scenario, the wallet needs to be able to //decrypt its root's private key @@ -6370,7 +6470,7 @@ TEST_F(WalletsTest, BIP32_Chain_AddAccount) //derive bip32 node BIP32_Node seedNode; - seedNode.initFromSeed(seed); + seedNode.initFromSeed(rawEntropy); for (auto& derId : derivationPath1) seedNode.derivePrivate(derId); @@ -6439,7 +6539,7 @@ TEST_F(WalletsTest, BIP32_Chain_AddAccount) auto accountID2 = assetWlt->createBIP32Account(accountTypePtr); BIP32_Node seedNode2; - seedNode2.initFromSeed(seed); + seedNode2.initFromSeed(rawEntropy); for (auto& derId : derivationPath2) seedNode2.derivePrivate(derId); seedNode2.derivePrivate(50); @@ -6528,9 +6628,11 @@ TEST_F(WalletsTest, BIP32_Fork_WatchingOnly) auto&& passphrase = SecureBinaryData::fromString("password"); //create regular wallet - auto&& seed = CryptoPRNG::generateRandom(32); - auto wlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, seed, passphrase, controlPass_, 10); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass_, homedir_, 10); //create WO copy auto woCopyPath = AssetWallet::forkWatchingOnly( @@ -6620,13 +6722,16 @@ TEST_F(WalletsTest, BIP32_WatchingOnly_FromXPub) auto&& passphrase = SecureBinaryData::fromString("password"); //create regular wallet - auto&& seed = CryptoPRNG::generateRandom(32); - auto wlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, seed, passphrase, controlPass_, 10); + auto rawEntropy = CryptoPRNG::generateRandom(32); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Structured)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass_, homedir_, 10); //get xpub for main account BIP32_Node seedNode; - seedNode.initFromSeed(seed); + seedNode.initFromSeed(rawEntropy); auto seedFingerprint = seedNode.getThisFingerprint(); for (auto& derId : derPath) seedNode.derivePrivate(derId); @@ -6690,9 +6795,11 @@ TEST_F(WalletsTest, AddressEntryTypes) auto&& passphrase = SecureBinaryData::fromString("password"); //create regular wallet - auto&& seed = CryptoPRNG::generateRandom(32); - auto wlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, seed, passphrase, controlPass_, 10); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass_, homedir_, 10); //grab a bunch of addresses of various types set addrHashes; @@ -6770,9 +6877,12 @@ TEST_F(WalletsTest, LegacyUncompressedAddressTypes) auto&& passphrase = SecureBinaryData::fromString("password"); //create regular wallet - auto&& seed = CryptoPRNG::generateRandom(32); - auto wlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, seed, passphrase, controlPass_); + auto rawEntropy = CryptoPRNG::generateRandom(32); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Virgin)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass_, homedir_); //create account with all common uncompressed address types & their //compressed counterparts @@ -6812,7 +6922,7 @@ TEST_F(WalletsTest, LegacyUncompressedAddressTypes) //derive the keys locally and reproduce the addresses BIP32_Node bip32Node; - bip32Node.initFromSeed(seed); + bip32Node.initFromSeed(rawEntropy); for (auto& der : derPath) bip32Node.derivePrivate(der); bip32Node.derivePublic(0); //spender leaf @@ -6882,9 +6992,9 @@ TEST_F(WalletsTest, BIP32_SaltedAccount) 327 }; - auto&& seed = CryptoPRNG::generateRandom(32); - auto&& salt1 = CryptoPRNG::generateRandom(32); - auto&& salt2 = CryptoPRNG::generateRandom(32); + auto rawEntropy = CryptoPRNG::generateRandom(32); + auto salt1 = CryptoPRNG::generateRandom(32); + auto salt2 = CryptoPRNG::generateRandom(32); string filename; AddressAccountId accountID1; @@ -6894,9 +7004,12 @@ TEST_F(WalletsTest, BIP32_SaltedAccount) { //create empty wallet + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Virgin)); auto&& passphrase = SecureBinaryData::fromString("password"); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, seed, passphrase, controlPass_); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass_, homedir_); auto rootbip32 = dynamic_pointer_cast( assetWlt->getRoot()); @@ -6942,7 +7055,7 @@ TEST_F(WalletsTest, BIP32_SaltedAccount) //derive from seed { BIP32_Node seedNode; - seedNode.initFromSeed(seed); + seedNode.initFromSeed(rawEntropy); for (auto& derId : derivationPath1) seedNode.derivePrivate(derId); @@ -6959,7 +7072,7 @@ TEST_F(WalletsTest, BIP32_SaltedAccount) { BIP32_Node seedNode; - seedNode.initFromSeed(seed); + seedNode.initFromSeed(rawEntropy); for (auto& derId : derivationPath2) seedNode.derivePrivate(derId); @@ -7000,7 +7113,7 @@ TEST_F(WalletsTest, BIP32_SaltedAccount) //derive from seed { BIP32_Node seedNode; - seedNode.initFromSeed(seed); + seedNode.initFromSeed(rawEntropy); for (auto& derId : derivationPath1) seedNode.derivePrivate(derId); @@ -7017,7 +7130,7 @@ TEST_F(WalletsTest, BIP32_SaltedAccount) { BIP32_Node seedNode; - seedNode.initFromSeed(seed); + seedNode.initFromSeed(rawEntropy); for (auto& derId : derivationPath2) seedNode.derivePrivate(derId); @@ -7062,7 +7175,7 @@ TEST_F(WalletsTest, BIP32_SaltedAccount) //derive from seed { BIP32_Node seedNode; - seedNode.initFromSeed(seed); + seedNode.initFromSeed(rawEntropy); for (auto& derId : derivationPath1) seedNode.derivePrivate(derId); @@ -7079,7 +7192,7 @@ TEST_F(WalletsTest, BIP32_SaltedAccount) { BIP32_Node seedNode; - seedNode.initFromSeed(seed); + seedNode.initFromSeed(rawEntropy); for (auto& derId : derivationPath2) seedNode.derivePrivate(derId); @@ -7102,8 +7215,6 @@ TEST_F(WalletsTest, ECDH_Account) //create blank wallet string filename, woFilename; - auto&& seed = CryptoPRNG::generateRandom(32); - auto&& privKey1 = READHEX( "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); auto&& pubKey1 = CryptoECDSA().ComputePublicKey(privKey1, true); @@ -7123,8 +7234,11 @@ TEST_F(WalletsTest, ECDH_Account) { //create empty wallet - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, seed, passphrase, controlPass_); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Virgin)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass_, homedir_); auto passphraseLbd = [&passphrase] (const set&) @@ -7372,7 +7486,7 @@ TEST_F(WalletsTest, ECDH_Account) TEST_F(WalletsTest, AssetPathResolution) { //seed shared across all wallet instances - auto seed = CryptoPRNG::generateRandom(32); + auto rawEntropy = CryptoPRNG::generateRandom(32); vector derPath = { 0x800012ab, @@ -7381,7 +7495,7 @@ TEST_F(WalletsTest, AssetPathResolution) }; BIP32_Node node; - node.initFromSeed(seed); + node.initFromSeed(rawEntropy); auto seedFingerprint = node.getThisFingerprint(); for (auto& step : derPath) @@ -7430,9 +7544,11 @@ TEST_F(WalletsTest, AssetPathResolution) { //empty wallet + custom account - auto wlt = AssetWallet_Single::createFromSeed_BIP32_Blank( - homedir_, seed, - SecureBinaryData(), SecureBinaryData()); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + rawEntropy, Armory::Seeds::SeedType::BIP32_Virgin)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), {}, {}, homedir_); auto account = wlt->makeNewBip32AccTypeObject(derPath); account->setMain(true); @@ -7470,26 +7586,9 @@ TEST_F(WalletsTest, AssetPathResolution) //empty WO wallet auto wltWO = AssetWallet_Single::createBlank(homedir_, "walletWO1", {}); - auto pubkey = pubNode.getPublicKey(); - auto chaincode = pubNode.getChaincode(); - - auto pubRootAsset = make_shared( - AssetId(0, 0, 0), //not relevant, this stuff is ignored in this context - - pubkey, //pub key - nullptr, //no priv key, this is a public node - chaincode, //have to pass the chaincode too - - //aesthetical stuff, not mandatory, not useful for the crypto side of things - pubNode.getDepth(), pubNode.getLeafID(), pubNode.getParentFingerprint(), seedFingerprint, - - //derivation path for this root, used for path discovery & PSBT - derPath - ); - //add account - auto mainAccType = - AccountType_BIP32::makeFromDerPaths(seedFingerprint, {derPath}); + auto mainAccType = AccountType_BIP32::makeFromDerPaths( + seedFingerprint, {derPath}); mainAccType->setMain(true); mainAccType->setAddressLookup(10); mainAccType->setNodes({0}); @@ -7513,9 +7612,11 @@ TEST_F(WalletsTest, isAssetIdInUse) auto passphrase = SecureBinaryData::fromString("password"); //create regular wallet - auto seed = CryptoPRNG::generateRandom(32); - auto wlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, seed, passphrase, controlPass_, 10); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass_, homedir_, 10); //grab a bunch of addresses of various types map addrHashesInUse; @@ -8328,9 +8429,11 @@ TEST_F(WalletMetaDataTest, Comments) //create regular wallet string filename; { - auto&& seed = CryptoPRNG::generateRandom(32); - auto wlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, seed, passphrase, controlPass, 10); + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto wlt = AssetWallet_Single::createFromSeed( + move(seed), passphrase, controlPass, homedir_, 10); filename = wlt->getDbFilename(); //set comments @@ -8400,7 +8503,8 @@ class BackupTests : public ::testing::Test Armory::Config::parseArgs({ "--offline", - "--datadir=./fakehomedir" }, + "--datadir=./fakehomedir", + "--testnet" }, Armory::Config::ProcessType::DB); } @@ -8415,7 +8519,7 @@ class BackupTests : public ::testing::Test ///////////////////////////////////////////////////////////////////////////// bool compareWalletWithBackup( std::shared_ptr assetWlt, - const string& path, + const string& path, const SecureBinaryData& pass, const SecureBinaryData& control) { unsigned controlPassCount = 0; @@ -8482,6 +8586,7 @@ class BackupTests : public ::testing::Test // EXPECT_EQ(address->getPrefixedHash(), newAddr->getPrefixedHash()); EXPECT_EQ(privKey, newKey); + EXPECT_EQ(assetID.first, newID.first); } METHOD_ASSERT_EQ(keyPassCount, 10U); @@ -8492,19 +8597,19 @@ class BackupTests : public ::testing::Test //////////////////////////////////////////////////////////////////////////////// TEST_F(BackupTests, Easy16) { - for (const auto& index : Armory::Backups::BackupEasy16::eligibleIndexes_) + for (const auto& index : Armory::Seeds::Easy16Codec::eligibleIndexes_) { auto root = CryptoPRNG::generateRandom(32); //encode the root - auto encoded = Armory::Backups::BackupEasy16::encode(root.getRef(), index); + auto encoded = Armory::Seeds::Easy16Codec::encode(root.getRef(), index); ASSERT_EQ(encoded.size(), 2ULL); - auto decoded = Armory::Backups::BackupEasy16::decode(encoded); + auto decoded = Armory::Seeds::Easy16Codec::decode(encoded); ASSERT_EQ(decoded.checksumIndexes_.size(), 2ULL); - EXPECT_EQ(decoded.checksumIndexes_[0], index); - EXPECT_EQ(decoded.checksumIndexes_[1], index); + EXPECT_EQ(decoded.checksumIndexes_[0], (uint8_t)index); + EXPECT_EQ(decoded.checksumIndexes_[1], (uint8_t)index); EXPECT_EQ(decoded.data_, root); } @@ -8514,7 +8619,7 @@ TEST_F(BackupTests, Easy16) TEST_F(BackupTests, Easy16_Repair) { /*NOTE: this test will lead to a lot of hashing*/ - auto corruptLine = [](vector& lines, + auto corruptLine = [](vector& lines, uint8_t lineSelect, uint8_t wordSelect, uint8_t charSelect, uint8_t newVal) { auto& line = lines[lineSelect]; @@ -8528,7 +8633,7 @@ TEST_F(BackupTests, Easy16_Repair) char newChar; while (true) { - newChar = Armory::Backups::BackupEasy16::e16chars_[newVal % 16]; + newChar = Armory::Seeds::Easy16Codec::e16chars_[newVal % 16]; if (newChar != val) break; @@ -8545,9 +8650,10 @@ TEST_F(BackupTests, Easy16_Repair) for (unsigned i=0; i<64; i++) { auto root = prng.generateRandom(32); - + //encode the root - auto encoded = Armory::Backups::BackupEasy16::encode(root.getRef(), 0); + auto encoded = Armory::Seeds::Easy16Codec::encode(root.getRef(), + Armory::Seeds::BackupType::Armory135); ASSERT_EQ(encoded.size(), 2ULL); //corrupt one character in one line @@ -8563,7 +8669,7 @@ TEST_F(BackupTests, Easy16_Repair) ASSERT_NE(encoded[lineSelect], corrupted[lineSelect]); //decode the corrupted data, should yield an incorrect value - auto decoded = Armory::Backups::BackupEasy16::decode(corrupted); + auto decoded = Armory::Seeds::Easy16Codec::decode(corrupted); ASSERT_EQ(decoded.checksumIndexes_.size(), 2ULL); if (lineSelect == 0) { @@ -8581,7 +8687,7 @@ TEST_F(BackupTests, Easy16_Repair) //attempt to repair, may fail because of collisions (no unique solution) try { - auto result = Armory::Backups::BackupEasy16::repair(decoded); + auto result = Armory::Seeds::Easy16Codec::repair(decoded); if (result) { ASSERT_EQ(decoded.repairedIndexes_.size(), 2ULL); @@ -8592,7 +8698,7 @@ TEST_F(BackupTests, Easy16_Repair) ++succesfulRepairs; } } - catch (const Armory::Backups::Easy16RepairError&) + catch (const Armory::Seeds::Easy16RepairError&) {} } @@ -8604,7 +8710,8 @@ TEST_F(BackupTests, Easy16_Repair) auto root = prng.generateRandom(32); //encode the root - auto encoded = Armory::Backups::BackupEasy16::encode(root.getRef(), 0); + auto encoded = Armory::Seeds::Easy16Codec::encode(root.getRef(), + Armory::Seeds::BackupType::Armory135); ASSERT_EQ(encoded.size(), 2ULL); //corrupt 2 characters in one line @@ -8627,7 +8734,7 @@ TEST_F(BackupTests, Easy16_Repair) ASSERT_NE(encoded[lineSelect], corrupted[lineSelect]); //decode, should yield an incorrect value - auto decoded = Armory::Backups::BackupEasy16::decode(corrupted); + auto decoded = Armory::Seeds::Easy16Codec::decode(corrupted); ASSERT_EQ(decoded.checksumIndexes_.size(), 2ULL); if (lineSelect == 0) { @@ -8643,7 +8750,7 @@ TEST_F(BackupTests, Easy16_Repair) EXPECT_NE(root, decoded.data_); //attempt to repair, should fail - auto result = Armory::Backups::BackupEasy16::repair(decoded); + auto result = Armory::Seeds::Easy16Codec::repair(decoded); if (result) { EXPECT_NE(decoded.data_, root); @@ -8657,7 +8764,8 @@ TEST_F(BackupTests, Easy16_Repair) auto root = prng.generateRandom(32); //encode the root - auto encoded = Armory::Backups::BackupEasy16::encode(root.getRef(), 0); + auto encoded = Armory::Seeds::Easy16Codec::encode(root.getRef(), + Armory::Seeds::BackupType::Armory135); ASSERT_EQ(encoded.size(), 2ULL); //corrupt 1 character per line @@ -8676,7 +8784,7 @@ TEST_F(BackupTests, Easy16_Repair) corruptLine(corrupted, 1, wordSelect2, charSelect2, newVal2); //decode, should yield an incorrect value - auto decoded = Armory::Backups::BackupEasy16::decode(corrupted); + auto decoded = Armory::Seeds::Easy16Codec::decode(corrupted); ASSERT_EQ(decoded.checksumIndexes_.size(), 2ULL); EXPECT_NE(decoded.checksumIndexes_[0], 0); EXPECT_NE(decoded.checksumIndexes_[1], 0); @@ -8684,7 +8792,7 @@ TEST_F(BackupTests, Easy16_Repair) //attempt to repair, may fail because of collisions (no evident solution) try { - auto result = Armory::Backups::BackupEasy16::repair(decoded); + auto result = Armory::Seeds::Easy16Codec::repair(decoded); if (result) { ASSERT_EQ(decoded.repairedIndexes_.size(), 2ULL); @@ -8698,7 +8806,7 @@ TEST_F(BackupTests, Easy16_Repair) ++succesfulRepairs; } } - catch (const Armory::Backups::Easy16RepairError&) + catch (const Armory::Seeds::Easy16RepairError&) {} } @@ -8711,14 +8819,14 @@ TEST_F(BackupTests, SecurePrint) auto root = CryptoPRNG::generateRandom(32); //encrypt the root - Armory::Backups::SecurePrint spEncr; + Armory::Seeds::SecurePrint spEncr; auto encryptedData = spEncr.encrypt(root, {}); ASSERT_FALSE(spEncr.getPassphrase().empty()); ASSERT_EQ(encryptedData.first.getSize(), 32ULL); ASSERT_EQ(encryptedData.second.getSize(), 0ULL); EXPECT_NE(encryptedData.first, root); - Armory::Backups::SecurePrint spDecr; + Armory::Seeds::SecurePrint spDecr; auto decryptedData = spDecr.decrypt(encryptedData.first, spEncr.getPassphrase()); @@ -8728,7 +8836,7 @@ TEST_F(BackupTests, SecurePrint) //with chaincode auto chaincode = CryptoPRNG::generateRandom(32); - Armory::Backups::SecurePrint spWithCC; + Armory::Seeds::SecurePrint spWithCC; auto dataWithCC = spWithCC.encrypt(root, chaincode); ASSERT_FALSE(spWithCC.getPassphrase().empty()); @@ -8739,7 +8847,7 @@ TEST_F(BackupTests, SecurePrint) EXPECT_NE(spEncr.getPassphrase(), spWithCC.getPassphrase()); EXPECT_NE(encryptedData.first, dataWithCC.first); - Armory::Backups::SecurePrint spDecrWithCC; + Armory::Seeds::SecurePrint spDecrWithCC; auto decrRoot = spDecrWithCC.decrypt( dataWithCC.first, spWithCC.getPassphrase()); @@ -8759,7 +8867,7 @@ TEST_F(BackupTests, SecurePrint) ASSERT_GE(mangledPass.getSize(), 4ULL); mangledPass.getPtr()[3] ^= 0xFF; - Armory::Backups::SecurePrint spDecrWithCC; + Armory::Seeds::SecurePrint spDecrWithCC; auto decrypted = spDecrWithCC.decrypt( dataWithCC.first, mangledPass); @@ -8780,7 +8888,7 @@ TEST_F(BackupTests, SecurePrint) auto passB58 = BinaryData::fromString( BtcUtils::base58_encode(passphrase)); - Armory::Backups::SecurePrint spDecrWithCC; + Armory::Seeds::SecurePrint spDecrWithCC; auto decrypted = spDecrWithCC.decrypt( dataWithCC.first, passB58); @@ -8793,7 +8901,7 @@ TEST_F(BackupTests, SecurePrint) //mismatched pass { - Armory::Backups::SecurePrint spDecrWithCC; + Armory::Seeds::SecurePrint spDecrWithCC; auto decrypted = spDecrWithCC.decrypt( dataWithCC.first, spEncr.getPassphrase()); EXPECT_NE(decrypted, dataWithCC.first); @@ -8804,13 +8912,14 @@ TEST_F(BackupTests, SecurePrint) TEST_F(BackupTests, BackupStrings_Legacy) { //create a legacy wallet - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135( + Armory::Seeds::ClearTextSeed_Armory135::LegacyType::Armory135)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries auto passLbd = [](const set&)->SecureBinaryData @@ -8818,43 +8927,135 @@ TEST_F(BackupTests, BackupStrings_Legacy) return SecureBinaryData::fromString("passphrase"); }; assetWlt->setPassphrasePromptLambda(passLbd); - - auto backupData = Armory::Backups::Helpers::getWalletBackup(assetWlt); + auto backupData = Armory::Seeds::Helpers::getWalletBackup(assetWlt); + auto backupEasy16 = dynamic_cast(backupData.get()); auto newPass = CryptoPRNG::generateRandom(10); auto newCtrl = CryptoPRNG::generateRandom(10); auto callback = [&backupData, &newPass, &newCtrl]( - const Armory::Backups::RestorePromptType promptType, - const vector checksums, SecureBinaryData& extra)->bool + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply { - switch (promptType) + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) { - case Armory::Backups::RestorePromptType::Passphrase: + case BridgeProto::RestorePrompt::kGetPassphrases: { - extra = newPass; - return true; + auto passphrases = reply.mutable_passphrases(); + passphrases->set_privkey(newPass.toCharPtr(), newPass.getSize()); + passphrases->set_control(newCtrl.toCharPtr(), newCtrl.getSize()); + reply.set_success(true); + break; } - case Armory::Backups::RestorePromptType::Control: + case BridgeProto::RestorePrompt::kCheckWalletId: { - extra = newCtrl; - return true; + auto checkWalleIdMsg = prompt.check_wallet_id(); + EXPECT_EQ(checkWalleIdMsg.wallet_id(), backupData->getWalletId()); + + EXPECT_EQ(checkWalleIdMsg.backup_type(), + (int)Armory::Seeds::BackupType::Armory135); + reply.set_success(true); + break; + } + + default: + reply.set_success(false); } + return reply; + }; - case Armory::Backups::RestorePromptType::Id: + string newHomeDir("./newhomedir"); + DBUtils::removeDirectory(newHomeDir); + mkdir(newHomeDir); + + string filename; + { + //restore wallet + auto backupCopy = Backup_Easy16::fromLines({ + backupEasy16->getRoot(Backup_Easy16::LineIndex::One, false), + backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, false), + }); + auto newWltPtr = Armory::Seeds::Helpers::restoreFromBackup( + move(backupCopy), newHomeDir, callback); + EXPECT_NE(newWltPtr, nullptr); + + auto passLbd2 = [&newPass](const set&)->SecureBinaryData { - EXPECT_EQ(extra, SecureBinaryData::fromString(backupData.wltId_)); - - EXPECT_EQ(checksums.size(), 2ULL); - for (const auto& chksum : checksums) - EXPECT_EQ(chksum, 0); + return newPass; + }; + newWltPtr->setPassphrasePromptLambda(passLbd2); - return true; + auto newWalletSingle = dynamic_pointer_cast(newWltPtr); + auto backupData2 = Armory::Seeds::Helpers::getWalletBackup(newWalletSingle); + auto backupEasy16_2 = dynamic_cast(backupData2.get()); + + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::One, false), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::One, false)); + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, false), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::Two, false)); + + EXPECT_EQ(backupEasy16->getWalletId(), backupEasy16_2->getWalletId()); + + filename = newWltPtr->getDbFilename(); + } + + EXPECT_TRUE(compareWalletWithBackup(assetWlt, filename, newPass, newCtrl)); + DBUtils::removeDirectory(newHomeDir); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST_F(BackupTests, BackupStrings_Legacy_Armory200a) +{ + //create a legacy wallet + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), + SecureBinaryData::fromString("passphrase"), + SecureBinaryData::fromString("control"), + homedir_, + 4); //set lookup computation to 4 entries + + auto passLbd = [](const set&)->SecureBinaryData + { + return SecureBinaryData::fromString("passphrase"); + }; + assetWlt->setPassphrasePromptLambda(passLbd); + auto backupData = Armory::Seeds::Helpers::getWalletBackup(assetWlt); + auto backupEasy16 = dynamic_cast(backupData.get()); + + auto newPass = CryptoPRNG::generateRandom(10); + auto newCtrl = CryptoPRNG::generateRandom(10); + auto callback = [&backupData, &newPass, &newCtrl]( + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply + { + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) + { + case BridgeProto::RestorePrompt::kGetPassphrases: + { + auto passphrases = reply.mutable_passphrases(); + passphrases->set_privkey(newPass.toCharPtr(), newPass.getSize()); + passphrases->set_control(newCtrl.toCharPtr(), newCtrl.getSize()); + reply.set_success(true); + break; + } + + case BridgeProto::RestorePrompt::kCheckWalletId: + { + auto checkWalleIdMsg = prompt.check_wallet_id(); + EXPECT_EQ(checkWalleIdMsg.wallet_id(), backupData->getWalletId()); + + EXPECT_EQ(checkWalleIdMsg.backup_type(), + (int)Armory::Seeds::BackupType::Armory200a); + reply.set_success(true); + break; } default: - return false; + reply.set_success(false); } + return reply; }; string newHomeDir("./newhomedir"); @@ -8864,10 +9065,31 @@ TEST_F(BackupTests, BackupStrings_Legacy) string filename; { //restore wallet - auto newWltPtr = Armory::Backups::Helpers::restoreFromBackup( - backupData.rootClear_, {}, newHomeDir, callback); + auto backupCopy = Backup_Easy16::fromLines({ + backupEasy16->getRoot(Backup_Easy16::LineIndex::One, false), + backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, false), + }); + auto newWltPtr = Armory::Seeds::Helpers::restoreFromBackup( + move(backupCopy), newHomeDir, callback); EXPECT_NE(newWltPtr, nullptr); - + + auto passLbd2 = [&newPass](const set&)->SecureBinaryData + { + return newPass; + }; + newWltPtr->setPassphrasePromptLambda(passLbd2); + + auto newWalletSingle = dynamic_pointer_cast(newWltPtr); + auto backupData2 = Armory::Seeds::Helpers::getWalletBackup(newWalletSingle); + auto backupEasy16_2 = dynamic_cast(backupData2.get()); + + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::One, false), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::One, false)); + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, false), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::Two, false)); + + EXPECT_EQ(backupEasy16->getWalletId(), backupEasy16_2->getWalletId()); + filename = newWltPtr->getDbFilename(); } @@ -8875,18 +9097,18 @@ TEST_F(BackupTests, BackupStrings_Legacy) DBUtils::removeDirectory(newHomeDir); } - //////////////////////////////////////////////////////////////////////////////// TEST_F(BackupTests, BackupStrings_Legacy_SecurePrint) { //create a legacy wallet - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135( + Armory::Seeds::ClearTextSeed_Armory135::LegacyType::Armory135)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries auto passLbd = [](const set&)->SecureBinaryData @@ -8895,43 +9117,39 @@ TEST_F(BackupTests, BackupStrings_Legacy_SecurePrint) }; assetWlt->setPassphrasePromptLambda(passLbd); - auto backupData = Armory::Backups::Helpers::getWalletBackup(assetWlt); + auto backupData = Armory::Seeds::Helpers::getWalletBackup(assetWlt); + auto backupEasy16 = dynamic_cast(backupData.get()); auto newPass = CryptoPRNG::generateRandom(10); auto newCtrl = CryptoPRNG::generateRandom(10); auto callback = [&backupData, &newPass, &newCtrl]( - const Armory::Backups::RestorePromptType promptType, - const vector checksums, SecureBinaryData& extra)->bool + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply { - switch (promptType) + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) { - case Armory::Backups::RestorePromptType::Passphrase: + case BridgeProto::RestorePrompt::kGetPassphrases: { - extra = newPass; - return true; + auto passphrases = reply.mutable_passphrases(); + passphrases->set_privkey(newPass.toCharPtr(), newPass.getSize()); + passphrases->set_control(newCtrl.toCharPtr(), newCtrl.getSize()); + reply.set_success(true); + break; } - case Armory::Backups::RestorePromptType::Control: + case BridgeProto::RestorePrompt::kCheckWalletId: { - extra = newCtrl; - return true; - } - - case Armory::Backups::RestorePromptType::Id: - { - if (extra != SecureBinaryData::fromString(backupData.wltId_)) - return false; - - EXPECT_EQ(checksums.size(), 2ULL); - for (const auto& chksum : checksums) - EXPECT_EQ(chksum, 0); - - return true; + auto checkWalleIdMsg = prompt.check_wallet_id(); + EXPECT_EQ(checkWalleIdMsg.backup_type(), + (int)Armory::Seeds::BackupType::Armory135); + reply.set_success(checkWalleIdMsg.wallet_id() == backupData->getWalletId()); + break; } default: - return false; + reply.set_success(false); } + return reply; }; string newHomeDir("./newhomedir"); @@ -8943,20 +9161,44 @@ TEST_F(BackupTests, BackupStrings_Legacy_SecurePrint) //try without sp pass try { - Armory::Backups::Helpers::restoreFromBackup( - backupData.rootEncr_, {}, newHomeDir, callback); + auto backupCopy = Backup_Easy16::fromLines({ + backupEasy16->getRoot(Backup_Easy16::LineIndex::One, true), + backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, true), + }); + Armory::Seeds::Helpers::restoreFromBackup( + move(backupCopy), newHomeDir, callback); ASSERT_TRUE(false); } - catch (const Armory::Backups::RestoreUserException& e) + catch (const Armory::Seeds::RestoreUserException& e) { EXPECT_EQ(e.what(), string("user rejected id")); } //try with secure print now - auto newWltPtr = Armory::Backups::Helpers::restoreFromBackup( - backupData.rootEncr_, backupData.spPass_, newHomeDir, callback); + auto backupCopy = Backup_Easy16::fromLines({ + backupEasy16->getRoot(Backup_Easy16::LineIndex::One, true), + backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, true)}, + backupEasy16->getSpPass()); + auto newWltPtr = Armory::Seeds::Helpers::restoreFromBackup( + move(backupCopy), newHomeDir, callback); EXPECT_NE(newWltPtr, nullptr); - + + auto passLbd2 = [&newPass](const set&)->SecureBinaryData + { + return newPass; + }; + newWltPtr->setPassphrasePromptLambda(passLbd2); + + auto newWalletSingle = dynamic_pointer_cast(newWltPtr); + auto backupData2 = Armory::Seeds::Helpers::getWalletBackup(newWalletSingle); + auto backupEasy16_2 = dynamic_cast(backupData2.get()); + + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::One, true), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::One, true)); + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, true), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::Two, true)); + EXPECT_EQ(backupEasy16->getWalletId(), backupEasy16_2->getWalletId()); + filename = newWltPtr->getDbFilename(); } @@ -8968,7 +9210,7 @@ TEST_F(BackupTests, BackupStrings_Legacy_SecurePrint) TEST_F(BackupTests, Easy16_AutoRepair) { /*NOTE: this test will lead to a lot of hashing*/ - auto corruptLine = [](vector& lines, + auto corruptLine = [](vector& lines, uint8_t lineSelect, uint8_t wordSelect, uint8_t charSelect, uint8_t newVal) { auto& line = lines[lineSelect]; @@ -8982,7 +9224,7 @@ TEST_F(BackupTests, Easy16_AutoRepair) char newChar; while (true) { - newChar = Armory::Backups::BackupEasy16::e16chars_[newVal % 16]; + newChar = Armory::Seeds::Easy16Codec::e16chars_[newVal % 16]; if (newChar != val) break; @@ -9001,7 +9243,15 @@ TEST_F(BackupTests, Easy16_AutoRepair) auto asset_single = make_shared( AssetId::getRootAssetId(), pubkey, nullptr); - return AssetWallet_Single::computeWalletID(derScheme, asset_single); + auto addrVec = derScheme->extendPublicChain(asset_single, 1, 1, nullptr); + if (addrVec.size() != 1) + throw runtime_error("unexpected chain derivation output"); + + auto firstEntry = dynamic_pointer_cast(addrVec[0]); + if (firstEntry == nullptr) + throw runtime_error("unexpected asset entry type"); + + return BtcUtils::computeID(firstEntry->getPubKey()->getUncompressedKey()); }; PRNG_Fortuna prng; @@ -9014,7 +9264,7 @@ TEST_F(BackupTests, Easy16_AutoRepair) auto wltID = computeWalletID(root); //encode the root - auto encoded = Armory::Backups::BackupEasy16::encode(root.getRef(), 0); + auto encoded = Easy16Codec::encode(root.getRef(), BackupType::Armory135); ASSERT_EQ(encoded.size(), 2ULL); //corrupt one character in one line @@ -9030,7 +9280,7 @@ TEST_F(BackupTests, Easy16_AutoRepair) ASSERT_NE(encoded[lineSelect], corrupted[lineSelect]); //decode the corrupted data, should yield an incorrect value - auto decoded = Armory::Backups::BackupEasy16::decode(corrupted); + auto decoded = Easy16Codec::decode(corrupted); ASSERT_EQ(decoded.checksumIndexes_.size(), 2ULL); if (lineSelect == 0) { @@ -9049,35 +9299,42 @@ TEST_F(BackupTests, Easy16_AutoRepair) try { auto userPrompt = [&wltID, &decoded, &succesfulRepairs]( - Armory::Backups::RestorePromptType promptType, - const vector& chksumIndexes, - SecureBinaryData& extra)->bool + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply { - switch (promptType) + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) { - case Armory::Backups::RestorePromptType::ChecksumError: + case BridgeProto::RestorePrompt::kChecksumError: { - EXPECT_EQ(chksumIndexes, decoded.checksumIndexes_); - return false; + EXPECT_EQ(prompt.checksum_error().index(0), decoded.checksumIndexes_[0]); + EXPECT_EQ(prompt.checksum_error().index(1), decoded.checksumIndexes_[1]); + reply.set_success(false); + break; } - case Armory::Backups::RestorePromptType::Id: + case BridgeProto::RestorePrompt::kCheckWalletId: { - EXPECT_EQ(chksumIndexes, decoded.checksumIndexes_); - string extraStr(extra.toCharPtr(), extra.getSize()); - if (extraStr == wltID) + EXPECT_EQ(prompt.check_wallet_id().backup_type(), + (int)BackupType::Armory135); + if (prompt.check_wallet_id().wallet_id() == wltID) ++succesfulRepairs; - return false; + reply.set_success(false); + break; } default: - return true; + reply.set_success(true); } + return reply; }; - Armory::Backups::Helpers::restoreFromBackup( - corrupted, BinaryDataRef(), string(), userPrompt); + auto backup = Backup_Easy16::fromLines({ + string_view(corrupted[0].toCharPtr(), corrupted[0].getSize()), + string_view(corrupted[1].toCharPtr(), corrupted[1].getSize()) + }); + Armory::Seeds::Helpers::restoreFromBackup( + move(backup), homedir_, userPrompt); } catch (const exception&) {} @@ -9090,14 +9347,14 @@ TEST_F(BackupTests, Easy16_AutoRepair) TEST_F(BackupTests, BackupStrings_LegacyWithChaincode_SecurePrint) { //create a legacy wallet - auto wltRoot = CryptoPRNG::generateRandom(32); - auto chaincode = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - wltRoot, //root as a r value - chaincode, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135( + CryptoPRNG::generateRandom(32), CryptoPRNG::generateRandom(32))); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), //root as a r value SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries auto passLbd = [](const set&)->SecureBinaryData @@ -9106,43 +9363,39 @@ TEST_F(BackupTests, BackupStrings_LegacyWithChaincode_SecurePrint) }; assetWlt->setPassphrasePromptLambda(passLbd); - auto backupData = Armory::Backups::Helpers::getWalletBackup(assetWlt); + auto backupData = Armory::Seeds::Helpers::getWalletBackup(assetWlt); + auto backupEasy16 = dynamic_cast(backupData.get()); auto newPass = CryptoPRNG::generateRandom(10); auto newCtrl = CryptoPRNG::generateRandom(10); auto callback = [&backupData, &newPass, &newCtrl]( - const Armory::Backups::RestorePromptType promptType, - const vector checksums, SecureBinaryData& extra)->bool + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply { - switch (promptType) - { - case Armory::Backups::RestorePromptType::Passphrase: + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) { - extra = newPass; - return true; - } - - case Armory::Backups::RestorePromptType::Control: + case BridgeProto::RestorePrompt::kGetPassphrases: { - extra = newCtrl; - return true; + auto passphrases = reply.mutable_passphrases(); + passphrases->set_privkey(newPass.toCharPtr(), newPass.getSize()); + passphrases->set_control(newCtrl.toCharPtr(), newCtrl.getSize()); + reply.set_success(true); + break; } - case Armory::Backups::RestorePromptType::Id: + case BridgeProto::RestorePrompt::kCheckWalletId: { - if (extra != SecureBinaryData::fromString(backupData.wltId_)) - return false; - - EXPECT_EQ(checksums.size(), 4ULL); - for (const auto& chksum : checksums) - EXPECT_EQ(chksum, 0); - - return true; + auto checkWalleIdMsg = prompt.check_wallet_id(); + EXPECT_EQ(checkWalleIdMsg.backup_type(), + (int)Armory::Seeds::BackupType::Armory135); + reply.set_success(checkWalleIdMsg.wallet_id() == backupData->getWalletId()); + break; } default: - return false; + reply.set_success(false); } + return reply; }; string newHomeDir("./newhomedir"); @@ -9151,33 +9404,58 @@ TEST_F(BackupTests, BackupStrings_LegacyWithChaincode_SecurePrint) string filename; { - vector rootData; - auto insertVector = [&rootData](const vector& vec) - { - for (const auto& str : vec) - rootData.emplace_back((const uint8_t*)str.c_str(), str.size()); - }; - - insertVector(backupData.rootEncr_); - insertVector(backupData.chaincodeEncr_); - //try without sp pass try { - Armory::Backups::Helpers::restoreFromBackup( - backupData.rootEncr_, {}, newHomeDir, callback); + auto backupCopy = Backup_Easy16::fromLines({ + backupEasy16->getRoot(Backup_Easy16::LineIndex::One, true), + backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, true), + backupEasy16->getChaincode(Backup_Easy16::LineIndex::One, true), + backupEasy16->getChaincode(Backup_Easy16::LineIndex::Two, true), + }); + Armory::Seeds::Helpers::restoreFromBackup( + move(backupCopy), newHomeDir, callback); ASSERT_TRUE(false); } - catch (const Armory::Backups::RestoreUserException& e) + catch (const Armory::Seeds::RestoreUserException& e) { EXPECT_EQ(e.what(), string("user rejected id")); } //try with secure print now - auto newWltPtr = Armory::Backups::Helpers::restoreFromBackup( - rootData, backupData.spPass_, newHomeDir, callback); + auto backupCopy = Backup_Easy16::fromLines({ + backupEasy16->getRoot(Backup_Easy16::LineIndex::One, true), + backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, true), + backupEasy16->getChaincode(Backup_Easy16::LineIndex::One, true), + backupEasy16->getChaincode(Backup_Easy16::LineIndex::Two, true)}, + backupEasy16->getSpPass() + ); + auto newWltPtr = Armory::Seeds::Helpers::restoreFromBackup( + move(backupCopy), newHomeDir, callback); EXPECT_NE(newWltPtr, nullptr); - + + auto passLbd2 = [&newPass](const set&)->SecureBinaryData + { + return newPass; + }; + newWltPtr->setPassphrasePromptLambda(passLbd2); + + auto newWalletSingle = dynamic_pointer_cast(newWltPtr); + auto backupData2 = Armory::Seeds::Helpers::getWalletBackup(newWalletSingle); + auto backupEasy16_2 = dynamic_cast(backupData2.get()); + + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::One, true), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::One, true)); + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, true), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::Two, true)); + + EXPECT_EQ(backupEasy16->getChaincode(Backup_Easy16::LineIndex::One, true), + backupEasy16_2->getChaincode(Backup_Easy16::LineIndex::One, true)); + EXPECT_EQ(backupEasy16->getChaincode(Backup_Easy16::LineIndex::Two, true), + backupEasy16_2->getChaincode(Backup_Easy16::LineIndex::Two, true)); + + EXPECT_EQ(backupEasy16->getWalletId(), backupEasy16_2->getWalletId()); + filename = newWltPtr->getDbFilename(); } @@ -9189,12 +9467,14 @@ TEST_F(BackupTests, BackupStrings_LegacyWithChaincode_SecurePrint) TEST_F(BackupTests, BackupStrings_BIP32) { //create a legacy wallet - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - move(wltRoot), //root as a r value + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Structured)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), //root as a r value SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries auto passLbd = [](const set&)->SecureBinaryData @@ -9203,42 +9483,41 @@ TEST_F(BackupTests, BackupStrings_BIP32) }; assetWlt->setPassphrasePromptLambda(passLbd); - auto backupData = Armory::Backups::Helpers::getWalletBackup(assetWlt); + auto backupData = Armory::Seeds::Helpers::getWalletBackup(assetWlt); + auto backupEasy16 = dynamic_cast(backupData.get()); auto newPass = CryptoPRNG::generateRandom(10); auto newCtrl = CryptoPRNG::generateRandom(10); auto callback = [&backupData, &newPass, &newCtrl]( - const Armory::Backups::RestorePromptType promptType, - const vector checksums, SecureBinaryData& extra)->bool + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply { - switch (promptType) - { - case Armory::Backups::RestorePromptType::Passphrase: + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) { - extra = newPass; - return true; - } - - case Armory::Backups::RestorePromptType::Control: + case BridgeProto::RestorePrompt::kGetPassphrases: { - extra = newCtrl; - return true; + auto passphrases = reply.mutable_passphrases(); + passphrases->set_privkey(newPass.toCharPtr(), newPass.getSize()); + passphrases->set_control(newCtrl.toCharPtr(), newCtrl.getSize()); + reply.set_success(true); + break; } - case Armory::Backups::RestorePromptType::Id: + case BridgeProto::RestorePrompt::kCheckWalletId: { - EXPECT_EQ(extra, SecureBinaryData::fromString(backupData.wltId_)); - - EXPECT_EQ(checksums.size(), 2U); - for (const auto& chksum : checksums) - EXPECT_EQ(chksum, 1); + auto checkWalleIdMsg = prompt.check_wallet_id(); + EXPECT_EQ(checkWalleIdMsg.wallet_id(), backupData->getWalletId()); - return true; + EXPECT_EQ(checkWalleIdMsg.backup_type(), + (int)Armory::Seeds::BackupType::Armory200b); + reply.set_success(true); + break; } default: - return false; + reply.set_success(false); } + return reply; }; string newHomeDir("./newhomedir"); @@ -9248,10 +9527,31 @@ TEST_F(BackupTests, BackupStrings_BIP32) string filename; { //restore wallet - auto newWltPtr = Armory::Backups::Helpers::restoreFromBackup( - backupData.rootClear_, {}, newHomeDir, callback); - EXPECT_NE(newWltPtr, nullptr); - + auto backupCopy = Backup_Easy16::fromLines({ + backupEasy16->getRoot(Backup_Easy16::LineIndex::One, false), + backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, false), + }); + auto newWltPtr = Armory::Seeds::Helpers::restoreFromBackup( + move(backupCopy), newHomeDir, callback); + ASSERT_NE(newWltPtr, nullptr); + + auto passLbd2 = [&newPass](const set&)->SecureBinaryData + { + return newPass; + }; + newWltPtr->setPassphrasePromptLambda(passLbd2); + + auto newWalletSingle = dynamic_pointer_cast(newWltPtr); + auto backupData2 = Armory::Seeds::Helpers::getWalletBackup(newWalletSingle); + auto backupEasy16_2 = dynamic_cast(backupData2.get()); + + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::One, false), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::One, false)); + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, false), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::Two, false)); + + EXPECT_EQ(backupEasy16->getWalletId(), backupEasy16_2->getWalletId()); + filename = newWltPtr->getDbFilename(); } @@ -9260,15 +9560,18 @@ TEST_F(BackupTests, BackupStrings_BIP32) } //////////////////////////////////////////////////////////////////////////////// -TEST_F(BackupTests, BackupStrings_BIP32_Custom) +TEST_F(BackupTests, BackupStrings_BIP32_Virgin) { //create a legacy wallet - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromSeed_BIP32( - homedir_, - move(wltRoot), //root as a r value + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_BIP32( + Armory::Seeds::SeedType::BIP32_Virgin + )); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData::fromString("passphrase"), SecureBinaryData::fromString("control"), + homedir_, 4); //set lookup computation to 4 entries auto passLbd = [](const set&)->SecureBinaryData @@ -9277,43 +9580,42 @@ TEST_F(BackupTests, BackupStrings_BIP32_Custom) }; assetWlt->setPassphrasePromptLambda(passLbd); - auto backupData = Armory::Backups::Helpers::getWalletBackup( - assetWlt, Armory::Backups::BackupType::BIP32_Seed_Virgin); + auto backupData = Armory::Seeds::Helpers::getWalletBackup(assetWlt); + auto backupEasy16 = dynamic_cast( + backupData.get()); auto newPass = CryptoPRNG::generateRandom(10); auto newCtrl = CryptoPRNG::generateRandom(10); auto callback = [&backupData, &newPass, &newCtrl]( - const Armory::Backups::RestorePromptType promptType, - const vector checksums, SecureBinaryData& extra)->bool + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply { - switch (promptType) - { - case Armory::Backups::RestorePromptType::Passphrase: + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) { - extra = newPass; - return true; - } - - case Armory::Backups::RestorePromptType::Control: + case BridgeProto::RestorePrompt::kGetPassphrases: { - extra = newCtrl; - return true; + auto passphrases = reply.mutable_passphrases(); + passphrases->set_privkey(newPass.toCharPtr(), newPass.getSize()); + passphrases->set_control(newCtrl.toCharPtr(), newCtrl.getSize()); + reply.set_success(true); + break; } - case Armory::Backups::RestorePromptType::Id: + case BridgeProto::RestorePrompt::kCheckWalletId: { - EXPECT_EQ(extra, SecureBinaryData::fromString(backupData.wltId_)); - - EXPECT_EQ(checksums.size(), 2U); - for (const auto& chksum : checksums) - EXPECT_EQ(chksum, 15); + auto checkWalleIdMsg = prompt.check_wallet_id(); + EXPECT_EQ(checkWalleIdMsg.wallet_id(), backupData->getWalletId()); - return true; + EXPECT_EQ(checkWalleIdMsg.backup_type(), + (int)Armory::Seeds::BackupType::Armory200c); + reply.set_success(true); + break; } default: - return false; + reply.set_success(false); } + return reply; }; string newHomeDir("./newhomedir"); @@ -9321,10 +9623,14 @@ TEST_F(BackupTests, BackupStrings_BIP32_Custom) mkdir(newHomeDir); //restore wallet - auto newWltPtr = Armory::Backups::Helpers::restoreFromBackup( - backupData.rootClear_, {}, newHomeDir, callback); - EXPECT_NE(newWltPtr, nullptr); - + auto backupCopy = Backup_Easy16::fromLines({ + backupEasy16->getRoot(Backup_Easy16::LineIndex::One, false), + backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, false), + }); + auto newWltPtr = Armory::Seeds::Helpers::restoreFromBackup( + move(backupCopy), newHomeDir, callback); + ASSERT_NE(newWltPtr, nullptr); + //check wallet id EXPECT_EQ(assetWlt->getID(), newWltPtr->getID()); @@ -9332,9 +9638,283 @@ TEST_F(BackupTests, BackupStrings_BIP32_Custom) auto loadedIDs = newWltPtr->getAccountIDs(); EXPECT_EQ(loadedIDs.size(), 0ULL); + auto passLbd2 = [&newPass](const set&)->SecureBinaryData + { + return newPass; + }; + newWltPtr->setPassphrasePromptLambda(passLbd2); + + auto newWalletSingle = dynamic_pointer_cast(newWltPtr); + auto backupData2 = Armory::Seeds::Helpers::getWalletBackup(newWalletSingle); + auto backupEasy16_2 = dynamic_cast( + backupData2.get()); + + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::One, false), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::One, false)); + EXPECT_EQ(backupEasy16->getRoot(Backup_Easy16::LineIndex::Two, false), + backupEasy16_2->getRoot(Backup_Easy16::LineIndex::Two, false)); + + EXPECT_EQ(backupEasy16->getWalletId(), backupEasy16_2->getWalletId()); + DBUtils::removeDirectory(newHomeDir); } +//////////////////////////////////////////////////////////////////////////////// +TEST_F(BackupTests, BackupStrings_BIP32_FromBase58) +{ + auto b58seed = string_view{ + "tprv8ZgxMBicQKsPd9TeAdPADNnSyH9SSUUbTVeFszDE23Ki6TBB5nCefAdHkK8Fm3qMQR6sHwA56zqRmKmxnHk37JkiFzvncDqoKmPWubu7hDF"}; + + auto newPass = CryptoPRNG::generateRandom(10); + auto newCtrl = CryptoPRNG::generateRandom(10); + auto callback = [&newPass, &newCtrl]( + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply + { + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) + { + case BridgeProto::RestorePrompt::kGetPassphrases: + { + auto passphrases = reply.mutable_passphrases(); + passphrases->set_privkey(newPass.toCharPtr(), newPass.getSize()); + passphrases->set_control(newCtrl.toCharPtr(), newCtrl.getSize()); + reply.set_success(true); + break; + } + + case BridgeProto::RestorePrompt::kCheckWalletId: + { + auto checkWalleIdMsg = prompt.check_wallet_id(); + EXPECT_EQ(checkWalleIdMsg.wallet_id(), "poUtmfmp"); + + EXPECT_EQ(checkWalleIdMsg.backup_type(), (int)BackupType::Base58); + reply.set_success(true); + break; + } + + default: + reply.set_success(false); + } + return reply; + }; + + //create bip32 wallet from xpriv, check it yields same xpriv + string filename; + { + auto backup = Backup_Base58::fromString(b58seed); + auto wallet = Helpers::restoreFromBackup( + move(backup), homedir_, callback); + ASSERT_NE(wallet, nullptr); + + auto passLbd = [newPass](const set&)->SecureBinaryData + { + return newPass; + }; + wallet->setPassphrasePromptLambda(passLbd); + + auto walletSingle = dynamic_pointer_cast(wallet); + auto backupData = Helpers::getWalletBackup(walletSingle); + auto backupBase58 = dynamic_cast(backupData.get()); + EXPECT_EQ(backupBase58->getBase58String(), b58seed); + filename = wallet->getDbFilename(); + } + + //load wallet from file and check xpriv again + { + auto controlPassLbd = [&newCtrl]( + const set&)->SecureBinaryData + { + return newCtrl; + }; + + //load it, newCtrl should work for the control passphrase + auto loadedWlt = AssetWallet::loadMainWalletFromFile( + filename, controlPassLbd); + ASSERT_NE(loadedWlt, nullptr); + + auto passLbd = [newPass](const set&)->SecureBinaryData + { + return newPass; + }; + loadedWlt->setPassphrasePromptLambda(passLbd); + + auto walletSingle = dynamic_pointer_cast(loadedWlt); + auto backupData = Helpers::getWalletBackup(walletSingle); + auto backupBase58 = dynamic_cast(backupData.get()); + EXPECT_EQ(backupBase58->getBase58String(), b58seed); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST_F(BackupTests, BackupStrings_BIP39) +{ + //create a legacy wallet + string filename; + unique_ptr seed( + new ClearTextSeed_BIP39( + ClearTextSeed_BIP39::Dictionnary::English_Trezor)); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), //root as a r value + SecureBinaryData::fromString("passphrase"), + SecureBinaryData::fromString("control"), + homedir_, + 4); //set lookup computation to 4 entries + + auto passLbd = [](const set&)->SecureBinaryData + { + return SecureBinaryData::fromString("passphrase"); + }; + auto walletId = assetWlt->getID(); + assetWlt->setPassphrasePromptLambda(passLbd); + auto backupDataBIP39 = Armory::Seeds::Helpers::getWalletBackup( + assetWlt, BackupType::BIP39); + auto backupDataArmory200d = Armory::Seeds::Helpers::getWalletBackup( + assetWlt, BackupType::Armory200d); + + EXPECT_EQ(walletId, backupDataBIP39->getWalletId()); + EXPECT_EQ(walletId, backupDataArmory200d->getWalletId()); + + //restore Armory200d lambda + auto newPass = CryptoPRNG::generateRandom(10); + auto newCtrl = CryptoPRNG::generateRandom(10); + auto callback = [&walletId, &newPass, &newCtrl]( + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply + { + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) + { + case BridgeProto::RestorePrompt::kGetPassphrases: + { + auto passphrases = reply.mutable_passphrases(); + passphrases->set_privkey(newPass.toCharPtr(), newPass.getSize()); + passphrases->set_control(newCtrl.toCharPtr(), newCtrl.getSize()); + reply.set_success(true); + break; + } + + case BridgeProto::RestorePrompt::kCheckWalletId: + { + auto checkWalleIdMsg = prompt.check_wallet_id(); + EXPECT_EQ(checkWalleIdMsg.wallet_id(), walletId); + EXPECT_EQ(checkWalleIdMsg.backup_type(), (int)BackupType::Armory200d); + reply.set_success(true); + break; + } + + default: + reply.set_success(false); + } + return reply; + }; + + string newHomeDir("./newhomedir"); + DBUtils::removeDirectory(newHomeDir); + mkdir(newHomeDir); + + { + auto backupE16 = dynamic_cast(backupDataArmory200d.get()); + ASSERT_NE(backupE16, nullptr); + auto backupE16Copy = Backup_Easy16::fromLines({ + backupE16->getRoot(Backup_Easy16::LineIndex::One, false), + backupE16->getRoot(Backup_Easy16::LineIndex::Two, false), + }); + auto newWltPtr = Armory::Seeds::Helpers::restoreFromBackup( + move(backupE16Copy), newHomeDir, callback); + ASSERT_NE(newWltPtr, nullptr); + + auto passLbd2 = [&newPass](const set&)->SecureBinaryData + { + return newPass; + }; + newWltPtr->setPassphrasePromptLambda(passLbd2); + + auto newWalletSingle = dynamic_pointer_cast(newWltPtr); + auto backupData2 = Armory::Seeds::Helpers::getWalletBackup( + newWalletSingle, BackupType::Armory200d); + auto backupE16_2 = dynamic_cast(backupData2.get()); + + EXPECT_EQ(backupE16->getRoot(Backup_Easy16::LineIndex::One, false), + backupE16_2->getRoot(Backup_Easy16::LineIndex::One, false)); + EXPECT_EQ(backupE16->getRoot(Backup_Easy16::LineIndex::Two, false), + backupE16_2->getRoot(Backup_Easy16::LineIndex::Two, false)); + EXPECT_EQ(backupE16->getWalletId(), backupE16_2->getWalletId()); + + filename = newWltPtr->getDbFilename(); + } + + EXPECT_TRUE(compareWalletWithBackup(assetWlt, filename, newPass, newCtrl)); + DBUtils::removeDirectory(newHomeDir); + mkdir(newHomeDir); + + //restore BIP39 lambda + auto newPass2 = CryptoPRNG::generateRandom(10); + auto newCtrl2 = CryptoPRNG::generateRandom(10); + auto callbackBip39 = [&walletId, &newPass2, &newCtrl2]( + BridgeProto::RestorePrompt prompt)->BridgeProto::RestoreReply + { + BridgeProto::RestoreReply reply; + switch (prompt.prompt_case()) + { + case BridgeProto::RestorePrompt::kGetPassphrases: + { + auto passphrases = reply.mutable_passphrases(); + passphrases->set_privkey(newPass2.toCharPtr(), newPass2.getSize()); + passphrases->set_control(newCtrl2.toCharPtr(), newCtrl2.getSize()); + reply.set_success(true); + break; + } + + case BridgeProto::RestorePrompt::kCheckWalletId: + { + auto checkWalleIdMsg = prompt.check_wallet_id(); + EXPECT_EQ(checkWalleIdMsg.wallet_id(), walletId); + EXPECT_EQ(checkWalleIdMsg.backup_type(), (int)BackupType::BIP39); + reply.set_success(true); + break; + } + + default: + reply.set_success(false); + } + return reply; + }; + + //restore from mnemonic string + { + //restore wallet + auto backupBIP39 = dynamic_cast(backupDataBIP39.get()); + ASSERT_NE(backupBIP39, nullptr); + + auto backupBIP39Copy = Backup_BIP39::fromMnemonicString( + backupBIP39->getMnemonicString()); + auto newWltPtr = Armory::Seeds::Helpers::restoreFromBackup( + move(backupBIP39Copy), newHomeDir, callbackBip39); + ASSERT_NE(newWltPtr, nullptr); + + auto passLbd2 = [&newPass2](const set&)->SecureBinaryData + { + return newPass2; + }; + newWltPtr->setPassphrasePromptLambda(passLbd2); + + auto newWalletSingle = dynamic_pointer_cast(newWltPtr); + auto backupData2 = Armory::Seeds::Helpers::getWalletBackup(newWalletSingle); + auto backupBIP39_2 = dynamic_cast(backupData2.get()); + + EXPECT_EQ(backupBIP39->getMnemonicString(), backupBIP39_2->getMnemonicString()); + EXPECT_EQ(backupBIP39->getWalletId(), backupBIP39_2->getWalletId()); + + filename = newWltPtr->getDbFilename(); + + //grab 10 addresses from restored wallet to get in sync with original + //otherwise the comparision will fail + for (int i=0; i<10; i++) + newWltPtr->getNewAddress(); + } + + EXPECT_TRUE(compareWalletWithBackup(assetWlt, filename, newPass2, newCtrl2)); + DBUtils::removeDirectory(newHomeDir); +} //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/cppForSwig/gtest/ZeroConfTests.cpp b/cppForSwig/gtest/ZeroConfTests.cpp index 792b91898..a3834aa11 100644 --- a/cppForSwig/gtest/ZeroConfTests.cpp +++ b/cppForSwig/gtest/ZeroConfTests.cpp @@ -12,6 +12,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "TestUtils.h" +#include "../Wallets/Seeds/Seeds.h" using namespace std; using namespace Armory::Signer; using namespace Armory::Config; @@ -2364,15 +2365,15 @@ TEST_F(ZeroConfTests_FullNode, Replace_ZC_Test) //// create assetWlt //// //create a root private key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData(), SecureBinaryData(), + homedir_, 10); //set lookup computation to 5 entries - + //register with db vector addrVec; @@ -2877,13 +2878,13 @@ TEST_F(ZeroConfTests_FullNode, RegisterAddress_AfterZC) //// create assetWlt //// //create a root private key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData(), SecureBinaryData(), + homedir_, 3); //set lookup computation to 3 entries //register with db @@ -3095,14 +3096,14 @@ TEST_F(ZeroConfTests_FullNode, ChainZC_RBFchild_Test) //// create assetWlt //// //create a root private key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData(), - SecureBinaryData(), - 10); //set lookup computation to 10 entries + SecureBinaryData(), + homedir_, + 10); //set lookup computation to 3 entries //register with db vector addrVec; @@ -3576,14 +3577,14 @@ TEST_F(ZeroConfTests_FullNode, TwoZC_CheckLedgers) //// create assetWlt //// //create a root private key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), - {}, - SecureBinaryData(), //empty passphrase + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), + SecureBinaryData(), SecureBinaryData(), - 5); + homedir_, + 5); //set lookup computation to 3 entries //register with db vector addrVec; @@ -4375,13 +4376,13 @@ TEST_F(ZeroConfTests_Supernode, ZC_Reorg) theBDMt_->start(DBSettings::initMode()); auto&& bdvID = DBTestUtils::registerBDV(clients_, BitcoinSettings::getMagicBytes()); - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a rvalue - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData(), SecureBinaryData(), + homedir_, 3); //set lookup computation to 3 entries auto addr1_ptr = assetWlt->getNewAddress(); auto addr2_ptr = assetWlt->getNewAddress(); @@ -4546,14 +4547,14 @@ TEST_F(ZeroConfTests_Supernode, ChainZC_RBFchild_Test) //// create assetWlt //// //create a root private key - auto&& wltRoot = CryptoPRNG::generateRandom(32); - auto assetWlt = AssetWallet_Single::createFromPrivateRoot_Armory135( - homedir_, - move(wltRoot), //root as a r value - {}, + unique_ptr seed( + new Armory::Seeds::ClearTextSeed_Armory135()); + auto assetWlt = AssetWallet_Single::createFromSeed( + move(seed), SecureBinaryData(), - SecureBinaryData(), - 10); //set lookup computation to 5 entries + SecureBinaryData(), + homedir_, + 10); //set lookup computation to 3 entries //register with db vector addrVec; diff --git a/cppForSwig/leveldbwin/README.txt b/cppForSwig/leveldbwin/README.txt deleted file mode 100644 index 5bec1c5d1..000000000 --- a/cppForSwig/leveldbwin/README.txt +++ /dev/null @@ -1,5 +0,0 @@ -This file directory is maintained in the repo solely for snappy compression support. - -The code itself doesn't require snappy, but the original port needed it in order to -compile on Windows in MSVS. As soon as I figure out how to cut the umbilical cord, -I will remove the snappy project from the MSVS solution and remove this directory. \ No newline at end of file diff --git a/cppForSwig/leveldbwin/build/msvc10/snappy/snappy.vcxproj b/cppForSwig/leveldbwin/build/msvc10/snappy/snappy.vcxproj deleted file mode 100644 index e7a2de166..000000000 --- a/cppForSwig/leveldbwin/build/msvc10/snappy/snappy.vcxproj +++ /dev/null @@ -1,164 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - - - - - - - - - - - - - {72639F93-D2E6-4220-AA46-E24C502E470C} - Win32Proj - snappy - - - - StaticLibrary - true - Unicode - v110 - - - StaticLibrary - true - Unicode - v110 - - - StaticLibrary - false - true - Unicode - v110 - - - StaticLibrary - false - true - Unicode - v110 - - - - - - - - - - - - - - - - - - - $(ProjectName)_d - $(SolutionDir)libs\IntermediateBuildFiles\$(Configuration).$(ProjectName)\ - $(SolutionDir)libs\$(Platform)\ - - - $(ProjectName)_d - - - $(SolutionDir)libs\IntermediateBuildFiles\$(Configuration).$(ProjectName)\ - $(SolutionDir)libs\$(Platform)\ - - - $(SolutionDir)libs\$(Platform) - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\..\snappy_src;..\..\..\win32_impl_src\; - - - Windows - true - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\..\snappy_src;..\..\..\win32_impl_src\; - - - Windows - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\..\snappy_src;..\..\..\win32_impl_src\; - MultiThreaded - - - Windows - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - ..\..\..\snappy_src;..\..\..\win32_impl_src\; - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/cppForSwig/leveldbwin/build/msvc10/snappy/snappy.vcxproj.filters b/cppForSwig/leveldbwin/build/msvc10/snappy/snappy.vcxproj.filters deleted file mode 100644 index fa3e05130..000000000 --- a/cppForSwig/leveldbwin/build/msvc10/snappy/snappy.vcxproj.filters +++ /dev/null @@ -1,41 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/cppForSwig/leveldbwin/snappy_src/snappy-internal.h b/cppForSwig/leveldbwin/snappy_src/snappy-internal.h deleted file mode 100644 index a32eda59f..000000000 --- a/cppForSwig/leveldbwin/snappy_src/snappy-internal.h +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Internals shared between the Snappy implementation and its unittest. - -#ifndef UTIL_SNAPPY_SNAPPY_INTERNAL_H_ -#define UTIL_SNAPPY_SNAPPY_INTERNAL_H_ - -#include "snappy-stubs-internal.h" - -namespace snappy { -namespace internal { - -class WorkingMemory { - public: - WorkingMemory() : large_table_(NULL) { } - ~WorkingMemory() { delete[] large_table_; } - - // Allocates and clears a hash table using memory in "*this", - // stores the number of buckets in "*table_size" and returns a pointer to - // the base of the hash table. - uint16* GetHashTable(size_t input_size, int* table_size); - - private: - uint16 small_table_[1<<10]; // 2KB - uint16* large_table_; // Allocated only when needed - - DISALLOW_COPY_AND_ASSIGN(WorkingMemory); -}; - -// Flat array compression that does not emit the "uncompressed length" -// prefix. Compresses "input" string to the "*op" buffer. -// -// REQUIRES: "input_length <= kBlockSize" -// REQUIRES: "op" points to an array of memory that is at least -// "MaxCompressedLength(input_length)" in size. -// REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero. -// REQUIRES: "table_size" is a power of two -// -// Returns an "end" pointer into "op" buffer. -// "end - op" is the compressed size of "input". -char* CompressFragment(const char* input, - size_t input_length, - char* op, - uint16* table, - const int table_size); - -// Return the largest n such that -// -// s1[0,n-1] == s2[0,n-1] -// and n <= (s2_limit - s2). -// -// Does not read *s2_limit or beyond. -// Does not read *(s1 + (s2_limit - s2)) or beyond. -// Requires that s2_limit >= s2. -// -// Separate implementation for x86_64, for speed. Uses the fact that -// x86_64 is little endian. -#if defined(ARCH_K8) -static inline int FindMatchLength(const char* s1, - const char* s2, - const char* s2_limit) { - DCHECK_GE(s2_limit, s2); - int matched = 0; - - // Find out how long the match is. We loop over the data 64 bits at a - // time until we find a 64-bit block that doesn't match; then we find - // the first non-matching bit and use that to calculate the total - // length of the match. - while (PREDICT_TRUE(s2 <= s2_limit - 8)) { - if (PREDICT_FALSE(UNALIGNED_LOAD64(s2) == UNALIGNED_LOAD64(s1 + matched))) { - s2 += 8; - matched += 8; - } else { - // On current (mid-2008) Opteron models there is a 3% more - // efficient code sequence to find the first non-matching byte. - // However, what follows is ~10% better on Intel Core 2 and newer, - // and we expect AMD's bsf instruction to improve. - uint64 x = UNALIGNED_LOAD64(s2) ^ UNALIGNED_LOAD64(s1 + matched); - int matching_bits = Bits::FindLSBSetNonZero64(x); - matched += matching_bits >> 3; - return matched; - } - } - while (PREDICT_TRUE(s2 < s2_limit)) { - if (PREDICT_TRUE(s1[matched] == *s2)) { - ++s2; - ++matched; - } else { - return matched; - } - } - return matched; -} -#else -static inline int FindMatchLength(const char* s1, - const char* s2, - const char* s2_limit) { - // Implementation based on the x86-64 version, above. - DCHECK_GE(s2_limit, s2); - int matched = 0; - - while (s2 <= s2_limit - 4 && - UNALIGNED_LOAD32(s2) == UNALIGNED_LOAD32(s1 + matched)) { - s2 += 4; - matched += 4; - } - if (LittleEndian::IsLittleEndian() && s2 <= s2_limit - 4) { - uint32 x = UNALIGNED_LOAD32(s2) ^ UNALIGNED_LOAD32(s1 + matched); - int matching_bits = Bits::FindLSBSetNonZero(x); - matched += matching_bits >> 3; - } else { - while ((s2 < s2_limit) && (s1[matched] == *s2)) { - ++s2; - ++matched; - } - } - return matched; -} -#endif - -} // end namespace internal -} // end namespace snappy - -#endif // UTIL_SNAPPY_SNAPPY_INTERNAL_H_ diff --git a/cppForSwig/leveldbwin/snappy_src/snappy-sinksource.cc b/cppForSwig/leveldbwin/snappy_src/snappy-sinksource.cc deleted file mode 100644 index 1017895f9..000000000 --- a/cppForSwig/leveldbwin/snappy_src/snappy-sinksource.cc +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include - -#include "snappy-sinksource.h" - -namespace snappy { - -Source::~Source() { } - -Sink::~Sink() { } - -char* Sink::GetAppendBuffer(size_t length, char* scratch) { - return scratch; -} - -ByteArraySource::~ByteArraySource() { } - -size_t ByteArraySource::Available() const { return left_; } - -const char* ByteArraySource::Peek(size_t* len) { - *len = left_; - return ptr_; -} - -void ByteArraySource::Skip(size_t n) { - left_ -= n; - ptr_ += n; -} - -UncheckedByteArraySink::~UncheckedByteArraySink() { } - -void UncheckedByteArraySink::Append(const char* data, size_t n) { - // Do no copying if the caller filled in the result of GetAppendBuffer() - if (data != dest_) { - memcpy(dest_, data, n); - } - dest_ += n; -} - -char* UncheckedByteArraySink::GetAppendBuffer(size_t len, char* scratch) { - return dest_; -} - - -} diff --git a/cppForSwig/leveldbwin/snappy_src/snappy-sinksource.h b/cppForSwig/leveldbwin/snappy_src/snappy-sinksource.h deleted file mode 100644 index 430baeabb..000000000 --- a/cppForSwig/leveldbwin/snappy_src/snappy-sinksource.h +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ -#define UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ - -#include - - -namespace snappy { - -// A Sink is an interface that consumes a sequence of bytes. -class Sink { - public: - Sink() { } - virtual ~Sink(); - - // Append "bytes[0,n-1]" to this. - virtual void Append(const char* bytes, size_t n) = 0; - - // Returns a writable buffer of the specified length for appending. - // May return a pointer to the caller-owned scratch buffer which - // must have at least the indicated length. The returned buffer is - // only valid until the next operation on this Sink. - // - // After writing at most "length" bytes, call Append() with the - // pointer returned from this function and the number of bytes - // written. Many Append() implementations will avoid copying - // bytes if this function returned an internal buffer. - // - // If a non-scratch buffer is returned, the caller may only pass a - // prefix of it to Append(). That is, it is not correct to pass an - // interior pointer of the returned array to Append(). - // - // The default implementation always returns the scratch buffer. - virtual char* GetAppendBuffer(size_t length, char* scratch); - - private: - // No copying - Sink(const Sink&); - void operator=(const Sink&); -}; - -// A Source is an interface that yields a sequence of bytes -class Source { - public: - Source() { } - virtual ~Source(); - - // Return the number of bytes left to read from the source - virtual size_t Available() const = 0; - - // Peek at the next flat region of the source. Does not reposition - // the source. The returned region is empty iff Available()==0. - // - // Returns a pointer to the beginning of the region and store its - // length in *len. - // - // The returned region is valid until the next call to Skip() or - // until this object is destroyed, whichever occurs first. - // - // The returned region may be larger than Available() (for example - // if this ByteSource is a view on a substring of a larger source). - // The caller is responsible for ensuring that it only reads the - // Available() bytes. - virtual const char* Peek(size_t* len) = 0; - - // Skip the next n bytes. Invalidates any buffer returned by - // a previous call to Peek(). - // REQUIRES: Available() >= n - virtual void Skip(size_t n) = 0; - - private: - // No copying - Source(const Source&); - void operator=(const Source&); -}; - -// A Source implementation that yields the contents of a flat array -class ByteArraySource : public Source { - public: - ByteArraySource(const char* p, size_t n) : ptr_(p), left_(n) { } - virtual ~ByteArraySource(); - virtual size_t Available() const; - virtual const char* Peek(size_t* len); - virtual void Skip(size_t n); - private: - const char* ptr_; - size_t left_; -}; - -// A Sink implementation that writes to a flat array without any bound checks. -class UncheckedByteArraySink : public Sink { - public: - explicit UncheckedByteArraySink(char* dest) : dest_(dest) { } - virtual ~UncheckedByteArraySink(); - virtual void Append(const char* data, size_t n); - virtual char* GetAppendBuffer(size_t len, char* scratch); - - // Return the current output pointer so that a caller can see how - // many bytes were produced. - // Note: this is not a Sink method. - char* CurrentDestination() const { return dest_; } - private: - char* dest_; -}; - - -} - -#endif // UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ diff --git a/cppForSwig/leveldbwin/snappy_src/snappy-stubs-internal.cc b/cppForSwig/leveldbwin/snappy_src/snappy-stubs-internal.cc deleted file mode 100644 index 6ed334371..000000000 --- a/cppForSwig/leveldbwin/snappy_src/snappy-stubs-internal.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include - -#include "snappy-stubs-internal.h" - -namespace snappy { - -void Varint::Append32(string* s, uint32 value) { - char buf[Varint::kMax32]; - const char* p = Varint::Encode32(buf, value); - s->append(buf, p - buf); -} - -} // namespace snappy diff --git a/cppForSwig/leveldbwin/snappy_src/snappy-stubs-internal.h b/cppForSwig/leveldbwin/snappy_src/snappy-stubs-internal.h deleted file mode 100644 index cc51e26ab..000000000 --- a/cppForSwig/leveldbwin/snappy_src/snappy-stubs-internal.h +++ /dev/null @@ -1,477 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Various stubs for the open-source version of Snappy. - -#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ -#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include -#include -#include - -#ifdef HAVE_SYS_MMAN_H -#include -#endif - -#include "snappy-stubs-public.h" - -#if defined(__x86_64__) - -// Enable 64-bit optimized versions of some routines. -#define ARCH_K8 1 - -#endif - -// Needed by OS X, among others. -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -// Pull in std::min, std::ostream, and the likes. This is safe because this -// header file is never used from any public header files. -using namespace std; - -// The size of an array, if known at compile-time. -// Will give unexpected results if used on a pointer. -// We undefine it first, since some compilers already have a definition. -#ifdef ARRAYSIZE -#undef ARRAYSIZE -#endif -#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) - -// Static prediction hints. -#ifdef HAVE_BUILTIN_EXPECT -#define PREDICT_FALSE(x) (__builtin_expect(x, 0)) -#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) -#else -#define PREDICT_FALSE(x) x -#define PREDICT_TRUE(x) x -#endif - -// This is only used for recomputing the tag byte table used during -// decompression; for simplicity we just remove it from the open-source -// version (anyone who wants to regenerate it can just do the call -// themselves within main()). -#define DEFINE_bool(flag_name, default_value, description) \ - bool FLAGS_ ## flag_name = default_value; -#define DECLARE_bool(flag_name) \ - extern bool FLAGS_ ## flag_name; -#define REGISTER_MODULE_INITIALIZER(name, code) - -namespace snappy { - -static const uint32 kuint32max = static_cast(0xFFFFFFFF); -static const int64 kint64max = static_cast(0x7FFFFFFFFFFFFFFFLL); - -// Logging. - -#define LOG(level) LogMessage() -#define VLOG(level) true ? (void)0 : \ - snappy::LogMessageVoidify() & snappy::LogMessage() - -class LogMessage { - public: - LogMessage() { } - ~LogMessage() { - cerr << endl; - } - - LogMessage& operator<<(const std::string& msg) { - cerr << msg; - return *this; - } - LogMessage& operator<<(int x) { - cerr << x; - return *this; - } -}; - -// Asserts, both versions activated in debug mode only, -// and ones that are always active. - -#define CRASH_UNLESS(condition) \ - PREDICT_TRUE(condition) ? (void)0 : \ - snappy::LogMessageVoidify() & snappy::LogMessageCrash() - -class LogMessageCrash : public LogMessage { - public: - LogMessageCrash() { } - ~LogMessageCrash() { - cerr << endl; - abort(); - } -}; - -// This class is used to explicitly ignore values in the conditional -// logging macros. This avoids compiler warnings like "value computed -// is not used" and "statement has no effect". - -class LogMessageVoidify { - public: - LogMessageVoidify() { } - // This has to be an operator with a precedence lower than << but - // higher than ?: - void operator&(const LogMessage&) { } -}; - -#define CHECK(cond) CRASH_UNLESS(cond) -#define CHECK_LE(a, b) CRASH_UNLESS((a) <= (b)) -#define CHECK_GE(a, b) CRASH_UNLESS((a) >= (b)) -#define CHECK_EQ(a, b) CRASH_UNLESS((a) == (b)) -#define CHECK_NE(a, b) CRASH_UNLESS((a) != (b)) -#define CHECK_LT(a, b) CRASH_UNLESS((a) < (b)) -#define CHECK_GT(a, b) CRASH_UNLESS((a) > (b)) - -#ifdef NDEBUG - -#define DCHECK(cond) CRASH_UNLESS(true) -#define DCHECK_LE(a, b) CRASH_UNLESS(true) -#define DCHECK_GE(a, b) CRASH_UNLESS(true) -#define DCHECK_EQ(a, b) CRASH_UNLESS(true) -#define DCHECK_NE(a, b) CRASH_UNLESS(true) -#define DCHECK_LT(a, b) CRASH_UNLESS(true) -#define DCHECK_GT(a, b) CRASH_UNLESS(true) - -#else - -#define DCHECK(cond) CHECK(cond) -#define DCHECK_LE(a, b) CHECK_LE(a, b) -#define DCHECK_GE(a, b) CHECK_GE(a, b) -#define DCHECK_EQ(a, b) CHECK_EQ(a, b) -#define DCHECK_NE(a, b) CHECK_NE(a, b) -#define DCHECK_LT(a, b) CHECK_LT(a, b) -#define DCHECK_GT(a, b) CHECK_GT(a, b) - -#endif - -// Potentially unaligned loads and stores. - -#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) - -#define UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) -#define UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) -#define UNALIGNED_LOAD64(_p) (*reinterpret_cast(_p)) - -#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast(_p) = (_val)) -#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast(_p) = (_val)) -#define UNALIGNED_STORE64(_p, _val) (*reinterpret_cast(_p) = (_val)) - -#else - -// These functions are provided for architectures that don't support -// unaligned loads and stores. - -inline uint16 UNALIGNED_LOAD16(const void *p) { - uint16 t; - memcpy(&t, p, sizeof t); - return t; -} - -inline uint32 UNALIGNED_LOAD32(const void *p) { - uint32 t; - memcpy(&t, p, sizeof t); - return t; -} - -inline uint64 UNALIGNED_LOAD64(const void *p) { - uint64 t; - memcpy(&t, p, sizeof t); - return t; -} - -inline void UNALIGNED_STORE16(void *p, uint16 v) { - memcpy(p, &v, sizeof v); -} - -inline void UNALIGNED_STORE32(void *p, uint32 v) { - memcpy(p, &v, sizeof v); -} - -inline void UNALIGNED_STORE64(void *p, uint64 v) { - memcpy(p, &v, sizeof v); -} - -#endif - -// The following guarantees declaration of the byte swap functions. -#ifdef WORDS_BIGENDIAN - -#ifdef _MSC_VER -#include -#define bswap_16(x) _byteswap_ushort(x) -#define bswap_32(x) _byteswap_ulong(x) -#define bswap_64(x) _byteswap_uint64(x) - -#elif defined(__APPLE__) -// Mac OS X / Darwin features -#include -#define bswap_16(x) OSSwapInt16(x) -#define bswap_32(x) OSSwapInt32(x) -#define bswap_64(x) OSSwapInt64(x) - -#else -#include -#endif - -#endif // WORDS_BIGENDIAN - -// Convert to little-endian storage, opposite of network format. -// Convert x from host to little endian: x = LittleEndian.FromHost(x); -// convert x from little endian to host: x = LittleEndian.ToHost(x); -// -// Store values into unaligned memory converting to little endian order: -// LittleEndian.Store16(p, x); -// -// Load unaligned values stored in little endian converting to host order: -// x = LittleEndian.Load16(p); -class LittleEndian { - public: - // Conversion functions. -#ifdef WORDS_BIGENDIAN - - static uint16 FromHost16(uint16 x) { return bswap_16(x); } - static uint16 ToHost16(uint16 x) { return bswap_16(x); } - - static uint32 FromHost32(uint32 x) { return bswap_32(x); } - static uint32 ToHost32(uint32 x) { return bswap_32(x); } - - static bool IsLittleEndian() { return false; } - -#else // !defined(WORDS_BIGENDIAN) - - static uint16 FromHost16(uint16 x) { return x; } - static uint16 ToHost16(uint16 x) { return x; } - - static uint32 FromHost32(uint32 x) { return x; } - static uint32 ToHost32(uint32 x) { return x; } - - static bool IsLittleEndian() { return true; } - -#endif // !defined(WORDS_BIGENDIAN) - - // Functions to do unaligned loads and stores in little-endian order. - static uint16 Load16(const void *p) { - return ToHost16(UNALIGNED_LOAD16(p)); - } - - static void Store16(void *p, uint16 v) { - UNALIGNED_STORE16(p, FromHost16(v)); - } - - static uint32 Load32(const void *p) { - return ToHost32(UNALIGNED_LOAD32(p)); - } - - static void Store32(void *p, uint32 v) { - UNALIGNED_STORE32(p, FromHost32(v)); - } -}; - -// Some bit-manipulation functions. -class Bits { - public: - // Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0. - static int Log2Floor(uint32 n); - - // Return the first set least / most significant bit, 0-indexed. Returns an - // undefined value if n == 0. FindLSBSetNonZero() is similar to ffs() except - // that it's 0-indexed. - static int FindLSBSetNonZero(uint32 n); - static int FindLSBSetNonZero64(uint64 n); - - private: - DISALLOW_COPY_AND_ASSIGN(Bits); -}; - -#ifdef HAVE_BUILTIN_CTZ - -inline int Bits::Log2Floor(uint32 n) { - return n == 0 ? -1 : 31 ^ __builtin_clz(n); -} - -inline int Bits::FindLSBSetNonZero(uint32 n) { - return __builtin_ctz(n); -} - -inline int Bits::FindLSBSetNonZero64(uint64 n) { - return __builtin_ctzll(n); -} - -#else // Portable versions. - -inline int Bits::Log2Floor(uint32 n) { - if (n == 0) - return -1; - int log = 0; - uint32 value = n; - for (int i = 4; i >= 0; --i) { - int shift = (1 << i); - uint32 x = value >> shift; - if (x != 0) { - value = x; - log += shift; - } - } - assert(value == 1); - return log; -} - -inline int Bits::FindLSBSetNonZero(uint32 n) { - int rc = 31; - for (int i = 4, shift = 1 << 4; i >= 0; --i) { - const uint32 x = n << shift; - if (x != 0) { - n = x; - rc -= shift; - } - shift >>= 1; - } - return rc; -} - -// FindLSBSetNonZero64() is defined in terms of FindLSBSetNonZero(). -inline int Bits::FindLSBSetNonZero64(uint64 n) { - const uint32 bottombits = static_cast(n); - if (bottombits == 0) { - // Bottom bits are zero, so scan in top bits - return 32 + FindLSBSetNonZero(static_cast(n >> 32)); - } else { - return FindLSBSetNonZero(bottombits); - } -} - -#endif // End portable versions. - -// Variable-length integer encoding. -class Varint { - public: - // Maximum lengths of varint encoding of uint32. - static const int kMax32 = 5; - - // Attempts to parse a varint32 from a prefix of the bytes in [ptr,limit-1]. - // Never reads a character at or beyond limit. If a valid/terminated varint32 - // was found in the range, stores it in *OUTPUT and returns a pointer just - // past the last byte of the varint32. Else returns NULL. On success, - // "result <= limit". - static const char* Parse32WithLimit(const char* ptr, const char* limit, - uint32* OUTPUT); - - // REQUIRES "ptr" points to a buffer of length sufficient to hold "v". - // EFFECTS Encodes "v" into "ptr" and returns a pointer to the - // byte just past the last encoded byte. - static char* Encode32(char* ptr, uint32 v); - - // EFFECTS Appends the varint representation of "value" to "*s". - static void Append32(string* s, uint32 value); -}; - -inline const char* Varint::Parse32WithLimit(const char* p, - const char* l, - uint32* OUTPUT) { - const unsigned char* ptr = reinterpret_cast(p); - const unsigned char* limit = reinterpret_cast(l); - uint32 b, result; - if (ptr >= limit) return NULL; - b = *(ptr++); result = b & 127; if (b < 128) goto done; - if (ptr >= limit) return NULL; - b = *(ptr++); result |= (b & 127) << 7; if (b < 128) goto done; - if (ptr >= limit) return NULL; - b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done; - if (ptr >= limit) return NULL; - b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done; - if (ptr >= limit) return NULL; - b = *(ptr++); result |= (b & 127) << 28; if (b < 16) goto done; - return NULL; // Value is too long to be a varint32 - done: - *OUTPUT = result; - return reinterpret_cast(ptr); -} - -inline char* Varint::Encode32(char* sptr, uint32 v) { - // Operate on characters as unsigneds - unsigned char* ptr = reinterpret_cast(sptr); - static const int B = 128; - if (v < (1<<7)) { - *(ptr++) = v; - } else if (v < (1<<14)) { - *(ptr++) = v | B; - *(ptr++) = v>>7; - } else if (v < (1<<21)) { - *(ptr++) = v | B; - *(ptr++) = (v>>7) | B; - *(ptr++) = v>>14; - } else if (v < (1<<28)) { - *(ptr++) = v | B; - *(ptr++) = (v>>7) | B; - *(ptr++) = (v>>14) | B; - *(ptr++) = v>>21; - } else { - *(ptr++) = v | B; - *(ptr++) = (v>>7) | B; - *(ptr++) = (v>>14) | B; - *(ptr++) = (v>>21) | B; - *(ptr++) = v>>28; - } - return reinterpret_cast(ptr); -} - -// If you know the internal layout of the std::string in use, you can -// replace this function with one that resizes the string without -// filling the new space with zeros (if applicable) -- -// it will be non-portable but faster. -inline void STLStringResizeUninitialized(string* s, size_t new_size) { - s->resize(new_size); -} - -// Return a mutable char* pointing to a string's internal buffer, -// which may not be null-terminated. Writing through this pointer will -// modify the string. -// -// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the -// next call to a string method that invalidates iterators. -// -// As of 2006-04, there is no standard-blessed way of getting a -// mutable reference to a string's internal buffer. However, issue 530 -// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#530) -// proposes this as the method. It will officially be part of the standard -// for C++0x. This should already work on all current implementations. -inline char* string_as_array(string* str) { - return str->empty() ? NULL : &*str->begin(); -} - -} // namespace snappy - -#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ diff --git a/cppForSwig/leveldbwin/snappy_src/snappy-stubs-public.h b/cppForSwig/leveldbwin/snappy_src/snappy-stubs-public.h deleted file mode 100644 index b089baca9..000000000 --- a/cppForSwig/leveldbwin/snappy_src/snappy-stubs-public.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// Author: sesse@google.com (Steinar H. Gunderson) -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Various type stubs for the open-source version of Snappy. -// -// This file cannot include config.h, as it is included from snappy.h, -// which is a public header. Instead, snappy-stubs-public.h is generated by -// from snappy-stubs-public.h.in at configure time. - -#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ -#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ - -#if 1 -#include -#endif - -#if 1 -#include -#endif - -#define SNAPPY_MAJOR 1 -#define SNAPPY_MINOR 0 -#define SNAPPY_PATCHLEVEL 3 -#define SNAPPY_VERSION \ - ((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL) - -#include - -namespace snappy { - -#if 1 -typedef int8_t int8; -typedef uint8_t uint8; -typedef int16_t int16; -typedef uint16_t uint16; -typedef int32_t int32; -typedef uint32_t uint32; -typedef int64_t int64; -typedef uint64_t uint64; -#else -typedef signed char int8; -typedef unsigned char uint8; -typedef short int16; -typedef unsigned short uint16; -typedef int int32; -typedef unsigned int uint32; -typedef long long int64; -typedef unsigned long long uint64; -#endif - -typedef std::string string; - -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -} // namespace snappy - -#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ diff --git a/cppForSwig/leveldbwin/snappy_src/snappy.cc b/cppForSwig/leveldbwin/snappy_src/snappy.cc deleted file mode 100644 index c79edb58a..000000000 --- a/cppForSwig/leveldbwin/snappy_src/snappy.cc +++ /dev/null @@ -1,1030 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "snappy.h" -#include "snappy-internal.h" -#include "snappy-sinksource.h" - -#include - -#include -#include -#include - - -namespace snappy { - -// Any hash function will produce a valid compressed bitstream, but a good -// hash function reduces the number of collisions and thus yields better -// compression for compressible input, and more speed for incompressible -// input. Of course, it doesn't hurt if the hash function is reasonably fast -// either, as it gets called a lot. -static inline uint32 HashBytes(uint32 bytes, int shift) { - uint32 kMul = 0x1e35a7bd; - return (bytes * kMul) >> shift; -} -static inline uint32 Hash(const char* p, int shift) { - return HashBytes(UNALIGNED_LOAD32(p), shift); -} - -size_t MaxCompressedLength(size_t source_len) { - // Compressed data can be defined as: - // compressed := item* literal* - // item := literal* copy - // - // The trailing literal sequence has a space blowup of at most 62/60 - // since a literal of length 60 needs one tag byte + one extra byte - // for length information. - // - // Item blowup is trickier to measure. Suppose the "copy" op copies - // 4 bytes of data. Because of a special check in the encoding code, - // we produce a 4-byte copy only if the offset is < 65536. Therefore - // the copy op takes 3 bytes to encode, and this type of item leads - // to at most the 62/60 blowup for representing literals. - // - // Suppose the "copy" op copies 5 bytes of data. If the offset is big - // enough, it will take 5 bytes to encode the copy op. Therefore the - // worst case here is a one-byte literal followed by a five-byte copy. - // I.e., 6 bytes of input turn into 7 bytes of "compressed" data. - // - // This last factor dominates the blowup, so the final estimate is: - return 32 + source_len + source_len/6; -} - -enum { - LITERAL = 0, - COPY_1_BYTE_OFFSET = 1, // 3 bit length + 3 bits of offset in opcode - COPY_2_BYTE_OFFSET = 2, - COPY_4_BYTE_OFFSET = 3 -}; - -// Copy "len" bytes from "src" to "op", one byte at a time. Used for -// handling COPY operations where the input and output regions may -// overlap. For example, suppose: -// src == "ab" -// op == src + 2 -// len == 20 -// After IncrementalCopy(src, op, len), the result will have -// eleven copies of "ab" -// ababababababababababab -// Note that this does not match the semantics of either memcpy() -// or memmove(). -static inline void IncrementalCopy(const char* src, char* op, int len) { - DCHECK_GT(len, 0); - do { - *op++ = *src++; - } while (--len > 0); -} - -// Equivalent to IncrementalCopy except that it can write up to ten extra -// bytes after the end of the copy, and that it is faster. -// -// The main part of this loop is a simple copy of eight bytes at a time until -// we've copied (at least) the requested amount of bytes. However, if op and -// src are less than eight bytes apart (indicating a repeating pattern of -// length < 8), we first need to expand the pattern in order to get the correct -// results. For instance, if the buffer looks like this, with the eight-byte -// and patterns marked as intervals: -// -// abxxxxxxxxxxxx -// [------] src -// [------] op -// -// a single eight-byte copy from to will repeat the pattern once, -// after which we can move two bytes without moving : -// -// ababxxxxxxxxxx -// [------] src -// [------] op -// -// and repeat the exercise until the two no longer overlap. -// -// This allows us to do very well in the special case of one single byte -// repeated many times, without taking a big hit for more general cases. -// -// The worst case of extra writing past the end of the match occurs when -// op - src == 1 and len == 1; the last copy will read from byte positions -// [0..7] and write to [4..11], whereas it was only supposed to write to -// position 1. Thus, ten excess bytes. - -namespace { - -const int kMaxIncrementCopyOverflow = 10; - -} // namespace - -static inline void IncrementalCopyFastPath(const char* src, char* op, int len) { - while (op - src < 8) { - UNALIGNED_STORE64(op, UNALIGNED_LOAD64(src)); - len -= op - src; - op += op - src; - } - while (len > 0) { - UNALIGNED_STORE64(op, UNALIGNED_LOAD64(src)); - src += 8; - op += 8; - len -= 8; - } -} - -static inline char* EmitLiteral(char* op, - const char* literal, - int len, - bool allow_fast_path) { - int n = len - 1; // Zero-length literals are disallowed - if (n < 60) { - // Fits in tag byte - *op++ = LITERAL | (n << 2); - - // The vast majority of copies are below 16 bytes, for which a - // call to memcpy is overkill. This fast path can sometimes - // copy up to 15 bytes too much, but that is okay in the - // main loop, since we have a bit to go on for both sides: - // - // - The input will always have kInputMarginBytes = 15 extra - // available bytes, as long as we're in the main loop, and - // if not, allow_fast_path = false. - // - The output will always have 32 spare bytes (see - // MaxCompressedLength). - if (allow_fast_path && len <= 16) { - UNALIGNED_STORE64(op, UNALIGNED_LOAD64(literal)); - UNALIGNED_STORE64(op + 8, UNALIGNED_LOAD64(literal + 8)); - return op + len; - } - } else { - // Encode in upcoming bytes - char* base = op; - int count = 0; - op++; - while (n > 0) { - *op++ = n & 0xff; - n >>= 8; - count++; - } - assert(count >= 1); - assert(count <= 4); - *base = LITERAL | ((59+count) << 2); - } - memcpy(op, literal, len); - return op + len; -} - -static inline char* EmitCopyLessThan64(char* op, int offset, int len) { - DCHECK_LE(len, 64); - DCHECK_GE(len, 4); - DCHECK_LT(offset, 65536); - - if ((len < 12) && (offset < 2048)) { - int len_minus_4 = len - 4; - assert(len_minus_4 < 8); // Must fit in 3 bits - *op++ = COPY_1_BYTE_OFFSET | ((len_minus_4) << 2) | ((offset >> 8) << 5); - *op++ = offset & 0xff; - } else { - *op++ = COPY_2_BYTE_OFFSET | ((len-1) << 2); - LittleEndian::Store16(op, offset); - op += 2; - } - return op; -} - -static inline char* EmitCopy(char* op, int offset, int len) { - // Emit 64 byte copies but make sure to keep at least four bytes reserved - while (len >= 68) { - op = EmitCopyLessThan64(op, offset, 64); - len -= 64; - } - - // Emit an extra 60 byte copy if have too much data to fit in one copy - if (len > 64) { - op = EmitCopyLessThan64(op, offset, 60); - len -= 60; - } - - // Emit remainder - op = EmitCopyLessThan64(op, offset, len); - return op; -} - - -bool GetUncompressedLength(const char* start, size_t n, size_t* result) { - uint32 v = 0; - const char* limit = start + n; - if (Varint::Parse32WithLimit(start, limit, &v) != NULL) { - *result = v; - return true; - } else { - return false; - } -} - -namespace internal { -uint16* WorkingMemory::GetHashTable(size_t input_size, int* table_size) { - // Use smaller hash table when input.size() is smaller, since we - // fill the table, incurring O(hash table size) overhead for - // compression, and if the input is short, we won't need that - // many hash table entries anyway. - assert(kMaxHashTableSize >= 256); - int htsize = 256; - while (htsize < kMaxHashTableSize && htsize < input_size) { - htsize <<= 1; - } - CHECK_EQ(0, htsize & (htsize - 1)) << ": must be power of two"; - CHECK_LE(htsize, kMaxHashTableSize) << ": hash table too large"; - - uint16* table; - if (htsize <= ARRAYSIZE(small_table_)) { - table = small_table_; - } else { - if (large_table_ == NULL) { - large_table_ = new uint16[kMaxHashTableSize]; - } - table = large_table_; - } - - *table_size = htsize; - memset(table, 0, htsize * sizeof(*table)); - return table; -} -} // end namespace internal - -// For 0 <= offset <= 4, GetUint32AtOffset(UNALIGNED_LOAD64(p), offset) will -// equal UNALIGNED_LOAD32(p + offset). Motivation: On x86-64 hardware we have -// empirically found that overlapping loads such as -// UNALIGNED_LOAD32(p) ... UNALIGNED_LOAD32(p+1) ... UNALIGNED_LOAD32(p+2) -// are slower than UNALIGNED_LOAD64(p) followed by shifts and casts to uint32. -static inline uint32 GetUint32AtOffset(uint64 v, int offset) { - DCHECK(0 <= offset && offset <= 4) << offset; - return v >> (LittleEndian::IsLittleEndian() ? 8 * offset : 32 - 8 * offset); -} - -// Flat array compression that does not emit the "uncompressed length" -// prefix. Compresses "input" string to the "*op" buffer. -// -// REQUIRES: "input" is at most "kBlockSize" bytes long. -// REQUIRES: "op" points to an array of memory that is at least -// "MaxCompressedLength(input.size())" in size. -// REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero. -// REQUIRES: "table_size" is a power of two -// -// Returns an "end" pointer into "op" buffer. -// "end - op" is the compressed size of "input". -namespace internal { -char* CompressFragment(const char* input, - size_t input_size, - char* op, - uint16* table, - const int table_size) { - // "ip" is the input pointer, and "op" is the output pointer. - const char* ip = input; - CHECK_LE(input_size, kBlockSize); - CHECK_EQ(table_size & (table_size - 1), 0) << ": table must be power of two"; - const int shift = 32 - Bits::Log2Floor(table_size); - DCHECK_EQ(kuint32max >> shift, table_size - 1); - const char* ip_end = input + input_size; - const char* base_ip = ip; - // Bytes in [next_emit, ip) will be emitted as literal bytes. Or - // [next_emit, ip_end) after the main loop. - const char* next_emit = ip; - - const int kInputMarginBytes = 15; - if (PREDICT_TRUE(input_size >= kInputMarginBytes)) { - const char* ip_limit = input + input_size - kInputMarginBytes; - - for (uint32 next_hash = Hash(++ip, shift); ; ) { - DCHECK_LT(next_emit, ip); - // The body of this loop calls EmitLiteral once and then EmitCopy one or - // more times. (The exception is that when we're close to exhausting - // the input we goto emit_remainder.) - // - // In the first iteration of this loop we're just starting, so - // there's nothing to copy, so calling EmitLiteral once is - // necessary. And we only start a new iteration when the - // current iteration has determined that a call to EmitLiteral will - // precede the next call to EmitCopy (if any). - // - // Step 1: Scan forward in the input looking for a 4-byte-long match. - // If we get close to exhausting the input then goto emit_remainder. - // - // Heuristic match skipping: If 32 bytes are scanned with no matches - // found, start looking only at every other byte. If 32 more bytes are - // scanned, look at every third byte, etc.. When a match is found, - // immediately go back to looking at every byte. This is a small loss - // (~5% performance, ~0.1% density) for compressible data due to more - // bookkeeping, but for non-compressible data (such as JPEG) it's a huge - // win since the compressor quickly "realizes" the data is incompressible - // and doesn't bother looking for matches everywhere. - // - // The "skip" variable keeps track of how many bytes there are since the - // last match; dividing it by 32 (ie. right-shifting by five) gives the - // number of bytes to move ahead for each iteration. - uint32 skip = 32; - - const char* next_ip = ip; - const char* candidate; - do { - ip = next_ip; - uint32 hash = next_hash; - DCHECK_EQ(hash, Hash(ip, shift)); - uint32 bytes_between_hash_lookups = skip++ >> 5; - next_ip = ip + bytes_between_hash_lookups; - if (PREDICT_FALSE(next_ip > ip_limit)) { - goto emit_remainder; - } - next_hash = Hash(next_ip, shift); - candidate = base_ip + table[hash]; - DCHECK_GE(candidate, base_ip); - DCHECK_LT(candidate, ip); - - table[hash] = ip - base_ip; - } while (PREDICT_TRUE(UNALIGNED_LOAD32(ip) != - UNALIGNED_LOAD32(candidate))); - - // Step 2: A 4-byte match has been found. We'll later see if more - // than 4 bytes match. But, prior to the match, input - // bytes [next_emit, ip) are unmatched. Emit them as "literal bytes." - DCHECK_LE(next_emit + 16, ip_end); - op = EmitLiteral(op, next_emit, ip - next_emit, true); - - // Step 3: Call EmitCopy, and then see if another EmitCopy could - // be our next move. Repeat until we find no match for the - // input immediately after what was consumed by the last EmitCopy call. - // - // If we exit this loop normally then we need to call EmitLiteral next, - // though we don't yet know how big the literal will be. We handle that - // by proceeding to the next iteration of the main loop. We also can exit - // this loop via goto if we get close to exhausting the input. - uint64 input_bytes = 0; - uint32 candidate_bytes = 0; - - do { - // We have a 4-byte match at ip, and no need to emit any - // "literal bytes" prior to ip. - const char* base = ip; - int matched = 4 + FindMatchLength(candidate + 4, ip + 4, ip_end); - ip += matched; - int offset = base - candidate; - DCHECK_EQ(0, memcmp(base, candidate, matched)); - op = EmitCopy(op, offset, matched); - // We could immediately start working at ip now, but to improve - // compression we first update table[Hash(ip - 1, ...)]. - const char* insert_tail = ip - 1; - next_emit = ip; - if (PREDICT_FALSE(ip >= ip_limit)) { - goto emit_remainder; - } - input_bytes = UNALIGNED_LOAD64(insert_tail); - uint32 prev_hash = HashBytes(GetUint32AtOffset(input_bytes, 0), shift); - table[prev_hash] = ip - base_ip - 1; - uint32 cur_hash = HashBytes(GetUint32AtOffset(input_bytes, 1), shift); - candidate = base_ip + table[cur_hash]; - candidate_bytes = UNALIGNED_LOAD32(candidate); - table[cur_hash] = ip - base_ip; - } while (GetUint32AtOffset(input_bytes, 1) == candidate_bytes); - - next_hash = HashBytes(GetUint32AtOffset(input_bytes, 2), shift); - ++ip; - } - } - - emit_remainder: - // Emit the remaining bytes as a literal - if (next_emit < ip_end) { - op = EmitLiteral(op, next_emit, ip_end - next_emit, false); - } - - return op; -} -} // end namespace internal - -// Signature of output types needed by decompression code. -// The decompression code is templatized on a type that obeys this -// signature so that we do not pay virtual function call overhead in -// the middle of a tight decompression loop. -// -// class DecompressionWriter { -// public: -// // Called before decompression -// void SetExpectedLength(size_t length); -// -// // Called after decompression -// bool CheckLength() const; -// -// // Called repeatedly during decompression -// bool Append(const char* ip, uint32 length, bool allow_fast_path); -// bool AppendFromSelf(uint32 offset, uint32 length); -// }; -// -// "allow_fast_path" is a parameter that says if there is at least 16 -// readable bytes in "ip". It is currently only used by SnappyArrayWriter. - -// ----------------------------------------------------------------------- -// Lookup table for decompression code. Generated by ComputeTable() below. -// ----------------------------------------------------------------------- - -// Mapping from i in range [0,4] to a mask to extract the bottom 8*i bits -static const uint32 wordmask[] = { - 0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu -}; - -// Data stored per entry in lookup table: -// Range Bits-used Description -// ------------------------------------ -// 1..64 0..7 Literal/copy length encoded in opcode byte -// 0..7 8..10 Copy offset encoded in opcode byte / 256 -// 0..4 11..13 Extra bytes after opcode -// -// We use eight bits for the length even though 7 would have sufficed -// because of efficiency reasons: -// (1) Extracting a byte is faster than a bit-field -// (2) It properly aligns copy offset so we do not need a <<8 -static const uint16 char_table[256] = { - 0x0001, 0x0804, 0x1001, 0x2001, 0x0002, 0x0805, 0x1002, 0x2002, - 0x0003, 0x0806, 0x1003, 0x2003, 0x0004, 0x0807, 0x1004, 0x2004, - 0x0005, 0x0808, 0x1005, 0x2005, 0x0006, 0x0809, 0x1006, 0x2006, - 0x0007, 0x080a, 0x1007, 0x2007, 0x0008, 0x080b, 0x1008, 0x2008, - 0x0009, 0x0904, 0x1009, 0x2009, 0x000a, 0x0905, 0x100a, 0x200a, - 0x000b, 0x0906, 0x100b, 0x200b, 0x000c, 0x0907, 0x100c, 0x200c, - 0x000d, 0x0908, 0x100d, 0x200d, 0x000e, 0x0909, 0x100e, 0x200e, - 0x000f, 0x090a, 0x100f, 0x200f, 0x0010, 0x090b, 0x1010, 0x2010, - 0x0011, 0x0a04, 0x1011, 0x2011, 0x0012, 0x0a05, 0x1012, 0x2012, - 0x0013, 0x0a06, 0x1013, 0x2013, 0x0014, 0x0a07, 0x1014, 0x2014, - 0x0015, 0x0a08, 0x1015, 0x2015, 0x0016, 0x0a09, 0x1016, 0x2016, - 0x0017, 0x0a0a, 0x1017, 0x2017, 0x0018, 0x0a0b, 0x1018, 0x2018, - 0x0019, 0x0b04, 0x1019, 0x2019, 0x001a, 0x0b05, 0x101a, 0x201a, - 0x001b, 0x0b06, 0x101b, 0x201b, 0x001c, 0x0b07, 0x101c, 0x201c, - 0x001d, 0x0b08, 0x101d, 0x201d, 0x001e, 0x0b09, 0x101e, 0x201e, - 0x001f, 0x0b0a, 0x101f, 0x201f, 0x0020, 0x0b0b, 0x1020, 0x2020, - 0x0021, 0x0c04, 0x1021, 0x2021, 0x0022, 0x0c05, 0x1022, 0x2022, - 0x0023, 0x0c06, 0x1023, 0x2023, 0x0024, 0x0c07, 0x1024, 0x2024, - 0x0025, 0x0c08, 0x1025, 0x2025, 0x0026, 0x0c09, 0x1026, 0x2026, - 0x0027, 0x0c0a, 0x1027, 0x2027, 0x0028, 0x0c0b, 0x1028, 0x2028, - 0x0029, 0x0d04, 0x1029, 0x2029, 0x002a, 0x0d05, 0x102a, 0x202a, - 0x002b, 0x0d06, 0x102b, 0x202b, 0x002c, 0x0d07, 0x102c, 0x202c, - 0x002d, 0x0d08, 0x102d, 0x202d, 0x002e, 0x0d09, 0x102e, 0x202e, - 0x002f, 0x0d0a, 0x102f, 0x202f, 0x0030, 0x0d0b, 0x1030, 0x2030, - 0x0031, 0x0e04, 0x1031, 0x2031, 0x0032, 0x0e05, 0x1032, 0x2032, - 0x0033, 0x0e06, 0x1033, 0x2033, 0x0034, 0x0e07, 0x1034, 0x2034, - 0x0035, 0x0e08, 0x1035, 0x2035, 0x0036, 0x0e09, 0x1036, 0x2036, - 0x0037, 0x0e0a, 0x1037, 0x2037, 0x0038, 0x0e0b, 0x1038, 0x2038, - 0x0039, 0x0f04, 0x1039, 0x2039, 0x003a, 0x0f05, 0x103a, 0x203a, - 0x003b, 0x0f06, 0x103b, 0x203b, 0x003c, 0x0f07, 0x103c, 0x203c, - 0x0801, 0x0f08, 0x103d, 0x203d, 0x1001, 0x0f09, 0x103e, 0x203e, - 0x1801, 0x0f0a, 0x103f, 0x203f, 0x2001, 0x0f0b, 0x1040, 0x2040 -}; - -// In debug mode, allow optional computation of the table at startup. -// Also, check that the decompression table is correct. -#ifndef NDEBUG -DEFINE_bool(snappy_dump_decompression_table, false, - "If true, we print the decompression table at startup."); - -static uint16 MakeEntry(unsigned int extra, - unsigned int len, - unsigned int copy_offset) { - // Check that all of the fields fit within the allocated space - DCHECK_EQ(extra, extra & 0x7); // At most 3 bits - DCHECK_EQ(copy_offset, copy_offset & 0x7); // At most 3 bits - DCHECK_EQ(len, len & 0x7f); // At most 7 bits - return len | (copy_offset << 8) | (extra << 11); -} - -static void ComputeTable() { - uint16 dst[256]; - - // Place invalid entries in all places to detect missing initialization - int assigned = 0; - for (int i = 0; i < 256; i++) { - dst[i] = 0xffff; - } - - // Small LITERAL entries. We store (len-1) in the top 6 bits. - for (unsigned int len = 1; len <= 60; len++) { - dst[LITERAL | ((len-1) << 2)] = MakeEntry(0, len, 0); - assigned++; - } - - // Large LITERAL entries. We use 60..63 in the high 6 bits to - // encode the number of bytes of length info that follow the opcode. - for (unsigned int extra_bytes = 1; extra_bytes <= 4; extra_bytes++) { - // We set the length field in the lookup table to 1 because extra - // bytes encode len-1. - dst[LITERAL | ((extra_bytes+59) << 2)] = MakeEntry(extra_bytes, 1, 0); - assigned++; - } - - // COPY_1_BYTE_OFFSET. - // - // The tag byte in the compressed data stores len-4 in 3 bits, and - // offset/256 in 5 bits. offset%256 is stored in the next byte. - // - // This format is used for length in range [4..11] and offset in - // range [0..2047] - for (unsigned int len = 4; len < 12; len++) { - for (unsigned int offset = 0; offset < 2048; offset += 256) { - dst[COPY_1_BYTE_OFFSET | ((len-4)<<2) | ((offset>>8)<<5)] = - MakeEntry(1, len, offset>>8); - assigned++; - } - } - - // COPY_2_BYTE_OFFSET. - // Tag contains len-1 in top 6 bits, and offset in next two bytes. - for (unsigned int len = 1; len <= 64; len++) { - dst[COPY_2_BYTE_OFFSET | ((len-1)<<2)] = MakeEntry(2, len, 0); - assigned++; - } - - // COPY_4_BYTE_OFFSET. - // Tag contents len-1 in top 6 bits, and offset in next four bytes. - for (unsigned int len = 1; len <= 64; len++) { - dst[COPY_4_BYTE_OFFSET | ((len-1)<<2)] = MakeEntry(4, len, 0); - assigned++; - } - - // Check that each entry was initialized exactly once. - CHECK_EQ(assigned, 256); - for (int i = 0; i < 256; i++) { - CHECK_NE(dst[i], 0xffff); - } - - if (FLAGS_snappy_dump_decompression_table) { - printf("static const uint16 char_table[256] = {\n "); - for (int i = 0; i < 256; i++) { - printf("0x%04x%s", - dst[i], - ((i == 255) ? "\n" : (((i%8) == 7) ? ",\n " : ", "))); - } - printf("};\n"); - } - - // Check that computed table matched recorded table - for (int i = 0; i < 256; i++) { - CHECK_EQ(dst[i], char_table[i]); - } -} -REGISTER_MODULE_INITIALIZER(snappy, ComputeTable()); -#endif /* !NDEBUG */ - -// Helper class for decompression -class SnappyDecompressor { - private: - Source* reader_; // Underlying source of bytes to decompress - const char* ip_; // Points to next buffered byte - const char* ip_limit_; // Points just past buffered bytes - uint32 peeked_; // Bytes peeked from reader (need to skip) - bool eof_; // Hit end of input without an error? - char scratch_[5]; // Temporary buffer for PeekFast() boundaries - - // Ensure that all of the tag metadata for the next tag is available - // in [ip_..ip_limit_-1]. Also ensures that [ip,ip+4] is readable even - // if (ip_limit_ - ip_ < 5). - // - // Returns true on success, false on error or end of input. - bool RefillTag(); - - public: - explicit SnappyDecompressor(Source* reader) - : reader_(reader), - ip_(NULL), - ip_limit_(NULL), - peeked_(0), - eof_(false) { - } - - ~SnappyDecompressor() { - // Advance past any bytes we peeked at from the reader - reader_->Skip(peeked_); - } - - // Returns true iff we have hit the end of the input without an error. - bool eof() const { - return eof_; - } - - // Read the uncompressed length stored at the start of the compressed data. - // On succcess, stores the length in *result and returns true. - // On failure, returns false. - bool ReadUncompressedLength(uint32* result) { - DCHECK(ip_ == NULL); // Must not have read anything yet - // Length is encoded in 1..5 bytes - *result = 0; - uint32 shift = 0; - while (true) { - if (shift >= 32) return false; - size_t n; - const char* ip = reader_->Peek(&n); - if (n == 0) return false; - const unsigned char c = *(reinterpret_cast(ip)); - reader_->Skip(1); - *result |= static_cast(c & 0x7f) << shift; - if (c < 128) { - break; - } - shift += 7; - } - return true; - } - - // Process the next item found in the input. - // Returns true if successful, false on error or end of input. - template - void DecompressAllTags(Writer* writer) { - const char* ip = ip_; - for ( ;; ) { - if (ip_limit_ - ip < 5) { - ip_ = ip; - if (!RefillTag()) return; - ip = ip_; - } - - const unsigned char c = *(reinterpret_cast(ip++)); - - if ((c & 0x3) == LITERAL) { - uint32 literal_length = c >> 2; - if (PREDICT_FALSE(literal_length >= 60)) { - // Long literal. - const uint32 literal_length_length = literal_length - 59; - literal_length = - LittleEndian::Load32(ip) & wordmask[literal_length_length]; - ip += literal_length_length; - } - ++literal_length; - - uint32 avail = ip_limit_ - ip; - while (avail < literal_length) { - if (!writer->Append(ip, avail, false)) return; - literal_length -= avail; - reader_->Skip(peeked_); - size_t n; - ip = reader_->Peek(&n); - avail = n; - peeked_ = avail; - if (avail == 0) return; // Premature end of input - ip_limit_ = ip + avail; - } - bool allow_fast_path = (avail >= 16); - if (!writer->Append(ip, literal_length, allow_fast_path)) { - return; - } - ip += literal_length; - } else { - const uint32 entry = char_table[c]; - const uint32 trailer = LittleEndian::Load32(ip) & wordmask[entry >> 11]; - const uint32 length = entry & 0xff; - ip += entry >> 11; - - // copy_offset/256 is encoded in bits 8..10. By just fetching - // those bits, we get copy_offset (since the bit-field starts at - // bit 8). - const uint32 copy_offset = entry & 0x700; - if (!writer->AppendFromSelf(copy_offset + trailer, length)) { - return; - } - } - } - } -}; - -bool SnappyDecompressor::RefillTag() { - const char* ip = ip_; - if (ip == ip_limit_) { - // Fetch a new fragment from the reader - reader_->Skip(peeked_); // All peeked bytes are used up - size_t n; - ip = reader_->Peek(&n); - peeked_ = n; - if (n == 0) { - eof_ = true; - return false; - } - ip_limit_ = ip + n; - } - - // Read the tag character - DCHECK_LT(ip, ip_limit_); - const unsigned char c = *(reinterpret_cast(ip)); - const uint32 entry = char_table[c]; - const uint32 needed = (entry >> 11) + 1; // +1 byte for 'c' - DCHECK_LE(needed, sizeof(scratch_)); - - // Read more bytes from reader if needed - uint32 nbuf = ip_limit_ - ip; - if (nbuf < needed) { - // Stitch together bytes from ip and reader to form the word - // contents. We store the needed bytes in "scratch_". They - // will be consumed immediately by the caller since we do not - // read more than we need. - memmove(scratch_, ip, nbuf); - reader_->Skip(peeked_); // All peeked bytes are used up - peeked_ = 0; - while (nbuf < needed) { - size_t length; - const char* src = reader_->Peek(&length); - if (length == 0) return false; - uint32 to_add = min(needed - nbuf, length); - memcpy(scratch_ + nbuf, src, to_add); - nbuf += to_add; - reader_->Skip(to_add); - } - DCHECK_EQ(nbuf, needed); - ip_ = scratch_; - ip_limit_ = scratch_ + needed; - } else if (nbuf < 5) { - // Have enough bytes, but move into scratch_ so that we do not - // read past end of input - memmove(scratch_, ip, nbuf); - reader_->Skip(peeked_); // All peeked bytes are used up - peeked_ = 0; - ip_ = scratch_; - ip_limit_ = scratch_ + nbuf; - } else { - // Pass pointer to buffer returned by reader_. - ip_ = ip; - } - return true; -} - -template -static bool InternalUncompress(Source* r, - Writer* writer, - uint32 max_len) { - // Read the uncompressed length from the front of the compressed input - SnappyDecompressor decompressor(r); - uint32 uncompressed_len = 0; - if (!decompressor.ReadUncompressedLength(&uncompressed_len)) return false; - // Protect against possible DoS attack - if (static_cast(uncompressed_len) > max_len) { - return false; - } - - writer->SetExpectedLength(uncompressed_len); - - // Process the entire input - decompressor.DecompressAllTags(writer); - return (decompressor.eof() && writer->CheckLength()); -} - -bool GetUncompressedLength(Source* source, uint32* result) { - SnappyDecompressor decompressor(source); - return decompressor.ReadUncompressedLength(result); -} - -size_t Compress(Source* reader, Sink* writer) { - size_t written = 0; - int N = reader->Available(); - char ulength[Varint::kMax32]; - char* p = Varint::Encode32(ulength, N); - writer->Append(ulength, p-ulength); - written += (p - ulength); - - internal::WorkingMemory wmem; - char* scratch = NULL; - char* scratch_output = NULL; - - while (N > 0) { - // Get next block to compress (without copying if possible) - size_t fragment_size; - const char* fragment = reader->Peek(&fragment_size); - DCHECK_NE(fragment_size, 0) << ": premature end of input"; - const int num_to_read = min(N, kBlockSize); - size_t bytes_read = fragment_size; - - int pending_advance = 0; - if (bytes_read >= num_to_read) { - // Buffer returned by reader is large enough - pending_advance = num_to_read; - fragment_size = num_to_read; - } else { - // Read into scratch buffer - if (scratch == NULL) { - // If this is the last iteration, we want to allocate N bytes - // of space, otherwise the max possible kBlockSize space. - // num_to_read contains exactly the correct value - scratch = new char[num_to_read]; - } - memcpy(scratch, fragment, bytes_read); - reader->Skip(bytes_read); - - while (bytes_read < num_to_read) { - fragment = reader->Peek(&fragment_size); - size_t n = min(fragment_size, num_to_read - bytes_read); - memcpy(scratch + bytes_read, fragment, n); - bytes_read += n; - reader->Skip(n); - } - DCHECK_EQ(bytes_read, num_to_read); - fragment = scratch; - fragment_size = num_to_read; - } - DCHECK_EQ(fragment_size, num_to_read); - - // Get encoding table for compression - int table_size; - uint16* table = wmem.GetHashTable(num_to_read, &table_size); - - // Compress input_fragment and append to dest - const int max_output = MaxCompressedLength(num_to_read); - - // Need a scratch buffer for the output, in case the byte sink doesn't - // have room for us directly. - if (scratch_output == NULL) { - scratch_output = new char[max_output]; - } else { - // Since we encode kBlockSize regions followed by a region - // which is <= kBlockSize in length, a previously allocated - // scratch_output[] region is big enough for this iteration. - } - char* dest = writer->GetAppendBuffer(max_output, scratch_output); - char* end = internal::CompressFragment(fragment, fragment_size, - dest, table, table_size); - writer->Append(dest, end - dest); - written += (end - dest); - - N -= num_to_read; - reader->Skip(pending_advance); - } - - delete[] scratch; - delete[] scratch_output; - - return written; -} - -// ----------------------------------------------------------------------- -// Flat array interfaces -// ----------------------------------------------------------------------- - -// A type that writes to a flat array. -// Note that this is not a "ByteSink", but a type that matches the -// Writer template argument to SnappyDecompressor::DecompressAllTags(). -class SnappyArrayWriter { - private: - char* base_; - char* op_; - char* op_limit_; - - public: - inline explicit SnappyArrayWriter(char* dst) - : base_(dst), - op_(dst) { - } - - inline void SetExpectedLength(size_t len) { - op_limit_ = op_ + len; - } - - inline bool CheckLength() const { - return op_ == op_limit_; - } - - inline bool Append(const char* ip, uint32 len, bool allow_fast_path) { - char* op = op_; - const int space_left = op_limit_ - op; - if (allow_fast_path && len <= 16 && space_left >= 16) { - // Fast path, used for the majority (about 90%) of dynamic invocations. - UNALIGNED_STORE64(op, UNALIGNED_LOAD64(ip)); - UNALIGNED_STORE64(op + 8, UNALIGNED_LOAD64(ip + 8)); - } else { - if (space_left < len) { - return false; - } - memcpy(op, ip, len); - } - op_ = op + len; - return true; - } - - inline bool AppendFromSelf(uint32 offset, uint32 len) { - char* op = op_; - const int space_left = op_limit_ - op; - - if (op - base_ <= offset - 1u) { // -1u catches offset==0 - return false; - } - if (len <= 16 && offset >= 8 && space_left >= 16) { - // Fast path, used for the majority (70-80%) of dynamic invocations. - UNALIGNED_STORE64(op, UNALIGNED_LOAD64(op - offset)); - UNALIGNED_STORE64(op + 8, UNALIGNED_LOAD64(op - offset + 8)); - } else { - if (space_left >= len + kMaxIncrementCopyOverflow) { - IncrementalCopyFastPath(op - offset, op, len); - } else { - if (space_left < len) { - return false; - } - IncrementalCopy(op - offset, op, len); - } - } - - op_ = op + len; - return true; - } -}; - -bool RawUncompress(const char* compressed, size_t n, char* uncompressed) { - ByteArraySource reader(compressed, n); - return RawUncompress(&reader, uncompressed); -} - -bool RawUncompress(Source* compressed, char* uncompressed) { - SnappyArrayWriter output(uncompressed); - return InternalUncompress(compressed, &output, kuint32max); -} - -bool Uncompress(const char* compressed, size_t n, string* uncompressed) { - size_t ulength; - if (!GetUncompressedLength(compressed, n, &ulength)) { - return false; - } - // Protect against possible DoS attack - if ((static_cast(ulength) + uncompressed->size()) > - uncompressed->max_size()) { - return false; - } - STLStringResizeUninitialized(uncompressed, ulength); - return RawUncompress(compressed, n, string_as_array(uncompressed)); -} - - -// A Writer that drops everything on the floor and just does validation -class SnappyDecompressionValidator { - private: - size_t expected_; - size_t produced_; - - public: - inline SnappyDecompressionValidator() : produced_(0) { } - inline void SetExpectedLength(size_t len) { - expected_ = len; - } - inline bool CheckLength() const { - return expected_ == produced_; - } - inline bool Append(const char* ip, uint32 len, bool allow_fast_path) { - produced_ += len; - return produced_ <= expected_; - } - inline bool AppendFromSelf(uint32 offset, uint32 len) { - if (produced_ <= offset - 1u) return false; // -1u catches offset==0 - produced_ += len; - return produced_ <= expected_; - } -}; - -bool IsValidCompressedBuffer(const char* compressed, size_t n) { - ByteArraySource reader(compressed, n); - SnappyDecompressionValidator writer; - return InternalUncompress(&reader, &writer, kuint32max); -} - -void RawCompress(const char* input, - size_t input_length, - char* compressed, - size_t* compressed_length) { - ByteArraySource reader(input, input_length); - UncheckedByteArraySink writer(compressed); - Compress(&reader, &writer); - - // Compute how many bytes were added - *compressed_length = (writer.CurrentDestination() - compressed); -} - -size_t Compress(const char* input, size_t input_length, string* compressed) { - // Pre-grow the buffer to the max length of the compressed output - compressed->resize(MaxCompressedLength(input_length)); - - size_t compressed_length; - RawCompress(input, input_length, string_as_array(compressed), - &compressed_length); - compressed->resize(compressed_length); - return compressed_length; -} - - -} // end namespace snappy - diff --git a/cppForSwig/leveldbwin/snappy_src/snappy.h b/cppForSwig/leveldbwin/snappy_src/snappy.h deleted file mode 100644 index 8d6ef2294..000000000 --- a/cppForSwig/leveldbwin/snappy_src/snappy.h +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2005 and onwards Google Inc. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// A light-weight compression algorithm. It is designed for speed of -// compression and decompression, rather than for the utmost in space -// savings. -// -// For getting better compression ratios when you are compressing data -// with long repeated sequences or compressing data that is similar to -// other data, while still compressing fast, you might look at first -// using BMDiff and then compressing the output of BMDiff with -// Snappy. - -#ifndef UTIL_SNAPPY_SNAPPY_H__ -#define UTIL_SNAPPY_SNAPPY_H__ - -#include -#include - -#include "snappy-stubs-public.h" - -namespace snappy { - class Source; - class Sink; - - // ------------------------------------------------------------------------ - // Generic compression/decompression routines. - // ------------------------------------------------------------------------ - - // Compress the bytes read from "*source" and append to "*sink". Return the - // number of bytes written. - size_t Compress(Source* source, Sink* sink); - - bool GetUncompressedLength(Source* source, uint32* result); - - // ------------------------------------------------------------------------ - // Higher-level string based routines (should be sufficient for most users) - // ------------------------------------------------------------------------ - - // Sets "*output" to the compressed version of "input[0,input_length-1]". - // Original contents of *output are lost. - // - // REQUIRES: "input[]" is not an alias of "*output". - size_t Compress(const char* input, size_t input_length, string* output); - - // Decompresses "compressed[0,compressed_length-1]" to "*uncompressed". - // Original contents of "*uncompressed" are lost. - // - // REQUIRES: "compressed[]" is not an alias of "*uncompressed". - // - // returns false if the message is corrupted and could not be decompressed - bool Uncompress(const char* compressed, size_t compressed_length, - string* uncompressed); - - - // ------------------------------------------------------------------------ - // Lower-level character array based routines. May be useful for - // efficiency reasons in certain circumstances. - // ------------------------------------------------------------------------ - - // REQUIRES: "compressed" must point to an area of memory that is at - // least "MaxCompressedLength(input_length)" bytes in length. - // - // Takes the data stored in "input[0..input_length]" and stores - // it in the array pointed to by "compressed". - // - // "*compressed_length" is set to the length of the compressed output. - // - // Example: - // char* output = new char[snappy::MaxCompressedLength(input_length)]; - // size_t output_length; - // RawCompress(input, input_length, output, &output_length); - // ... Process(output, output_length) ... - // delete [] output; - void RawCompress(const char* input, - size_t input_length, - char* compressed, - size_t* compressed_length); - - // Given data in "compressed[0..compressed_length-1]" generated by - // calling the Snappy::Compress routine, this routine - // stores the uncompressed data to - // uncompressed[0..GetUncompressedLength(compressed)-1] - // returns false if the message is corrupted and could not be decrypted - bool RawUncompress(const char* compressed, size_t compressed_length, - char* uncompressed); - - // Given data from the byte source 'compressed' generated by calling - // the Snappy::Compress routine, this routine stores the uncompressed - // data to - // uncompressed[0..GetUncompressedLength(compressed,compressed_length)-1] - // returns false if the message is corrupted and could not be decrypted - bool RawUncompress(Source* compressed, char* uncompressed); - - // Returns the maximal size of the compressed representation of - // input data that is "source_bytes" bytes in length; - size_t MaxCompressedLength(size_t source_bytes); - - // REQUIRES: "compressed[]" was produced by RawCompress() or Compress() - // Returns true and stores the length of the uncompressed data in - // *result normally. Returns false on parsing error. - // This operation takes O(1) time. - bool GetUncompressedLength(const char* compressed, size_t compressed_length, - size_t* result); - - // Returns true iff the contents of "compressed[]" can be uncompressed - // successfully. Does not return the uncompressed data. Takes - // time proportional to compressed_length, but is usually at least - // a factor of four faster than actual decompression. - bool IsValidCompressedBuffer(const char* compressed, - size_t compressed_length); - - // *** DO NOT CHANGE THE VALUE OF kBlockSize *** - // - // New Compression code chops up the input into blocks of at most - // the following size. This ensures that back-references in the - // output never cross kBlockSize block boundaries. This can be - // helpful in implementing blocked decompression. However the - // decompression code should not rely on this guarantee since older - // compression code may not obey it. - static const int kBlockLog = 15; - static const int kBlockSize = 1 << kBlockLog; - - static const int kMaxHashTableBits = 14; - static const int kMaxHashTableSize = 1 << kMaxHashTableBits; - -} // end namespace snappy - - -#endif // UTIL_SNAPPY_SNAPPY_H__ diff --git a/cppForSwig/main.cpp b/cppForSwig/main.cpp index 883903a95..825c88a02 100644 --- a/cppForSwig/main.cpp +++ b/cppForSwig/main.cpp @@ -80,6 +80,7 @@ int main(int argc, char* argv[]) { //setup remote peers db, this will block the init process until //peers db is unlocked + LOGINFO << "datadir: " << Armory::Config::getDataDir(); auto&& passLbd = TerminalPassphrasePrompt::getLambda("peers db"); WebSocketServer::initAuthPeers(passLbd); } diff --git a/cppForSwig/protobuf/BridgeProto.proto b/cppForSwig/protobuf/BridgeProto.proto new file mode 100644 index 000000000..abbd43941 --- /dev/null +++ b/cppForSwig/protobuf/BridgeProto.proto @@ -0,0 +1,773 @@ +syntax = "proto2"; + +package BridgeProto; + +//////////////////////////////////////////////////////////////////////////////// +// RestoreWallet messages +message RestoreWalletPayload +{ + repeated string root = 1; + repeated string secondary = 2; + optional string spPass = 3; +} + +message RestorePrompt +{ + message TypeError + { + required string error = 1; + } + + message ChecksumIndexes + { + repeated int32 index = 1; + } + + message CheckWalletId + { + required string wallet_id = 1; + required int32 backup_type = 2; + } + + oneof prompt { + CheckWalletId check_wallet_id = 10; + bool get_passphrases = 11; + bool decrypt_error = 12; + + TypeError type_error = 20; + ChecksumIndexes checksum_error = 21; + ChecksumIndexes checksum_mismatch = 22; + } +} + +message RestoreReply +{ + message Passphrases + { + required string control = 1; + required string privkey = 2; + } + + required bool success = 1; + oneof reply { + Passphrases passphrases = 11; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +//// Data types +// +//////////////////////////////////////////////////////////////////////////////// +message Ledger +{ + required int64 value = 1; + required bytes hash = 2; + required string id = 3; + required uint32 height = 4; + required uint32 tx_index = 5; + required uint32 tx_time = 6; + required bool coinbase = 7; + required bool sent_to_self = 8; + required bool change_back = 9; + required bool chained_zc = 10; + required bool witness = 11; + required bool rbf = 12; + repeated bytes scraddr = 13; +} + +message NodeStatus +{ + message NodeChainStatus + { + required uint32 chain_state = 2; + required float block_speed = 3; + required float progress_pct = 4; + required uint64 eta = 5; + required uint32 blocks_left = 6; + } + + required bool is_valid = 1; + optional uint32 node_state = 10; + optional bool is_segwit_enabled = 11; + optional uint32 rpc_state = 12; + optional NodeChainStatus chain_status = 13; +} + +message Utxo +{ + required bytes tx_hash = 1; + required uint32 txout_index = 2; + + required uint64 value = 3; + required uint32 tx_height = 4; + required uint32 tx_index = 5; + + required bytes script = 6; + required bytes scraddr = 7; +} + +//////////////////////////////////////////////////////////////////////////////// +// +//// Callbacks +// +//////////////////////////////////////////////////////////////////////////////// + +message CallbackPush +{ + message Ready { + required uint32 height = 1; + } + message SetupDone{} + message Disconnected{} + + message Registered { + repeated string id = 1; + } + + message Refresh { + repeated string id = 1; + } + + message NewBlock { + required uint32 height = 1; + } + + message Progress { + optional uint32 phase = 1; + required float progress = 2; + optional uint32 eta_sec = 3; + required uint32 progress_numeric = 4; + + repeated string id = 10; + } + + message ZeroConf { + repeated Ledger ledger = 1; + } + + //// + message UnlockRequest { + repeated string encryption_key_ids = 1; + } + + //// + required string callback_id = 1; + optional uint32 reference_id = 2; + + oneof push_payload { + Ready ready = 10; + SetupDone setup_done = 11; + Registered registered = 12; + Refresh refresh = 13; + NewBlock new_block = 14; + Disconnected disconnected = 15; + Progress progress = 20; + NodeStatus node_status = 21; + ZeroConf zero_conf = 22; + string error = 30; + bool cleanup = 40; + UnlockRequest unlock_request = 41; + } +} + +message CallbackReply +{ + required bool success = 1; + required uint32 reference_id = 2; + + oneof reply_payload { + string passphrase = 10; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +//// Request +// +//////////////////////////////////////////////////////////////////////////////// +message BlockchainService +{ + message LoadWallets { + required string callback_id = 1; + } + message RegisterWallet { + required string id = 1; + required bool is_new = 2; + } + + message BroadcastTx { + repeated bytes raw_tx = 1; + } + message GetTxByHash { + required bytes tx_hash = 1; + } + message GetHeaderByHeight { + required uint32 height = 1; + } + message GetBlockTimeByHeight { + required uint32 height = 1; + } + message EstimateFee { + required uint32 blocks = 1; + required string strat = 2; + } + + message UpdateWalletsLedgerFilter { + repeated string wallet_id = 1; + } + + message GetHistoryPageForDelegate { + required string delegate_id = 1; + required uint32 page_id = 2; + } + + message GetHistoryForWalletSelection { + repeated string wallet_id = 1; + required string order = 2; + } + + //// + oneof method { + bool shutdown = 1; + bool setup_db = 2; + bool go_online = 3; + bool get_node_status = 4; + LoadWallets load_wallets = 5; + bool register_wallets = 6; + + RegisterWallet register_wallet = 10; + BroadcastTx broadcast_tx = 11; + GetTxByHash get_tx_by_hash = 12; + GetHeaderByHeight get_header_by_height = 13; + GetBlockTimeByHeight get_block_time_by_height = 14; + EstimateFee estimate_fee = 15; + + bool get_ledger_delegate_id_for_wallets = 20; + UpdateWalletsLedgerFilter update_wallets_ledger_filter = 21; + GetHistoryPageForDelegate get_history_page_for_delegate = 22; + GetHistoryForWalletSelection get_history_for_wallet_selection = 23; + } +} + +message Wallet +{ + message GetNewAddress { + required uint32 type = 1; + } + message GetChangeAddress { + required uint32 type = 1; + } + message PeekChangeAddress { + required uint32 type = 1; + } + + message ExtendAddressPool { + required uint32 count = 1; + required string callback_id = 2; + } + + message SetAddressTypeFor { + required bytes asset_id = 1; + required uint32 address_type = 2; + } + + message GetLedgerDelegateIdForScrAddr { + required bytes hash = 1; + } + + message SetupNewCoinSelectionInstance { + required uint32 height = 1; + } + message GetUtxosForValue { + required uint64 value = 1; + } + + message SetComment { + required bytes hash_key = 1; + required string comment = 2; + } + message SetLabels { + required string title = 1; + required string description = 2; + } + + message CreateBackupString { + required string callback_id = 1; + } + + //// + required string id = 1; + oneof method { + GetNewAddress get_new_address = 2; + GetChangeAddress get_change_address = 3; + PeekChangeAddress peek_change_address = 4; + + bool get_highest_used_index = 10; + ExtendAddressPool extend_address_pool = 11; + + CreateBackupString create_backup_string = 20; + bool delete = 21; + bool get_data = 22; + + bool get_addr_combined_list = 30; + SetAddressTypeFor set_address_type_for = 31; + + GetLedgerDelegateIdForScrAddr get_ledger_delegate_id_for_scraddr = 40; + bool get_balance_and_count = 41; + + SetupNewCoinSelectionInstance setup_new_coin_selection_instance = 50; + GetUtxosForValue get_utxos_for_value = 51; + bool get_spendable_zc_list = 52; + bool get_rbf_txout_list = 53; + + bool create_address_book = 60; + SetComment set_comment = 61; + SetLabels set_labels = 62; + } +} + +message CoinSelection +{ + message SetRecipient { + required string address = 1; + required uint64 value = 2; + required uint32 id = 3; + } + + message SelectUTXOs { + required uint32 flags = 1; + oneof fee { + uint64 flat_fee = 10; + float fee_byte = 11; + } + } + + message ProcessCustomUtxoList { + repeated Utxo utxos = 1; + required uint32 flags = 2; + oneof fee { + uint64 flat_fee = 10; + float fee_byte = 11; + } + } + + message GetFeeForMaxVal { + repeated Utxo utxos = 1; + optional float fee_byte = 2; + } + + //// + required string id = 1; + oneof method { + bool cleanup = 2; + bool reset = 3; + + SetRecipient set_recipient = 4; + SelectUTXOs select_utxos = 5; + + bool get_utxo_selection = 6; + bool get_flat_fee = 7; + bool get_fee_byte = 8; + bool get_size_estimate = 9; + + ProcessCustomUtxoList process_custom_utxo_list = 10; + GetFeeForMaxVal get_fee_for_max_val = 11; + } +} + +message Signer +{ + message SetVersion { + required uint32 version = 1; + } + message SetLockTime { + required uint32 lock_time = 1; + } + + message AddSpenderByOutpoint { + required bytes hash = 1; + required uint32 tx_out_id = 2; + required uint32 sequence = 3; + } + + message PopulateUtxo { + required bytes hash = 1; + required bytes script = 2; + required uint32 tx_out_id = 3; + required uint64 value = 4; + } + + message AddRecipient{ + required bytes script = 1; + required uint64 value = 2; + } + + message ToTxSigCollect { + required uint32 ustx_type = 1; + } + message FromTxSigCollect{ + required string tx_sig_collect = 1; + } + + message SignTx { + required string wallet_id = 1; + required string callback_id = 2; + } + message GetSignedStateForInput { + required uint32 input_id = 1; + } + + message Resolve { + required string wallet_id = 1; + } + message AddSupportingTx { + required bytes raw_tx = 1; + } + + //// + required string id = 1; + oneof method { + bool get_new = 2; + bool cleanup = 3; + + SetVersion set_version = 4; + SetLockTime set_lock_time = 5; + + AddSpenderByOutpoint add_spender_by_outpoint = 6; + PopulateUtxo populate_utxo = 7; + AddRecipient add_recipient = 8; + + ToTxSigCollect to_tx_sig_collect = 9; + FromTxSigCollect from_tx_sig_collect = 10; + + SignTx sign_tx = 11; + bool get_signed_tx = 12; + bool get_unsigned_tx = 13; + GetSignedStateForInput get_signed_state_for_input = 14; + + Resolve resolve = 15; + AddSupportingTx add_supporting_tx = 16; + + bool from_type = 17; + bool can_legacy_serialize = 18; + } +} + +message Utils +{ + message GenerateRandomHex { + required uint32 length = 1; + } + message GetHash160 { + required bytes data = 1; + } + + message GetScrAddrForAddrStr { + required string address = 1; + } + message GetNameForAddrType { + required int32 address_type = 1; + } + + message CreateWalletStruct + { + required uint32 lookup = 1; + optional string passphrase = 10; + optional string control_passphrase = 11; + optional bytes extra_entropy = 20; + + optional string label = 30; + optional string description = 31; + } + + oneof method { + GenerateRandomHex generate_random_hex = 1; + GetHash160 get_hash_160 = 2; + + GetScrAddrForAddrStr get_scraddr_for_addrstr = 3; + GetNameForAddrType get_name_for_addr_type = 4; + + CreateWalletStruct create_wallet = 5; + } +} + +message ScriptUtils +{ + message GetTxInScriptType { + required bytes hash = 1; + } + + //// + required bytes script = 1; + oneof method { + GetTxInScriptType get_txin_script_type = 2; + bool get_txout_script_type = 3; + + bool get_scraddr_for_script = 10; + bool get_last_push_data_in_script = 11; + bool get_txout_script_for_scraddr = 12; + bool get_addrstr_for_scraddr = 13; + } +} + +message Request +{ + required uint32 reference_id = 1; + + oneof method { + BlockchainService service = 20; + Wallet wallet = 21; + CoinSelection coin_selection = 22; + Signer signer = 23; + Utils utils = 24; + ScriptUtils script_utils = 25; + CallbackReply callback_reply = 30; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +//// Replies +// +//////////////////////////////////////////////////////////////////////////////// +message BlockchainServiceReply +{ + message FeeEstimate + { + required float fee_byte = 1; + required bool smart_fee = 2; + } + + message LedgerHistory { + repeated Ledger ledger = 1; + } + + message Tx + { + required bytes raw = 2; + optional uint32 height = 10; + optional uint32 tx_index = 11; + optional bool rbf = 20; + optional bool chained_zc = 21; + } + + // + oneof reply { + uint32 block_time = 10; + string ledger_delegate_id = 11; + bytes header_data = 12; + FeeEstimate fee_estimate = 13; + LedgerHistory ledger_history = 14; + Tx tx = 15; + NodeStatus node_status = 16; + } +} + +//// +message WalletReply +{ + message UtxoList { + repeated Utxo utxo = 1; + } + + //address book + message AddressBook { + message AddressBookEntry { + required bytes scraddr = 10; + repeated bytes tx_hash = 11; + } + + repeated AddressBookEntry address = 1; + } + + //wallet data + message AddressData + { + required int32 id = 1; + required uint32 addr_type = 2; + required bool is_used = 3; + required bool is_change = 4; + required bytes asset_id = 5; + required bool has_priv_key = 6; + required bool use_encryption = 7; + + required bytes prefixed_hash = 10; + required bytes public_key = 11; + optional bytes precursor_script = 12; + + required string address_string = 20; + } + + message WalletData + { + required string id = 1; + required int64 use_count = 2; + required int64 lookup_count = 3; + required bool watching_only = 4; + repeated uint32 address_type = 5; + required uint32 default_address_type = 6; + required bool use_encryption = 7; + required uint32 kdf_mem_req = 8; + + optional string label = 10; + optional string desc = 11; + + repeated AddressData address_data = 20; + + message Comment + { + required bytes key = 1; + required bytes val = 2; + } + repeated Comment comments = 30; + } + + message MultipleWalletData { + repeated WalletData wallet = 1; + } + + message BackupString + { + repeated string root_clear = 10; + repeated string chain_clear = 11; + + repeated string root_encr = 20; + repeated string chain_encr = 21; + + optional string sp_pass = 30; + } + + //address balance + message AddressBalanceData { + required bytes id = 1; + required BalanceAndCount balance = 2; + } + + message AddressAndBalanceData { + repeated AddressBalanceData balance = 1; + repeated AddressData updated_asset = 2; + } + + message BalanceAndCount { + required uint64 full = 1; + required uint64 spendable = 2; + required uint64 unconfirmed = 3; + required uint64 count = 4; + } + + // + oneof reply { + int32 highest_used_index = 10; + string coin_selection_id = 11; + string ledger_delegate_id = 12; + BalanceAndCount balance_and_count = 13; + AddressAndBalanceData address_and_balance_data = 14; + UtxoList utxo_list = 15; + AddressBook address_book = 16; + + AddressData address_data = 20; + WalletData wallet_data = 21; + MultipleWalletData multiple_wallets = 22; + BackupString backup_string = 23; + } +} + +//// +message CoinSelectionReply +{ + message UtxoList { + repeated Utxo utxo = 1; + } + + // + oneof reply { + uint64 flat_fee = 10; + float fee_byte = 11; + uint32 size_estimate = 12; + UtxoList utxo_list = 13; + } +} + +//// +message SignerReply +{ + message InputSignedState { + required bool is_valid = 1; + required uint32 m = 2; + required uint32 n = 3; + + required uint32 sig_count = 10; + + message PubKeySignatureState + { + required bytes pub_key = 1; + required bool has_sig = 2; + } + repeated PubKeySignatureState sign_state = 11; + } + + // + oneof reply { + string signer_id = 10; + uint32 from_type = 11; + string tx_sig_collect = 12; + bytes tx_data = 13; + InputSignedState input_signed_state = 14; + } +} + +//// +message UtilsReply +{ + oneof reply { + string random_hex = 10; + string address_type_name = 11; + string wallet_id = 12; + bytes hash = 13; + bytes scraddr = 14; + } +} + +//// +message ScriptUtilsReply +{ + oneof reply { + uint32 txin_script_type = 10; + uint32 txout_script_type = 11; + string address_string = 12; + bytes scraddr = 13; + bytes push_data = 14; + bytes script_data = 15; + } +} + +//// +message Reply +{ + required bool success = 1; + optional uint32 reference_id = 2; + optional string error = 3; + + oneof reply_payload { + BlockchainServiceReply service = 10; + WalletReply wallet = 11; + CoinSelectionReply coin_selection = 12; + SignerReply signer = 13; + UtilsReply utils = 14; + ScriptUtilsReply script_utils = 15; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +//// Wrapper message +// +//////////////////////////////////////////////////////////////////////////////// +message Payload +{ + oneof payload { + Reply reply = 1; + CallbackPush callback = 2; + } +} \ No newline at end of file diff --git a/cppForSwig/protobuf/ClientProto.proto b/cppForSwig/protobuf/ClientProto.proto deleted file mode 100755 index 5207d96c4..000000000 --- a/cppForSwig/protobuf/ClientProto.proto +++ /dev/null @@ -1,429 +0,0 @@ -syntax = "proto2"; - -package Codec_ClientProto; - -enum Methods -{ - shutdown = 1; - - setupDB = 10; - goOnline = 11; - registerWallets = 12; - registerWallet = 13; - - loadWallets = 20; - getNodeStatus = 21; - returnPassphrase = 22; - broadcastTx = 23; - - getLedgerDelegateIdForWallets = 30; - updateWalletsLedgerFilter = 31; - getLedgerDelegateIdForScrAddr = 32; - - getHistoryPageForDelegate = 40; - getBalanceAndCount = 41; - getAddrCombinedList = 42; - - getTxByHash = 70; - getHeaderByHeight = 71; - createAddressBook = 72; - setComment = 73; - - getNewAddress = 80; - getChangeAddress = 81; - peekChangeAddress = 82; - getHighestUsedIndex = 83; - extendAddressPool = 84; - createWallet = 85; - createBackupStringForWallet = 86; - deleteWallet = 87; - getWalletData = 88; - - generateRandomHex = 90; - getTxInScriptType = 91; - getTxOutScriptType = 92; - getScrAddrForScript = 93; - getLastPushDataInScript = 94; - getTxOutScriptForScrAddr = 95; - getAddrStrForScrAddr = 96; - getNameForAddrType = 97; - setAddressTypeFor = 98; - getScrAddrForAddrStr = 99; - - getUtxosForValue = 100; - getSpendableZCList = 101; - getRBFTxOutList = 102; - - setupNewCoinSelectionInstance = 110; - destroyCoinSelectionInstance = 111; - resetCoinSelection = 112; - setCoinSelectionRecipient = 113; - cs_SelectUTXOs = 114; - cs_getUtxoSelection = 115; - cs_getFlatFee = 116; - cs_getFeeByte = 117; - cs_getSizeEstimate = 118; - cs_ProcessCustomUtxoList = 119; - - initNewSigner = 130; - destroySigner = 131; - signer_SetVersion = 132; - signer_SetLockTime = 133; - signer_addSpenderByOutpoint = 134; - signer_populateUtxo = 135; - signer_addRecipient = 136; - signer_getSerializedState = 137; - signer_unserializeState = 138; - signer_signTx = 139; - signer_getSignedTx = 140; - signer_getUnsignedTx = 141; - signer_getSignedStateForInput = 142; - signer_resolve = 143; - - getHash160 = 200; - getBlockTimeByHeight = 201; - estimateFee = 202; - - methodWithCallback = 220; -} - -enum MethodsWithCallback -{ - followUp = 1; - cleanup = 2; - - restoreWallet = 10; -} - -message ClientCommand -{ - required Methods method = 1; - required uint32 payloadId = 2; - - repeated string stringArgs = 3; - repeated uint32 intArgs = 4; - repeated bytes byteArgs = 5; - repeated uint64 longArgs = 6; - repeated float floatArgs = 7; - - optional MethodsWithCallback methodWithCallback = 10; -} - -//////////////////////////////////////////////////////////////////////////////// -// wallet public data -message WalletAsset -{ - required int32 id = 1; - required uint32 addrType = 2; - required bool isUsed = 3; - required bool isChange = 4; - required bytes assetId = 5; - - required bytes prefixedHash = 10; - required bytes publicKey = 11; - optional bytes precursorScript = 12; - - required string addressString = 20; -} - -message WalletData -{ - required string id = 1; - required int64 useCount = 2; - required int64 lookupCount = 3; - required bool watchingOnly = 4; - repeated uint32 addressTypes = 5; - required uint32 defaultAddressType = 6; - - optional string label = 10; - optional string desc = 11; - - repeated WalletAsset assets = 20; - - message Comment - { - required bytes key = 1; - required bytes val = 2; - } - - repeated Comment comments = 30; -} - -message WalletPayload -{ - repeated WalletData wallets = 1; -} - -//////////////////////////////////////////////////////////////////////////////// -// BDV callback -message CppBridgeCallback -{ - required uint32 type = 1; - - optional uint32 height = 10; - repeated string ids = 11; - - repeated bytes opaque = 20; -} - -message CppProgressCallback -{ - optional uint32 phase = 1; - required float progress = 2; - optional uint32 etaSec = 3; - required uint32 progressNumeric = 4; - - repeated string ids = 10; -} - -//////////////////////////////////////////////////////////////////////////////// -// Unlock prompt -enum UnlockPromptState -{ - start = 1; - stop = 2; - cycle = 3; -} - -enum UnlockPromptType -{ - decrypt = 1; - migrate = 2; -} - -message UnlockPromptCallback -{ - required bytes promptID = 1; - required UnlockPromptType promptType = 2; - required string verbose = 3; - required UnlockPromptState state = 4; - optional string walletID = 5; -} - -//////////////////////////////////////////////////////////////////////////////// -message BridgeLedger -{ - required int64 value = 1; - required bytes hash = 2; - required string id = 3; - required uint32 height = 4; - required uint32 txIndex = 5; - required uint32 txTime = 6; - required bool isCoinbase = 7; - required bool isSentToSelf = 8; - required bool isChangeBack = 9; - required bool isChainedZC = 10; - required bool isWitness = 11; - required bool isRBF = 12; - repeated bytes scrAddrList = 13; -} - -message BridgeLedgers -{ - repeated BridgeLedger le = 1; -} - -message BridgeNodeChainStatus -{ - required uint32 chainState = 2; - required float blockSpeed = 3; - required float progressPct = 4; - required uint64 eta = 5; - required uint32 blocksLeft = 6; -} - -message BridgeNodeStatus -{ - required bool isValid = 1; - - optional uint32 nodeState = 10; - optional bool isSegWitEnabled = 11; - optional uint32 rpcState = 12; - optional BridgeNodeChainStatus chainStatus = 13; -} - -message BridgeBalanceAndCount -{ - required uint64 full = 1; - required uint64 spendable = 2; - required uint64 unconfirmed = 3; - required uint64 count = 4; -} - -message BridgeMultipleBalanceAndCount -{ - repeated bytes ids = 1; - repeated BridgeBalanceAndCount data = 2; - repeated WalletAsset updatedAssets = 3; -} - -message BridgeTx -{ - required bool isValid = 1; - optional bytes raw = 2; - - optional uint32 height = 10; - optional uint32 txIndex = 11; - - optional bool isRBF = 20; - optional bool isChainedZC = 21; -} - -message ReplyBinary -{ - repeated bytes reply = 30; -} - -message ReplyStrings -{ - repeated string reply = 31; -} - -message ReplyNumbers -{ - repeated uint32 ints = 40; - repeated uint64 longs = 41; - repeated float floats = 42; -} - -message BridgeAddressBookEntry -{ - required bytes scrAddr = 1; - repeated bytes txHashes = 2; -} - -message BridgeAddressBook -{ - repeated BridgeAddressBookEntry data = 1; -} - -message BridgeUtxo -{ - required bytes txHash = 1; - required uint32 txOutIndex = 2; - - required uint64 value = 3; - required uint32 txHeight = 4; - required uint32 txIndex = 5; - - required bytes script = 6; - required bytes scrAddr = 7; -} - -message BridgeUtxoList -{ - repeated BridgeUtxo data = 1; -} - -message BridgeInputSignedState -{ - required bool isValid = 1; - required uint32 m = 2; - required uint32 n = 3; - - required uint32 sigCount = 10; - repeated PubKeySignatureState signStateList = 11; - - message PubKeySignatureState - { - required bytes pubKey = 1; - required bool hasSig = 2; - } -} - -message ReplyError -{ - required bool isError = 24; - required string error = 25; - optional uint32 code = 26; -} - -message BridgeFeeEstimate -{ - required float feeByte = 1; - optional bool smartFee = 2; - optional string error = 3; -} - -//////////////////////////////////////////////////////////////////////////////// -// Wallet creation messages -message BridgeCreateWalletStruct -{ - required uint32 lookup = 1; - - optional string passphrase = 10; - optional string controlPassphrase = 11; - - optional bytes extraEntropy = 20; - - optional string label = 30; - optional string description = 31; -} - -message BridgeBackupString -{ - required bool isvalid = 1; - - repeated string rootclear = 10; - repeated string chainclear = 11; - - repeated string rootencr = 20; - repeated string chainencr = 21; - - optional string sppass = 5; -} - -//////////////////////////////////////////////////////////////////////////////// -// Opaque payloads - -enum OpaquePayloadType -{ - prompt = 1; - commandWithCallback = 2; -} - -message OpaquePayload -{ - required OpaquePayloadType payloadType = 1; - optional bytes uniqueId = 2; - optional uint32 intId = 3; - - optional bytes payload = 10; -} - -//////////////////////////////////////////////////////////////////////////////// -// RestoreWallet messages -message RestoreWalletPayload -{ - repeated string root = 1; - repeated string secondary = 2; - optional string spPass = 3; -} - -enum RestorePromptType -{ - FormatError = 1; - Failure = 2; - ChecksumError = 3; - DecryptError = 4; - Passphrase = 5; - Control = 6; - Id = 7; - TypeError = 8; - Success = 9; - UnknownError = 10; -} - -message RestorePrompt -{ - - required RestorePromptType promptType = 1; - repeated int32 checksums = 2; - optional string extra = 3; -} - -message RestoreReply -{ - required bool result = 1; - optional bytes extra = 2; -} diff --git a/jasvet.py b/jasvet.py new file mode 100644 index 000000000..bedb7e00e --- /dev/null +++ b/jasvet.py @@ -0,0 +1,683 @@ +#!/usr/bin/env python + +# jackjack's signing/verifying tool +# verifies base64 signatures from Bitcoin +# signs message in three formats: +# - Bitcoin base64 (compatible with Bitcoin) +# - ASCII armored, Clearsign +# - ASCII armored, Base64 +# +# Licence: Public domain or CC0 + +from __future__ import print_function +import base64 +import hashlib +import random +import time + +#import CppBlockUtils +from armoryengine.ArmoryUtils import getVersionString, BTCARMORY_VERSION, \ + ChecksumError, ADDRBYTE + + +FTVerbose=False + +version='0.1.0' + +_p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F +_r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 +_b = 0x0000000000000000000000000000000000000000000000000000000000000007 +_a = 0x0000000000000000000000000000000000000000000000000000000000000000 +_Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 +_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 + +BEGIN_MARKER = '-----BEGIN ' +END_MARKER = '-----END ' +DASHX5 = '-----' +RN = '\r\n' +RNRN = '\r\n\r\n' +CLEARSIGN_MSG_TYPE_MARKER = 'BITCOIN SIGNED MESSAGE' +BITCOIN_SIG_TYPE_MARKER = 'BITCOIN SIGNATURE' +BASE64_MSG_TYPE_MARKER = 'BITCOIN MESSAGE' +BITCOIN_ARMORY_COMMENT = '' +class UnknownSigBlockType(Exception): pass + +def randomk(): + # Using Crypto++ CSPRNG instead of python's + #sbdRandK = CppBlockUtils.SecureBinaryData().GenerateRandom(32) + sbdRandK = 0 + hexRandK = sbdRandK.toBinStr().encode('hex_codec') + return int(hexRandK, 16) + + +# Common constants/functions for Bitcoin +def hash_160_to_bc_address(h160, addrtype=0): + vh160 = chr(addrtype) + h160 + h = Hash(vh160) + addr = vh160 + h[0:4] + return b58encode(addr) + +def bc_address_to_hash_160(addr): + hash160 = b58decode(addr, 25) + return hash160[1:21] + +def Hash(data): + return hashlib.sha256(hashlib.sha256(data).digest()).digest() + +def sha256(data): + return hashlib.sha256(data).digest() + +def sha1(data): + return hashlib.sha1(data).digest() + +__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' +__b58base = len(__b58chars) + +def b58encode(v): + long_value = 0 + for (i, c) in enumerate(v[::-1]): + long_value += (256**i) * ord(c) + + result = '' + while long_value >= __b58base: + div, mod = divmod(long_value, __b58base) + result = __b58chars[mod] + result + long_value = div + result = __b58chars[long_value] + result + + nPad = 0 + for c in v: + if c == '\0': nPad += 1 + else: break + + return (__b58chars[0]*nPad) + result + +def b58decode(v, length): + long_value = 0 + for (i, c) in enumerate(v[::-1]): + long_value += __b58chars.find(c) * (__b58base**i) + + result = '' + while long_value >= 256: + div, mod = divmod(long_value, 256) + result = chr(mod) + result + long_value = div + result = chr(long_value) + result + + nPad = 0 + for c in v: + if c == __b58chars[0]: nPad += 1 + else: break + + result = chr(0)*nPad + result + if length is not None and len(result) != length: + return None + + return result + +def ASecretToSecret(key): + vch = DecodeBase58Check(key) + if vch and vch[0] == chr(128): + return vch[1:] + else: + return False + +def DecodeBase58Check(psz): + vchRet = b58decode(psz, None) + key = vchRet[0:-4] + csum = vchRet[-4:] + hashValue = Hash(key) + cs32 = hashValue[0:4] + if cs32 != csum: + return None + else: + return key + + +def regenerate_key(sec): + b = ASecretToSecret(sec) + if not b: + return False + b = b[0:32] + secret = int('0x' + b.encode('hex'), 16) + return EC_KEY(secret) + +def GetPubKey(pkey, compressed=False): + return i2o_ECPublicKey(pkey, compressed) + +def GetPrivKey(pkey, compressed=False): + return i2d_ECPrivateKey(pkey, compressed) + +def GetSecret(pkey): + return ('%064x' % pkey.secret).decode('hex') + + +def i2d_ECPrivateKey(pkey, compressed=False):#, crypted=True): + part3='a081a53081a2020101302c06072a8648ce3d0101022100' # for uncompressed keys + if compressed: + if True:#not crypted: ## Bitcoin accepts both part3's for crypted wallets... + part3='a08185308182020101302c06072a8648ce3d0101022100' # for compressed keys + key = '3081d30201010420' + \ + '%064x' % pkey.secret + \ + part3 + \ + '%064x' % _p + \ + '3006040100040107042102' + \ + '%064x' % _Gx + \ + '022100' + \ + '%064x' % _r + \ + '020101a124032200' + else: + key = '308201130201010420' + \ + '%064x' % pkey.secret + \ + part3 + \ + '%064x' % _p + \ + '3006040100040107044104' + \ + '%064x' % _Gx + \ + '%064x' % _Gy + \ + '022100' + \ + '%064x' % _r + \ + '020101a144034200' + + return key.decode('hex') + i2o_ECPublicKey(pkey, compressed) + +def i2o_ECPublicKey(pkey, compressed=False): + if compressed: + if pkey.pubkey.point.y() & 1: + key = '03' + '%064x' % pkey.pubkey.point.x() + else: + key = '02' + '%064x' % pkey.pubkey.point.x() + else: + key = '04' + \ + '%064x' % pkey.pubkey.point.x() + \ + '%064x' % pkey.pubkey.point.y() + + return key.decode('hex') + +def hash_160(public_key): + md = hashlib.new('ripemd160') + md.update(hashlib.sha256(public_key).digest()) + return md.digest() + +def public_key_to_bc_address(public_key, v=ADDRBYTE): + h160 = hash_160(public_key) + if isinstance(v, str): + v = ord(v) + return hash_160_to_bc_address(h160, v) + +def inverse_mod( a, m ): + if a < 0 or m <= a: a = a % m + c, d = a, m + uc, vc, ud, vd = 1, 0, 0, 1 + while c != 0: + q, c, d = divmod( d, c ) + ( c, ) + uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc + assert d == 1 + if ud > 0: return ud + else: return ud + m + +class CurveFp( object ): + def __init__( self, p, a, b ): + self.__p = p + self.__a = a + self.__b = b + + def p( self ): + return self.__p + + def a( self ): + return self.__a + + def b( self ): + return self.__b + + def contains_point( self, x, y ): + return ( y * y - ( x * x * x + self.__a * x + self.__b ) ) % self.__p == 0 + +class Point( object ): + def __init__( self, curve, x, y, order = None ): + self.__curve = curve + self.__x = x + self.__y = y + self.__order = order + if self.__curve: assert self.__curve.contains_point( x, y ) + if order: assert self * order == INFINITY + + def __add__( self, other ): + if other == INFINITY: return self + if self == INFINITY: return other + assert self.__curve == other.__curve + if self.__x == other.__x: + if ( self.__y + other.__y ) % self.__curve.p() == 0: + return INFINITY + else: + return self.double() + + p = self.__curve.p() + l = ( ( other.__y - self.__y ) * \ + inverse_mod( other.__x - self.__x, p ) ) % p + x3 = ( l * l - self.__x - other.__x ) % p + y3 = ( l * ( self.__x - x3 ) - self.__y ) % p + return Point( self.__curve, x3, y3 ) + + def __mul__( self, other ): + def leftmost_bit( x ): + assert x > 0 + result = 1 + while result <= x: result = 2 * result + return result / 2 + + e = other + if self.__order: e = e % self.__order + if e == 0: return INFINITY + if self == INFINITY: return INFINITY + assert e > 0 + e3 = 3 * e + negative_self = Point( self.__curve, self.__x, -self.__y, self.__order ) + i = leftmost_bit( e3 ) / 2 + result = self + while i > 1: + result = result.double() + if ( e3 & i ) != 0 and ( e & i ) == 0: result = result + self + if ( e3 & i ) == 0 and ( e & i ) != 0: result = result + negative_self + i = i / 2 + return result + + def __rmul__( self, other ): + return self * other + + def __str__( self ): + if self == INFINITY: return "infinity" + return "(%d,%d)" % ( self.__x, self.__y ) + + def double( self ): + if self == INFINITY: + return INFINITY + + p = self.__curve.p() + a = self.__curve.a() + l = ( ( 3 * self.__x * self.__x + a ) * \ + inverse_mod( 2 * self.__y, p ) ) % p + x3 = ( l * l - 2 * self.__x ) % p + y3 = ( l * ( self.__x - x3 ) - self.__y ) % p + return Point( self.__curve, x3, y3 ) + + def x( self ): + return self.__x + + def y( self ): + return self.__y + + def curve( self ): + return self.__curve + + def order( self ): + return self.__order + +INFINITY = Point( None, None, None ) + +def str_to_long(b): + res = 0 + pos = 1 + for a in reversed(b): + res += ord(a) * pos + pos *= 256 + return res + +class Public_key( object ): + def __init__( self, generator, point, c ): + self.curve = generator.curve() + self.generator = generator + self.point = point + self.compressed = c + n = generator.order() + if not n: + raise RuntimeError("Generator point must have order.") + if not n * point == INFINITY: + raise RuntimeError("Generator point order is bad.") + if point.x() < 0 or n <= point.x() or point.y() < 0 or n <= point.y(): + raise RuntimeError("Generator point has x or y out of range.") + + def verify( self, hashValue, signature ): + if isinstance(hashValue, str): + hashValue=str_to_long(hashValue) + G = self.generator + n = G.order() + r = signature.r + s = signature.s + if r < 1 or r > n-1: return False + if s < 1 or s > n-1: return False + c = inverse_mod( s, n ) + u1 = ( hashValue * c ) % n + u2 = ( r * c ) % n + xy = u1 * G + u2 * self.point + v = xy.x() % n + return v == r + + def ser(self): + if self.compressed: + if self.point.y() & 1: + key = '03' + '%064x' % self.point.x() + else: + key = '02' + '%064x' % self.point.x() + else: + key = '04' + \ + '%064x' % self.point.x() + \ + '%064x' % self.point.y() + + return key.decode('hex') + + +class Signature( object ): + def __init__( self, r, s ): + self.r = r + self.s = s + + def ser(self): + return ("%064x%064x"%(self.r,self.s)).decode('hex') + +class Private_key( object ): + def __init__( self, public_key, secret_multiplier ): + self.public_key = public_key + self.secret_multiplier = secret_multiplier + +# def der( self ): +# hex_der_key = '06052b8104000a30740201010420' + \ +# '%064x' % self.secret_multiplier + \ +# 'a00706052b8104000aa14403420004' + \ +# '%064x' % self.public_key.point.x() + \ +# '%064x' % self.public_key.point.y() +# return hex_der_key.decode('hex') + + def sign( self, hashValue, random_k ): + if isinstance(hashValue, str): + hashValue=str_to_long(hashValue) + G = self.public_key.generator + n = G.order() + k = random_k % n + p1 = k * G + r = p1.x() + if r == 0: raise RuntimeError("amazingly unlucky random number r") + s = ( inverse_mod( k, n ) * \ + ( hashValue + ( self.secret_multiplier * r ) % n ) ) % n + if s == 0: raise RuntimeError("amazingly unlucky random number s") + return Signature( r, s ) + +class EC_KEY(object): + def __init__( self, secret, c=False): + curve = CurveFp( _p, _a, _b ) + generator = Point( curve, _Gx, _Gy, _r ) + self.pubkey = Public_key( generator, generator * secret, c ) + self.privkey = Private_key( self.pubkey, secret ) + self.secret = secret + +def decbin(d, l=0, rev=False): + if l==0: + a="%x"%d + if len(a)%2: a='0'+a + else: + a=("%0"+str(2*l)+"x")%d + a=a.decode('hex') + if rev: + a=a[::-1] + return a + +def decvi(d): + if d<0xfd: + return decbin(d) + elif d<0xffff: + return '\xfd'+decbin(d,2,True) + elif d<0xffffffff: + return '\xfe'+decbin(d,4,True) + return '\xff'+decbin(d,8,True) + +def format_msg_to_sign(msg): + return "\x18Bitcoin Signed Message:\n"+decvi(len(msg))+msg + +def sqrt_mod(a, p): + return pow(a, (p+1)/4, p) + + + +curve_secp256k1 = CurveFp (_p, _a, _b) +generator_secp256k1 = g = Point (curve_secp256k1, _Gx, _Gy, _r) +randrange = random.SystemRandom().randrange + +# Signing/verifying + +def verify_message_Bitcoin(signature, message, pureECDSASigning=False, networkVersionNumber=0): + msg=message + if not pureECDSASigning: + msg=Hash(format_msg_to_sign(message)) + + compressed=False + curve = curve_secp256k1 + G = generator_secp256k1 + _a,_b,_p=curve.a(),curve.b(),curve.p() + + order = G.order() + sig = base64.b64decode(signature) + if len(sig) != 65: + raise Exception("vmB","Bad signature") + + hb = ord(sig[0]) + r,s = map(str_to_long,[sig[1:33],sig[33:65]]) + + if hb < 27 or hb >= 35: + raise Exception("vmB","Bad first byte") + if hb >= 31: + compressed = True + hb -= 4 + + recid = hb - 27 + x = (r + (recid/2) * order) % _p + y2 = ( pow(x,3,_p) + _a*x + _b ) % _p + yomy = sqrt_mod(y2, _p) + if (yomy - recid) % 2 == 0: + y=yomy + else: + y=_p - yomy + + R = Point(curve, x, y, order) + e = str_to_long(msg) + minus_e = -e % order + inv_r = inverse_mod(r,order) + Q = inv_r * ( R*s + G*minus_e ) + public_key = Public_key(G, Q, compressed) + addr = public_key_to_bc_address(public_key.ser(), networkVersionNumber) + return addr + +def sign_message(secret, message, pureECDSASigning=False): + if len(secret) == 32: + pkey = EC_KEY(str_to_long(secret)) + compressed = False + elif len(secret) == 33: + pkey = EC_KEY(str_to_long(secret[:-1])) + secret=secret[:-1] + compressed = True + else: + raise Exception("sm","Bad private key size") + + msg=message + if not pureECDSASigning: + msg=Hash(format_msg_to_sign(message)) + + eckey = EC_KEY(str_to_long(secret), compressed) + private_key = eckey.privkey + public_key = eckey.pubkey + addr = public_key_to_bc_address(GetPubKey(eckey,eckey.pubkey.compressed)) + + sig = private_key.sign(msg, randomk()) + if not public_key.verify(msg, sig): + raise Exception("sm","Problem signing message") + return [sig,addr,compressed,public_key] + + +def sign_message_Bitcoin(secret, msg, pureECDSASigning=False): + sig,addr,compressed,public_key=sign_message(secret, msg, pureECDSASigning) + + for i in range(4): + hb=27+i + if compressed: + hb+=4 + sign=base64.b64encode(chr(hb)+sig.ser()) + try: + networkVersionNumber = str_to_long(b58decode(addr, None)) >> (8*24) + if addr == verify_message_Bitcoin(sign, msg, pureECDSASigning, networkVersionNumber): + return {'address':addr, 'b64-signature':sign, 'signature':chr(hb)+sig.ser(), 'message':msg} + except Exception as e: +# print e.args + pass + + raise Exception("smB","Unable to construct recoverable key") + +def FormatText(t, sigctx=False, verbose=False): #sigctx: False=what is displayed, True=what is signed + r='' + te=t.split('\n') + for l in te: + while len(l) and l[len(l)-1] in [' ', '\r', '\t', chr(9)]: + l=l[:-1] + if not len(l) or l[len(l)-1]!='\r': + l+='\r' + if not sigctx: + if len(l) and l[0]=='-': + l='- '+l + r+=l+'\n' + r=r[:-2] + + global FTVerbose + if FTVerbose: + print(' -- Sent: '+t.encode('hex')) + if sigctx: + print(' -- Signed: '+r.encode('hex')) + else: + print(' -- Displayed: '+r.encode('hex')) + + return r + + +def crc24(m): + INIT = 0xB704CE + POLY = 0x1864CFB + crc = INIT + r = '' + for o in m: + o=ord(o) + crc ^= (o << 16) + for i in xrange(8): + crc <<= 1 + if crc & 0x1000000: + crc ^= POLY + for i in range(3): + r += chr( ( crc & (0xff<<(8*i))) >> (8*i) ) + return r + +def chunks(t, n): + return [t[i:i+n] for i in range(0, len(t), n)] + +def ASCIIArmory(block, name, addComment=False): + + r=BEGIN_MARKER+name+DASHX5+RN + if addComment: + r+= BITCOIN_ARMORY_COMMENT + r+=RNRN + r+=RN.join(chunks(base64.b64encode(block), 64))+RN+'=' + r+=base64.b64encode(crc24(block))+RN + + r+=END_MARKER+name+DASHX5 + return r + +def readSigBlock(r): + # Take the name off of the end because the BEGIN markers are confusing + r = FormatText(r, True) + name = r.split(BEGIN_MARKER)[1].split(DASHX5)[0] + if name == BASE64_MSG_TYPE_MARKER: + encoded,crc = r.split(BEGIN_MARKER)[1].split(END_MARKER)[0].split(DASHX5)[1].strip().split('\n=') + crc = crc.strip() + # Always starts with a blank line (\r\n\r\n) chop that off with the comment oand process the rest + encoded = encoded.split(RNRN)[1] + # Combines 64 byte chunks that are separated by \r\n + encoded = ''.join(encoded.split(RN)) + # decode the message. + decoded = base64.b64decode(encoded) + # Check sum of decoded messgae + if base64.b64decode(crc) != crc24(decoded): + raise ChecksumError + # The signature is followed by the message and the whole thing is encoded + # The message always starts at 65 because the signature is 65 bytes. + signature = base64.b64encode(decoded[:65]) + msg = decoded[65:] + elif name == CLEARSIGN_MSG_TYPE_MARKER: + # First get rid of the Clearsign marker and everything before it in case the user + # added extra lines that would confuse the parsing that follows + # The message is preceded by a blank line (\r\n\r\n) chop that off with the comment and process the rest + # For Clearsign the message is unencoded since the message could include the \r\n\r\n we only ignore + # the first and combine the rest. + msg = r.split(BEGIN_MARKER+CLEARSIGN_MSG_TYPE_MARKER+DASHX5)[1] + msg = RNRN.join(msg.split(RNRN)[1:]) + msg = msg.split(RN+DASHX5)[0] + # Only the signature is encoded, use the original r to pull out the encoded signature + encoded = r.split(BEGIN_MARKER)[2].split(DASHX5)[1].split(BITCOIN_SIG_TYPE_MARKER)[0] + encoded, crc = encoded.split('\n=') + encoded = ''.join(encoded.split('\n')) + signature = ''.join(encoded.split('\r')) + crc = crc.strip() + if base64.b64decode(crc) != crc24(base64.b64decode(signature)): + raise ChecksumError + else: + raise UnknownSigBlockType() + return signature, msg + +#============================================== + +def verifySignature(b64sig, msg, signVer='v0', networkVersionNumber=0): + # If version 1, apply RFC2440 formatting rules to the message + if signVer=='v1': + msg = FormatText(msg, True) + return verify_message_Bitcoin(b64sig, msg, networkVersionNumber = networkVersionNumber) + +def ASv0(privkey, msg): + return sign_message_Bitcoin(privkey, msg) + +def ASv1CS(privkey, msg): + sig=ASv0(privkey, FormatText(msg)) + r=BEGIN_MARKER+CLEARSIGN_MSG_TYPE_MARKER+DASHX5+RN+BITCOIN_ARMORY_COMMENT+RN + r+=FormatText(msg)+RN + r+=ASCIIArmory(sig['signature'], BITCOIN_SIG_TYPE_MARKER) + return r + +def ASv1B64(privkey, msg): + sig=ASv0(privkey, FormatText(msg)) + return ASCIIArmory(sig['signature']+sig['message'], BASE64_MSG_TYPE_MARKER, True) + +#============================================== + +# +# Some tests with ugly output +# You can delete the print commands in FormatText() after testing +# + +if __name__=='__main__': + pvk1='\x01'*32 + text0='Hello world!' + text1='Hello world!\n' + text2='Hello world!\n\t' + text3='Hello world!\n-jackjack' + text4='Hello world!\n-jackjack ' + text5='Hello world!' + + FTVerbose=True + + sv0=ASv0(pvk1, text1) + print(sv0) + print(verifySignature(sv0['b64-signature'], sv0['message'], signVer='v0')) + print(ASv1B64(pvk1, text1)) + print() + print(ASv1CS(pvk1, text1)) + print() + print(ASv1CS(pvk1, text2)) + print() + print(ASv1CS(pvk1, text3)) + print() + print(ASv1CS(pvk1, text4)) + print() + print(ASv1CS(pvk1, text5)) \ No newline at end of file