diff --git a/.gitignore b/.gitignore index 6e7cc0f8c1..e27a4343b6 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ libconftest.dylib* *.o *.o-* *.patch +!depends/patches/*/*.patch .dynamic *.a *.pb.cc @@ -73,6 +74,7 @@ libconftest.dylib* *.json.h *.raw.h +*.cl.h #libtool object files *.lo @@ -134,3 +136,45 @@ dynamic-cli dynamicd dynamic-qt make + +# Compiled Object files +*.slo +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.lib + +# Executables +*.out +*.app + +# CMake +CMakeFiles/ +*.cmake +CMakeCache.txt +install_manifest.txt + +# Qt Creator +*.user +*.autosave + +# Visual Studio Code +.vscode/ + +# DHT Test binary +src/dht/test/data_test +.dht \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..aa09ba98ba --- /dev/null +++ b/.gitmodules @@ -0,0 +1,8 @@ +[submodule "src/bdap/vgp"] + path = src/bdap/vgp + url = https://github.com/duality-solutions/VGP.git + branch = master +[submodule "src/libtorrent"] + path = src/libtorrent + url = https://github.com/duality-solutions/libbdaptorrent.git + branch = incompatible diff --git a/.travis.yml b/.travis.yml index d613fde9b6..55bcd43ab5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,57 @@ language: cpp -compiler: gcc -os: linux +compiler: + - gcc +os: + - linux sudo: required -dist: trusty -install: - - sudo apt-get -qq update - - sudo apt-get install -y build-essential libtool autotools-dev autoconf pkg-config libssl-dev libboost-all-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler libcrypto++-dev libevent-dev - - sudo add-apt-repository -y ppa:silknetwork/silknetwork - - sudo apt-get update -y && sudo apt-get install -y libdb4.8-dev libdb4.8++-dev -script: - - ./autogen.sh && ./configure --with-gui=qt5 && make - -deploy: - provider: releases - file: "dynamic-qt" - skip_cleanup: true - on: - tags: true +dist: bionic +env: + global: + - MAKETHREADS="-j2" + - MAIN_PACKAGES="build-essential libtool autotools-dev autoconf libssl-dev libboost-all-dev libcrypto++-dev libevent-dev" + - QT_PACKAGES="libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler" + - GPU_PACKAGES="ocl-icd-opencl-dev" + - EXTRA_PPA="ppa:bitcoin/bitcoin" + - EXTRA_PPA_PACKAGES="libdb4.8-dev libdb4.8++-dev" +cache: + apt: true +addons: + apt: + packages: + - pkg-config +jobs: + include: + # Linux daemon and Qt wallet + - stage: build + name: 'Linux daemon and Qt wallet' + install: + - sudo apt-get install -y $MAIN_PACKAGES $QT_PACKAGES + - sudo add-apt-repository -y $EXTRA_PPA + - sudo apt-get update -y && sudo apt-get install -y $EXTRA_PPA_PACKAGES + script: + - ./autogen.sh + - ./configure --with-gui=qt5 --disable-tests --disable-bench + - make $MAKETHREADS + # Linux daemon only with GPU + - stage: build + name: 'Linux daemon only with GPU' + install: + - sudo apt-get install -y $MAIN_PACKAGES + - sudo add-apt-repository -y $EXTRA_PPA + - sudo apt-get update -y && sudo apt-get install -y $EXTRA_PPA_PACKAGES + - sudo apt-get install -y $GPU_PACKAGES + script: + - ./autogen.sh + - ./configure --without-gui --enable-gpu --disable-tests --disable-bench + - make $MAKETHREADS + # Linux daemon only with tests + - stage: build + name: 'Linux daemon only with tests' + install: + - sudo apt-get install -y $MAIN_PACKAGES + - sudo add-apt-repository -y $EXTRA_PPA + - sudo apt-get update -y && sudo apt-get install -y $EXTRA_PPA_PACKAGES + script: + - ./autogen.sh + - ./configure --without-gui + - make $MAKETHREADS \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b38f6f8ee9..b476ad25f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,601 @@ **Dynamic CHANGELOG** ------------------------- +**Dynamic v2.5.0.0** + + +* [BDAP] Add BDAP audits with meta data transactions +* [BDAP] Add BDAP x509 Certificate CA, requests and approval transactions +* [Build] Bump Boost version to 1.70 +* [Build] Upgrade to OpenSSL v1.1.1i +* [PoW] Change DAA parameters +* [RPC] Add getsubsidy RPC command +* [RPC] Add audits RPC commands +* [RPC] Add certificate RPC commands +* [Wallet] Disable wallet versions +* [Wallet] Fix wallet issue where too many keys were being created during rescans +* [Util] Fix add months to epoch functions +* [Params] Add checkpoints every 100,000 blocks +* [Doc] Update build documentation for Ubuntu 20.04 +* Bump protocol version to 72500 +* Bump client version to 2.5.0.0 + +**Dynamic v2.4.4.1** + +* Use std::function and std::bind in scheduler instead of boost/std mix +* [Dynode] Do not call sentinel methods when spork is inactive +* [Dynode] Remove dncache.dat file + + +**Dynamic v2.4.4.0** + +* [Qt] Update Splashscreen for v2.4.4.0 +* [RPC] More user-friendly error message when partially signing +* [Qt] Translations Updated +* [BDAP] Show fee required in the insufficient funds error message +* [BDAP] Use new epoch to string format function in Qt +* [Tests] Add unit test for new add months to epoch function +* [Util] Refactor add months to epoch functions +* [Test] Add unit tests for new format ISO date and time +* [BDAP] Fix comparison between signed and unsigned warning +* [RPC] Fix dynode-list bug + + +**Dynamic v2.4.3.0** + +* [BDAP] Remove second month overrun check +* Bump client and block version to 2.4.3.0 + + +**Dynamic v2.4.2.0** + +* [BDAP] Set maximum months stored in local accounts db +* [BDAP] Limit acount registration to 100 years +* [Mempool] Don't check if standard tx for BDAP txs in accept to mempool +* [BDAP] Remove maximum months for updated accounts +* [BDAP] Fix add months to block and epoch times +* [Util] Fix epoch to ISO date string conversion +* Bump client and block version to v2.4.2.0 +* Increase minimum protocol to v2.4 (71000) or greater +* [Wallet] Check txout instead of entire tx for BDAP + + +**Dynamic v2.4.1.0** + +* [Qt] Update/Add Languages +* [BDAP] Fix send BDAP transaction after removing credits from wallet GetBalance() method +* [Wallet] Prevent transactions that require Ed25519 keys if wallet needs upgrading. Notify user. +* [Wallet] Prevent ed25519 keypool crash when trying to erase from an empty set +* [FIX] Fix locked wallet upgrade issues. +* [RPC] Refactor all RPC code files in a seperate directory +* [LOG] Silence LogPrint when not finding Dynodes with votes +* [DHT] Return an empty JSON array when the denylink record is not found +* [HD] Move mnemonic wordlists to separate directory +* [FIX] Correct versioning for alert max version +* [Wallet] Remove BDAP credits from GetBalance method +* [BDAP] Fix send BDAP transaction after removing credits from wallet GetBalance() method + + +**Dynamic v2.4.0.0** + +* [DHT] Add more UDP ports and fix saving key in wallet +* [BDAP] Update enum item names so it doesn't overlap with Windows macros +* Merge pull request #25 from duality-solutions/windows +* [DHT] Add parameter info to RPC call error +* [BDAP] More fixes to private key wallet saving +* Merge pull request #26 from duality-solutions/dht-fixes2 +* [DHT] Fix put mutable value method +* [DHT] Fix salt parsing in the put save data method +* [DHT] Check signature and pubkey length before saving for put +* [DHT] Fix put by using fixed sizes for pubkey and signature. Use variable sizes for salt and value +* Merge pull request #27 from duality-solutions/fix-dht3 +* [DHT] Fix session event logging and searching memory maps +* [DHT] Use multimap and implement locks session events +* Resolve merge conflicts with v2.4-WIP +* [DHT] Rework libtorrent event threads +* [DHT] Fix async get operations +* [DHT] Add function to remove old libtorrent events from memory multimap +* [DHT] Fix MacOSX build warnings +* Merge branch 'v2.4-WIP' of https://github.com/duality-solutions/dynamic into merge-public +* [DHT] Fix put BDAP data function for mutable hash table database +* [DHT] Add RPC command that returns all put message events in memory +* [DHT] Add RPC command that returns all get mutable events in memory +* [DHT] Fix blocking alert thread issue affecting puts +* Merge branch 'v2.4-WIP' of https://github.com/duality-solutions/dynamic into merge-public +* Merge pull request #29 from duality-solutions/fix-dht5 +* Merge branch 'master' into merge-public +* Merge pull request #30 from duality-solutions/merge-public +* [DHT] Fix put wait for reponse +* [BDAP] Add dump bdap keys RPC command +* [BDAP] Add RPC command to import BDAP account private keys +* Merge branch 'master' into fix-dht6 +* Merge pull request #31 from duality-solutions/fix-dht6 +* [BDAP] Fix build errors after merge conflicts +* Merge pull request #32 from duality-solutions/hd-seed +* [BDAP] Add RPC command to get local wallet accounts +* Merge branch 'master' into myaccounts +* Merge pull request #33 from duality-solutions/myaccounts +* Update testnet spork address +* Update print in ThreadSocketHandler +* Fixes +* Merge pull request #34 from duality-solutions/spencer +* Fix Strings +* Change uint256S to Int +* Merge pull request #35 from duality-solutions/spencer +* Merge pull request #36 from duality-solutions/chainwork +* Merge pull request #37 from duality-solutions/newtestnet +* [DHT] Revert CPubKey class and add AddCryptedDHTKey +* [DHT] Fix segfault when shutdown before libtorrent session init +* Add mnemonic import +* Improve menu title +* Update fluiddynode.cpp +* Add second spork address to testnet +* [DHT] Fixes to wallet encryption for Ed25519 keys +* [DHT] Fix libtorrent event map for bootstrap event +* [DHT] Cleanup storage debug.log usage +* [DHT] Fix last wallet encryption issue for ed25519 keys +* Merge pull request #39 from duality-solutions/dht-keys +* [DHT] Fix segfault when saving BDAP hash table key +* Merge pull request #258 from duality-solutions/v2.4-WIP +* Resolve merge conflicts and fix mnemonic build error +* Merge pull request #41 from duality-solutions/skfix +* [BDAP] Move entries leveldb database into blocks directory +* Merge pull request #40 from duality-solutions/dht-keys2 +* Fix non-standard and null data sign step and combine signatures +* [Fluid] Add boost thread include to fluid db code files +* Fix override warnings in keystore and crypter +* [BDAP] Update certificate class, refactor and add category +* [BDAP] Update link classes +* [BDAP] Stub linking db and RPC commands +* [BDAP] Refactor common utility functions to seperate file +* [BDAP] Add invite message to link request class +* [BDAP] Add generic script parsing for linking and domain entries +* Remove second spork address for testnet +* Add privatenet to chain parameters +* Merge pull request #46 from duality-solutions/privatenet +* Add privatenet seed nodes +* [BDAP] Rearrange operation codes +* [BDAP] Use op1 and op2 to get operation type +* [BDAP] Fix update entry issue +* [BDAP] Put users and groups in @public.bdap.io by default +* Merge pull request #49 from duality-solutions/bdap-opcodes +* Merge branch 'master' into bdap-updates +* [BDAP] Fix issues caused by previous merge conflicts +* Merge pull request #48 from duality-solutions/bdap-updates +* Updated LibTorrent submodule, synced with root repo +* [BDAP] Updates to link requests +* [BDAP] Check if link request pubkey already exists in the mempool +* [BDAP] Add shared pubkey to link requests +* Merge pull request #51 from duality-solutions/linking +* Merge pull request #50 from duality-solutions/fix-warnings +* Merge public v2.4-WIP with private repo +* Resolve merge conflicts with v2.4-WIP public repo +* Sync public repo v2.4-WIP changes +* Fix warnings for struct/class mismatch and missing overrides +* Merge pull request #52 from duality-solutions/merge-public4 +* [BDAP] Fix link request from and to me functions +* Update ReadMe +* Update README.md +* Update README.md +* Merge pull request #54 from duality-solutions/ReadMeUpdate +* Merge pull request #55 from duality-solutions/merge-public4 +* [BDAP] Fixes to linking and account db functions +* Move endif to correct place +* [BDAP] Rename entry channel to sidechain +* [BDAP] Add link accept RPC command +* [BDAP] Fixes to link consensus checks +* [DHT] Fill Ed25519 private keys with zeros in destructor +* [BDAP] Fixes to Leveldb link request and accept databases +* [BDAP] More fixes for link request and accept consensus +* [BDAP] Fix transaction display in Qt UI for account entries and links +* [Fluid] Add initial sovereign addresses for privatenet +* [BDAP] Use Instant Send when possible for BDAP txs +* [BDAP] Fix mybdapaccounts after adding links +* [BDAP] Add expire time and pubkey to user and group operation transaction +* [BDAP] Implement link pending RPC commands +* Sync with public v2.4-WIP branch 2019-01-10 +* Merge pull request #57 from duality-solutions/merge-public6 +* Fix Windows build issue for embedded libtorrent +* Fix Windows Qt resource file so it will build +* Update libtorrent synced with original repo on 2019-01-11 +* Merge pull request #53 from duality-solutions/linking2 +* Add MacOS framework CoreFoundation and SystemConfiguration to make +* Update locales and add fully translated NL file +* Merge branch 'master' of https://github.com/duality-solutions/Dynamic-private +* Stub BIP39 Wordlist files for zh_CN/zh_TW/fr/it/jp/ko/es +* fix final text for translations +* Remove 1 ? +* Merge pull request #58 from duality-solutions/locales +* Update documentation +* Merge pull request #59 from duality-solutions/readme +* Update Docs +* Merge pull request #60 from duality-solutions/readme +* Fix mismatched parameters to LogPrint +* Fix warning comparison between signed and unsigned integer expressions +* Merge pull request #62 from duality-solutions/dm-bugfixes +* Add BDAP to menubar and associated GUI +* [DHT] Change alert threading to avoid segfault +* [DHT] Change alert threading to avoid segfault +* [BDAP] Fix linking destination and source address for request/accept +* [BDAP] Fix registration days parameter for RPC commands +* Merge pull request #64 from duality-solutions/updates +* BDAP Whitepaper v0.1 +* Update BDAP.md +* Update BDAP.md +* Add DHT RPC Calls and link to code location. +* Codify OP_RETURN +* Update wording +* Improve formatting +* update dht link +* link dynamic and sequence +* Link BDAP references to website +* Improve Layout +* Add a para to intro +* Add to technical information. +* Link LDAP +* Improve wording +* Improve wording +* Improve layout +* Remove DYN and link Dynamic +* Merge pull request #66 from duality-solutions/RPCWording +* Update BDAP.md +* Add BDAP AddUser modal, button event handlers and css +* Update BDAP.md +* Stub BDK section +* [BDAP] Implement version 0 (public) linking without encryption +* [DHT] Fix keymeta wallet issue when loading +* [BDAP] Add signature proof verification for link requests +* Update class info +* Fix formatting +* Stub further sections and tidy RPC sections +* Outline stubs +* Amend RPC section formatting to match +* Remove ` +* Update libtorrent, allow larger mutable DHT entries (from 1000 to 5120 bytes) +* Update Spanish Translation +* Merge pull request #68 from duality-solutions/locales +* Update dynamic_es.ts +* Merge pull request #67 from duality-solutions/linking4 +* [BDAP GUI] Implement List All Users in TableWidget +* [BDAP] Add ability to filter by users, groups or all in ListDirectories +* [BDAP] Prevent creating duplicate links +* [BDAP] Add completed link RPC command +* [BDAP] Improve link request and accept database structure +* [BDAP] Filter pending link RPC commands +* [BDAP] Add delete link request and accept RPC command +* [BDAP] Remove OP_RETURN data from delete domain account RPC +* [BDAP GUI] Implement List All Groups in TableWidget. WIP +* [BDAP GUI] Make BDAP Users table resize dynamically. WIP +* [BDAP] Add create raw account transaction RPC command +* [BDAP GUI] Make BDAP Groups table resize dynamically. Bugfixes. WIP +* [BDAP GUI] Handle get user details. WIP +* [BDAP GUI] Change ListDirectories output from condensed to full in order to populate expiration date +* [BDAP GUI] Rearrange GUI. WIP +* [BDAP GUI] Change refresh method, add My Users/Groups checkbox. WIP +* Update importmnemonic RPC command example +* [BDAP GUI] Tweak GUI, wire up My Groups checkbox. WIP +* [BDAP] Add optional accountType parameter to RPC mybdapaccounts +* [BDAP] Check if account exists in createrawbdapaccount RPC +* [BDAP] Add RPC command to pay, sign and send a raw hex account +* [BDAP] Fix mybdapaccounts help +* [BDAP] Fix help for account RPC commands +* Merge pull request #70 from duality-solutions/rpc-bdap +* [BDAP] Fix DHT RPC comand help output +* [BDAP] Add parameter names to all bdap RPC commands +* [BDAP] Fix delete link consensus and wallet checks +* Merge pull request #69 from duality-solutions/linking5 +* [BDAP GUI] Wire up search functionality. Save sort states. +* [BDAP] Fix issue when trying to delete link multiple times +* [BDAP GUI] Add BDAP Account Detail dialog box functionality +* Less chatty debug.log file when not in debug mode +* Add syncstatus RPC command for better info on chain status +* Merge pull request #71 from duality-solutions/sync-status +* Fix debug logging due to an extra category passed +* Tweak syncstatus progress calculation +* [BDAP GUI] Add User Dialog functionality. WIP +* Merge branch 'master' into qt-mockups +* [BDAP GUI] Tweak Add User Error Message reporting. WIP +* [BDAP GUI] Display user details upon successful add user transaction +* [BDAP GUI] Make My Users/Groups default view. Add record count display. +* [BDAP GUI] Add add group functionality. Enable wordWrap for longer error messages. +* [BDAP] Reduce linking logging when not in debug mode +* [BDAP GUI] Add delete user/group functionality +* [BDAP GUI] Add update BDAP user/group functionality +* [BDAP] Add VGP encryption library to build +* [BDAP] Add VGP encryption to link request +* [BDAP] Update VGP submodule to most recent master branch +* [BDAP] Add function to convert hex ed25519 pubkeys to bytes +* [BDAP] Add, remove, get version number for encrypted data +* [BDAP] Fix missing operation code translation +* [BDAP] Decrypt v1 link data before adding to local wallet +* [BDAP] Increase maximum link data size to 1592 +* [BDAP] Add more debug log print for links +* Merge pull request #74 from duality-solutions/VGP +* [BDAP GUI] Add user-friendly behavior, more error handling and cleanup +* [BDAP GUI] Implement changes requested by PR reviewers +* Merge pull request #73 from duality-solutions/qt-mockups +* [BDAP] Update VGP library's gitignore +* [VGP] Fix unit test and qt test make files +* [BDAP QT] Remove net include from tablemodel class +* Update German Translation +* Stub BDAP UI translations to NL ts file +* Pass placeholdertext through QObject::tr +* [BDAP] Fix issue with deleting an account +* [BDAP] Fix decrypting link request and accept data +* [BDAP] Add missing license headers to code files +* [Fluid] Fix get miner reward after first change +* [Fluid] Move operations code to fluid directory +* Bump client version to 2.4.6 +* Merge pull request #76 from duality-solutions/BDAP-Translate +* Fixes for PS and UTXO sorting +* Cleanup fee section +* Increase Signatures Required and Total +* Fix psq/psa conditions +* Amend GetCollateralAmount and GetMaxCollateralAmount +* Update denom info in locale +* c++14 for travis +* Increade skip DNS Thread +* Use IN6ADDR_ANY_INIT instead of in6addr_any +* Update select coin methods +* Call InitializeCurrentBlockTip after importing has finished +* Fix crash bug with duplicate inputs within a transaction +* Add instantlock field to getrawtransaction rpc output +* Use VersionBitsState instead of VersionBitsTipState to avoid cs_main lock +* Remove unused instantsenddepth from init +* Do not hold cs_main while emitting messages in WalletModel::prepareTransaction +* Base psq/pstx thresholold on the total number of up to date dynodes +* Workaround for MacOS Mojave Dark Mode +* Rename SnTimer to DnTimer +* BIP147 +* Fix gettxoutsetinfo RPC command +* Update README.md +* Fix frameFeeSelection CSS +* Fix Mining Page Colour +* Remove auto entry of ports to config file +* Remove unused CheckWork function +* Fix ZMQAbstractNotifier +* Update Icons and Splashscreen +* Update TestNet checkpoint and minchainwork +* Light Purple for LockedbyInstantSend +* Update TestNet seed IP's +* Update Alert/Spork for TestNet +* Update mainnet minchainwork +* Add a column for IS lock status on Transactions tab +* fixes for shutdown sequence +* Automatic InstantSend locks for simple transactions and some fixes +* [ZMQ] Notify when an IS double spend is attempted +* Remove dummy confirmations in RPC API and GUI for InstantSend transactions +* Update showSNConfEditor -> showDNConfEditor +* Change default build to disable GPU miner +* Do not ignore patches in depends +* Force fvisibility=hidden when compiling on macos +* PrivateSend spending txes should have "outgoing" icon on overview screen +* Relay txes through DN network faster than through regular nodes +* Update XTHIN code +* Reduce Memory Imprint on DB +* Add protected distructor for CValidationInterface +* Amend DEFAULT_TRANSACTION_MAXFEE +* Fix ' warning: delete called on non-final 'PeerLogicValidation' that has virtual functions but non-virtual destructor' +* Add WakeMessageHandler call to UpdateBlockTip +* Cleanup from changing "boost::lexical_cast" with atoi +* clang-format +* Update info for testnet spork key +* add missing file to makefile +* Remove bdap from DIST_SUBDIRS in make file +* Do not check for CUDA as default at configure time +* Repair Send in ThreadSocketHandler +* Repair nActiveStatePrev +* Repair 'GUI: QColor::setRgb: RGB parameters out of range' warning +* Fix segfault with nRefCount in net +* Amend Check in dynode.cpp +* minor things i missed +* update sync.cpp/h +* amend some versioning +* Use unique_ptr for db copy +* Use unique_ptr for wallet db env +* Remove dummy constructor +* Allow users to mix up to 16 rounds +* Only allow 2.4 nodes to mix with 2.4 nodes or newer +* remove unused variable from serialization +* A couple of small fixes for mixing collaterals +* Add an option to disable popups for PS mixing txes +* Identify PS collateral payments in transaction list a bit more accurate +* Add more variance to coin selection in PS mixing +* Revert Require all participants to submit equal number of inputs +* Split PS into Manager and Session and allow running multiple mixing sessions in parallel +* Document Sporks +* M-of-N-like sporks +* Update ImportPrivKey command +* adds rpc calls for and 'setprivatesendamount' +* Add versioning to spork cache +* extract sporkmanager from sporkmessage +* Save/load spork cache +* Update HD Feature Base and update build-debian.md +* Sweep and Update RPC files +* Tidy chainparams and update block.cpp/h +* [GPU] Fix debug block info +* Update rpcwallet.cpp calls and add missing AbandonTransaction bits +* Update miner code back with new pointers etc. +* [GPU] Disable GPU info on configure failure +* Fix Spork Address for TestNet +* Improve fee warning colour +* Update Qt and fix usage of dustRelayFee +* Fix segfault when sending a Qt transaction +* Increase fileout version in WriteFeeEstimates +* Amend Fee Structure +* Protect CSporkManager with critical section +* Fix wallet lock check in DoAutomaticDenominating +* Move block template specific stuff from CBlock to CBlockTemplate +* Fix activeDynode task scheduler +* Show some info about the wallet dumped via dumpwallet and show warning +* Make sure pwalletMain is not null whenever it's used in PS client +* Update rpcdynode and add helpers +* Switch RequestGovernanceObjectVotes from pointers to hashes +* remove/update dns seeders +* [GPU] Update obsolete macro AC_HELP_STRING +* [GPU] Prevent crash when changing the slidebar too fast +* [GPU] Optimise GPU Miner +* Fix copy elision warning in opencl device.cpp +* Supress OSX private field warnings +* Fix comparator and supress warning +* Supress MacOS build warnings for deprecated code +* [Qt] Fix styling of PrivateSend option on sendcoinsdialog.ui +* Increase Min Peer Protocol Version to 70900(v2.3) for Peers/DynodePayments/InstantSend/PrivateSend +* [GPU] Fix GPU found block nonce before ProcessFoundSolution +* [GPU] Update README for GPU Mining +* [GPU] Seperate CPU and GPU miners to fix hashmeters +* [GPU] Fix Qt mining page layout so it expands +* [GPU] Fixes to miner UI controls +* [GPU] Hide slider until sync completes/change batch size +* [GPU] Split CPU/GPU UI thread allocation +* [GPU] fix global and order members as they appear in initializer +* [GPU] fix processingUnit batch size and minor code tweaks +* [GPU] fix autoreplace +* [GPU] move implementations out of definitions +* [GPU] fix const char* instead of std::string +* [GPU] fix unique_ptr null check +* [GPU] remove redundant comments and whitespace +* [GPU] fix thread names +* [GPU] remove redundant comments and whitespace +* [GPU] follow pattern and add this-> +* [GPU] remove redundant DynamicMiner function +* [GPU] explicit boost::none for boost::bind +* [GPU] fix boost::optional no value_or method error +* [GPU] reorder constructor initialization +* [GPU] move constructor code to base +* [GPU] move hashTarget to protected variables +* [GPU] fix non-pointer operand +* [GPU] move protected variables +* [GPU] fix CPUMiner constructor +* [GPU] track chain tip +* [GPU] remove name collison +* [GPU] add device index to base class +* [GPU] provide pblock to LoopChecks +* [GPU] remove unused template from BaseMiner +* [GPU] remove static from StartLoop +* [GPU] c++11 compatibility +* [GPU] cleanup thread constructor +* [GPU] remove unused assignment +* [GPU] nullptr comparisons +* [GPU] use boost::shared_ptr as expected +* [GPU] move transactionsUdatedLast to base class +* [GPU] enable_gpu ifdef +* [GPU] fix miner start loop call +* [GPU] rename namespace to miners +* [GPU] move threads to namespace +* [GPU] fix ptr ptr semantics +* [GPU] fix count hashes function params +* [GPU] mark function as override +* [GPU] bring back enable_gpu ifdef +* [GPU] rename processing unit +* [GPU] remove static from thread_group +* [GPU] fix optional dereference +* [GPU] rename check function and fix breaks +* [GPU] use shared_ptr to manage thread_group ptr +* [GPU] Refactor miners code +* [GPU] Process hashes in batches +* [GPU] Remove obvious type hint +* [GPU] Device get total memory method +* [GPU] OpenCL kernel static build rule +* [GPU] Remove unsigned and signed int comparison +* [GPU] Mac build fix attempt +* [GPU] Disable CUDA in Travis +* [GPU] Fix autoconf warnings +* [GPU] Apple OpenCL linker flags +* [GPU] Implement GPU Mining for both Daemon/Qt +* [GPU] Split CUDA and OpenCL libraries +* [GPU] Add CUDA/OpenCL Libraries for GPU Mining +* Remove unused serialization method +* Fix consts in txmempool +* [depends] upgrade boost to 1.67.0 +* [depends] upgrade dbus to 1.13.4 +* [depends] update expad download path +* [depends] upgrade freetype to 2.9.1 +* [depends] update libevent download path +* [depends] upgrade libxcb to 1.13 +* [depends] upgrade miniupnpc to 2.1 +* [depends] upgrade native_biplist to 1.0.3 +* [depends] upgrade native_ccache to 3.4.2 +* [depends] update native_ds_store download path +* [depends] upgrade native_mac_alias to 2.0.7 +* [depends] upgrade native_protobuf to 3.6.0 +* [depends] update openssl to 1.0.1k - Add RISC-V support +* [depends] upgrade qt to 5.9.6 +* [depends] upgrade qrencode +* [depends] upgrade xcb_proto to 1.13 +* [depends] upgrade xtrans to 1.3.5 +* [depends] upgrade zeromq to 4.2.5 +* [depends] add fix_configure_mac.patch file +* [depends] add fix_no_printer.patch file +* [depends] update mac-qmake.conf patch file +* [BDAP] Add directory type function +* [BDAP] Implement add new entry validation checking +* [BDAP] Fix validation when syncing blocks from peers +* [BDAP] Implement directory entry list RPC command +* [BDAP] Add getdirectoryinfo RPC command +* [BDAP] Add leveldb update method to db wrapper class +* [BDAP] Fix validate input function; leveldb check not DOS +* [BDAP] Update getdirectoryinfo help parameter +* [BDAP] Implement update & delete entry tx validation checking +* [BDAP] Fix saving tx hash in leveldb bdap database +* [BDAP] Replace updatedirectory RPC command +* [BDAP] Fix getdirectoryinfo return when entry not found +* [BDAP] Fix expire time in RPC commands +* [BDAP] Refactor directory to domainentry +* [BDAP] Add domain entry link class for binding operations +* [BDAP] Refactor domain entry certificate and move to its own class +* [BDAP] Refactor domain entry checkpoints and move to its own class +* [BDAP] Refactor domain entry channel data and move to its own class +* [BDAP] Check if tx exists in memory pool for new domain entries +* [BDAP] Update RPC command names +* [BDAP] Check domain entry wallet address and encrypt pub key +* [BDAP] Remove SignWalletAddress in domain entry. Only use WalletAddress +* [BDAP] Check ownership in updatedomainentry RPC command +* [BDAP] Fix domain entry so it populates block height +* [BDAP] Add code to check domain entry's previous UTXO +* Remove duplicate mem pool check in wallet available coins +* [BDAP] Add link address to domain entry class +* [BDAP] Check previous wallet address for update and delete txs +* [BDAP] Add delete domain entry RPC command +* [BDAP] Allow blank link address and encrypt pub key for delete operations +* [Fluid] Fix segfault when running reindex +* Move makekeypair to BDAP and change testnet spork pub key +* [BDAP] Add identity and identity verification classes +* [BDAP] Add missing operation codes +* [BDAP] Adjust identity verification class +* [BDAP] Fix domain entry object type enum +* [BDAP] Add entry audit data class +* [BDAP] Add new public group entry RPC command +* [BDAP] Add list domain group entries RPC command +* [BDAP] Add update and delete public group RPC commands +* Corrected the documentation for Fluid RPC Calls +* [BDAP] Refactor general functions and fix get op type +* [BDAP] Improve transaction display in Qt UI +* Added more seednodes +* Remove double forcecompactdb arg +* [Fluid] Refactor fluid code and remove index database +* [BDAP] Remove fluid reference from domain entry +* [Fluid] Add mining update and mint leveldb databases +* [Fluid] Implement new fluid databases +* [Fluid] Fix get fluid sovereigns RPC +* [Fluid] Fixes to get last functions and RPC commands +* [Fluid] Fix consensus issues with new db code +* Drop delayed headers logic and fix duplicate initial headers sync +* replace boost iterators with for +* RPC: Add description for InstantSend-related fields of mempool entry +* RPC: fix wallet lock check in +* minor reformatting +* Remove explicit wallet lock in DynodeList::StartAll() +* Do not create dnb until dynodeSync is finished +* Don't drop dnb's for outdated DN's +* Fix previous commit and fix 2 Spork issues +* PrepareDenominate fix +* Sync DN list and DNW list from 3 peers max +* Use correct protocol when serializing messages in reply to +* Bump Versioning +* Update dynamic_qt.m4 (Remove ability to build with Qt4) + + **Dynamic v2.3.5.0** * Fix crash bug with duplicate inputs within a transaction @@ -14,6 +609,7 @@ * [Fluid] Fix consensus issues with new db code * Update changelog and cleanup fluid to do lists/comments + **Dynamic v2.3.0.0** * Skip existing Dynodes connections on mixing @@ -191,6 +787,7 @@ * Inline Argon2d code with commit fba7b9a * Update CHANGELOG + **Dynamic v2.2.0.0** * Add dynamic address label to request payment QR code @@ -214,6 +811,7 @@ * Fix fixed seeds * Update CHANGELOG + **Dynamic v2.1.0.0** * [Trivial] Shift non-Fluid specific operations to separate file @@ -299,6 +897,7 @@ * Improve handling of unconnecting headers * Update CHANGELOG + **Dynamic v2.0.0.0** * Fix Network Time Protocol (NTP) @@ -570,6 +1169,7 @@ * Optimize CheckOutpoint * Update CHANGELOG + **Dynamic v1.4.0.0** * Securely erase potentially sensitive keys/values @@ -632,6 +1232,7 @@ * Bump Governance/InstantSend/PrivateSend/Core Proto/Versions * Update CHANGELOG + **Dynamic v1.3.0.2** * [Sync] Fix issue with headers first sync @@ -644,11 +1245,13 @@ * Bump Governance/Core Proto/Versions * Update CHANGELOG + **Dynamic v1.3.0.1** * Bump Protocols to lock out nodes at or below v1.2 to prevent any forks * Update CHANGELOG + **Dynamic v1.3.0.0** * c++11:Backport from bitcoin-core: don't throw from the reverselock destructor @@ -656,6 +1259,7 @@ * Hard Fork at block 300,000 for Delta difficulty retarget algorithm * Update CHANGELOG + **Dynamic v1.2.0.0** * Make RelayWalletTransaction attempt to AcceptToMemoryPool @@ -699,6 +1303,7 @@ * Added IPv4 seed nodes to chainparamsseeds.h * Update CHANGELOG + **Dynamic v1.1.0.0** * Inline with BTC 0.12 diff --git a/COPYING b/COPYING index 797d30df37..21f4f6faf5 100644 --- a/COPYING +++ b/COPYING @@ -1,7 +1,7 @@ -// Copyright (c) 2009-2018 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 160a7c2842..77bdfa408c 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,12 @@ [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) [![Build Status](https://travis-ci.org/duality-solutions/Dynamic.png?branch=master)](https://travis-ci.org/duality-solutions/Dynamic) -[![Stories in Ready](https://badge.waffle.io/duality-solutions/Dynamic.png?label=ready&title=Ready)](https://waffle.io/duality-solutions/Dynamic) -Graph on Pull Request History -==================================== - -[![Throughput Graph](https://graphs.waffle.io/duality-solutions/Dynamic/throughput.svg)](https://waffle.io/duality-solutions/Dynamic/metrics/throughput) - -# **Dynamic (DYN) v2.3.5.0** +# **Dynamic (DYN) v2.5.0.0** ![DYN logo](https://github.com/duality-solutions/Dynamic/blob/master/src/qt/res/icons/drk/about.png) -**Copyright (c) 2016-2018 [Duality Blockchain Solutions](https://duality.solutions/)** +**Copyright (c) 2016-2021 [Duality Blockchain Solutions](https://duality.solutions/)** What is [Dynamic](https://duality.solutions/dynamic)? ---------------- @@ -23,24 +17,25 @@ What is [Dynamic](https://duality.solutions/dynamic)? * PoW Target Spacing: 128 Seconds * PoW Reward per Block: Controlled via Fluid Protocol * PoW Reward Start Height: Block 5,137 +* PoS Mining Algorithm: Blake2b +* PoS Period: Unlimited +* PoS Target Spacing: 128 Seconds +* PoS Reward per Block: Controlled via Fluid Protocol +* PoS Reward Start Height: Controlled via SPORK activation * Maturity: 10 Blocks * PoW Blocks: ~675 per day +* PoS Blocks: ~675 per day +* Total Blocks Per Day: ~1350 * Dynode Collateral Amount: 1000 DYN * Dynode Min Confirmation: 17 Blocks * Dynode Reward: Controlled via Fluid Protocol * Dynode Reward Start Height: Block 10,273 * Total Coins: 263 - 1 * Min TX Fee: 0.0001 DYN +* Max Block Size: 4MB -[Dynamic(DYN)](https://duality.solutions/dynamic) is [Duality](https://duality.solutions/)’s tokenized-currency provided with supply elasticity to ensure price stability for day to day transactions of end-users. [Duality](https://duality.solutions/) uses company proceeds to place buy back orders on the [Dynamic(DYN)](https://duality.solutions/dynamic) market to keep inflation within acceptable bounds. - -[Dynamic(DYN)](https://duality.solutions/dynamic) lays the groundwork for offering BaaS(Blockchain as a Service) by hosting a multitude of second tier nodes called Dynodes. Rewards can be adjusted through the 'Fluid Protocol' created by [Duality](https://duality.solutions/) to adjust to a maturing market. - -As a modern currency [Dynamic(DYN)](https://github.com/duality-solutions/dynamic) will be actively maintained to keep up with the latest market trends. [Dynamic(DYN)](https://github.com/duality-solutions/dynamic) features fast and InstantSend transactions at an affordable rate, also end-users that care for consumer privacy are able to anonymously transact using PrivateSend. - -[Dynamic(DYN)](https://github.com/duality-solutions/dynamic) utilises Dynodes which are the 2nd tier of security, processing InstantSend transactions and providing fungibility via PrivateSend. - +[Dynamic(DYN)](https://duality.solutions/dynamic) allows fast, secure, verifiable transfers of data using blockchain technology and enables third-party developers to build low-cost solutions across varied industry using the BDAP protocol. Dynamic utlises Proof-of-Work, and can be used to run incentivized Dynodes; the second tier of nodes on the network used for BDAP, the DHT, and processing, verifying, validating and storing data. **MainNet Parameters** P2P Port = 33300 @@ -114,27 +109,27 @@ For the versions used in the release, see [release-process.md](release-process.m System requirements -------------------- -C++ compilers are memory-hungry. It is recommended to have at least 3 GB of -memory available when compiling Dynamic. +C++ compilers are memory-hungry. It is recommended to have at least 3 GB of memory available when compiling Dynamic. Dependency Build Instructions: Ubuntu & Debian ---------------------------------------------- + +It is required to build Dynamic on Ubuntu 20.04LTS(Focal) or later due to C++14/GCC7 requirements. Also OpenSSL 1.1.1f is included in Ubuntu 20.04LTS and later. It is required to use OpenSSL 1.1.1LTS. + Build requirements: sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libcrypto++-dev libevent-dev git automake -for Ubuntu 12.04 and later or Debian 7 and later libboost-all-dev has to be installed: +For Ubuntu 20.04LTS(Bionic) and later, or Debian 7 and later; libboost-all-dev has to be installed: sudo apt-get install libboost-all-dev - db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). - You can add the repository using the following command: +db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). You can add the repository using the following command: - sudo add-apt-repository ppa:bitcoin/bitcoin - sudo apt-get update + sudo add-apt-repository ppa:pivx/pivx + sudo apt-get update - Ubuntu 12.04 and later have packages for libdb5.1-dev and libdb5.1++-dev, - but using these will break binary wallet compatibility, and is not recommended. +Ubuntu 20.04 and later have packages for libdb 5.3.21 but using these will break binary wallet compatibility, and is not recommended. for Debian 7 (Wheezy) and later: The oldstable repository contains db4.8 packages. @@ -162,10 +157,7 @@ ZMQ dependencies (provides ZMQ API 4.x): Dependencies for the GUI: Ubuntu & Debian ----------------------------------------- -If you want to build Dynamic-Qt, make sure that the required packages for Qt development -are installed. Qt 5 is necessary to build the GUI. -If both Qt 4 and Qt 5 are installed, Qt 5 will be used. Pass `--with-gui=qt5` to configure to choose Qt5. -To build without GUI pass `--without-gui`. +If you want to build Dynamic-Qt, make sure that the required packages for Qt development are installed. Qt 5 is necessary to build the GUI. If both Qt 4 and Qt 5 are installed, Qt 5 will be used. Pass `--with-gui=qt5` to configure to choose Qt5. To build without GUI pass `--without-gui`. For Qt 5 you need the following: @@ -186,6 +178,8 @@ symbols, which reduces the executable size by about 90%. miniupnpc --------- +The dependencies for miniupnpc are included above within the 'Dependency Build Instructions: Ubuntu & Debian' section, however, for any reason you wish to build the source, please follow these instructions. + [miniupnpc](http://miniupnp.free.fr/) may be used for UPnP port mapping. It can be downloaded from [here]( http://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and turned off by default. See the configure options for upnp behavior desired: @@ -204,38 +198,41 @@ To build: Berkeley DB ----------- -It is recommended to use Berkeley DB 4.8. If you have to build it yourself: - -```bash -DYNAMIC_ROOT=$(pwd) - -# Pick some path to install BDB to, here we create a directory within the dynamic directory -BDB_PREFIX="${DYNAMIC_ROOT}/db4" -mkdir -p $BDB_PREFIX - -# Fetch the source and verify that it is not tampered with -wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' -echo '12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz' | sha256sum -c -# -> db-4.8.30.NC.tar.gz: OK -tar -xzvf db-4.8.30.NC.tar.gz - -# Build the library and install to our prefix -cd db-4.8.30.NC/build_unix/ -# Note: Do a static build so that it can be embedded into the exectuable, instead of having to find a .so at runtime -../dist/configure --prefix=/usr/local --enable-cxx -make -sudo make install - -# Configure Dynamic to use our own-built instance of BDB -cd $DYNAMIC_ROOT -./configure (other args...) LDFLAGS="-L${BDB_PREFIX}/lib/" CPPFLAGS="-I${BDB_PREFIX}/include/" +It is recommended to use Berkeley DB 4.8 and is included in the dependencies above in the 'Dependency Build Instructions: Ubuntu & Debian' section. + +If you have to, or wish to build Berkeley DB 4.8 yourself: + +``` + bash + DYNAMIC_ROOT=$(pwd) + + # Pick some path to install BDB to, here we create a directory within the dynamic directory + BDB_PREFIX="${DYNAMIC_ROOT}/db4" + mkdir -p $BDB_PREFIX + + # Fetch the source and verify that it is not tampered with + wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' + echo '12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz' | sha256sum -c + # -> db-4.8.30.NC.tar.gz: OK + tar -xzvf db-4.8.30.NC.tar.gz + + # Build the library and install to our prefix + cd db-4.8.30.NC/build_unix/ + # Note: Do a static build so that it can be embedded into the exectuable, instead of having to find a .so at runtime + ../dist/configure --prefix=/usr/local --enable-cxx + make + sudo make install + + # Configure Dynamic to use our own-built instance of BDB + cd $DYNAMIC_ROOT + ./configure (other args...) LDFLAGS="-L${BDB_PREFIX}/lib/" CPPFLAGS="-I${BDB_PREFIX}/include/" ``` **Note**: You only need Berkeley DB if the wallet is enabled (see the section *Disable-Wallet mode* below). Boost ----- -If you need to build Boost yourself: +If you need to build Boost yourself, in terminal enter: sudo su ./bootstrap.sh @@ -244,8 +241,8 @@ If you need to build Boost yourself: Security -------- -To help make your Dynamic installation more secure by making certain attacks impossible to -exploit even if a vulnerability is found, binaries are hardened by default. +To help make your Dynamic installation more secure by making certain attacks impossible to exploit even if a vulnerability is found, binaries are hardened by default. + This can be disabled with: Hardening Flags: @@ -268,10 +265,12 @@ Hardening enables the following features: To test that you have built PIE executable, install scanelf, part of paxutils, and use: - scanelf -e ./dynamicd + scanelf -e ./dynamicd + The output should contain: - TYPE + + TYPE ET_DYN * Non-executable Stack @@ -319,8 +318,8 @@ CPU's with AVX2 support: Broadwell E processor, Q3 2016 Skylake processor, Q3 2015 Kaby Lake processor, Q3 2016(ULV mobile)/Q1 2017(desktop/mobile) - Coffee Lake processor, expected in 2017 - Cannonlake processor, expected in 2018 + Coffee Lake processor, Q4 2017 + AMD Carrizo processor, Q2 2015 Ryzen processor, Q1 2017 @@ -340,15 +339,61 @@ CPU's with AVX512 support: Knights Mill processor, 2017 Skylake-SP processor, 2017 Skylake-X processor, 2017 - Cannonlake processor, expected in 2018 - Ice Lake processor, expected in 2018 + Cannonlake processor, expected in 2019 + Ice Lake processor, expected in 2019 + + +GPU Mining +---------- +To enable GPU mining within the wallet, OpenCL or CUDA can be utilised. Please use GCC/G++ 6.4 or newer and for CUDA to be utilised please use CUDA 9.1 or newer and ensure you have graphics drivers installed. + +For OpenCL you need the following: + + sudo apt-get install ocl-icd-opencl-dev + +For CUDA please visit: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html + +At configure time for OpenCL(Nvidia/AMD): + + --enable-gpu + +At configure time for CUDA(Nvidia): + + --enable-gpu --enable-cuda + +or run the daemon with: + + ./src/dynamicd -staking=1 + +or Qt wallet with: + + ./src/qt/dynamic-qt -staking=1 + Example Build Command -------------------- -Qt Wallet and Deamon, CLI version build: +Qt Wallet and Deamon, CLI version build without GPU support and without AVX support: + + ./autogen.sh && ./configure --with-gui --disable-gpu && make + +CLI and Deamon Only build without GPU support and without AVX support: + + ./autogen.sh && ./configure --without-gui --disable-gpu && make + +Use Qt Creator as IDE +------------------------ +You can use Qt Creator as IDE, for debugging and for manipulating forms, etc. +Download Qt Creator from http://www.qt.io/download/. Download the "community edition" and only install Qt Creator (uncheck the rest during the installation process). - ./autogen.sh && ./configure --with-gui && make +1. Make sure you installed everything through homebrew mentioned above +2. Do a proper ./configure --with-gui=qt5 --enable-debug +3. In Qt Creator do "New Project" -> Import Project -> Import Existing Project +4. Enter "dynamic-qt" as project name, enter src/qt as location +5. Leave the file selection as it is +6. Confirm the "summary page" +7. In the "Projects" tab select "Manage Kits..." +8. Select the default "Desktop" kit and select "Clang (x86 64bit in /usr/bin)" as compiler +9. Select LLDB as debugger (you might need to set the path to your installtion) +10. Start debugging with Qt Creator -CLI and Deamon Only Buld: - ./autogen.sh && ./configure --without-gui && make diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000000..8c5fcffcb5 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,151 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +VM_NAME = "dynamic-v2.4" +DYNAMIC_PATH = "/opt/dynamic" + +# ugly hack to prevent hashicorp's bitrot. See https://github.com/hashicorp/vagrant/issues/9442 +# this setting is required for pre-2.0 vagrant, but causes an error as of 2.0.3, +# remove entirely when confident nobody uses vagrant 1.x for anything. +unless Vagrant::DEFAULT_SERVER_URL.frozen? + Vagrant::DEFAULT_SERVER_URL.replace('https://vagrantcloud.com') +end + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure("2") do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + # Every Vagrant development environment requires a box. You can search for + # boxes at https://vagrantcloud.com/search. + # Base on the Sandstorm snapshots of the official Debian 9 (stretch) box with vboxsf support. + config.vm.box = "ubuntu/bionic64" + + # vagrant plugin install vagrant-disksize + if Vagrant.has_plugin?("vagrant-disksize") then + config.disksize.size = "50GB" + end + + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + if Vagrant.has_plugin?("vagrant-vbguest") then + # vagrant-vbguest is a Vagrant plugin that upgrades + # the version of VirtualBox Guest Additions within each + # guest. If you have the vagrant-vbguest plugin, then it + # needs to know how to compile kernel modules, etc., and so + # we give it this hint about operating system type. + config.vm.guest = "ubuntu" + end + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + # NOTE: This will enable public access to the opened port + + # Main net + config.vm.network "forwarded_port", guest: 33300, host: 33300 # P2P + config.vm.network "forwarded_port", guest: 33350, host: 33350, host_ip: "127.0.0.1" # RPC + + # Test net + config.vm.network "forwarded_port", guest: 33400, host: 33400 # P2P + config.vm.network "forwarded_port", guest: 33450, host: 33450, host_ip: "127.0.0.1" # RPC + + # ReqTest net + config.vm.network "forwarded_port", guest: 33500, host: 33500 # P2P + config.vm.network "forwarded_port", guest: 33550, host: 33550, host_ip: "127.0.0.1" # RPC + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # Calculate the number of CPUs and the amount of RAM the system has, + # in a platform-dependent way; further logic below. + cpus = nil + total_kB_ram = nil + + host = RbConfig::CONFIG['host_os'] + if host =~ /darwin/ + cpus = `sysctl -n hw.ncpu`.to_i + total_kB_ram = `sysctl -n hw.memsize`.to_i / 1024 + elsif host =~ /linux/ + cpus = `nproc`.to_i + total_kB_ram = `grep MemTotal /proc/meminfo | awk '{print $2}'`.to_i + elsif host =~ /mingw/ + # powershell may not be available on Windows XP and Vista, so wrap this in a rescue block + begin + cpus = `powershell -Command "(Get-WmiObject Win32_Processor -Property NumberOfLogicalProcessors | Select-Object -Property NumberOfLogicalProcessors | Measure-Object NumberOfLogicalProcessors -Sum).Sum"`.to_i + total_kB_ram = `powershell -Command "[math]::Round((Get-WmiObject -Class Win32_ComputerSystem).TotalPhysicalMemory)"`.to_i / 1024 + rescue + end + end + + # Use the same number of CPUs within Vagrant as the system, with 1 + # as a default. + # + # Use at least 512MB of RAM, and if the system has more than 2GB of + # RAM, use 1/4 of the system RAM. This seems a reasonable compromise + # between having the Vagrant guest operating system not run out of + # RAM entirely (which it basically would if we went much lower than + # 512MB) and also allowing it to use up a healthily large amount of + # RAM so it can run faster on systems that can afford it. + if cpus.nil? or cpus.zero? + cpus = 1 + end + if total_kB_ram.nil? or total_kB_ram < 2048000 + assign_ram_mb = 512 + else + assign_ram_mb = (total_kB_ram / 1024 / 4) + end + + # Actually apply these CPU/memory values to the providers. + config.vm.provider :virtualbox do |vb, override| + vb.cpus = cpus + vb.memory = assign_ram_mb + vb.name = VM_NAME + vb.customize ["modifyvm", :id, "--nictype1", "virtio"] + + # enables symlinks for windows + override.vm.synced_folder ".", DYNAMIC_PATH + override.vm.synced_folder ".dynamic", "/home/vagrant/.dynamic" + vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/#{DYNAMIC_PATH}", "1"] + end + + config.vm.provider :libvirt do |libvirt, override| + libvirt.cpus = cpus + libvirt.memory = assign_ram_mb + libvirt.default_prefix = VM_NAME + + # /opt/dynamic/dynamic and /root/.dynamic are used by vagrant-spk + override.vm.synced_folder ".", DYNAMIC_PATH, type: "9p", accessmode: "passthrough" + override.vm.synced_folder ".dynamic", "/home/vagrant/.dynamic", type: "9p", accessmode: "passthrough" + end + + # View the documentation for the provider you are using for more + # information on available options. + + # Enable provisioning with a shell script. Additional provisioners such as + # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the + # documentation for more information about their specific syntax and use. + # config.vm.provision "shell", inline: "bash #{DYNAMIC_PATH}/dynamic-devenv/scripts/setup.sh", keep_color: true, env: {"VAGRANT" => "1"} + config.vm.provision "shell", inline: <<-SHELL + sudo add-apt-repository -y ppa:bitcoin/bitcoin + sudo apt-get update + sudo apt-get install -qy libdb4.8-dev libdb4.8++-dev build-essential libtool autotools-dev autoconf pkg-config libssl-dev libcrypto++-dev libevent-dev git libboost-all-dev libminiupnpc-dev libzmq3-dev + sudo bash -c 'echo "Dynamic in /opt/dynamic" >/etc/motd' + cd /opt/dynamic && ./autogen.sh && ./configure --without-gui --disable-gpu && make -j12 + SHELL + +end diff --git a/autogen.sh b/autogen.sh index 5e37212166..a9fd47a64f 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,4 +1,5 @@ #!/bin/sh +git submodule update --init --recursive set -e srcdir="$(dirname $0)" cd "$srcdir" diff --git a/build-aux/m4/ax_check_cuda.m4 b/build-aux/m4/ax_check_cuda.m4 new file mode 100644 index 0000000000..ce123afae0 --- /dev/null +++ b/build-aux/m4/ax_check_cuda.m4 @@ -0,0 +1,153 @@ +##### +# +# SYNOPSIS +# +# AX_CHECK_CUDA +# +# DESCRIPTION +# +# Figures out if CUDA Driver API/nvcc is available, i.e. existence of: +# nvcc +# cuda.h +# libcuda.a +# +# If something isn't found, fails straight away. +# +# The following variables are substituted in the makefile: +# NVCC : the nvcc compiler command. +# NVCCFLAGS : nvcc specific flags +# CUDA_CFLAGS : CUDA includes +# CUDA_LDLIBS : CUDA libraries +# +# Defines HAVE_CUDA in config.h +# +# LICENCE +# Public domain +# +##### + +AC_DEFUN([AX_CHECK_CUDA], [ + +# Provide your CUDA path with this +AC_ARG_WITH([cuda], + [AS_HELP_STRING([--with-cuda=PATH],[prefix where CUDA is installed @<:@default=no@:>@])], + [], + [with_cuda=yes]) + +NVCC=no +CUDA_CFLAGS= +CUDA_LDLIBS= + +if test "x$with_cuda" != "xno" +then + + # ----------------------------------------- + # Setup CUDA paths + # ----------------------------------------- + if test "x$with_cuda" != "xyes" + then + AX_NORMALIZE_PATH([with_cuda], ["/"]) + CUDAPATH="$with_cuda" + CUDA_CFLAGS+=" -I$with_cuda/include" + CUDA_LDLIBS+=" -L$with_cuda/lib64" + else + AC_CHECK_FILE(/usr/local/cuda/,[CUDAPATH="/usr/local/cuda"],[]) + AC_CHECK_FILE(/usr/local/cuda/include,[CUDA_CFLAGS+=" -I/usr/local/cuda/include"],[CUDA_CFLAGS=""]) + AC_CHECK_FILE(/usr/local/cuda/lib64,[CUDA_LDLIBS+=" -L/usr/local/cuda/lib64"],[]) + fi + CUDA_LDLIBS+=" -lcuda -lcudart -lcublas" + + + # ----------------------------------------- + # Checking for nvcc + # ----------------------------------------- + AC_PATH_PROG([NVCC],[nvcc],[no],[$PATH:$CUDAPATH/bin]) + if test "x$NVCC" = "xno" + then + AC_MSG_ERROR([Cannot find nvcc compiler. To enable CUDA, please add path to + nvcc in the PATH environment variable and/or specify the path + where CUDA is installed using: --with-cuda=PATH]) + fi + + + # ----------------------------------------- + # Setup nvcc flags + # ----------------------------------------- + AC_ARG_VAR(NVCCFLAGS,[Additional nvcc flags (example: NVCCFLAGS="-arch=compute_30 -code=sm_30")]) + if test x$DEBUG = xtrue + then + NVCCFLAGS+=" -g" + else + NVCCFLAGS+=" -O3" + fi + AC_ARG_ENABLE([emu], + AS_HELP_STRING([--enable-emu],[turn on device emulation for CUDA]), + [case "${enableval}" in + yes) EMULATION=true;; + no) EMULATION=false;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-emu]);; + esac], + [EMULATION=false]) + if test x$EMULATION = xtrue + then + NVCCFLAGS+=" -deviceemu" + fi + + + # ----------------------------------------- + # Check if nvcc works + # ----------------------------------------- + ac_compile_nvcc=no + AC_MSG_CHECKING([whether nvcc works]) + cat>conftest.cu< /dev/null + then + ac_compile_nvcc=yes + fi + rm -f conftest.cu conftest.o + AC_MSG_RESULT([$ac_compile_nvcc]) + + if test "x$ac_compile_nvcc" = "xno" + then + AC_MSG_ERROR([CUDA compiler has problems.]) + fi + + + # ----------------------------------------- + # Check for headers and libraries + # ----------------------------------------- + ax_save_CFLAGS="${CFLAGS}" + ax_save_LIBS="${LIBS}" + + CFLAGS="$CUDA_CFLAGS $CFLAGS" + LIBS="$CUDA_LDLIBS $LIBS" + + # And the header and the lib + AC_CHECK_HEADER([cuda.h], [], AC_MSG_FAILURE([Couldn't find cuda.h]), [#include ]) + AC_CHECK_HEADER([cuda_runtime_api.h], [], AC_MSG_FAILURE([Couldn't find cuda_runtime_api.h]), [#include ]) + AC_CHECK_HEADER([cublas.h], [], AC_MSG_FAILURE([Couldn't find cublas.h]), [#include ]) + AC_CHECK_LIB([cuda], [cuInit], [], AC_MSG_FAILURE([Couldn't find libcuda])) + AC_CHECK_LIB([cudart], [cudaMalloc], [], AC_MSG_FAILURE([Couldn't find libcudart])) + AC_CHECK_LIB([cublas], [cublasInit], [], AC_MSG_FAILURE([Couldn't find libcublas])) + + # Returning to the original flags + CFLAGS=${ax_save_CFLAGS} + LIBS=${ax_save_LIBS} + + AC_DEFINE(HAVE_CUDA,1,[Define if we have CUDA]) +fi + + +# Announcing the new variables +AC_SUBST([NVCC]) +AC_SUBST([NVCCFLAGS]) +AC_SUBST([CUDA_CFLAGS]) +AC_SUBST([CUDA_LDLIBS]) +]) diff --git a/build-aux/m4/ax_normalize_path.m4 b/build-aux/m4/ax_normalize_path.m4 new file mode 100644 index 0000000000..b789a9369e --- /dev/null +++ b/build-aux/m4/ax_normalize_path.m4 @@ -0,0 +1,115 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_normalize_path.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_NORMALIZE_PATH(VARNAME, [REFERENCE_STRING]) +# +# DESCRIPTION +# +# Perform some cleanups on the value of $VARNAME (interpreted as a path): +# +# - empty paths are changed to '.' +# - trailing slashes are removed +# - repeated slashes are squeezed except a leading doubled slash '//' +# (which might indicate a networked disk on some OS). +# +# REFERENCE_STRING is used to turn '/' into '\' and vice-versa: if +# REFERENCE_STRING contains some backslashes, all slashes and backslashes +# are turned into backslashes, otherwise they are all turned into slashes. +# +# This makes processing of DOS filenames quite easier, because you can +# turn a filename to the Unix notation, make your processing, and turn it +# back to original notation. +# +# filename='A:\FOO\\BAR\' +# old_filename="$filename" +# # Switch to the unix notation +# AX_NORMALIZE_PATH([filename], ["/"]) +# # now we have $filename = 'A:/FOO/BAR' and we can process it as if +# # it was a Unix path. For instance let's say that you want +# # to append '/subpath': +# filename="$filename/subpath" +# # finally switch back to the original notation +# AX_NORMALIZE_PATH([filename], ["$old_filename"]) +# # now $filename equals to 'A:\FOO\BAR\subpath' +# +# One good reason to make all path processing with the unix convention is +# that backslashes have a special meaning in many cases. For instance +# +# expr 'A:\FOO' : 'A:\Foo' +# +# will return 0 because the second argument is a regex in which +# backslashes have to be backslashed. In other words, to have the two +# strings to match you should write this instead: +# +# expr 'A:\Foo' : 'A:\\Foo' +# +# Such behavior makes DOS filenames extremely unpleasant to work with. So +# temporary turn your paths to the Unix notation, and revert them to the +# original notation after the processing. See the macro +# AX_COMPUTE_RELATIVE_PATHS for a concrete example of this. +# +# REFERENCE_STRING defaults to $VARIABLE, this means that slashes will be +# converted to backslashes if $VARIABLE already contains some backslashes +# (see $thirddir below). +# +# firstdir='/usr/local//share' +# seconddir='C:\Program Files\\' +# thirddir='C:\home/usr/' +# AX_NORMALIZE_PATH([firstdir]) +# AX_NORMALIZE_PATH([seconddir]) +# AX_NORMALIZE_PATH([thirddir]) +# # $firstdir = '/usr/local/share' +# # $seconddir = 'C:\Program Files' +# # $thirddir = 'C:\home\usr' +# +# LICENSE +# +# Copyright (c) 2008 Alexandre Duret-Lutz +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 8 + +AU_ALIAS([ADL_NORMALIZE_PATH], [AX_NORMALIZE_PATH]) +AC_DEFUN([AX_NORMALIZE_PATH], +[case ":[$]$1:" in +# change empty paths to '.' + ::) $1='.' ;; +# strip trailing slashes + :*[[\\/]]:) $1=`echo "[$]$1" | sed 's,[[\\/]]*[$],,'` ;; + :*:) ;; +esac +# squeeze repeated slashes +case ifelse($2,,"[$]$1",$2) in +# if the path contains any backslashes, turn slashes into backslashes + *\\*) $1=`echo "[$]$1" | sed 's,\(.\)[[\\/]][[\\/]]*,\1\\\\,g'` ;; +# if the path contains slashes, also turn backslashes into slashes + *) $1=`echo "[$]$1" | sed 's,\(.\)[[\\/]][[\\/]]*,\1/,g'` ;; +esac]) diff --git a/build-aux/m4/dynamic_qt.m4 b/build-aux/m4/dynamic_qt.m4 index 3f91ff2209..35e882a49e 100644 --- a/build-aux/m4/dynamic_qt.m4 +++ b/build-aux/m4/dynamic_qt.m4 @@ -1,12 +1,12 @@ -dnl Copyright (c) 2013-2016 The Dualiy Blockchain Solutions developers +dnl Copyright (c) 2013-2016 The Dynamic Core developers dnl Distributed under the MIT software license, see the accompanying dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. dnl Helper for cases where a qt dependency is not met. dnl Output: If qt version is auto, set dynamic_enable_qt to false. Else, exit. AC_DEFUN([DYNAMIC_QT_FAIL],[ - if test "x$dynamic_qt_want_version" = "xauto" && test x$dynamic_qt_force != xyes; then - if test x$dynamic_enable_qt != xno; then + if test "x$dynamic_qt_want_version" = xauto && test "x$dynamic_qt_force" != xyes; then + if test "x$dynamic_enable_qt" != xno; then AC_MSG_WARN([$1; dynamic-qt frontend will not be built]) fi dynamic_enable_qt=no @@ -17,7 +17,7 @@ AC_DEFUN([DYNAMIC_QT_FAIL],[ ]) AC_DEFUN([DYNAMIC_QT_CHECK],[ - if test "x$dynamic_enable_qt" != "xno" && test x$dynamic_qt_want_version != xno; then + if test "x$dynamic_enable_qt" != xno && test "x$dynamic_qt_want_version" != xno; then true $1 else @@ -35,12 +35,12 @@ dnl Inputs: $4: If "yes", don't fail if $2 is not found. dnl Output: $1 is set to the path of $2 if found. $2 are searched in order. AC_DEFUN([DYNAMIC_QT_PATH_PROGS],[ DYNAMIC_QT_CHECK([ - if test "x$3" != "x"; then + if test "x$3" != x; then AC_PATH_PROGS($1,$2,,$3) else AC_PATH_PROGS($1,$2) fi - if test "x$$1" = "x" && test "x$4" != "xyes"; then + if test "x$$1" = x && test "x$4" != xyes; then DYNAMIC_QT_FAIL([$1 not found]) fi ]) @@ -53,11 +53,11 @@ dnl CAUTION: Do not use this inside of a conditional. AC_DEFUN([DYNAMIC_QT_INIT],[ dnl enable qt support AC_ARG_WITH([gui], - [AS_HELP_STRING([--with-gui@<:@=no|qt4|qt5|auto@:>@], - [build dynamic-qt GUI (default=auto, qt5 tried first)])], + [AS_HELP_STRING([--with-gui@<:@=no|qt5|auto@:>@], + [build dynamic-qt GUI (default=auto)])], [ dynamic_qt_want_version=$withval - if test x$dynamic_qt_want_version = xyes; then + if test "x$dynamic_qt_want_version" = xyes; then dynamic_qt_force=yes dynamic_qt_want_version=auto fi @@ -89,23 +89,22 @@ dnl Outputs: dynamic_enable_qt, dynamic_enable_qt_dbus, dynamic_enable_qt_test AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ use_pkgconfig=$1 - if test x$use_pkgconfig = x; then + if test "x$use_pkgconfig" = x; then use_pkgconfig=yes fi - if test x$use_pkgconfig = xyes; then - DYNAMIC_QT_CHECK([_DYNAMIC_QT_FIND_LIBS_WITH_PKGCONFIG([$2])]) + if test "x$use_pkgconfig" = xyes; then + DYNAMIC_QT_CHECK([_DYNAMIC_QT_FIND_LIBS_WITH_PKGCONFIG]) else DYNAMIC_QT_CHECK([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG]) fi dnl This is ugly and complicated. Yuck. Works as follows: - dnl We can't discern whether Qt4 builds are static or not. For Qt5, we can - dnl check a header to find out. When Qt is built statically, some plugins must - dnl be linked into the final binary as well. These plugins have changed between - dnl Qt4 and Qt5. With Qt5, languages moved into core and the WindowsIntegration - dnl plugin was added. Since we can't tell if Qt4 is static or not, it is - dnl assumed for windows builds. + dnl For Qt5, we can check a header to find out whether Qt is build + dnl statically. When Qt is built statically, some plugins must be linked into + dnl the final binary as well. + dnl With Qt5, languages moved into core and the WindowsIntegration plugin was + dnl added. dnl _DYNAMIC_QT_CHECK_STATIC_PLUGINS does a quick link-check and appends the dnl results to QT_LIBS. DYNAMIC_QT_CHECK([ @@ -113,69 +112,67 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ TEMP_CXXFLAGS=$CXXFLAGS CPPFLAGS="$QT_INCLUDES $CPPFLAGS" CXXFLAGS="$PIC_FLAGS $CXXFLAGS" - if test x$dynamic_qt_got_major_vers = x5; then - _DYNAMIC_QT_IS_STATIC - if test x$dynamic_cv_static_qt = xyes; then - _DYNAMIC_QT_FIND_STATIC_PLUGINS - AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) - AC_CACHE_CHECK(for Qt < 5.4, dynamic_cv_need_acc_widget,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]],[[ + _DYNAMIC_QT_IS_STATIC + if test "x$dynamic_cv_static_qt" = xyes; then + _DYNAMIC_QT_FIND_STATIC_PLUGINS + AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) + AC_CACHE_CHECK(for Qt < 5.4, dynamic_cv_need_acc_widget,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], + [[ #if QT_VERSION >= 0x050400 - choke; + choke #endif - ]])], - [dynamic_cv_need_acc_widget=yes], - [dynamic_cv_need_acc_widget=no]) - ]) - if test "x$dynamic_cv_need_acc_widget" = "xyes"; then - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) - fi - if test x$TARGET_OS = xwindows; then - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) - AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) - elif test x$TARGET_OS = xlinux; then - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static]) - AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb]) - elif test x$TARGET_OS = xdarwin; then - AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)]) - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa]) - AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa]) - fi + ]])], + [dynamic_cv_need_acc_widget=yes], + [dynamic_cv_need_acc_widget=no]) + ]) + if test "x$dynamic_cv_need_acc_widget" = xyes; then + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) fi - else - if test x$TARGET_OS = xwindows; then - AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([ - Q_IMPORT_PLUGIN(qcncodecs) - Q_IMPORT_PLUGIN(qjpcodecs) - Q_IMPORT_PLUGIN(qtwcodecs) - Q_IMPORT_PLUGIN(qkrcodecs) - Q_IMPORT_PLUGIN(AccessibleFactory)], - [-lqcncodecs -lqjpcodecs -lqtwcodecs -lqkrcodecs -lqtaccessiblewidgets]) + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) + AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) + if test "x$TARGET_OS" = xwindows; then + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) + AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) + elif test "x$TARGET_OS" = xlinux; then + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static]) + AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb]) + elif test "x$TARGET_OS" = xdarwin; then + AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)]) + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa]) + AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa]) fi fi CPPFLAGS=$TEMP_CPPFLAGS CXXFLAGS=$TEMP_CXXFLAGS ]) - if test x$use_pkgconfig$qt_bin_path = xyes; then - if test x$dynamic_qt_got_major_vers = x5; then - qt_bin_path="`$PKG_CONFIG --variable=host_bins Qt5Core 2>/dev/null`" - fi + if test "x$use_pkgconfig$qt_bin_path" = xyes; then + qt_bin_path="`$PKG_CONFIG --variable=host_bins Qt5Core 2>/dev/null`" fi - if test x$use_hardening != xno; then + if test "x$use_hardening" != xno; then DYNAMIC_QT_CHECK([ AC_MSG_CHECKING(whether -fPIE can be used with this Qt config) TEMP_CPPFLAGS=$CPPFLAGS TEMP_CXXFLAGS=$CXXFLAGS CPPFLAGS="$QT_INCLUDES $CPPFLAGS" CXXFLAGS="$PIE_FLAGS $CXXFLAGS" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], [[ - #if defined(QT_REDUCE_RELOCATIONS) - choke; - #endif + #if defined(QT_REDUCE_RELOCATIONS) + choke + #endif ]])], [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIE_FLAGS ], [ AC_MSG_RESULT(no); QT_PIE_FLAGS=$PIC_FLAGS] @@ -188,11 +185,16 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ AC_MSG_CHECKING(whether -fPIC is needed with this Qt config) TEMP_CPPFLAGS=$CPPFLAGS CPPFLAGS="$QT_INCLUDES $CPPFLAGS" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], [[ - #if defined(QT_REDUCE_RELOCATIONS) - choke; - #endif + #if defined(QT_REDUCE_RELOCATIONS) + choke + #endif ]])], [ AC_MSG_RESULT(no)], [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIC_FLAGS] @@ -201,11 +203,11 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ ]) fi - DYNAMIC_QT_PATH_PROGS([MOC], [moc-qt${dynamic_qt_got_major_vers} moc${dynamic_qt_got_major_vers} moc], $qt_bin_path) - DYNAMIC_QT_PATH_PROGS([UIC], [uic-qt${dynamic_qt_got_major_vers} uic${dynamic_qt_got_major_vers} uic], $qt_bin_path) - DYNAMIC_QT_PATH_PROGS([RCC], [rcc-qt${dynamic_qt_got_major_vers} rcc${dynamic_qt_got_major_vers} rcc], $qt_bin_path) - DYNAMIC_QT_PATH_PROGS([LRELEASE], [lrelease-qt${dynamic_qt_got_major_vers} lrelease${dynamic_qt_got_major_vers} lrelease], $qt_bin_path) - DYNAMIC_QT_PATH_PROGS([LUPDATE], [lupdate-qt${dynamic_qt_got_major_vers} lupdate${dynamic_qt_got_major_vers} lupdate],$qt_bin_path, yes) + DYNAMIC_QT_PATH_PROGS([MOC], [moc-qt5 moc5 moc], $qt_bin_path) + DYNAMIC_QT_PATH_PROGS([UIC], [uic-qt5 uic5 uic], $qt_bin_path) + DYNAMIC_QT_PATH_PROGS([RCC], [rcc-qt5 rcc5 rcc], $qt_bin_path) + DYNAMIC_QT_PATH_PROGS([LRELEASE], [lrelease-qt5 lrelease5 lrelease], $qt_bin_path) + DYNAMIC_QT_PATH_PROGS([LUPDATE], [lupdate-qt5 lupdate5 lupdate],$qt_bin_path, yes) MOC_DEFS='-DHAVE_CONFIG_H -I$(srcdir)' case $host in @@ -228,23 +230,23 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ DYNAMIC_QT_CHECK([ dynamic_enable_qt=yes dynamic_enable_qt_test=yes - if test x$have_qt_test = xno; then + if test "x$have_qt_test" = xno; then dynamic_enable_qt_test=no fi dynamic_enable_qt_dbus=no - if test x$use_dbus != xno && test x$have_qt_dbus = xyes; then + if test "x$use_dbus" != xno && test "x$have_qt_dbus" = xyes; then dynamic_enable_qt_dbus=yes fi - if test x$use_dbus = xyes && test x$have_qt_dbus = xno; then - AC_MSG_ERROR("libQtDBus not found. Install libQtDBus or remove --with-qtdbus.") + if test "x$use_dbus" = xyes && test "x$have_qt_dbus" = xno; then + AC_MSG_ERROR([libQtDBus not found. Install libQtDBus or remove --with-qtdbus.]) fi - if test x$LUPDATE = x; then - AC_MSG_WARN("lupdate is required to update qt translations") + if test "x$LUPDATE" = x; then + AC_MSG_WARN([lupdate is required to update qt translations]) fi ],[ dynamic_enable_qt=no ]) - AC_MSG_RESULT([$dynamic_enable_qt (Qt${dynamic_qt_got_major_vers})]) + AC_MSG_RESULT([$dynamic_enable_qt (Qt5)]) AC_SUBST(QT_PIE_FLAGS) AC_SUBST(QT_INCLUDES) @@ -254,7 +256,7 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ AC_SUBST(QT_DBUS_LIBS) AC_SUBST(QT_TEST_INCLUDES) AC_SUBST(QT_TEST_LIBS) - AC_SUBST(QT_SELECT, qt${dynamic_qt_got_major_vers}) + AC_SUBST(QT_SELECT, qt5) AC_SUBST(MOC_DEFS) ]) @@ -267,39 +269,64 @@ dnl Requires: INCLUDES must be populated as necessary. dnl Output: dynamic_cv_qt5=yes|no AC_DEFUN([_DYNAMIC_QT_CHECK_QT5],[ AC_CACHE_CHECK(for Qt 5, dynamic_cv_qt5,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]], + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], [[ - #if QT_VERSION < 0x050000 - choke me - #else - return 0; + #if QT_VERSION < 0x050000 || QT_VERSION_MAJOR < 5 + choke #endif ]])], [dynamic_cv_qt5=yes], [dynamic_cv_qt5=no]) ])]) +dnl Internal. Check if the included version of Qt is greater than Qt58. +dnl Requires: INCLUDES must be populated as necessary. +dnl Output: dynamic_cv_qt5=yes|no +AC_DEFUN([_DYNAMIC_QT_CHECK_QT58],[ + AC_CACHE_CHECK(for > Qt 5.7, dynamic_cv_qt58,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], + [[ + #if QT_VERSION_MINOR < 8 + choke + #endif + ]])], + [dynamic_cv_qt58=yes], + [dynamic_cv_qt58=no]) +])]) + + dnl Internal. Check if the linked version of Qt was built as static libs. -dnl Requires: Qt5. This check cannot determine if Qt4 is static. +dnl Requires: Qt5. dnl Requires: INCLUDES and LIBS must be populated as necessary. dnl Output: dynamic_cv_static_qt=yes|no dnl Output: Defines QT_STATICPLUGIN if plugins are static. AC_DEFUN([_DYNAMIC_QT_IS_STATIC],[ AC_CACHE_CHECK(for static Qt, dynamic_cv_static_qt,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]], - [[ - #if defined(QT_STATIC) - return 0; - #else - choke me - #endif - ]])], - [dynamic_cv_static_qt=yes], - [dynamic_cv_static_qt=no]) - ]) - if test xdynamic_cv_static_qt = xyes; then + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION OR QT_VERSION_STR + # include + #endif + ]], + [[ + #if !defined(QT_STATIC) + choke + #endif + ]])], + [dynamic_cv_static_qt=yes], + [dynamic_cv_static_qt=no]) + ]) + if test "x$dynamic_cv_static_qt" = xyes; then AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol for static Qt plugins]) fi ]) @@ -324,56 +351,76 @@ AC_DEFUN([_DYNAMIC_QT_CHECK_STATIC_PLUGINS],[ ]) dnl Internal. Find paths necessary for linking qt static plugins -dnl Inputs: dynamic_qt_got_major_vers. 4 or 5. dnl Inputs: qt_plugin_path. optional. dnl Outputs: QT_LIBS is appended AC_DEFUN([_DYNAMIC_QT_FIND_STATIC_PLUGINS],[ - if test x$dynamic_qt_got_major_vers = x5; then - if test x$qt_plugin_path != x; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" - if test -d "$qt_plugin_path/accessible"; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" - fi + if test "x$qt_plugin_path" != x; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" + if test -d "$qt_plugin_path/accessible"; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" fi - if test x$use_pkgconfig = xyes; then + if test "x$use_pkgconfig" = xyes; then : dnl m4_ifdef([PKG_CHECK_MODULES],[ - PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) - if test x$TARGET_OS = xlinux; then + case $host in + *linux*) + dynamic_cv_qt58=no + ;; + esac + if test "x$dynamic_cv_qt58" = xno; then + PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) + else + PKG_CHECK_MODULES([QTFONTDATABASE], [Qt5FontDatabaseSupport], [QT_LIBS="-lQt5FontDatabaseSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTEVENTDISPATCHER], [Qt5EventDispatcherSupport], [QT_LIBS="-lQt5EventDispatcherSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTTHEME], [Qt5ThemeSupport], [QT_LIBS="-lQt5ThemeSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTDEVICEDISCOVERY], [Qt5DeviceDiscoverySupport], [QT_LIBS="-lQt5DeviceDiscoverySupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTACCESSIBILITY], [Qt5AccessibilitySupport], [QT_LIBS="-lQt5AccessibilitySupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTFB], [Qt5FbSupport], [QT_LIBS="-lQt5FbSupport $QT_LIBS"]) + fi + if test "x$TARGET_OS" = xlinux; then PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"]) if ${PKG_CONFIG} --exists "Qt5Core >= 5.5" 2>/dev/null; then PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"]) fi - elif test x$TARGET_OS = xdarwin; then - PKG_CHECK_MODULES([QTPRINT], [Qt5PrintSupport], [QT_LIBS="$QTPRINT_LIBS $QT_LIBS"]) - else - if ${PKG_CONFIG} --exists "Qt5Core >= 5.6" 2>/dev/null; then - QT_LIBS="-lQt5PlatformSupport $QT_LIBS" - fi + elif test "x$TARGET_OS" = xdarwin; then + PKG_CHECK_MODULES([QTCLIPBOARD], [Qt5ClipboardSupport], [QT_LIBS="-lQt5ClipboardSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTGRAPHICS], [Qt5GraphicsSupport], [QT_LIBS="-lQt5GraphicsSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTCGL], [Qt5CglSupport], [QT_LIBS="-lQt5CglSupport $QT_LIBS"]) fi ]) else - if test x$TARGET_OS = xwindows; then - AC_CACHE_CHECK(for Qt >= 5.6, dynamic_cv_need_platformsupport,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]],[[ - #if QT_VERSION < 0x050600 - choke; - #endif + if test "x$TARGET_OS" = xwindows; then + AC_CACHE_CHECK(for Qt >= 5.6, dynamic_cv_need_platformsupport,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], + [[ + #if QT_VERSION < 0x050600 || QT_VERSION_MINOR < 6 + choke + #endif ]])], [dynamic_cv_need_platformsupport=yes], [dynamic_cv_need_platformsupport=no]) ]) - if test x$dynamic_cv_need_platformsupport = xyes; then - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}PlatformSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXPlatformSupport not found))) + if test "x$dynamic_cv_need_platformsupport" = xyes; then + if test x$dynamic_cv_qt58 = xno; then + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}PlatformSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXPlatformSupport not found))) + else + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}FontDatabaseSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXFontDatabaseSupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}EventDispatcherSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXEventDispatcherSupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}ThemeSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXThemeSupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}FbSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXFbSupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}DeviceDiscoverySupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXDeviceDiscoverySupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}AccessibilitySupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXAccessibilitySupport not found))) + QT_LIBS="$QT_LIBS -lversion -ldwmapi -luxtheme" + fi fi fi fi - else - if test x$qt_plugin_path != x; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" - QT_LIBS="$QT_LIBS -L$qt_plugin_path/codecs" - fi - fi + fi ]) dnl Internal. Find Qt libraries using pkg-config. @@ -382,46 +429,22 @@ dnl first. dnl Inputs: $1: If dynamic_qt_want_version is "auto", check for this version dnl first. dnl Outputs: All necessary QT_* variables are set. -dnl Outputs: dynamic_qt_got_major_vers is set to "4" or "5". dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITH_PKGCONFIG],[ m4_ifdef([PKG_CHECK_MODULES],[ - auto_priority_version=$1 - if test x$auto_priority_version = x; then - auto_priority_version=qt5 - fi - if test x$dynamic_qt_want_version = xqt5 || ( test x$dynamic_qt_want_version = xauto && test x$auto_priority_version = xqt5 ); then - QT_LIB_PREFIX=Qt5 - dynamic_qt_got_major_vers=5 - else - QT_LIB_PREFIX=Qt - dynamic_qt_got_major_vers=4 - fi + QT_LIB_PREFIX=Qt5 qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets" - qt4_modules="QtCore QtGui QtNetwork" DYNAMIC_QT_CHECK([ - if test x$dynamic_qt_want_version = xqt5 || ( test x$dynamic_qt_want_version = xauto && test x$auto_priority_version = xqt5 ); then - PKG_CHECK_MODULES([QT], [$qt5_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes],[have_qt=no]) - elif test x$dynamic_qt_want_version = xqt4 || ( test x$dynamic_qt_want_version = xauto && test x$auto_priority_version = xqt4 ); then - PKG_CHECK_MODULES([QT], [$qt4_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes], [have_qt=no]) - fi + PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" have_qt=yes],[have_qt=no]) - dnl qt version is set to 'auto' and the preferred version wasn't found. Now try the other. - if test x$have_qt = xno && test x$dynamic_qt_want_version = xauto; then - if test x$auto_priority_version = xqt5; then - PKG_CHECK_MODULES([QT], [$qt4_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes; QT_LIB_PREFIX=Qt; dynamic_qt_got_major_vers=4], [have_qt=no]) - else - PKG_CHECK_MODULES([QT], [$qt5_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes; QT_LIB_PREFIX=Qt5; dynamic_qt_got_major_vers=5], [have_qt=no]) - fi - fi - if test x$have_qt != xyes; then + if test "x$have_qt" != xyes; then have_qt=no DYNAMIC_QT_FAIL([Qt dependencies not found]) fi ]) DYNAMIC_QT_CHECK([ PKG_CHECK_MODULES([QT_TEST], [${QT_LIB_PREFIX}Test], [QT_TEST_INCLUDES="$QT_TEST_CFLAGS"; have_qt_test=yes], [have_qt_test=no]) - if test x$use_dbus != xno; then + if test "x$use_dbus" != xno; then PKG_CHECK_MODULES([QT_DBUS], [${QT_LIB_PREFIX}DBus], [QT_DBUS_INCLUDES="$QT_DBUS_CFLAGS"; have_qt_dbus=yes], [have_qt_dbus=no]) fi ]) @@ -434,7 +457,6 @@ dnl from the discovered headers. dnl Inputs: dynamic_qt_want_version (from --with-gui=). The version to use. dnl If "auto", the version will be discovered by _DYNAMIC_QT_CHECK_QT5. dnl Outputs: All necessary QT_* variables are set. -dnl Outputs: dynamic_qt_got_major_vers is set to "4" or "5". dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ TEMP_CPPFLAGS="$CPPFLAGS" @@ -442,7 +464,7 @@ AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ CXXFLAGS="$PIC_FLAGS $CXXFLAGS" TEMP_LIBS="$LIBS" DYNAMIC_QT_CHECK([ - if test x$qt_include_path != x; then + if test "x$qt_include_path" != x; then QT_INCLUDES="-I$qt_include_path -I$qt_include_path/QtCore -I$qt_include_path/QtGui -I$qt_include_path/QtWidgets -I$qt_include_path/QtNetwork -I$qt_include_path/QtTest -I$qt_include_path/QtDBus" CPPFLAGS="$QT_INCLUDES $CPPFLAGS" fi @@ -453,54 +475,52 @@ AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ DYNAMIC_QT_CHECK([AC_CHECK_HEADER([QLocalSocket],, DYNAMIC_QT_FAIL(QtNetwork headers missing))]) DYNAMIC_QT_CHECK([ - if test x$dynamic_qt_want_version = xauto; then + if test "x$dynamic_qt_want_version" = xauto; then _DYNAMIC_QT_CHECK_QT5 + _DYNAMIC_QT_CHECK_QT58 fi - if test x$dynamic_cv_qt5 = xyes || test x$dynamic_qt_want_version = xqt5; then - QT_LIB_PREFIX=Qt5 - dynamic_qt_got_major_vers=5 - else - QT_LIB_PREFIX=Qt - dynamic_qt_got_major_vers=4 - fi + QT_LIB_PREFIX=Qt5 ]) DYNAMIC_QT_CHECK([ LIBS= - if test x$qt_lib_path != x; then + if test "x$qt_lib_path" != x; then LIBS="$LIBS -L$qt_lib_path" fi - if test x$TARGET_OS = xwindows; then + if test "x$TARGET_OS" = xwindows; then AC_CHECK_LIB([imm32], [main],, DYNAMIC_QT_FAIL(libimm32 not found)) fi ]) DYNAMIC_QT_CHECK(AC_CHECK_LIB([z] ,[main],,AC_MSG_WARN([zlib not found. Assuming qt has it built-in]))) - DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([jpeg_create_decompress] ,[qtjpeg jpeg],,AC_MSG_WARN([libjpeg not found. Assuming qt has it built-in]))) - DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([pcre16_exec], [qtpcre pcre16],,AC_MSG_WARN([libpcre16 not found. Assuming qt has it built-in]))) - DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([hb_ot_tags_from_script] ,[qtharfbuzzng harfbuzz],,AC_MSG_WARN([libharfbuzz not found. Assuming qt has it built-in or support is disabled]))) - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Core] ,[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXCore not found))) - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Gui] ,[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXGui not found))) - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXNetwork not found))) - if test x$dynamic_qt_got_major_vers = x5; then - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXWidgets not found))) + if test x$dynamic_cv_qt58 = xno; then + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([pcre16_exec], [qtpcre pcre16],,AC_MSG_WARN([libpcre16 not found. Assuming qt has it built-in]))) + else + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtlibpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([pcre2_match_16], [qtpcre2 libqtpcre2],,AC_MSG_WARN([libqtpcre2 not found. Assuming qt has it built-in]))) fi + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([hb_ot_tags_from_script] ,[qtharfbuzzng qtharfbuzz harfbuzz],,AC_MSG_WARN([libharfbuzz not found. Assuming qt has it built-in or support is disabled]))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Core] ,[main],,DYNAMIC_QT_FAIL(lib${QT_LIB_PREFIX}Core not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Gui] ,[main],,DYNAMIC_QT_FAIL(lib${QT_LIB_PREFIX}Gui not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,DYNAMIC_QT_FAIL(lib${QT_LIB_PREFIX}Network not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,DYNAMIC_QT_FAIL(lib${QT_LIB_PREFIX}Widgets not found))) QT_LIBS="$LIBS" LIBS="$TEMP_LIBS" DYNAMIC_QT_CHECK([ LIBS= - if test x$qt_lib_path != x; then + if test "x$qt_lib_path" != x; then LIBS="-L$qt_lib_path" fi AC_CHECK_LIB([${QT_LIB_PREFIX}Test], [main],, have_qt_test=no) AC_CHECK_HEADER([QTest],, have_qt_test=no) QT_TEST_LIBS="$LIBS" - if test x$use_dbus != xno; then + if test "x$use_dbus" != xno; then LIBS= - if test x$qt_lib_path != x; then + if test "x$qt_lib_path" != x; then LIBS="-L$qt_lib_path" fi AC_CHECK_LIB([${QT_LIB_PREFIX}DBus], [main],, have_qt_dbus=no) @@ -512,4 +532,3 @@ AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ CXXFLAGS="$TEMP_CXXFLAGS" LIBS="$TEMP_LIBS" ]) - diff --git a/configure.ac b/configure.ac index f7dffd670f..890f69d2d4 100644 --- a/configure.ac +++ b/configure.ac @@ -1,11 +1,11 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 2) -define(_CLIENT_VERSION_MINOR, 3) -define(_CLIENT_VERSION_REVISION, 5) +define(_CLIENT_VERSION_MINOR, 5) +define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) -define(_COPYRIGHT_YEAR, 2018) +define(_COPYRIGHT_YEAR, 2021) AC_INIT([Dynamic],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/duality-solutions/dynamic/issues],[dynamic]) AC_CONFIG_SRCDIR([src/validation.cpp]) AC_CONFIG_HEADERS([src/config/dynamic-config.h]) @@ -48,11 +48,11 @@ case $host in ;; esac -dnl Require C++11 compiler (no GNU extensions) -AX_CXX_COMPILE_STDCXX([11], [ext], [mandatory], [nodefault]) +dnl Require C++14 compiler (no GNU extensions) +AX_CXX_COMPILE_STDCXX([14], [ext], [mandatory], [nodefault]) dnl Check if -latomic is required for CHECK_ATOMIC - + dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures dnl that we get the same -std flags for both. m4_ifdef([AC_PROG_OBJCXX],[ @@ -91,6 +91,20 @@ AC_ARG_ENABLE([wallet], [enable_wallet=$enableval], [enable_wallet=yes]) +# Enable GPU miner +AC_ARG_ENABLE([gpu], + [AS_HELP_STRING([--enable-gpu], + [enable GPU miner (disabled by default)])], + [enable_gpu=$enableval], + [enable_gpu=no]) + +# Enable CUDA +AC_ARG_ENABLE([cuda], + [AS_HELP_STRING([--enable-cuda], + [enable CUDA miner (defaults is no)])], + [enable_cuda=$enableval], + [enable_cuda=no]) + AC_ARG_WITH([miniupnpc], [AS_HELP_STRING([--with-miniupnpc], [enable UPNP (default is yes if libminiupnpc is found)])], @@ -193,8 +207,6 @@ AC_ARG_ENABLE([avx512f], [have_avx512f=${enableval}], [have_avx512f=no]) -AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], []) - # Enable debug AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], @@ -245,9 +257,9 @@ AC_ARG_WITH([utils], AC_ARG_WITH([libs], [AS_HELP_STRING([--with-libs], - [build libraries (default=yes)])], + [build libraries (default=no)])], [build_dynamic_libs=$withval], - [build_dynamic_libs=yes]) + [build_dynamic_libs=no]) AC_ARG_WITH([daemon], [AS_HELP_STRING([--with-daemon], @@ -337,8 +349,8 @@ case $host in AC_CHECK_PROG([BREW],brew, brew) if test x$BREW = xbrew; then dnl These Homebrew packages may be keg-only, meaning that they won't be found - dnl in expected paths because they may conflict with system files. Ask dnl Homebrew where each one is located, then adjust paths accordingly. + dnl in expected paths because they may conflict with system files. Ask dnl It's safe to add these paths even if the functionality is disabled by dnl the user (--without-wallet or --without-gui for example). @@ -482,6 +494,8 @@ if test x$use_glibc_compat != xno; then [ fdelt_type="long int"]) AC_MSG_RESULT($fdelt_type) AC_DEFINE_UNQUOTED(FDELT_TYPE, $fdelt_type,[parameter and return value type for __fdelt_chk]) + AX_CHECK_LINK_FLAG([[-Wl,--wrap=__divmoddi4]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=__divmoddi4"]) + AX_CHECK_LINK_FLAG([[-Wl,--wrap=log2f]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=log2f"]) else AC_SEARCH_LIBS([clock_gettime],[rt]) fi @@ -528,7 +542,7 @@ fi AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h]) AC_CHECK_DECLS([strnlen]) - + # Check for daemon(3), unrelated to --with-daemon (although used by it) AC_CHECK_DECLS([daemon]) @@ -569,6 +583,22 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([ ] ) +dnl check for gmtime_r(), fallback to gmtime_s() if that is unavailable +dnl fail if neither are available. +AC_MSG_CHECKING(for gmtime_r) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ gmtime_r((const time_t *) nullptr, (struct tm *) nullptr); ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_GMTIME_R, 1, [Define this symbol if gmtime_r is available]) ], + [ AC_MSG_RESULT(no); + AC_MSG_CHECKING(for gmtime_s); + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ gmtime_s((struct tm *) nullptr, (const time_t *) nullptr); ]])], + [ AC_MSG_RESULT(yes)], + [ AC_MSG_RESULT(no); AC_MSG_ERROR(Both gmtime_r and gmtime_s are unavailable) ] + ) + ] +) + if test x$use_reduce_exports = xyes; then AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"], [AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])]) @@ -609,6 +639,12 @@ AC_SUBST(LEVELDB_CPPFLAGS) AC_SUBST(LIBLEVELDB) AC_SUBST(LIBMEMENV) +LIBTORRENT_CPPFLAGS= +LIBTORRENT= +AM_CONDITIONAL([EMBEDDED_LIBTORRENT],[true]) +AC_SUBST(LIBTORRENT_CPPFLAGS) +AC_SUBST(LIBTORRENT) + if test x$enable_wallet != xno; then dnl Check for libdb_cxx only if wallet enabled DYNAMIC_FIND_BDB48 @@ -623,10 +659,10 @@ if test x$use_upnp != xno; then ) fi -DYNAMIC_QT_INIT +DYNAMIC_QT_INIT() dnl sets $dynamic_enable_qt, $dynamic_enable_qt_test, $dynamic_enable_qt_dbus -DYNAMIC_QT_CONFIGURE([$use_pkgconfig], [qt5]) +DYNAMIC_QT_CONFIGURE([$use_pkgconfig]) if test x$build_dynamic_utils$build_dynamicd$dynamic_enable_qt$use_tests = xnononono; then use_boost=no @@ -807,7 +843,6 @@ if test x$use_pkgconfig = xyes; then [ PKG_CHECK_MODULES([SSL], [libssl],, [AC_MSG_ERROR(openssl not found.)]) PKG_CHECK_MODULES([CRYPTO], [libcrypto],,[AC_MSG_ERROR(libcrypto not found.)]) - DYNAMIC_QT_CHECK([PKG_CHECK_MODULES([PROTOBUF], [protobuf], [have_protobuf=yes], [DYNAMIC_QT_FAIL(libprotobuf not found)])]) if test x$use_qr != xno; then DYNAMIC_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) fi @@ -858,13 +893,21 @@ else AC_DEFINE_UNQUOTED([ENABLE_ZMQ],[0],[Define to 1 to enable ZMQ functions]) fi - DYNAMIC_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],[PROTOBUF_LIBS=-lprotobuf], DYNAMIC_QT_FAIL(libprotobuf not found))) if test x$use_qr != xno; then DYNAMIC_QT_CHECK([AC_CHECK_LIB([qrencode], [main],[QR_LIBS=-lqrencode], [have_qrencode=no])]) DYNAMIC_QT_CHECK([AC_CHECK_HEADER([qrencode.h],, have_qrencode=no)]) fi fi +if test "x$use_zmq" = xyes; then + dnl Assume libzmq was built for static linking + case $host in + *mingw*) + ZMQ_CFLAGS="$ZMQ_CFLAGS -DZMQ_STATIC" + ;; + esac +fi + CXXFLAGS_TEMP="$CXXFLAGS" LIBS_TEMP="$LIBS" CXXFLAGS="$CXXFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS" @@ -873,8 +916,6 @@ AC_CHECK_HEADER([openssl/ec.h],, AC_MSG_ERROR(OpenSSL ec header missing),) CXXFLAGS="$CXXFLAGS_TEMP" LIBS="$LIBS_TEMP" -DYNAMIC_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path) - AC_MSG_CHECKING([whether to build dynamicd]) AM_CONDITIONAL([BUILD_DYNAMICD], [test x$build_dynamicd = xyes]) AC_MSG_RESULT($build_dynamicd) @@ -922,6 +963,18 @@ else AC_MSG_RESULT(no) fi +if test x$enable_gpu = xyes; then + AC_DEFINE_UNQUOTED([ENABLE_GPU],[1],[Define to 1 to enable GPU miner]) + + if test "x$enable_cuda" = xyes; then + AX_CHECK_CUDA + if test "x$NVCC" = xno; then + enable_cuda=no + AC_MSG_WARN([NVIDIA CUDA nvcc compiler not found, falling back on OpenCL. Specify --with-cuda=/path/to/cuda or --disable-gpu]) + fi + fi +fi + dnl enable upnp support AC_MSG_CHECKING([whether to build with support for UPnP]) if test x$have_miniupnpc = xno; then @@ -1014,6 +1067,8 @@ fi AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) +AM_CONDITIONAL([ENABLE_GPU],[test x$enable_gpu = xyes]) +AM_CONDITIONAL([ENABLE_CUDA], [test x"$enable_cuda" = xyes]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$dynamic_enable_qt = xyes]) @@ -1044,6 +1099,7 @@ AC_SUBST(RELDFLAGS) AC_SUBST(HARDENED_CXXFLAGS) AC_SUBST(HARDENED_CPPFLAGS) AC_SUBST(HARDENED_LDFLAGS) +AC_SUBST(COMPAT_LDFLAGS) AC_SUBST(PIC_FLAGS) AC_SUBST(PIE_FLAGS) AC_SUBST(SSE42_CXXFLAGS) @@ -1057,6 +1113,7 @@ AC_SUBST(MINIUPNPC_CPPFLAGS) AC_SUBST(MINIUPNPC_LIBS) AC_SUBST(LEVELDB_ATOMIC_CPPFLAGS) AC_SUBST(LEVELDB_ATOMIC_CXXFLAGS) +AC_SUBST(HAVE_GMTIME_R) AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) AC_CONFIG_FILES([qa/pull-tester/run-dynamicd-for-test.sh],[chmod +x qa/pull-tester/run-dynamicd-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py]) @@ -1084,7 +1141,7 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR" unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" -ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery" +ac_configure_args="${ac_configure_args} --enable-module-ecdh --enable-experimental --disable-shared --with-pic --with-bignum=no --enable-module-recovery" AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue]) AC_OUTPUT diff --git a/contrib/debian/control b/contrib/debian/control index 96b3e19444..6eb32a8330 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -19,8 +19,7 @@ Build-Depends: debhelper, libboost-test-dev (>> 1.35) | libboost-test1.35-dev, qt4-qmake, libqt4-dev, - libqrencode-dev, - libprotobuf-dev, protobuf-compiler + libqrencode-dev Standards-Version: 3.9.2 Homepage: http://www.dynamicpay.io/ Vcs-Git: git://github.com/duality-solutions/dynamic.git diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index af2ad3fff5..8239ab9199 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -40,14 +40,14 @@ 'GCC': (4,4,0), 'CXXABI': (1,3,3), 'GLIBCXX': (3,4,13), -'GLIBC': (2,11) +'GLIBC': (2,28) } # See here for a description of _IO_stdin_used: # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109 # Ignore symbols that are exported as part of every executable IGNORE_EXPORTS = { -'_edata', '_end', '_init', '__bss_start', '_fini', '_IO_stdin_used' +'_edata', '_end', '_init', '__bss_start', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr' } READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt') diff --git a/contrib/gitian-descriptors/gitian-arm.yml b/contrib/gitian-descriptors/gitian-arm.yml index a00184afc1..48188e5bdc 100644 --- a/contrib/gitian-descriptors/gitian-arm.yml +++ b/contrib/gitian-descriptors/gitian-arm.yml @@ -1,5 +1,5 @@ --- -name: "dynamic-arm-2.3.5.0" +name: "dynamic-arm-2.5.0.0" enable_cache: true suites: - "trusty" @@ -27,7 +27,7 @@ packages: - "bsdmainutils" - "ca-certificates" - "python" -reference_datetime: "2018-01-01 00:00:00" +reference_datetime: "2020-01-01 00:00:00" remotes: - "url": "https://github.com/duality-solutions/dynamic.git" "dir": "dynamic" diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index dc87c7c017..c72aa8c2c9 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "dynamic-linux-2.3.5.0" +name: "dynamic-linux-2.5.0.0" enable_cache: true suites: - "trusty" @@ -16,7 +16,7 @@ packages: - "faketime" - "bsdmainutils" - "binutils-gold" -reference_datetime: "2017-01-01 00:00:00" +reference_datetime: "2020-01-01 00:00:00" remotes: - "url": "https://github.com/duality-solutions/dynamic.git" "dir": "dynamic" diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index f1164aa22d..75ffd6e4dd 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -6,7 +6,7 @@ architectures: - "amd64" packages: - "faketime" -reference_datetime: "2018-01-01 00:00:00" +reference_datetime: "2020-01-01 00:00:00" remotes: - "url": "https://github.com/duality-solutions/dynamic-detached-sigs.git" "dir": "signature" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 73b4368ebf..d2dbee03a2 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,5 +1,5 @@ --- -name: "dynamic-osx-2.3.5.0" +name: "dynamic-osx-2.5.0.0" enable_cache: true suites: - "trusty" @@ -27,7 +27,7 @@ packages: - "python-dev" - "python-setuptools" - "fonts-tuffy" -reference_datetime: "2018-01-01 00:00:00" +reference_datetime: "2020-01-01 00:00:00" remotes: - "url": "https://github.com/duality-solutions/dynamic.git" "dir": "dynamic" diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index 1d86fa8dc8..16c737b270 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -7,7 +7,7 @@ architectures: packages: - "libssl-dev" - "autoconf" -reference_datetime: "2018-01-01 00:00:00" +reference_datetime: "2020-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin-detached-sigs.git" "dir": "signature" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index b37c2421a1..1af7019a8a 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,5 +1,5 @@ --- -name: "dynamic-2.3.5.0" +name: "dynamic-2.5.0.0" enable_cache: true suites: - "trusty" diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh new file mode 100755 index 0000000000..3b8dc3cdd3 --- /dev/null +++ b/contrib/macdeploy/extract-osx-sdk.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +set -e + +INPUTFILE="Xcode_7.3.1.dmg" +HFSFILENAME="5.hfs" +SDKDIR="Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk" + +7z x "${INPUTFILE}" "${HFSFILENAME}" +SDKNAME="$(basename "${SDKDIR}")" +SDKDIRINODE=$(ifind -n "${SDKDIR}" "${HFSFILENAME}") +fls "${HFSFILENAME}" -rpF ${SDKDIRINODE} | + while read type inode filename; do + inode="${inode::-1}" + if [ "${filename:0:14}" = "usr/share/man/" ]; then + continue + fi + filename="${SDKNAME}/$filename" + echo "Extracting $filename ..." + mkdir -p "$(dirname "$filename")" + if [ "$type" = "l/l" ]; then + ln -s "$(icat "${HFSFILENAME}" $inode)" "$filename" + else + icat "${HFSFILENAME}" $inode >"$filename" + fi +done +echo "Building ${SDKNAME}.tar.gz ..." +MTIME="$(istat "${HFSFILENAME}" "${SDKDIRINODE}" | perl -nle 'm/Content Modified:\s+(.*?)\s\(/ && print $1')" +find "${SDKNAME}" | sort | tar --no-recursion --mtime="${MTIME}" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > "${SDKNAME}.tar.gz" +echo 'All done!' diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py index 62c3d34fb7..b4ca312dde 100755 --- a/contrib/zmq/zmq_sub.py +++ b/contrib/zmq/zmq_sub.py @@ -12,9 +12,11 @@ zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock") zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx") zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtxlock") +zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashinstantsenddoublespend") zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawblock") zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawtx") zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawtxlock") +zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawinstantsenddoublespend") zmqSubSocket.connect("tcp://127.0.0.1:%i" % port) try: @@ -46,6 +48,12 @@ elif topic == "rawtxlock": print('- RAW TX LOCK ('+sequence+') -') print(binascii.hexlify(body).decode("utf-8")) + elif topic == "rawinstantsenddoublespend": + print('- RAW IS DOUBLE SPEND ('+sequence+') -') + print(binascii.hexlify(body).decode("utf-8")) + elif topic == "hashinstantsenddoublespend": + print('- HASH IS DOUBLE SPEND ('+sequence+') -') + print(binascii.hexlify(body).decode("utf-8")) except KeyboardInterrupt: zmqContext.destroy() diff --git a/depends/Makefile b/depends/Makefile index dedb0674cf..85c805745e 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -14,14 +14,12 @@ PATCHES_PATH = $(BASEDIR)/patches BASEDIR = $(CURDIR) HASH_LENGTH:=11 DOWNLOAD_CONNECT_TIMEOUT:=10 -DOWNLOAD_RETRIES:=3 HOST_ID_SALT ?= salt BUILD_ID_SALT ?= salt host:=$(BUILD) ifneq ($(HOST),) host:=$(HOST) -host_toolchain:=$(HOST)- endif ifneq ($(DEBUG),) @@ -96,10 +94,6 @@ upnp_packages_$(NO_UPNP) = $(upnp_packages) packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) -ifneq ($(qt_packages_),) -native_packages += $(qt_native_packages) -endif - all_packages = $(packages) $(native_packages) meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk @@ -171,7 +165,7 @@ install: check-packages $(host_prefix)/share/config.site download-one: check-sources $(all_sources) download-osx: - @$(MAKE) -s HOST=x86_64-apple-darwin11 download-one + @$(MAKE) -s HOST=x86_64-apple-darwin16 download-one download-linux: @$(MAKE) -s HOST=x86_64-unknown-linux-gnu download-one download-win: diff --git a/depends/README.md b/depends/README.md index 6053c531b4..9df1b720e1 100644 --- a/depends/README.md +++ b/depends/README.md @@ -22,7 +22,7 @@ Common `host-platform-triplets` for cross compilation are: - `i686-w64-mingw32` for Win32 - `x86_64-w64-mingw32` for Win64 -- `x86_64-apple-darwin11` for MacOSX +- `x86_64-apple-darwin16` for MacOSX - `arm-linux-gnueabihf` for Linux ARM 32 bit - `aarch64-linux-gnu` for Linux ARM 64 bit diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index 27f550ab03..adf75e6ff5 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -7,11 +7,11 @@ build_darwin_OTOOL: = $(shell xcrun -f otool) build_darwin_NM: = $(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) build_darwin_SHA256SUM = shasum -a 256 -build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o +build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) -o #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) -darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) -stdlib=libc++ +darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) -stdlib=libc++ -fvisibility=hidden darwin_AR:=$(shell xcrun -f ar) darwin_RANLIB:=$(shell xcrun -f ranlib) darwin_STRIP:=$(shell xcrun -f strip) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk index b03f424010..9af0d066a0 100644 --- a/depends/builders/linux.mk +++ b/depends/builders/linux.mk @@ -1,2 +1,2 @@ build_linux_SHA256SUM = sha256sum -build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o +build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) -o diff --git a/depends/config.site.in b/depends/config.site.in index 3d7c9fd43c..4879b24f69 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -16,10 +16,6 @@ fi if test -z $with_qt_bindir; then with_qt_bindir=$depends_prefix/native/bin fi -if test -z $with_protoc_bindir; then - with_protoc_bindir=$depends_prefix/native/bin -fi - if test -z $enable_wallet && test -n "@no_wallet@"; then enable_wallet=no diff --git a/depends/funcs.mk b/depends/funcs.mk index 15e404e42d..934a3bf055 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -31,6 +31,8 @@ endef define fetch_file ( test -f $$($(1)_source_dir)/$(4) || \ ( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \ + (sleep 5 && $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5))) || \ + (sleep 10 && $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5))) || \ $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))) endef @@ -129,9 +131,9 @@ $(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$( $(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig $(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig -$(1)_config_env+=PATH=$(build_prefix)/bin:$(PATH) -$(1)_build_env+=PATH=$(build_prefix)/bin:$(PATH) -$(1)_stage_env+=PATH=$(build_prefix)/bin:$(PATH) +$(1)_config_env+=PATH="$(build_prefix)/bin:$(PATH)" +$(1)_build_env+=PATH="$(build_prefix)/bin:$(PATH)" +$(1)_stage_env+=PATH="$(build_prefix)/bin:$(PATH)" $(1)_autoconf=./configure --host=$($($(1)_type)_host) --disable-dependency-tracking --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)" ifneq ($($(1)_nm),) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 4e58bec74e..f5a1d75233 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,9 +1,9 @@ -OSX_MIN_VERSION=10.8 -OSX_SDK_VERSION=10.11 +OSX_MIN_VERSION=10.14 +OSX_SDK_VERSION=10.14 OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk -LD64_VERSION=253.9 -darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ + +darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) +darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -stdlib=libc++ darwin_CFLAGS=-pipe darwin_CXXFLAGS=$(darwin_CFLAGS) diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk index 6f60d6b3fd..144e5f88b7 100644 --- a/depends/hosts/default.mk +++ b/depends/hosts/default.mk @@ -1,3 +1,7 @@ +ifneq ($(host),$(build)) +host_toolchain:=$(host)- +endif + default_host_CC = $(host_toolchain)gcc default_host_CXX = $(host_toolchain)g++ default_host_AR = $(host_toolchain)ar diff --git a/depends/hosts/linux.mk b/depends/hosts/linux.mk index b13a0f1ad7..602206d634 100644 --- a/depends/hosts/linux.mk +++ b/depends/hosts/linux.mk @@ -1,5 +1,5 @@ linux_CFLAGS=-pipe -linux_CXXFLAGS=$(linux_CFLAGS) +linux_CXXFLAGS=$(linux_CFLAGS) -static-libstdc++ linux_release_CFLAGS=-O2 linux_release_CXXFLAGS=$(linux_release_CFLAGS) diff --git a/depends/hosts/mingw32.mk b/depends/hosts/mingw32.mk index dbfb62fdcf..83fc501a19 100644 --- a/depends/hosts/mingw32.mk +++ b/depends/hosts/mingw32.mk @@ -1,5 +1,5 @@ mingw32_CFLAGS=-pipe -mingw32_CXXFLAGS=$(mingw32_CFLAGS) +mingw32_CXXFLAGS=$(mingw32_CFLAGS) -static-libstdc++ mingw32_release_CFLAGS=-O2 mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS) diff --git a/depends/packages/backtrace.mk b/depends/packages/backtrace.mk new file mode 100644 index 0000000000..d84391c0fe --- /dev/null +++ b/depends/packages/backtrace.mk @@ -0,0 +1,21 @@ +package=backtrace +$(package)_version=rust-snapshot-2018-05-22 +$(package)_download_path=https://github.com/rust-lang-nursery/libbacktrace/archive +$(package)_file_name=$($(package)_version).tar.gz +$(package)_sha256_hash=8da6daa0a582c9bbd1f2933501168b4c43664700f604f43e922e85b99e5049bc + +define $(package)_set_vars +$(package)_config_opts=--disable-shared --prefix=$(host_prefix) +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 423a3ce01b..4367747916 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1_65_1_rc2 -$(package)_download_path=https://dl.bintray.com/boostorg/release/1.65.1/source/ +$(package)_version=1_70_0 +$(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/1.70.0/source/ $(package)_file_name=$(package)_$($(package)_version).tar.bz2 -$(package)_sha256_hash=9807a5d16566c57fd74fb522764e0b134a8bbe6b6e8967b83afefd30dcd3be81 +$(package)_sha256_hash=430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778 define $(package)_set_vars $(package)_config_opts_release=variant=release diff --git a/depends/packages/chia_bls.mk b/depends/packages/chia_bls.mk new file mode 100644 index 0000000000..36ed585fb9 --- /dev/null +++ b/depends/packages/chia_bls.mk @@ -0,0 +1,51 @@ +package=chia_bls +$(package)_version=v20181101 +# It's actually from https://github.com/Chia-Network/bls-signatures, but we have so many patches atm that it's forked +$(package)_download_path=https://github.com/dashpay/bls-signatures/archive +$(package)_file_name=$($(package)_version).tar.gz +$(package)_sha256_hash=b3ec74a77a7b6795f84b05e051a0824ef8d9e05b04b2993f01040f35689aa87c +$(package)_dependencies=gmp +#$(package)_patches=...TODO (when we switch back to https://github.com/Chia-Network/bls-signatures) + +#define $(package)_preprocess_cmds +# for i in $($(package)_patches); do patch -N -p1 < $($(package)_patch_dir)/$$$$i; done +#endef + +define $(package)_set_vars + $(package)_config_opts=-DCMAKE_INSTALL_PREFIX=$($(package)_staging_dir)/$(host_prefix) + $(package)_config_opts+= -DCMAKE_PREFIX_PATH=$($(package)_staging_dir)/$(host_prefix) + $(package)_config_opts+= -DSTLIB=ON -DSHLIB=OFF -DSTBIN=ON + $(package)_config_opts_linux=-DOPSYS=LINUX -DCMAKE_SYSTEM_NAME=Linux + $(package)_config_opts_darwin=-DOPSYS=MACOSX -DCMAKE_SYSTEM_NAME=Darwin + $(package)_config_opts_mingw32=-DOPSYS=WINDOWS -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS="" -DCMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS="" + $(package)_config_opts_i686+= -DWSIZE=32 + $(package)_config_opts_x86_64+= -DWSIZE=64 + $(package)_config_opts_arm+= -DWSIZE=32 + $(package)_config_opts_armv7l+= -DWSIZE=32 + $(package)_config_opts_debug=-DDEBUG=ON -DCMAKE_BUILD_TYPE=Debug + + ifneq ($(darwin_native_toolchain),) + $(package)_config_opts_darwin+= -DCMAKE_AR="$(host_prefix)/native/bin/$($(package)_ar)" + $(package)_config_opts_darwin+= -DCMAKE_RANLIB="$(host_prefix)/native/bin/$($(package)_ranlib)" + endif +endef + +define $(package)_config_cmds + export CC="$($(package)_cc)" && \ + export CXX="$($(package)_cxx)" && \ + export CFLAGS="$($(package)_cflags) $($(package)_cppflags)" && \ + export CXXFLAGS="$($(package)_cxxflags) $($(package)_cppflags)" && \ + export LDFLAGS="$($(package)_ldflags)" && \ + mkdir -p build && cd build && \ + cmake ../ $($(package)_config_opts) +endef + +define $(package)_build_cmds + cd build && \ + $(MAKE) $($(package)_build_opts) +endef + +define $(package)_stage_cmds + cd build && \ + $(MAKE) install +endef diff --git a/depends/packages/dbus.mk b/depends/packages/dbus.mk index ecac8a2cbd..90ddcb923f 100644 --- a/depends/packages/dbus.mk +++ b/depends/packages/dbus.mk @@ -1,8 +1,8 @@ package=dbus -$(package)_version=1.12.2 +$(package)_version=1.10.14 $(package)_download_path=http://dbus.freedesktop.org/releases/dbus $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=272bb5091770b047c8188b926d5e6038fa4fe6745488b2add96b23e2d9a83d88 +$(package)_sha256_hash=23238f70353e38ce5ca183ebc9525c0d97ac00ef640ad29cf794782af6e6a083 $(package)_dependencies=expat define $(package)_set_vars diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk index c041fd6c4d..84c6d0be15 100644 --- a/depends/packages/expat.mk +++ b/depends/packages/expat.mk @@ -1,11 +1,13 @@ package=expat -$(package)_version=2.2.5 -$(package)_download_path=https://downloads.sourceforge.net/project/expat/expat/$($(package)_version) +$(package)_version=2.2.7 +$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_2_7/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=d9dc32efba7e74f788fcc4f212a43216fc37cf5f23f4c2339664d473353aedf6 +$(package)_sha256_hash=cbc9102f4a31a8dafd42d642e9a3aa31e79a0aedaa1f6efd2795ebc83174ec18 define $(package)_set_vars -$(package)_config_opts=--disable-static + $(package)_config_opts=--disable-shared --without-docbook --without-tests --without-examples + $(package)_config_opts += --disable-dependency-tracking --enable-option-checking + $(package)_config_opts_linux=--with-pic endef define $(package)_config_cmds @@ -19,3 +21,7 @@ endef define $(package)_stage_cmds $(MAKE) DESTDIR=$($(package)_staging_dir) install endef + +define $(package)_postprocess_cmds + rm lib/*.la +endef \ No newline at end of file diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk index e53ac25e96..41e02e2030 100644 --- a/depends/packages/freetype.mk +++ b/depends/packages/freetype.mk @@ -1,11 +1,11 @@ package=freetype -$(package)_version=2.8.1 +$(package)_version=2.7.1 $(package)_download_path=http://download.savannah.gnu.org/releases/$(package) $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=e5435f02e02d2b87bb8e4efdcaa14b1f78c9cf3ab1ed80f94b6382fb6acc7d78 +$(package)_sha256_hash=3a3bb2c4e15ffb433f2032f50a5b5a92558206822e22bfe8cbe339af4aa82f88 define $(package)_set_vars - $(package)_config_opts=--without-zlib --without-png --disable-static + $(package)_config_opts=--without-zlib --without-png --without-harfbuzz --without-bzip2 --disable-static $(package)_config_opts_linux=--with-pic endef diff --git a/depends/packages/gmp.mk b/depends/packages/gmp.mk new file mode 100644 index 0000000000..ac685d7679 --- /dev/null +++ b/depends/packages/gmp.mk @@ -0,0 +1,23 @@ +package=gmp +$(package)_version=6.1.2 +$(package)_download_path=https://gmplib.org/download/gmp +$(package)_file_name=gmp-$($(package)_version).tar.bz2 +$(package)_sha256_hash=5275bb04f4863a13516b2f39392ac5e272f5e1bb8057b18aec1c9b79d73d8fb2 + +define $(package)_set_vars +$(package)_config_opts+=--enable-cxx --enable-fat --with-pic --disable-shared +$(package)_cflags_armv7l_linux+=-march=armv7-a +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + diff --git a/depends/packages/libX11.mk b/depends/packages/libX11.mk index abc1e8107f..178d592ee6 100644 --- a/depends/packages/libX11.mk +++ b/depends/packages/libX11.mk @@ -1,8 +1,8 @@ package=libX11 -$(package)_version=1.6.5 +$(package)_version=1.6.2 $(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=4d3890db2ba225ba8c55ca63c6409c1ebb078a2806de59fb16342768ae63435d +$(package)_sha256_hash=2aa027e837231d2eeea90f3a4afe19948a6eb4c8b2bec0241eba7dbc8106bd16 $(package)_dependencies=libxcb xtrans xextproto xproto define $(package)_set_vars diff --git a/depends/packages/libXext.mk b/depends/packages/libXext.mk index c2331c0f64..4db836066f 100644 --- a/depends/packages/libXext.mk +++ b/depends/packages/libXext.mk @@ -1,8 +1,8 @@ package=libXext -$(package)_version=1.3.3 +$(package)_version=1.3.2 $(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=b518d4d332231f313371fdefac59e3776f4f0823bcb23cf7c7305bfb57b16e35 +$(package)_sha256_hash=f829075bc646cdc085fa25d98d5885d83b1759ceb355933127c257e8e50432e0 $(package)_dependencies=xproto xextproto libX11 libXau define $(package)_set_vars diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index f6d17a7924..ed143830c5 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -1,8 +1,8 @@ package=libevent $(package)_version=2.1.8 -$(package)_download_path=https://github.com/libevent/libevent/archive/ -$(package)_file_name=release-$($(package)_version)-stable.tar.gz -$(package)_sha256_hash=316ddb401745ac5d222d7c529ef1eada12f58f6376a66c1118eee803cb70f83d +$(package)_download_path=https://github.com/libevent/libevent/releases/download/release-$($(package)_version)-stable +$(package)_file_name=$(package)-$($(package)_version)-stable.tar.gz +$(package)_sha256_hash=965cc5a8bb46ce4199a47e9b2c9e1cae3b137e8356ffdad6d94d3b9069b71dc2 define $(package)_preprocess_cmds ./autogen.sh diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk index e0f205b990..28f2bd6f25 100644 --- a/depends/packages/libxcb.mk +++ b/depends/packages/libxcb.mk @@ -1,8 +1,8 @@ package=libxcb -$(package)_version=1.12 +$(package)_version=1.10 $(package)_download_path=http://xcb.freedesktop.org/dist $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=4adfb1b7c67e99bc9c2ccb110b2f175686576d2f792c8a71b9c8b19014057b5b +$(package)_sha256_hash=98d9ab05b636dd088603b64229dd1ab2d2cc02ab807892e107d674f9c3f2d5b5 $(package)_dependencies=xcb_proto libXau xproto define $(package)_set_vars diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index fc4461f3e2..1bb8cb5d26 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,8 +1,8 @@ package=miniupnpc -$(package)_version=2.0.20171102 +$(package)_version=2.0.20170509 $(package)_download_path=http://miniupnp.free.fr/files $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=148517020581260c8a2fa532224870bc53e59004777affcaf27ef636a72825d4 +$(package)_sha256_hash=d3c368627f5cdfb66d3ebd64ca39ba54d6ff14a61966dbecb8dd296b7039f16a define $(package)_set_vars $(package)_build_opts=CC="$($(package)_cc)" diff --git a/depends/packages/native_biplist.mk b/depends/packages/native_biplist.mk index 3c6e8900f6..373490aedc 100644 --- a/depends/packages/native_biplist.mk +++ b/depends/packages/native_biplist.mk @@ -11,10 +11,10 @@ define $(package)_preprocess_cmds endef define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk index 966804ce8b..3be669dc47 100644 --- a/depends/packages/native_ccache.mk +++ b/depends/packages/native_ccache.mk @@ -1,8 +1,8 @@ package=native_ccache -$(package)_version=3.3.4 +$(package)_version=3.4.2 $(package)_download_path=https://samba.org/ftp/ccache $(package)_file_name=ccache-$($(package)_version).tar.bz2 -$(package)_sha256_hash=fa9d7f38367431bc86b19ad107d709ca7ecf1574fdacca01698bdf0a47cd8567 +$(package)_sha256_hash=3aa5587793d4c790bd22999bfc678250c029307b3afb9d16f6f4a49c67b78fb3 define $(package)_set_vars $(package)_config_opts= diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk index 44d238cc4c..4195230b40 100644 --- a/depends/packages/native_cctools.mk +++ b/depends/packages/native_cctools.mk @@ -1,45 +1,55 @@ package=native_cctools -$(package)_version=807d6fd1be5d2224872e381870c0a75387fe05e6 -$(package)_download_path=https://github.com/theuni/cctools-port/archive +$(package)_version=3764b223c011574971ee3ae09ce968ba5dc2f00f +$(package)_download_path=https://github.com/tpoechtrager/cctools-port/archive $(package)_file_name=$($(package)_version).tar.gz -$(package)_sha256_hash=a09c9ba4684670a0375e42d9d67e7f12c1f62581a27f28f7c825d6d7032ccc6a +$(package)_sha256_hash=3e35907bf376269a844df08e03cbb43e345c88125374f2228e03724b5f9a2a04 $(package)_build_subdir=cctools -$(package)_clang_version=3.7.1 -$(package)_clang_download_path=http://llvm.org/releases/$($(package)_clang_version) +$(package)_clang_version=6.0.1 +$(package)_clang_download_path=https://releases.llvm.org/$($(package)_clang_version) $(package)_clang_download_file=clang+llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz $(package)_clang_file_name=clang-llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz -$(package)_clang_sha256_hash=99b28a6b48e793705228a390471991386daa33a9717cd9ca007fcdde69608fd9 +$(package)_clang_sha256_hash=fa5416553ca94a8c071a27134c094a5fb736fe1bd0ecc5ef2d9bc02754e1bef0 + +$(package)_libtapi_version=3efb201881e7a76a21e0554906cf306432539cef +$(package)_libtapi_download_path=https://github.com/tpoechtrager/apple-libtapi/archive +$(package)_libtapi_download_file=$($(package)_libtapi_version).tar.gz +$(package)_libtapi_file_name=$($(package)_libtapi_version).tar.gz +$(package)_libtapi_sha256_hash=380c1ca37cfa04a8699d0887a8d3ee1ad27f3d08baba78887c73b09485c0fbd3 + $(package)_extra_sources=$($(package)_clang_file_name) +$(package)_extra_sources += $($(package)_libtapi_file_name) define $(package)_fetch_cmds $(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_clang_download_path),$($(package)_clang_download_file),$($(package)_clang_file_name),$($(package)_clang_sha256_hash)) +$(call fetch_file,$(package),$($(package)_clang_download_path),$($(package)_clang_download_file),$($(package)_clang_file_name),$($(package)_clang_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_libtapi_download_path),$($(package)_libtapi_download_file),$($(package)_libtapi_file_name),$($(package)_libtapi_sha256_hash)) endef define $(package)_extract_cmds mkdir -p $($(package)_extract_dir) && \ echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ echo "$($(package)_clang_sha256_hash) $($(package)_source_dir)/$($(package)_clang_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_libtapi_sha256_hash) $($(package)_source_dir)/$($(package)_libtapi_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ - mkdir -p toolchain/bin toolchain/lib/clang/3.5/include && \ - tar --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ + mkdir -p toolchain/bin toolchain/lib/clang/$($(package)_clang_version)/include && \ + mkdir -p libtapi && \ + tar --no-same-owner --strip-components=1 -C libtapi -xf $($(package)_source_dir)/$($(package)_libtapi_file_name) && \ + tar --no-same-owner --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ rm -f toolchain/lib/libc++abi.so* && \ - echo "#!/bin/sh" > toolchain/bin/$(host)-dsymutil && \ - echo "exit 0" >> toolchain/bin/$(host)-dsymutil && \ - chmod +x toolchain/bin/$(host)-dsymutil && \ - tar --strip-components=1 -xf $($(package)_source) + tar --no-same-owner --strip-components=1 -xf $($(package)_source) endef define $(package)_set_vars -$(package)_config_opts=--target=$(host) --disable-lto-support -$(package)_ldflags+=-Wl,-rpath=\\$$$$$$$$\$$$$$$$$ORIGIN/../lib -$(package)_cc=$($(package)_extract_dir)/toolchain/bin/clang -$(package)_cxx=$($(package)_extract_dir)/toolchain/bin/clang++ + $(package)_config_opts=--target=$(host) --disable-lto-support --with-libtapi=$($(package)_extract_dir) + $(package)_ldflags+=-Wl,-rpath=\\$$$$$$$$\$$$$$$$$ORIGIN/../lib + $(package)_cc=$($(package)_extract_dir)/toolchain/bin/clang + $(package)_cxx=$($(package)_extract_dir)/toolchain/bin/clang++ endef define $(package)_preprocess_cmds - cd $($(package)_build_subdir); ./autogen.sh && \ - sed -i.old "/define HAVE_PTHREADS/d" ld64/src/ld/InputFiles.h + CC=$($(package)_cc) CXX=$($(package)_cxx) INSTALLPREFIX=$($(package)_extract_dir) ./libtapi/build.sh && \ + CC=$($(package)_cc) CXX=$($(package)_cxx) INSTALLPREFIX=$($(package)_extract_dir) ./libtapi/install.sh && \ + sed -i.old "/define HAVE_PTHREADS/d" $($(package)_build_subdir)/ld64/src/ld/InputFiles.h endef define $(package)_config_cmds @@ -52,6 +62,9 @@ endef define $(package)_stage_cmds $(MAKE) DESTDIR=$($(package)_staging_dir) install && \ + mkdir -p $($(package)_staging_prefix_dir)/lib/ && \ + cd $($(package)_extract_dir) && \ + cp lib/libtapi.so.6 $($(package)_staging_prefix_dir)/lib/ && \ cd $($(package)_extract_dir)/toolchain && \ mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_clang_version)/include && \ mkdir -p $($(package)_staging_prefix_dir)/bin $($(package)_staging_prefix_dir)/include && \ diff --git a/depends/packages/native_ds_store.mk b/depends/packages/native_ds_store.mk index c25b836972..44108925a4 100644 --- a/depends/packages/native_ds_store.mk +++ b/depends/packages/native_ds_store.mk @@ -1,17 +1,15 @@ package=native_ds_store -$(package)_version=1.1.2 -$(package)_download_path=https://github.com/al45tair/ds_store/archive -$(package)_download_file=v$($(package)_version).tar.gz -$(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=3b3ecb7bf0a5157f5b6010bc3af7c141fb0ad3527084e63336220d22744bc20c -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages -$(package)_dependencies=native_biplist +$(package)_version=1.3.0 +$(package)_download_path=https://github.com/al45tair/ds_store/archive/ +$(package)_file_name=v$($(package)_version).tar.gz +$(package)_sha256_hash=76b3280cd4e19e5179defa23fb594a9dd32643b0c80d774bd3108361d94fb46d +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_mac_alias.mk b/depends/packages/native_mac_alias.mk index 665c13cff3..e60b99dccc 100644 --- a/depends/packages/native_mac_alias.mk +++ b/depends/packages/native_mac_alias.mk @@ -1,21 +1,15 @@ package=native_mac_alias -$(package)_version=2.0.1 -$(package)_download_path=https://bitbucket.org/al45tair/mac_alias/get -$(package)_download_file=v$($(package)_version).tar.bz2 -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=7285739414d8d6bc36b0b1a00c8ec8d6757e92971e8142cda51e4c3a5d76b413 -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages -$(package)_patches=python3.patch - -define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/python3.patch -endef +$(package)_version=2.0.7 +$(package)_download_path=https://github.com/al45tair/mac_alias/archive/ +$(package)_file_name=v$($(package)_version).tar.gz +$(package)_sha256_hash=6f606d3b6bccd2112aeabf1a063f5b5ece87005a5d7e97c8faca23b916e88838 +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_protobuf.mk b/depends/packages/native_protobuf.mk deleted file mode 100644 index c8f7da5745..0000000000 --- a/depends/packages/native_protobuf.mk +++ /dev/null @@ -1,25 +0,0 @@ -package=native_protobuf -$(package)_version=3.5.0 -$(package)_download_path=https://github.com/google/protobuf/releases/download/v$($(package)_version) -$(package)_file_name=protobuf-all-$($(package)_version).tar.gz -$(package)_sha256_hash=5c3e0b369e767993969fdebcb3f44cbddd7fdd86644a926780daab46341d10a7 - -define $(package)_set_vars -$(package)_config_opts=--disable-shared -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -C src protoc -endef - -define $(package)_stage_cmds - $(MAKE) -C src DESTDIR=$($(package)_staging_dir) install-strip -endef - -define $(package)_postprocess_cmds - rm -rf lib include -endef diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 5ee9f17a63..62e975e50d 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -1,64 +1,57 @@ package=openssl -$(package)_version=1.0.1k +$(package)_version=1.1.1i $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=8f9faeaebad088e772f4ef5e38252d472be4d878c6b3a2718c10a4fcebe7a41c +$(package)_sha256_hash=e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242 define $(package)_set_vars -$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" +$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" +$(package)_config_env_arm_android=ANDROID_NDK_HOME="$(host_prefix)/native" PATH="$(host_prefix)/native/bin" CC=clang AR=ar RANLIB=ranlib +$(package)_config_env_aarch64_android=ANDROID_NDK_HOME="$(host_prefix)/native" PATH="$(host_prefix)/native/bin" CC=clang AR=ar RANLIB=ranlib +$(package)_build_env_arm_android=ANDROID_NDK_HOME="$(host_prefix)/native" +$(package)_build_env_aarch64_android=ANDROID_NDK_HOME="$(host_prefix)/native" $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl -$(package)_config_opts+=no-camellia $(package)_config_opts+=no-capieng -$(package)_config_opts+=no-cast -$(package)_config_opts+=no-comp $(package)_config_opts+=no-dso $(package)_config_opts+=no-dtls1 $(package)_config_opts+=no-ec_nistp_64_gcc_128 $(package)_config_opts+=no-gost -$(package)_config_opts+=no-gmp $(package)_config_opts+=no-heartbeats -$(package)_config_opts+=no-idea -$(package)_config_opts+=no-jpake -$(package)_config_opts+=no-krb5 -$(package)_config_opts+=no-libunbound $(package)_config_opts+=no-md2 -$(package)_config_opts+=no-mdc2 -$(package)_config_opts+=no-rc4 $(package)_config_opts+=no-rc5 $(package)_config_opts+=no-rdrand $(package)_config_opts+=no-rfc3779 -$(package)_config_opts+=no-rsax $(package)_config_opts+=no-sctp -$(package)_config_opts+=no-seed -$(package)_config_opts+=no-sha0 $(package)_config_opts+=no-shared $(package)_config_opts+=no-ssl-trace $(package)_config_opts+=no-ssl2 $(package)_config_opts+=no-ssl3 -$(package)_config_opts+=no-static_engine -$(package)_config_opts+=no-store $(package)_config_opts+=no-unit-test $(package)_config_opts+=no-weak-ssl-ciphers -$(package)_config_opts+=no-whirlpool $(package)_config_opts+=no-zlib $(package)_config_opts+=no-zlib-dynamic $(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) $(package)_config_opts_linux=-fPIC -Wa,--noexecstack +$(package)_config_opts_freebsd=-fPIC -Wa,--noexecstack $(package)_config_opts_x86_64_linux=linux-x86_64 $(package)_config_opts_i686_linux=linux-generic32 $(package)_config_opts_arm_linux=linux-generic32 $(package)_config_opts_aarch64_linux=linux-generic64 +$(package)_config_opts_arm_android=--static android-arm +$(package)_config_opts_aarch64_android=--static android-arm64 +$(package)_config_opts_riscv64_linux=linux-generic64 $(package)_config_opts_mipsel_linux=linux-generic32 $(package)_config_opts_mips_linux=linux-generic32 $(package)_config_opts_powerpc_linux=linux-generic32 $(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc $(package)_config_opts_x86_64_mingw32=mingw64 $(package)_config_opts_i686_mingw32=mingw +$(package)_config_opts_x86_64_freebsd=BSD-x86_64 endef define $(package)_preprocess_cmds - sed -i.old "/define DATE/d" util/mkbuildinf.pl && \ - sed -i.old "s|engines apps test|engines|" Makefile.org + sed -i.old 's|"engines", "apps", "test", "util", "tools", "fuzz"|"engines", "tools"|' Configure && \ + sed -i -e 's|cflags --sysroot.*",|cflags",|' Configurations/15-android.conf endef define $(package)_config_cmds @@ -70,7 +63,7 @@ define $(package)_build_cmds endef define $(package)_stage_cmds - $(MAKE) INSTALL_PREFIX=$($(package)_staging_dir) -j1 install_sw + $(MAKE) DESTDIR=$($(package)_staging_dir) -j1 install_sw endef define $(package)_postprocess_cmds diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 145760238d..81eed141e3 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,14 +1,13 @@ -packages:=boost openssl libevent -native_packages := native_ccache +packages:=boost openssl libevent zeromq gmp chia_bls backtrace +native_packages := native_ccache -qt_native_packages = native_protobuf -qt_packages = qrencode protobuf zlib +qt_packages = qrencode zlib -qt_x86_64_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans +qt_x86_64_linux_packages:=qt5.7 expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans qt_i686_linux_packages:=$(qt_x86_64_linux_packages) -qt_darwin_packages=qt -qt_mingw32_packages=qt +qt_darwin_packages=qt5.9 +qt_mingw32_packages=qt5.9 wallet_packages=bdb diff --git a/depends/packages/protobuf.mk b/depends/packages/protobuf.mk deleted file mode 100644 index 54d3fd9245..0000000000 --- a/depends/packages/protobuf.mk +++ /dev/null @@ -1,29 +0,0 @@ -package=protobuf -$(package)_version=$(native_$(package)_version) -$(package)_download_path=$(native_$(package)_download_path) -$(package)_file_name=$(native_$(package)_file_name) -$(package)_sha256_hash=$(native_$(package)_sha256_hash) -$(package)_dependencies=native_$(package) -$(package)_cxxflags=-std=c++11 - -define $(package)_set_vars - $(package)_config_opts=--disable-shared --with-protoc=$(build_prefix)/bin/protoc - $(package)_config_opts_linux=--with-pic -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -C src libprotobuf.la -endef - -define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-libLTLIBRARIES install-nobase_includeHEADERS &&\ - $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA -endef - -define $(package)_postprocess_cmds - rm lib/libprotoc.a -endef diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk index 377febe28a..44fdf1c295 100644 --- a/depends/packages/qrencode.mk +++ b/depends/packages/qrencode.mk @@ -1,8 +1,8 @@ package=qrencode -$(package)_version=4.0.0 +$(package)_version=3.4.4 $(package)_download_path=https://fukuchi.org/works/qrencode/ -$(package)_file_name=qrencode-$(qrencode_version).tar.bz2 -$(package)_sha256_hash=c90035e16921117d4086a7fdee65aab85be32beb4a376f6b664b8a425d327d0b +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5 define $(package)_set_vars $(package)_config_opts=--disable-shared -without-tools --disable-sdltest diff --git a/depends/packages/qt.mk b/depends/packages/qt5.7.mk similarity index 97% rename from depends/packages/qt.mk rename to depends/packages/qt5.7.mk index f0f930616f..10fa7843e0 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt5.7.mk @@ -1,14 +1,14 @@ -PACKAGE=qt +PACKAGE=qt5.7 $(package)_version=5.7.1 -$(package)_download_path=http://download.qt.io/official_releases/qt/5.7/$($(package)_version)/submodules +$(package)_download_path=http://download.qt.io/new_archive/qt/5.7/$($(package)_version)/submodules $(package)_suffix=opensource-src-$($(package)_version).tar.gz $(package)_file_name=qtbase-$($(package)_suffix) $(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410 -$(package)_dependencies=openssl zlib +$(package)_dependencies=zlib $(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib -$(package)_patches=mac-qmake.conf mingw-uuidof.patch pidlist_absolute.patch fix-xcb-include-order.patch fix_qt_pkgconfig.patch +$(package)_patches=mac-qmake.conf mingw-uuidof.patch pidlist_absolute.patch fix-xcb-include-order.patch fix_qt_pkgconfig.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=3a15aebd523c6d89fb97b2d3df866c94149653a26d27a00aac9b6d3020bc5a1d @@ -46,10 +46,12 @@ $(package)_config_opts += -no-linuxfb $(package)_config_opts += -no-libudev $(package)_config_opts += -no-mitshm $(package)_config_opts += -no-mtdev +$(package)_config_opts += -no-openssl $(package)_config_opts += -no-pulseaudio $(package)_config_opts += -no-openvg $(package)_config_opts += -no-reduce-relocations $(package)_config_opts += -no-qml-debug +$(package)_config_opts += -no-securetransport $(package)_config_opts += -no-sql-db2 $(package)_config_opts += -no-sql-ibase $(package)_config_opts += -no-sql-oci @@ -65,7 +67,6 @@ $(package)_config_opts += -no-xrender $(package)_config_opts += -nomake examples $(package)_config_opts += -nomake tests $(package)_config_opts += -opensource -$(package)_config_opts += -openssl-linked $(package)_config_opts += -optimized-qmake $(package)_config_opts += -pch $(package)_config_opts += -pkg-config diff --git a/depends/packages/qt5.9.mk b/depends/packages/qt5.9.mk new file mode 100644 index 0000000000..f92e448f31 --- /dev/null +++ b/depends/packages/qt5.9.mk @@ -0,0 +1,283 @@ +PACKAGE=qt5.9 +$(package)_version=5.9.8 +$(package)_download_path=https://download.qt.io/archive/qt/5.9/$($(package)_version)/submodules +$(package)_suffix=opensource-src-$($(package)_version).tar.xz +$(package)_file_name=qtbase-$($(package)_suffix) +$(package)_sha256_hash=9b9dec1f67df1f94bce2955c5604de992d529dde72050239154c56352da0907d +$(package)_dependencies=zlib +$(package)_linux_dependencies=freetype fontconfig libxcb +$(package)_build_subdir=qtbase +$(package)_qt_libs=corelib network widgets gui plugins testlib +$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch +$(package)_patches+= fix_rcc_determinism.patch fix_riscv64_arch.patch xkb-default.patch no-xlib.patch +$(package)_patches+= fix_android_qmake_conf.patch fix_android_jni_static.patch dont_hardcode_pwd.patch +$(package)_patches+= freetype_back_compat.patch drop_lrelease_dependency.patch fix_powerpc_libpng.patch +$(package)_patches+= fix_mingw_cross_compile.patch + +# Update OSX_QT_TRANSLATIONS when this is updated +$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) +$(package)_qttranslations_sha256_hash=fb5a47799754af73d3bf501fe513342cfe2fc37f64e80df5533f6110e804220c + +$(package)_qttools_file_name=qttools-$($(package)_suffix) +$(package)_qttools_sha256_hash=a97556eb7b2f30252cdd8a598c396cfce2b2f79d2bae883af6d3b26a2cdcc63c + +$(package)_extra_sources = $($(package)_qttranslations_file_name) +$(package)_extra_sources += $($(package)_qttools_file_name) + +define $(package)_set_vars +$(package)_config_opts_release = -release +$(package)_config_opts_release += -silent +$(package)_config_opts_debug = -debug +$(package)_config_opts += -bindir $(build_prefix)/bin +$(package)_config_opts += -c++std c++11 +$(package)_config_opts += -confirm-license +$(package)_config_opts += -hostprefix $(build_prefix) +$(package)_config_opts += -no-compile-examples +$(package)_config_opts += -no-cups +$(package)_config_opts += -no-egl +$(package)_config_opts += -no-eglfs +$(package)_config_opts += -no-freetype +$(package)_config_opts += -no-gif +$(package)_config_opts += -no-glib +$(package)_config_opts += -no-icu +$(package)_config_opts += -no-ico +$(package)_config_opts += -no-iconv +$(package)_config_opts += -no-kms +$(package)_config_opts += -no-linuxfb +$(package)_config_opts += -no-libjpeg +$(package)_config_opts += -no-libproxy +$(package)_config_opts += -no-libudev +$(package)_config_opts += -no-mtdev +$(package)_config_opts += -no-openssl +$(package)_config_opts += -no-openvg +$(package)_config_opts += -no-reduce-relocations +$(package)_config_opts += -no-qml-debug +$(package)_config_opts += -no-sctp +$(package)_config_opts += -no-securetransport +$(package)_config_opts += -no-sql-db2 +$(package)_config_opts += -no-sql-ibase +$(package)_config_opts += -no-sql-oci +$(package)_config_opts += -no-sql-tds +$(package)_config_opts += -no-sql-mysql +$(package)_config_opts += -no-sql-odbc +$(package)_config_opts += -no-sql-psql +$(package)_config_opts += -no-sql-sqlite +$(package)_config_opts += -no-sql-sqlite2 +$(package)_config_opts += -no-system-proxies +$(package)_config_opts += -no-use-gold-linker +$(package)_config_opts += -no-xinput2 +$(package)_config_opts += -nomake examples +$(package)_config_opts += -nomake tests +$(package)_config_opts += -opensource +$(package)_config_opts += -optimized-tools +$(package)_config_opts += -pch +$(package)_config_opts += -pkg-config +$(package)_config_opts += -prefix $(host_prefix) +$(package)_config_opts += -qt-libpng +$(package)_config_opts += -qt-pcre +$(package)_config_opts += -qt-harfbuzz +$(package)_config_opts += -system-zlib +$(package)_config_opts += -static +$(package)_config_opts += -v +$(package)_config_opts += -no-feature-bearermanagement +$(package)_config_opts += -no-feature-colordialog +$(package)_config_opts += -no-feature-commandlineparser +$(package)_config_opts += -no-feature-concurrent +$(package)_config_opts += -no-feature-dial +$(package)_config_opts += -no-feature-fontcombobox +$(package)_config_opts += -no-feature-ftp +$(package)_config_opts += -no-feature-http +$(package)_config_opts += -no-feature-image_heuristic_mask +$(package)_config_opts += -no-feature-keysequenceedit +$(package)_config_opts += -no-feature-lcdnumber +$(package)_config_opts += -no-feature-networkdiskcache +$(package)_config_opts += -no-feature-pdf +$(package)_config_opts += -no-feature-printdialog +$(package)_config_opts += -no-feature-printer +$(package)_config_opts += -no-feature-printpreviewdialog +$(package)_config_opts += -no-feature-printpreviewwidget +$(package)_config_opts += -no-feature-regularexpression +$(package)_config_opts += -no-feature-sessionmanager +$(package)_config_opts += -no-feature-socks5 +$(package)_config_opts += -no-feature-sql +$(package)_config_opts += -no-feature-statemachine +$(package)_config_opts += -no-feature-syntaxhighlighter +$(package)_config_opts += -no-feature-textodfwriter +$(package)_config_opts += -no-feature-topleveldomain +$(package)_config_opts += -no-feature-udpsocket +$(package)_config_opts += -no-feature-undocommand +$(package)_config_opts += -no-feature-undogroup +$(package)_config_opts += -no-feature-undostack +$(package)_config_opts += -no-feature-undoview +$(package)_config_opts += -no-feature-vnc +$(package)_config_opts += -no-feature-wizard +$(package)_config_opts += -no-feature-xml + +$(package)_config_opts_darwin = -no-dbus +$(package)_config_opts_darwin += -no-opengl + +ifneq ($(build_os),darwin) +$(package)_config_opts_darwin += -xplatform macx-clang-linux +$(package)_config_opts_darwin += -device-option MAC_SDK_PATH=$(OSX_SDK) +$(package)_config_opts_darwin += -device-option MAC_SDK_VERSION=$(OSX_SDK_VERSION) +$(package)_config_opts_darwin += -device-option CROSS_COMPILE="$(host)-" +$(package)_config_opts_darwin += -device-option MAC_MIN_VERSION=$(OSX_MIN_VERSION) +$(package)_config_opts_darwin += -device-option MAC_TARGET=$(host) +$(package)_config_opts_darwin += -device-option XCODE_VERSION=$(XCODE_VERSION) +endif + +$(package)_config_opts_linux = -qt-xkbcommon-x11 +$(package)_config_opts_linux += -qt-xcb +$(package)_config_opts_linux += -no-xcb-xlib +$(package)_config_opts_linux += -no-feature-xlib +$(package)_config_opts_linux += -system-freetype +$(package)_config_opts_linux += -fontconfig +$(package)_config_opts_linux += -no-opengl +$(package)_config_opts_linux += -dbus-runtime +$(package)_config_opts_arm_linux += -platform linux-g++ -xplatform bitcoin-linux-g++ +$(package)_config_opts_i686_linux = -xplatform linux-g++-32 +$(package)_config_opts_x86_64_linux = -xplatform linux-g++-64 +$(package)_config_opts_aarch64_linux = -xplatform linux-aarch64-gnu-g++ +$(package)_config_opts_powerpc64_linux = -platform linux-g++ -xplatform bitcoin-linux-g++ +$(package)_config_opts_powerpc64le_linux = -platform linux-g++ -xplatform bitcoin-linux-g++ +$(package)_config_opts_riscv64_linux = -platform linux-g++ -xplatform bitcoin-linux-g++ +$(package)_config_opts_s390x_linux = -platform linux-g++ -xplatform bitcoin-linux-g++ + +$(package)_config_opts_mingw32 = -no-opengl +$(package)_config_opts_mingw32 += -no-dbus +$(package)_config_opts_mingw32 += -xplatform win32-g++ +$(package)_config_opts_mingw32 += -device-option CROSS_COMPILE="$(host)-" + +$(package)_config_opts_android = -xplatform android-clang +$(package)_config_opts_android += -android-sdk $(ANDROID_SDK) +$(package)_config_opts_android += -android-ndk $(ANDROID_NDK) +$(package)_config_opts_android += -android-ndk-platform android-$(ANDROID_API_LEVEL) +$(package)_config_opts_android += -device-option CROSS_COMPILE="$(host)-" +$(package)_config_opts_android += -egl +$(package)_config_opts_android += -qpa xcb +$(package)_config_opts_android += -no-eglfs +$(package)_config_opts_android += -no-dbus +$(package)_config_opts_android += -opengl es2 +$(package)_config_opts_android += -qt-freetype +$(package)_config_opts_android += -no-fontconfig +$(package)_config_opts_android += -L $(host_prefix)/lib +$(package)_config_opts_android += -I $(host_prefix)/include + +$(package)_config_opts_aarch64_android += -android-arch arm64-v8a +$(package)_config_opts_armv7a_android += -android-arch armeabi-v7a +$(package)_config_opts_x86_64_android += -android-arch x86_64 +$(package)_config_opts_i686_android += -android-arch i686 + +$(package)_build_env = QT_RCC_TEST=1 +$(package)_build_env += QT_RCC_SOURCE_DATE_OVERRIDE=1 +endef + +define $(package)_fetch_cmds +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qttranslations_file_name),$($(package)_qttranslations_file_name),$($(package)_qttranslations_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qttools_file_name),$($(package)_qttools_file_name),$($(package)_qttools_sha256_hash)) +endef + +define $(package)_extract_cmds + mkdir -p $($(package)_extract_dir) && \ + echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qttranslations_sha256_hash) $($(package)_source_dir)/$($(package)_qttranslations_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + mkdir qtbase && \ + tar --no-same-owner --strip-components=1 -xf $($(package)_source) -C qtbase && \ + mkdir qttranslations && \ + tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ + mkdir qttools && \ + tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools +endef + +# Preprocessing steps work as follows: +# +# 1. Apply our patches to the extracted source. See each patch for more info. +# +# 2. Point to lrelease in qttools/bin/lrelease; otherwise Qt will look for it in +# $(host)/native/bin/lrelease and not find it. +# +# 3. Create a macOS-Clang-Linux mkspec using our mac-qmake.conf. +# +# 4. After making a copy of the mkspec for the linux-arm-gnueabi host, named +# bitcoin-linux-g++, replace instances of linux-arm-gnueabi with $(host). This +# way we can generically support hosts like riscv64-linux-gnu, which Qt doesn't +# ship a mkspec for. See it's usage in config_opts_* above. +# +# 5. Put our C, CXX and LD FLAGS into gcc-base.conf. Only used for non-host builds. +# +# 6. Do similar for the win32-g++ mkspec. +# +# 7. In clang.conf, swap out clang & clang++, for our compiler + flags. See #17466. +# +# 8. Adjust a regex in toolchain.prf, to accomodate Guix's usage of +# CROSS_LIBRARY_PATH. See #15277. +define $(package)_preprocess_cmds + patch -p1 -i $($(package)_patch_dir)/freetype_back_compat.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_powerpc_libpng.patch && \ + patch -p1 -i $($(package)_patch_dir)/drop_lrelease_dependency.patch && \ + patch -p1 -i $($(package)_patch_dir)/dont_hardcode_pwd.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_configure_mac.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_rcc_determinism.patch && \ + patch -p1 -i $($(package)_patch_dir)/xkb-default.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_android_qmake_conf.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_android_jni_static.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_riscv64_arch.patch && \ + patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_mingw_cross_compile.patch && \ + sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ + mkdir -p qtbase/mkspecs/macx-clang-linux &&\ + cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ + cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/bitcoin-linux-g++ && \ + sed -i.old "s/arm-linux-gnueabi-/$(host)-/g" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ + echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + sed -i.old "s|QMAKE_CFLAGS += |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "s|QMAKE_CXXFLAGS += |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "0,/^QMAKE_LFLAGS_/s|^QMAKE_LFLAGS_|!host_build: QMAKE_LFLAGS = $($(package)_ldflags)\n&|" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "s|QMAKE_CC = clang|QMAKE_CC = $($(package)_cc)|" qtbase/mkspecs/common/clang.conf && \ + sed -i.old "s|QMAKE_CXX = clang++|QMAKE_CXX = $($(package)_cxx)|" qtbase/mkspecs/common/clang.conf && \ + sed -i.old "s/LIBRARY_PATH/(CROSS_)?\0/g" qtbase/mkspecs/features/toolchain.prf +endef + +define $(package)_config_cmds + export PKG_CONFIG_SYSROOT_DIR=/ && \ + export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \ + export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \ + ./configure $($(package)_config_opts) && \ + echo "host_build: QT_CONFIG ~= s/system-zlib/zlib" >> mkspecs/qconfig.pri && \ + echo "CONFIG += force_bootstrap" >> mkspecs/qconfig.pri && \ + $(MAKE) sub-src-clean && \ + cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \ + cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. && \ + cd qttools/src/linguist/lrelease/ && ../../../../qtbase/bin/qmake lrelease.pro -o Makefile && \ + cd ../lupdate/ && ../../../../qtbase/bin/qmake lupdate.pro -o Makefile && cd ../../../.. +endef + +define $(package)_build_cmds + $(MAKE) -C src $(addprefix sub-,$($(package)_qt_libs)) && \ + $(MAKE) -C ../qttools/src/linguist/lrelease && \ + $(MAKE) -C ../qttools/src/linguist/lupdate && \ + $(MAKE) -C ../qttranslations +endef + +define $(package)_stage_cmds + $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && cd .. && \ + $(MAKE) -C qttools/src/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install_target && \ + $(MAKE) -C qttools/src/linguist/lupdate INSTALL_ROOT=$($(package)_staging_dir) install_target && \ + $(MAKE) -C qttranslations INSTALL_ROOT=$($(package)_staging_dir) install_subtargets && \ + if `test -f qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a`; then \ + cp qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a $($(package)_staging_prefix_dir)/lib; \ + fi +endef + +define $(package)_postprocess_cmds + rm -rf native/mkspecs/ native/lib/ lib/cmake/ && \ + rm -f lib/lib*.la lib/*.prl plugins/*/*.prl +endef diff --git a/depends/packages/xcb_proto.mk b/depends/packages/xcb_proto.mk index 55c6e08462..0c7c958d62 100644 --- a/depends/packages/xcb_proto.mk +++ b/depends/packages/xcb_proto.mk @@ -1,8 +1,8 @@ package=xcb_proto -$(package)_version=1.12 +$(package)_version=1.10 $(package)_download_path=http://xcb.freedesktop.org/dist $(package)_file_name=xcb-proto-$($(package)_version).tar.bz2 -$(package)_sha256_hash=5922aba4c664ab7899a29d92ea91a87aa4c1fc7eb5ee550325c3216c480a4906 +$(package)_sha256_hash=7ef40ddd855b750bc597d2a435da21e55e502a0fefa85b274f2c922800baaf05 define $(package)_set_vars $(package)_config_opts=--disable-shared diff --git a/depends/packages/xproto.mk b/depends/packages/xproto.mk index c148017660..50a90b2685 100644 --- a/depends/packages/xproto.mk +++ b/depends/packages/xproto.mk @@ -1,8 +1,8 @@ package=xproto -$(package)_version=7.0.31 +$(package)_version=7.0.26 $(package)_download_path=http://xorg.freedesktop.org/releases/individual/proto $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=c6f9747da0bd3a95f86b17fb8dd5e717c8f3ab7f0ece3ba1b247899ec1ef7747 +$(package)_sha256_hash=636162c1759805a5a0114a369dffdeccb8af8c859ef6e1445f26a4e6e046514f define $(package)_set_vars $(package)_config_opts=--disable-shared diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 01146c26f6..c9068e83a5 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -1,20 +1,20 @@ package=zeromq -$(package)_version=4.1.5 -$(package)_download_path=https://github.com/zeromq/zeromq4-1/releases/download/v$($(package)_version)/ +$(package)_version=4.2.5 +$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=04aac57f081ffa3a2ee5ed04887be9e205df3a7ddade0027460b8042432bdbcf -$(package)_patches=9114d3957725acd34aa8b8d011585812f3369411.patch 9e6745c12e0b100cd38acecc16ce7db02905e27c.patch +$(package)_sha256_hash=cc9090ba35713d59bb2f7d7965f877036c49c5558ea0c290b0dcc6f2a17e489f +$(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch define $(package)_set_vars - $(package)_config_opts=--without-documentation --disable-shared --without-libsodium --disable-curve + $(package)_config_opts=--without-docs --disable-shared --without-libsodium --disable-curve --disable-curve-keygen --disable-perf --disable-Werror $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 endef define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/9114d3957725acd34aa8b8d011585812f3369411.patch && \ - patch -p1 < $($(package)_patch_dir)/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch && \ - ./autogen.sh + patch -p1 < $($(package)_patch_dir)/0001-fix-build-with-older-mingw64.patch && \ + patch -p1 < $($(package)_patch_dir)/0002-disable-pthread_set_name_np.patch && \ + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config endef define $(package)_config_cmds @@ -22,7 +22,7 @@ define $(package)_config_cmds endef define $(package)_build_cmds - $(MAKE) libzmq.la + $(MAKE) src/libzmq.la endef define $(package)_stage_cmds @@ -30,5 +30,6 @@ define $(package)_stage_cmds endef define $(package)_postprocess_cmds + sed -i.old "s/ -lstdc++//" lib/pkgconfig/libzmq.pc && \ rm -rf bin share endef diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk index 7ff5d00bbd..589490800f 100644 --- a/depends/packages/zlib.mk +++ b/depends/packages/zlib.mk @@ -7,8 +7,10 @@ $(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca11 define $(package)_set_vars $(package)_build_opts= CC="$($(package)_cc)" $(package)_build_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC" -$(package)_build_opts+=AR="$($(package)_ar)" $(package)_build_opts+=RANLIB="$($(package)_ranlib)" +$(package)_build_opts+=AR="$($(package)_ar)" +$(package)_build_opts_darwin+=AR="$($(package)_libtool)" +$(package)_build_opts_darwin+=ARFLAGS="-o" endef define $(package)_config_cmds diff --git a/depends/patches/qt/fix-xcb-include-order.patch b/depends/patches/qt5.7/fix-xcb-include-order.patch similarity index 100% rename from depends/patches/qt/fix-xcb-include-order.patch rename to depends/patches/qt5.7/fix-xcb-include-order.patch diff --git a/depends/patches/qt5.7/fix_configure_mac.patch b/depends/patches/qt5.7/fix_configure_mac.patch new file mode 100644 index 0000000000..0d7dd647de --- /dev/null +++ b/depends/patches/qt5.7/fix_configure_mac.patch @@ -0,0 +1,50 @@ +--- old/qtbase/mkspecs/features/mac/sdk.prf 2018-02-08 10:24:48.000000000 -0800 ++++ new/qtbase/mkspecs/features/mac/sdk.prf 2018-03-23 10:38:56.000000000 -0700 +@@ -8,21 +8,21 @@ + defineReplace(xcodeSDKInfo) { + info = $$1 + equals(info, "Path"): \ +- info = --show-sdk-path ++ infoarg = --show-sdk-path + equals(info, "PlatformPath"): \ +- info = --show-sdk-platform-path ++ infoarg = --show-sdk-platform-path + equals(info, "SDKVersion"): \ +- info = --show-sdk-version ++ infoarg = --show-sdk-version + sdk = $$2 + isEmpty(sdk): \ + sdk = $$QMAKE_MAC_SDK + + isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}) { +- QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$info 2>/dev/null") ++ QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$infoarg 2>/dev/null") + # --show-sdk-platform-path won't work for Command Line Tools; this is fine + # only used by the XCTest backend to testlib +- isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(info, "--show-sdk-platform-path")): \ +- error("Could not resolve SDK $$info for \'$$sdk\'") ++ isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(infoarg, "--show-sdk-platform-path")): \ ++ error("Could not resolve SDK $$info for \'$$sdk\' using $$infoarg") + cache(QMAKE_MAC_SDK.$${sdk}.$${info}, set stash, QMAKE_MAC_SDK.$${sdk}.$${info}) + } + +--- old/qtbase/configure 2018-02-08 10:24:48.000000000 -0800 ++++ new/qtbase/configure 2018-03-23 05:42:29.000000000 -0700 +@@ -232,8 +232,13 @@ + + sdk=$(getSingleQMakeVariable "QMAKE_MAC_SDK" "$1") + if [ -z "$sdk" ]; then echo "QMAKE_MAC_SDK must be set when building on Mac" >&2; exit 1; fi +- sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null) +- if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi ++ sysroot=$(getSingleQMakeVariable "QMAKE_MAC_SDK_PATH" "$1") ++ ++ echo "sysroot pre-configured as $sysroot"; ++ if [ -z "$sysroot" ]; then ++ sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null) ++ if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi ++ fi + + case "$sdk" in + macosx*) + + diff --git a/depends/patches/qt5.7/fix_no_printer.patch b/depends/patches/qt5.7/fix_no_printer.patch new file mode 100644 index 0000000000..f868ca2577 --- /dev/null +++ b/depends/patches/qt5.7/fix_no_printer.patch @@ -0,0 +1,19 @@ +--- x/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h ++++ y/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h +@@ -52,6 +52,7 @@ + // + + #include ++#include + + #ifndef QT_NO_PRINTER + +--- x/qtbase/src/plugins/plugins.pro ++++ y/qtbase/src/plugins/plugins.pro +@@ -8,6 +8,3 @@ qtHaveModule(gui) { + qtConfig(imageformatplugin): SUBDIRS *= imageformats + !android:qtConfig(library): SUBDIRS *= generic + } +- +-!winrt:qtHaveModule(printsupport): \ +- SUBDIRS += printsupport diff --git a/depends/patches/qt/fix_qt_pkgconfig.patch b/depends/patches/qt5.7/fix_qt_pkgconfig.patch similarity index 100% rename from depends/patches/qt/fix_qt_pkgconfig.patch rename to depends/patches/qt5.7/fix_qt_pkgconfig.patch diff --git a/depends/patches/qt/mac-qmake.conf b/depends/patches/qt5.7/mac-qmake.conf similarity index 91% rename from depends/patches/qt/mac-qmake.conf rename to depends/patches/qt5.7/mac-qmake.conf index ca70d30b15..4cd96df29f 100644 --- a/depends/patches/qt/mac-qmake.conf +++ b/depends/patches/qt5.7/mac-qmake.conf @@ -14,10 +14,11 @@ QMAKE_MAC_SDK.macosx.Path = $${MAC_SDK_PATH} QMAKE_MAC_SDK.macosx.platform_name = macosx QMAKE_MAC_SDK.macosx.SDKVersion = $${MAC_SDK_VERSION} QMAKE_MAC_SDK.macosx.PlatformPath = /phony +QMAKE_APPLE_DEVICE_ARCHS=x86_64 !host_build: QMAKE_CFLAGS += -target $${MAC_TARGET} !host_build: QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_CFLAGS !host_build: QMAKE_CXXFLAGS += $$QMAKE_CFLAGS -!host_build: QMAKE_LFLAGS += -target $${MAC_TARGET} -mlinker-version=$${MAC_LD64_VERSION} +!host_build: QMAKE_LFLAGS += -target $${MAC_TARGET} QMAKE_AR = $${CROSS_COMPILE}ar cq QMAKE_RANLIB=$${CROSS_COMPILE}ranlib QMAKE_LIBTOOL=$${CROSS_COMPILE}libtool diff --git a/depends/patches/qt/mingw-uuidof.patch b/depends/patches/qt5.7/mingw-uuidof.patch similarity index 100% rename from depends/patches/qt/mingw-uuidof.patch rename to depends/patches/qt5.7/mingw-uuidof.patch diff --git a/depends/patches/qt/pidlist_absolute.patch b/depends/patches/qt5.7/pidlist_absolute.patch similarity index 100% rename from depends/patches/qt/pidlist_absolute.patch rename to depends/patches/qt5.7/pidlist_absolute.patch diff --git a/depends/patches/qt5.9/dont_hardcode_pwd.patch b/depends/patches/qt5.9/dont_hardcode_pwd.patch new file mode 100644 index 0000000000..a74e9cb098 --- /dev/null +++ b/depends/patches/qt5.9/dont_hardcode_pwd.patch @@ -0,0 +1,27 @@ +commit 0e953866fc4672486e29e1ba6d83b4207e7b2f0b +Author: fanquake +Date: Tue Aug 18 15:09:06 2020 +0800 + + Don't hardcode pwd path + + Let a man use his builtins if he wants to! Also, removes the unnecessary + assumption that pwd lives under /bin/pwd. + + See #15581. + +diff --git a/qtbase/configure b/qtbase/configure +index 08b49a8d..faea5b55 100755 +--- a/qtbase/configure ++++ b/qtbase/configure +@@ -36,9 +36,9 @@ + relconf=`basename $0` + # the directory of this script is the "source tree" + relpath=`dirname $0` +-relpath=`(cd "$relpath"; /bin/pwd)` ++relpath=`(cd "$relpath"; pwd)` + # the current directory is the "build tree" or "object tree" +-outpath=`/bin/pwd` ++outpath=`pwd` + + WHICH="which" + diff --git a/depends/patches/qt5.9/drop_lrelease_dependency.patch b/depends/patches/qt5.9/drop_lrelease_dependency.patch new file mode 100644 index 0000000000..f6b2c9fc80 --- /dev/null +++ b/depends/patches/qt5.9/drop_lrelease_dependency.patch @@ -0,0 +1,20 @@ +commit 67b3ed7406e1d0762188dbad2c44a06824ba0778 +Author: fanquake +Date: Tue Aug 18 15:24:01 2020 +0800 + + Drop dependency on lrelease + + Qts buildsystem insists on using the installed lrelease, but gets + confused about how to find it. Since we manually control the build + order, just drop the dependency. + + See #9469 + +diff --git a/qttranslations/translations/translations.pro b/qttranslations/translations/translations.pro +index 694544c..eff339d 100644 +--- a/qttranslations/translations/translations.pro ++++ b/qttranslations/translations/translations.pro +@@ -109,3 +109,2 @@ updateqm.commands = $$LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT} + silent:updateqm.commands = @echo lrelease ${QMAKE_FILE_IN} && $$updateqm.commands +-updateqm.depends = $$LRELEASE_EXE + updateqm.name = LRELEASE ${QMAKE_FILE_IN} diff --git a/depends/patches/qt5.9/fix_android_jni_static.patch b/depends/patches/qt5.9/fix_android_jni_static.patch new file mode 100644 index 0000000000..2f6ff00f40 --- /dev/null +++ b/depends/patches/qt5.9/fix_android_jni_static.patch @@ -0,0 +1,18 @@ +--- old/qtbase/src/plugins/platforms/android/androidjnimain.cpp ++++ new/qtbase/src/plugins/platforms/android/androidjnimain.cpp +@@ -890,6 +890,14 @@ + __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); + return -1; + } ++ ++ const jint ret = QT_PREPEND_NAMESPACE(QtAndroidPrivate::initJNI(vm, env)); ++ if (ret != 0) ++ { ++ __android_log_print(ANDROID_LOG_FATAL, "Qt", "initJNI failed"); ++ return ret; ++ } ++ + QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); + + m_javaVM = vm; + diff --git a/depends/patches/qt5.9/fix_android_qmake_conf.patch b/depends/patches/qt5.9/fix_android_qmake_conf.patch new file mode 100644 index 0000000000..13bfff9776 --- /dev/null +++ b/depends/patches/qt5.9/fix_android_qmake_conf.patch @@ -0,0 +1,20 @@ +--- old/qtbase/mkspecs/android-clang/qmake.conf ++++ new/qtbase/mkspecs/android-clang/qmake.conf +@@ -30,7 +30,7 @@ + QMAKE_CFLAGS += -target mips64el-none-linux-android + + QMAKE_CFLAGS += -gcc-toolchain $$NDK_TOOLCHAIN_PATH +-QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -Wl,--exclude-libs,libgcc.a ++QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -Wl,--exclude-libs,libgcc.a -nostdlib++ + QMAKE_CFLAGS += -DANDROID_HAS_WSTRING --sysroot=$$NDK_ROOT/sysroot \ + -isystem $$NDK_ROOT/sysroot/usr/include/$$NDK_TOOLS_PREFIX \ + -isystem $$NDK_ROOT/sources/cxx-stl/llvm-libc++/include \ +@@ -40,7 +40,7 @@ + ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$ANDROID_TARGET_ARCH + + ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so +-ANDROID_CXX_STL_LIBS = -lc++ ++ANDROID_CXX_STL_LIBS = -lc++_shared + + QMAKE_ARM_CFLAGS_RELEASE = -Oz + QMAKE_ARM_CFLAGS_RELEASE_WITH_DEBUGINFO = -g -Oz diff --git a/depends/patches/qt5.9/fix_configure_mac.patch b/depends/patches/qt5.9/fix_configure_mac.patch new file mode 100644 index 0000000000..0d7dd647de --- /dev/null +++ b/depends/patches/qt5.9/fix_configure_mac.patch @@ -0,0 +1,50 @@ +--- old/qtbase/mkspecs/features/mac/sdk.prf 2018-02-08 10:24:48.000000000 -0800 ++++ new/qtbase/mkspecs/features/mac/sdk.prf 2018-03-23 10:38:56.000000000 -0700 +@@ -8,21 +8,21 @@ + defineReplace(xcodeSDKInfo) { + info = $$1 + equals(info, "Path"): \ +- info = --show-sdk-path ++ infoarg = --show-sdk-path + equals(info, "PlatformPath"): \ +- info = --show-sdk-platform-path ++ infoarg = --show-sdk-platform-path + equals(info, "SDKVersion"): \ +- info = --show-sdk-version ++ infoarg = --show-sdk-version + sdk = $$2 + isEmpty(sdk): \ + sdk = $$QMAKE_MAC_SDK + + isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}) { +- QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$info 2>/dev/null") ++ QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$infoarg 2>/dev/null") + # --show-sdk-platform-path won't work for Command Line Tools; this is fine + # only used by the XCTest backend to testlib +- isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(info, "--show-sdk-platform-path")): \ +- error("Could not resolve SDK $$info for \'$$sdk\'") ++ isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(infoarg, "--show-sdk-platform-path")): \ ++ error("Could not resolve SDK $$info for \'$$sdk\' using $$infoarg") + cache(QMAKE_MAC_SDK.$${sdk}.$${info}, set stash, QMAKE_MAC_SDK.$${sdk}.$${info}) + } + +--- old/qtbase/configure 2018-02-08 10:24:48.000000000 -0800 ++++ new/qtbase/configure 2018-03-23 05:42:29.000000000 -0700 +@@ -232,8 +232,13 @@ + + sdk=$(getSingleQMakeVariable "QMAKE_MAC_SDK" "$1") + if [ -z "$sdk" ]; then echo "QMAKE_MAC_SDK must be set when building on Mac" >&2; exit 1; fi +- sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null) +- if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi ++ sysroot=$(getSingleQMakeVariable "QMAKE_MAC_SDK_PATH" "$1") ++ ++ echo "sysroot pre-configured as $sysroot"; ++ if [ -z "$sysroot" ]; then ++ sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null) ++ if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi ++ fi + + case "$sdk" in + macosx*) + + diff --git a/depends/patches/qt5.9/fix_mingw_cross_compile.patch b/depends/patches/qt5.9/fix_mingw_cross_compile.patch new file mode 100644 index 0000000000..67f76f1d85 --- /dev/null +++ b/depends/patches/qt5.9/fix_mingw_cross_compile.patch @@ -0,0 +1,25 @@ +commit 5a992a549adfe5a587bbcd6cd2b2cee47d236e27 +Author: fanquake +Date: Fri Sep 4 08:13:44 2020 +0800 + + Work around broken mingw cross-compilation + + See upstream issues: + https://bugreports.qt.io/browse/QTBUG-63637 + https://bugreports.qt.io/browse/QTBUG-63659 + https://codereview.qt-project.org/q/8bebded9 + + We should be able to drop this once we are building qt 5.10.1 or later. + + Added in #12971. + +diff --git a/qtbase/mkspecs/win32-g++/qmake.conf b/qtbase/mkspecs/win32-g++/qmake.conf +index e071a0d1..ad229b10 100644 +--- a/qtbase/mkspecs/win32-g++/qmake.conf ++++ b/qtbase/mkspecs/win32-g++/qmake.conf +@@ -87,3 +87,5 @@ QMAKE_NM = $${CROSS_COMPILE}nm -P + include(../common/angle.conf) + + load(qt_config) ++QMAKE_LINK_OBJECT_MAX = 10 ++QMAKE_LINK_OBJECT_SCRIPT = object_script diff --git a/depends/patches/qt5.9/fix_no_printer.patch b/depends/patches/qt5.9/fix_no_printer.patch new file mode 100644 index 0000000000..f868ca2577 --- /dev/null +++ b/depends/patches/qt5.9/fix_no_printer.patch @@ -0,0 +1,19 @@ +--- x/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h ++++ y/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h +@@ -52,6 +52,7 @@ + // + + #include ++#include + + #ifndef QT_NO_PRINTER + +--- x/qtbase/src/plugins/plugins.pro ++++ y/qtbase/src/plugins/plugins.pro +@@ -8,6 +8,3 @@ qtHaveModule(gui) { + qtConfig(imageformatplugin): SUBDIRS *= imageformats + !android:qtConfig(library): SUBDIRS *= generic + } +- +-!winrt:qtHaveModule(printsupport): \ +- SUBDIRS += printsupport diff --git a/depends/patches/qt5.9/fix_powerpc_libpng.patch b/depends/patches/qt5.9/fix_powerpc_libpng.patch new file mode 100644 index 0000000000..d37b6c7776 --- /dev/null +++ b/depends/patches/qt5.9/fix_powerpc_libpng.patch @@ -0,0 +1,23 @@ +commit 6f9feb773a43c5abfa3455da2e324180e789285b +Author: fanquake +Date: Tue Sep 15 21:44:31 2020 +0800 + + Fix PowerPC build of libpng + + See https://bugreports.qt.io/browse/QTBUG-66388. + + Can be dropped when we are building qt 5.12.0 or later. + +diff --git a/qtbase/src/3rdparty/libpng/libpng.pro b/qtbase/src/3rdparty/libpng/libpng.pro +index 577b61d8..a2f56669 100644 +--- a/qtbase/src/3rdparty/libpng/libpng.pro ++++ b/qtbase/src/3rdparty/libpng/libpng.pro +@@ -10,7 +10,7 @@ MODULE_INCLUDEPATH = $$PWD + + load(qt_helper_lib) + +-DEFINES += PNG_ARM_NEON_OPT=0 ++DEFINES += PNG_ARM_NEON_OPT=0 PNG_POWERPC_VSX_OPT=0 + SOURCES += \ + png.c \ + pngerror.c \ diff --git a/depends/patches/qt5.9/fix_qt_pkgconfig.patch b/depends/patches/qt5.9/fix_qt_pkgconfig.patch new file mode 100644 index 0000000000..8c722ffb46 --- /dev/null +++ b/depends/patches/qt5.9/fix_qt_pkgconfig.patch @@ -0,0 +1,23 @@ +--- old/qtbase/mkspecs/features/qt_module.prf ++++ new/qtbase/mkspecs/features/qt_module.prf +@@ -264,7 +264,7 @@ + load(qt_targets) + + # this builds on top of qt_common +-!internal_module:!lib_bundle:if(unix|mingw) { ++if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) { + CONFIG += create_pc + QMAKE_PKGCONFIG_DESTDIR = pkgconfig + host_build: \ +@@ -274,9 +274,9 @@ + QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_HEADERS/raw] + QMAKE_PKGCONFIG_CFLAGS = -I${includedir}/$$MODULE_INCNAME + QMAKE_PKGCONFIG_NAME = $$replace(TARGET, ^Qt, "Qt$$QT_MAJOR_VERSION ") +- QMAKE_PKGCONFIG_FILE = $$replace(TARGET, ^Qt, Qt$$QT_MAJOR_VERSION) ++ QMAKE_PKGCONFIG_FILE = $$replace(TARGET, ^Qt, Qt$$QT_MAJOR_VERSION)$$qtPlatformTargetSuffix() + for(i, MODULE_DEPENDS): \ +- QMAKE_PKGCONFIG_REQUIRES += $$replace(QT.$${i}.name, ^Qt, Qt$$section(QT.$${i}.VERSION, ., 0, 0)) ++ QMAKE_PKGCONFIG_REQUIRES += $$replace(QT.$${i}.name, ^Qt, Qt$$section(QT.$${i}.VERSION, ., 0, 0))$$qtPlatformTargetSuffix() + isEmpty(QMAKE_PKGCONFIG_DESCRIPTION): \ + QMAKE_PKGCONFIG_DESCRIPTION = $$replace(TARGET, ^Qt, "Qt ") module + pclib_replace.match = $$lib_replace.match diff --git a/depends/patches/qt5.9/fix_rcc_determinism.patch b/depends/patches/qt5.9/fix_rcc_determinism.patch new file mode 100644 index 0000000000..c1b07fe23a --- /dev/null +++ b/depends/patches/qt5.9/fix_rcc_determinism.patch @@ -0,0 +1,15 @@ +--- old/qtbase/src/tools/rcc/rcc.cpp ++++ new/qtbase/src/tools/rcc/rcc.cpp +@@ -207,7 +207,11 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) + if (lib.formatVersion() >= 2) { + // last modified time stamp + const QDateTime lastModified = m_fileInfo.lastModified(); +- lib.writeNumber8(quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0)); ++ quint64 lastmod = quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0); ++ static const quint64 sourceDate = 1000 * qgetenv("QT_RCC_SOURCE_DATE_OVERRIDE").toULongLong(); ++ if (sourceDate != 0) ++ lastmod = sourceDate; ++ lib.writeNumber8(lastmod); + if (text || pass1) + lib.writeChar('\n'); + } diff --git a/depends/patches/qt5.9/fix_riscv64_arch.patch b/depends/patches/qt5.9/fix_riscv64_arch.patch new file mode 100644 index 0000000000..e7f29f01f9 --- /dev/null +++ b/depends/patches/qt5.9/fix_riscv64_arch.patch @@ -0,0 +1,14 @@ +diff --git a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h +index 20bfd36..93729fa 100644 +--- a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h ++++ b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h +@@ -65,7 +65,8 @@ + defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ + defined(__SH4__) || defined(__alpha__) || \ + defined(_MIPS_ARCH_MIPS32R2) || \ +- defined(__AARCH64EL__) ++ defined(__AARCH64EL__) || defined(__aarch64__) || \ ++ defined(__riscv) + #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 + #elif defined(_M_IX86) || defined(__i386__) || defined(__i386) + #if defined(_WIN32) diff --git a/depends/patches/qt5.9/freetype_back_compat.patch b/depends/patches/qt5.9/freetype_back_compat.patch new file mode 100644 index 0000000000..b0f1c98aa6 --- /dev/null +++ b/depends/patches/qt5.9/freetype_back_compat.patch @@ -0,0 +1,28 @@ +commit 14bc77db61bf9d56f9b6c8b84aa02573605c19c6 +Author: fanquake +Date: Tue Aug 18 15:15:08 2020 +0800 + + Fix backwards compatibility with older Freetype versions at runtime + + A few years ago, libfreetype introduced FT_Get_Font_Format() as an alias + for FT_Get_X11_Font_Format(), but FT_Get_X11_Font_Format() was kept for abi + backwards-compatibility. + + Qt 5.9 introduced a call to FT_Get_Font_Format(). Replace it with FT_Get_X11_Font_Format() + in order to remain compatibile with older freetype, which is still used by e.g. Ubuntu Trusty. + + See #14348. + +diff --git a/qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp +index 3f543755..8ecc1c8c 100644 +--- a/qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp ++++ b/qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp +@@ -898,7 +898,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, + } + } + #if defined(FT_FONT_FORMATS_H) +- const char *fmt = FT_Get_Font_Format(face); ++ const char *fmt = FT_Get_X11_Font_Format(face); + if (fmt && qstrncmp(fmt, "CFF", 4) == 0) { + FT_Bool no_stem_darkening = true; + FT_Error err = FT_Property_Get(qt_getFreetype(), "cff", "no-stem-darkening", &no_stem_darkening); diff --git a/depends/patches/qt5.9/mac-qmake.conf b/depends/patches/qt5.9/mac-qmake.conf new file mode 100644 index 0000000000..0142667547 --- /dev/null +++ b/depends/patches/qt5.9/mac-qmake.conf @@ -0,0 +1,26 @@ +MAKEFILE_GENERATOR = UNIX +CONFIG += app_bundle incremental lib_version_first absolute_library_soname +QMAKE_INCREMENTAL_STYLE = sublib +include(../common/macx.conf) +include(../common/gcc-base-mac.conf) +include(../common/clang.conf) +include(../common/clang-mac.conf) +QMAKE_MAC_SDK_PATH=$${MAC_SDK_PATH} +QMAKE_XCODE_VERSION = $${XCODE_VERSION} +QMAKE_XCODE_DEVELOPER_PATH=/Developer +QMAKE_MACOSX_DEPLOYMENT_TARGET = $${MAC_MIN_VERSION} +QMAKE_MAC_SDK=macosx +QMAKE_MAC_SDK.macosx.Path = $${MAC_SDK_PATH} +QMAKE_MAC_SDK.macosx.platform_name = macosx +QMAKE_MAC_SDK.macosx.SDKVersion = $${MAC_SDK_VERSION} +QMAKE_MAC_SDK.macosx.PlatformPath = /phony +QMAKE_APPLE_DEVICE_ARCHS=x86_64 +!host_build: QMAKE_CFLAGS += -target $${MAC_TARGET} +!host_build: QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_CFLAGS +!host_build: QMAKE_CXXFLAGS += $$QMAKE_CFLAGS +!host_build: QMAKE_LFLAGS += -target $${MAC_TARGET} +QMAKE_AR = $${CROSS_COMPILE}ar cq +QMAKE_RANLIB=$${CROSS_COMPILE}ranlib +QMAKE_LIBTOOL=$${CROSS_COMPILE}libtool +QMAKE_INSTALL_NAME_TOOL=$${CROSS_COMPILE}install_name_tool +load(qt_config) diff --git a/depends/patches/qt5.9/no-xlib.patch b/depends/patches/qt5.9/no-xlib.patch new file mode 100644 index 0000000000..fe82c2c73c --- /dev/null +++ b/depends/patches/qt5.9/no-xlib.patch @@ -0,0 +1,69 @@ +From 9563cef873ae82e06f60708d706d054717e801ce Mon Sep 17 00:00:00 2001 +From: Carl Dong +Date: Thu, 18 Jul 2019 17:22:05 -0400 +Subject: [PATCH] Wrap xlib related code blocks in #if's + +They are not necessary to compile QT. +--- + qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp +index 7c62c2e2b3..c05c6c0a07 100644 +--- a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp ++++ b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp +@@ -49,7 +49,9 @@ + #include + #include + #include ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + #include ++#endif + #include + #include + +@@ -384,6 +386,7 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget) + w->setCursor(c, isBitmapCursor); + } + ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + static int cursorIdForShape(int cshape) + { + int cursorId = 0; +@@ -437,6 +440,7 @@ static int cursorIdForShape(int cshape) + } + return cursorId; + } ++#endif + + xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape) + { +@@ -558,7 +562,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape) + xcb_cursor_t QXcbCursor::createFontCursor(int cshape) + { + xcb_connection_t *conn = xcb_connection(); ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + int cursorId = cursorIdForShape(cshape); ++#endif + xcb_cursor_t cursor = XCB_NONE; + + // Try Xcursor first +@@ -589,6 +595,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) + // Non-standard X11 cursors are created from bitmaps + cursor = createNonStandardCursor(cshape); + ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + // Create a glpyh cursor if everything else failed + if (!cursor && cursorId) { + cursor = xcb_generate_id(conn); +@@ -596,6 +603,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) + cursorId, cursorId + 1, + 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0); + } ++#endif + + if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) { + const char *name = cursorNames[cshape]; +-- +2.22.0 + diff --git a/depends/patches/qt5.9/xkb-default.patch b/depends/patches/qt5.9/xkb-default.patch new file mode 100644 index 0000000000..165abf3e2e --- /dev/null +++ b/depends/patches/qt5.9/xkb-default.patch @@ -0,0 +1,26 @@ +--- old/qtbase/src/gui/configure.pri 2018-06-06 17:28:10.000000000 -0400 ++++ new/qtbase/src/gui/configure.pri 2018-08-17 18:43:01.589384567 -0400 +@@ -43,18 +43,11 @@ + } + + defineTest(qtConfTest_xkbConfigRoot) { +- qtConfTest_getPkgConfigVariable($${1}): return(true) +- +- for (dir, $$list("/usr/share/X11/xkb", "/usr/local/share/X11/xkb")) { +- exists($$dir) { +- $${1}.value = $$dir +- export($${1}.value) +- $${1}.cache += value +- export($${1}.cache) +- return(true) +- } +- } +- return(false) ++ $${1}.value = "/usr/share/X11/xkb" ++ export($${1}.value) ++ $${1}.cache += value ++ export($${1}.cache) ++ return(true) + } + + defineTest(qtConfTest_qpaDefaultPlatform) { diff --git a/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch new file mode 100644 index 0000000000..a6c508fb8a --- /dev/null +++ b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch @@ -0,0 +1,30 @@ +From 1a159c128c69a42d90819375c06a39994f3fbfc1 Mon Sep 17 00:00:00 2001 +From: Cory Fields +Date: Tue, 28 Nov 2017 20:33:25 -0500 +Subject: [PATCH] fix build with older mingw64 + +--- + src/windows.hpp | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/windows.hpp b/src/windows.hpp +index 99e889d..e69038e 100644 +--- a/src/windows.hpp ++++ b/src/windows.hpp +@@ -55,6 +55,13 @@ + #include + #include + #include ++ ++#if defined __MINGW64_VERSION_MAJOR && __MINGW64_VERSION_MAJOR < 4 ++// Workaround for mingw-w64 < v4.0 which did not include ws2ipdef.h in iphlpapi.h. ++// Fixed in mingw-w64 by 9bd8fe9148924840d315b4c915dd099955ea89d1. ++#include ++#include ++#endif + #include + + #if !defined __MINGW32__ +-- +2.7.4 + diff --git a/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch b/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch new file mode 100644 index 0000000000..d220b54f3e --- /dev/null +++ b/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch @@ -0,0 +1,35 @@ +From 6e6b47d5ab381c3df3b30bb0b0a6cf210dfb1eba Mon Sep 17 00:00:00 2001 +From: Cory Fields +Date: Mon, 5 Mar 2018 14:22:05 -0500 +Subject: [PATCH] disable pthread_set_name_np + +pthread_set_name_np adds a Glibc requirement on >= 2.12. +--- + src/thread.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/thread.cpp b/src/thread.cpp +index 4fc59c3e..c3fdfd46 100644 +--- a/src/thread.cpp ++++ b/src/thread.cpp +@@ -220,7 +220,7 @@ void zmq::thread_t::setThreadName(const char *name_) + */ + if (!name_) + return; +- ++#if 0 + #if defined(ZMQ_HAVE_PTHREAD_SETNAME_1) + int rc = pthread_setname_np(name_); + if(rc) return; +@@ -233,6 +233,8 @@ void zmq::thread_t::setThreadName(const char *name_) + #elif defined(ZMQ_HAVE_PTHREAD_SET_NAME) + pthread_set_name_np(descriptor, name_); + #endif ++#endif ++ return; + } + + #endif +-- +2.11.1 + diff --git a/depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch b/depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch deleted file mode 100644 index f704b3d94f..0000000000 --- a/depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 9114d3957725acd34aa8b8d011585812f3369411 Mon Sep 17 00:00:00 2001 -From: Jeroen Ooms -Date: Tue, 20 Oct 2015 13:10:38 +0200 -Subject: [PATCH] enable static libraries on mingw - ---- - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index 393505b..e92131a 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -265,7 +265,7 @@ case "${host_os}" in - libzmq_dso_visibility="no" - - if test "x$enable_static" = "xyes"; then -- AC_MSG_ERROR([Building static libraries is not supported under MinGW32]) -+ CPPFLAGS="-DZMQ_STATIC" - fi - - # Set FD_SETSIZE to 1024 \ No newline at end of file diff --git a/depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch b/depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch deleted file mode 100644 index 9aff2c179a..0000000000 --- a/depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 9e6745c12e0b100cd38acecc16ce7db02905e27c Mon Sep 17 00:00:00 2001 -From: David Millard -Date: Tue, 10 May 2016 13:53:53 -0700 -Subject: [PATCH] Fix autotools for static MinGW builds - ---- - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index 5a0fa14..def6ea7 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -259,7 +259,7 @@ case "${host_os}" in - libzmq_dso_visibility="no" - - if test "x$enable_static" = "xyes"; then -- CPPFLAGS="-DZMQ_STATIC" -+ CPPFLAGS="-DZMQ_STATIC $CPPFLAGS" - fi - - # Set FD_SETSIZE to 1024 \ No newline at end of file diff --git a/doc/BDAP.md b/doc/BDAP.md new file mode 100644 index 0000000000..b9493bbdeb --- /dev/null +++ b/doc/BDAP.md @@ -0,0 +1,123 @@ +# BDAP - Blockchain Directory Access Protocol + +## Abstract + +[BDAP (Blockchain Directory Access Protocol)](https://duality.solutions/bdap) gives programmable access control and direct communication with users on the network, adding a layer of resource hierarchy and providing a distributed database with account linking, making it possible to develop core information systems using the blockchain technology of [Dynamic](https://github.com/duality-solutions/dynamic) and [Sequence](https://github.com/duality-solutions/sequence). This design allows user controlled nodes to securely connect, privately share data without a third-party intermediary, and to scale the database up indefinitely. + +BDAP enables the creation of applications across the spectrum of industry, drastically reducing the costs involved with core information systems. Removing the requirement for the majority of administration roles and the need for trusted third parties. Rendering current centralized database systems such as [LDAP (Lightweight Directory Access Protocol)](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol) a thing of the past. + +## Technical Information + +[BDAP](https://duality.solutions/bdap) is used to create and amend entries on a [libtorrent](https://github.com/arvidn/libtorrent) based DHT (Distributed Hash Table), and utilizes the blockchain of [Dynamic](https://github.com/duality-solutions/dynamic) to provide decentralization and security. + +### BDAP Development Kit (BDK) + +Developers can build their own BDAP based dApps (decentralised applications) by using the BDAP Development Kit (BDK). + +### BDAP Domain Entry Database + +Needs content. + +### BDAP Data Auditing + +Needs content. + +### BDAP Entry Creation + +Needs content. + +### BDAP Entry Updating + +Needs content. + +### BDAP Entry Linking + +Entry linking is a type of DAP binding operation and is used to manage domain entry link requests. When linking entries, we use stealth addresses so the linkage requests remain private. Link requests (class CLinkRequest) are stored, serialized and encrypted in a [BDAP](https://duality.solutions/bdap) ```OP_RETURN``` transaction. The link request recipient can decrypt the [BDAP](https://duality.solutions/bdap) ```OP_RETURN``` transaction and get the needed information (class CLinkAccept) to accept the link request. It is used to bootstrap the linkage relationship with a new set of public keys. + +##### class CLinkRequest + +``` +CharString RequestorFullObjectPath; // Requestor's BDAP object path + +CharString RecipientFullObjectPath; // Recipient's BDAP object path + +CharString RequestorPubKey; // ed25519 public key new/unique for this link + +CharString SharedPubKey; // ed25519 shared public key(RequestorPubKey + Recipient's BDAP DHT PubKey) + +CharString LinkMessage // Link message to recipient + +CharString SignatureProof; // Requestor's BDAP account ownership proof by signing the recipient's object path with their wallet public key +``` + +##### class CLinkAccept + +``` +CharString RequestorFullObjectPath; // Requestor's BDAP object path + +CharString RecipientFullObjectPath; // Recipient's BDAP object path + +uint256 txLinkRequestHash; // transaction hash for the link request. + +CharString RecipientPubKey; // ed25519 public key new/unique for this link + +CharString SharedPubKey; // ed25519 shared public key using the requestor and recipient keys + +CharString SignatureProof; // Acceptor's BDAP account ownership proof by signing the requestor's object path with their wallet public key. +``` + +### BDAP Sidechaining + +Needs content. + +### BDAP RPC Calls + +* **adduser** - adds a public name entry to blockchain directory:```adduser "userid" "common name" "registration days"``` + +* **getusers** - list all BDAP public users:```getusers "records per page" "page returned"``` + +* **getgroups** - list all BDAP public groups:```getgroups "records per page" "page returned"``` + +* **getuserinfo** - list BDAP entry:```getuserinfo "public name"``` + +* **updateuser** - update an existing public name blockchain directory entry:```updateuser "userid" "common name" "registration days"``` + +* **updategroup** - update an existing public group blockchain directory entry:```updategroup "groupid" "common name" "registration days"``` + +* **deleteuser** - delete an existing public name blockchain directory entry:```deleteuser "userid"``` + +* **deletegroup** - delete an existing public name blockchain directory entry:```deletegroup "groupid"``` + +* **addgroup** - add public group entry to blockchain directory:```addgroup "groupid" "common name"``` + +* **getgroupinfo** - list BDAP entry:```getgroupinfo "groupid"``` + +* **mybdapaccounts** - returns your BDAP accounts: ```mybdapaccounts``` + +* **link** - link commands are request, accept, pending, complete, and delete:```link "operation" "common name" "registration days"``` + +### DHT RPC Calls + +* **getmutable** - gets mutable data from the DHT:```getmutable "pubkey" "operation"``` + +* **putmutable** - saves mutable data in the DHT:```putmutable "dht value" "operation" "pubkey" "privkey"``` + +* **dhtinfo** - gets DHT network stats and info:```dhtinfo``` + +* **dhtdb** - gets the local DHT cache database contents:```dhtdb``` + +* **putbdapdata** - saves mutable data in the DHT for a BDAP entry:```putbdapdata "bdap id" "dht value" "operation"``` + +* **getbdapdata** - gets the mutable data from the DHT for a BDAP entry:```getbdapdata "bdap id" "operation"``` + +* **dhtputmessages** - gets all DHT put messages in memory:```dhtputmessages``` + +* **dhtgetmessages** - gets all DHT get messages in memory:```dhtgetmessages``` + +### BDAP Code + +All of the code for [BDAP](https://duality.solutions/bdap) can be found in the [/src/bdap/](https://github.com/duality-solutions/Dynamic/tree/master/src/bdap) directory of [Dynamic](https://github.com/duality-solutions/dynamic). + +### DHT Code + +All of the code for the DHT can be found in the [/src/dht/](https://github.com/duality-solutions/Dynamic/tree/master/src/dht) directory of [Dynamic](https://github.com/duality-solutions/dynamic). diff --git a/doc/README.md b/doc/README.md index 094b952568..f0a2a094da 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,56 +1,45 @@ [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -[![Build Status](https://travis-ci.org/Duality-Solutions/Dynamic.png?branch=master)](https://travis-ci.org/Duality-Solutions/Dynamic) -[![Stories in Ready](https://badge.waffle.io/Duality-Solutions/Dynamic.png?label=ready&title=Ready)](https://waffle.io/Duality-Solutions/Dynamic) +[![Build Status](https://travis-ci.org/duality-solutions/Dynamic.png?branch=master)](https://travis-ci.org/duality-solutions/Dynamic) +[![Stories in Ready](https://badge.waffle.io/duality-solutions/Dynamic.png?label=ready&title=Ready)](https://waffle.io/duality-solutions/Dynamic) Graph on Pull Request History ==================================== -[![Throughput Graph](https://graphs.waffle.io/Duality-Solutions/Dynamic/throughput.svg)](https://waffle.io/Duality-Solutions/Dynamic/metrics/throughput) +[![Throughput Graph](https://graphs.waffle.io/duality-solutions/Dynamic/throughput.svg)](https://waffle.io/duality-solutions/Dynamic/metrics/throughput) -# **Dynamic (DYN) v1.4.0.0** +# **Dynamic (DYN) v2.4.0.0** -![DYN logo](https://github.com/Duality-Solutions/Dynamic/blob/master/src/qt/res/icons/drk/about.png) +![DYN logo](https://github.com/duality-solutions/Dynamic/blob/master/src/qt/res/icons/drk/about.png) -**Copyright (c) 2016-2018 Duality Blockchain Solutions** +**Copyright (c) 2016-2021 [Duality Blockchain Solutions](https://duality.solutions/)** -What is Dynamic? +What is [Dynamic](https://duality.solutions/dynamic)? ---------------- * Coin Suffix: DYN -* PoW Algorithm: Argon2d +* PoW Mining Algorithm: Argon2d +* PoW Difficulty Algorithm: Digishield V3 * PoW Period: Unlimited * PoW Target Spacing: 128 Seconds -* PoW Reward per Block: 1 DYN -* PoW Reward Start Height: Block 20,546 +* PoW Reward per Block: Controlled via Fluid Protocol +* PoW Reward Start Height: Block 5,137 * Maturity: 10 Blocks * PoW Blocks: ~675 per day * Dynode Collateral Amount: 1000 DYN -* Dynode Min Confirmation: 10 Blocks -* Dynode Reward: 0.382 DYN Static Reward (38.2% of a PoW reward) -* Dynode Reward Start Height: Block 20,546 -* Budget Reward: 10,000 DYN Static Reward Every 20,545 blocks (~30 days) -* Budget Proposal Fee: 100 DYN, 20 confirmations (~30 minutes) +* Dynode Min Confirmation: 17 Blocks +* Dynode Reward: Controlled via Fluid Protocol +* Dynode Reward Start Height: Block 10,273 * Total Coins: 263 - 1 * Min TX Fee: 0.0001 DYN -The Dynamic(DYN) blockchain exists in the Duality binary architecture as a DAO, whilst [Sequence(SEQ)](https://github.com/duality-solutions/sequence) is its real world interface. Dynamic uses peer-to-peer technology to operate securly with no central authority (decentralisation): managing transactions and issuing currency (DYN) are carried out collectively by the Dynamic network. Dynamic is the name of open source software which enables the use of the currency DYN. - -Dynamic utilises Dynodes, PrivateSend and InstantSend to provide anonymous and near instant transaction confirmations. - -Dynamic implements Gavin Andresens signature cache optimisation from Bitcoin for significantly faster transaction validation. - - -**Dynode/PrivateSend Network Information** -Ported Masternodes from Dash, rebranded as Dynodes. -Darksend ported and rebranded as PrivateSend. -Utilisation of InstantSend for near-instant transactions. +[Dynamic(DYN)](https://duality.solutions/dynamic) allows fast, secure, verifiable transfers of data using blockchain technology and enables third-party developers to build low-cost solutions across varied industry using the BDAP protocol. Dynamic can be used to run incentivized Dynodes; the second tier of nodes on the network processing, verifying, validating and storing data. **MainNet Parameters** P2P Port = 33300 RPC Port = 33350 Dynodes = 33300 -Magic Bytes: 0x3f 0x42 0x55 0x61 +Magic Bytes: 0x5e 0x61 0x74 0x80 **TestNet Parameters** P2P Port = 33400 @@ -67,7 +56,7 @@ Magic Bytes = 0x2f 0x32 0x15 0x3f UNIX BUILD NOTES ==================== -Some notes on how to build Dynamic in Unix. +Some notes on how to build [Dynamic](https://duality.solutions/dynamic) in Unix. Note --------------------- @@ -100,7 +89,8 @@ These dependencies are required: ------------|------------------|---------------------- libssl | SSL Support | Secure communications libboost | Boost | C++ Library - libevent | Networking | OS independent asynchronous networking + libevent | Networking | OS independent asynchronous networking + Optional dependencies: Library | Purpose | Description @@ -117,27 +107,27 @@ For the versions used in the release, see [release-process.md](release-process.m System requirements -------------------- -C++ compilers are memory-hungry. It is recommended to have at least 3 GB of -memory available when compiling Dynamic. +C++ compilers are memory-hungry. It is recommended to have at least 3 GB of memory available when compiling Dynamic. Dependency Build Instructions: Ubuntu & Debian ---------------------------------------------- + +It is required to build Dynamic on Ubuntu 18.04LTS(Bionic) or later due to C++14/GCC7 requirements. Also OpenSSL 1.1.0g is included in Ubuntu 18.04LTS and later, however it is suggested to use OpenSSL 1.1.1LTS. + Build requirements: sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libcrypto++-dev libevent-dev git -for Ubuntu 12.04 and later or Debian 7 and later libboost-all-dev has to be installed: +For Ubuntu 18.04LTS(Bionic) and later, or Debian 7 and later; libboost-all-dev has to be installed: sudo apt-get install libboost-all-dev - db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). - You can add the repository using the following command: +db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). You can add the repository using the following command: - sudo add-apt-repository ppa:bitcoin/bitcoin - sudo apt-get update + sudo add-apt-repository ppa:bitcoin/bitcoin + sudo apt-get update - Ubuntu 12.04 and later have packages for libdb5.1-dev and libdb5.1++-dev, - but using these will break binary wallet compatibility, and is not recommended. +Ubuntu 18.04 and later have packages for libdb 5.3.21 but using these will break binary wallet compatibility, and is not recommended. for Debian 7 (Wheezy) and later: The oldstable repository contains db4.8 packages. @@ -165,10 +155,7 @@ ZMQ dependencies (provides ZMQ API 4.x): Dependencies for the GUI: Ubuntu & Debian ----------------------------------------- -If you want to build Dynamic-Qt, make sure that the required packages for Qt development -are installed. Qt 5 is necessary to build the GUI. -If both Qt 4 and Qt 5 are installed, Qt 5 will be used. Pass `--with-gui=qt5` to configure to choose Qt5. -To build without GUI pass `--without-gui`. +If you want to build Dynamic-Qt, make sure that the required packages for Qt development are installed. Qt 5 is necessary to build the GUI. If both Qt 4 and Qt 5 are installed, Qt 5 will be used. Pass `--with-gui=qt5` to configure to choose Qt5. To build without GUI pass `--without-gui`. For Qt 5 you need the following: @@ -189,6 +176,8 @@ symbols, which reduces the executable size by about 90%. miniupnpc --------- +The dependencies for miniupnpc are included above within the 'Dependency Build Instructions: Ubuntu & Debian' section, however, for any reason you wish to build the source, please follow these instructions. + [miniupnpc](http://miniupnp.free.fr/) may be used for UPnP port mapping. It can be downloaded from [here]( http://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and turned off by default. See the configure options for upnp behavior desired: @@ -207,38 +196,41 @@ To build: Berkeley DB ----------- -It is recommended to use Berkeley DB 4.8. If you have to build it yourself: - -```bash -DYNAMIC_ROOT=$(pwd) - -# Pick some path to install BDB to, here we create a directory within the dynamic directory -BDB_PREFIX="${DYNAMIC_ROOT}/db4" -mkdir -p $BDB_PREFIX - -# Fetch the source and verify that it is not tampered with -wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' -echo '12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz' | sha256sum -c -# -> db-4.8.30.NC.tar.gz: OK -tar -xzvf db-4.8.30.NC.tar.gz - -# Build the library and install to our prefix -cd db-4.8.30.NC/build_unix/ -# Note: Do a static build so that it can be embedded into the exectuable, instead of having to find a .so at runtime -../dist/configure --prefix=/usr/local --enable-cxx -make -sudo make install - -# Configure Dynamic to use our own-built instance of BDB -cd $DYNAMIC_ROOT -./configure (other args...) LDFLAGS="-L${BDB_PREFIX}/lib/" CPPFLAGS="-I${BDB_PREFIX}/include/" +It is recommended to use Berkeley DB 4.8 and is included in the dependencies above in the 'Dependency Build Instructions: Ubuntu & Debian' section. + +If you have to, or wish to build Berkeley DB 4.8 yourself: + +``` + bash + DYNAMIC_ROOT=$(pwd) + + # Pick some path to install BDB to, here we create a directory within the dynamic directory + BDB_PREFIX="${DYNAMIC_ROOT}/db4" + mkdir -p $BDB_PREFIX + + # Fetch the source and verify that it is not tampered with + wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' + echo '12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz' | sha256sum -c + # -> db-4.8.30.NC.tar.gz: OK + tar -xzvf db-4.8.30.NC.tar.gz + + # Build the library and install to our prefix + cd db-4.8.30.NC/build_unix/ + # Note: Do a static build so that it can be embedded into the exectuable, instead of having to find a .so at runtime + ../dist/configure --prefix=/usr/local --enable-cxx + make + sudo make install + + # Configure Dynamic to use our own-built instance of BDB + cd $DYNAMIC_ROOT + ./configure (other args...) LDFLAGS="-L${BDB_PREFIX}/lib/" CPPFLAGS="-I${BDB_PREFIX}/include/" ``` **Note**: You only need Berkeley DB if the wallet is enabled (see the section *Disable-Wallet mode* below). Boost ----- -If you need to build Boost yourself: +If you need to build Boost yourself, in terminal enter: sudo su ./bootstrap.sh @@ -247,8 +239,8 @@ If you need to build Boost yourself: Security -------- -To help make your Dynamic installation more secure by making certain attacks impossible to -exploit even if a vulnerability is found, binaries are hardened by default. +To help make your Dynamic installation more secure by making certain attacks impossible to exploit even if a vulnerability is found, binaries are hardened by default. + This can be disabled with: Hardening Flags: @@ -271,10 +263,12 @@ Hardening enables the following features: To test that you have built PIE executable, install scanelf, part of paxutils, and use: - scanelf -e ./dynamicd + scanelf -e ./dynamicd + The output should contain: - TYPE + + TYPE ET_DYN * Non-executable Stack @@ -305,12 +299,90 @@ In this case there is no dependency on Berkeley DB 4.8. Mining is also possible in disable-wallet mode, but only using the `getblocktemplate` RPC call not `getwork`. +AVX2 Mining Optimisations +------------------------- +For increased performance when mining, AVX2 optimisations can be enabled. + +At configure time: + + --enable-avx2 + +CPU's with AVX2 support: + + Intel + Haswell processor, Q2 2013 + Haswell E processor, Q3 2014 + Broadwell processor, Q4 2014 + Broadwell E processor, Q3 2016 + Skylake processor, Q3 2015 + Kaby Lake processor, Q3 2016(ULV mobile)/Q1 2017(desktop/mobile) + Coffee Lake processor, Q4 2017 + + AMD + Carrizo processor, Q2 2015 + Ryzen processor, Q1 2017 + +AVX512 Mining Optimisations +------------------------- +For increased performance when mining, AVX512 optimisations can be enabled. + +At configure time: + + --enable-avx512f + +CPU's with AVX512 support: + + Intel + Xeon Phi x200/Knights Landing processor, 2016 + Knights Mill processor, 2017 + Skylake-SP processor, 2017 + Skylake-X processor, 2017 + Cannonlake processor, expected in 2019 + Ice Lake processor, expected in 2019 + + +GPU Mining +---------- +To enable GPU mining within the wallet, OpenCL or CUDA can be utilised. Please use GCC/G++ 6.4 or newer and for CUDA to be utilised please use CUDA 9.1 or newer and ensure you have graphics drivers installed. + +For OpenCL you need the following: + + sudo apt-get install ocl-icd-opencl-dev + +For CUDA please visit: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html + +At configure time for OpenCL(Nvidia/AMD): + + --enable-gpu + +At configure time for CUDA(Nvidia): + + --enable-gpu --enable-cuda + Example Build Command -------------------- -Qt Wallet and Deamon, CLI version build: +Qt Wallet and Deamon, CLI version build without GPU support and without AVX support: + + ./autogen.sh && ./configure --with-gui --disable-gpu && make + +CLI and Deamon Only build without GPU support and without AVX support: + + ./autogen.sh && ./configure --without-gui --disable-gpu && make + +Use Qt Creator as IDE +------------------------ +You can use Qt Creator as IDE, for debugging and for manipulating forms, etc. +Download Qt Creator from http://www.qt.io/download/. Download the "community edition" and only install Qt Creator (uncheck the rest during the installation process). - ./autogen.sh && ./configure --with-gui && make +1. Make sure you installed everything through homebrew mentioned above +2. Do a proper ./configure --with-gui=qt5 --enable-debug +3. In Qt Creator do "New Project" -> Import Project -> Import Existing Project +4. Enter "dynamic-qt" as project name, enter src/qt as location +5. Leave the file selection as it is +6. Confirm the "summary page" +7. In the "Projects" tab select "Manage Kits..." +8. Select the default "Desktop" kit and select "Clang (x86 64bit in /usr/bin)" as compiler +9. Select LLDB as debugger (you might need to set the path to your installtion) +10. Start debugging with Qt Creator -CLI and Deamon Only Buld: - ./autogen.sh && ./configure --without-gui && make diff --git a/doc/README_windows.txt b/doc/README_windows.txt index bfa5701be5..dd696d4d04 100644 --- a/doc/README_windows.txt +++ b/doc/README_windows.txt @@ -1,4 +1,4 @@ -Dynamic 1.4.0.0 +Dynamic 2.4.0.0 ===================== Intro diff --git a/doc/build-debian.md b/doc/build-debian.md index 6fc72c2a48..45554dc7f4 100644 --- a/doc/build-debian.md +++ b/doc/build-debian.md @@ -95,18 +95,18 @@ in the getinfo-output. If the numbers match, the installation is completed. ``` dynamic-cli getinfo { - "version": 2030000, - "protocolversion": 70900, - "walletversion": 120200, + "version": 2040400, + "protocolversion": 71050, + "walletversion": 204000, "balance": 0.00000000, "privatesend_balance": 0.00000000, - "blocks": 73731, <- we're looking for this line right here + "blocks": 193619, "timeoffset": 0, "connections": 16, "proxy": "127.0.0.1:9050", - "difficulty": 0.5382088449061717, + "difficulty": 1.129563238994795, "testnet": false, - "keypoololdest": 1522174973, + "keypoololdest": 1538953839, "keypoolsize": 1999, "paytxfee": 0.00000000, "relayfee": 0.00001000, diff --git a/doc/build-osx.md b/doc/build-osx.md index 00cf6cad57..3b5db7b75b 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -5,7 +5,7 @@ This guide will show you how to build dynamicd (headless client) for OSX. Notes ----- -* Tested on OS X 10.7 through 10.12.6 on 64-bit Intel processors only. +* Tested on OS X Lion 10.7 through to Mojave 10.14.2 on 64-bit Intel processors only. * All of the commands should be executed in a Terminal application. The built-in one is located in `/Applications/Utilities`. @@ -38,8 +38,7 @@ Instructions: Homebrew #### Install dependencies using Homebrew - $ brew install git autoconf automake libevent libtool boost --c++11 miniupnpc openssl pkg-config qt berkeley-db4 - $ brew install homebrew/versions/protobuf260 --c++11 + $ brew install git autoconf automake libevent libtool boost --c++11 miniupnpc openssl pkg-config protobuf260 --c++11 qt berkeley-db4 Because of OS X having LibreSSL installed we have to tell the compiler where OpenSSL is located: @@ -49,7 +48,7 @@ Because of OS X having LibreSSL installed we have to tell the compiler where Ope or you can instead symlink your newly installed OpenSSL: - $ sudo ln -s openssl-1.0.2j /usr/local/openssl + $ sudo ln -s openssl-1.0.2q /usr/local/openssl (the above version of OpenSSL may differ to the one you have installed, amend to suit) @@ -67,6 +66,10 @@ Prior to running the build commands: CPPFLAGS=-march=native +At configure time: + + --enable-avx2 + CPU's with AVX2 support: Intel @@ -76,33 +79,63 @@ CPU's with AVX2 support: Broadwell E processor, Q3 2016 Skylake processor, Q3 2015 Kaby Lake processor, Q3 2016(ULV mobile)/Q1 2017(desktop/mobile) - Coffee Lake processor, expected in 2017 - Cannonlake processor, expected in 2017 + Coffee Lake processor, Q4 2017 + AMD Carrizo processor, Q2 2015 Ryzen processor, Q1 2017 - -### Building `dynamicd` -1. Clone the github tree to get the source code and go into the directory. +AVX512 Mining Optimisations +------------------------- +For increased performance when mining, AVX512 optimisations can be enabled. + +Prior to running the build commands: + + CPPFLAGS=-march=native + +At configure time: - git clone https://github.com/duality-solutions/dynamic.git - cd dynamic + --enable-avx512f + +CPU's with AVX512 support: + + Intel + Xeon Phi x200/Knights Landing processor, 2016 + Knights Mill processor, 2017 + Skylake-SP processor, 2017 + Skylake-X processor, 2017 + Cannonlake processor, expected in 2019 + Ice Lake processor, expected in 2019 + -2. Build dynamicd: +GPU Mining +---------- +To enable GPU mining within the wallet, OpenCL or CUDA can be utilised. Please use GCC/G++ 6.4 or newer and for CUDA to be utilised please use CUDA 9.1 or newer and ensure you have graphics drivers installed. - ./autogen.sh - ./configure - make +For OpenCL you need the following: -3. It is also a good idea to build and run the unit tests: + sudo apt-get install ocl-icd-opencl-dev + +For CUDA please visit: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html + +At configure time for OpenCL(Nvidia/AMD): - make check + --enable-gpu -4. (Optional) You can also install dynamicd to your path: +At configure time for CUDA(Nvidia): - make install + --enable-gpu --enable-cuda +Example Build Command +-------------------- +Qt Wallet and Deamon, CLI version build without GPU support and without AVX support: + + ./autogen.sh && ./configure --with-gui --disable-gpu && make + +CLI and Deamon Only build without GPU support and without AVX support: + + ./autogen.sh && ./configure --without-gui --disable-gpu && make + Use Qt Creator as IDE ------------------------ You can use Qt Creator as IDE, for debugging and for manipulating forms, etc. diff --git a/doc/build-unix.md b/doc/build-unix.md index 85d7abc6da..aa6404e7a6 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -249,9 +249,9 @@ AVX2 Mining Optimisations ------------------------- For increased performance when mining, AVX2 optimisations can be enabled. -Prior to running the build commands: +At configure time: - CPPFLAGS=-march=native + --enable-avx2 CPU's with AVX2 support: @@ -262,8 +262,56 @@ CPU's with AVX2 support: Broadwell E processor, Q3 2016 Skylake processor, Q3 2015 Kaby Lake processor, Q3 2016(ULV mobile)/Q1 2017(desktop/mobile) - Coffee Lake processor, expected in 2017 - Cannonlake processor, expected in 2017 + Coffee Lake processor, Q4 2017 + AMD Carrizo processor, Q2 2015 Ryzen processor, Q1 2017 + +AVX512 Mining Optimisations +------------------------- +For increased performance when mining, AVX512 optimisations can be enabled. + +At configure time: + + --enable-avx512f + +CPU's with AVX512 support: + + Intel + Xeon Phi x200/Knights Landing processor, 2016 + Knights Mill processor, 2017 + Skylake-SP processor, 2017 + Skylake-X processor, 2017 + Cannonlake processor, expected in 2019 + Ice Lake processor, expected in 2019 + + +GPU Mining +---------- +To enable GPU mining within the wallet, OpenCL or CUDA can be utilised. Please use GCC/G++ 6.4 or newer and for CUDA to be utilised please use CUDA 9.1 or newer and ensure you have graphics drivers installed. + +For OpenCL you need the following: + + sudo apt-get install ocl-icd-opencl-dev + +For CUDA please visit: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html + +At configure time for OpenCL(Nvidia/AMD): + + --enable-gpu + +At configure time for CUDA(Nvidia): + + --enable-gpu --enable-cuda + +Example Build Command +-------------------- +Qt Wallet and Deamon, CLI version build without GPU support and without AVX support: + + ./autogen.sh && ./configure --with-gui --disable-gpu && make + +CLI and Deamon Only build without GPU support and without AVX support: + + ./autogen.sh && ./configure --without-gui --disable-gpu && make + \ No newline at end of file diff --git a/doc/dynamic_logo_doxygen.png b/doc/dynamic_logo_doxygen.png index 812f996656..6ce0d44f60 100644 Binary files a/doc/dynamic_logo_doxygen.png and b/doc/dynamic_logo_doxygen.png differ diff --git a/doc/files.md b/doc/files.md index 34306f3227..44007de1dc 100644 --- a/doc/files.md +++ b/doc/files.md @@ -1,4 +1,4 @@ -Used in 1.4.0.0 +Used in 2.4.0.0 --------------------- * wallet.dat: personal wallet (BDB) with keys and transactions * peers.dat: peer IP address database (custom format); diff --git a/doc/initialisation-arguments.md b/doc/initialisation-arguments.md index b81291dc28..7bd66b4032 100644 --- a/doc/initialisation-arguments.md +++ b/doc/initialisation-arguments.md @@ -138,7 +138,7 @@ debug Categories are "addrman, alert, bench, coindb, db, http, libevent, lock, m ("If [category] is not supplied or if [category] = 1, output all debugging information.") + ("[category] can be:") * "-nodebug" ("Turn off debugging messages, same as -debug=0") * "-gen" ("Generate coins") -* "-genproclimit=[n]" ("Set the number of threads for coin generation if enabled (-1 = all cores)") +* "-genproclimit-cpu=[n]" ("Set the number of threads for coin generation if enabled (-1 = all cores)") * "-help-debug" ("Show all debugging options (usage: --help -help-debug)") * "-logips" ("Include IP addresses in debug output") * "-logtimestamps" ("Prepend debug output with timestamp") diff --git a/doc/release-notes.md b/doc/release-notes.md index a387e7ee25..55630b1a7b 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,3 +1,3 @@ -Dynamic 2.3.5.0 +Dynamic 2.4.0.0 ================== -- [v2.3.5.0](release-notes/dynamic/release-notes.md) \ No newline at end of file +- [v2.4.0.0](release-notes/dynamic/release-notes.md) \ No newline at end of file diff --git a/doc/release-process.md b/doc/release-process.md index 9e2e02d81a..eb34e687e8 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -15,11 +15,11 @@ Release Process ###tag version in git - git tag -s v(new version, e.g. 1.3.0.0) + git tag -s v(new version, e.g. 2.4.0.0) ###write release notes. git shortlog helps a lot, for example: - git shortlog --no-merges v(current version, e.g. 1.3.0.0)..v(new version, e.g. 1.4.0.0) + git shortlog --no-merges v(current version, e.g. 2.3.5.0)..v(new version, e.g. 2.4.0.0) * * * @@ -32,7 +32,7 @@ Release Process From a directory containing the dynamic source, gitian-builder and gitian.sigs export SIGNER=(your gitian key, ie bluematt, sipa, etc) - export VERSION=(new version, e.g. 1.3.0.0) + export VERSION=(new version, e.g. 2.4.0.0) pushd ./dynamic git checkout v${VERSION} popd diff --git a/doc/zmq.md b/doc/zmq.md index 485cb8de01..71056d36ef 100644 --- a/doc/zmq.md +++ b/doc/zmq.md @@ -62,6 +62,8 @@ Currently, the following notifications are supported: -zmqpubrawblock=address -zmqpubrawtx=address -zmqpubrawtxlock=address + -zmqpubrawinstantsenddoublespend=address + -zmqpubhashinstantsenddoublespend=address The socket type is PUB and the address must be a valid ZeroMQ socket address. The same address can be used in more than one notification. diff --git a/dynamic-qt.pro b/dynamic-qt.pro index 0e4abb3a8f..2b2097d67c 100644 --- a/dynamic-qt.pro +++ b/dynamic-qt.pro @@ -1,6 +1,6 @@ TEMPLATE = app TARGET = dynamic -VERSION = 2.3.5.0 +VERSION = 2.5.0.0 INCLUDEPATH += src \ src/crypto \ src/crypto/heavyhash \ @@ -376,7 +376,6 @@ HEADERS += \ src/flat-database.h \ src/governance-classes.h \ src/governance-exceptions.h \ - src/governance-misc.h \ src/governance-object.h \ src/governance-vote.h \ src/governance-votedb.h \ @@ -629,21 +628,28 @@ RESOURCES += \ FORMS += \ src/qt/forms/addressbookpage.ui \ src/qt/forms/askpassphrasedialog.ui \ + src/qt/forms/bdapaddlinkdialog.ui \ + src/qt/forms/bdapadduserdialog.ui \ + src/qt/forms/bdaplinkdetaildialog.ui \ + src/qt/forms/bdappage.ui \ + src/qt/forms/bdapupdateaccountdialog.ui \ + src/qt/forms/bdapuserdetaildialog.ui \ src/qt/forms/coincontroldialog.ui \ + src/qt/forms/dynodelist.ui \ src/qt/forms/editaddressdialog.ui \ src/qt/forms/helpmessagedialog.ui \ src/qt/forms/intro.ui \ + src/qt/forms/miningpage.ui \ + src/qt/forms/mnemonicdialog.ui \ + src/qt/forms/modaloverlay.ui \ src/qt/forms/openuridialog.ui \ src/qt/forms/optionsdialog.ui \ src/qt/forms/overviewpage.ui \ + src/qt/forms/privatesendconfig.ui \ src/qt/forms/receivecoinsdialog.ui \ src/qt/forms/receiverequestdialog.ui \ src/qt/forms/rpcconsole.ui \ - src/qt/forms/privatesendconfig.ui \ src/qt/forms/sendcoinsdialog.ui \ src/qt/forms/sendcoinsentry.ui \ src/qt/forms/signverifymessagedialog.ui \ - src/qt/forms/dynodelist.ui \ - src/qt/forms/transactiondescdialog.ui \ - src/qt/forms/modaloverlay.ui \ - src/qt/forms/miningpage.ui + src/qt/forms/transactiondescdialog.ui diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/qa/rpc-tests/p2p-versionbits-warning.py index 6b8e42441d..336a5d65f4 100755 --- a/qa/rpc-tests/p2p-versionbits-warning.py +++ b/qa/rpc-tests/p2p-versionbits-warning.py @@ -1,5 +1,5 @@ #!/usr/bin/env python2 -# Copyright (c) 2016-2018 Duality Blockchain Solutions developers +# Copyright (c) 2016-2021 Duality Blockchain Solutions Developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index ee36c94969..3ddba1ff80 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -35,7 +35,7 @@ import dynamic_hash BIP0031_VERSION = 60000 -MY_VERSION = 70900 # past bip-31 for ping/pong +MY_VERSION = 71000 # past bip-31 for ping/pong MY_SUBVERSION = b"/python-mininode-tester:0.0.2/" MAX_INV_SZ = 50000 @@ -1158,6 +1158,7 @@ class NodeConn(asyncore.dispatcher): MAGIC_BYTES = { "mainnet": b"\xbf\x0c\x6b\xbd", # mainnet "testnet3": b"\xce\xe2\xca\xff", # testnet3 + "privatenet": b"\xce\xe2\xca\xff", # privatenet "regtest": b"\xfc\xc1\xb7\xdc" # regtest } diff --git a/share/pixmaps/dynamic.ico b/share/pixmaps/dynamic.ico index 1e14ae779b..41077a9faf 100644 Binary files a/share/pixmaps/dynamic.ico and b/share/pixmaps/dynamic.ico differ diff --git a/share/pixmaps/dynamic128.png b/share/pixmaps/dynamic128.png index 6cd22b8491..a3f9a03e07 100644 Binary files a/share/pixmaps/dynamic128.png and b/share/pixmaps/dynamic128.png differ diff --git a/share/pixmaps/dynamic128.xpm b/share/pixmaps/dynamic128.xpm index ce35b32678..da316b603b 100644 --- a/share/pixmaps/dynamic128.xpm +++ b/share/pixmaps/dynamic128.xpm @@ -1,160 +1,219 @@ /* XPM */ -static char *c862c2cce420458bb481fd2922127e4d[] = { +static char *_b695dc1b0ba4538a20093069021165f[] = { /* columns rows colors chars-per-pixel */ -"128 128 26 1 ", -" c #4F0070", -". c #530073", -"X c #580777", -"o c #570876", -"O c #580877", -"+ c #5A0C79", -"@ c #5E117C", -"# c #61157E", -"$ c #62187F", -"% c #631780", -"& c #641C81", -"* c #681F84", -"= c #672183", -"- c #6A2485", -"; c #6C2987", -": c #6D2688", -"> c #6E2C89", -", c #712D8B", -"< c #75328E", -"1 c #773690", -"2 c #783791", -"3 c #7B3B93", -"4 c #7F4196", -"5 c #804397", -"6 c #814598", -"7 c #84499A", +"128 128 85 1 ", +" c #5B0071", +". c #620077", +"X c #65007A", +"o c #6B007F", +"O c #6D0081", +"+ c #720085", +"@ c #760189", +"# c #79038B", +"$ c #7C0B8D", +"% c #7D128F", +"& c #7F0B90", +"* c #7F1490", +"= c #7F1F91", +"- c #7D2A8F", +"; c #800F92", +": c #831393", +"> c #851996", +", c #881A97", +"< c #871A98", +"1 c #891F99", +"2 c #862397", +"3 c #872098", +"4 c #8B229B", +"5 c #872898", +"6 c #8D299C", +"7 c #912B9F", +"8 c #8E359D", +"9 c #8F399F", +"0 c #903A9F", +"q c #9335A1", +"w c #943CA2", +"e c #983FA7", +"r c #9542A3", +"t c #9942A7", +"y c #9C43A9", +"u c #9D4BAA", +"i c #9F50AC", +"p c #A04EAE", +"a c #A151AE", +"s c #A25EAF", +"d c #A457B0", +"f c #A659B2", +"g c #A85EB3", +"h c #AB64B6", +"j c #AE67B8", +"k c #AF6BBA", +"l c #B16DBC", +"z c #B374BE", +"x c #B578BF", +"c c #B677C0", +"v c #B779C1", +"b c #B97EC2", +"n c #BB82C5", +"m c #BF8BC8", +"M c #C18DCA", +"N c #C595CD", +"B c #C897CF", +"V c #C599CD", +"C c #C89DCF", +"Z c #CA9DD2", +"A c #CCA3D3", +"S c #CEA9D5", +"D c #D1ACD7", +"F c #D2AED9", +"G c #D5B4DB", +"H c #D8B3DE", +"J c #D7B9DD", +"K c #DABCDF", +"L c #DCBEE1", +"P c #DEC3E3", +"I c #E0C6E4", +"U c #E3CBE6", +"Y c #E4CCE8", +"T c #E7D2EB", +"R c #E9D6EC", +"E c #EBDAEE", +"W c #EEDEF0", +"Q c #EFE0F1", +"! c #F2E6F4", +"~ c #F4EBF6", +"^ c #F6EDF8", +"/ c #F7F1F8", +"( c #FAF6FB", +") c #FFFFFF", +"_ c None", /* pixels */ -"................................................................................................................................", -"........................................X.....................................X...............X.................................", -"................................................................................................................................", -"..................................................................................................................X.............", -"................................................................................................................................", -".....................X..........................................................................................................", -"................................................................................................................................", -"...........................................................X....................................................................", -"..........................................................................................................X..................X..", -"................................................................................................................................", -"..................................................X.............................................................................", -".....................................................................X...............X..........................................", -"................................................................................................................................", -"................................................................................................................................", -"...............................X................................................................................................", -"...........................................X....................................................................................", -"................................................................................................................................", -"................................................................................................................................", -"................................................................................................................................", -".......................X........................................................................................................", -"................................................................................................X...............................", -"................................................................................................................................", -"................................................................................................................................", -"...................................................................................................................X............", -"...............X................................................................................................................", -"................................................................+X.......................................X......................", -"..............................................................o&;-@. ...........................................................", -".X......................................................... .&>>>,,=+...........................................................", -"...........................................................@;>,=+&;>>&o ........................................................", -"..........................X..............................+=>>;+@<=+=>>;%....................................................X...", -".......................................................o&;>>&O,7773#+;>>;+ .....................................................", -"......................................................#;>>-+ ;773477+.%;>>-+....................................................", -".................................................. .+;>>-#. +774+>77< .+$;>>$o..................................................", -"..........X.......................................+=>>;%. ..<77: X777# .o@=>>;#.................................................", -"........................................X........&;>>=O ...&774O. =773.....#;>>=@ .............................................", -"...............................................%;>>-+ .....377= ...377* ... O$;>;=+. ...........................................", -"........................................... .+->;;@...... ;772.... $755o .....O=>>;#. ..........................................", -"...........................................O&>>>&X.......+477# .....<77> .......@->>>@............X.............................", -".........................................o$;>>=O........ ,77<.......@757+.........#>,>=+........................................", -"........................................@->>-@. ....... +774+........>771......... o$>>>$O......................................", -".................................... .+=>>;@o ..........177:.........+477#...........+=>>;#. ...................................", -".......X............................O&>>;&o........... &774.......... *773........... .@->>;@. .................................", -"..................................o@;>>=+..............477&............377=.............o#>,>=+.......................X.........", -"............................... .@->>-@. .............;772............ #775X..............O$>>>$X...............................", -"...............................o=>>;#o ..............+447# .............<77> .............. +=>>:@..............................", -"...............................@>>&o................ 177,...............+775@.................#-,=..............................", -".............................. @>;o ............... @774+................;771................. #,=+.............................", -"...............................@>-..................177-................ o577$ ................#,&;& ...........................", -"...............................+>-X................&773...................*773X................#,&:6............................", -".............................. @>;.................477= ...................357: .............. #,&-7= ..........................", -"...............................+>-o.............. :772.................... #775+ ............. #>&=74O..........................", -"..........X....................@>; ..............+677+......................,77>...............#>&;77:.........................X", -"...............................+>-...............177,...................... +677# .............#>&-476+.........................", -"...............................@>-X............ #774O....................... :772..............#>&-7671.........................", -"...............................+>;X.............277- ........................o377* ............#>&-7667&........................", -".............................. @>-.............=773...........................&773X............#>&-76673 .......................", -"...............................@>-X ..........o474&............................277: .......... #>=-74667;.......................", -"...............................+>;............>771............................ #775+...........#>&-766674O......................", -"...............................+>;X..........+667+ .............................>77<...........$>&-766667,......................", -"...............................@>;...........177: ..............................+567# .........$>==7664677+.......X.............", -"...............................@>;..........%774O............................... -773..........$>&-76666672.....................", -"...X...........................@>-o........o367=..................................377* ........$>&-76666667=....................", -"...............................+>-.........-772...................................$774X........$>&-766666673X...................", -".......................X.......#>;........O477#....................................<77;........$>$-766666667:...................", -".............................. @>-........<77< ....................................@665@...... $>$-7666666666@ o................", -".............................. @>-X..... @675+..................................... ,77<.......$<$-7666566667<. ................", -"....X..........................@>;X......167> ......................................X577# .....$>=-76666666657# ................", -".............................. @>-..... $764X....................................... =773......$>$-766666666573 ................", -"...............................@>-o ...o467$..........................................377= ... $,$*766666665666- ...............", -".............................. @>;.... -773X..........................................#775O....$,$-7666666666665O...............", -".............................. @>-o...+566# .......................................... <77,....$,&-7666666666667, ..............", -"...............................@>;....,77<.............................................@575@ ..$>&*76666666666576@ .............", -"...............................@>-o. #576+............................................. >771...$>&-766666666666671..............", -".............................. @>;...277- ..............................................X567$ .$,&-766666666666667$.............", -"...............................+>-o $755X............................................... $763X $>&-7666657655666663X............", -"...............................@>;.o577$ ................................................X377- #>$-7566655576666667- ...........", -"...............................@>:.=771...................................................#755O#>&-75566666666666665X...........", -"...............................+>=#777@....................................................<77>#>&-76566666666666667,...........", -"...............................@>==77> .. .. ........... .. ... .. .. ........ ........ O57<#>&-766666566666666667@..........", -"...............................@>=$75#OO+X++O+O+Oo+X+X+++X++O+OO+X+++X+X+++X+X+++OOOOOOOOO+O<7<$>=-7666657566666666673..........", -"...............................@>=*75555555555555555555555555555555555555555555555555555555557<$>=-7666666666566666667$ ........", -"...............................@>:+,7777777777777777777777776777777777777757777757777757776773#$>$*76666666666666666665X........", -"...............................#>>:@#1333333332333333333331333332333332333333333333333333333$#$>>$=76665666666666666667: .......", -"................................@->>=+. ................................................. o$>,;##2766666666666666666666+.......", -"................................+$#:>;=+ .................................................$;>>$@-57666666666666666666667<.......", -"....X...........................o3,#$>>>$O..............................................@->>=#$37666666666656666666666667# .....", -"................................ #75-@$>>;#...........................................+=;>-##17666666666666666666666666572o.....", -"................................. ,773$#=>>=+...................................... o$>>;##,666666666666666666666666666667$.....", -"..................................+5677<$#;>>=O ..................................#;>>$@-576666666666665666576666666566675X....", -".................................. -76575;@$>>;$o ...............................@->>=@$37666666656666665766556566666666667> ...", -"...................................O4666774=@=>>;@............................ +=>>;##<7666666666666666665667755566666666666@ ..", -"................................... $76657571$#->,=+. ...................... o#>>;$@;576666666666666566666665557666666666667<...", -".....................................275555777<@$;>>$O. .................. .#;>>=+=575666666666666666666666666666666666666667$..", -".....................................@7577555575;@$>>;#o..................@=>>=@$277656666666666666666666666666666666666666672o.", -"..................................... ,75575555773$@=,>-@...............O$>,;##,7756666666666666566666666666666666666666666667* ", -"..............X.......................O5575577557772##->>=+ ..........o#;>>$@-5755666666666666666666666666566665666656666656675O", -"........................X............. -7666666666676,##;>;$+ ...o @;;>=@=476666666666666666666666666666666666666666666666667,", -"........................................376666666666675-@=>>-#. . +=>;;@$176666666666666666656666666666666666666666666666666666", -"........................................$7666666666666673$@->>-@ o=;>;$@>6764666666666666666666666666665666666665666666666566666", -".........................................17666666666666677<##;>>=;>;=@=676666666666466665666666666666666656666656666566666666666", -".........................................@566666556665756675>@#>>>=@=37666666666666666666666666666566666666666666666656666666666", -"......................................... ,7666677566656666774-@=##,666666666666666665666666666666666666666666566666666666666666", -"..X.......................................X466665566667566665773$>67666666666666666666666666666666666666666666666666666666666666", -".......................................... -766657666665666555577766666666666666666666666666666566666666666666666666666666665666", -"............................................376655576666666666667566666666666666664666666666666666666666666666666666666666666666", -"............X...............................#76657556666666666665766666646666666666666665666666666666666666666666666666665666675", -".............................................<7675756656566666665666666666666666666666666666666666666666656666666656666666666655", -"............................................ @6655756666666666666666666666666666666666666666666666666665666666666666666666666557", -"..............................................>755557575666666666666666666666666666666666666666666666666666666666666666666666657", -"..............................................O577755556666666666666566666666666666666666666666656666666666666666666666666666665", -".....................X.........................$75557666666666656666666666666666466666666665666666666666666666666666666666666656", -"................................................37575566666666666566666666666666666666666666666666666666666666655666566666666666", -"...........................X....................#7575666666666666666666666666665666666666666566666666566566666666666666666666666", -"................................................ <756666666665666666656666666666666656666666666666666666666666666666566666666665", -".............X.................................. +756666666666666666666666666666666666666666666666666666666666656666666666666666", -"..................................................;76666666666666666666666666666666666666656666666666666666666666666666666666666", -"..................................................X37556666566666666666666666666665666666666666666666666666666666666666666666666", -".................................................. $7566666666666666666666666666666666656666656656666666666666666665666666666666", -"...............................................X....1766666666666665666666566666666666666666666666666656666666666666666666656666", -"....................................................#766666666666666666666666666666666666666666666666666666666666666666666666666", -"......................X..............................<75666666666656666666656666666666666656666666666666666666666666666666665666", -".....................................................O57656666666666666666666666665666666666666666666666666666666656666666666666", -"..................................................... -7555766656666666666666666666666666666666666566666666666656666666666666666", -"..................................................... o3775566666666666666666666666666666666666666666666656666666666666666666666", -"......X............................................... $755666666666666666666666666666666666666566665666666666666666566666666666", -"........................................................176666666666566666666666666666666666666666566666666666666666666666666666", -"........................................................@76666656666666666666666666666665666666666666666666666666666666666666566", -"........................................................ >7666666666666666666566566666666666666666666666666666666666666666666666" +"____________________________________________________________11111111____________________________________________________________", +"_________________________________________________111111111111111111111111111111_________________________________________________", +"__________________________________________11111111111111111111111111111111111131111111__________________________________________", +"_____________________________________111111111111111111111111111111111111111111111111111111_____________________________________", +"__________________________________111111111111111111111111111111111111111111111111111111111111__________________________________", +"_______________________________111311111111111111111111111111111111111111111111111111111111111111_______________________________", +"____________________________111111111111111111111111131111111111111111111111111111111111111111111111____________________________", +"__________________________1111111111111111111111111111111111111111111111111111111111111111111111111111__________________________", +"________________________11111111111111111111111111111111111111111111111111111111111111111111111111111111________________________", +"______________________111111111111111111111111111111111111411111111111111111111111111111111111111111111111______________________", +"_____________________11111111111111111111111111111111111111111111111111111111111111111111111411111111111111_____________________", +"___________________111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111___________________", +"__________________11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111__________________", +"_________________1113111111111111111111111111111111111111111111111111111111111111111111111111111111131111111111_________________", +"________________111111111111111111111111111111111111111111111111111111111131111111111111111111111111111111111111________________", +"_______________11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_______________", +"______________1111111131111111111111111111111111111111111111114>,4111111111111111111111111111111111111111111111111______________", +"_____________1111111111111111111111111111111111111111111111341#$$#4311111111111111111111111111111111111111111111111_____________", +"____________111111111111111111111111111111111111111111111134;O8PI8O&631111111111111111111111111111111111111111111111____________", +"___________11111111111111111111111111111111111111111111144>O:M))))M*+,41111111111111111111111111111111111111111111111___________", +"___________1141111111111111111111111111111111111111111111+@h!))))))!h@+1411111111111111111111111111111111111111111111___________", +"__________111111111111111111111111111111111111111111144$+tI))))))))))ItO$441111111111111111111111111111111111111111111__________", +"_________11111111111111111111111111111111111111111114;o5S))))))))))))))S5o;44111111111111111111111111111111111111311111_________", +"_________111111111111111111111111111111111111111114>+%n))))))))))))))))))b%+,411111111111111113111111111111111111111111_________", +"________111111111111111111111111111111111111111144@+dW))))))))))))))))))))Wf++441111111111111111111111111111111111111111________", +"________1111111111111111111111311111111111111114$orK))))))))))))))))))))))))K0o$4411111111111111111111111111111111111111________", +"_______111111111111111111111111111111111111116;o1A))))))))W())))))))(Q))))))))A2o:411114111111111111111111111111111111111_______", +"_______1111111111111111111111111111111111114,+$z())))))))sl)))))))))(zs))))))))(x#+14113111111111111111111111111111111111_______", +"______1111111111111111111111111111111114144#+aE))))))))F-o~))))AA))))~o-F))))))))Ra+@3431111111111111111111111111111111111______", +"______11111111113111111111111111111111134$o0G))))))))Yu+ H)))))%$)))))H OuY))))))))G0o$44111111111111111111111111111111111______", +"______111111111111111111111111111111114:o>V))))))))~j#++y)))))BoOZ)))))y+@@l^))))))))V>o>411111111111111111111111111111111______", +"_____111111111111111111111111111111141+@k^))))))))V>o:1+T))))(:;*:/))))T@1:o>V))))))))^k#+,41111111111111111111111411111111_____", +"_____1111111111111111111111111111444@OuY))))))))G9o;44Ol)))))zo44Ol)))))lO64;O9G))))))))Yuo@4311111111111111111111111111111_____", +"_____11111111111111111111111111134;O8F))))))))Ri+#444;$/))))E@:43:@E))))/$;343@+aR))))))))F8O;41111111111111111111111111111_____", +"____1111111111111111111111111134>O%M))))))))(x#O,4434oN)))))y+6136+u)))))No4114,+#z())))))))M:O>4114111111111111111111111111____", +"____111111111111111111111111144+@hQ))))))))A2O:41114#6)))))K+111111OK)))))6#41114:o2A))))))))!h@@133111111111111111111111111____", +"____1111111111111111111111344$OtP))))))))Kw+$4311111OK)))))5#411114#5)))))Ko1111344$orK))))))))PtO$4411111111111111111111111____", +"____11111111311111111111114;O5A))))))))Wf+@14111114+u)))))No43111114oN)))))p+41133144@+fW))))))))S5o;44111111111111111111111____", +"___1111111111111111111114+$n)))))))))x$+,4411111111111111111111___", +"___111111111111111111114#@dW))))))))S5o;4311111134Oz)))))jo4111111114oj)))))xO4111111116;o5S))))))))Wd+#411111111111111111111___", +"___11111111111111111111;wK))))))))Ir+#44341111113$:())))T+>1111111114,+T))))(;$41111111134$+tI))))))))Kw;11111111111113111111___", +"___1111111111111111111>#W)))))))!h@@1411111111114oA)))))e@411111111114+e)))))Zo4111111111111+@h!)))))))W$>1111111111111111111___", +"__11111111111111111111>&T))))))m*O>4111111111114@q)))))Fo11111111111111OF)))))q@411111111111411111111111111111111__", +"__11111111111111111111>;Y))))J8O;41111111111143,OP)))))1#41111111111113$2)))))PO,41111111111334;o8J))))Y&>11111111111111111111__", +"__11111111111111111111>&Y))))5o4411111111111114+d)))))no4411111111111114on)))))d+4111111111111144X5))))Y&>11111111111111111111__", +"__11111141111111111111>&Y))))e#311111114111114:#!))))~$;4311111111111114;$~))))!$;411111111111114#e))))Y;:11111111111111111111__", +"__11111111111111111111>&Y))))e#411111111111133on)))))f+411114111111111114+f)))))bo411111111111113#t))))Y;:,1111111111111111111__", +"__11111111111111111111>&Y))))t#31111111111134$1())))I+,311111111111111113>OI))))(1$41111111111114#e))))Y;:11111111111111111111__", +"__11111111111111111411>;Y))))t#11111111111111OS)))))q@41111111111111111114@q)))))SO11111111111111#t))))U;>11111111111111111111__", +"_111111111111111111111:;Y))))t#4111111111114@e)))))Ao4111111111111111111114OA)))))w@4111111111113#e))))U;,111111111111111111111_", +"_111111111111111111111>;Y))))t#311111111113>+U))))(>$4111111111111111111114&>())))U+<341111111114#t))))U&:111111111111111111111_", +"_11111111111111111111,:;Y))))t#111111111434Oh)))))xo411111111111111111111144ov)))))hO411111111111#t))))U;:111111111111141111111_", +"_111111111111111111111>;Y))))e#41111111134;$^))))Q#:411111111111111111111113:@!))))^$;43111111113#t))))U;:,11111111111111111111_", +"_111111111111111111111:;Y))))t#31111111134OM)))))a+41111111111111111111111114+a)))))MO43111111114#e))))U;:111111111111111111111_", +"_111111111111111111111:;U))))t#1111111114#4)))))LO1111111111111111111111111111oP)))))3#4111111111#t))))U;>111111111111111111111_", +"_111111111111111111111:;U))))t#4111111111oG)))))6@4111111111111111111111111114@6)))))Go1111111113#t))))U;,111111111111111111111_", +"_111111111111111111111,;I))))t#311111114+t)))))Bo411111111111111111111111111114OB)))))t+611111114#t))))U;:,11111111111111111111_", +"_111111111111111111111,;Y))))t#11111111>@R))))/*%411111111111111111111111111114$;/))))R@>31111111#t))))U;>111111111111111111111_", +"_111111111111111111111:;U))))e#41111114Ol)))))lO41111111111111111111111111111136ol)))))lO41111113#t))))Y;:111111111111111111111_", +"_11111111111311111111,:;U))))t#3111114;%/))))R@>41111111111111111111111111111111>+R))))/;;4111114#e))))Y;>111111111111111111111_", +"1111111111111111111111:;U))))t#1111114oB)))))y+4111111111111111111111111111111116@y)))))NO4311111#t))))Y&:,111111111111111111111", +"1111111111111111111111:;U))))t#411114#6)))))JO141111111111111111111111111111111111OK)))))6#411113#t))))Y;>1111111111111111111111", +"1113111111111111111111,;U))))e#311111oK)))))4#431111111111111113111111111111111134#4)))))KO111114#t))))Y&>1111111111111113111111", +"1111111111111111111111:;U))))t#11114+p)))))Mo43311111111111111111111111111111111334oM)))))p+41111#t))))Y;<1111111111111111111111", +"1111111111111111111111:$U))))e#4143:@W))))^$;11111111111111111111111111111111111114&%/))))W@>1111#t))))U;:,111111111111111111111", +"111111111111111111111,,;Y))))t#3134ox)))))hO4111111111111111111111111111111111111114Oh)))))cO4111#t))))Y;:1111111111111111111111", +"1111111111111111111111:;Y))))t#114$:())))Y+>1111111111111111111111111111111111111114>OT))))(>$313#t))))U;:1111111111111111111111", +"1111111111111111111111>;Y))))t#414oA)))))w@711111111111111111111111111111111111111114@e)))))AO414#e))))Y;>1111111111111111111111", +"_111111111111111111111>&U))))t#34@q)))))Fo11111111111111111111111111111111111111111111OD)))))q+41#t))))Y&:111111111111111111111_", +"_111111111111111111111>&Y))))t#1,+I)))))1$31111111111111111111111111111111111111111113$1())))PO13#t))))Y;>111111111111111111111_", +"_111111111111111111111>&Y))))t#6Of)))))nO4311111111111111111111111111111111111111111114On)))))fO6#t))))Y&>111111111111111111111_", +"_111111111111111111111>&Y))))t#:#~))))!$;4111111111111111111111111111111111111111111111:$!))))~#:#t))))Y&>111111111111111111111_", +"_111111111111111111111>;Y))))t#On)))))fO711111111111411111111111111111111111111111111114Of)))))nO#t))))Y&>111111111111111111111_", +"_111111111111111111111:;Y))))yo3)))))PO,111111111111111111111111111111111111111111111114,OP)))))1oy))))Y&>111111111111111111111_", +"_11111111111111111111,>;Y))))t F)))))q@41111111111111111111111111111111111111111111111114@q)))))F y))))Y&>111111111111111111111_", +"_11111111111111111111,:;Y))))>2)))))AO4111111111111111111111111111111111111111111111111114oZ)))))2>))))Y&>111111111111411111111_", +"_111111111111111111111,;Y)))(2F))))(:$3311111111111111111111111111111111111111111111111114&:())))F>))))Y&>111111111111111111111_", +"_111111111111111111111:;Y)))~M)))))vO443111111111111111111111111111111111111111111111111114Ox)))))M!)))U&>111111111111111111111_", +"_11111111111111111111,>;U)))))))))W@:111111111111111111111111111111111111111111111111111113:@W)))))))))U&>,11111111111111111111_", +"__1111111111111111111,:;U)))))))))p@41411411411411411411114114111414111411411414114114114146+p)))))))))U&>11111111111111111111__", +"__14111111111111111111>;U))))))))S.&;&&;&&&&&&&&;&&;&&&&&&&&;&&;;;&&&&&&;&&;&&&&&&&&&;&&;$;;;.S))))))))Y&>11111111111111111111__", +"__11111111111111111111;;U)))))))(q%7664664746664664664746664664674746664664664744666467466467%q()))))))Y&>11111111111111111111__", +"__11111111111111111111>;U)))))))(!(((((()((((()((((()((((()((((((((((()((((()((()(((((((((((((!()))))))Y&>11111111111111111111__", +"__11111111111111111111>;U))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))Y&>11111111111111111111__", +"__11111111111111111111>;U))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))U&>11111111111111111111__", +"__1111111111111111111,>;T))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))Y&>11111111111111111111__", +"___1111111111111111111>$W)))))))))QU/)/(((((((((((((/(((((((((((((((((((((((/(((((((((((((((UW)))))))))W&>1111111111111111111___", +"___11111111411111111113;wL))))))))Ru+%7464466464664474444646464664466464466474646446646467$+uR))))))))Lw&11111111111111111111___", +"___111111111111111111114@+dW))))))))V>.@;;;;;;;;;;;;;;;;;;;;;;;;$;$;;;;;;;;;;;&;$;$;;&;;@.>V))))))))Wd+@441111111111111111111___", +"___1111111111111111111114,+$b)))))))))n%+,44,11>14,11>111111,111441111,1,1,,14,1441134>+%n)))))))))n$O,4111111111111111111111___", +"____11111111111111111111114;o5S))))))))Qf++1411111111111,111,111111111111111111111111@+gQ))))))))S5O;63311111111111141111111____", +"____1111111111111111111111144$otP))))))))Pro#41111111111111111111111111111111111114#OrP))))))))ItO#4411111111111111111111111____", +"____111111111111111111111111141@+h!))))))))A4O;4311111111111111111111111111111136:O5A))))))))!h@@141111111111111111111111111____", +"____1111111111111111111111111114>o%m)))))))))b$+>41111111111111111111111111,114,+;v)))))))))M%o>4111111111111111111111111111____", +"_____11111111111111111111111111116;o8F))))))))Wd+@1111111111111111111111111441@+dE))))))))F8o;44111111111111111111111111111_____", +"_____1111111111111111111111111111134#OuY))))))))Kw+;4111111111111111111111,4;+wK))))))))Yuo#4111111111111111111111111111111_____", +"_____111111111111111111111111111111141+#l^))))))))A2o;43411111111111111114;o2A))))))))^l@@,41111111111111111111111111111111_____", +"______111111111111111111111111111111114>O>V))))))))(x$+143111111111111141+$x())))))))V>O:611111111111111111111111111111111______", +"______11111411111111111111111111111111116$o9G))))))))Ea+#33111111111143#+aR))))))))G0o;41111111111111111111111111111111111______", +"______1111111111111111111111111111111111143@+pR))))))))Jqo$4411111144$o0J))))))))Ri+@4411111111111111111111111111111311111______", +"_______1111111111111111111111111111111111114,+$x())))))))C>o:443114:o>A))))))))(x$+,4311111111111111111113111111111111111_______", +"_______111111111111111111111111111111111111114:O2A))))))))(z#+,34,+#z/))))))))A2o;411111111111111111111111111111111111111_______", +"________1111111111111111111111111111111111111144$orK))))))))Ri+##+iT))))))))KrO$4133111111111111111111111111111111111111________", +"________111111111111111111111111111111111111111141@+fW))))))))G25G))))))))Wf+#141114111111111111111111111111111111111111________", +"_________111111111111111111111111111111111111111114>+$n))))))))))))))))))n%+>411111111111111111111111111111111111111111_________", +"_________11111111111111111111111111111111111111111134;O8S))))))))))))))S5O;43311111111111111111111111111111111111111111_________", +"__________111111111111111111111111111111111111111111114$otP))))))))))Pto#441411111111111111111111111111111111111111111__________", +"___________1111111111111111111111111111111111111111111143+@h!))))))!h@@1411111111111111111111111111111111111111111111___________", +"___________11111111111111111111111111111111111141111111134>O:M))))N;o>43111111111111111111111111111111111111111111111___________", +"____________111111111111111111111111111111111111111111111444;oqLP8o;444311111111111111111111111111111111111111111111____________", +"_____________1111111111111111111111111111111111111111111111134#;$#4111111111141111111111111111111111111111111111111_____________", +"______________1111111111111111111111111111111111111111111111314>>4111111111111111111111111111111111111111111111111______________", +"_______________11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_______________", +"________________111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111________________", +"_________________1131111111111111111111111111111111111113111111111111111111111111111111111111111111111111411111_________________", +"__________________11111111111111111131111111111111111111111111111111111111111111111111111111111411111111111111__________________", +"___________________111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111___________________", +"_____________________11141111111111111111111111111111111111111111111111111111111111111111111111111111111111_____________________", +"______________________111111111111111111111111111111111111111111111111111111111131111111111111111111111111______________________", +"________________________11111111111111111111111111111111111111111111111111111111111111111111111111111111________________________", +"__________________________1111111111111111111111111111111111111111111111111111111111111111111111111111__________________________", +"____________________________111111111111111111111111111111111111111111111111111111111111111111111111____________________________", +"_______________________________111111111111111111111111111111111111111111111111111111111111113111_______________________________", +"__________________________________111111111111111311111111111111111111111111111111111111111111__________________________________", +"_____________________________________111141111111111111111111111111111111111111111111111111_____________________________________", +"__________________________________________11111111111111111111111111111111111111111111__________________________________________", +"_________________________________________________111111111111111111111111111111_________________________________________________", +"____________________________________________________________31111111____________________________________________________________" }; diff --git a/share/pixmaps/dynamic16.png b/share/pixmaps/dynamic16.png index 877510c859..b4200604a6 100644 Binary files a/share/pixmaps/dynamic16.png and b/share/pixmaps/dynamic16.png differ diff --git a/share/pixmaps/dynamic16.xpm b/share/pixmaps/dynamic16.xpm index 3e1b931e79..8fc6c8dfda 100644 --- a/share/pixmaps/dynamic16.xpm +++ b/share/pixmaps/dynamic16.xpm @@ -1,278 +1,113 @@ /* XPM */ -static char *_494762459176[] = { +static char *_410372df6e04863afbb9d3a6a4a7ced[] = { /* columns rows colors chars-per-pixel */ -"16 16 256 2 ", -" c #530073", -". c #530074", -"X c #540074", -"o c #540074", -"O c #540074", -"+ c #540074", -"@ c #540074", -"# c #540074", -"$ c #540074", -"% c #540074", -"& c #540074", -"* c #540074", -"= c #540074", -"- c #540074", -"; c #530074", -": c #530073", -"> c #530074", -", c #530075", -"< c #540075", -"1 c #540075", -"2 c #540075", -"3 c #540075", -"4 c #540075", -"5 c #540075", -"6 c #540075", -"7 c #540075", -"8 c #540075", -"9 c #540075", -"0 c #540075", -"q c #540075", -"w c #530075", -"e c #530074", -"r c #540074", -"t c #540075", -"y c #550075", -"u c #550075", -"i c #550075", -"p c #550075", -"a c #540075", -"s c #530074", -"d c #530074", -"f c #540075", -"g c #550075", -"h c #550075", -"j c #550075", -"k c #550075", -"l c #540075", -"z c #540074", -"x c #540074", -"c c #540075", -"v c #550075", -"b c #550075", -"n c #540075", -"m c #540074", -"M c #550376", -"N c #61137F", -"B c #641881", -"V c #560476", -"C c #540074", -"Z c #540075", -"A c #550075", -"S c #550075", -"D c #540075", -"F c #540074", -"G c #540074", -"H c #540075", -"J c #550075", -"K c #540075", -"L c #550275", -"P c #5A0B7A", -"I c #5C0C7B", -"U c #681E85", -"Y c #692086", -"T c #5E0F7C", -"R c #5B0B7A", -"E c #560376", -"W c #540074", -"Q c #550075", -"! c #540075", -"~ c #540074", -"^ c #540074", -"/ c #540075", -"( c #540074", -") c #560376", -"_ c #5D0E7C", -"` c #560576", -"' c #5F117E", -"] c #5E0F7D", -"[ c #590778", -"{ c #631781", -"} c #550375", -"| c #5D0E7C", -" . c #570677", -".. c #540074", -"X. c #540075", -"o. c #540074", -"O. c #540074", -"+. c #540075", -"@. c #540074", -"#. c #580678", -"$. c #590879", -"%. c #550275", -"&. c #671C83", -"*. c #540174", -"=. c #520073", -"-. c #641882", -";. c #5A0879", -":. c #560476", -">. c #6C2488", -",. c #540175", -"<. c #540074", -"1. c #540074", -"2. c #540074", -"3. c #540075", -"4. c #540074", -"5. c #580678", -"6. c #580678", -"7. c #631680", -"8. c #5C0B7B", -"9. c #530074", -"0. c #540074", -"q. c #570577", -"w. c #661A83", -"e. c #550275", -"r. c #7B3B94", -"t. c #651982", -"y. c #520073", -"u. c #540074", -"i. c #540074", -"p. c #540075", -"a. c #540074", -"s. c #570477", -"d. c #5F117D", -"f. c #631681", -"g. c #520073", -"h. c #540074", -"j. c #540074", -"k. c #510072", -"l. c #60117E", -"z. c #60127E", -"x. c #793992", -"c. c #7D3E96", -"v. c #550375", -"b. c #530074", -"n. c #540074", -"m. c #540075", -"M. c #540074", -"N. c #560476", -"B. c #6C2487", -"V. c #5D0E7C", -"C. c #5A0979", -"Z. c #5B097A", -"A. c #5B097A", -"S. c #5A097A", -"D. c #5B0A7A", -"F. c #692086", -"G. c #793892", -"H. c #874C9E", -"J. c #6A2186", -"K. c #510072", -"L. c #540074", -"P. c #540075", -"I. c #540074", -"U. c #550276", -"Y. c #6D2688", -"T. c #651A82", -"R. c #60127E", -"E. c #62147F", -"W. c #621480", -"Q. c #60127E", -"!. c #621680", -"~. c #6F298A", -"^. c #7E4097", -"/. c #85499B", -"(. c #804197", -"). c #5A0979", -"_. c #540074", -"`. c #540075", -"'. c #550075", -"]. c #520073", -"[. c #661B83", -"{. c #793892", -"}. c #60137E", -"|. c #520073", -" X c #510072", -".X c #5C0E7B", -"XX c #722E8D", -"oX c #814499", -"OX c #84479B", -"+X c #83459A", -"@X c #85499B", -"#X c #742F8E", -"$X c #540074", -"%X c #540075", -"&X c #550075", -"*X c #540074", -"=X c #540175", -"-X c #7B3A94", -";X c #84499B", -":X c #712C8C", -">X c #6E2789", -",X c #804398", -" c #810E91", +", c #800F91", +"< c #811193", +"1 c #831293", +"2 c #821393", +"3 c #841395", +"4 c #861696", +"5 c #811993", +"6 c #821993", +"7 c #811A93", +"8 c #851D96", +"9 c #891A99", +"0 c #8A1A99", +"q c #8A1A9A", +"w c #891E99", +"e c #891F99", +"r c #8A1C9A", +"t c #891F9A", +"y c #872497", +"u c #892099", +"i c #8A209A", +"p c #8A219A", +"a c #8C229B", +"s c #8C239C", +"d c #8C249C", +"f c #8D249C", +"g c #8C379B", +"h c #8C3B9C", +"j c #8D3B9C", +"k c #8F3C9E", +"l c #8E3F9E", +"z c #902BA0", +"x c #922EA1", +"c c #8E409E", +"v c #974BA6", +"b c #9F43AB", +"n c #9E44AB", +"m c #A04AAD", +"M c #A24BAE", +"N c #A054AD", +"B c #A154AD", +"V c #A264AE", +"C c #A265AE", +"Z c #A774B3", +"A c #AD7DB8", +"S c #B176BC", +"D c #B178BC", +"F c #B57ABF", +"G c #B47BBF", +"H c #B47CBE", +"J c #B280BC", +"K c #B281BC", +"L c #BA82C4", +"P c #C797CF", +"I c #C99FD1", +"U c #C3A0CB", +"Y c #C6A3CD", +"T c #C9A0D0", +"R c #CBA2D2", +"E c #CFAFD6", +"W c #D0A7D7", +"Q c #CBB3D2", +"! c #D5B8DB", +"~ c #D6B8DB", +"^ c #D6BADC", +"/ c #D6BBDC", +"( c #D5C0DB", +") c #D5C1DB", +"_ c #D5C2DB", +"` c #DFCCE3", +"' c #E6D7E9", +"] c #F2E6F4", +"[ c #F2EAF3", +"{ c gray100", +"} c None", /* pixels */ -" . X o O + @ # $ % & * = - ; : ", -"> , < 1 2 3 4 5 6 7 8 9 0 q w e ", -"r t y u i p a s d f g h j k l z ", -"x c v b n m M N B V C Z A S D F ", -"G H J K L P I U Y T R E W Q ! ~ ", -"^ / ( ) _ ` ' ] [ { } | ...X.o.", -"O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", -"2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.u.", -"i.p.a.s.d.f.g.h.j.k.l.z.x.c.v.b.", -"n.m.M.N.B.V.C.Z.A.S.D.F.G.H.J.K.", -"L.P.I.U.Y.T.R.E.W.Q.!.~.^./.(.).", -"_.`.'.].[.{.}.|. X.XXXoXOX+X@X#X", -"$X%X&X*X=X-X;X:X>X,Xu", +"unDYM+ee#mYDn;u", +"u>z]JXe88eXJ]zj)Qg=;gQ)j>ue", +"}uf*%SECCES%*fu}", +"}ues9OyTTyO9see}", +"}}eees3*#4feee}}", +"}}}}eeeuueee}}}}" }; diff --git a/share/pixmaps/dynamic256.png b/share/pixmaps/dynamic256.png index b754b29fcd..74e28b0694 100644 Binary files a/share/pixmaps/dynamic256.png and b/share/pixmaps/dynamic256.png differ diff --git a/share/pixmaps/dynamic256.xpm b/share/pixmaps/dynamic256.xpm index d0b8550a68..6ba48354df 100644 --- a/share/pixmaps/dynamic256.xpm +++ b/share/pixmaps/dynamic256.xpm @@ -1,289 +1,332 @@ /* XPM */ -static char *c790c53714894897d42bbd7cd25107f6[] = { +static char *c55f9f7888564ba8927f597b503cd8ff[] = { /* columns rows colors chars-per-pixel */ -"256 256 27 1 ", -" c #4E006F", -". c #4F0070", -"X c #530073", -"o c #580777", -"O c #570877", -"+ c #580977", -"@ c #5B0D7A", -"# c #5E127C", -"$ c #61167E", -"% c #62187F", -"& c #631780", -"* c #651D82", -"= c #681F84", -"- c #672083", -"; c #6A2586", -": c #6C2987", -"> c #6D2688", -", c #6D2B88", -"< c #712D8B", -"1 c #75338E", -"2 c #773690", -"3 c #783790", -"4 c #7B3C93", -"5 c #7E4195", -"6 c #804397", -"7 c #814598", -"8 c #84499A", +"256 256 70 1 ", +" c #5C0072", +". c #630078", +"X c #69007D", +"o c #6F0082", +"O c #720085", +"+ c #760089", +"@ c #7A038C", +"# c #7D098F", +"$ c #7F0C90", +"% c #800E91", +"& c #831494", +"* c #861A96", +"= c #871C98", +"- c #891F99", +"; c #8A219A", +": c #8E2A9E", +"> c #902D9F", +", c #912FA0", +"< c #9333A2", +"1 c #9639A5", +"2 c #993DA7", +"3 c #9A3FA8", +"4 c #9C44AA", +"5 c #9F49AC", +"6 c #A14CAE", +"7 c #A250AF", +"8 c #A554B1", +"9 c #A854B4", +"0 c #A758B3", +"q c #A95CB5", +"w c #AC62B7", +"e c #AD64B9", +"r c #AF69BA", +"t c #B16BBC", +"y c #B573BF", +"u c #B675C0", +"i c #B877C1", +"p c #BA7CC3", +"a c #BD82C6", +"s c #BF85C8", +"d c #C087C9", +"f c #C28BCA", +"g c #C692CD", +"h c #C897CF", +"j c #C897D0", +"k c #CA9BD1", +"l c #CEA2D4", +"z c #D0A7D7", +"x c #D1A8D7", +"c c #D3ACD9", +"v c #D6B2DC", +"b c #D8B5DD", +"n c #DAB9DF", +"m c #DCBDE1", +"M c #DFC2E3", +"N c #E1C6E5", +"B c #E3C9E7", +"V c #E5CEE9", +"C c #E6D0EA", +"Z c #E9D5EC", +"A c #ECDBEE", +"S c #EEDEF0", +"D c #EFE0F1", +"F c #F1E5F3", +"G c #F4EBF6", +"H c #F7EFF8", +"J c #F7F0F8", +"K c #FAF6FA", +"L c #FFFFFF", +"P c None", /* pixels */ -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @%@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX O-,,,%o XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO%:,:,,,:$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#;,,::::::,;#X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+-,,::::,::::::-+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX O*:,::::,:%:,::::,:%o XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%;,::::,:%X +%,,::::,:$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#;,:::::,*o $1# +-,,::::,;@oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+-,,,,::,;@X@<888,o #:::::::,%oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo%:,::::,:$XX,8886885;XX%:<,:::::%o XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX$:,::::,:%+ #68866668775@ +%,,::::<;#X X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX$>::::::,-+X.o4877788867786oXX@;,,::::,;@ oXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+*:,::::,;#XXXX;877776>667778> XX $:,::::><%oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX o%:,::::,:%XXXXX@577778, :877777@XXX o%:,::::,:%X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#:,,:,:,,%+XXXXXX,877776oXo7777781XXXXXX@-,,::::,;$X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@;,:::,,,;@X XXXX $877768-XXX%877777$ XXXX X#;:::::,,-@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +%,,::::,;#X XXXXXXX3877784oXXXX4877783oXXXXXX X#:,::::<>%o XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX$:,::::,:%XXXXXXXXX -866788% XXXX$877778= XXXXXXXX+%:,::::,:$X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#:,:::::,-+XXXXXXXXXXo6866782XXXXXXX1877776oXXXXXXXX X#-,,::::,;#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@-,::::::;@XXXXXXXXXXXX;868686@XXXXXX @777778>XXXXXXXXXXXX#;,::::,,%@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo%,,::::,:#X XXXXXXXXXXXo686688,XXXXXXXXX>877777@XXXXXXXXXXXXX%:,::::,,%oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX$:,::::,:%oXXXXXXXXXXXXXX<866686oXXXXXXXXXo4777782XXXXXXXXXXXXXXo%,,::::,:$X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#=,::::::-@X XXXXXXXXXXXX $886868- XXXXXXXXXX%877777%XXXXXXXXXXXXXXX@=,,:::::;#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+-,,::::,;#XXXXXXXXXXXXXXXXX3866684XXXXXXXXXXXXo2877784XXXXXXXXXXXXXXXXo#;,:::::,*+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX o%:,::::,:#oXXXXXXXXXXXXXXXXX-868688$ XXXXXXXXXXX #877778; XXXXXXXXXXXXXXXXo%:,::::,,%o XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX$:,::::::%+XXXXXXXXXXXXXXXXXX+586688XXXXXXXXXXXXXXXX ;877777# XXXXXXXXXXXXXXXXXXXX%::::::,,%+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo%::::::::%o XXXXXXXXXXXXXXXXXXXXX1876684XXXXXXXXXXXXXXXXXXo4777782XXXXXXXXXXXXXXXXXXXXX +%::::::,,%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#-::::::,-+XXXXXXXXXXXXXXXXXXXXXXX$877788%XXXXXXXXXXXXXXXXXX %877778% XXXXXXXXXXXXXXXXXXXXXX+-,:::::,;#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @-::::::,-#X XXXXXXXXXXXXXXXXXXXXXXX4877784XXXXXXXXXXXXXXXXXXXXX3877774oXXXXXXXXXXXXXXXXXXXXXXXX#;,::::,,*@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo%:,::::<:$XXXXXXXXXXXXXXXXXXXXXXXXXX=877778$ XXXXXXXXXXXXXXXXXXXX$877777:XXXXXXXXXXXXXXXXXXXXXXXXXX$:,,::,,,%+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X%:<::::::%o XXXXXXXXXXXXXXXXXXXXXXXXXo587778 XXXXXXXXXXXXXXXXXXXXXXXX=886867$XXXXXXXXXXXXXXXXXXXXXXXXXXXX $;,:,:,,,%+X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+%:,::::,:#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2867784oXXXXXXXXXXXXXXXXXXXXXXXXXo4868682XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo$,,::::,:%oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#:,::::::*oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%868788%XXXXXXXXXXXXXXXXXXXXXXXXXX %866878% XXXXXXXXXXXXXXXXXXXXXXXXXXXX X+%:,::,,,:$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#-,,:::,:-@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4877782XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1886685oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@;::::::,;@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%::::::::#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX;877768$ XXXXXXXXXXXXXXXXXXXXXXXXXXXX#886867;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X$;,::::,:$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-::::::%oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@577778866666+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo%::::::%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%,::,%+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ,877786@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+686888 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-866668$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo:::,%o@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo *,::; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2877784XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4868883XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX;:::%o,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,:::oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX %877778%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX %866668% XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;::,%X6%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,:::XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo4877783XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1868686@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+;,:,%o64XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,:::XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;877778#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@777778,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+:::,%X58> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%,::;oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@687778, XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX >877777@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:::,%X686@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-::::XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<867776oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo4777781XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,:,%o568,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,::;+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX$877778= XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo%877778$ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo;::,%X5887$ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%,::;X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4877784XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4877784oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo:,:,%X68673XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,:::XoXXXXXXXXXXXXXXXXXXXXXXXXXXXXX %877778$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $877778; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo-:::%X56678% XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,::;oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo6867781 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,867775oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+:::,%X686685XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%,:::XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX>886786@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@687788, XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:::,$X686668: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX *,:,;oXXXXXXXXXXXXXXXXXXXXXXXXXXXX #777778> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX;877778$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:,:,$X5777777@XXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo *,::;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1877785oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX5877683XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:::,$o5777778 XXXXXXXXXXXXXXXXXXXXXXXXXXo:::,%o577777768%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXX -,:,;oXXXXXXXXXXXXXXXXXXXXXXXXXXo6777781XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX :877686oXXXXXXXXXXXXXXXXXXXXXXXXXXo;,:,%X6677777786oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,:,;XXXXXXXXXXXXXXXXXXXXXXXXXX <877786@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo677668::,%X5877777778,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%,:,;oXXXXXXXXXXXXXXXXXXXXXXXXX#777778> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX;878666$XXXXXXXXXXXXXXXXXXXXXXXXXX:::<%X66777777776@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,:::XXXXXXXXXXXXXXXXXXXXXXXXXX1877785oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo4866683XXXXXXXXXXXXXXXXXXXXXXXX o::,,$o567777777781XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,:,;XXXXXXXXXXXXXXXXXXXXXXXXX%877778%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX$886868%XXXXXXXXXXXXXXXXXXXXXXX o;,;,$X577777777777% XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%,::;+XXXXXXXXXXXXXXXXXXXXXXXo4777781XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<866886o XXXXXXXXXXXXXXXXXXXXXXo:::,$o5877777777785XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -,::;XXXXXXXXXXXXXXXXXXXXXXXX;877778# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $866668> XXXXXXXXXXXXXXXXXXXXX +:::,%X5776777777768; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,:,;+XXXXXXXXXXXXXXXXXXXXXXo687778877787@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @686668,XXXXXXXXXXXXXXXXXXXo::::%o56677777777777768;XXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXX%,:,;+XXXXXXXXXXXXXXXXXX@677778, XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:868686@XXXXXXXXXXXXXXXXXXo:::,$X586777677777777786oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,::: XXXXXXXXXXXXXXXXXX1877785oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo6866683XXXXXXXXXXXXXXXXXXo::::%X668777777777777778.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX>877777#.XXXXXXXXXXXX +,::,%X5876777777777777777688OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,,,,XXXXXXXXXXXXXXX2777775OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo4877781XXXXXXXXXXXXXX+,:::%o57777777777777777777881.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,;,;XXXXXXXXXXXXX.&777778=.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.&885878&.XXXXXXXXXXXXO:::,%X57777777777777777777688#.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,;OXXXXXXXXXXXXX4777784OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO1885784oXXXXXXXXXXX O,::,#X587777777777777777768684.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.-,,,;XXXXXXXXXXXX.=777777&.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.#877778-.XXXXXXXXXX O,:::%O577777777777777757767778-.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,;OXXXXXXXXXXXO777777858777#XXXXXXXXXX+,::,&X57777777785777777777777888#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,:,;OXXXXXXXXXX2877775OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO4857781XXXXXXXXX.O,::,#X587777777777777787777775882.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,:,-OXXXXXXXXX%777778*.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.&857778&XXXXXXXXXO,::,&O577777777777777757757778578*.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.*,,,;XXXXXXXXXO5877772XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1877784OXXXXXXXXO,::,#X5775858577777787757877777784XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,;O.XXXXXX.;777777#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.#887778;.XXXXXXXO:::,%o5778588877777757787777777778>.XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,;,;OXXXXXXXO5777771XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.<858786@XXXXXXX+:::,%O48858757775777777777777777786OXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,;XXXXXXXX<777775@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO.+587758.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.-877777$.XXXXXO,::,%O485588585858885858877777777777&.XXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,;,;OXXXXXX1877784OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO4877683OXXXX.O,::,%.5788558585885585885777777777782XXXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,;XXXXX.*877778&.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&777778&.XXXX+,::,%X5775858858558558858775777777788-.XXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,;OXXXXO4877782XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1877684OXXX.O,::,#o58785855858858855857787777577584OXXXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,:::..XXX;877786#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@587778>XX..+,::,&X57758588588588585857777777777778>.XXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,:,:OXXX@587778,.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,877786@.OX+,:,,$o487888558558858588877775777777785@XXXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=,::-OXXX,858787OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO4877781XO.O:::,$O5778585857758855858777787777777781.XXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,:::XX.#787778;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.-877777&..O:::,&X4875858587785588585777777777777778&XXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.*,,,;XXX2877783XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO4777784XXO:::,#O48777777587558585858858777777777782XXXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,;O.*877778&XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.#878578-.O:::,%X57777777777885885585885777777777778-XXXXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,;XO4877781.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXX1858585OO>::,%X585777777855885585885587777777777785OXXXXXXXoXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-,;,;X;877777@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@678858;O>::,%O588777777778588858858857857777777778,.XXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,;:X187858>.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO.XXXXXXXXXXXXXXXXXXXX.>85885;O::;,%O4857758777758885885855877777777777787@XXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,-X187785OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.OXXXXXOXXXXXXXXXXXXXXXo55588;X::,,%O58577777777855885585885777777777777781XXXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.-,,,:X<8778*.XXX..XX.X.X..XXXX.XXXXX.XXXXXXXXXXXXXX.XXXXXXXX.XXX. XXXXXXXX XXXX XXXXXXXXXXXXXXXXX..X..X.XXX.XXXXX.XX.X..&8588>O;::,#X55877777757558558858858777777777777778&XXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,-X<8785*@@@#@#@##@##@##@@@#@@@#@@@@#@@@#@#@###@@@#@@@@#@@@@#@@@#@@@##@##@#@@#@@@@@@#@@@#@#@###@##@##@@@#@@@@#@@@@#@@@*5858;O:::,%X585587777878858855858857777777777777784OXXXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXXXXO.XXXXX-,;,:.<88777778785858858585858588777777778787787788777877777788778886877777777787777877778786885886778858888588777777787777778>O:,,,$O577777777777777777777777777777777777778;.XXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,,,-X187777785778585775888585885777777778777777777777777777778776686857777777777777777776786588558775885858558777777857777778:O>;,,&X5877776777777777777777777677777777777775@XXXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,:::X$58777757778585777758588858777777777777777777777777777777776666585877777777777777777766585877778558585877777777777877883+O,,,,$O5777777777776777777777777777777777777778<.XXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*,:::$.O,7877877758587775858555857777777777777777777777777777777786868585777777777777777776688585777758858585777777777775885>X.*:,;,&X57777777777777777777777777777777777777788#.XXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.O.-,:,,,-@.#2788888885888888888888877877777887878777888888877778787888887888888878888887888888888888888888888888888888888885<+X#:,:,,,$O477777777777777777777777777777777777777782XXXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.O&,,;;,,,*O.&1111122221221111122122222222111112211211111111122212111111111111112111111111111111111111111111111111111111121#.O-,:::;,,#X577777777777777777777777777777777777777778*.XXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO%:,;,,,,:%O..X.XX.X..X.X...XX..XX..XX.XX.X.XX.X.X..XXX...XXXX.XXXXX XX.XX.X.XXX X..XX.XXXXX..X.XX.X.X.X....XX..X.XX..X..O*::::::,,#.$7777777777777777777777777777777757777777775OXXXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.O*,,;,,::;#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%>:::::,:%XX,77777777777777777776777777777777777777777778>.XXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO$.O;,,::::,-#.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#;,;,,,,,*O.%58777777777777777777777777777777777777777777776@XXXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXXXX.OXXXX.,4#.#>:::::,:*OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XO-,,:,,,,-@.$27877777777777777777777777777777777777777777777781.XXXXXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.O58OX%<:::::::$OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO&:,::,;,,#.O,787777777777777777777777777777777777777777777777777777776668,.XXXXXXXXXX", -"XXXXXXXXXXXXoXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXX@77777785*.O-,,::::,;@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.X#;,::::,,*XX;587777777777777777777777777777777777777777777777777777777778688@XXXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.=877777883@X#;,::::::-OX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@-,,:::,,-O.$488577777777677777777777777777777777777777777777777777777777777781.XXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO4877777787<+X#::::::,:*OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XO*:,:,:,,;#.+28855877777777777777777776777777777677777777777777777767777777778678*.XXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.&87777777785;OO%,,::::::#OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO%:,:::,,:#.O<8855888775777787777777777777777777777776777777777777777777777777766784XXXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2877777778854*.O;,:::::,-@X.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#;,::::,,*O.*585588585778777757777777777777777777777777777777777777767777777777777688;.XXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.#77777777588882#.#>,:::::,*O.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@-,,::::,;@.#588858558585857585877777777777777777777777777777777777777777777777777777785OXXXXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.,87777778558588&O.XX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO%:,::::,:#.O<88858588585858588858858855877777777777777777777777777777777777777677777777777777777684XXXXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX287778858588558588855=XO-,,;,,;,;#X.OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#;,::::,,%oX-5855858885858855885855885585877767777777777677777777677777777777777777777777777777777778>.XXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO7777858585858585555884#.@;,,,,,,,=O.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#;,::::,,-O.#4878585858585885858585885888588777777777777777777767777777777777777777777767777777777777786@XXX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.,8585858585858858858788<@.$;,;,,;,,*O.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+*,,::::,;# @188758758588585858585855858585885777777777777777777777776777777777777777777777777777777777778&XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo%::::::,:%Xo,88857777858585585888585885858885587777777777777777777777777777777677777777777777777777777777778#XX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.-8885858585588585587777785*.O-,,;,;,,;@XXXXXXXXXXXXXXXXXXXXXXXXXXX#;:::::,:*oX*58875877777858588585585888588585588577777777767777777777777777777777776777777777777777777777777784XX", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO.485858585885585885777777882#.#;,,,;,,,-OXXXXXXXXXXXXXXXXXXXXXXX@-,::::,,-@.#3875778577775885855858858558855858855877777777777777777777777777777777777777777777777777767777777778*.", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&777777777777777777777777778,,,,,,,%O...OXXXXXXXXXXX..O.O*,,,;,,,;#.O,777777777777777777757777777777777777777777777777777777677777775777777777767777777777777777777777777774O", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.18777777777777777777777777785;XO*,,,,;,,;#.X.XXXXXXXXXXXO..%;,,;>,,,%.O,78777777777777777777777777777777777777777777777777777777777777777777777777777777777777777776777777777778,", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@777777777777777777777777777784&.O-,,,,;,,-@XXX..XXXXXX..#;,,,,>,,*O.*48787777777777777777777777777777777777777777776777777777777777777777777777777777777777677777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX>8777777777777777777777777777782#.#>,;,,,,<*OXX.XXXXXXO-,>,,;,,;O.#2887777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX57777777777777777777777777777787,O.#:>,,,>,,%O.XXXXO*,,>,,,,;#.O,88777777777777777777777777777777777775777777777777777677777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*877777777777777777777777777777785-.O-,,>>>,,;@X.X&;,;,,;,,%OO-7887777777777777777777777777777777777777777777777777777767777777777777777777777777777777777777777777776777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX28777777777777777777777777777777884#.@-,,,;;,,;#;,,,,;,,-O.%487777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#777777777777777777775777777777777882O.#,,,,,,>,,>;,,,;#.O<8877777777777777777577777777777777777777777777777777777777777777777777777777777777777777776777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.<877777777777777777777777777777777787>OO*>,,,,:,::::#.O,787777777777777777777777777777777777777777777777777777777777777777777777757777777777777767767777776777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO77777777777777777777777777777777777774*.O-,>::>,,*O.*78877777777777777777777777777777777777777777777577777777777777777777777777777777777777777777777777777777777767777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX>877777777777777777777777777777777777782#.#;,,,-O.#2777777777777777777777777777777777777777777777777777777776777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX58777777777777777777777777777777777777887877777777777777777777777777777777777777777777777777777777777777777777776777777777777777777777776777777777777677777777777777", -"XXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXX28777777777777777777777777777777777777777842487777777777777777777777777747777777777777777777757777777777777777777777777777777777777777777777777777777777777777777777776777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.O8777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777677777777777777777777777777777777777767777777777777767777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO>877777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777775777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.;87777777777777777777777777777777775777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777767777777777777777777776777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX48777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.&8777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777767777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<877777777777777777777777775777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777775777777777777777777777777777777777777777677", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.#877775777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.>87777777777777777777777777777777777777777777777777777777777777777777777777757777777777777777777777777777777777777777777777777775777777777777677777777767777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO58777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.=8777777777777777777777777777777777777777777777757777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777677777777", -"XXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4877777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777757777777777577777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.&877777777777777777777777777757777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777776776777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXX.OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<87777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777677777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO.O.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.OXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX>8777777777777777777777777777777777757777777777777777777777747777777777777777777777757777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO5777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*877777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777767777777776777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777767777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.&87777777777777777777757777777777777777777777777777777777777777777577777777775777777777777777777777777777777477777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX28777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777477777777777776777777777777777777776777777767", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777577777777777777777777777777777777777777777777777777677777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.>887777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXX.O487777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777767777777777777777777777777777", -"XXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.*87777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.27777777777777777777777777777777777777777577777757777777777777777777777777777777777777777777777777777777777777777777777777777777777767777777777777776777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.&8777777777777777777777775777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.<877777777777777777777777777777777777777777777777777757777777777777777777777777777777777777777777777777777777777777777777777777777767767777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.O587777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.>87777777777777777777777777777777777777777777777777777777777777777777777575777777777777777777777777777777777777777777777777777777777777776777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO48777777777775777777777777777777777777777777777777777777777577777777777777777777777777777777777777777777777777777777777777777777777777777777777777777767", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.*8777777777777777777777777777777777777775777777777777777777777777777777777777777777577777777777777777777777777777777777777777677776777777777677777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.2777777777777777777777777757777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<87777777777777777777777777777777777777777777777777777777777775777777777777777777777777777777777777777777777777777777777777777677777777777767777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO77777777777777777777777777777777777777777777777777757777777777777777777777777777777777747777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.;8777777777777777777777777777777777777777777777777777777777777777777777777777777477777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4877777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXX.&877777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777767776777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.287777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777477777777777777777777777777777777776777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@77777777777777777777777577777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.<8777777777757777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777776776777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXO5877777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.=877777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", -"XXXXXXoXXXXXXXXXXXXXXXXXXXXXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX487777777777777777777777775777777777777777777777777777777777774777777777777777777777777777777777777777777777777777777777777777777777776776777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777767777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX28777777777777777777777777777777777777777777777777777777777777777777777777777777777777777747777777777777777777777777777777777777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.@7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777677777777777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..;877777777777777777577777777777777777757777777777777777777777777777777777777777777777777777777777777777777777677777777777777777767777777777777", -"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..O477777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777677" +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP------------------------------------------------------;---------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------;-----------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP;---------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP-----------------------------------------------------------------------------;------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP---------------------------------------------------------------------------------------------------------;-------------;=---------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------------------------------------;-----------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP-------------------------------------------------------------------------------------------------------------------------------------------------------------;--------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP---------------------;--------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPPP------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------------;**;----------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPPP---------------------------------------------------------------------------------------------------;;@%%+;;-------------------------------------------------------------------------;-------------------------PPPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------------;;#O2NN3O#;----------;----------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPPP-------------------------------------------------------------------------------------------------;&o-hLLLLh-O%;;------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------------O#yHLLLLLLHy#O=;------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPPP------------------------------------------------------------------------------------------------;@O7CLLLLLLLLLLC7++;------------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPP----------------------------------------------------------------------------------------------;;#oxLLLLLLLLLLLLLLLLLLGy@O-;-------------#&KLLLLLLLLLLno-------------=OmLLLLLLLLLLJ&$;------------;-O#yGLLLLLLLLLLLLLLLLLLx,o$;-=;-----------------------------------------------------PPPPPPPP", +"PPPPPPPP------------------------------------------------------;*O&dLLLLLLLLLLLLLLLLLLLg*O&;--------------;okLLLLLLLLLLL,@;------------;@>LLLLLLLLLLLko--------------;;%o=gLLLLLLLLLLLLLLLLLLLs*O*;------------------------------------------------------PPPPPPPP", +"PPPPPPPP----------------------------------------------------;=O@eDLLLLLLLLLLLLLLLLLLv1o#;;--------------;@,LLLLLLLLLLLgo;--------------;ohLLLLLLLLLLL,@;---------------;#O1bLLLLLLLLLLLLLLLLLLDe@O-;----------------------------------------------------PPPPPPPP", +"PPPPPPP---------------------------------------------------;;@O4MLLLLLLLLLLLLLLLLLLZ0++;;=;--------------=OMLLLLLLLLLLH%%;---------------%%HLLLLLLLLLLmO------------------;+O0ZLLLLLLLLLLLLLLLLLLN4O@;;---------------------------------------------------PPPPPPP", +"PPPPPPP-------------------------------------------------;;%o:lLLLLLLLLLLLLLLLLLLKi$O*;--;--------------;O0LLLLLLLLLLLtO;----------------;otLLLLLLLLLLL0O;-----------------;*O#iKLLLLLLLLLLLLLLLLLLl:o%;;-------------------------------------------------PPPPPPP", +"PPPPPPP------------------------------------------------;*O%pKLLLLLLLLLLLLLLLLLLk;o%;-;--=;------------;&@ALLLLLLLLLLZO*------------------*+ZLLLLLLLLLLA@*-------------------;&O;kLLLLLLLLLLLLLLLLLLKp%O*;------------------------------------------------PPPPPPP", +"PPPPPPP----------------------------------------------;;++qALLLLLLLLLLLLLLLLLLm3O@;;------------------;;opLLLLLLLLLLL4+;------------------;O4LLLLLLLLLLLio;;------------------;;@O3mLLLLLLLLLLLLLLLLLLAq++-;;-;-------------------------------------------PPPPPPP", +"PPPPPP---------------------------------------------;;#o2nLLLLLLLLLLLLLLLLLLSq+O-;;-------------------;#=KLLLLLLLLLLvo----------------------OvLLLLLLLLLLK*#;-------------------;;;++wSLLLLLLLLLLLLLLLLLLn2o#;;=--------------------------------------------PPPPPP", +"PPPPPP-----------------------------------------;--;&o;jLLLLLLLLLLLLLLLLLLLp%O*;-----------------------olLLLLLLLLLLL;#;--------------------;#;LLLLLLLLLLLlo-----------------------;*O%aLLLLLLLLLLLLLLLLLLLk;o%;--------------------------------------------PPPPPP", +"PPPPPP-----------------------------------------;;*O#yJLLLLLLLLLLLLLLLLLLl:O%;;;---------------------;+2LLLLLLLLLLLdo-----------------------;ofLLLLLLLLLLL2+;----------------------;;%o:lLLLLLLLLLLLLLLLLLLKy#O*;------------------------------------------PPPPPP", +"PPPPPP-----------------------------------------;@+7ZLLLLLLLLLLLLLLLLLLN4O@;;-----------------------;*+NLLLLLLLLLLF#&-----------------------;%$GLLLLLLLLLLN+*;------------------------;@O5NLLLLLLLLLLLLLLLLLLZ7O@;;----------------------------------------PPPPPP", +"PPPPPP-----------------------------------------%@;---------------------------------OyLLLLLLLLLb@=------------------------------------------PPPP", +"PPPP------------------------------------------=@bLLLLLLLLLy+---------------------------------=OmLLLLLLLLLLK&#;------------------------------------;#&KLLLLLLLLLLno=;--------------------------------OyLLLLLLLLLb@=------------------------------------------PPPP", +"PPPP------------------------------------------=@bLLLLLLLLLyO--------------------------------;O6LLLLLLLLLLLuo;--------------------------------------;ouLLLLLLLLLLL6O;--------------------------------OyLLLLLLLLLb@=------------------------------------------PPPP", +"PPP-------------------------------------------=@bLLLLLLLLLuO--------------------------------&+ALLLLLLLLLLA@&;---------------------------------------&@ALLLLLLLLLLA@&;-------------------------------OyLLLLLLLLLb@=-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLu+------------------------------;;ouLLLLLLLLLLL6O;---------------------------------------;;O6LLLLLLLLLLLuo;-------------------------------+yLLLLLLLLLb@=--------------------------------;----------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLyO------------------------------;#*KLLLLLLLLLLbO=------------------------------------------=onLLLLLLLLLLK&#;------------------------------OyLLLLLLLLLb@--------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLy+------------------------------;okLLLLLLLLLLL:@;------------------------------------------;@:LLLLLLLLLLLko;------------------------------+yLLLLLLLLLb@*-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLyO-----------------------------;+1LLLLLLLLLLLgo;;-------------------------------------------;ogLLLLLLLLLLL<@;-----------------------------OuLLLLLLLLLb@*-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLy+-----------------------------*OMLLLLLLLLLLH$$;--------------------------------------------;$%HLLLLLLLLLLNO*-----------------------------OyLLLLLLLLLb@*-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLyO----------------------------;O0LLLLLLLLLLLrO;----------------------------------------------;OrLLLLLLLLLLL0O;----------------------------+yLLLLLLLLLb@=-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLuO----------------------------%#DLLLLLLLLLLV+*;-----------------------------------------------*+CLLLLLLLLLLS#*----------------------------OyLLLLLLLLLb@=-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLy+---------------------------;oaLLLLLLLLLLL4+;=;----------------------------------------------;O4LLLLLLLLLLLpo;---------------------------+yLLLLLLLLLb@=-------------------------------------------PPP", +"PP-----------;--------------------------------=@bLLLLLLLLLyO--------------------------;#;KLLLLLLLLLLco--;=------------------------------------------------ocLLLLLLLLLLK-#;--------------------------OyLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLuO---------------------------ozLLLLLLLLLLL;@;-------------------------------------;------------;#;LLLLLLLLLLLzo---------------------------+uLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLu+------------------------;;+2LLLLLLLLLLLso;----------------------------------------------------;osLLLLLLLLLLL3+;-------------------------OuLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLyO-------------------------*OVLLLLLLLLLLF#&------------------------------------------------------%#GLLLLLLLLLLB+=-------------------------OyLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLuO---------;-------------=;oeLLLLLLLLLLLwO;------------------------------------------------------;OqLLLLLLLLLLLwo;------------------------+yLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLyO-----------------------;%#GLLLLLLLLLLNO*--------------------------------------------------------*ONLLLLLLLLLLG#%------------------------OyLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLy+-----------------------;ofLLLLLLLLLLL1+;--------------------------------------------------------;+1LLLLLLLLLLLfo;;----------------------+yLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLyO--------------------;-;@;LLLLLLLLLLLlo;-----------------------------------------------------------olLLLLLLLLLLL;@;----------------------OyLLLLLLLLLb@=-----------------------------------------;--PP", +"PP--------------------------------------------=@bLLLLLLLLLy+--------------------=;-OvLLLLLLLLLLK=#;----------------------------------------------------------;#-KLLLLLLLLLLvO-----------------------+yLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------*@bLLLLLLLLLy+---------------------;+4LLLLLLLLLLLpo;------------------------------------------------------------;opLLLLLLLLLLL4O;---------------------+yLLLLLLLLLb@*--------------------------------------------PP", +"PP------------------;-------------------------*@bLLLLLLLLLyO---------------------*+CLLLLLLLLLLS@&;------------------------------------------------------------;&@SLLLLLLLLLLZ+*---------------------OyLLLLLLLLLb@=--------------------------------------------PP", +"PP---------------------------------------------@bLLLLLLLLLy+--------------------;OtLLLLLLLLLLL0O;--------------------------------------------------------------;O0LLLLLLLLLLLtO;--------------------+yLLLLLLLLLb@=-----------------------;--------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLyO-------------------;%%HLLLLLLLLLLmO*;---------------------------------------------------------------*OMLLLLLLLLLLH%$;-------------------OyLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------*@bLLLLLLLLLy+-------------------;ohLLLLLLLLLLL,+;----------------------------------------------------------------;+,LLLLLLLLLLLho;-------------------OuLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------*@bLLLLLLLLLyO------------------;@,LLLLLLLLLLLko;------------------------------------------------------------------;okLLLLLLLLLLL>@;------------------OyLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLuO-------------------OmLLLLLLLLLLK&#;------------------------------------------------------------------;#&HLLLLLLLLLLmO-------------------+uLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLu+----------------;;O7LLLLLLLLLLLyo;-------------------------------------------------------------------;;oyLLLLLLLLLLL7O;-----------------OuLLLLLLLLLb@=--------------------------------------------PP", +"P---------------------------------------------=@bLLLLLLLLLyO----------------;&@ALLLLLLLLLLZ+&;---------------------------------------------------------------------*+ZLLLLLLLLLLA@*-----------------OyLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLy+----------------;oiLLLLLLLLLLL5+;----------------------------------------------------------------------;O6LLLLLLLLLLLio;----------------+yLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLyO---------------;#*KLLLLLLLLLLbO--------------------------------------------------------------------------ObLLLLLLLLLLK*$;---------------OuLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLy+----------------OkLLLLLLLLLLL:@;------------------------------------------------------------------------;@:LLLLLLLLLLLko----------------OyLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLyO--------------;+1LLLLLLLLLLLfo;--------------------------------------------------------------------------;ogLLLLLLLLLLL1+;--------------+yLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLuO--------------=ONLLLLLLLLLLG$%---------------------------------------------------------------------------;%%GLLLLLLLLLLNO=--------------OyLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLy+-------------;OqLLLLLLLLLLLeO;;---------------------------------------------------------------------------;oeLLLLLLLLLLLqO;-------------+yLLLLLLLLLb@*---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLyO-------------&@FLLLLLLLLLLVO=------------------------------------------------------------------------------*+VLLLLLLLLLLD#%;------------OyLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLuO------------;oaLLLLLLLLLLL3+;------------------------------------------------------------------------------;+4LLLLLLLLLLLso;------------+yLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLu+-----------;#;KLLLLLLLLLLco----------------------------------------------------------------------------------oxLLLLLLLLLLK;#;-----------OyLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLyO------------oxLLLLLLLLLLK;#;-----------------------------------------------------------;--------------------;#-KLLLLLLLLLLxo------------+yLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLuO----------;+4LLLLLLLLLLLao;----------------------------------------------------------------------------------;osLLLLLLLLLLL3+;----------OyLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLyO----------*+VLLLLLLLLLLF#&-----------------------------------------------------------------------------------;&#DLLLLLLLLLLV+*;---------OuLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLy+--------;;oeLLLLLLLLLLLqO;------------------------------------------------------------------------------------;OqLLLLLLLLLLLeo;---------OyLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLyO--------;%$GLLLLLLLLLLNO*-------------------;------------------------------------------------------------------=OMLLLLLLLLLLG$%---------+yLLLLLLLLLb@=---------------------------------------------P", +"P---------------------------------------------=@bLLLLLLLLLy+--------;ofLLLLLLLLLLL1+;--------------------------------------------------------------------------------------;+1LLLLLLLLLLLfo;--------OuLLLLLLLLLb@=---------------------------------------------P", +"PP--------------------------------------------=@bLLLLLLLLLy+--------@:LLLLLLLLLLLlo------------------------------------------------------------------------------------------olLLLLLLLLLLL;#;=;-----OyLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLyO--------ObLLLLLLLLLLK*#;----------------------------------------------------------------------------------------;#*KLLLLLLLLLLbo-;------+yLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLuO------;O6LLLLLLLLLLLuo;------------------------------------------------------------------------------------------;ouLLLLLLLLLLL5+;------OuLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLuO------*+ZLLLLLLLLLLA@*-------------------------------------------------------------------------------------------;*@ALLLLLLLLLLZ+&------OyLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLy+----;;oyLLLLLLLLLLL7O;--------------------------------------------------------------------------------------------;O7LLLLLLLLLLLtO;;----+yLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLyO----;$&HLLLLLLLLLLmO------------------------------------------------------------------------------------------------OmLLLLLLLLLLK&$;----OyLLLLLLLLLb@---------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLuO-----okLLLLLLLLLLL,@;----------------------------------------------------------------------------------------------;@>LLLLLLLLLLLko;----+yLLLLLLLLLb@*--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLu+--;;@,LLLLLLLLLLLgo;-----------;------------------------------------------------------------------------------------;ohLLLLLLLLLLL,+;---OyLLLLLLLLLb@*--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLyO---*OmLLLLLLLLLLH&$;------------------------------------------------------------------------------------------------;%%HLLLLLLLLLLmO*---+uLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLy+--;O7LLLLLLLLLLLtO;;----------------------------------------------------;--------------------------------------------;oyLLLLLLLLLLL7O;--OuLLLLLLLLLb@=--------------;-----------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLyO--*@SLLLLLLLLLLZO*----------------------------------------------------------------------------------------------------*+ZLLLLLLLLLLS#&;-OyLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLy+-;oiLLLLLLLLLLL4O;----------------------------------------------------------------------------------------------------;O4LLLLLLLLLLLio;-+yLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLuO;#*KLLLLLLLLLLvO--------------------------------------------------------------------------------------------------------ovLLLLLLLLLLK*#;OyLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLyO-olLLLLLLLLLLL:@;------------------------------------------------------------------------------------------------------;#;LLLLLLLLLLLlo;+yLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------=@bLLLLLLLLLy++2LLLLLLLLLLLfo;--------------------------------------------------------------------------------------------------------;ofLLLLLLLLLLL1++yLLLLLLLLLb@=--------------------------------------------PP", +"PP--------------------------------------------*@bLLLLLLLLLyOONLLLLLLLLLLG#%---------------------------------------------------------------------------------------------------------;%$GLLLLLLLLLLNOOyLLLLLLLLLb@=--------------------------------------------PP", +"PP---;----------------------------------------*@bLLLLLLLLLu qLLLLLLLLLLLeo;;---------------------------------------------------------------------------------------------------------;OeLLLLLLLLLLLq uLLLLLLLLLb@=--------------------------------------------PP", +"PPP-------------------------------------------*@bLLLLLLLLLeXFLLLLLLLLLLVO*------------------------------------------------------------------------------------------------------------*+VLLLLLLLLLLFXeLLLLLLLLLb@=----------------------------------------;--PPP", +"PPP--------------------------------------------@bLLLLLLLLL49LLLLLLLLLLL3+;------------------------------------------------------------------------------------------------------------;O3LLLLLLLLLLL93LLLLLLLLLb@=-------------------------------------------PPP", +"PPP-------------------------------------------*@bLLLLLLLLLpALLLLLLLLLLxo----------------------------------------------------------------------------------------------------------------oxLLLLLLLLLLApLLLLLLLLLb@=-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLKLLLLLLLLLLK-#;--------------------------------------------------------------------------------------------------------------;#;KLLLLLLLLLLKLLLLLLLLLb@*-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLLLLLLLLLLLLao;----------------------------------------------------------------------------------------------------------------;oaLLLLLLLLLLLLLLLLLLLLb@*-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLLLLLLLLLLLD#&-----------------------------------------------------------------------------------------------------------------;%#DLLLLLLLLLLLLLLLLLLLb@--------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLLLLLLLLLLL0O;------------------------------------------------------------------------------------------------------------------;O0LLLLLLLLLLLLLLLLLLLb@*-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLLLLLLLLLLmO=--------------------------------------------------------------------------------------------------------------------*+MLLLLLLLLLLLLLLLLLLb@=-------------------------------------------PPP", +"PPP-------------------------------------------=@bLLLLLLLLLLLLLLLLLL1@;---------*-----------*-----------*-----------*-----------*-----------*-----------*-------------------*-----------*--;@1LLLLLLLLLLLLLLLLLLb@=-------------------------------------------PPP", +"PPPP--------------------;---------------------=@bLLLLLLLLLLLLLLLLLs.%###%#%$%%%%%%%%%##%%%%%%%%%%#%$%%%%%%%%%##%%%%%%%%%%#%$%%%%#%##%##%%%%%%%%%%#%$%%%%%%%%%##%%%%#%##%%%%%%%%%%#%$%%%%%%%%.sLLLLLLLLLLLLLLLLLb@=------------------------------------------PPPP", +"PPPP------------------------------------------=@bLLLLLLLLLLLLLLLLG,-<<<<<<,<,<,,,,<,<<<<,<,,,<,,<<,<,<,,,<,,<<<<,<,,,<,,<<,<,<,,<<<<<<<<,<,,,<,,<<,<,<,,,<,,<<<<,<<,<<<<,<,,,<,,<<,<,<,,,<,<=,GLLLLLLLLLLLLLLLLb@=-----;------------------------------------PPPP", +"PPPP------------------------------------------=@bLLLLLLLLLLLLLLLLKGKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKGKLLLLLLLLLLLLLLLLb@=------------------------------------------PPPP", +"PPPP------------------------------------------=@bLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLb@=------------------------------------------PPPP", +"PPPP------------------------------------------=@bLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLb@=------------------------------------------PPPP", +"PPPP------------------------------------------=@bLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLb@=------------------------------------------PPPP", +"PPPP------------------------------------------=@bLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLb@=------------------------------------------PPPP", +"PPPPP-----------------------------------------=@bLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLb@=-----------------------------------------PPPPP", +"PPPPP------------------------------------------@bLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLb@=-----------------------------------------PPPPP", +"PPPPP-----------------------------------------*@bLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLb@=-----------------------------------------PPPPP", +"PPPPP------------------------------------------@nLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLm@=-----------------------------------------PPPPP", +"PPPPP-----------------------------------------*+MLLLLLLLLLLLLLLLLLLLJVHKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKHVHLLLLLLLLLLLLLLLLLLLM+=-----------------------------------------PPPPP", +"PPPPPP----------------------------------------;%1vLLLLLLLLLLLLLLLLLLHp&@,,,,,,,,>>>>,,,,>,,,,,>,>,,>>>,,,,>>,,,,,,,>>,,,>>,,>>,>>>>>,,,,>,,,,,>,>,,>>>>,>>>>>,,,>>>>,,,,>,,,,,>,,,,,>,,,#&aGLLLLLLLLLLLLLLLLLLv<&-----------------------------------------PPPPPP", +"PPPPPP----------------------------------------;;@O7ZLLLLLLLLLLLLLLLLLLb1Xo%%#%#%%%%#$$$$$$#$$$$$%#%%%#%$$$$#$$$$#%$$$$$$#%%##%%%%%%#$$$$$$#$$$$$#%%%#%#%%%%#%#%#%%%#$$$$$$#$$$$$$$$$%%oXo%;------------------------------------------------------------------------------------------------------;%o,zLLLLLLLLLLLLLLLLLLJy%O-;------------------------------------------PPPPPP", +"PPPPPP-------------------------------------------;;%o-kLLLLLLLLLLLLLLLLLLLa&O*;--------------------------------------------------------------------------------------------------;*o%dLLLLLLLLLLLLLLLLLLLk;o%;--------------------------------------------PPPPPP", +"PPPPPP---------------------------------------------;;#o2mLLLLLLLLLLLLLLLLLLDw++;;----------------------------------------------------------------------------------------------;-O@eSLLLLLLLLLLLLLLLLLLm2O#;----------------------------------------------PPPPPP", +"PPPPPPP----------------------------------------------;;++qALLLLLLLLLLLLLLLLLLM4O@;;------------------------------------------------------------------------------------------;;@O4NLLLLLLLLLLLLLLLLLLAq+O-;----------------------------------------------PPPPPPP", +"PPPPPPP------------------------------------------------;*O%pKLLLLLLLLLLLLLLLLLLk:o%;;;--------------------------------------------------------------------------------------;%o:lLLLLLLLLLLLLLLLLLLKa$O*;------------------------------------------------PPPPPPP", +"PPPPPPP--------------------------------------------------;%o;lLLLLLLLLLLLLLLLLLLKa%o*;-;----------------------------------------------------------------------------------;*O%aKLLLLLLLLLLLLLLLLLLz;o%;--------------------------------------------------PPPPPPP", +"PPPPPPP---------------------------------------------------;;@O4MLLLLLLLLLLLLLLLLLLAq@O-;------------------------;-------------------------------------------------------;-O@wSLLLLLLLLLLLLLLLLLLN4O@;----------------------------------------------------PPPPPPP", +"PPPPPPPP--------------------------------------------------;;;-O@eDLLLLLLLLLLLLLLLLLLn4O@;;----------------------=-----------------------------------------------------;;@o4mLLLLLLLLLLLLLLLLLLFe@O-;;;--------------------------------------------------PPPPPPPP", +"PPPPPPPP------------------------------------------------------;*O&fLLLLLLLLLLLLLLLLLLLk;o%;;=-------------------;=--------------------------------------------------;;%o;kLLLLLLLLLLLLLLLLLLLs*O*;------------------------------------------------------PPPPPPPP", +"PPPPPPPP--------------------------------------------------------;$o>xLLLLLLLLLLLLLLLLLLKi%O*;;-------------------;-------------------------------------------------;*O%pKLLLLLLLLLLLLLLLLLLx>O$;--------------------------------------------------------PPPPPPPP", +"PPPPPPPP--------------------------------------------------------;;;@O6VLLLLLLLLLLLLLLLLLLA0@@-;----------------------------------------------------------------;-;-O+0ALLLLLLLLLLLLLLLLLLV6O+;;---------------------------------------------------------PPPPPPPP", +"PPPPPPPPP-------------------------------------------------------;-=;-O#tGLLLLLLLLLLLLLLLLLLb1o#;;------------------------------------;-------------------------;;#O2bLLLLLLLLLLLLLLLLLLGt#O-;----------------------------------------------------------PPPPPPPPP", +"PPPPPPPPP------------------------------------------------------------;*O-gLLLLLLLLLLLLLLLLLLLh;o&;;-----------------------------------------------------------;%o;hLLLLLLLLLLLLLLLLLLLg*O&;;-----------------------------------------------------------PPPPPPPPP", +"PPPPPPPPP--------------------------------------------------------------;#o1vLLLLLLLLLLLLLLLLLLKy#O*;--------------------------------------------------------;*O#yKLLLLLLLLLLLLLLLLLLv1O#;;-------------------------------------------------------------PPPPPPPPP", +"PPPPPPPPPP---------------------------------------------------------------;++0ZLLLLLLLLLLLLLLLLLLZ7O+;;----------------------------------------------------;;@O0ZLLLLLLLLLLLLLLLLLLZ0++;;--------------------------------------------------------;-----PPPPPPPPPP", +"PPPPPPPPPP---------------------------------------------------------------;;*O#iKLLLLLLLLLLLLLLLLLLb1o#;--------------------------------------------------;#o1vLLLLLLLLLLLLLLLLLLKi#O*;----------------------------------------------------------------PPPPPPPPPP", +"PPPPPPPPPP------------------------------------------------------------------;%o;kLLLLLLLLLLLLLLLLLLLg=o%;;--------------------------------------------;;*o-gLLLLLLLLLLLLLLLLLLLk;o%;------------------------------------------------------------------PPPPPPPPPP", +"PPPPPPPPPPP-----------------------------------------------------------------=;;#O2mLLLLLLLLLLLLLLLLLLHy#O-;------------------------------------------;-O@tHLLLLLLLLLLLLLLLLLLm2O#;;------------------------------------------------------------------PPPPPPPPPPP", +"PPPPPPPPPPP-------------------------------------------------------------------=;;O@qSLLLLLLLLLLLLLLLLLLV7O@;--------------------------------------;;;++7VLLLLLLLLLLLLLLLLLLAq+O;;--------------------------------------------------------------------PPPPPPPPPPP", +"PPPPPPPPPPP-------------------------------------------------------------------;--;*O%aKLLLLLLLLLLLLLLLLLLczLLLLLLLLLLLLLLLLLLLf*O*;=;;=----------------------------;*o*fLLLLLLLLLLLLLLLLLLLz:o%;-----------------------------------------------------------------------PPPPPPPPPPPP", +"PPPPPPPPPPPP------------------------------------------------------------------------;;@O5NLLLLLLLLLLLLLLLLLLFt@O=;=;--------------------------;=O#tFLLLLLLLLLLLLLLLLLLN4O@;;------------------------------------------------------------------------PPPPPPPPPPPP", +"PPPPPPPPPPPP--------------------------------------------------------------------------;-O@rFLLLLLLLLLLLLLLLLLLV6+@;;------------------------;;@O6NLLLLLLLLLLLLLLLLLLDr@O-;-------------------------------------------------------------------------;PPPPPPPPPPPP", +"PPPPPPPPPPPPP---------------------------------------------------------------------------;*o*fLLLLLLLLLLLLLLLLLLLx,o$;--;------------------;;$o,xLLLLLLLLLLLLLLLLLLLf*O*;---------------------------------------------------------------------------PPPPPPPPPPPPP", +"PPPPPPPPPPPPP-----------------------------------------------------------------------------;$o,cLLLLLLLLLLLLLLLLLLLf&O*;;----------------;;&O&sLLLLLLLLLLLLLLLLLLLc,O#;-----------------------------------------------------------------------------PPPPPPPPPPPPP", +"PPPPPPPPPPPPPP-----------------------------------------------------------------------------;-@+7VLLLLLLLLLLLLLLLLLLDe@O=;--------------;=O@rFLLLLLLLLLLLLLLLLLLV7O@;;----------------;------------------------------------------------------------PPPPPPPPPPPPPP", +"PPPPPPPPPPPPPP-------------------------------------------------------------------------------;-O#yHLLLLLLLLLLLLLLLLLLM5O@;;-----------;@O5MLLLLLLLLLLLLLLLLLLHy#O-;-------------------------------------------------------------------------------PPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPP--------------------------------------------------------------------------------;%o=gLLLLLLLLLLLLLLLLLLLl:O$;--------;%o:zLLLLLLLLLLLLLLLLLLLg=o%;--------------------------------------------------------------------------------PPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPP---------------------------------------------------------------------------------;;#o1bLLLLLLLLLLLLLLLLLLKa%O*;--=;;*O&aLLLLLLLLLLLLLLLLLLLb1o#;----------------------------------------------------------------------------------PPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPP---------------------------------------------------------------------------------;-;;@O0ALLLLLLLLLLLLLLLLLLDe@O--;=++wDLLLLLLLLLLLLLLLLLLZ0+@;;-----------------------------------------------------------------------------------PPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPP------------------------------------------------------------------------------------;=O$iKLLLLLLLLLLLLLLLLLLm4O##O4MLLLLLLLLLLLLLLLLLLKi%O*;------------------------------------------------------------------------------------PPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPP-----------------------------------------------------------------------------------;;;%O;kLLLLLLLLLLLLLLLLLLLl**lLLLLLLLLLLLLLLLLLLLl;O&;--------------------------------------------------------------------------------------PPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPP---------------------------------------------------------------------------------------;#o4mLLLLLLLLLLLLLLLLLLGGLLLLLLLLLLLLLLLLLLm4o#;---------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPP---------------------------------------------------------------------------------------;-+@wDLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLDw@+-;---------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPP-----------------------------------------------------------------------------------------;*o%sLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLa%o*;-----------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPP------------------------------------------------------------------------------------------;%O:zLLLLLLLLLLLLLLLLLLLLLLLLLLLLz:O%;------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPP-------------------------------------------------------------------------------------------;;@O5NLLLLLLLLLLLLLLLLLLLLLLLLN5O@;;-------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPP--------------------------------------------------------------------------------------------;-+@rGLLLLLLLLLLLLLLLLLLLLGr@+=;--------------------------------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPP------------------------------;------------------------------------------------------------;-;&o*fLLLLLLLLLLLLLLLLLLf*o&;;----------------------;---------------------------------------------------------------------PPPPPPPPPPPPPPPPPPPPP", +"PPPPPPPPPPPPPPPPPPPPP--;------------------------------------------------------------------------------------------;;;#O c #570676", -", c #570776", -"< c #570677", -"1 c #570777", -"2 c #580777", -"3 c #570877", -"4 c #580877", -"5 c #580878", -"6 c #590878", -"7 c #580978", -"8 c #5A0979", -"9 c #590A78", -"0 c #5A0B78", -"q c #5A0A79", -"w c #5A0B79", -"e c #5B0B7A", -"r c #5B0C79", -"t c #5B0D79", -"y c #5C0E7A", -"u c #5C0F7A", -"i c #5D0E7B", -"p c #5D0F7B", -"a c #5D0F7C", -"s c #5E0F7C", -"d c #5D107C", -"f c #5E107C", -"g c #5E117C", -"h c #5F107D", -"j c #5F117D", -"k c #5E127C", -"l c #5F127C", -"z c #5F137D", -"x c #5F147D", -"c c #60127D", -"v c #60147E", -"b c #60157E", -"n c #61147F", -"m c #60167E", -"M c #61167E", -"N c #61167F", -"B c #61177F", -"V c #621680", -"C c #631780", -"Z c #631781", -"A c #631880", -"S c #631980", -"D c #631A80", -"F c #641881", -"G c #641B81", -"H c #651982", -"J c #661B82", -"K c #671F83", -"L c #681E84", -"P c #681F84", -"I c #682184", -"U c #692085", -"Y c #6A2186", -"T c #6A2286", -"R c #6B2386", -"E c #6B2586", -"W c #6C2687", -"Q c #6C2588", -"! c #6C2788", -"~ c #6D2689", -"^ c #6E2889", -"/ c #6E2989", -"( c #6F2A89", -") c #6F298A", -"_ c #6F2A8A", -"` c #6F2B8A", -"' c #702A8A", -"] c #702A8B", -"[ c #702B8B", -"{ c #702D8A", -"} c #702C8B", -"| c #712C8B", -" . c #702D8B", -".. c #712C8C", -"X. c #712D8C", -"o. c #722D8C", -"O. c #722E8C", -"+. c #722F8C", -"@. c #732E8D", -"#. c #732F8D", -"$. c #72308D", -"%. c #73308D", -"&. c #73318E", -"*. c #74308E", -"=. c #74318E", -"-. c #75328E", -";. c #75328F", -":. c #75338F", -">. c #76338F", -",. c #763390", -"<. c #763490", -"1. c #773690", -"2. c #773791", -"3. c #783691", -"4. c #783791", -"5. c #7A3A93", -"6. c #7B3C93", -"7. c #7C3C94", -"8. c #7C3D94", -"9. c #7C3D95", -"0. c #7D3E95", -"q. c #7E4096", -"w. c #7F4197", -"e. c #7F4297", -"r. c #804398", -"t. c #814598", -"y. c #814599", -"u. c #824599", -"i. c #824699", -"p. c #834799", -"a. c #81459A", -"s. c #82459A", -"d. c #82469A", -"f. c #83479A", -"g. c #83479B", -"h. c #83489B", -"j. c #84499B", -"k. c #85499B", -"l. c #854A9B", -"z. c #854A9C", -"x. c #854B9C", -"c. c #874C9D", +"32 32 190 2 ", +" c #53006B", +". c #590070", +"X c #5B0071", +"o c #610076", +"O c #620077", +"+ c #67007C", +"@ c #68007C", +"# c #68007D", +"$ c #69007D", +"% c #69007E", +"& c #6A007F", +"* c #6B007F", +"= c #6C0080", +"- c #6D0080", +"; c #6C0081", +": c #6D0081", +"> c #6E0081", +", c #6E0082", +"< c #6F0082", +"1 c #700083", +"2 c #710083", +"3 c #710085", +"4 c #720085", +"5 c #730086", +"6 c #760088", +"7 c #760089", +"8 c #770089", +"9 c #770189", +"0 c #77038A", +"q c #760588", +"w c #78008A", +"e c #79008B", +"r c #78028B", +"t c #78048A", +"y c #7B078D", +"u c #760989", +"i c #7C0A8E", +"p c #7A108C", +"a c #7C108D", +"s c #7C148E", +"d c #7D148E", +"f c #7E178F", +"g c #7E0B90", +"h c #7F0B90", +"j c #7F0B91", +"k c #7E0C90", +"l c #7F0E91", +"z c #79288B", +"x c #800E91", +"c c #810E91", +"v c #800F92", +"b c #801092", +"n c #811092", +"m c #821193", +"M c #821293", +"N c #831293", +"B c #821194", +"V c #841595", +"C c #851496", +"Z c #851596", +"A c #871697", +"S c #801B91", +"D c #871A97", +"F c #871898", +"G c #871B98", +"H c #881898", +"J c #881E99", +"K c #891E99", +"L c #891F99", +"P c #8A1C9A", +"I c #8C1F9B", +"U c #822293", +"Y c #832494", +"T c #872597", +"R c #892099", +"E c #8A2099", +"W c #8A209A", +"Q c #8A219A", +"! c #8B219A", +"~ c #8B209B", +"^ c #8B239B", +"/ c #8C229B", +"( c #8C209C", +") c #8D229D", +"_ c #8D239D", +"` c #8E239D", +"' c #8E219E", +"] c #8C249C", +"[ c #8D249C", +"{ c #8D249D", +"} c #8E249D", +"| c #8E269D", +" . c #8B359B", +".. c #8B369B", +"X. c #8B359C", +"o. c #8A399A", +"O. c #8C399C", +"+. c #8E3E9D", +"@. c #8F3E9E", +"#. c #903E9E", +"$. c #943EA2", +"%. c #8E469D", +"&. c #8E479D", +"*. c #9B4BA9", +"=. c #9F4FAC", +"-. c #9951A6", +";. c #9852A6", +":. c #9E57AB", +">. c #9E57AC", +",. c #9F5BAC", +"<. c #A555B1", +"1. c #A559B1", +"2. c #A55AB1", +"3. c #A961B5", +"4. c #AA66B6", +"5. c #AA67B6", +"6. c #AB6CB7", +"7. c #AB6DB7", +"8. c #AF6CBA", +"9. c #AF6FBA", +"0. c #AB76B7", +"q. c #B271BC", +"w. c #B378BD", +"e. c #B67DC0", +"r. c #B67EC0", +"t. c #B785C1", +"y. c #BA89C3", +"u. c #BE91C6", +"i. c #C28FC9", +"p. c #C290CA", +"a. c #C291CA", +"s. c #C397CC", +"d. c #C79ECF", +"f. c #C89DD0", +"g. c #C99FD1", +"h. c #C8A1CF", +"j. c #CBA4D2", +"k. c #CBA4D3", +"l. c #CBA9D2", +"z. c #CCAAD3", +"x. c #CFA9D6", +"c. c #D0A5D6", +"v. c #D0A5D7", +"b. c #D2ABD8", +"n. c #D5AADA", +"m. c #D5AADB", +"M. c #CEB1D4", +"N. c #D3B6D9", +"B. c #D7BADC", +"V. c #D8BDDE", +"C. c #D8BDDF", +"Z. c #DCC9E0", +"A. c #DCC9E1", +"S. c #E0CFE4", +"D. c #E2CEE5", +"F. c #E2CEE6", +"G. c #E1D2E5", +"H. c #E2D2E5", +"J. c #E8D6EB", +"K. c #E8D6EC", +"L. c #EDD9EF", +"P. c #EDDAEF", +"I. c #EBDDEE", +"U. c #ECDDEE", +"Y. c #EDDFEF", +"T. c #ECE2EF", +"R. c #ECE3EF", +"E. c #EDE0F0", +"W. c #F0E1F2", +"Q. c #F1E8F3", +"!. c #F2E8F3", +"~. c #F3EAF5", +"^. c #F6F0F7", +"/. c #F6F2F6", +"(. c #F6F2F7", +"). c #F6F3F7", +"_. c #F6F0F8", +"`. c #FAF3FA", +"'. c #FAF4FB", +"]. c #FBF5FB", +"[. c #FBF5FC", +"{. c #FBF6FC", +"}. c #FEF7FE", +"|. c #F7F8F8", +" X c #FCF8FD", +".X c #FDF9FD", +"XX c #FDFCFD", +"oX c #FEFFFE", +"OX c gray100", +"+X c None", /* pixels */ -"+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ", -"+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ", -"+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ", -"+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ", -"+ + + + + + + + + + + + @ @ @ @ + + + + + + + + + + + + + + + + ", -"+ + + + + + + + + + + + @ @ @ + + + + + + + + + + + + + + + + + ", -"+ + + + + + + + + + + + @ @ + 5 u 1 + + + + + + + + + + + + + + ", -"+ + + + + + + + + + + + + 2 B ^ :.B t + + + + + + + + + + + + + ", -"+ + + + + + + + + + + 1 x B g @.W P d B 4 + + + + + + + + + + + ", -"+ + + + + + + + + # u B 0 ^ B @ :.1 1 B x 1 + + + + + + + + + ", -"+ + + + + + + + 4 B g # + g +. + G ^ + t B g + + + + + + + + ", -"+ + + + + + + 1 G 1 + + + &.u + + + &.d + + + g B + + + + + + + ", -"+ + + + + + + 5 x + + + G ^ + + + + g +.+ + + 1 +.g + + + + + + ", -"+ + + + + + + 4 x + + 1 :.1 + + + + + ^ S + + 1 &.>.+ + + + + + ", -"+ + + + + + + 4 x + W G + + + + + + 4 :.$ + 1 ` l.S + + + + + ", -"+ + + + + + + 4 x + 0 &.1 + + + + + + + T T 1 ` l.8.$ + + + + ", -"O O O % O O O 5 V ! V + + + + # <.5 1 ` h.z.T + + + + ", -"% % O O O O O 5 V V ! V + + + + + V ^ $ +.p.h.e.5 + + + ", -"# # O O O O O 1 V ! V + + + + # +.S ^ p.p.z.+.+ + + ", -"# # O O O O O O ! ! V V V V 9 t 5 9 5 9 V <.^ h.e.p.p.g + + ", -"# # # O O O V I . . .! . .! ` +.` ` +.` ` ! +.a.a.a.h.<.# + ", -"# X # # O O O O I ! V V X # # # 9 G &.r.a.a.a.p.h.G ", -"+ + + + O O O V e.&.G V V # # + 1 V ` q.j.a.a.a.a.p.p.q.1 ", -"+ + + + O O O ! e.e.! V V # d ! 5.h.h.e.a.a.a.a.e.p.l.^ ", -"+ + + + + + + + V &.e.e.e.2.Z V ~ w.e.e.c.c.e.a.a.a.a.a.a.p.p.", -"+ + + + + + + + V e.e.e.e.e.&.e.e.c.e.e.e.e.a.a.a.a.a.a.e.p.", -"+ + + + + + + + .e.e.e.e.e.e.e.e.c.e.e.z.a.a.a.a.a.a.a.p.", -"+ + + + + + + + V V e.e.e.c.e.e.e.c.e.e.e.z.a.a.a.a.a.a.a.e.", -"+ + + + + + + + V 2.c.e.e.e.e.c.e.j.e.e.e.a.a.a.a.a.a.a.p.", -"+ + + + + + + + V e.c.c.e.e.e.e.e.j.z.e.a.a.a.a.a.a.a.e.", -"+ + + + + + + + V V e.e.e.e.c.e.e.e.a.a.a.p.e.a.e.p.p.e.", -"+ + + + + + + + V V e.c.e.c.e.e.j.e.p.e.j.e.p.a.a.a.e.p." +"+X+X+X+X+X+X+X+X+X+X+XL L L L L L L L L L +X+X+X+X+X+X+X+X+X+X+X", +"+X+X+X+X+X+X+XL L L L L L L L L L L L L L L L L L +X+X+X+X+X+X+X", +"+X+X+X+X+XL L L L L L L L L L Q Q L L L L L L L L L L +X+X+X+X+X", +"+X+X+X+XL L L L L L L L L Q ) e e I Q L L L L L L L L L +X+X+X+X", +"+X+X+XL L L L L L L L Q ) l > =.=.$ l ) Q L L L L L L L L +X+X+X", +"+X+XL L L L L L L L ) Z $ Y z.oXoXz.Y > Z ) L Q L L L L L L +X+X", +"+X+XL L L L L L [ L 5 q y.oX~.oXoX~.oXy.q 2 L ) L L L L L L +X+X", +"+XL L L L L Q ) 7 = :.^.}.%.M.b.b.M.%..X^.:.> 7 ) Q L L L L L +X", +"+XL L L L ] l = +.G.oXd.O ..oXp a oX..O f.oXG.#.$ c ^ L L L L +X", +"+XL L L Q M s h.oXA.X.+ > oXx.> > x.oX> + X.A.oXh.s M Q L L L +X", +"+XL L Q V l E.|.-.> j > i.oXp M M p oXi.> x > ;.|.E.c V Q L L +X", +"L L L L M ^ oX,.O ) l S oXe.* [ [ = e.oXS c ) O ,.oX[ M L L L L ", +"L L L L M L `.3.7 ) $ C.^.> H Q Q Z > _.C.$ ) 7 3.`.L M Q L L L ", +"L L L Q M L `.4.e 7 $.oX*.5 [ L L [ 5 *.oX$.7 e 4.`.L M L L L L ", +"L L L L M L `.4.7 > Q.F.$ ) L L L L ) $ F.Q.> 7 4.`.L M Q L L L ", +"L L L Q M L `.8.X 9.oXT y Q L L L Q Q y T oX9.X 9.'.L M J L L L ", +"L L L R M L }.<.O oXd.$ ) L L L L L L ) $ f.oXO <.}.L M L L L L ", +"L L L J M J }.o.w.oXu M Q L L L L L L Q M u oXw.o.}.L M Q J L L ", +"L L L Q M Q P.0.oXq.> [ Q Q Q Q Q R Q Q [ > q.oX0.L.Q M Q L L L ", +"L L J Q M G K.'.k. 1 5 2 5 5 5 5 5 5 5 5 5 k.'.K.G M J L L L ", +"L L L Q M F XoXf.a.m.v.v.v.v.c.c.c.v.v.v.n.i.f.oX|.F M Q L L L ", +"+XL J Q Z c J.oXoXB.A.W.T.I.Y.I.I.I.I.Y.W.A.B.oXoXJ.l Z R J L +X", +"+XL L L Q M f u.XXz.z X 5 i t t 7 t i 2 . z z.oXu.f M Q L L L +X", +"+XL L L L [ c $ o.F.oXs.p > A Q Q F > p s.oXS.O.= c [ L L L L +X", +"+XL L L L L Q ) e = :.^.oX7.2 7 7 > 6.oX^.:.= e ) Q L L L L L +X", +"+X+XL L L L L L [ L 5 q t.oXE.+.+.E.oXt.q 5 L [ L L L L L L +X+X", +"+X+XL L L L L L L L ) C = U N.oXoXN.U = Z [ L L L L L L L L +X+X", +"+X+X+XL L L L L L L L Q [ j $ 2.2.> l [ Q L L L L L L L L +X+X+X", +"+X+X+X+XL L L L L L L L L Q ) e 7 ) Q L L L L L L L L L +X+X+X+X", +"+X+X+X+X+XL L L L L L L L L L Q Q L L L L L L L L L L +X+X+X+X+X", +"+X+X+X+X+X+X+XL L L L L L L L L L L L L L L L L L +X+X+X+X+X+X+X", +"+X+X+X+X+X+X+X+X+X+X+XL L L L L L L L L L +X+X+X+X+X+X+X+X+X+X+X" }; diff --git a/share/pixmaps/dynamic64.png b/share/pixmaps/dynamic64.png index be7464ec90..6a8819e77f 100644 Binary files a/share/pixmaps/dynamic64.png and b/share/pixmaps/dynamic64.png differ diff --git a/share/pixmaps/dynamic64.xpm b/share/pixmaps/dynamic64.xpm index 408d85fa0d..3df89f3f43 100644 --- a/share/pixmaps/dynamic64.xpm +++ b/share/pixmaps/dynamic64.xpm @@ -1,270 +1,149 @@ /* XPM */ -static char *_494762411006[] = { +static char *_c2093f2681946f1f86cbf9f3386526d[] = { /* columns rows colors chars-per-pixel */ -"64 64 200 2 ", -" c #4E006F", -". c #4F0070", -"X c #500070", -"o c #500071", -"O c #510071", -"+ c #510072", -"@ c #510172", -"# c #520072", -"$ c #520073", -"% c #530073", -"& c #520173", -"* c #530173", -"= c #530273", -"- c #540174", -"; c #540274", -": c #540374", -"> c #550374", -", c #540275", -"< c #550375", -"1 c #550475", -"2 c #560475", -"3 c #560575", -"4 c #560576", -"5 c #560676", -"6 c #570676", -"7 c #570776", -"8 c #570777", -"9 c #580777", -"0 c #580877", -"q c #580878", -"w c #590878", -"e c #590978", -"r c #590A78", -"t c #590B78", -"y c #5A0A79", -"u c #5A0B79", -"i c #5A0C79", -"p c #5B0C79", -"a c #5A0C7A", -"s c #5B0C7A", -"d c #5B0D7A", -"f c #5B0E7A", -"g c #5C0C7A", -"h c #5C0E7A", -"j c #5D0E7B", -"k c #5D0F7B", -"l c #5D0F7C", -"z c #5D107B", -"x c #5D117B", -"c c #5E107C", -"v c #5F117C", -"b c #5F117D", -"n c #5E127C", -"m c #5E137C", -"M c #5F127D", -"N c #5F147D", -"B c #60127D", -"V c #60137E", -"C c #60147D", -"Z c #60157E", -"A c #61157E", -"S c #61157F", -"D c #62157F", -"F c #60167E", -"G c #61177F", -"H c #62167F", -"J c #62177F", -"K c #62187F", -"L c #62197F", -"P c #631780", -"I c #631880", -"U c #631980", -"Y c #631881", -"T c #631A80", -"R c #631B80", -"E c #641981", -"W c #651A81", -"Q c #651A82", -"! c #651B82", -"~ c #661B82", -"^ c #641C81", -"/ c #651C82", -"( c #661C82", -") c #661D83", -"_ c #671D83", -"` c #651E82", -"' c #661E82", -"] c #661F82", -"[ c #671E83", -"{ c #671F83", -"} c #681F84", -"| c #662083", -" . c #672083", -".. c #672183", -"X. c #682084", -"o. c #682184", -"O. c #692085", -"+. c #692185", -"@. c #6A2185", -"#. c #682284", -"$. c #682384", -"%. c #692384", -"&. c #692285", -"*. c #692385", -"=. c #6A2285", -"-. c #6A2385", -";. c #6A2286", -":. c #6A2386", -">. c #692485", -",. c #692585", -"<. c #6A2585", -"1. c #6A2486", -"2. c #6B2486", -"3. c #6B2487", -"4. c #6A2686", -"5. c #6B2686", -"6. c #6B2786", -"7. c #6B2787", -"8. c #6C2487", -"9. c #6C2687", -"0. c #6C2887", -"q. c #6C2987", -"w. c #6C2588", -"e. c #6D2688", -"r. c #6C2788", -"t. c #6D2788", -"y. c #6D2888", -"u. c #6C2988", -"i. c #6D2988", -"p. c #6E2889", -"a. c #6F2989", -"s. c #6D2A88", -"d. c #6F298A", -"f. c #6F2A8A", -"g. c #702A8A", -"h. c #702B8A", -"j. c #702B8B", -"k. c #702C8A", -"l. c #702C8B", -"z. c #712C8B", -"x. c #712D8B", -"c. c #712D8C", -"v. c #722D8C", -"b. c #722E8C", -"n. c #722F8D", -"m. c #732F8D", -"M. c #73308D", -"N. c #74308D", -"B. c #74318E", -"V. c #75328E", -"C. c #75338F", -"Z. c #76338F", -"A. c #76348F", -"S. c #763590", -"D. c #773690", -"F. c #783791", -"G. c #783891", -"H. c #793891", -"J. c #793892", -"K. c #793992", -"L. c #7A3992", -"P. c #7A3A92", -"I. c #7A3B93", -"U. c #7B3B93", -"Y. c #7B3C93", -"T. c #7C3C94", -"R. c #7C3D94", -"E. c #7C3D95", -"W. c #7C3E94", -"Q. c #7D3E95", -"!. c #7D3F95", -"~. c #7E4095", -"^. c #7E4096", -"/. c #7E4196", -"(. c #7F4196", -"). c #7F4297", -"_. c #804297", -"`. c #804397", -"'. c #804398", -"]. c #804498", -"[. c #814498", -"{. c #814598", -"}. c #814599", -"|. c #824599", -" X c #824699", -".X c #824799", -"XX c #834799", -"oX c #83479A", -"OX c #83489A", -"+X c #84489A", -"@X c #84499A", -"#X c #84499B", -"$X c #844A9B", -"%X c #854A9B", -"&X c #854B9B", -"*X c #854B9C", -"=X c #864B9C", -"-X c #864C9C", -";X c #864C9D", -":X c #874D9D", +"64 64 79 1 ", +" c #4F0067", +". c #500067", +"X c #54006B", +"o c #59006E", +"O c #5B0071", +"+ c #620077", +"@ c #67007B", +"# c #6B007F", +"$ c #6E0081", +"% c #720085", +"& c #700A83", +"* c #760289", +"= c #7A058C", +"- c #7A0B8C", +"; c #7C128E", +": c #791C8B", +"> c #7F0C91", +", c #810F92", +"< c #831494", +"1 c #851A95", +"2 c #881997", +"3 c #871998", +"4 c #891F99", +"5 c #852495", +"6 c #862996", +"7 c #872598", +"8 c #8B229B", +"9 c #872C98", +"0 c #8C2C9B", +"q c #8C339B", +"w c #8F3E9E", +"e c #9028A0", +"r c #933AA2", +"t c #8F409F", +"y c #9343A1", +"u c #9944A7", +"i c #9A4BA7", +"p c #9F51AD", +"a c #A054AE", +"s c #A359AF", +"d c #A65CB2", +"f c #9D61AA", +"g c #A661B2", +"h c #A962B4", +"j c #AA6CB5", +"k c #AE6CB9", +"l c #AE71B9", +"z c #B274BC", +"x c #B47CBE", +"c c #B77EC0", +"v c #B87FC2", +"b c #BA85C3", +"n c #BE8AC7", +"m c #C18AC9", +"M c #C493CC", +"N c #C799CF", +"B c #C89CCF", +"V c #CB9DD3", +"C c #C7A2CF", +"Z c #C8A2CF", +"A c #CAA4D2", +"S c #CDAAD4", +"D c #D4B4DA", +"F c #D6BADC", +"G c #D9BCDE", +"H c #DBC0DF", +"J c #DDC2E1", +"K c #E2CDE6", +"L c #E6D3EA", +"P c #E8D5EB", +"I c #EBDAEE", +"U c #EDE1EF", +"Y c #EEE3F1", +"T c #F1E5F3", +"R c #F3EBF5", +"E c #F7F1F8", +"W c #FAF5FA", +"Q c #FFFFFF", +"! c None", /* pixels */ -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % : % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 0 { q.K 1 % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % % , W ,...$.$.q.N % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % x s...F R.{.C.x ,.,.t % % % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % . . t ,.q.x % C./.F &X+.% K 0.{ 0 % % % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % % 0 | q.K % F ;XW . x.}.r % 1 { 0.K > % % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % % % K q.^ 0 % % , Q.P.% % 1 }.n. % . t $.q.x % % % % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % % % x q.,.t % % % % +.&Xh % % % +.&Xm % % % % m 0.| t . % % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % % % t $.q.x % % % % % 1 }.x.% % % % % Q.P., % % % % = L 0.^ 0 % % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % % 1 ^ s.K : % % % % % x.OX0 % % % % % F ;XW % % % % % % 0 | q.N % % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % 0 q.| 0 . % % % % % % h &X,.. % % % % % % D.).1 % % % % % % % x q.| % % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % 0 q., % % % % % % % % P./., % % % % % % . t &Xs.. % % % % % % t q.m % % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % 0 ,., * * % % % % T ;XP % % % % % % % . s.&Xr % % % % % % % t ,.M.t % % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % 0 q., * * % % % % : /.D.% % % % % % % % % % 1 }.C.. % % % % % % t +.P.M.% % % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % r 9., * * % % % % w.;Xh % % % % % % % % % % % { =XN % % % % % % t ..D.&Xm % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % 0 0., * * % % % 0 OXs.. % % % % % % % % % % % , P.Y.= % % % % % t ..D.&XG.% % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % 0 9.> * * * * % n.}.9 % % % % % % % % % % % % B ;X| % % % % % t ..C.OXOX{ % % % % % % % % % % % ", -"% % % % % % % % % % % % % % % r ,.1 * * % % B &X{ % % % % % % % % % % % % % % % M.{.1 % % % % x ,.D.&X}./.1 % % % % % % % % % % ", -"% % % % % % % % % % % % % % % 0 0.1 * * % % P.W.% % % % % % % % % % % % % % % % r OXs.% % % % t %.C.OX}.&Xw.% % % % % % % % % % ", -"% % % % % % % % % % % % % % % 0 0.* * * % W &XF % % % % % % % % % % % % % % % % % w.&Xt % % % t %.C.OX}.}.}.t . % % % % % % % % ", -"% % % % % % % % % % % % % % % 0 q., % , 1 /.C.. % % % % % % % % % % % % % % % % % 1 /.C.% % % t ,.C.OX}.{.OXC.% % % % % % % % % ", -"% % % % % % % % % % % % % % % t ,., % . w.=Xt % % % % % % % % % % % % % % % % % % { =XF % % h +.C.OX{.{.).OXF X % % % % % % % ", -"% % % % % % % % % % % % % % % 0 q., % r &Xs.X % % % % % % % % % % % % % % % % % % % % P.W.* % h %.C.OX{.).@X@XY.* % % % % % % % ", -"% % % % % % % % % % % % % % % 0 0., % S.'.1 % % % % % % % % % % % % % % % % % % % % % x &X+. t %.C.OX{.@X).).OX .% % % % % % % ", -"% % % % % % % % % % % % % % % t ,.* B &X{ % % % % % % % % % % % % % % % % % % % % % X n.}.1 t %.C.@X).{.{.{.@X`.9 X % % % % % ", -"% % % % % % % % % % % % % % % 0 ,.9 P.T.% % % % % % % % % % % % % % % % % % % % % % % % 9 &Xh.0 %.D.@X{.{.{.{.{.&Xs.X % % % % % ", -"% % % % % % % % % % % % % % % 0 .+.&XB X % % % % % % X % % % % % % % % % % % . % % % % % .&XW | C.&X{.{.{.{.{.}.}.x % % % % % ", -"% % % % % % % % % % % % % % % 0 ,.P.F.1 9 0 0 0 1 9 0 0 0 1 0 0 1 0 0 0 1 r 1 0 0 0 1 9 9 r `.x.| C.@X{.{.{.{.{.'.&XC.% % % % % ", -"% % % % % % % % % % % % % % % t ,.s.{.}.}.{.}.}.}.}.}.}.XX}.}.}.OX}.}.}.}.}.}.}.XX}.XX}.{.{.Q.+.} C.&X{.{.{.{.{.}.{.&XP % * * * ", -"% % % % % % % % % % % % % % % = +.+.+.+.} } +. .{ | +. .} +.{ { .} +. .{ +.+. .} } } +.} +. .+.L P.}.{.{.{.{.{.{.{.XXT.* * * * ", -"% % % % % % % % % % % % % % % % L 9.{ K 1 X X % % % % X X % % X % X . % X % X % t .} 2.W.}.{.{.{.{.{.{.{.{.{.&X+.% * * ", -"% % % % % % % % % % % % % % % % r Q.n.+.q.K > % % % % % % % % % % % % % % % % % % % 0 { ,. .C.XXXX{.{.{.{.{.{.{.{.{.{.XX{.0 % * ", -"% % % % % % % % % % % % % % % % X { ;XQ.0. .,.N , % % % * * * * % % % % % % % % > L ,. .x.'.&X`.{.{.{.{.{.{.{.{.{.{.{.{.OXx.% % ", -"% % % % % % % % % % % % % % % % % % P.&XOXP.,.%.,.t % % * * * * % % % % % % * C ,.$.0.W.&X}.{.{.{.{.{.{.{.{.{.{.{.{.{.{.}.OXm X ", -"% % % % % % % % % % % % % % % % % % B OX}.XX}.C. .,.{ 0 % % * * % % % X % x | %.,.P.}.OX{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.`.&XD.% ", -"% % % % % % % % % % % % % % % % % % % x.&X{.{.&X`.x. .%.K > % * % % % 0 { | .C.}.&X}.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.}.}.}.{ ", -"% % % % % % % % % % % % % % % % % % % t }.}.{.{.}.&XT.9. .,.B * % 1 K ,.} x.`.&X{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.}.`.", -"% % % % % % % % % % % % % % % % % % % 9.&X{.{.{.{.OX}.D.2.,.| F +.+.9.W.XX{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % , W.&X{.{.{.{.{.XX}.C. . .,.D.XX}.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % W XX}.{.{.{.{.{.{.XX`.C.{.&X{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % C.&X{.{.{.{.{.{.{.}.&X}.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % x OX}.{.{.{.{.{.{.{.`.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % f.&X{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % 0 `.}.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % X +.&X{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % % , Q.XX}.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % % % K &X`.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % % % % C.&X{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % % % % h }.XX{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % h.&X}.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % 0 /.}.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.", -"% % % % % % % % % % % % % % % % % % % % % % % % % % % .&X{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{." +"!!!!!!!!!!!!!!!!!!!!!!!!!!444444444444!!!!!!!!!!!!!!!!!!!!!!!!!!", +"!!!!!!!!!!!!!!!!!!!!444444444444444444444444!!!!!!!!!!!!!!!!!!!!", +"!!!!!!!!!!!!!!!!44444444444444444444444444444444!!!!!!!!!!!!!!!!", +"!!!!!!!!!!!!!44444444444444444444444444444444448444!!!!!!!!!!!!!", +"!!!!!!!!!!!444444844444484444444448444444444444444444!!!!!!!!!!!", +"!!!!!!!!!!44444444444444444444444444444444444444444444!!!!!!!!!!", +"!!!!!!!!!8444444444444444444444444444444444444444444448!!!!!!!!!", +"!!!!!!!!444444444444444444444483<84444444444444444444444!!!!!!!!", +"!!!!!!!44444444444444444444888====88444444444444444444444!!!!!!!", +"!!!!!!4444444444444444444448,#qGGq#,8844444444444444444444!!!!!!", +"!!!!!4544444444444444444483$;bQQQQb;$2844444444444444444444!!!!!", +"!!!!444444444444444444488%%gYQQQQQQYg%*484444444444444444444!!!!", +"!!!!4444444444444444448-$yHQQQQQQQQQQHy#-8444444444444444444!!!!", +"!!!444444444444444448<$5AQQQDJQQQQJDQQQA5$<044444444444444444!!!", +"!!!44444444444444484%-xWQQWf:IQNNQP:fWQQWx-$28444444444448444!!!", +"!!!444444444444484*$aIQQQC5.DQQ--QQF.5ZQQQIp%*484444444444444!!!", +"!!44444444444488-$wFQQQFw$+dQQM$$MQQs+%tFQQQFw#-88444444444444!!", +"!!444444444478<$:BQQQUs$*<-YQE;<,;EQT-<*%sUQQQB1$<844444444444!!", +"!!44484444482%*lEQQQc;$20$vQQk#88$kQQv#83$-xQQQEl*%48444444444!!", +"!!4444444483%iLQQQS9$<88-4WQL%<883%LQW4-88<#9SQQQLi%3844444444!!", +"!4444444443>AQQQJy#=8844#SQQr*8448%uQQS#8488=$uJQQQA>3444444844!", +"!444444444<>,>>;>>,>>>>>>>>>,<@qQQQQI<<444444444!", +"!444444444<3444444444!", +"!!4484444481%iLQQRx&X#*%%%%%%%%%%%%%%%%%%*#.&xRQQLi%3844444444!!", +"!!44444444484%*lEQQQb;%288888788484888882$;bQQQEl*%48444444444!!", +"!!444444444488<$1BQQQUd%%48444445444484*%dUQQQB1#<884444444444!!", +"!!44444444444888-#wFQQQHy$=8444444448=$yJQQQFw#-88444444844444!!", +"!!!444444444444484*$aIQQQA6$<888488<$6AQQQIp$*484444444444444!!!", +"!!!44484444444444482$-cWQQWx-$2882$;xWQQWx-%28444484444444444!!!", +"!!!444444444444444448<#6AQQQIs$**%aIQQQA6$<884444444444444444!!!", +"!!!!4444444444444444888=#yJQQQFqqFQQQHy$-8444444444444444444!!!!", +"!!!!444444444444444444484%%gYQQQQQQYg%%484444444444444444444!!!!", +"!!!!!4444444444444444444882%;bQQQQb;$3844444444444444444444!!!!!", +"!!!!!!4444444444444444444448<#qGGq#>8844444444444444444444!!!!!!", +"!!!!!!!44444444444444444444448====88444444444444444444448!!!!!!!", +"!!!!!!!!444444444444444444444483384444444444444444444444!!!!!!!!", +"!!!!!!!!!4444444484444444444444444444444444444444444444!!!!!!!!!", +"!!!!!!!!!!44448444444444444444444484444484444444444444!!!!!!!!!!", +"!!!!!!!!!!!444444444444444444444444444444444444444444!!!!!!!!!!!", +"!!!!!!!!!!!!!44444444444444444844444444444444444844!!!!!!!!!!!!!", +"!!!!!!!!!!!!!!!!44444444444444444444444444444444!!!!!!!!!!!!!!!!", +"!!!!!!!!!!!!!!!!!!!!444444444444444444444444!!!!!!!!!!!!!!!!!!!!", +"!!!!!!!!!!!!!!!!!!!!!!!!!!444444444444!!!!!!!!!!!!!!!!!!!!!!!!!!" }; diff --git a/share/pixmaps/nsis-header.bmp b/share/pixmaps/nsis-header.bmp index 8930bd55d5..a59edb628d 100644 Binary files a/share/pixmaps/nsis-header.bmp and b/share/pixmaps/nsis-header.bmp differ diff --git a/share/pixmaps/nsis-wizard.bmp b/share/pixmaps/nsis-wizard.bmp index 75ac254bfc..f4cf533eed 100644 Binary files a/share/pixmaps/nsis-wizard.bmp and b/share/pixmaps/nsis-wizard.bmp differ diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index 196577ae80..7981f79012 100644 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -17,13 +17,13 @@ APPL CFBundleGetInfoString - @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@, Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin Core developers, 2015-@COPYRIGHT_YEAR@ Dynamic Blockchain Solutions + @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@.@CLIENT_VERSION_BUILD@, Copyright © 2015-@COPYRIGHT_YEAR@ Dynamic Blockchain Solutions CFBundleShortVersionString - @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ + @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@.@CLIENT_VERSION_BUILD@ CFBundleVersion - @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ + @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@.@CLIENT_VERSION_BUILD@ CFBundleSignature ???? @@ -48,43 +48,6 @@ - UTExportedTypeDeclarations - - - UTTypeIdentifier - io.dynamic.paymentrequest - UTTypeDescription - Dynamic payment request - UTTypeConformsTo - - public.data - - UTTypeTagSpecification - - public.mime-type - application/x-dynamic-payment-request - public.filename-extension - - dynamicpaymentrequest - - - - - - CFBundleDocumentTypes - - - CFBundleTypeRole - Editor - LSItemContentTypes - - io.dynamic.paymentrequest - - LSHandlerRank - Owner - - - NSPrincipalClass NSApplication @@ -93,7 +56,10 @@ LSAppNapIsDisabled True - + + NSRequiresAquaSystemAppearance + True + LSApplicationCategoryType public.app-category.finance diff --git a/src/Makefile.am b/src/Makefile.am index 9acc4b9363..1e99260b2e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,13 +6,14 @@ AM_CPPFLAGS = $(HARDENED_CPPFLAGS) EXTRA_LIBRARIES = DYNAMIC_CONFIG_INCLUDES=-I$(builddir)/config -DYNAMIC_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) +DYNAMIC_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(LIBTORRENT_CPPFLAGS) $(LIBVGP_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) DYNAMIC_INCLUDES += -I$(srcdir)/secp256k1/include DYNAMIC_INCLUDES += -I$(srcdir)/univalue/include LIBDYNAMIC_SERVER=libdynamic_server.a LIBDYNAMIC_WALLET=libdynamic_wallet.a +LIBDYNAMIC_CONSENSUS=libdynamic_consensus.a LIBDYNAMIC_COMMON=libdynamic_common.a LIBDYNAMIC_CLI=libdynamic_cli.a LIBDYNAMIC_UTIL=libdynamic_util.a @@ -30,11 +31,14 @@ $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: EXTRA_LIBRARIES += \ - crypto/libdynamic_crypto.a \ - libdynamic_util.a \ - libdynamic_common.a \ - libdynamic_server.a \ - libdynamic_cli.a + $(LIBDYNAMIC_CRYPTO) \ + $(LIBDYNAMIC_UTIL) \ + $(LIBDYNAMIC_COMMON) \ + $(LIBDYNAMIC_CONSENSUS) \ + $(LIBDYNAMIC_SERVER) \ + $(LIBDYNAMIC_CLI) \ + $(LIBDYNAMIC_WALLET) + if ENABLE_WALLET DYNAMIC_INCLUDES += $(BDB_CPPFLAGS) EXTRA_LIBRARIES += libdynamic_wallet.a @@ -45,14 +49,15 @@ endif if BUILD_DYNAMIC_LIBS lib_LTLIBRARIES = libdynamicconsensus.la -LIBDYNAMIC_CONSENSUS=libdynamicconsensus.la +LIBDYNAMICCONSENSUS=libdynamicconsensus.la else -LIBDYNAMIC_CONSENSUS= +LIBDYNAMICCONSENSUS= endif bin_PROGRAMS = TESTS = BENCHMARKS = +DHT_TESTS = if BUILD_DYNAMICD bin_PROGRAMS += dynamicd @@ -70,11 +75,24 @@ DYNAMIC_CORE_H = \ addressindex.h \ addrman.h \ alert.h \ - amount.h \ - arith_uint256.h \ base58.h \ - bip39_english.h \ + bdap/audit.h \ + bdap/auditdb.h \ + bdap/bdap.h \ + bdap/certificatedb.h \ + bdap/domainentry.h \ + bdap/domainentrydb.h \ + bdap/fees.h \ + bdap/linking.h \ + bdap/linkingdb.h \ + bdap/linkmanager.h \ + bdap/linkstorage.h \ + bdap/stealth.h \ + bdap/utils.h \ + bdap/vgpmessage.h \ + bdap/x509certificate.h \ bip39.h \ + blockencodings.h \ bloom.h \ cachemap.h \ cachemultimap.h \ @@ -92,24 +110,36 @@ DYNAMIC_CORE_H = \ compat/sanity.h \ compressor.h \ consensus/consensus.h \ - consensus/merkle.h \ - consensus/params.h \ - consensus/validation.h \ core_io.h \ core_memusage.h \ + cuckoocache.h \ dbwrapper.h \ + dht/datachunk.h \ + dht/dataheader.h \ + dht/datarecord.h \ + dht/dataset.h \ + dht/ed25519.h \ + dht/limits.h \ + dht/mutable.h \ + dht/mutabledb.h \ + dht/session.h \ + dht/sessionevents.h \ + dht/settings.h \ + dht/storage.h \ dynode.h \ dynode-payments.h \ dynode-sync.h \ dynodeman.h \ dynodeconfig.h \ flat-database.h \ + fluid/banaccount.h \ fluid/fluid.h \ fluid/fluiddb.h \ fluid/fluiddynode.h \ fluid/fluidmining.h \ fluid/fluidmint.h \ fluid/fluidsovereign.h \ + fluid/operations.h \ governance.h \ governance-classes.h \ governance-exceptions.h \ @@ -117,7 +147,6 @@ DYNAMIC_CORE_H = \ governance-validators.h \ governance-vote.h \ governance-votedb.h \ - hash.h \ hdchain.h \ httprpc.h \ httpserver.h \ @@ -131,43 +160,46 @@ DYNAMIC_CORE_H = \ memusage.h \ merkleblock.h \ messagesigner.h \ - miner.h \ + miner/impl/miner-cpu.h \ + miner/impl/miner-gpu.h \ + miner/internal/hash-rate-counter.h \ + miner/internal/miner-base.h \ + miner/internal/miner-context.h \ + miner/internal/miners-controller.h \ + miner/internal/miners-group.h \ + miner/internal/thread-group.h \ + miner/miner-util.h \ + miner/miner.h \ net.h \ net_processing.h \ netaddress.h \ netbase.h \ netfulfilledman.h \ + netmessagemaker.h \ noui.h \ ntp.h \ - operations.h \ policy/fees.h \ policy/policy.h \ policy/rbf.h \ pow.h \ - prevector.h \ - primitives/block.h \ - primitives/transaction.h \ privatesend-client.h \ privatesend.h \ privatesend-server.h \ privatesend-util.h \ psnotificationinterface.h \ protocol.h \ - pubkey.h \ random.h \ reverselock.h \ - rpcclient.h \ - rpcprotocol.h \ - rpcregister.h \ - rpcserver.h \ + reverse_iterator.h \ + rpc/client.h \ + rpc/protocol.h \ + rpc/register.h \ + rpc/server.h \ + rpc/wallet.h \ scheduler.h \ - script/interpreter.h \ - script/script.h \ - script/script_error.h \ script/sigcache.h \ script/sign.h \ script/standard.h \ - serialize.h \ spentindex.h \ spork.h \ streams.h \ @@ -175,16 +207,15 @@ DYNAMIC_CORE_H = \ support/allocators/zeroafterfree.h \ support/cleanse.h \ support/lockedpool.h \ + support/events.h \ sync.h \ threadinterrupt.h \ threadsafety.h \ timedata.h \ - tinyformat.h \ torcontrol.h \ txdb.h \ txmempool.h \ ui_interface.h \ - uint256.h \ undo.h \ util.h \ utilmoneystr.h \ @@ -192,15 +223,24 @@ DYNAMIC_CORE_H = \ utiltime.h \ validation.h \ validationinterface.h \ - version.h \ versionbits.h \ wallet/coincontrol.h \ wallet/crypter.h \ wallet/db.h \ - wallet/rpcwallet.h \ wallet/wallet.h \ wallet/wallet_ismine.h \ wallet/walletdb.h \ + wordlists/chinese_simplified.h \ + wordlists/chinese_traditional.h \ + wordlists/english.h \ + wordlists/french.h \ + wordlists/german.h \ + wordlists/italian.h \ + wordlists/japanese.h \ + wordlists/korean.h \ + wordlists/russian.h \ + wordlists/spanish.h \ + wordlists/ukrainian.h \ warnings.h \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h\ @@ -221,22 +261,48 @@ libdynamic_server_a_SOURCES = \ addrdb.cpp \ addrman.cpp \ alert.cpp \ + blockencodings.cpp \ bloom.cpp \ chain.cpp \ checkpoints.cpp \ + bdap/audit.cpp \ + bdap/auditdb.cpp \ + bdap/certificatedb.cpp \ + bdap/domainentry.cpp \ + bdap/domainentrydb.cpp \ + bdap/fees.cpp \ + bdap/linking.cpp \ + bdap/linkingdb.cpp \ + bdap/linkmanager.cpp \ + bdap/linkstorage.cpp \ + bdap/utils.cpp \ + bdap/vgpmessage.cpp \ + bdap/x509certificate.cpp \ dbwrapper.cpp \ + dht/datachunk.cpp \ + dht/dataheader.cpp \ + dht/datarecord.cpp \ + dht/dataset.cpp \ + dht/limits.cpp \ + dht/mutable.cpp \ + dht/mutabledb.cpp \ + dht/session.cpp \ + dht/sessionevents.cpp \ + dht/settings.cpp \ + dht/storage.cpp \ dynode.cpp \ dynode-payments.cpp\ dynode-sync.cpp \ dynodeconfig.cpp \ dynodeman.cpp \ + fluid/banaccount.cpp \ fluid/fluid.cpp \ fluid/fluiddb.cpp \ fluid/fluiddynode.cpp \ fluid/fluidmining.cpp \ fluid/fluidmint.cpp \ - fluid/rpcfluid.cpp \ fluid/fluidsovereign.cpp \ + fluid/operations.cpp \ governance.cpp \ governance-classes.cpp \ governance-object.cpp \ @@ -249,13 +315,19 @@ libdynamic_server_a_SOURCES = \ instantsend.cpp \ merkleblock.cpp \ messagesigner.cpp \ - miner.cpp \ + miner/impl/miner-cpu.cpp \ + miner/impl/miner-gpu.cpp \ + miner/internal/hash-rate-counter.cpp \ + miner/internal/miner-base.cpp \ + miner/internal/miner-context.cpp \ + miner/internal/miners-controller.cpp \ + miner/miner-util.cpp \ + miner/miner.cpp \ net.cpp \ netfulfilledman.cpp \ net_processing.cpp \ noui.cpp \ ntp.cpp \ - operations.cpp \ policy/fees.cpp \ policy/policy.cpp \ pow.cpp \ @@ -263,14 +335,21 @@ libdynamic_server_a_SOURCES = \ privatesend-server.cpp \ psnotificationinterface.cpp \ rest.cpp \ - rpcblockchain.cpp \ - rpcdynode.cpp \ - rpcgovernance.cpp \ - rpcmining.cpp \ - rpcmisc.cpp \ - rpcnet.cpp \ - rpcrawtransaction.cpp \ - rpcserver.cpp \ + rpc/audits.cpp \ + rpc/blockchain.cpp \ + rpc/certificates.cpp \ + rpc/dht.cpp \ + rpc/domainentry.cpp \ + rpc/dynode.cpp \ + rpc/fluid.cpp \ + rpc/governance.cpp \ + rpc/linking.cpp \ + rpc/mining.cpp \ + rpc/misc.cpp \ + rpc/net.cpp \ + rpc/rawbdap.cpp \ + rpc/rawtransaction.cpp \ + rpc/server.cpp \ script/sigcache.cpp \ sendalert.cpp \ spork.cpp \ @@ -296,20 +375,22 @@ libdynamic_zmq_a_SOURCES = \ zmq/zmqpublishnotifier.cpp endif - # wallet: shared between dynamicd and dynamic-qt, but only linked # when wallet enabled libdynamic_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) libdynamic_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libdynamic_wallet_a_SOURCES = \ + bdap/stealth.cpp \ keepass.cpp \ policy/rbf.cpp \ privatesend-client.cpp \ privatesend-util.cpp \ + rpc/wallet.cpp \ + rpc/walletdump.cpp \ + uint256.cpp \ + uint256.h \ wallet/crypter.cpp \ wallet/db.cpp \ - wallet/rpcdump.cpp \ - wallet/rpcwallet.cpp \ wallet/wallet.cpp \ wallet/wallet_ismine.cpp \ wallet/walletdb.cpp \ @@ -319,21 +400,23 @@ libdynamic_wallet_a_SOURCES = \ crypto_libdynamic_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_CONFIG_INCLUDES) $(PIC_FLAGS) crypto_libdynamic_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PIC_FLAGS) crypto_libdynamic_crypto_a_SOURCES = \ - crypto/common.h \ - crypto/argon2d/argon2.h \ - crypto/argon2d/core.h \ - crypto/argon2d/encoding.h \ - crypto/argon2d/thread.h \ crypto/argon2d/argon2.c \ + crypto/argon2d/argon2.h \ crypto/argon2d/core.c \ + crypto/argon2d/core.h \ crypto/argon2d/encoding.c \ + crypto/argon2d/encoding.h \ crypto/argon2d/opt.c \ crypto/argon2d/thread.c \ - crypto/blake2/blake2b.c \ - crypto/blake2/blake2.h \ + crypto/argon2d/thread.h \ crypto/blake2/blake2-impl.h \ + crypto/blake2/blake2.h \ + crypto/blake2/blake2b.c \ crypto/blake2/blamka-round-opt.h \ crypto/blake2/blamka-round-ref.h \ + crypto/chacha20.cpp \ + crypto/chacha20.h \ + crypto/common.h \ crypto/hmac_sha256.cpp \ crypto/hmac_sha256.h \ crypto/hmac_sha512.cpp \ @@ -344,39 +427,70 @@ crypto_libdynamic_crypto_a_SOURCES = \ crypto/sha1.h \ crypto/sha256.cpp \ crypto/sha256.h \ + crypto/sha256_avx2.cpp \ + crypto/sha256_shani.cpp \ + crypto/sha256_sse4.cpp \ + crypto/sha256_sse41.cpp \ crypto/sha512.cpp \ crypto/sha512.h +# consensus: shared between all executables that validate any consensus rules. +libdynamic_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) +libdynamic_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +libdynamic_consensus_a_SOURCES = \ + amount.cpp \ + amount.h \ + arith_uint256.cpp \ + arith_uint256.h \ + consensus/merkle.cpp \ + consensus/merkle.h \ + consensus/params.h \ + consensus/validation.h \ + hash.cpp \ + hash.h \ + prevector.h \ + primitives/block.cpp \ + primitives/block.h \ + primitives/transaction.cpp \ + primitives/transaction.h \ + pubkey.cpp \ + pubkey.h \ + script/dynamicconsensus.cpp \ + script/interpreter.cpp \ + script/interpreter.h \ + script/script.cpp \ + script/script.h \ + script/script_error.cpp \ + script/script_error.h \ + serialize.h \ + tinyformat.h \ + uint256.cpp \ + uint256.h \ + version.h + # common: shared between dynamicd, and dynamic-qt and non-server tools libdynamic_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) libdynamic_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libdynamic_common_a_SOURCES = \ - amount.cpp \ - arith_uint256.cpp \ base58.cpp \ + bdap/stealth.cpp \ bip39.cpp \ chainparams.cpp \ coins.cpp \ compressor.cpp \ - consensus/merkle.cpp \ core_read.cpp \ core_write.cpp \ - hash.cpp \ + dht/ed25519.cpp \ hdchain.cpp \ key.cpp \ keystore.cpp \ netaddress.cpp \ netbase.cpp \ - primitives/block.cpp \ - primitives/transaction.cpp \ protocol.cpp \ - pubkey.cpp \ scheduler.cpp \ - script/interpreter.cpp \ - script/script.cpp \ - script/script_error.cpp \ script/sign.cpp \ script/standard.cpp \ + wallet/wallet_ismine.cpp \ $(DYNAMIC_CORE_H) # util: shared between all executables. @@ -391,12 +505,11 @@ libdynamic_util_a_SOURCES = \ compat/glibcxx_sanity.cpp \ compat/strnlen.cpp \ random.cpp \ - rpcprotocol.cpp \ + rpc/protocol.cpp \ support/cleanse.cpp \ support/lockedpool.cpp \ sync.cpp \ threadinterrupt.cpp \ - uint256.cpp \ util.cpp \ utilmoneystr.cpp \ utilstrencodings.cpp \ @@ -405,13 +518,14 @@ libdynamic_util_a_SOURCES = \ if GLIBC_BACK_COMPAT libdynamic_util_a_SOURCES += compat/glibc_compat.cpp +AM_LDFLAGS += $(COMPAT_LDFLAGS) endif # cli: shared between dynamic-cli and dynamic-qt libdynamic_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) libdynamic_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libdynamic_cli_a_SOURCES = \ - rpcclient.cpp \ + rpc/client.cpp \ $(DYNAMIC_CORE_H) nodist_libdynamic_util_a_SOURCES = $(srcdir)/obj/build.h @@ -432,11 +546,14 @@ dynamicd_LDADD = \ $(LIBDYNAMIC_COMMON) \ $(LIBUNIVALUE) \ $(LIBDYNAMIC_UTIL) \ + $(LIBDYNAMIC_CONSENSUS) \ $(LIBDYNAMIC_CRYPTO) \ + $(LIBVGP) \ $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) \ $(LIBMEMENV) \ - $(LIBSECP256K1) + $(LIBSECP256K1) \ + $(LIBTORRENT) if ENABLE_ZMQ dynamicd_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) @@ -461,7 +578,9 @@ endif dynamic_cli_LDADD = \ $(LIBDYNAMIC_CLI) \ $(LIBUNIVALUE) \ - $(LIBDYNAMIC_UTIL) + $(LIBDYNAMIC_UTIL) \ + $(LIBDYNAMIC_CRYPTO) + dynamic_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) # @@ -479,8 +598,11 @@ dynamic_tx_LDADD = \ $(LIBUNIVALUE) \ $(LIBDYNAMIC_COMMON) \ $(LIBDYNAMIC_UTIL) \ + $(LIBDYNAMIC_CONSENSUS) \ $(LIBDYNAMIC_CRYPTO) \ - $(LIBSECP256K1) + $(LIBVGP) \ + $(LIBSECP256K1) \ + $(LIBTORRENT) dynamic_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # @@ -488,27 +610,14 @@ dynamic_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # dynamicconsensus library # if BUILD_DYNAMIC_LIBS include_HEADERS = script/dynamicconsensus.h -libdynamicconsensus_la_SOURCES = \ - crypto/hmac_sha512.cpp \ - crypto/ripemd160.cpp \ - crypto/sha1.cpp \ - crypto/sha256.cpp \ - crypto/sha512.cpp \ - hash.cpp \ - primitives/transaction.cpp \ - pubkey.cpp \ - script/dynamicconsensus.cpp \ - script/interpreter.cpp \ - script/script.cpp \ - uint256.cpp \ - utilstrencodings.cpp +libdynamicconsensus_la_SOURCES = $(crypto_libdynamic_crypto_a_SOURCES) $(libdynamic_consensus_a_SOURCES) if GLIBC_BACK_COMPAT libdynamicconsensus_la_SOURCES += compat/glibc_compat.cpp endif libdynamicconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) -libdynamicconsensus_la_LIBADD = $(LIBSECP256K1) +libdynamicconsensus_la_LIBADD = $(LIBSECP256K1) $(BOOST_LIBS) libdynamicconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_DYNAMIC_INTERNAL libdynamicconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) @@ -517,10 +626,14 @@ endif CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a CLEANFILES += *.gcda *.gcno +CLEANFILES += bdap/*.gcda bdap/*.gcno +CLEANFILES += bdap/vgp/*.gcda bdap/vgp/*.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += consensus/*.gcda consensus/*.gcno CLEANFILES += crypto/*.gcda crypto/*.gcno +CLEANFILES += dht/*.gcda dht/*.gcno CLEANFILES += fluid/*.gcda fluid/*.gcno +CLEANFILES += miner/*.gcda miner/*.gcno CLEANFILES += policy/*.gcda policy/*.gcno CLEANFILES += primitives/*.gcda primitives/*.gcno CLEANFILES += script/*.gcda script/*.gcno @@ -561,14 +674,21 @@ if HARDEN $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) endif -%.pb.cc %.pb.h: %.proto - @test -f $(PROTOC) - $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $( $@ + @echo "static unsigned const char $(*F)[] = {" >> $@ + @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ + @echo "};};" >> $@ + @echo "Generated $@" \ No newline at end of file diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include new file mode 100644 index 0000000000..42f8db92ec --- /dev/null +++ b/src/Makefile.gpu.include @@ -0,0 +1,120 @@ +# +# Argon2 GPU miner +# + +LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a +LIBDYNAMIC_GPU_LDADD_EXTRA = $(LIBDYNAMIC_GPU) +LIBDYNAMIC_GPU_LDFLAGS_EXTRA = +EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) + +crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) +crypto_argon2gpu_libdynamic_gpu_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +crypto_argon2gpu_libdynamic_gpu_a_SOURCES = \ + crypto/argon2gpu/blake2b.h \ + crypto/argon2gpu/common.h \ + crypto/argon2gpu/common.cpp \ + crypto/argon2gpu/blake2b.cpp + +if ENABLE_CUDA +LIBDYNAMIC_GPU_CUDA = crypto/argon2gpu/cuda/libdynamic_gpu_cuda.a +EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_CUDA) + +LIBDYNAMIC_GPU_LDADD_EXTRA += $(LIBDYNAMIC_GPU_CUDA) +LIBDYNAMIC_GPU_LDADD_EXTRA += $(CUDA_LDLIBS) +DYNAMIC_INCLUDES += $(CUDA_CFLAGS) + +NVCCFLAGS += -arch=sm_30 -w -lineinfo -Xcompiler='--std=c++11 $(CFLAGS)' + +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_AR = $(NVCC) $(NVCCFLAGS) -lib -o +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_LIBADD = $(CUDA_LDLIBS) +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_CPPFLAGS = $(DYNAMIC_INCLUDES) +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_LIBADD += \ + crypto/argon2gpu/cuda/blake2b-kernels.cu.o \ + crypto/argon2gpu/cuda/kernels.cu.o +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_SOURCES = \ + crypto/argon2gpu/cuda/cuda-exception.h \ + crypto/argon2gpu/cuda/device.h \ + crypto/argon2gpu/cuda/global-context.h \ + crypto/argon2gpu/cuda/blake2b-kernels.h \ + crypto/argon2gpu/cuda/kernels.h \ + crypto/argon2gpu/cuda/processing-unit.h \ + crypto/argon2gpu/cuda/program-context.h \ + crypto/argon2gpu/cuda/device.cpp \ + crypto/argon2gpu/cuda/global-context.cpp \ + crypto/argon2gpu/cuda/blake2b-kernels.cu \ + crypto/argon2gpu/cuda/kernels.cu \ + crypto/argon2gpu/cuda/processing-unit.cpp \ + crypto/argon2gpu/cuda/program-context.cpp + +nvcc_FLAGS = -I. $(CUDA_CFLAGS) $(NVCCFLAGS) + +.cu.o: + $(NVCC) $(nvcc_FLAGS) -dc -o $@ -c $< + + +crypto/argon2gpu/cuda/blake2b-kernels.cu.o: crypto/argon2gpu/cuda/blake2b-kernels.cu + $(NVCC) $(nvcc_FLAGS) -dc -o $@ -c $< + +crypto/argon2gpu/cuda/blake2b-kernels.o: crypto/argon2gpu/cuda/blake2b-kernels.cu.o + $(NVCC) $(nvcc_FLAGS) -dlink -o $@ $< + +crypto/argon2gpu/cuda/kernels.cu.o: crypto/argon2gpu/cuda/kernels.cu + $(NVCC) $(nvcc_FLAGS) -dc -o $@ -c $< + +crypto/argon2gpu/cuda/kernels.o: crypto/argon2gpu/cuda/kernels.cu.o + $(NVCC) $(nvcc_FLAGS) -dlink -o $@ $< + + +else +LIBDYNAMIC_GPU_OPENCL = crypto/argon2gpu/opencl/libdynamic_gpu_opencl.a +EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_OPENCL) + +LIBDYNAMIC_GPU_LDADD_EXTRA += $(LIBDYNAMIC_GPU_OPENCL) + +if TARGET_DARWIN +LIBDYNAMIC_GPU_LDFLAGS_EXTRA += -stdlib=libc++ -framework OpenCL -L/System/Library/Frameworks/OpenCL.framework/Libraries -Wl,-x -m64 +else +LIBDYNAMIC_GPU_LDADD_EXTRA += -lOpenCL +endif + +OPENCL_KERNEL_FILES = crypto/argon2gpu/opencl/kernel.cl + +GENERATED_KERNEL_FILES = $(OPENCL_KERNEL_FILES:.cl=.cl.h) + +crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) +crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_SOURCES = \ + $(OPENCL_KERNEL_FILES) \ + crypto/argon2gpu/opencl/cl.hpp \ + crypto/argon2gpu/opencl/device.h \ + crypto/argon2gpu/opencl/global-context.h \ + crypto/argon2gpu/opencl/kernel-loader.h \ + crypto/argon2gpu/opencl/kernel-runner.h \ + crypto/argon2gpu/opencl/opencl.h \ + crypto/argon2gpu/opencl/processing-unit.h \ + crypto/argon2gpu/opencl/program-context.h \ + crypto/argon2gpu/opencl/device.cpp \ + crypto/argon2gpu/opencl/global-context.cpp \ + crypto/argon2gpu/opencl/kernel-loader.cpp \ + crypto/argon2gpu/opencl/kernel-runner.cpp \ + crypto/argon2gpu/opencl/processing-unit.cpp \ + crypto/argon2gpu/opencl/program-context.cpp + +nodist_crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_SOURCES = $(GENERATED_KERNEL_FILES) + +BUILT_SOURCES = $(GENERATED_KERNEL_FILES) +CLEANFILES += $(GENERATED_KERNEL_FILES) + +%.cl.h: %.cl + @$(MKDIR_P) $(@D) + @echo "namespace argon2gpu { namespace opencl { namespace code {" > $@ + @echo "static unsigned const char $(*F)[] = {" >> $@ + @$(HEXDUMP) -v -e '16/1 "_x%02X" "\n"' $< | $(SED) -e 's/_/\\/g; s/\\x //g; s/.*/ "&"/' >> $@ + @echo "};" >> $@ + @echo "}}}" >> $@ + @echo "Generated $@" +endif + +dynamicd_LDADD += $(LIBDYNAMIC_GPU_LDADD_EXTRA) +dynamicd_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS_EXTRA) diff --git a/src/Makefile.libtorrent.include b/src/Makefile.libtorrent.include new file mode 100644 index 0000000000..1eb2b8ff89 --- /dev/null +++ b/src/Makefile.libtorrent.include @@ -0,0 +1,288 @@ +# Copyright (c) 2018-2021 Duality Blockchain Solutions Developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +LIBTORRENT_INT = libtorrent/librasterbar.a +EXTRA_LIBRARIES += $(LIBTORRENT_INT) +LIBTORRENT += $(LIBTORRENT_INT) + +LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include +LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/ed25519/src + +LIBTORRENT_CPPFLAGS_INT = +LIBTORRENT_CPPFLAGS_INT += -Wno-deprecated-declarations -fstack-protector-all -I$(srcdir)/libtorrent + +if TARGET_WINDOWS +LIBTORRENT_CPPFLAGS_INT += -DWIN32_LEAN_AND_MEAN -D__USE_W32_SOCKETS -DWIN32 -D_WIN32 -DBOOST_ASIO_ENABLE_CANCELIO -D__USE_MINGW_ANSI_STDIO=1 +endif + +if TARGET_DARWIN +AM_LDFLAGS += -framework CoreFoundation -framework SystemConfiguration +endif + +libtorrent_librasterbar_a_CPPFLAGS = $(CPPFLAGS) $(LIBTORRENT_CPPFLAGS_INT) $(LIBTORRENT_CPPFLAGS) +libtorrent_librasterbar_a_CXXFLAGS = $(CXXFLAGS) $(PIE_FLAGS) + +libtorrent_librasterbar_a_SOURCES= \ + libtorrent/src/add_torrent_params.cpp \ + libtorrent/src/alert.cpp \ + libtorrent/src/alert_manager.cpp \ + libtorrent/src/announce_entry.cpp \ + libtorrent/src/assert.cpp \ + libtorrent/src/bandwidth_limit.cpp \ + libtorrent/src/bandwidth_manager.cpp \ + libtorrent/src/bandwidth_queue_entry.cpp \ + libtorrent/src/bdecode.cpp \ + libtorrent/src/bitfield.cpp \ + libtorrent/src/block_cache.cpp \ + libtorrent/src/bloom_filter.cpp \ + libtorrent/src/broadcast_socket.cpp \ + libtorrent/src/bt_peer_connection.cpp \ + libtorrent/src/chained_buffer.cpp \ + libtorrent/src/choker.cpp \ + libtorrent/src/close_reason.cpp \ + libtorrent/src/ConvertUTF.cpp \ + libtorrent/src/cpuid.cpp \ + libtorrent/src/crc32c.cpp \ + libtorrent/src/create_torrent.cpp \ + libtorrent/src/disk_buffer_holder.cpp \ + libtorrent/src/disk_buffer_pool.cpp \ + libtorrent/src/disk_io_job.cpp \ + libtorrent/src/disk_io_thread.cpp \ + libtorrent/src/disk_io_thread_pool.cpp \ + libtorrent/src/disk_job_fence.cpp \ + libtorrent/src/disk_job_pool.cpp \ + libtorrent/src/entry.cpp \ + libtorrent/src/enum_net.cpp \ + libtorrent/src/error_code.cpp \ + libtorrent/src/escape_string.cpp \ + libtorrent/src/ffs.cpp \ + libtorrent/src/file.cpp \ + libtorrent/src/file_pool.cpp \ + libtorrent/src/file_progress.cpp \ + libtorrent/src/file_storage.cpp \ + libtorrent/src/fingerprint.cpp \ + libtorrent/src/generate_peer_id.cpp \ + libtorrent/src/gzip.cpp \ + libtorrent/src/hasher.cpp \ + libtorrent/src/hasher512.cpp \ + libtorrent/src/hex.cpp \ + libtorrent/src/http_connection.cpp \ + libtorrent/src/http_parser.cpp \ + libtorrent/src/http_seed_connection.cpp \ + libtorrent/src/http_stream.cpp \ + libtorrent/src/http_tracker_connection.cpp \ + libtorrent/src/i2p_stream.cpp \ + libtorrent/src/identify_client.cpp \ + libtorrent/src/instantiate_connection.cpp \ + libtorrent/src/ip_filter.cpp \ + libtorrent/src/ip_notifier.cpp \ + libtorrent/src/ip_voter.cpp \ + libtorrent/src/lazy_bdecode.cpp \ + libtorrent/src/listen_socket_handle.cpp \ + libtorrent/src/lsd.cpp \ + libtorrent/src/magnet_uri.cpp \ + libtorrent/src/merkle.cpp \ + libtorrent/src/natpmp.cpp \ + libtorrent/src/packet_buffer.cpp \ + libtorrent/src/parse_url.cpp \ + libtorrent/src/part_file.cpp \ + libtorrent/src/path.cpp \ + libtorrent/src/pe_crypto.cpp \ + libtorrent/src/peer_class.cpp \ + libtorrent/src/peer_class_set.cpp \ + libtorrent/src/peer_connection.cpp \ + libtorrent/src/peer_connection_handle.cpp \ + libtorrent/src/peer_info.cpp \ + libtorrent/src/peer_list.cpp \ + libtorrent/src/performance_counters.cpp \ + libtorrent/src/piece_picker.cpp \ + libtorrent/src/platform_util.cpp \ + libtorrent/src/proxy_base.cpp \ + libtorrent/src/proxy_settings.cpp \ + libtorrent/src/puff.cpp \ + libtorrent/src/random.cpp \ + libtorrent/src/read_resume_data.cpp \ + libtorrent/src/receive_buffer.cpp \ + libtorrent/src/request_blocks.cpp \ + libtorrent/src/resolve_links.cpp \ + libtorrent/src/resolver.cpp \ + libtorrent/src/session.cpp \ + libtorrent/src/session_call.cpp \ + libtorrent/src/session_handle.cpp \ + libtorrent/src/session_impl.cpp \ + libtorrent/src/session_settings.cpp \ + libtorrent/src/session_stats.cpp \ + libtorrent/src/settings_pack.cpp \ + libtorrent/src/sha1.cpp \ + libtorrent/src/sha1_hash.cpp \ + libtorrent/src/sha512.cpp \ + libtorrent/src/smart_ban.cpp \ + libtorrent/src/socket_io.cpp \ + libtorrent/src/socket_type.cpp \ + libtorrent/src/socks5_stream.cpp \ + libtorrent/src/stack_allocator.cpp \ + libtorrent/src/stat.cpp \ + libtorrent/src/stat_cache.cpp \ + libtorrent/src/storage.cpp \ + libtorrent/src/storage_piece_set.cpp \ + libtorrent/src/storage_utils.cpp \ + libtorrent/src/string_util.cpp \ + libtorrent/src/time.cpp \ + libtorrent/src/timestamp_history.cpp \ + libtorrent/src/torrent.cpp \ + libtorrent/src/torrent_handle.cpp \ + libtorrent/src/torrent_info.cpp \ + libtorrent/src/torrent_peer.cpp \ + libtorrent/src/torrent_peer_allocator.cpp \ + libtorrent/src/torrent_status.cpp \ + libtorrent/src/tracker_manager.cpp \ + libtorrent/src/udp_socket.cpp \ + libtorrent/src/udp_tracker_connection.cpp \ + libtorrent/src/upnp.cpp \ + libtorrent/src/ut_metadata.cpp \ + libtorrent/src/ut_pex.cpp \ + libtorrent/src/utf8.cpp \ + libtorrent/src/utp_socket_manager.cpp \ + libtorrent/src/utp_stream.cpp \ + libtorrent/src/version.cpp \ + libtorrent/src/web_connection_base.cpp \ + libtorrent/src/web_peer_connection.cpp \ + libtorrent/src/write_resume_data.cpp \ + libtorrent/src/xml_parse.cpp \ + libtorrent/src/kademlia/dht_settings.cpp \ + libtorrent/src/kademlia/dht_state.cpp \ + libtorrent/src/kademlia/dht_storage.cpp \ + libtorrent/src/kademlia/dht_tracker.cpp \ + libtorrent/src/kademlia/dos_blocker.cpp \ + libtorrent/src/kademlia/ed25519.cpp \ + libtorrent/src/kademlia/find_data.cpp \ + libtorrent/src/kademlia/get_item.cpp \ + libtorrent/src/kademlia/get_peers.cpp \ + libtorrent/src/kademlia/item.cpp \ + libtorrent/src/kademlia/msg.cpp \ + libtorrent/src/kademlia/node.cpp \ + libtorrent/src/kademlia/node_entry.cpp \ + libtorrent/src/kademlia/node_id.cpp \ + libtorrent/src/kademlia/put_data.cpp \ + libtorrent/src/kademlia/refresh.cpp \ + libtorrent/src/kademlia/routing_table.cpp \ + libtorrent/src/kademlia/rpc_manager.cpp \ + libtorrent/src/kademlia/sample_infohashes.cpp \ + libtorrent/src/kademlia/traversal_algorithm.cpp \ + libtorrent/ed25519/src/add_scalar.cpp \ + libtorrent/ed25519/src/fe.cpp \ + libtorrent/ed25519/src/ge.cpp \ + libtorrent/ed25519/src/key_exchange.cpp \ + libtorrent/ed25519/src/keypair.cpp \ + libtorrent/ed25519/src/sc.cpp \ + libtorrent/ed25519/src/sign.cpp \ + libtorrent/ed25519/src/verify.cpp + +LIBTORRENT_DOCS_IMAGES = \ + libtorrent/docs/client_test.png \ + libtorrent/docs/cwnd.png \ + libtorrent/docs/cwnd_thumb.png \ + libtorrent/docs/delays.png \ + libtorrent/docs/delays_thumb.png \ + libtorrent/docs/hacking.html \ + libtorrent/docs/merkle_tree.png \ + libtorrent/docs/our_delay_base.png \ + libtorrent/docs/our_delay_base_thumb.png \ + libtorrent/docs/read_disk_buffers.png \ + libtorrent/docs/read_disk_buffers.diagram \ + libtorrent/docs/storage.png \ + libtorrent/docs/todo.html \ + libtorrent/docs/write_disk_buffers.png \ + libtorrent/docs/write_disk_buffers.diagram \ + libtorrent/docs/ip_id_v4.png \ + libtorrent/docs/ip_id_v6.png \ + libtorrent/docs/hash_distribution.png \ + libtorrent/docs/complete_bit_prefixes.png \ + libtorrent/docs/troubleshooting.dot \ + libtorrent/docs/troubleshooting.png \ + libtorrent/docs/troubleshooting_thumb.png \ + libtorrent/docs/hacking.diagram \ + libtorrent/docs/hacking.png \ + libtorrent/docs/disk_cache.diagram \ + libtorrent/docs/disk_cache.png \ + libtorrent/docs/utp_stack.diagram \ + libtorrent/docs/utp_stack.png \ + libtorrent/docs/bitcoin.png \ + libtorrent/docs/style.css \ + libtorrent/docs/rst.css \ + libtorrent/docs/img/bg.png \ + libtorrent/docs/img/blue_bottom.png \ + libtorrent/docs/img/blue_top.png \ + libtorrent/docs/img/dotline.gif \ + libtorrent/docs/img/minus.gif \ + libtorrent/docs/img/orange.png + +LIBTORRENT_DOCS_PAGES = \ + libtorrent/docs/building.html \ + libtorrent/docs/client_test.html \ + libtorrent/docs/contributing.html \ + libtorrent/docs/dht_extensions.html \ + libtorrent/docs/dht_rss.html \ + libtorrent/docs/dht_sec.html \ + libtorrent/docs/dht_store.html \ + libtorrent/docs/examples.html \ + libtorrent/docs/extension_protocol.html \ + libtorrent/docs/features.html \ + libtorrent/docs/index.html \ + libtorrent/docs/manual-ref.html \ + libtorrent/docs/projects.html \ + libtorrent/docs/python_binding.html \ + libtorrent/docs/tuning.html \ + libtorrent/docs/settings.rst \ + libtorrent/docs/stats_counters.rst \ + libtorrent/docs/troubleshooting.html \ + libtorrent/docs/udp_tracker_protocol.html \ + libtorrent/docs/utp.html \ + libtorrent/docs/streaming.html \ + libtorrent/docs/building.rst \ + libtorrent/docs/client_test.rst \ + libtorrent/docs/contributing.rst \ + libtorrent/docs/dht_extensions.rst \ + libtorrent/docs/dht_rss.rst \ + libtorrent/docs/dht_sec.rst \ + libtorrent/docs/dht_store.rst \ + libtorrent/docs/examples.rst \ + libtorrent/docs/extension_protocol.rst \ + libtorrent/docs/features.rst \ + libtorrent/docs/index.rst \ + libtorrent/docs/manual-ref.rst \ + libtorrent/docs/projects.rst \ + libtorrent/docs/python_binding.rst \ + libtorrent/docs/tuning.rst \ + libtorrent/docs/troubleshooting.rst \ + libtorrent/docs/udp_tracker_protocol.rst \ + libtorrent/docs/utp.rst \ + libtorrent/docs/streaming.rst \ + libtorrent/docs/tutorial.rst \ + libtorrent/docs/tutorial.html \ + libtorrent/docs/reference-Alerts.html \ + libtorrent/docs/reference-Bdecoding.html \ + libtorrent/docs/reference-Bencoding.html \ + libtorrent/docs/reference-Core.html \ + libtorrent/docs/reference-Create_Torrents.html \ + libtorrent/docs/reference-Custom_Storage.html \ + libtorrent/docs/reference-ed25519.html \ + libtorrent/docs/reference-Error_Codes.html \ + libtorrent/docs/reference-Filter.html \ + libtorrent/docs/reference-Plugins.html \ + libtorrent/docs/reference-Settings.html \ + libtorrent/docs/reference-Storage.html \ + libtorrent/docs/reference-Utility.html \ + libtorrent/docs/reference.html \ + libtorrent/docs/single-page-ref.html + +LIBTORRENT_EXTRA_DIST = \ + libtorrent/Jamfile \ + libtorrent/Jamroot.jam \ + libtorrent/CMakeLists.txt \ + libtorrent/setup.py \ + libtorrent/LICENSE \ + libtorrent/README.rst \ + $(LIBTORRENT_DOCS_PAGES) \ + $(LIBTORRENT_DOCS_IMAGES) \ No newline at end of file diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 7b8f6846cb..26552211d2 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -12,6 +12,7 @@ QT_TS = \ qt/locale/dynamic_it.ts \ qt/locale/dynamic_ja.ts \ qt/locale/dynamic_ko.ts \ + qt/locale/dynamic_nl.ts \ qt/locale/dynamic_pl.ts \ qt/locale/dynamic_pt.ts \ qt/locale/dynamic_ru.ts \ @@ -24,12 +25,19 @@ QT_TS = \ QT_FORMS_UI = \ qt/forms/addressbookpage.ui \ qt/forms/askpassphrasedialog.ui \ + qt/forms/bdapaddlinkdialog.ui \ + qt/forms/bdapadduserdialog.ui \ + qt/forms/bdaplinkdetaildialog.ui \ + qt/forms/bdappage.ui \ + qt/forms/bdapupdateaccountdialog.ui \ + qt/forms/bdapuserdetaildialog.ui \ qt/forms/coincontroldialog.ui \ qt/forms/dynodelist.ui \ qt/forms/editaddressdialog.ui \ qt/forms/helpmessagedialog.ui \ qt/forms/intro.ui \ qt/forms/miningpage.ui \ + qt/forms/mnemonicdialog.ui \ qt/forms/modaloverlay.ui \ qt/forms/openuridialog.ui \ qt/forms/optionsdialog.ui \ @@ -41,13 +49,22 @@ QT_FORMS_UI = \ qt/forms/sendcoinsdialog.ui \ qt/forms/sendcoinsentry.ui \ qt/forms/signverifymessagedialog.ui \ - qt/forms/transactiondescdialog.ui + qt/forms/transactiondescdialog.ui QT_MOC_CPP = \ qt/moc_addressbookpage.cpp \ qt/moc_addresstablemodel.cpp \ qt/moc_askpassphrasedialog.cpp \ qt/moc_bantablemodel.cpp \ + qt/moc_bdapaccounttablemodel.cpp \ + qt/moc_bdapaddlinkdialog.cpp \ + qt/moc_bdapadduserdialog.cpp \ + qt/moc_bdapfeespopup.cpp \ + qt/moc_bdaplinkdetaildialog.cpp \ + qt/moc_bdaplinktablemodel.cpp \ + qt/moc_bdappage.cpp \ + qt/moc_bdapupdateaccountdialog.cpp \ + qt/moc_bdapuserdetaildialog.cpp \ qt/moc_clientmodel.cpp \ qt/moc_coincontroldialog.cpp \ qt/moc_coincontroltreewidget.cpp \ @@ -64,6 +81,7 @@ QT_MOC_CPP = \ qt/moc_macdockiconhandler.cpp \ qt/moc_macnotificationhandler.cpp \ qt/moc_miningpage.cpp \ + qt/moc_mnemonicdialog.cpp \ qt/moc_modaloverlay.cpp \ qt/moc_notificator.cpp \ qt/moc_openuridialog.cpp \ @@ -71,7 +89,6 @@ QT_MOC_CPP = \ qt/moc_optionsmodel.cpp \ qt/moc_overviewpage.cpp \ qt/moc_peertablemodel.cpp \ - qt/moc_paymentserver.cpp \ qt/moc_privatesendconfig.cpp \ qt/moc_qvalidatedlineedit.cpp \ qt/moc_qvaluecombobox.cpp \ @@ -110,15 +127,20 @@ QT_QRC = qt/dynamic.qrc QT_QRC_LOCALE_CPP = qt/qrc_dynamic_locale.cpp QT_QRC_LOCALE = qt/dynamic_locale.qrc -PROTOBUF_CC = qt/paymentrequest.pb.cc -PROTOBUF_H = qt/paymentrequest.pb.h -PROTOBUF_PROTO = qt/paymentrequest.proto - DYNAMIC_QT_H = \ qt/addressbookpage.h \ qt/addresstablemodel.h \ qt/askpassphrasedialog.h \ qt/bantablemodel.h \ + qt/bdapaccounttablemodel.h \ + qt/bdapaddlinkdialog.h \ + qt/bdapadduserdialog.h \ + qt/bdapfeespopup.h \ + qt/bdaplinkdetaildialog.h \ + qt/bdaplinktablemodel.h \ + qt/bdappage.h \ + qt/bdapupdateaccountdialog.h \ + qt/bdapuserdetaildialog.h \ qt/clientmodel.h \ qt/coincontroldialog.h \ qt/coincontroltreewidget.h \ @@ -136,6 +158,7 @@ DYNAMIC_QT_H = \ qt/macdockiconhandler.h \ qt/macnotificationhandler.h \ qt/miningpage.h \ + qt/mnemonicdialog.h \ qt/modaloverlay.h \ qt/networkstyle.h \ qt/notificator.h \ @@ -143,8 +166,6 @@ DYNAMIC_QT_H = \ qt/optionsdialog.h \ qt/optionsmodel.h \ qt/overviewpage.h \ - qt/paymentrequestplus.h \ - qt/paymentserver.h \ qt/peertablemodel.h \ qt/platformstyle.h \ qt/privatesendconfig.h \ @@ -172,7 +193,7 @@ DYNAMIC_QT_H = \ qt/walletmodeltransaction.h \ qt/walletview.h \ qt/winshutdownmonitor.h - + RES_ICONS = \ qt/res/icons/dynamic.icns \ qt/res/icons/dynamic.ico \ @@ -181,6 +202,7 @@ RES_ICONS = \ qt/res/icons/drk/about_qt.png \ qt/res/icons/drk/add.png \ qt/res/icons/drk/address-book.png \ + qt/res/icons/drk/bdap.png \ qt/res/icons/drk/browse.png \ qt/res/icons/drk/chevron.png \ qt/res/icons/drk/clock1.png \ @@ -195,7 +217,6 @@ RES_ICONS = \ qt/res/icons/drk/connect3_16.png \ qt/res/icons/drk/connect4_16.png \ qt/res/icons/drk/debugwindow.png \ - qt/res/icons/drk/decentralised.png \ qt/res/icons/drk/drkpurple_editpaste.png \ qt/res/icons/drk/drkpurple_address-book.png \ qt/res/icons/drk/drkpurple_editcopy.png \ @@ -221,11 +242,15 @@ RES_ICONS = \ qt/res/icons/drk/lock_open.png \ qt/res/icons/drk/notsynced.png \ qt/res/icons/drk/overview.png \ + qt/res/icons/drk/pos.png \ qt/res/icons/drk/quit.png \ qt/res/icons/drk/receive.png \ qt/res/icons/drk/remove.png \ qt/res/icons/drk/send.png \ + qt/res/icons/drk/staking_active.png \ + qt/res/icons/drk/staking_inactive.png \ qt/res/icons/drk/synced.png \ + qt/res/icons/drk/transaction_abandoned.png \ qt/res/icons/drk/transaction_conflicted.png \ qt/res/icons/drk/transaction0.png \ qt/res/icons/drk/transaction2.png \ @@ -238,12 +263,14 @@ RES_ICONS = \ qt/res/icons/drk/unit_satoshis.png \ qt/res/icons/drk/unit_udyn.png \ qt/res/icons/drk/fontbigger.png \ - qt/res/icons/drk/fontsmaller.png \ + qt/res/icons/drk/fontsmaller.png \ qt/res/icons/drk/verify.png \ qt/res/icons/drk/warning.png DYNAMIC_QT_CPP = \ qt/bantablemodel.cpp \ + qt/bdapaccounttablemodel.cpp \ + qt/bdaplinktablemodel.cpp \ qt/clientmodel.cpp \ qt/csvmodelwriter.cpp \ qt/dynamicaddressvalidator.cpp \ @@ -276,16 +303,22 @@ DYNAMIC_QT_CPP += \ qt/addressbookpage.cpp \ qt/addresstablemodel.cpp \ qt/askpassphrasedialog.cpp \ + qt/bdapaddlinkdialog.cpp \ + qt/bdapadduserdialog.cpp \ + qt/bdapfeespopup.cpp \ + qt/bdaplinkdetaildialog.cpp \ + qt/bdappage.cpp \ + qt/bdapupdateaccountdialog.cpp \ + qt/bdapuserdetaildialog.cpp \ qt/coincontroldialog.cpp \ qt/coincontroltreewidget.cpp \ qt/dynodelist.cpp \ qt/editaddressdialog.cpp \ qt/hashrategraphwidget.cpp \ qt/miningpage.cpp \ + qt/mnemonicdialog.cpp \ qt/openuridialog.cpp \ qt/overviewpage.cpp \ - qt/paymentrequestplus.cpp \ - qt/paymentserver.cpp \ qt/privatesendconfig.cpp \ qt/receivecoinsdialog.cpp \ qt/receiverequestdialog.cpp \ @@ -319,10 +352,10 @@ RES_IMAGES = \ qt/res/images/drk/dynamic_logo_horizontal.png \ qt/res/images/drk/splash_testnet.png \ qt/res/images/drk/splash.png \ - qt/res/images/drk/unchecked.png + qt/res/images/drk/unchecked.png RES_CSS = \ - qt/res/css/drk.css + qt/res/css/drk.css RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png) @@ -332,14 +365,14 @@ DYNAMIC_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \ -I$(builddir)/qt/forms -DQT_NO_KEYWORDS qt_libdynamicqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) $(DYNAMIC_QT_INCLUDES) \ - $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) + $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS) qt_libdynamicqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) qt_libdynamicqt_a_SOURCES = $(DYNAMIC_QT_CPP) $(DYNAMIC_QT_H) $(QT_FORMS_UI) \ - $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_CSS) $(RES_MOVIES) + $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(RES_ICONS) $(RES_IMAGES) $(RES_CSS) $(RES_MOVIES) -nodist_qt_libdynamicqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \ - $(PROTOBUF_H) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP) +nodist_qt_libdynamicqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) \ + $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP) # forms/foo.h -> forms/ui_foo.h QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h)))) @@ -349,14 +382,9 @@ QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI: $(QT_MOC): $(QT_FORMS_H) $(qt_libdynamicqt_a_OBJECTS) $(qt_dynamic_qt_OBJECTS) : | $(QT_MOC) -#Generating these with a half-written protobuf header leads to wacky results. -#This makes sure it's done. -$(QT_MOC): $(PROTOBUF_H) -$(QT_MOC_CPP): $(PROTOBUF_H) - # dynamic-qt binary # qt_dynamic_qt_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) $(DYNAMIC_QT_INCLUDES) \ - $(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) + $(QT_INCLUDES) $(QR_CFLAGS) qt_dynamic_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) qt_dynamic_qt_SOURCES = qt/dynamic.cpp @@ -370,13 +398,18 @@ qt_dynamic_qt_LDADD = qt/libdynamicqt.a $(LIBDYNAMIC_SERVER) if ENABLE_WALLET qt_dynamic_qt_LDADD += $(LIBDYNAMIC_WALLET) endif +qt_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +if ENABLE_GPU +qt_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD_EXTRA) +qt_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS_EXTRA) +endif if ENABLE_ZMQ qt_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) endif -qt_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \ - $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ + +qt_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CONSENSUS) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBVGP) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \ + $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBTORRENT) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) -qt_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) qt_dynamic_qt_LIBTOOLFLAGS = --tag CXX #locale/foo.ts -> locale/foo.qm @@ -398,7 +431,7 @@ $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name dynamic_locale $(@D)/$( $@ -$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_CSS) $(RES_MOVIES) $(PROTOBUF_H) +$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_CSS) $(RES_MOVIES) @test -f $(RCC) $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name dynamic $< | \ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 39a616a8a1..88a4787682 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -5,22 +5,16 @@ TEST_QT_MOC_CPP = \ qt/test/moc_compattests.cpp \ qt/test/moc_rpcnestedtests.cpp \ qt/test/moc_trafficgraphdatatests.cpp \ - qt/test/moc_uritests.cpp - -if ENABLE_WALLET -TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp -endif + qt/test/moc_uritests.cpp TEST_QT_H = \ qt/test/compattests.h \ qt/test/rpcnestedtests.h \ qt/test/uritests.h \ - qt/test/paymentrequestdata.h \ - qt/test/paymentservertests.h \ qt/test/trafficgraphdatatests.h qt_test_test_dynamic_qt_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) $(DYNAMIC_QT_INCLUDES) \ - $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) + $(QT_INCLUDES) $(QT_TEST_INCLUDES) qt_test_test_dynamic_qt_SOURCES = \ qt/test/compattests.cpp \ @@ -29,13 +23,8 @@ qt_test_test_dynamic_qt_SOURCES = \ qt/test/uritests.cpp \ qt/test/trafficgraphdatatests.cpp \ $(TEST_QT_H) -if ENABLE_WALLET -qt_test_test_dynamic_qt_SOURCES += \ - qt/test/paymentservertests.cpp -endif nodist_qt_test_test_dynamic_qt_SOURCES = $(TEST_QT_MOC_CPP) - qt_test_test_dynamic_qt_LDADD = $(LIBDYNAMICQT) $(LIBDYNAMIC_SERVER) if ENABLE_WALLET qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_WALLET) @@ -43,11 +32,16 @@ endif if ENABLE_ZMQ qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) endif -qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ +qt_test_test_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +if ENABLE_GPU +qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD_EXTRA) +qt_test_test_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS_EXTRA) +endif + +qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CONSENSUS) $(LIBVGP) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ - $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ + $(QR_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBTORRENT) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) -qt_test_test_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) qt_test_test_dynamic_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) CLEAN_DYNAMIC_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c8222f3447..2499891dec 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -27,6 +27,8 @@ JSON_TEST_FILES = \ test/data/base58_encode_decode.json \ test/data/base58_keys_invalid.json \ test/data/bip39_vectors.json \ + test/data/proposals_valid.json \ + test/data/proposals_invalid.json \ test/data/tx_invalid.json \ test/data/tx_valid.json \ test/data/sighash.json @@ -41,20 +43,26 @@ DYNAMIC_TESTS =\ test/addrman_tests.cpp \ test/alert_tests.cpp \ test/allocator_tests.cpp \ + test/audit_tests.cpp \ test/base32_tests.cpp \ test/base58_tests.cpp \ test/base64_tests.cpp \ + test/bdap_link_tests.cpp \ + test/bdap_vgp_message_tests.cpp \ test/bip32_tests.cpp \ test/bip39_tests.cpp \ + test/blockencodings_tests.cpp \ test/bloom_tests.cpp \ test/bswap_tests.cpp \ test/cachemap_tests.cpp \ test/cachemultimap_tests.cpp \ + test/certificatex509_tests.cpp \ test/checkblock_tests.cpp \ - test/Checkpoints_tests.cpp \ test/coins_tests.cpp \ test/compress_tests.cpp \ test/crypto_tests.cpp \ + test/dht_data_tests.cpp \ + test/dht_key_tests.cpp \ test/DoS_tests.cpp \ test/getarg_tests.cpp \ test/governance_validators_tests.cpp \ @@ -102,25 +110,29 @@ DYNAMIC_TESTS =\ if ENABLE_WALLET DYNAMIC_TESTS += \ - test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp endif test_test_dynamic_SOURCES = $(DYNAMIC_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_dynamic_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) -test_test_dynamic_LDADD = $(LIBDYNAMIC_SERVER) $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) \ + +test_test_dynamic_LDADD = $(LIBDYNAMIC_SERVER) $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CONSENSUS) $(LIBDYNAMIC_CRYPTO) $(LIBVGP) $(LIBUNIVALUE) $(LIBTORRENT) \ $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) test_test_dynamic_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) if ENABLE_WALLET test_test_dynamic_LDADD += $(LIBDYNAMIC_WALLET) endif -test_test_dynamic_LDADD += $(LIBDYNAMIC_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) +test_test_dynamic_LDADD += $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) test_test_dynamic_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static if ENABLE_ZMQ test_test_dynamic_LDADD += $(ZMQ_LIBS) endif +if ENABLE_GPU +test_test_dynamic_LDADD += $(LIBDYNAMIC_GPU_LDADD_EXTRA) +test_test_dynamic_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS_EXTRA) +endif nodist_test_test_dynamic_SOURCES = $(GENERATED_TEST_FILES) diff --git a/src/Makefile.vgp.include b/src/Makefile.vgp.include new file mode 100644 index 0000000000..b27bfde0fe --- /dev/null +++ b/src/Makefile.vgp.include @@ -0,0 +1,37 @@ +# Copyright (c) 2018-2021 Duality Blockchain Solutions Developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +LIBVGP= +LIBVGP_CPPFLAGS= + +LIBVGP_INT = bdap/vgp/libvgp.a +EXTRA_LIBRARIES += $(LIBVGP_INT) +LIBVGP += $(LIBVGP_INT) + +LIBVGP_CPPFLAGS += -I$(srcdir)/bdap/vgp/include + +LIBVGP_CPPFLAGS_INT = +LIBVGP_CPPFLAGS_INT += -Wno-deprecated-declarations -fstack-protector-all -I$(srcdir)/bdap/vgp/src + +bdap_vgp_libvgp_a_CPPFLAGS = $(CPPFLAGS) $(LIBVGP_CPPFLAGS_INT) $(LIBVGP_CPPFLAGS) +bdap_vgp_libvgp_a_CXXFLAGS = $(CXXFLAGS) $(PIE_FLAGS) + +bdap_vgp_libvgp_a_SOURCES= \ + bdap/vgp/src/aes256.c \ + bdap/vgp/src/aes256ctr.c \ + bdap/vgp/src/aes256gcm.c \ + bdap/vgp/src/curve25519.c \ + bdap/vgp/src/ed25519.c \ + bdap/vgp/src/encryption.cpp \ + bdap/vgp/src/encryption_core.c \ + bdap/vgp/src/encryption_error.c \ + bdap/vgp/src/ed25519.c \ + bdap/vgp/src/fe.c \ + bdap/vgp/src/ge.c \ + bdap/vgp/src/os_rand.c \ + bdap/vgp/src/rand.c \ + bdap/vgp/src/sha512.c \ + bdap/vgp/src/shake256.c \ + bdap/vgp/src/shake256_rand.c \ + bdap/vgp/src/utils.c \ No newline at end of file diff --git a/src/activedynode.cpp b/src/activedynode.cpp index 75553a5483..a6f5dae895 100644 --- a/src/activedynode.cpp +++ b/src/activedynode.cpp @@ -1,15 +1,16 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "activedynode.h" -#include "dynode.h" #include "dynode-sync.h" +#include "dynode.h" #include "dynodeman.h" +#include "init.h" #include "netbase.h" #include "protocol.h" @@ -20,31 +21,37 @@ extern CWallet* pwalletMain; // Keep track of the active Dynode CActiveDynode activeDynode; +void CActiveDynode::DoMaintenance(CConnman &connman) +{ + if (ShutdownRequested()) return; + ManageState(connman); +} + void CActiveDynode::ManageState(CConnman& connman) { - LogPrint("Dynode", "CActiveDynode::ManageState -- Start\n"); - if(!fDynodeMode) { - LogPrint("Dynode", "CActiveDynode::ManageState -- Not a Dynode, returning\n"); + LogPrint("dynode", "CActiveDynode::ManageState -- Start\n"); + if (!fDynodeMode) { + LogPrint("dynode", "CActiveDynode::ManageState -- Not a Dynode, returning\n"); return; } - if(Params().NetworkIDString() != CBaseChainParams::REGTEST && !dynodeSync.IsBlockchainSynced()) { + if (Params().NetworkIDString() != CBaseChainParams::REGTEST && !dynodeSync.IsBlockchainSynced()) { nState = ACTIVE_DYNODE_SYNC_IN_PROCESS; LogPrintf("CActiveDynode::ManageState -- %s: %s\n", GetStateString(), GetStatus()); return; } - if(nState == ACTIVE_DYNODE_SYNC_IN_PROCESS) { + if (nState == ACTIVE_DYNODE_SYNC_IN_PROCESS) { nState = ACTIVE_DYNODE_INITIAL; } - LogPrint("Dynode", "CActiveDynode::ManageState -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled); + LogPrint("dynode", "CActiveDynode::ManageState -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled); - if(eType == DYNODE_UNKNOWN) { + if (eType == DYNODE_UNKNOWN) { ManageStateInitial(connman); } - if(eType == DYNODE_REMOTE) { + if (eType == DYNODE_REMOTE) { ManageStateRemote(); } @@ -54,31 +61,43 @@ void CActiveDynode::ManageState(CConnman& connman) std::string CActiveDynode::GetStateString() const { switch (nState) { - case ACTIVE_DYNODE_INITIAL: return "INITIAL"; - case ACTIVE_DYNODE_SYNC_IN_PROCESS: return "SYNC_IN_PROCESS"; - case ACTIVE_DYNODE_INPUT_TOO_NEW: return "INPUT_TOO_NEW"; - case ACTIVE_DYNODE_NOT_CAPABLE: return "NOT_CAPABLE"; - case ACTIVE_DYNODE_STARTED: return "STARTED"; - default: return "UNKNOWN"; + case ACTIVE_DYNODE_INITIAL: + return "INITIAL"; + case ACTIVE_DYNODE_SYNC_IN_PROCESS: + return "SYNC_IN_PROCESS"; + case ACTIVE_DYNODE_INPUT_TOO_NEW: + return "INPUT_TOO_NEW"; + case ACTIVE_DYNODE_NOT_CAPABLE: + return "NOT_CAPABLE"; + case ACTIVE_DYNODE_STARTED: + return "STARTED"; + default: + return "UNKNOWN"; } } std::string CActiveDynode::GetStatus() const { switch (nState) { - case ACTIVE_DYNODE_INITIAL: return "Node just started, not yet activated"; - case ACTIVE_DYNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Dynode"; - case ACTIVE_DYNODE_INPUT_TOO_NEW: return strprintf("Dynode input must have at least %d confirmations", Params().GetConsensus().nDynodeMinimumConfirmations); - case ACTIVE_DYNODE_NOT_CAPABLE: return "Not capable Dynode: " + strNotCapableReason; - case ACTIVE_DYNODE_STARTED: return "Dynode successfully started"; - default: return "Unknown"; + case ACTIVE_DYNODE_INITIAL: + return "Node just started, not yet activated"; + case ACTIVE_DYNODE_SYNC_IN_PROCESS: + return "Sync in progress. Must wait until sync is complete to start Dynode"; + case ACTIVE_DYNODE_INPUT_TOO_NEW: + return strprintf("Dynode input must have at least %d confirmations", Params().GetConsensus().nDynodeMinimumConfirmations); + case ACTIVE_DYNODE_NOT_CAPABLE: + return "Not capable Dynode: " + strNotCapableReason; + case ACTIVE_DYNODE_STARTED: + return "Dynode successfully started"; + default: + return "Unknown"; } } std::string CActiveDynode::GetTypeString() const { std::string strType; - switch(eType) { + switch (eType) { case DYNODE_REMOTE: strType = "REMOTE"; break; @@ -91,12 +110,12 @@ std::string CActiveDynode::GetTypeString() const bool CActiveDynode::SendDynodePing(CConnman& connman) { - if(!fPingerEnabled) { - LogPrint("Dynode", "CActiveDynode::SendDynodePing -- %s: Dynode ping service is disabled, skipping...\n", GetStateString()); + if (!fPingerEnabled) { + LogPrint("dynode", "CActiveDynode::SendDynodePing -- %s: Dynode ping service is disabled, skipping...\n", GetStateString()); return false; } - if(!dnodeman.Has(outpoint)) { + if (!dnodeman.Has(outpoint)) { strNotCapableReason = "Dynode not in Dynode list"; nState = ACTIVE_DYNODE_NOT_CAPABLE; LogPrintf("CActiveDynode::SendDynodePing -- %s: %s\n", GetStateString(), strNotCapableReason); @@ -106,14 +125,14 @@ bool CActiveDynode::SendDynodePing(CConnman& connman) CDynodePing dnp(outpoint); dnp.nSentinelVersion = nSentinelVersion; dnp.fSentinelIsCurrent = - (llabs(GetAdjustedTime() - nSentinelPingTime) < DYNODE_SENTINEL_PING_MAX_SECONDS); - if(!dnp.Sign(keyDynode, pubKeyDynode)) { + (llabs(GetAdjustedTime() - nSentinelPingTime) < DYNODE_SENTINEL_PING_MAX_SECONDS); + if (!dnp.Sign(keyDynode, pubKeyDynode)) { LogPrintf("CActiveDynode::SendDynodePing -- ERROR: Couldn't sign Dynode Ping\n"); return false; } // Update lastPing for our Dynode in Dynode list - if(dnodeman.IsDynodePingedWithin(outpoint, DYNODE_MIN_DNP_SECONDS, dnp.sigTime)) { + if (dnodeman.IsDynodePingedWithin(outpoint, DYNODE_MIN_DNP_SECONDS, dnp.sigTime)) { LogPrintf("CActiveDynode::SendDynodePing -- Too early to send Dynode Ping\n"); return false; } @@ -136,7 +155,7 @@ bool CActiveDynode::UpdateSentinelPing(int version) void CActiveDynode::ManageStateInitial(CConnman& connman) { - LogPrint("Dynode", "CActiveDynode::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled); + LogPrint("dynode", "CActiveDynode::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled); // Check that our local network configuration is correct if (!fListen) { // listen option is probably overwritten by smth else, no good @@ -148,7 +167,7 @@ void CActiveDynode::ManageStateInitial(CConnman& connman) // First try to find whatever local address is specified by externalip option bool fFoundLocal = GetLocal(service) && CDynode::IsValidNetAddr(service); - if(!fFoundLocal) { + if (!fFoundLocal) { bool empty = true; // If we have some peers, let's try to find our local address from one of them connman.ForEachNodeContinueIf(CConnman::AllNodes, [&fFoundLocal, &empty, this](CNode* pnode) { @@ -166,42 +185,27 @@ void CActiveDynode::ManageStateInitial(CConnman& connman) } } - if(!fFoundLocal) { + if (!fFoundLocal) { nState = ACTIVE_DYNODE_NOT_CAPABLE; strNotCapableReason = "Can't detect valid external address. Please consider using the externalip configuration option if problem persists. Make sure to use IPv4 address only."; LogPrintf("CActiveDynode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason); return; } - - int mainnetDefaultPort = DEFAULT_P2P_PORT; - int testnetDefaultPort = DEFAULT_P2P_PORT + 100; - int regTestnetDefaultPort = DEFAULT_P2P_PORT + 200; - - if(Params().NetworkIDString() == CBaseChainParams::MAIN) { - if(service.GetPort() != mainnetDefaultPort) { - nState = ACTIVE_DYNODE_NOT_CAPABLE; - strNotCapableReason = strprintf("Invalid port: %u - only %u is supported on mainnet.", service.GetPort(), mainnetDefaultPort); - LogPrintf("CActiveDynode::ManageStatus() - not capable: %s\n", strNotCapableReason); - return; - } - } - - if(Params().NetworkIDString() != CBaseChainParams::TESTNET) { - if(service.GetPort() == testnetDefaultPort) { - nState = ACTIVE_DYNODE_NOT_CAPABLE; - strNotCapableReason = strprintf("Invalid port: %u - only %u is supported on testnnet.", service.GetPort(), testnetDefaultPort); - LogPrintf("CActiveDynode::ManageStatus() - not capable: %s\n", strNotCapableReason); - return; - } - } - if(Params().NetworkIDString() != CBaseChainParams::REGTEST) { - if(service.GetPort() == regTestnetDefaultPort) { + int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort(); + + if (Params().NetworkIDString() == CBaseChainParams::MAIN) { + if (service.GetPort() != mainnetDefaultPort) { nState = ACTIVE_DYNODE_NOT_CAPABLE; - strNotCapableReason = strprintf("Invalid port: %u - only %u is supported on regtestnnet.", service.GetPort(), regTestnetDefaultPort); - LogPrintf("CActiveDynode::ManageStatus() - not capable: %s\n", strNotCapableReason); + strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort); + LogPrintf("CActiveDynode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason); return; } + } else if (Params().NetworkIDString() != CBaseChainParams::MAIN && service.GetPort() == mainnetDefaultPort) { + nState = ACTIVE_DYNODE_NOT_CAPABLE; + strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort); + LogPrintf("CActiveDynode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason); + return; } // Check socket connectivity @@ -220,44 +224,43 @@ void CActiveDynode::ManageStateInitial(CConnman& connman) // Default to REMOTE eType = DYNODE_REMOTE; - LogPrint("Dynode", "CActiveDynode::ManageStateInitial -- End status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled); + LogPrint("dynode", "CActiveDynode::ManageStateInitial -- End status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled); } void CActiveDynode::ManageStateRemote() { - LogPrint("Dynode", "CActiveDynode::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, pubKeyDynode.GetID() = %s\n", - GetStatus(), fPingerEnabled, GetTypeString(), pubKeyDynode.GetID().ToString()); + LogPrint("dynode", "CActiveDynode::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, pubKeyDynode.GetID() = %s\n", + GetStatus(), fPingerEnabled, GetTypeString(), pubKeyDynode.GetID().ToString()); dnodeman.CheckDynode(pubKeyDynode, true); dynode_info_t infoDn; - if(dnodeman.GetDynodeInfo(pubKeyDynode, infoDn)) { - if(infoDn.nProtocolVersion != PROTOCOL_VERSION) { + if (dnodeman.GetDynodeInfo(pubKeyDynode, infoDn)) { + if (infoDn.nProtocolVersion != PROTOCOL_VERSION) { nState = ACTIVE_DYNODE_NOT_CAPABLE; strNotCapableReason = "Invalid protocol version"; LogPrintf("CActiveDynode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); return; } - if(service != infoDn.addr) { + if (service != infoDn.addr) { nState = ACTIVE_DYNODE_NOT_CAPABLE; strNotCapableReason = "Broadcasted IP doesn't match our external address. Make sure you issued a new broadcast if IP of this Dynode changed recently."; LogPrintf("CActiveDynode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); return; } - if(!CDynode::IsValidStateForAutoStart(infoDn.nActiveState)) { + if (!CDynode::IsValidStateForAutoStart(infoDn.nActiveState)) { nState = ACTIVE_DYNODE_NOT_CAPABLE; strNotCapableReason = strprintf("Dynode in %s state", CDynode::StateToString(infoDn.nActiveState)); LogPrintf("CActiveDynode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); return; } - if(nState != ACTIVE_DYNODE_STARTED) { + if (nState != ACTIVE_DYNODE_STARTED) { LogPrintf("CActiveDynode::ManageStateRemote -- STARTED!\n"); - outpoint = infoDn.vin.prevout; + outpoint = infoDn.outpoint; service = infoDn.addr; fPingerEnabled = true; nState = ACTIVE_DYNODE_STARTED; } - } - else { + } else { nState = ACTIVE_DYNODE_NOT_CAPABLE; strNotCapableReason = "Dynode not in Dynode list"; LogPrintf("CActiveDynode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); diff --git a/src/activedynode.h b/src/activedynode.h index aeedc123ed..246bef6b5d 100644 --- a/src/activedynode.h +++ b/src/activedynode.h @@ -1,7 +1,7 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,16 +14,16 @@ #include "primitives/transaction.h" #ifdef ENABLE_WALLET -#include "wallet/wallet.h" +#include "wallet/wallet.h" #endif //ENABLE_WALLET class CActiveDynode; -static const int ACTIVE_DYNODE_INITIAL = 0; // initial state -static const int ACTIVE_DYNODE_SYNC_IN_PROCESS = 1; -static const int ACTIVE_DYNODE_INPUT_TOO_NEW = 2; -static const int ACTIVE_DYNODE_NOT_CAPABLE = 3; -static const int ACTIVE_DYNODE_STARTED = 4; +static const int ACTIVE_DYNODE_INITIAL = 0; // initial state +static const int ACTIVE_DYNODE_SYNC_IN_PROCESS = 1; +static const int ACTIVE_DYNODE_INPUT_TOO_NEW = 2; +static const int ACTIVE_DYNODE_NOT_CAPABLE = 3; +static const int ACTIVE_DYNODE_STARTED = 4; extern CActiveDynode activeDynode; @@ -33,7 +33,7 @@ class CActiveDynode public: enum dynode_type_enum_t { DYNODE_UNKNOWN = 0, - DYNODE_REMOTE = 1 + DYNODE_REMOTE = 1 }; private: @@ -71,7 +71,8 @@ class CActiveDynode outpoint(), service(), nState(ACTIVE_DYNODE_INITIAL) - {} + { + } /// Manage state of active Dynode void ManageState(CConnman& connman); @@ -82,6 +83,8 @@ class CActiveDynode bool UpdateSentinelPing(int version); + void DoMaintenance(CConnman &connman); + private: void ManageStateInitial(CConnman& connman); void ManageStateRemote(); diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 3a46365ecf..e7b557ae38 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -1,7 +1,7 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -39,7 +39,7 @@ bool CBanDB::Write(const banmap_t& banSet) // open temp output file, and associate with CAutoFile boost::filesystem::path pathTmp = GetDataDir() / tmpfn; - FILE *file = fopen(pathTmp.string().c_str(), "wb"); + FILE* file = fopen(pathTmp.string().c_str(), "wb"); CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); if (fileout.IsNull()) return error("%s: Failed to open file %s", __func__, pathTmp.string()); @@ -47,8 +47,7 @@ bool CBanDB::Write(const banmap_t& banSet) // Write and commit header, data try { fileout << ssBanlist; - } - catch (const std::exception& e) { + } catch (const std::exception& e) { return error("%s: Serialize or I/O error - %s", __func__, e.what()); } FileCommit(fileout.Get()); @@ -64,7 +63,7 @@ bool CBanDB::Write(const banmap_t& banSet) bool CBanDB::Read(banmap_t& banSet) { // open input file, and associate with CAutoFile - FILE *file = fopen(pathBanlist.string().c_str(), "rb"); + FILE* file = fopen(pathBanlist.string().c_str(), "rb"); CAutoFile filein(file, SER_DISK, CLIENT_VERSION); if (filein.IsNull()) return error("%s: Failed to open file %s", __func__, pathBanlist.string()); @@ -81,10 +80,9 @@ bool CBanDB::Read(banmap_t& banSet) // read data and checksum from file try { - filein.read((char *)&vchData[0], dataSize); + filein.read((char*)&vchData[0], dataSize); filein >> hashIn; - } - catch (const std::exception& e) { + } catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } filein.fclose(); @@ -107,8 +105,7 @@ bool CBanDB::Read(banmap_t& banSet) // de-serialize address data into one CAddrMan object ssBanlist >> banSet; - } - catch (const std::exception& e) { + } catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } @@ -136,7 +133,7 @@ bool CAddrDB::Write(const CAddrMan& addr) // open temp output file, and associate with CAutoFile boost::filesystem::path pathTmp = GetDataDir() / tmpfn; - FILE *file = fopen(pathTmp.string().c_str(), "wb"); + FILE* file = fopen(pathTmp.string().c_str(), "wb"); CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); if (fileout.IsNull()) return error("%s: Failed to open file %s", __func__, pathTmp.string()); @@ -144,8 +141,7 @@ bool CAddrDB::Write(const CAddrMan& addr) // Write and commit header, data try { fileout << ssPeers; - } - catch (const std::exception& e) { + } catch (const std::exception& e) { return error("%s: Serialize or I/O error - %s", __func__, e.what()); } FileCommit(fileout.Get()); @@ -161,7 +157,7 @@ bool CAddrDB::Write(const CAddrMan& addr) bool CAddrDB::Read(CAddrMan& addr) { // open input file, and associate with CAutoFile - FILE *file = fopen(pathAddr.string().c_str(), "rb"); + FILE* file = fopen(pathAddr.string().c_str(), "rb"); CAutoFile filein(file, SER_DISK, CLIENT_VERSION); if (filein.IsNull()) return error("%s: Failed to open file %s", __func__, pathAddr.string()); @@ -178,10 +174,9 @@ bool CAddrDB::Read(CAddrMan& addr) // read data and checksum from file try { - filein.read((char *)&vchData[0], dataSize); + filein.read((char*)&vchData[0], dataSize); filein >> hashIn; - } - catch (const std::exception& e) { + } catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } filein.fclose(); @@ -209,8 +204,7 @@ bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers) // de-serialize address data into one CAddrMan object ssPeers >> addr; - } - catch (const std::exception& e) { + } catch (const std::exception& e) { // de-serialization has failed, ensure addrman is left in a clean state addr.Clear(); return error("%s: Deserialize or I/O error - %s", __func__, e.what()); diff --git a/src/addrdb.h b/src/addrdb.h index fb249cb52a..c1e57ee530 100644 --- a/src/addrdb.h +++ b/src/addrdb.h @@ -1,7 +1,7 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,25 +10,24 @@ #include "serialize.h" -#include -#include #include +#include +#include class CSubNet; class CAddrMan; class CDataStream; -typedef enum BanReason -{ - BanReasonUnknown = 0, - BanReasonNodeMisbehaving = 1, - BanReasonManuallyAdded = 2 +typedef enum BanReason { + BanReasonUnknown = 0, + BanReasonNodeMisbehaving = 1, + BanReasonManuallyAdded = 2 } BanReason; class CBanEntry { public: - static const int CURRENT_VERSION=1; + static const int CURRENT_VERSION = 1; int nVersion; int64_t nCreateTime; int64_t nBanUntil; @@ -48,7 +47,8 @@ class CBanEntry ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action) { + inline void SerializationOp(Stream& s, Operation ser_action) + { READWRITE(this->nVersion); READWRITE(nCreateTime); READWRITE(nBanUntil); @@ -83,6 +83,7 @@ class CAddrDB { private: boost::filesystem::path pathAddr; + public: CAddrDB(); bool Write(const CAddrMan& addr); @@ -95,6 +96,7 @@ class CBanDB { private: boost::filesystem::path pathBanlist; + public: CBanDB(); bool Write(const banmap_t& banSet); diff --git a/src/addressindex.h b/src/addressindex.h index 031b15c9e3..8bc3bde079 100644 --- a/src/addressindex.h +++ b/src/addressindex.h @@ -1,8 +1,8 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2012-2018 Pieter Wuille -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2012-2021 Pieter Wuille +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,21 +12,22 @@ #include "amount.h" #include "uint256.h" -struct CMempoolAddressDelta -{ +struct CMempoolAddressDelta { int64_t time; CAmount amount; uint256 prevhash; unsigned int prevout; - CMempoolAddressDelta(int64_t t, CAmount a, uint256 hash, unsigned int out) { + CMempoolAddressDelta(int64_t t, CAmount a, uint256 hash, unsigned int out) + { time = t; amount = a; prevhash = hash; prevout = out; } - CMempoolAddressDelta(int64_t t, CAmount a) { + CMempoolAddressDelta(int64_t t, CAmount a) + { time = t; amount = a; prevhash.SetNull(); @@ -34,15 +35,15 @@ struct CMempoolAddressDelta } }; -struct CMempoolAddressDeltaKey -{ +struct CMempoolAddressDeltaKey { int type; uint160 addressBytes; uint256 txhash; unsigned int index; int spending; - CMempoolAddressDeltaKey(int addressType, uint160 addressHash, uint256 hash, unsigned int i, int s) { + CMempoolAddressDeltaKey(int addressType, uint160 addressHash, uint256 hash, unsigned int i, int s) + { type = addressType; addressBytes = addressHash; txhash = hash; @@ -50,7 +51,8 @@ struct CMempoolAddressDeltaKey spending = s; } - CMempoolAddressDeltaKey(int addressType, uint160 addressHash) { + CMempoolAddressDeltaKey(int addressType, uint160 addressHash) + { type = addressType; addressBytes = addressHash; txhash.SetNull(); @@ -59,9 +61,9 @@ struct CMempoolAddressDeltaKey } }; -struct CMempoolAddressDeltaKeyCompare -{ - bool operator()(const CMempoolAddressDeltaKey& a, const CMempoolAddressDeltaKey& b) const { +struct CMempoolAddressDeltaKeyCompare { + bool operator()(const CMempoolAddressDeltaKey& a, const CMempoolAddressDeltaKey& b) const + { if (a.type == b.type) { if (a.addressBytes == b.addressBytes) { if (a.txhash == b.txhash) { diff --git a/src/addrman.cpp b/src/addrman.cpp index c0fb208403..a6390479b8 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -1,8 +1,8 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2012-2018 Pieter Wuille -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2012-2021 Pieter Wuille +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,6 +12,8 @@ #include "serialize.h" #include "streams.h" +#include + int CAddrInfo::GetTriedBucket(const uint256& nKey) const { uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetCheapHash(); @@ -27,7 +29,7 @@ int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src) const return hash2 % ADDRMAN_NEW_BUCKET_COUNT; } -int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const +int CAddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const { uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetHash().GetCheapHash(); return hash1 % ADDRMAN_BUCKET_SIZE; @@ -56,14 +58,7 @@ bool CAddrInfo::IsTerrible(int64_t nNow) const double CAddrInfo::GetChance(int64_t nNow) const { double fChance = 1.0; - - int64_t nSinceLastSeen = nNow - nTime; - int64_t nSinceLastTry = nNow - nLastTry; - - if (nSinceLastSeen < 0) - nSinceLastSeen = 0; - if (nSinceLastTry < 0) - nSinceLastTry = 0; + int64_t nSinceLastTry = std::max(nNow - nLastTry, 0); // deprioritize very recent attempts away if (nSinceLastTry < 60 * 10) @@ -75,9 +70,14 @@ double CAddrInfo::GetChance(int64_t nNow) const return fChance; } -CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId) +CAddrInfo* CAddrMan::Find(const CService& addr, int* pnId) { - std::map::iterator it = mapAddr.find(addr); + CService addr2 = addr; + if (!discriminatePorts) { + addr2.SetPort(0); + } + + std::map::iterator it = mapAddr.find(addr2); if (it == mapAddr.end()) return NULL; if (pnId) @@ -90,9 +90,14 @@ CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId) CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId) { + CService addr2 = addr; + if (!discriminatePorts) { + addr2.SetPort(0); + } + int nId = nIdCount++; mapInfo[nId] = CAddrInfo(addr, addrSource); - mapAddr[addr] = nId; + mapAddr[addr2] = nId; mapInfo[nId].nRandomPos = vRandom.size(); vRandom.push_back(nId); if (pnId) @@ -127,9 +132,14 @@ void CAddrMan::Delete(int nId) assert(!info.fInTried); assert(info.nRefCount == 0); + CService addr = info; + if (!discriminatePorts) { + addr.SetPort(0); + } + SwapRandom(info.nRandomPos, vRandom.size() - 1); vRandom.pop_back(); - mapAddr.erase(info); + mapAddr.erase(addr); mapInfo.erase(nId); nNew--; } @@ -354,7 +364,7 @@ CAddrInfo CAddrMan::Select_(bool newOnly) // Use a 50% chance for choosing between tried and new table entries. if (!newOnly && - (nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) { + (nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) { // use a tried node double fChanceFactor = 1.0; while (1) { @@ -433,15 +443,15 @@ int CAddrMan::Check_() for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) { for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { - if (vvTried[n][i] != -1) { - if (!setTried.count(vvTried[n][i])) - return -11; - if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey) != n) - return -17; - if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i) - return -18; - setTried.erase(vvTried[n][i]); - } + if (vvTried[n][i] != -1) { + if (!setTried.count(vvTried[n][i])) + return -11; + if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey) != n) + return -17; + if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i) + return -18; + setTried.erase(vvTried[n][i]); + } } } @@ -528,7 +538,7 @@ void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices) info.nServices = nServices; } -int CAddrMan::RandomInt(int nMax){ +int CAddrMan::RandomInt(int nMax) +{ return GetRandInt(nMax); -} - +} diff --git a/src/addrman.h b/src/addrman.h index 7fbbcef1cf..c1af69b7be 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -1,8 +1,8 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2012-2018 Pieter Wuille -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2012-2021 Pieter Wuille +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -26,7 +26,6 @@ */ class CAddrInfo : public CAddress { - public: //! last try whatsoever by us (memory only) int64_t nLastTry; @@ -56,11 +55,11 @@ class CAddrInfo : public CAddress friend class CAddrMan; public: - ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action) { + inline void SerializationOp(Stream& s, Operation ser_action) + { READWRITE(*(CAddress*)this); READWRITE(source); READWRITE(nLastSuccess); @@ -78,7 +77,7 @@ class CAddrInfo : public CAddress nRandomPos = -1; } - CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) + CAddrInfo(const CAddress& addrIn, const CNetAddr& addrSource) : CAddress(addrIn), source(addrSource) { Init(); } @@ -89,26 +88,25 @@ class CAddrInfo : public CAddress } //! Calculate in which "tried" bucket this entry belongs - int GetTriedBucket(const uint256 &nKey) const; + int GetTriedBucket(const uint256& nKey) const; //! Calculate in which "new" bucket this entry belongs, given a certain source - int GetNewBucket(const uint256 &nKey, const CNetAddr& src) const; + int GetNewBucket(const uint256& nKey, const CNetAddr& src) const; //! Calculate in which "new" bucket this entry belongs, using its default source - int GetNewBucket(const uint256 &nKey) const + int GetNewBucket(const uint256& nKey) const { return GetNewBucket(nKey, source); } //! Calculate in which position of a bucket to store this entry. - int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const; + int GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const; //! Determine whether the statistics about this entry are bad enough so that it can just be deleted bool IsTerrible(int64_t nNow = GetAdjustedTime()) const; //! Calculate the relative chance this entry should be given when selecting nodes to connect to double GetChance(int64_t nNow = GetAdjustedTime()) const; - }; /** Stochastic address manager @@ -189,7 +187,7 @@ class CAddrMan std::map mapInfo; //! find an nId based on its network address - std::map mapAddr; + std::map mapAddr; //! randomly-ordered vector of all nIds std::vector vRandom; @@ -209,6 +207,9 @@ class CAddrMan //! last time Good was called (memory only) int64_t nLastGood; + // discriminate entries based on port. Should be false on mainnet/testnet and can be true on devnet/regtest + bool discriminatePorts; + protected: //! secret key to randomize bucket select with uint256 nKey; @@ -217,11 +218,11 @@ class CAddrMan FastRandomContext insecure_rand; //! Find an entry. - CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL); + CAddrInfo* Find(const CService& addr, int* pnId = NULL); //! find an entry, creating it if necessary. //! nTime and nServices of the found node are updated, if necessary. - CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL); + CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = NULL); //! Swap two elements in vRandom. void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2); @@ -236,13 +237,13 @@ class CAddrMan void ClearNew(int nUBucket, int nUBucketPos); //! Mark an entry "good", possibly moving it from "new" to "tried". - void Good_(const CService &addr, int64_t nTime); + void Good_(const CService& addr, int64_t nTime); //! Add an entry to the "new" table. - bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty); + bool Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty); //! Mark an entry as attempted to connect. - void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime); + void Attempt_(const CService& addr, bool fCountFailure, int64_t nTime); //! Select an address to connect to, if newOnly is set to true, only the new table is selected from. CAddrInfo Select_(bool newOnly); @@ -256,13 +257,13 @@ class CAddrMan #endif //! Select several addresses at once. - void GetAddr_(std::vector &vAddr); + void GetAddr_(std::vector& vAddr); //! Mark an entry as currently-connected-to. - void Connected_(const CService &addr, int64_t nTime); + void Connected_(const CService& addr, int64_t nTime); //! Update an entry's service bits. - void SetServices_(const CService &addr, ServiceFlags nServices); + void SetServices_(const CService& addr, ServiceFlags nServices); public: /** @@ -294,8 +295,8 @@ class CAddrMan * We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has * very little in common. */ - template - void Serialize(Stream &s) const + template + void Serialize(Stream& s) const { LOCK(cs); @@ -312,7 +313,7 @@ class CAddrMan int nIds = 0; for (std::map::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) { mapUnkIds[(*it).first] = nIds; - const CAddrInfo &info = (*it).second; + const CAddrInfo& info = (*it).second; if (info.nRefCount) { assert(nIds != nNew); // this means nNew was wrong, oh ow s << info; @@ -321,7 +322,7 @@ class CAddrMan } nIds = 0; for (std::map::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) { - const CAddrInfo &info = (*it).second; + const CAddrInfo& info = (*it).second; if (info.fInTried) { assert(nIds != nTried); // this means nTried was wrong, oh ow s << info; @@ -344,7 +345,7 @@ class CAddrMan } } - template + template void Unserialize(Stream& s) { LOCK(cs); @@ -355,7 +356,8 @@ class CAddrMan s >> nVersion; unsigned char nKeySize; s >> nKeySize; - if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization"); + if (nKeySize != 32) + throw std::ios_base::failure("Incorrect keysize in addrman deserialization"); s >> nKey; s >> nNew; s >> nTried; @@ -375,7 +377,7 @@ class CAddrMan // Deserialize entries from the new table. for (int n = 0; n < nNew; n++) { - CAddrInfo &info = mapInfo[n]; + CAddrInfo& info = mapInfo[n]; s >> info; mapAddr[info] = n; info.nRandomPos = vRandom.size(); @@ -422,7 +424,7 @@ class CAddrMan int nIndex = 0; s >> nIndex; if (nIndex >= 0 && nIndex < nNew) { - CAddrInfo &info = mapInfo[nIndex]; + CAddrInfo& info = mapInfo[nIndex]; int nUBucketPos = info.GetBucketPosition(nKey, true, bucket); if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) { info.nRefCount++; @@ -434,7 +436,7 @@ class CAddrMan // Prune new entries with refcount 0 (as a result of collisions). int nLostUnk = 0; - for (std::map::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) { + for (std::map::const_iterator it = mapInfo.begin(); it != mapInfo.end();) { if (it->second.fInTried == false && it->second.nRefCount == 0) { std::map::const_iterator itCopy = it++; Delete(itCopy->first); @@ -471,7 +473,7 @@ class CAddrMan nLastGood = 1; //Initially at 1 so that "never" is strictly worse. } - CAddrMan() + CAddrMan(bool _discriminatePorts = false) : discriminatePorts(_discriminatePorts) { Clear(); } @@ -495,14 +497,14 @@ class CAddrMan { LOCK(cs); int err; - if ((err=Check_())) + if ((err = Check_())) LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); } #endif } //! Add a single address. - bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0) + bool Add(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty = 0) { LOCK(cs); bool fRet = false; @@ -515,7 +517,7 @@ class CAddrMan } //! Add multiple addresses. - bool Add(const std::vector &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0) + bool Add(const std::vector& vAddr, const CNetAddr& source, int64_t nTimePenalty = 0) { LOCK(cs); int nAdd = 0; @@ -529,7 +531,7 @@ class CAddrMan } //! Mark an entry as accessible. - void Good(const CService &addr, int64_t nTime = GetAdjustedTime()) + void Good(const CService& addr, int64_t nTime = GetAdjustedTime()) { LOCK(cs); Check(); @@ -538,7 +540,7 @@ class CAddrMan } //! Mark an entry as connection attempted to. - void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime()) + void Attempt(const CService& addr, bool fCountFailure, int64_t nTime = GetAdjustedTime()) { LOCK(cs); Check(); @@ -575,7 +577,7 @@ class CAddrMan } //! Mark an entry as currently-connected-to. - void Connected(const CService &addr, int64_t nTime = GetAdjustedTime()) + void Connected(const CService& addr, int64_t nTime = GetAdjustedTime()) { LOCK(cs); Check(); @@ -583,7 +585,7 @@ class CAddrMan Check(); } - void SetServices(const CService &addr, ServiceFlags nServices) + void SetServices(const CService& addr, ServiceFlags nServices) { LOCK(cs); Check(); diff --git a/src/alert.cpp b/src/alert.cpp index 223c50b133..ed6c38c8df 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -1,7 +1,7 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,6 +10,7 @@ #include "base58.h" #include "clientversion.h" #include "net.h" +#include "netmessagemaker.h" #include "pubkey.h" #include "timedata.h" #include "ui_interface.h" @@ -49,10 +50,10 @@ void CUnsignedAlert::SetNull() std::string CUnsignedAlert::ToString() const { std::string strSetCancel; - BOOST_FOREACH(int n, setCancel) + BOOST_FOREACH (int n, setCancel) strSetCancel += strprintf("%d ", n); std::string strSetSubVer; - BOOST_FOREACH(const std::string& str, setSubVer) + BOOST_FOREACH (const std::string& str, setSubVer) strSetSubVer += "\"" + str + "\" "; return strprintf( "CAlert(\n" @@ -133,13 +134,11 @@ bool CAlert::RelayTo(CNode* pnode, CConnman& connman) const if (pnode->nVersion == 0) return false; // returns true if wasn't already contained in the set - if (pnode->setKnown.insert(GetHash()).second) - { + if (pnode->setKnown.insert(GetHash()).second) { if (AppliesTo(pnode->nVersion, pnode->strSubVer) || AppliesToMe() || - GetAdjustedTime() < nRelayUntil) - { - connman.PushMessage(pnode, NetMsgType::ALERT, *this); + GetAdjustedTime() < nRelayUntil) { + connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::ALERT, *this)); return true; } } @@ -152,14 +151,12 @@ bool CAlert::Sign() sMsg << *(CUnsignedAlert*)this; vchMsg = std::vector(sMsg.begin(), sMsg.end()); CDynamicSecret vchSecret; - if (!vchSecret.SetString(GetArg("-alertkey", ""))) - { + if (!vchSecret.SetString(GetArg("-alertkey", ""))) { printf("CAlert::SignAlert() : vchSecret.SetString failed\n"); return false; } CKey key = vchSecret.GetKey(); - if (!key.Sign(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) - { + if (!key.Sign(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) { printf("CAlert::SignAlert() : key.Sign failed\n"); return false; } @@ -179,13 +176,13 @@ bool CAlert::CheckSignature(const std::vector& alertKey) const return true; } -CAlert CAlert::getAlertByHash(const uint256 &hash) +CAlert CAlert::getAlertByHash(const uint256& hash) { CAlert retval; { LOCK(cs_mapAlerts); std::map::iterator mi = mapAlerts.find(hash); - if(mi != mapAlerts.end()) + if (mi != mapAlerts.end()) retval = mi->second; } return retval; @@ -206,48 +203,39 @@ bool CAlert::ProcessAlert(const std::vector& alertKey, bool fThre // send an "everything is OK, don't panic" version that // cannot be overridden): int maxInt = std::numeric_limits::max(); - if (nID == maxInt) - { + if (nID == maxInt) { if (!( nExpiration == maxInt && - nCancel == (maxInt-1) && + nCancel == (maxInt - 1) && nMinVer == 0 && nMaxVer == maxInt && setSubVer.empty() && nPriority == maxInt && - strStatusBar == "URGENT: Alert key compromised, upgrade required" - )) + strStatusBar == "URGENT: Alert key compromised, upgrade required")) return false; } { LOCK(cs_mapAlerts); // Cancel previous alerts - for (std::map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) - { + for (std::map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) { const CAlert& alert = (*mi).second; - if (Cancels(alert)) - { + if (Cancels(alert)) { LogPrint("alert", "cancelling alert %d\n", alert.nID); uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); mapAlerts.erase(mi++); - } - else if (!alert.IsInEffect()) - { + } else if (!alert.IsInEffect()) { LogPrint("alert", "expiring alert %d\n", alert.nID); uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); mapAlerts.erase(mi++); - } - else + } else mi++; } // Check if this alert has been cancelled - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - { + BOOST_FOREACH (PAIRTYPE(const uint256, CAlert) & item, mapAlerts) { const CAlert& alert = item.second; - if (alert.Cancels(*this)) - { + if (alert.Cancels(*this)) { LogPrint("alert", "alert already cancelled by %d\n", alert.nID); return false; } @@ -256,8 +244,7 @@ bool CAlert::ProcessAlert(const std::vector& alertKey, bool fThre // Add to mapAlerts mapAlerts.insert(std::make_pair(GetHash(), *this)); // Notify UI and -alertnotify if it applies to me - if(AppliesToMe()) - { + if (AppliesToMe()) { uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); Notify(strStatusBar, fThread); } @@ -267,18 +254,18 @@ bool CAlert::ProcessAlert(const std::vector& alertKey, bool fThre return true; } -void -CAlert::Notify(const std::string& strMessage, bool fThread) +void CAlert::Notify(const std::string& strMessage, bool fThread) { std::string strCmd = GetArg("-alertnotify", ""); - if (strCmd.empty()) return; + if (strCmd.empty()) + return; // Alert text should be plain ascii coming from a trusted source, but to // be safe we first strip anything not in safeChars, then add single quotes around // the whole string before passing it to the shell: std::string singleQuote("'"); std::string safeStatus = SanitizeString(strMessage); - safeStatus = singleQuote+safeStatus+singleQuote; + safeStatus = singleQuote + safeStatus + singleQuote; boost::replace_all(strCmd, "%s", safeStatus); if (fThread) diff --git a/src/alert.h b/src/alert.h index d3bfeb8881..2c1d1cd7ef 100644 --- a/src/alert.h +++ b/src/alert.h @@ -1,7 +1,7 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -34,14 +34,14 @@ class CUnsignedAlert { public: int nVersion; - int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes + int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes int64_t nExpiration; int nID; int nCancel; std::set setCancel; - int nMinVer; // lowest version inclusive - int nMaxVer; // highest version inclusive - std::set setSubVer; // empty matches all + int nMinVer; // lowest version inclusive + int nMaxVer; // highest version inclusive + std::set setSubVer; // empty matches all int nPriority; // Actions @@ -52,7 +52,8 @@ class CUnsignedAlert ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action) { + inline void SerializationOp(Stream& s, Operation ser_action) + { READWRITE(this->nVersion); READWRITE(nRelayUntil); READWRITE(nExpiration); @@ -89,7 +90,8 @@ class CAlert : public CUnsignedAlert ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action) { + inline void SerializationOp(Stream& s, Operation ser_action) + { READWRITE(vchMsg); READWRITE(vchSig); } @@ -110,7 +112,7 @@ class CAlert : public CUnsignedAlert /* * Get copy of (active) alert object by hash. Returns a null alert if it is not found. */ - static CAlert getAlertByHash(const uint256 &hash); + static CAlert getAlertByHash(const uint256& hash); }; #endif // DYNAMIC_ALERT_H diff --git a/src/amount.cpp b/src/amount.cpp index bb262f29b9..1ff980ba2f 100644 --- a/src/amount.cpp +++ b/src/amount.cpp @@ -1,7 +1,7 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/amount.h b/src/amount.h index 1da8465d5b..6492008bd4 100644 --- a/src/amount.h +++ b/src/amount.h @@ -1,7 +1,7 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,9 +17,7 @@ typedef int64_t CAmount; static const CAmount COIN = 100000000; static const CAmount CENT = 1000000; -static const CAmount SUBCENT = 100; -static const CAmount MIN_TX_FEE = CENT; -static const CAmount MIN_MULTISIG_NAME_FEE = SUBCENT; +static const CAmount BDAP_CREDIT = 100001; //= 0.00100001 DYN. Matches lowest PrivateSend denomination extern const std::string CURRENCY_UNIT; @@ -36,8 +34,8 @@ class CFeeRate CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes public: /** Fee rate of 0 satoshis per kB */ - CFeeRate() : nSatoshisPerK(0) { } - explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { } + CFeeRate() : nSatoshisPerK(0) {} + explicit CFeeRate(const CAmount& _nSatoshisPerK) : nSatoshisPerK(_nSatoshisPerK) {} /** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/ CFeeRate(const CAmount& nFeePaid, size_t nBytes); CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; } @@ -54,13 +52,18 @@ class CFeeRate friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; } friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; } friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; } - CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; } + CFeeRate& operator+=(const CFeeRate& a) + { + nSatoshisPerK += a.nSatoshisPerK; + return *this; + } std::string ToString() const; ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action) { + inline void SerializationOp(Stream& s, Operation ser_action) + { READWRITE(nSatoshisPerK); } }; diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 9546bca0a1..52b299390a 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -1,7 +1,7 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -219,8 +219,8 @@ arith_uint256& arith_uint256::SetCompact(uint32_t nCompact, bool* pfNegative, bo *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; if (pfOverflow) *pfOverflow = nWord != 0 && ((nSize > 34) || - (nWord > 0xff && nSize > 33) || - (nWord > 0xffff && nSize > 32)); + (nWord > 0xff && nSize > 33) || + (nWord > 0xffff && nSize > 32)); return *this; } @@ -247,17 +247,17 @@ uint32_t arith_uint256::GetCompact(bool fNegative) const return nCompact; } -uint256 ArithToUint256(const arith_uint256 &a) +uint256 ArithToUint256(const arith_uint256& a) { uint256 b; - for(int x=0; x +template class base_uint { protected: - enum { WIDTH=BITS/32 }; + enum { WIDTH = BITS / 32 }; uint32_t pn[WIDTH]; -public: +public: base_uint() { for (int i = 0; i < WIDTH; i++) @@ -137,8 +138,7 @@ class base_uint base_uint& operator+=(const base_uint& b) { uint64_t carry = 0; - for (int i = 0; i < WIDTH; i++) - { + for (int i = 0; i < WIDTH; i++) { uint64_t n = carry + pn[i] + b.pn[i]; pn[i] = n & 0xffffffff; carry = n >> 32; @@ -176,7 +176,7 @@ class base_uint { // prefix operator int i = 0; - while (++pn[i] == 0 && i < WIDTH-1) + while (++pn[i] == 0 && i < WIDTH - 1) i++; return *this; } @@ -193,7 +193,7 @@ class base_uint { // prefix operator int i = 0; - while (--pn[i] == (uint32_t)-1 && i < WIDTH-1) + while (--pn[i] == (uint32_t)-1 && i < WIDTH - 1) i++; return *this; } @@ -252,7 +252,8 @@ class base_uint }; /** 256-bit unsigned big integer. */ -class arith_uint256 : public base_uint<256> { +class arith_uint256 : public base_uint<256> +{ public: arith_uint256() {} arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {} @@ -279,14 +280,14 @@ class arith_uint256 : public base_uint<256> { * complexities of the sign bit and using base 256 are probably an * implementation accident. */ - arith_uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL); + arith_uint256& SetCompact(uint32_t nCompact, bool* pfNegative = NULL, bool* pfOverflow = NULL); uint32_t GetCompact(bool fNegative = false) const; - friend uint256 ArithToUint256(const arith_uint256 &); - friend arith_uint256 UintToArith256(const uint256 &); + friend uint256 ArithToUint256(const arith_uint256&); + friend arith_uint256 UintToArith256(const uint256&); }; -uint256 ArithToUint256(const arith_uint256 &); -arith_uint256 UintToArith256(const uint256 &); +uint256 ArithToUint256(const arith_uint256&); +arith_uint256 UintToArith256(const uint256&); #endif // DYNAMIC_ARITH_UINT256_H diff --git a/src/base58.cpp b/src/base58.cpp index aeb8d8ceaa..7f6292e298 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -1,16 +1,18 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "base58.h" +#include "bdap/stealth.h" #include "hash.h" #include "uint256.h" #include +#include #include #include #include @@ -22,6 +24,68 @@ /** All alphanumeric characters except for "0", "I", "O", and "l" */ static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + +namespace +{ +class DestinationEncoder : public boost::static_visitor +{ +private: + const CChainParams& m_params; + +public: + explicit DestinationEncoder(const CChainParams& params) : m_params(params) {} + + std::string operator()(const CKeyID& id) const + { + std::vector data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); + data.insert(data.end(), id.begin(), id.end()); + return EncodeBase58Check(data); + } + + std::string operator()(const CScriptID& id) const + { + std::vector data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); + data.insert(data.end(), id.begin(), id.end()); + return EncodeBase58Check(data); + } + + std::string operator()(const CNoDestination& no) const { return {}; } + std::string operator()(const CStealthAddress& sxAddr) const { return CDynamicAddress(sxAddr).ToString(); } + +}; + +static CTxDestination DecodeDestination(const std::string& str, const CChainParams& params) +{ + CDynamicAddress addr(str); + if (addr.IsValid()) { + return addr.Get(); + } + + std::vector data; + if (DecodeBase58Check(str, data)) { + const std::vector& stealth_prefix = params.Base58Prefix(CChainParams::STEALTH_ADDRESS); + if (data.size() > stealth_prefix.size() && std::equal(stealth_prefix.begin(), stealth_prefix.end(), data.begin())) { + CStealthAddress sxAddr; + if (0 == sxAddr.FromRaw(data.data() + stealth_prefix.size(), data.size())) + return sxAddr; + return CNoDestination(); + } + } + data.clear(); + return CNoDestination(); +} +} // namespace + +CTxDestination DecodeDestination(const std::string& str) +{ + return DecodeDestination(str, Params()); +} + +std::string EncodeDestination(const CTxDestination& dest) +{ + return boost::apply_visitor(DestinationEncoder(Params()), dest); +} + bool DecodeBase58(const char* psz, std::vector& vch) { // Skip leading spaces. @@ -35,7 +99,7 @@ bool DecodeBase58(const char* psz, std::vector& vch) psz++; } // Allocate enough space in big-endian base256 representation. - int size = strlen(psz) * 733 /1000 + 1; // log(58) / log(256), rounded up. + int size = strlen(psz) * 733 / 1000 + 1; // log(58) / log(256), rounded up. std::vector b256(size); // Process the characters. while (*psz && !isspace(*psz)) { @@ -227,9 +291,10 @@ class CDynamicAddressVisitor : public boost::static_visitor bool operator()(const CKeyID& id) const { return addr->Set(id); } bool operator()(const CScriptID& id) const { return addr->Set(id); } bool operator()(const CNoDestination& no) const { return false; } + bool operator()(const CStealthAddress& sxAddr) const { return addr->Set(sxAddr); } }; -} // anon namespace +} // namespace bool CDynamicAddress::Set(const CKeyID& id) { @@ -248,6 +313,16 @@ bool CDynamicAddress::Set(const CTxDestination& dest) return boost::apply_visitor(CDynamicAddressVisitor(this), dest); } +bool CDynamicAddress::Set(const CStealthAddress& sxAddr) +{ + std::vector raw; + if (0 != sxAddr.ToRaw(raw)) + return false; + + SetData(Params().Base58Prefix(CChainParams::STEALTH_ADDRESS), &raw[0], raw.size()); + return true; +} + bool CDynamicAddress::IsValid() const { return IsValid(Params()); @@ -261,6 +336,36 @@ bool CDynamicAddress::IsValid(const CChainParams& params) const return fCorrectSize && fKnownVersion; } +bool CDynamicAddress::IsValidStealthAddress() const +{ + return IsValidStealthAddress(Params()); +} + +bool CDynamicAddress::IsValidStealthAddress(const CChainParams& params) const +{ + if (vchVersion != params.Base58Prefix(CChainParams::STEALTH_ADDRESS)) + return false; + + if (vchData.size() < MIN_STEALTH_RAW_SIZE) + return false; + + size_t nPkSpend = vchData[34]; + + if (nPkSpend != 1) // TODO: allow multi + return false; + + size_t nBits = vchData[35 + EC_COMPRESSED_SIZE * nPkSpend + 1]; + if (nBits > 32) + return false; + + size_t nPrefixBytes = std::ceil((float)nBits / 8.0); + + if (vchData.size() != MIN_STEALTH_RAW_SIZE + EC_COMPRESSED_SIZE * (nPkSpend-1) + nPrefixBytes) + return false; + + return true; +} + CTxDestination CDynamicAddress::Get() const { if (!IsValid()) diff --git a/src/base58.h b/src/base58.h index 2399ae36ea..b249f38924 100644 --- a/src/base58.h +++ b/src/base58.h @@ -1,7 +1,7 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2018 The Dash Core Developers -// Copyright (c) 2009-2018 The Bitcoin Developers -// Copyright (c) 2009-2018 Satoshi Nakamoto +// Copyright (c) 2016-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2014-2021 The Dash Core Developers +// Copyright (c) 2009-2021 The Bitcoin Developers +// Copyright (c) 2009-2021 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,6 +16,7 @@ #ifndef DYNAMIC_BASE58_H #define DYNAMIC_BASE58_H +#include "bdap/stealth.h" #include "chainparams.h" #include "key.h" #include "pubkey.h" @@ -26,6 +27,14 @@ #include #include +/** + * Encode a tx destination as a base58-encoded string. + */ +std::string EncodeDestination(const CTxDestination& dest); +/** + * Decode a tx destination as a base58-encoded string. + */ +CTxDestination DecodeDestination(const std::string& str); /** * Encode a byte sequence as a base58-encoded string. * pbegin and pend cannot be NULL, unless both are. @@ -81,8 +90,8 @@ class CBase58Data vector_uchar vchData; CBase58Data(); - void SetData(const std::vector &vchVersionIn, const void* pdata, size_t nSize); - void SetData(const std::vector &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend); + void SetData(const std::vector& vchVersionIn, const void* pdata, size_t nSize); + void SetData(const std::vector& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend); public: bool SetString(const char* psz, unsigned int nVersionBytes = 1); @@ -93,8 +102,8 @@ class CBase58Data bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; } bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; } bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; } - bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; } - bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } + bool operator<(const CBase58Data& b58) const { return CompareTo(b58) < 0; } + bool operator>(const CBase58Data& b58) const { return CompareTo(b58) > 0; } }; /** base58-encoded Dynamic addresses. @@ -103,21 +112,25 @@ class CBase58Data * Script-hash-addresses have version 16 (or 19 testnet). * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. */ -class CDynamicAddress : public CBase58Data { +class CDynamicAddress : public CBase58Data +{ public: - bool Set(const CKeyID &id); - bool Set(const CScriptID &id); - bool Set(const CTxDestination &dest); + bool Set(const CKeyID& id); + bool Set(const CScriptID& id); + bool Set(const CTxDestination& dest); + bool Set(const CStealthAddress& sxAddr); bool IsValid() const; - bool IsValid(const CChainParams ¶ms) const; + bool IsValid(const CChainParams& params) const; + bool IsValidStealthAddress() const; + bool IsValidStealthAddress(const CChainParams& params) const; CDynamicAddress() {} - CDynamicAddress(const CTxDestination &dest) { Set(dest); } + CDynamicAddress(const CTxDestination& dest) { Set(dest); } CDynamicAddress(const std::string& strAddress) { SetString(strAddress); } CDynamicAddress(const char* pszAddress) { SetString(pszAddress); } CTxDestination Get() const; - bool GetKeyID(CKeyID &keyID) const; + bool GetKeyID(CKeyID& keyID) const; bool GetIndexKey(uint160& hashBytes, int& type) const; bool IsScript() const; }; @@ -138,16 +151,19 @@ class CDynamicSecret : public CBase58Data CDynamicSecret() {} }; -template class CDynamicExtKeyBase : public CBase58Data +template +class CDynamicExtKeyBase : public CBase58Data { public: - void SetKey(const K &key) { + void SetKey(const K& key) + { unsigned char vch[Size]; key.Encode(vch); - SetData(Params().Base58Prefix(Type), vch, vch+Size); + SetData(Params().Base58Prefix(Type), vch, vch + Size); } - K GetKey() { + K GetKey() + { K ret; if (vchData.size() == Size) { //if base58 encouded data not holds a ext key, return a !IsValid() key @@ -156,11 +172,13 @@ template class CDynamicExtK return ret; } - CDynamicExtKeyBase(const K &key) { + CDynamicExtKeyBase(const K& key) + { SetKey(key); } - CDynamicExtKeyBase(const std::string& strBase58c) { + CDynamicExtKeyBase(const std::string& strBase58c) + { SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size()); } diff --git a/src/bdap/audit.cpp b/src/bdap/audit.cpp new file mode 100644 index 0000000000..916719258e --- /dev/null +++ b/src/bdap/audit.cpp @@ -0,0 +1,288 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/audit.h" + +#include "bdap/bdap.h" +#include "bdap/utils.h" +#include "key.h" +#include "hash.h" +#include "messagesigner.h" +#include "pubkey.h" +#include "serialize.h" +#include "streams.h" +#include "validation.h" + +#include + +void CAuditData::Serialize(std::vector& vchData) +{ + CDataStream dsAuditData(SER_NETWORK, PROTOCOL_VERSION); + dsAuditData << *this; + vchData = std::vector(dsAuditData.begin(), dsAuditData.end()); +} + +bool CAuditData::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsAuditData(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsAuditData >> *this; + + std::vector vchAuditData; + Serialize(vchAuditData); + const uint256& calculatedHash = Hash(vchAuditData.begin(), vchAuditData.end()); + const std::vector& vchRandAuditData = vchFromValue(calculatedHash.GetHex()); + if(vchRandAuditData != vchHash) { + SetNull(); + return false; + } + } catch (std::exception& e) { + SetNull(); + return false; + } + return true; +} + +bool CAuditData::UnserializeFromData(const std::vector& vchData) +{ + try { + CDataStream dsAuditData(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsAuditData >> *this; + + std::vector vchAuditData; + Serialize(vchAuditData); + } catch (std::exception& e) { + SetNull(); + return false; + } + return true; +} + +bool CAuditData::ValidateValues(std::string& strErrorMessage) +{ + for(const CharString& vchHash : vAuditData) { + if (vchHash.size() > MAX_BDAP_AUDIT_HASH_SIZE) { + strErrorMessage = "Invalid audit length. Can not have more than " + std::to_string(MAX_BDAP_AUDIT_HASH_SIZE) + " characters."; + return false; + } + } + return true; +} + +CAudit::CAudit(CAuditData& auditData) { + auditData.Serialize(vchAuditData); +} + +uint256 CAudit::GetHash() const +{ + CDataStream dsAudit(SER_NETWORK, PROTOCOL_VERSION); + dsAudit << *this; + return Hash(dsAudit.begin(), dsAudit.end()); +} + +uint256 CAudit::GetAuditHash() const +{ + CDataStream dsAudit(SER_NETWORK, PROTOCOL_VERSION); + dsAudit << vchAuditData << vchOwnerFullObjectPath << vchAlgorithmType << vchDescription; + return Hash(dsAudit.begin(), dsAudit.end()); +} + +bool CAudit::Sign(const CKey& key) +{ + if (!CHashSigner::SignHash(GetAuditHash(), key, vchSignature)) { + return error("CAudit::%s() -- Failed to sign audit data.\n", __func__); + } + + return true; +} + +bool CAudit::CheckSignature(const std::vector& vchPubKey) const +{ + std::string strError = ""; + CPubKey pubkey(vchPubKey); + if (!CHashSigner::VerifyHash(GetAuditHash(), pubkey, vchSignature, strError)) { + return error("CAudit::%s() -- Failed to verify signature - %s\n", __func__, strError); + } + + return true; +} + +int CAudit::Version() const +{ + if (vchAuditData.size() == 0) + return -1; + + return CAuditData(vchAuditData).nVersion; +} + +bool CAudit::ValidateValues(std::string& strErrorMessage) const +{ + CAuditData auditData(vchAuditData); + if (!auditData.ValidateValues(strErrorMessage)) + return false; + + if (auditData.vAuditData.size() == 0) + return false; + + //Check for duplicates + if (auditData.vAuditData.size() >> 1) { + auto it = std::unique(auditData.vAuditData.begin(), auditData.vAuditData.end()); + if (!(it == auditData.vAuditData.end())) { + strErrorMessage = "Invalid Audit data. Can not have duplicates."; + return false; + } + } + + if (vchOwnerFullObjectPath.size() > MAX_OBJECT_FULL_PATH_LENGTH) { + strErrorMessage = "Invalid BDAP audit owner FQDN length. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + + if (vchSignature.size() > MAX_SIGNATURE_LENGTH) { + strErrorMessage = "Invalid BDAP audit signature length. Can not have more than " + std::to_string(MAX_SIGNATURE_LENGTH) + " characters."; + return false; + } + + if (vchAlgorithmType.size() > MAX_ALGORITHM_TYPE_LENGTH) { + strErrorMessage = "Invalid Algorithm Type length. Can not have more than " + std::to_string(MAX_ALGORITHM_TYPE_LENGTH) + " characters."; + return false; + } + + if (vchDescription.size() > MAX_DATA_DESCRIPTION_LENGTH) { + strErrorMessage = "Invalid Data Description length. Can not have more than " + std::to_string(MAX_DATA_DESCRIPTION_LENGTH) + " characters."; + return false; + } + + return CAuditData(vchAuditData).ValidateValues(strErrorMessage); +} + +void CAudit::Serialize(std::vector& vchData) +{ + CDataStream dsAudit(SER_NETWORK, PROTOCOL_VERSION); + dsAudit << *this; + vchData = std::vector(dsAudit.begin(), dsAudit.end()); +} + +bool CAudit::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsAudit(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsAudit >> *this; + + std::vector vchAudit; + Serialize(vchAudit); + const uint256& calculatedHash = Hash(vchAudit.begin(), vchAudit.end()); + const std::vector& vchRandAudit = vchFromValue(calculatedHash.GetHex()); + if(vchRandAudit != vchHash) { + SetNull(); + return false; + } + } catch (std::exception& e) { + SetNull(); + return false; + } + return true; +} + +bool CAudit::UnserializeFromTx(const CTransactionRef& tx, const unsigned int& height) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetBDAPData(tx, vchData, vchHash, nOut)) { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) { + return false; + } + txHash = tx->GetHash(); + nHeight = height; + return true; +} + +std::string CAudit::ToString() const +{ + CAuditData auditData = GetAuditData(); + std::string strAuditData; + for(const std::vector& vchAudit : auditData.vAuditData) + strAuditData += "\n " + stringFromVch(vchAudit); + + return strprintf( + "CAudit(\n" + " nVersion = %d\n" + " Audit Count = %d\n" + " Audit Data = %s\n" + " Algorithm Type = %s\n" + " Description = %s\n" + " nTimeStamp = %d\n" + " Owner = %s\n" + " Signed = %s\n" + ")\n", + auditData.nVersion, + auditData.vAuditData.size(), + strAuditData, + stringFromVch(vchAlgorithmType), + stringFromVch(vchDescription), + auditData.nTimeStamp, + stringFromVch(vchOwnerFullObjectPath), + IsSigned() ? "True" : "False" + ); +} + +bool BuildAuditJson(const CAudit& audit, UniValue& oAudit) +{ + int64_t nTime = 0; + CAuditData auditData = audit.GetAuditData(); + + UniValue oAuditHashes(UniValue::VOBJ); + int counter = 0; + for(const std::vector& vchAudit : auditData.vAuditData) { + counter++; + oAuditHashes.push_back(Pair("audit_hash" + std::to_string(counter), stringFromVch(vchAudit))); + } + oAudit.push_back(Pair("version", std::to_string(audit.Version()))); + oAudit.push_back(Pair("audit_count", auditData.vAuditData.size())); + oAudit.push_back(Pair("audit_hashes", oAuditHashes)); + oAudit.push_back(Pair("timestamp", std::to_string(auditData.nTimeStamp))); + oAudit.push_back(Pair("owner", stringFromVch(audit.vchOwnerFullObjectPath))); + oAudit.push_back(Pair("signed", audit.IsSigned() ? "True" : "False")); + oAudit.push_back(Pair("algorithm_type", stringFromVch(audit.vchAlgorithmType))); + oAudit.push_back(Pair("description", stringFromVch(audit.vchDescription))); + oAudit.push_back(Pair("txid", audit.txHash.GetHex())); + if ((unsigned int)chainActive.Height() >= audit.nHeight) { + CBlockIndex *pindex = chainActive[audit.nHeight]; + if (pindex) { + nTime = pindex->GetBlockTime(); + } + } + oAudit.push_back(Pair("block_time", nTime)); + oAudit.push_back(Pair("block_height", std::to_string(audit.nHeight))); + return true; +} + +bool BuildVerifyAuditJson(const CAudit& audit, UniValue& oAudit) +{ + int64_t nTime = 0; + CAuditData auditData = audit.GetAuditData(); + + oAudit.push_back(Pair("version", std::to_string(audit.Version()))); + oAudit.push_back(Pair("audit_count", auditData.vAuditData.size())); + oAudit.push_back(Pair("timestamp", std::to_string(auditData.nTimeStamp))); + oAudit.push_back(Pair("owner", stringFromVch(audit.vchOwnerFullObjectPath))); + oAudit.push_back(Pair("signed", audit.IsSigned() ? "True" : "False")); + oAudit.push_back(Pair("algorithm_type", stringFromVch(audit.vchAlgorithmType))); + oAudit.push_back(Pair("description", stringFromVch(audit.vchDescription))); + oAudit.push_back(Pair("txid", audit.txHash.GetHex())); + if ((unsigned int)chainActive.Height() >= audit.nHeight) { + CBlockIndex *pindex = chainActive[audit.nHeight]; + if (pindex) { + nTime = pindex->GetBlockTime(); + } + } + oAudit.push_back(Pair("block_time", nTime)); + oAudit.push_back(Pair("block_height", std::to_string(audit.nHeight))); + return true; +} + diff --git a/src/bdap/audit.h b/src/bdap/audit.h new file mode 100644 index 0000000000..b6285e4573 --- /dev/null +++ b/src/bdap/audit.h @@ -0,0 +1,173 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_AUDITDATA_H +#define DYNAMIC_BDAP_AUDITDATA_H + +#include "bdap.h" +#include "primitives/transaction.h" +#include "serialize.h" +#include "uint256.h" + +class CKey; +class UniValue; + +typedef std::vector AuditData; + +class CAuditData { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + std::vector vAuditData; // vector of hashes that points to the document being audited + int64_t nTimeStamp; + + CAuditData() { + SetNull(); + } + + CAuditData(const std::vector& vchData) { + UnserializeFromData(vchData); + } + + inline void SetNull() + { + nVersion = CAuditData::CURRENT_VERSION; + vAuditData.clear(); + nTimeStamp = 0; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(vAuditData); + READWRITE(VARINT(nTimeStamp)); + } + + inline friend bool operator==(const CAuditData& a, const CAuditData& b) { + return (a.vAuditData == b.vAuditData && a.nTimeStamp == b.nTimeStamp); + } + + inline friend bool operator!=(const CAuditData& a, const CAuditData& b) { + return !(a == b); + } + + inline CAuditData operator=(const CAuditData& b) { + nVersion = b.nVersion; + vAuditData = b.vAuditData; + nTimeStamp = b.nTimeStamp; + return *this; + } + + inline bool IsNull() const { return (vAuditData.size() == 0); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromData(const std::vector& vchData); + bool ValidateValues(std::string& strErrorMessage); +}; + +/** A CAudit is a combination of a serialized CAuditData class and BDAP account with a signature. */ +class CAudit +{ +public: + std::vector vchAuditData; // serialized CAuditData class + std::vector vchOwnerFullObjectPath; // name of the owner's full domain entry path + std::vector vchSignature; // signature using the owners wallet public key + std::vector vchAlgorithmType; // Algorithm Type (SHA256, Argon2d) - 32 max length + std::vector vchDescription; // Data Description (FHIR message, JSON document, file, database record, etc...) - 128 max length + unsigned int nHeight; + uint64_t nExpireTime; + uint256 txHash; + + CAudit() { + SetNull(); + } + + CAudit(const CTransactionRef& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + CAudit(CAuditData& auditData); + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) + { + READWRITE(vchAuditData); + READWRITE(vchOwnerFullObjectPath); + READWRITE(vchSignature); + READWRITE(vchAlgorithmType); + READWRITE(vchDescription); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline CAudit operator=(const CAudit& b) { + vchAuditData = b.vchAuditData; + vchOwnerFullObjectPath = b.vchOwnerFullObjectPath; + vchSignature = b.vchSignature; + vchAlgorithmType = b.vchAlgorithmType; + vchDescription = b.vchDescription; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline void SetNull() + { + vchAuditData.clear(); + vchOwnerFullObjectPath.clear(); + vchSignature.clear(); + vchAlgorithmType.clear(); + vchDescription.clear(); + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + } + + bool SignatureRequired() const { + return (vchOwnerFullObjectPath.size() > 0); + } + + bool IsSigned() const { + return (vchSignature.size() > 0); + } + + bool IsNull() const { + return (vchAuditData.size() == 0); + } + + CAuditData GetAuditData() const { + return CAuditData(vchAuditData); + } + + std::vector GetAudits() const { + return GetAuditData().vAuditData; + } + + int64_t GetTimeStamp() const { + return GetAuditData().nTimeStamp; + } + + uint256 GetHash() const; + uint256 GetAuditHash() const; + bool Sign(const CKey& key); + bool CheckSignature(const std::vector& vchPubKey) const; + int Version() const; + bool ValidateValues(std::string& strErrorMessage) const; + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransactionRef& tx, const unsigned int& height=0); + std::string ToString() const; +}; + +bool BuildAuditJson(const CAudit& audit, UniValue& oAudit); +bool BuildVerifyAuditJson(const CAudit& audit, UniValue& oAudit); + +#endif // DYNAMIC_BDAP_AUDITDATA_H \ No newline at end of file diff --git a/src/bdap/auditdb.cpp b/src/bdap/auditdb.cpp new file mode 100644 index 0000000000..0b4dd29eaf --- /dev/null +++ b/src/bdap/auditdb.cpp @@ -0,0 +1,383 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/auditdb.h" + +#include "amount.h" +#include "base58.h" +#include "bdap/domainentrydb.h" +#include "bdap/fees.h" +#include "bdap/utils.h" +#include "coins.h" +#include "utilmoneystr.h" +#include "utiltime.h" +#include "validation.h" +#include "validationinterface.h" + +#include + +#include + +CAuditDB *pAuditDB = NULL; + +bool GetAuditTxId(const std::string& strTxId, CAudit& audit) +{ + if (!pAuditDB || !pAuditDB->ReadAuditTxId(vchFromString(strTxId), audit)) + return false; + + return !audit.IsNull(); +} + +bool AuditExists(const std::vector& vchAudit) +{ + if (!pAuditDB) + return false; + + return pAuditDB->AuditExists(vchAudit); +} + +bool UndoAddAudit(const CAudit& audit) +{ + if (!pAuditDB) + return false; + + return pAuditDB->EraseAuditTxId(vchFromString(audit.txHash.ToString())); +} + +bool CAuditDB::AddAudit(const CAudit& audit) +{ + bool writeState = false; + bool writeStateDN = false; + bool auditHashWriteState = true; + { + LOCK(cs_bdap_audit); + CAuditData auditData = audit.GetAuditData(); + for(const std::vector& vchAuditHash : auditData.vAuditData) { + std::vector> vvTxHash; + CDBWrapper::Read(make_pair(std::string("audit"), vchAuditHash), vvTxHash); + vvTxHash.push_back(vchFromString(audit.txHash.ToString())); + // each hash points to a txid. The txid record stores the audit record. + if (!Write(make_pair(std::string("audit"), vchAuditHash), vvTxHash)) { + auditHashWriteState = false; + } + } + if (audit.vchOwnerFullObjectPath.size() > 0) { + std::vector> vvTxId; + CDBWrapper::Read(make_pair(std::string("dn"), audit.vchOwnerFullObjectPath), vvTxId); + vvTxId.push_back(vchFromString(audit.txHash.ToString())); + + writeStateDN = Write(make_pair(std::string("dn"), audit.vchOwnerFullObjectPath), vvTxId); + } + else { + writeStateDN = true; + } + writeState = Write(make_pair(std::string("txid"), vchFromString(audit.txHash.ToString())), audit); + } + + return writeState && auditHashWriteState && writeStateDN; +} + +bool CAuditDB::ReadAuditTxId(const std::vector& vchTxId, CAudit& audit) +{ + LOCK(cs_bdap_audit); + return CDBWrapper::Read(make_pair(std::string("txid"), vchTxId), audit); +} + +bool CAuditDB::ReadAuditDN(const std::vector& vchOwnerFullObjectPath, std::vector& vAudits) +{ + LOCK(cs_bdap_audit); + std::vector> vvTxId; + bool readState = false; + readState = CDBWrapper::Read(make_pair(std::string("dn"), vchOwnerFullObjectPath), vvTxId); + + if (readState) { + for (const std::vector& vchTxId : vvTxId) { + CAudit audit; + if (ReadAuditTxId(vchTxId, audit)) { + vAudits.push_back(audit); + } + } + } + + return (vAudits.size() > 0); +} + +bool CAuditDB::ReadAuditHash(const std::vector& vchAudit, std::vector& vAudits) +{ + LOCK(cs_bdap_audit); + std::vector> vvTxId; + bool readState = false; + readState = CDBWrapper::Read(make_pair(std::string("audit"), vchAudit), vvTxId); + + if (readState) { + for (const std::vector& vchTxId : vvTxId) { + CAudit audit; + if (ReadAuditTxId(vchTxId, audit)) { + vAudits.push_back(audit); + } + } + } + + return (vAudits.size() > 0); +} + +bool CAuditDB::AuditExists(const std::vector& vchAudit) +{ + LOCK(cs_bdap_audit); + return CDBWrapper::Exists(make_pair(std::string("audit"), vchAudit)); +} + +bool CAuditDB::EraseAuditTxId(const std::vector& vchTxId) +{ + LOCK(cs_bdap_audit); + CAudit audit; + if (ReadAuditTxId(vchTxId, audit)) { + for(const std::vector& vchAudit : audit.GetAudits()) + CDBWrapper::Erase(make_pair(std::string("audit"), vchAudit)); + } + if (audit.vchOwnerFullObjectPath.size() > 0) { + std::vector> vvTxId; + CDBWrapper::Read(make_pair(std::string("dn"), audit.vchOwnerFullObjectPath), vvTxId); + if (vvTxId.size() == 1 && vvTxId[0] == vchTxId) { + CDBWrapper::Erase(make_pair(std::string("dn"), audit.vchOwnerFullObjectPath)); + } + else { + std::vector> vvTxIdNew; + for (const std::vector& txid : vvTxId) { + if (txid != vchTxId) { + vvTxIdNew.push_back(txid); + } + } + Write(make_pair(std::string("dn"), audit.vchOwnerFullObjectPath), vvTxIdNew); + } + } + return CDBWrapper::Erase(make_pair(std::string("txid"), vchTxId)); +} + +bool CAuditDB::EraseAudit(const std::vector& vchAudit) +{ + LOCK(cs_bdap_audit); + return CDBWrapper::Erase(make_pair(std::string("audit"), vchAudit)); +} + +bool CheckAuditDB() +{ + if (!pAuditDB) + return false; + + return true; +} + +bool FlushAuditLevelDB() +{ + { + LOCK(cs_bdap_audit); + if (pAuditDB != NULL) + { + if (!pAuditDB->Flush()) { + LogPrintf("Failed to flush Audit BDAP database!"); + return false; + } + } + } + return true; +} + +static bool CommonDataCheck(const CAudit& audit, const vchCharString& vvchOpParameters, std::string& errorMessage) +{ + if (audit.IsNull()) { + errorMessage = "CommonDataCheck failed! Audit is null."; + return false; + } + + if (!audit.ValidateValues(errorMessage)) { + errorMessage = "CommonDataCheck failed! Invalid audit value. " + errorMessage; + return false; + } + + if (vvchOpParameters.size() > 3) { + errorMessage = "CommonDataCheck failed! Too many parameters."; + return false; + } + + if (vvchOpParameters.size() < 1) { + errorMessage = "CommonDataCheck failed! Not enough parameters."; + return false; + } + // check count parameter is not longer than + if (vvchOpParameters[0].size() > 10) { + errorMessage = "CommonDataCheck failed! Not enough parameters."; + return false; + } + // check if count equals audit count. + uint32_t nCount; + ParseUInt32(stringFromVch(vvchOpParameters[0]), &nCount); + if (nCount != audit.GetAudits().size()) { + errorMessage = "CommonDataCheck failed! Parameter count does not match audits in data."; + return false; + } + + // check if signed. + if (vvchOpParameters.size() == 2) { + errorMessage = "CommonDataCheck failed! Only two parameters. Signed audits require 3 parameters."; + return false; + } + + if (vvchOpParameters.size() > 1 && audit.vchOwnerFullObjectPath != vvchOpParameters[1]) { + errorMessage = "CommonDataCheck failed! Script operation account parameter does not match account in audit object."; + return false; + } + // check FQDN size + if (vvchOpParameters.size() > 1 && vvchOpParameters[1].size() > MAX_OBJECT_FULL_PATH_LENGTH) { + errorMessage = "CommonDataCheck failed! Count parameter value too large."; + return false; + } + // check pubkey size + if (vvchOpParameters.size() > 1 && vvchOpParameters[2].size() > MAX_KEY_LENGTH) { + errorMessage = "CommonDataCheck failed! Count parameter value too large."; + return false; + } + return true; +} + +static bool CheckNewAuditTxInputs(const CAudit& audit, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash, + std::string& errorMessage, bool fJustCheck) +{ + if (!CommonDataCheck(audit, vvchOpParameters, errorMessage)) + return error(errorMessage.c_str()); + + if (fJustCheck) + return true; + + // check audit signature if required. + if (audit.SignatureRequired()) { + if (!audit.IsSigned()) { + errorMessage = "CheckNewAuditTxInputs: - The audit requires a signature. Add new audit failed!"; + return error(errorMessage.c_str()); + } + CDomainEntry entry; + if (!GetDomainEntry(audit.vchOwnerFullObjectPath, entry)) { + errorMessage = "CheckNewAuditTxInputs: - Could not find specified audit account owner! " + stringFromVch(audit.vchOwnerFullObjectPath); + return error(errorMessage.c_str()); + } + CDynamicAddress address = entry.GetWalletAddress(); + CKeyID keyID; + if (!address.GetKeyID(keyID)) { + errorMessage = "CheckNewAuditTxInputs: - Could not get key id. " + address.ToString(); + return error(errorMessage.c_str()); + } + // check signature and pubkey belongs to bdap account. + CPubKey pubkey(vvchOpParameters[2]); + + CDynamicAddress addressCompare(pubkey.GetID()); + + if (!(address == addressCompare)) { + errorMessage = "CheckNewAuditTxInputs: - Wallet address does not match. "; + return error(errorMessage.c_str()); + } + + if (!audit.CheckSignature(pubkey.Raw())) { + errorMessage = "CheckNewAuditTxInputs: - Could not validate signature. "; + return error(errorMessage.c_str()); + } + + } + + CAudit getAudit; + if (GetAuditTxId(audit.txHash.ToString(), getAudit)) { + if (audit.txHash != txHash) { + errorMessage = "CheckNewAuditTxInputs: - The audit " + audit.txHash.ToString() + " already exists. Add new audit failed!"; + return error(errorMessage.c_str()); + } else { + LogPrintf("%s -- Already have audit %s in local database. Skipping add audit step.\n", __func__, audit.txHash.ToString()); + return true; + } + } + + if (!pAuditDB) { + errorMessage = "CheckNewAuditTxInputs failed! Can not open LevelDB BDAP audit database."; + return error(errorMessage.c_str()); + } + if (!pAuditDB->AddAudit(audit)) { + errorMessage = "CheckNewAuditTxInputs failed! Error adding new audit record to LevelDB."; + pAuditDB->EraseAuditTxId(vchFromString(audit.txHash.ToString())); + return error(errorMessage.c_str()); + } + + return FlushAuditLevelDB(); +} + +bool CheckAuditTx(const CTransactionRef& tx, const CScript& scriptOp, const int& op1, const int& op2, const std::vector >& vvchArgs, + const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage) +{ + if (tx->IsCoinBase() && !fJustCheck && !bSanityCheck) { + LogPrintf("*Trying to add BDAP audit in coinbase transaction, skipping..."); + return true; + } + + LogPrint("bdap", "%s -- BDAP nHeight=%d, chainActive.Tip()=%d, op1=%s, op2=%s, hash=%s justcheck=%s\n", __func__, nHeight, chainActive.Tip()->nHeight, BDAPFromOp(op1).c_str(), BDAPFromOp(op2).c_str(), tx->GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); + + // unserialize BDAP from txn, check if the audit is valid and does not conflict with a previous audit + CAudit audit; + std::vector vchData; + std::vector vchHash; + int nDataOut; + bool bData = GetBDAPData(tx, vchData, vchHash, nDataOut); + if(bData && !audit.UnserializeFromTx(tx, nHeight)) + { + errorMessage = ("UnserializeFromData data in tx failed!"); + LogPrintf("%s -- %s \n", __func__, errorMessage); + return error(errorMessage.c_str()); + } + const std::string strOperationType = GetBDAPOpTypeString(op1, op2); + CAmount monthlyFee, oneTimeFee, depositFee; + if (strOperationType == "bdap_new_audit") { + if (!audit.ValidateValues(errorMessage)) + return false; + + if (vvchArgs.size() > 3) { + errorMessage = "Failed to get fees to add a new BDAP account"; + return false; + } + std::string strCount = stringFromVch(vvchArgs[0]); + uint32_t nCount; + ParseUInt32(stringFromVch(vvchArgs[0]), &nCount); + if (!GetBDAPFees(OP_BDAP_NEW, OP_BDAP_AUDIT, BDAP::ObjectType::BDAP_AUDIT, (uint16_t)nCount, monthlyFee, oneTimeFee, depositFee)) { + errorMessage = "Failed to get fees to add a new BDAP account"; + return false; + } + LogPrint("bdap", "%s -- nCount %d, oneTimeFee %d\n", __func__, nCount, FormatMoney(oneTimeFee)); + // extract amounts from tx. + CAmount dataAmount, opAmount; + if (!ExtractAmountsFromTx(tx, dataAmount, opAmount)) { + errorMessage = "Unable to extract BDAP amounts from transaction"; + return false; + } + LogPrint("bdap", "%s -- dataAmount %d, opAmount %d\n", __func__, FormatMoney(dataAmount), FormatMoney(opAmount)); + if (monthlyFee > dataAmount) { + LogPrintf("%s -- Invalid BDAP monthly registration fee amount for new BDAP account. Monthly paid %d but should be %d\n", __func__, + FormatMoney(dataAmount), FormatMoney(monthlyFee)); + errorMessage = "Invalid BDAP monthly registration fee amount for new BDAP account"; + return false; + } + else { + LogPrint("bdap", "%s -- Valid BDAP monthly registration fee amount for new BDAP account. Monthly paid %d, should be %d.\n", __func__, + FormatMoney(dataAmount), FormatMoney(monthlyFee)); + } + if (depositFee > opAmount) { + LogPrintf("%s -- Invalid BDAP deposit fee amount for new BDAP account. Deposit paid %d but should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + errorMessage = "Invalid BDAP deposit fee amount for new BDAP account"; + return false; + } + else { + LogPrint("bdap", "%s -- Valid BDAP deposit fee amount for new BDAP account. Deposit paid %d, should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + } + + return CheckNewAuditTxInputs(audit, scriptOp, vvchArgs, tx->GetHash(), errorMessage, fJustCheck); + } + + return false; +} diff --git a/src/bdap/auditdb.h b/src/bdap/auditdb.h new file mode 100644 index 0000000000..6550533218 --- /dev/null +++ b/src/bdap/auditdb.h @@ -0,0 +1,41 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_AUDITDB_H +#define DYNAMIC_BDAP_AUDITDB_H + +#include "bdap/audit.h" +#include "dbwrapper.h" +#include "sync.h" + +class CCoinsViewCache; +class UniValue; + +static CCriticalSection cs_bdap_audit; + +class CAuditDB : public CDBWrapper { +public: + CAuditDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "blocks" / "bdap-audits", nCacheSize, fMemory, fWipe, obfuscate) { + } + bool AddAudit(const CAudit& audit); + bool ReadAudit(const std::vector& vchAudit, CAudit& audit); + bool ReadAuditTxId(const std::vector& vchTxId, CAudit& audit); + bool ReadAuditDN(const std::vector& vchOwnerFullObjectPath, std::vector& vAudits); + bool ReadAuditHash(const std::vector& vchAudit, std::vector& vAudits); + bool EraseAuditTxId(const std::vector& vchTxId); + bool EraseAudit(const std::vector& vchAudit); + bool AuditExists(const std::vector& vchAudit); +}; + +bool GetAuditTxId(const std::string& strTxId, CAudit& audit); +bool AuditExists(const std::vector& vchAudit); +bool UndoAddAudit(const CAudit& audit); +bool CheckAuditDB(); +bool FlushAuditLevelDB(); +bool CheckAuditTx(const CTransactionRef& tx, const CScript& scriptOp, const int& op1, const int& op2, const std::vector >& vvchArgs, + const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage); + +extern CAuditDB *pAuditDB; + +#endif // DYNAMIC_BDAP_AUDITDB_H \ No newline at end of file diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h new file mode 100644 index 0000000000..78243b6ba7 --- /dev/null +++ b/src/bdap/bdap.h @@ -0,0 +1,94 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_H +#define DYNAMIC_BDAP_H + +#include +#include + +namespace BDAP { + enum ObjectType { + BDAP_DEFAULT_TYPE = 0, + BDAP_USER = 1, + BDAP_GROUP = 2, + BDAP_DEVICE = 3, + BDAP_DOMAIN = 4, + BDAP_ORGANIZATIONAL_UNIT = 5, + BDAP_CERTIFICATE = 6, + BDAP_AUDIT = 7, + BDAP_SIDECHAIN = 8, + BDAP_SIDECHAIN_CHECKPOINT = 9, + BDAP_LINK_REQUEST = 10, + BDAP_LINK_ACCEPT = 11, + BDAP_IDENTITY = 12, + BDAP_IDENTITY_VERIFICATION = 13 + }; +} + +typedef std::vector CharString; +typedef std::vector vchCharString; +typedef std::pair CheckPoint; +typedef std::vector vCheckPoints; // << height, block hash >> + +static constexpr unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) +static constexpr unsigned int MAX_OBJECT_NAME_LENGTH = 63; +static constexpr unsigned int MAX_OBJECT_FULL_PATH_LENGTH = (MAX_OBJECT_NAME_LENGTH * 3) + 2; // domain + ou + object name + 2 dot chars +static constexpr unsigned int MAX_ALGORITHM_TYPE_LENGTH = 32; +static constexpr unsigned int MAX_DATA_DESCRIPTION_LENGTH = 128; +static constexpr unsigned int MAX_COMMON_NAME_LENGTH = 95; +static constexpr unsigned int MAX_ORG_NAME_LENGTH = 95; +static constexpr unsigned int MAX_WALLET_ADDRESS_LENGTH = 105; // Stealth addresses are 102 chars in length plus 3 for a prefix. Regular addresses are 34 chars. +static constexpr unsigned int MAX_RESOURCE_POINTER_LENGTH = 127; +static constexpr unsigned int MAX_KEY_LENGTH = 156; +static constexpr unsigned int MAX_DESCRIPTION_LENGTH = 256; +static constexpr unsigned int MAX_CERTIFICATE_FILENAME = 256; +static constexpr unsigned int MAX_CERTIFICATE_LENGTH = 512; +static constexpr unsigned int MAX_CERTIFICATE_NAME = 63; +static constexpr unsigned int MAX_CERTIFICATE_CATEGORY = 32; +static constexpr unsigned int MAX_CERTIFICATE_FINGERPRINT = 32; +static constexpr unsigned int MAX_CERTIFICATE_PEM_LENGTH = 3600; +static constexpr unsigned int MAX_CERTIFICATE_EXTENSION_RECORDS = 10; +static constexpr unsigned int MAX_CERTIFICATE_EXTENSION_LENGTH = 100; +static constexpr unsigned int MAX_CERTIFICATE_KEY_LENGTH = 512; +static constexpr unsigned int MAX_CERTIFICATE_SIGNATURE_LENGTH = 512; +static constexpr unsigned int MAX_CERTIFICATE_MONTHS_VALID = 12; +static constexpr unsigned int MAX_CERTIFICATE_CA_MONTHS_VALID = 120; +static constexpr unsigned int MAX_OID_LENGTH = 128; +static constexpr unsigned int MAX_SIGNATURE_LENGTH = 65; // https://bitcoin.stackexchange.com/questions/12554/why-the-signature-is-always-65-13232-bytes-long +static constexpr unsigned int MAX_PRIVATE_DATA_LENGTH = 512; // Pay per byte for hosting on chain +static constexpr unsigned int MAX_NUMBER_CHECKPOINTS = 25; // Pay per byte for hosting on chain +static constexpr unsigned int MAX_CHECKPOINT_HASH_LENGTH = 64; +static constexpr unsigned int DHT_HEX_PUBLIC_KEY_LENGTH = 64; // Ed25519 pubkeys are 32 bytes and 64 bytes when hex encoded. +static constexpr unsigned int MAX_BDAP_LINK_MESSAGE = 256; +static constexpr unsigned int MAX_BDAP_SIGNATURE_PROOF = 90; // TODO (bdap): Update to 65 or use MAX_SIGNATURE_LENGTH when you start a new chain. +static constexpr unsigned int MAX_BDAP_LINK_DATA_SIZE = 1592; +static constexpr uint64_t DEFAULT_LINK_EXPIRE_TIME = 1861920000; +static constexpr int32_t DEFAULT_REGISTRATION_MONTHS = 12; // 1 year +static constexpr bool ENFORCE_BDAP_CREDIT_USE = false; // TODO: Change to true before release +static constexpr uint32_t MAX_REGISTRATION_MONTHS = 1200; // 100 years +static constexpr unsigned int MAX_BDAP_AUDIT_HASH_SIZE = 64; +static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; +static const std::string DEFAULT_PUBLIC_OU = "public"; +static const std::string DEFAULT_ADMIN_OU = "admin"; +static const std::string DEFAULT_ORGANIZATION_NAME = "Duality Blockchain Solutions"; +/* +BDAP Root OID: 2.16.840.1.114564 +{joint-iso-ccitt(2) country(16) US(840) organization(1) BDAP(114564)} +*/ +static const std::string DEFAULT_OID_PREFIX = "2.16.840.1.114564"; + +inline const CharString ConvertConstantToCharString (const std::string strConvert) +{ + CharString vchConvert(strConvert.begin(), strConvert.end()); + return vchConvert; +}; + +static const CharString vchDefaultDomainName = ConvertConstantToCharString(DEFAULT_PUBLIC_DOMAIN); +static const CharString vchDefaultPublicOU = ConvertConstantToCharString(DEFAULT_PUBLIC_OU); +static const CharString vchDefaultAdminOU = ConvertConstantToCharString(DEFAULT_ADMIN_OU); +static const CharString vchDefaultOrganizationName = ConvertConstantToCharString(DEFAULT_ORGANIZATION_NAME); +static const CharString vchDefaultOIDPrefix = ConvertConstantToCharString(DEFAULT_OID_PREFIX); + +#endif // DYNAMIC_BDAP_H diff --git a/src/bdap/certificatedb.cpp b/src/bdap/certificatedb.cpp new file mode 100644 index 0000000000..a03c491bd1 --- /dev/null +++ b/src/bdap/certificatedb.cpp @@ -0,0 +1,660 @@ +// Copyright (c) 2020 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/certificatedb.h" + +#include "amount.h" +#include "base58.h" +#include "bdap/domainentrydb.h" +#include "bdap/fees.h" +#include "bdap/utils.h" +#include "coins.h" +#include "dht/ed25519.h" +#include "utilmoneystr.h" +#include "utiltime.h" +#include "validation.h" +#include "validationinterface.h" + +#include + +#include + +CCertificateDB *pCertificateDB = NULL; + +bool GetCertificateTxId(const std::string& strTxId, CX509Certificate& certificate) +{ + if (!pCertificateDB || !pCertificateDB->ReadCertificateTxId(vchFromString(strTxId), certificate)) + return false; + + return !certificate.IsNull(); +} + +bool GetCertificateSerialNumber(const std::string& strSerialNumber, CX509Certificate& certificate) +{ + uint64_t value; + std::istringstream iss(strSerialNumber); + iss >> value; + + if (!pCertificateDB || !pCertificateDB->ReadCertificateSerialNumber(value, certificate)) + return false; + + return !certificate.IsNull(); +} + +bool UndoAddCertificate(const CX509Certificate& certificate) +{ + if (!pCertificateDB) + return false; + + if (certificate.IsApproved()) { + return pCertificateDB->EraseCertificateTxId(vchFromString(certificate.txHashSigned.ToString())); + } + else { + return pCertificateDB->EraseCertificateTxId(vchFromString(certificate.txHashRequest.ToString())); + } + +} + +bool CCertificateDB::AddCertificate(const CX509Certificate& certificate) +{ + bool writeState = false; + bool writeStateCA = true; + bool writeStateSerial = true; + bool updateState = true; + bool writeStateIssuerDN = true; + bool writeStateSubjectDN = true; + { + LOCK(cs_bdap_certificate); + + std::string labelTxId; + std::string labelSubjectDN; + std::string labelIssuerDN; + std::vector vchTxHash; + std::vector vchTxHashRequest; + + if (certificate.IsRootCA){ //Root certificate + vchTxHash = vchFromString(certificate.txHashSigned.ToString()); + labelTxId = "txrootcaid"; + //labelSubjectDN = "subjectdnrootca"; + //labelIssuerDN = "issuerdnrootca"; + } + else if (certificate.IsApproved()){ //Approve + vchTxHash = vchFromString(certificate.txHashSigned.ToString()); + vchTxHashRequest = vchFromString(certificate.txHashRequest.ToString()); + labelTxId = "txapproveid"; + labelSubjectDN = "subjectdnapprove"; + labelIssuerDN = "issuerdnapprove"; + } + else { //Request + vchTxHash = vchFromString(certificate.txHashRequest.ToString()); + labelTxId = "txrequestid"; + labelSubjectDN = "subjectdnrequest"; + labelIssuerDN = "issuerdnrequest"; + } + + if (!certificate.IsRootCA) { + //Subject + std::vector> vvTxIdSubject; + CDBWrapper::Read(make_pair(labelSubjectDN, certificate.Subject), vvTxIdSubject); + vvTxIdSubject.push_back(vchTxHash); + writeStateSubjectDN = Write(make_pair(labelSubjectDN, certificate.Subject), vvTxIdSubject); + + //Issuer + std::vector> vvTxIdIssuer; + CDBWrapper::Read(make_pair(labelIssuerDN, certificate.Issuer), vvTxIdIssuer); + vvTxIdIssuer.push_back(vchTxHash); + writeStateIssuerDN = Write(make_pair(labelIssuerDN, certificate.Issuer), vvTxIdIssuer); + } + + //Certificate + writeState = Write(make_pair(labelTxId, vchTxHash), certificate); + + //Serial Number + if (certificate.SerialNumber != 0) { + writeStateSerial = Write(make_pair(std::string("serialnumber"), certificate.SerialNumber), vchTxHash); + } + + //if root certificate, index the issuer (subject=issuer). only one root certificate per bdap account + if (certificate.IsRootCA){ + writeStateCA = Write(make_pair(std::string("issuerrootca"), certificate.Issuer), vchTxHash); + } + //if an approve (not self-signed), update the previous request certificate with txHashSigned + else if ((certificate.IsApproved()) && (!certificate.SelfSignedX509Certificate())) { + CX509Certificate requestCertificate; + if (ReadCertificateTxId(vchTxHashRequest, requestCertificate)) { + requestCertificate.txHashSigned = certificate.txHashSigned; + updateState = Write(make_pair(std::string("txrequestid"), vchTxHashRequest), requestCertificate); + } + } + + } + return writeState && writeStateIssuerDN && writeStateSubjectDN && updateState && writeStateCA && writeStateSerial; +} + +bool CCertificateDB::ReadCertificateTxId(const std::vector& vchTxId, CX509Certificate& certificate) +{ + LOCK(cs_bdap_certificate); + if(!(CDBWrapper::Read(make_pair(std::string("txrequestid"), vchTxId), certificate))) { + if(!(CDBWrapper::Read(make_pair(std::string("txapproveid"), vchTxId), certificate))) { + return CDBWrapper::Read(make_pair(std::string("txrootcaid"), vchTxId), certificate); + } + } + return true; +} + +bool CCertificateDB::ReadCertificateIssuerRootCA(const std::vector& vchIssuer, CX509Certificate& certificate) +{ + LOCK(cs_bdap_certificate); + std::vector vchTxId; + bool readState = false; + readState = CDBWrapper::Read(make_pair(std::string("issuerrootca"), vchIssuer), vchTxId); + + if (readState) { + return ReadCertificateTxId(vchTxId, certificate); + } + else { + return false; + } +} + +bool CCertificateDB::ReadCertificateSerialNumber(const uint64_t& nSerialNumber, CX509Certificate& certificate) +{ + LOCK(cs_bdap_certificate); + std::vector vchTxId; + bool readState = false; + readState = CDBWrapper::Read(make_pair(std::string("serialnumber"), nSerialNumber), vchTxId); + + if (readState) { + return ReadCertificateTxId(vchTxId, certificate); + } + else { + return false; + } + return true; +} + +bool CCertificateDB::ReadCertificateSubjectDNRequest(const std::vector& vchSubject, std::vector& vCertificates, bool getAll) +{ + LOCK(cs_bdap_certificate); + std::vector> vvTxId; + std::vector> vvTxIdApprove; + bool readState = false; + readState = CDBWrapper::Read(make_pair(std::string("subjectdnrequest"), vchSubject), vvTxId); + + if (readState) { + for (const std::vector& vchTxId : vvTxId) { + CX509Certificate certificate; + if (ReadCertificateTxId(vchTxId, certificate)) { + if (getAll || (!certificate.IsApproved())) { + vCertificates.push_back(certificate); + } + } + } + } + + return (vCertificates.size() > 0); +} + +bool CCertificateDB::ReadCertificateIssuerDNRequest(const std::vector& vchIssuer, std::vector& vCertificates, bool getAll) +{ + LOCK(cs_bdap_certificate); + std::vector> vvTxId; + std::vector> vvTxIdApprove; + bool readState = false; + readState = CDBWrapper::Read(make_pair(std::string("issuerdnrequest"), vchIssuer), vvTxId); + + if (readState) { + for (const std::vector& vchTxId : vvTxId) { + CX509Certificate certificate; + if (ReadCertificateTxId(vchTxId, certificate)) { + if (getAll || (!certificate.IsApproved())) { + vCertificates.push_back(certificate); + } + } + } + } + + return (vCertificates.size() > 0); +} + +bool CCertificateDB::ReadCertificateSubjectDNApprove(const std::vector& vchSubject, std::vector& vCertificates) +{ + LOCK(cs_bdap_certificate); + std::vector> vvTxId; + bool readState = false; + readState = CDBWrapper::Read(make_pair(std::string("subjectdnapprove"), vchSubject), vvTxId); + + if (readState) { + for (const std::vector& vchTxId : vvTxId) { + CX509Certificate certificate; + if (ReadCertificateTxId(vchTxId, certificate)) { + vCertificates.push_back(certificate); + } + } + } + + return (vCertificates.size() > 0); +} + +bool CCertificateDB::ReadCertificateIssuerDNApprove(const std::vector& vchIssuer, std::vector& vCertificates) +{ + LOCK(cs_bdap_certificate); + std::vector> vvTxId; + bool readState = false; + readState = CDBWrapper::Read(make_pair(std::string("issuerdnapprove"), vchIssuer), vvTxId); + + if (readState) { + for (const std::vector& vchTxId : vvTxId) { + CX509Certificate certificate; + if (ReadCertificateTxId(vchTxId, certificate)) { + vCertificates.push_back(certificate); + } + } + } + + return (vCertificates.size() > 0); +} + +bool CCertificateDB::EraseCertificateTxId(const std::vector& vchTxId) +{ + LOCK(cs_bdap_certificate); + CX509Certificate certificate; + + if (!ReadCertificateTxId(vchTxId, certificate)) + return false; + + //subjectrequest + std::vector> vvSubjectRequestTxId; + CDBWrapper::Read(make_pair(std::string("subjectdnrequest"), certificate.Subject), vvSubjectRequestTxId); + if (vvSubjectRequestTxId.size() == 1 && vvSubjectRequestTxId[0] == vchTxId) { + CDBWrapper::Erase(make_pair(std::string("subjectdnrequest"), certificate.Subject)); + } + else { + std::vector> vvTxIdSubjectRequestNew; + for (const std::vector& txid : vvSubjectRequestTxId) { + if (txid != vchTxId) { + vvTxIdSubjectRequestNew.push_back(txid); + } + } + Write(make_pair(std::string("subjectdnrequest"), certificate.Subject), vvTxIdSubjectRequestNew); + } + + //issuerrequest + std::vector> vvIssuerRequestTxId; + CDBWrapper::Read(make_pair(std::string("issuerdnrequest"), certificate.Issuer), vvIssuerRequestTxId); + if (vvIssuerRequestTxId.size() == 1 && vvIssuerRequestTxId[0] == vchTxId) { + CDBWrapper::Erase(make_pair(std::string("issuerdnrequest"), certificate.Issuer)); + } + else { + std::vector> vvTxIdIssuerRequestNew; + for (const std::vector& txid : vvIssuerRequestTxId) { + if (txid != vchTxId) { + vvTxIdIssuerRequestNew.push_back(txid); + } + } + Write(make_pair(std::string("issuerdnrequest"), certificate.Issuer), vvTxIdIssuerRequestNew); + } + + //subjectapprove + std::vector> vvSubjectApproveTxId; + CDBWrapper::Read(make_pair(std::string("subjectdnapprove"), certificate.Subject), vvSubjectApproveTxId); + if (vvSubjectApproveTxId.size() == 1 && vvSubjectApproveTxId[0] == vchTxId) { + CDBWrapper::Erase(make_pair(std::string("subjectdnapprove"), certificate.Subject)); + } + else { + std::vector> vvTxIdSubjectApproveNew; + for (const std::vector& txid : vvSubjectApproveTxId) { + if (txid != vchTxId) { + vvTxIdSubjectApproveNew.push_back(txid); + } + } + Write(make_pair(std::string("subjectdnapprove"), certificate.Subject), vvTxIdSubjectApproveNew); + } + + //issuerapprove + std::vector> vvIssuerApproveTxId; + CDBWrapper::Read(make_pair(std::string("issuerdnapprove"), certificate.Issuer), vvIssuerApproveTxId); + if (vvIssuerApproveTxId.size() == 1 && vvIssuerApproveTxId[0] == vchTxId) { + CDBWrapper::Erase(make_pair(std::string("issuerdnapprove"), certificate.Issuer)); + } + else { + std::vector> vvTxIdIssuerApproveNew; + for (const std::vector& txid : vvIssuerApproveTxId) { + if (txid != vchTxId) { + vvTxIdIssuerApproveNew.push_back(txid); + } + } + Write(make_pair(std::string("issuerdnapprove"), certificate.Issuer), vvTxIdIssuerApproveNew); + } + + if (certificate.SerialNumber != 0) { + CDBWrapper::Erase(make_pair(std::string("serialnumber"), certificate.SerialNumber)); + } + + if (certificate.IsRootCA) { + return (CDBWrapper::Erase(make_pair(std::string("issuerrootca"), certificate.Issuer))) && (CDBWrapper::Erase(make_pair(std::string("txrootcaid"), vchTxId))); + } + else if (certificate.IsApproved()) { + return CDBWrapper::Erase(make_pair(std::string("txapproveid"), vchTxId)); + } + else { + return CDBWrapper::Erase(make_pair(std::string("txrequestid"), vchTxId)); + } + +} + +bool CheckCertificateDB() +{ + if (!pCertificateDB) + return false; + + return true; +} + +bool FlushCertificateLevelDB() +{ + { + LOCK(cs_bdap_certificate); + if (pCertificateDB != NULL) + { + if (!pCertificateDB->Flush()) { + LogPrintf("Failed to flush Certificate BDAP database!"); + return false; + } + } + } + return true; +} + +static bool CommonDataCheck(const CX509Certificate& certificate, const vchCharString& vvchOpParameters, std::string& errorMessage) +{ + if (certificate.IsNull()) { + errorMessage = "CommonDataCheck failed! Certificate is null."; + return false; + } + + if (!certificate.ValidateValues(errorMessage)) { + errorMessage = "CommonDataCheck failed! Invalid certificate value. " + errorMessage; + return false; + } + + if (vvchOpParameters.size() > 6) { + errorMessage = "CommonDataCheck failed! Too many parameters."; + return false; + } + + if (vvchOpParameters.size() < 5) { + errorMessage = "CommonDataCheck failed! Not enough parameters."; + return false; + } + + if (certificate.Subject != vvchOpParameters[2]) { + errorMessage = "CommonDataCheck failed! Script operation subject account parameter does not match subject account in certificate object."; + return false; + } + + if (certificate.Issuer != vvchOpParameters[4]) { + errorMessage = "CommonDataCheck failed! Script operation issuer account parameter does not match issuer account in certificate object."; + return false; + } + + // check SubjectFQDN size + if (vvchOpParameters.size() > 2 && vvchOpParameters[2].size() > MAX_OBJECT_FULL_PATH_LENGTH) { + errorMessage = "CommonDataCheck failed! Subject FQDN is too large."; + return false; + } + + // check IssuerFQDN size + if (vvchOpParameters.size() > 4 && vvchOpParameters[4].size() > MAX_OBJECT_FULL_PATH_LENGTH) { + errorMessage = "CommonDataCheck failed! Issuer FQDN is too large."; + return false; + } + + // check subject pubkey size + if (vvchOpParameters.size() > 3 && vvchOpParameters[3].size() > MAX_CERTIFICATE_KEY_LENGTH) { + errorMessage = "CommonDataCheck failed! Subject PubKey is too large."; + return false; + } + + //check certificate pubkey size + if (certificate.SubjectPublicKey.size() > MAX_CERTIFICATE_KEY_LENGTH) { + errorMessage = "CommonDataCheck failed! Certificate PubKey is too large."; + return false; + } + + // if self-signed, pubkey of subject = issuer + if (certificate.SelfSignedX509Certificate()) { + if (vvchOpParameters[3] != vvchOpParameters[5]) { + errorMessage = "CommonDataCheck failed! Self signed, but subject pubkey not equal to issuer pubkey."; + return false; + } + } + + // check if Months Valid is an accepted value + uint32_t nMonthsValid; + ParseUInt32(stringFromVch(vvchOpParameters[1]), &nMonthsValid); + + if (certificate.IsRootCA) { + if (!(nMonthsValid > 0 && nMonthsValid <= MAX_CERTIFICATE_CA_MONTHS_VALID)) { // if NOT (nMonthsValid greater than 0 and less than or equal to 120) + errorMessage = "CommonDataCheck failed! Months Valid is out of bounds."; + return false; + } + } + else { + if (!(nMonthsValid > 0 && nMonthsValid <= MAX_CERTIFICATE_MONTHS_VALID)) { // if NOT (nMonthsValid greater than 0 and less than or equal to 12) + errorMessage = "CommonDataCheck failed! Months Valid is out of bounds."; + return false; + } + } + + // if approved or self signed, do additional checks + if (certificate.IsApproved() || certificate.SelfSignedX509Certificate()) { + + // check issuer pubkey size + if (vvchOpParameters.size() > 5 && vvchOpParameters[5].size() > MAX_CERTIFICATE_KEY_LENGTH) { + errorMessage = "CommonDataCheck failed! Issuer PubKey is too large."; + return false; + } + + } + + return true; +} + +static bool CheckNewCertificateTxInputs(const CX509Certificate& certificate, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash, + const std::string& strOpType, std::string& errorMessage, bool fJustCheck) +{ + if (!CommonDataCheck(certificate, vvchOpParameters, errorMessage)) + return error(errorMessage.c_str()); + + if (fJustCheck) + return true; + + std::string strTxHashToUse; + + //confirm state of certificate matches strOpType + if (strOpType == "bdap_new_certificate") { + if (certificate.IsApproved()) { + errorMessage = "CheckNewCertificateTxInputs: - Certificate approved but this is identified as a request op"; + return error(errorMessage.c_str()); + } + } + else if (strOpType == "bdap_approve_certificate") { + if (!certificate.IsApproved()) { + errorMessage = "CheckNewCertificateTxInputs: - Certificate not approved but this is identified as an approve op"; + return error(errorMessage.c_str()); + } + } + + if (certificate.IsApproved()){ //Approve + strTxHashToUse = certificate.txHashSigned.ToString(); + } + else { //Request + strTxHashToUse = certificate.txHashRequest.ToString(); + } + + CDomainEntry entrySubject; + if (!GetDomainEntry(certificate.Subject, entrySubject)) { + errorMessage = "CheckNewCertificateTxInputs: - Could not find specified certificate subject! " + stringFromVch(certificate.Subject); + return error(errorMessage.c_str()); + } + CharString vchSubjectPubKey = entrySubject.DHTPublicKey; + + if ( (!certificate.SelfSignedX509Certificate()) && (!certificate.IsApproved()) ) { + //check subject signature (only if Request) + if (!certificate.CheckSubjectSignature(EncodedPubKeyToBytes(vchSubjectPubKey))) { //test in rpc, should work + errorMessage = "CheckNewCertificateTxInputs: - Could not validate subject signature. "; + return error(errorMessage.c_str()); + } + } + + //if approved check issuer signature and if not self signed check if request exists + if (certificate.IsApproved()) { + CDomainEntry entryIssuer; + if (!GetDomainEntry(certificate.Issuer, entryIssuer)) { + errorMessage = "CheckNewCertificateTxInputs: - Could not find specified certificate issuer! " + stringFromVch(certificate.Issuer); + return error(errorMessage.c_str()); + } + CDynamicAddress address = entryIssuer.GetWalletAddress(); + + CharString vchIssuerPubKey = entryIssuer.DHTPublicKey; + + if (!certificate.CheckIssuerSignature(EncodedPubKeyToBytes(vchIssuerPubKey))) { //test in rpc, should work + errorMessage = "CheckNewCertificateTxInputs: - Could not validate issuer signature. "; + return error(errorMessage.c_str()); + } + + //if not self signed, check if request exists + if (!certificate.SelfSignedX509Certificate()) { + CX509Certificate certificateRequest; + if (!GetCertificateTxId(certificate.txHashRequest.ToString(), certificateRequest)) { + errorMessage = "CheckNewCertificateTxInputs: - Could not find previous request. "; + return error(errorMessage.c_str()); + } + } + } + + //Check if Certificate already exists - should work w/Approve TXID occurring after Request + CX509Certificate getCertificate; + if (GetCertificateTxId(strTxHashToUse, getCertificate)) { + if ((certificate.txHashSigned != txHash) && (certificate.txHashRequest != txHash)) { //check request and approve in case + errorMessage = "CheckNewCertificateTxInputs: - The certificate " + txHash.ToString() + " already exists. Add new certificate failed!"; + return error(errorMessage.c_str()); + } else { + LogPrintf("%s -- Already have certificate %s in local database. Skipping add certificate step.\n", __func__, txHash.ToString()); + return true; + } + } + + //make sure serial number doesn't already exist. + if (certificate.SerialNumber != 0) { + CX509Certificate getCertificateSerial; + if (GetCertificateSerialNumber(std::to_string(certificate.SerialNumber), getCertificateSerial)) { + errorMessage = "CheckNewCertificateTxInputs: - The certificate serial number " + std::to_string(certificate.SerialNumber) + " already exists. Add new certificate failed!"; + return error(errorMessage.c_str()); + } + } + + if (!pCertificateDB) { + errorMessage = "CheckNewCertificateTxInputs failed! Can not open LevelDB BDAP certificate database."; + return error(errorMessage.c_str()); + } + + if (!pCertificateDB->AddCertificate(certificate)) { + errorMessage = "CheckNewCertificateTxInputs failed! Error adding new certificate record to LevelDB."; + pCertificateDB->EraseCertificateTxId(vchFromString(txHash.ToString())); + return error(errorMessage.c_str()); + } + + return FlushCertificateLevelDB(); +} + +bool CheckCertificateTx(const CTransactionRef& tx, const CScript& scriptOp, const int& op1, const int& op2, const std::vector >& vvchArgs, + const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage) +{ + if (tx->IsCoinBase() && !fJustCheck && !bSanityCheck) { + LogPrintf("*Trying to add BDAP certificate in coinbase transaction, skipping..."); + return true; + } + + LogPrint("bdap", "%s -- BDAP nHeight=%d, chainActive.Tip()=%d, op1=%s, op2=%s, hash=%s justcheck=%s\n", __func__, nHeight, chainActive.Tip()->nHeight, BDAPFromOp(op1).c_str(), BDAPFromOp(op2).c_str(), tx->GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); + + // unserialize BDAP from txn, check if the certificate is valid and does not conflict with a previous certificate + CX509Certificate certificate; + std::vector vchData; + std::vector vchHash; + int nDataOut; + bool bData = GetBDAPData(tx, vchData, vchHash, nDataOut); + if(bData && !certificate.UnserializeFromTx(tx, nHeight)) + { + errorMessage = ("UnserializeFromData data in tx failed!"); + LogPrintf("%s -- %s \n", __func__, errorMessage); + return error(errorMessage.c_str()); + } + const std::string strOperationType = GetBDAPOpTypeString(op1, op2); + CAmount monthlyFee, oneTimeFee, depositFee; + if (strOperationType == "bdap_new_certificate" || strOperationType == "bdap_approve_certificate") { + if (!certificate.ValidatePEM(errorMessage)) + return false; + + if (!certificate.ValidateValues(errorMessage)) + return false; + + if (vvchArgs.size() > 6) { + errorMessage = "Failed to get fees to add a certificate request"; + return false; + } + std::string strCount = stringFromVch(vvchArgs[1]); + uint32_t nCount; + ParseUInt32(stringFromVch(vvchArgs[1]), &nCount); + + if (strOperationType == "bdap_new_certificate") { //Request + if (!GetBDAPFees(OP_BDAP_NEW, OP_BDAP_CERTIFICATE, BDAP::ObjectType::BDAP_CERTIFICATE, (uint16_t)nCount, monthlyFee, oneTimeFee, depositFee)) { + errorMessage = "Failed to get fees to add a certificate request"; + return false; + } + } + else { //Approve + if (!GetBDAPFees(OP_BDAP_MODIFY, OP_BDAP_CERTIFICATE, BDAP::ObjectType::BDAP_CERTIFICATE, (uint16_t)nCount, monthlyFee, oneTimeFee, depositFee)) { + errorMessage = "Failed to get fees to add a certificate appoval"; + return false; + } + + } + + LogPrint("bdap", "%s -- nCount %d, oneTimeFee %d\n", __func__, nCount, FormatMoney(oneTimeFee)); + // extract amounts from tx. + CAmount dataAmount, opAmount; + if (!ExtractAmountsFromTx(tx, dataAmount, opAmount)) { + errorMessage = "Unable to extract BDAP amounts from transaction"; + return false; + } + LogPrint("bdap", "%s -- dataAmount %d, opAmount %d\n", __func__, FormatMoney(dataAmount), FormatMoney(opAmount)); + if (monthlyFee > dataAmount) { + LogPrintf("%s -- Invalid BDAP monthly registration fee amount for certificate. Monthly paid %d but should be %d\n", __func__, + FormatMoney(dataAmount), FormatMoney(monthlyFee)); + errorMessage = "Invalid BDAP monthly registration fee amount for certificate"; + return false; + } + else { + LogPrint("bdap", "%s -- Valid BDAP monthly registration fee amount for certificate. Monthly paid %d, should be %d.\n", __func__, + FormatMoney(dataAmount), FormatMoney(monthlyFee)); + } + if (depositFee > opAmount) { + LogPrintf("%s -- Invalid BDAP deposit fee amount for certificate. Deposit paid %d but should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + errorMessage = "Invalid BDAP deposit fee amount for certificate"; + return false; + } + else { + LogPrint("bdap", "%s -- Valid BDAP deposit fee amount for certificate. Deposit paid %d, should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + } + + return CheckNewCertificateTxInputs(certificate, scriptOp, vvchArgs, tx->GetHash(), strOperationType, errorMessage, fJustCheck); + } + + return false; + +} diff --git a/src/bdap/certificatedb.h b/src/bdap/certificatedb.h new file mode 100644 index 0000000000..82717e4ff4 --- /dev/null +++ b/src/bdap/certificatedb.h @@ -0,0 +1,44 @@ +// Copyright (c) 2020 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_CERTIFICATEDB_H +#define DYNAMIC_BDAP_CERTIFICATEDB_H + +#include "bdap/x509certificate.h" +#include "dbwrapper.h" +#include "sync.h" + +class CCoinsViewCache; +class UniValue; + +static CCriticalSection cs_bdap_certificate; + +class CCertificateDB : public CDBWrapper { +public: + CCertificateDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "blocks" / "bdap-certificates", nCacheSize, fMemory, fWipe, obfuscate) { + } + bool AddCertificate(const CX509Certificate& certificate); + bool ReadCertificateTxId(const std::vector& vchTxId, CX509Certificate& certificate); + bool ReadCertificateIssuerRootCA(const std::vector& vchIssuer, CX509Certificate& certificate); + bool ReadCertificateSerialNumber(const uint64_t& nSerialNumber, CX509Certificate& certificate); + + bool ReadCertificateSubjectDNRequest(const std::vector& vchSubject, std::vector& vCertificates, bool getAll = true); + bool ReadCertificateIssuerDNRequest(const std::vector& vchIssuer, std::vector& vCertificates, bool getAll = true); + bool ReadCertificateSubjectDNApprove(const std::vector& vchSubject, std::vector& vCertificates); + bool ReadCertificateIssuerDNApprove(const std::vector& vchSubject, std::vector& vCertificates); + + bool EraseCertificateTxId(const std::vector& vchTxId); +}; + +bool GetCertificateTxId(const std::string& strTxId, CX509Certificate& certificate); +bool GetCertificateSerialNumber(const std::string& strSerialNumber, CX509Certificate& certificate); +bool UndoAddCertificate(const CX509Certificate& certificate); +bool CheckCertificateDB(); +bool FlushCertificateLevelDB(); +bool CheckCertificateTx(const CTransactionRef& tx, const CScript& scriptOp, const int& op1, const int& op2, const std::vector >& vvchArgs, + const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage); + +extern CCertificateDB *pCertificateDB; + +#endif // DYNAMIC_BDAP_CERTIFICATEDB_H \ No newline at end of file diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp new file mode 100644 index 0000000000..9144bca590 --- /dev/null +++ b/src/bdap/domainentry.cpp @@ -0,0 +1,360 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/domainentry.h" + +#include "base58.h" +#include "bdap/utils.h" +#include "rpc/client.h" +#include "rpc/server.h" +#include "primitives/block.h" +#include "txmempool.h" +#include "serialize.h" +#include "streams.h" +#include "validation.h" +#include "wallet/wallet.h" + +#include + +#include +#include + +using namespace boost::xpressive; + +bool CDomainEntry::UnserializeFromTx(const CTransactionRef& tx) { + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetBDAPData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +void CDomainEntry::Serialize(std::vector& vchData) { + CDataStream dsBDAP(SER_NETWORK, PROTOCOL_VERSION); + dsBDAP << *this; + vchData = std::vector(dsBDAP.begin(), dsBDAP.end()); +} + +bool CDomainEntry::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) { + try { + CDataStream dsBDAP(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsBDAP >> *this; + + std::vector vchBDAPData; + Serialize(vchBDAPData); + const uint256 &calculatedHash = Hash(vchBDAPData.begin(), vchBDAPData.end()); + const std::vector &vchRandBDAP = vchFromValue(calculatedHash.GetHex()); + if(vchRandBDAP != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +CDynamicAddress CDomainEntry::GetWalletAddress() const { + return CDynamicAddress(stringFromVch(WalletAddress)); +} + +CDynamicAddress CDomainEntry::GetLinkAddress() const { + return CDynamicAddress(stringFromVch(LinkAddress)); +} + +std::string CDomainEntry::DHTPubKeyString() const { + return stringFromVch(DHTPublicKey); +} + +std::string CDomainEntry::GetFullObjectPath() const { + return stringFromVch(ObjectID) + "@" + stringFromVch(OrganizationalUnit) + "." + stringFromVch(DomainComponent); +} + +std::string CDomainEntry::GetObjectLocation() const { + return stringFromVch(OrganizationalUnit) + "." + stringFromVch(DomainComponent); +} + +std::vector CDomainEntry::vchFullObjectPath() const { + std::string strFullObjectPath = GetFullObjectPath(); + std::vector vchReturnValue(strFullObjectPath.begin(), strFullObjectPath.end()); + return vchReturnValue; +} + +std::vector CDomainEntry::vchObjectLocation() const { + std::string strObjectLocation = GetObjectLocation(); + std::vector vchReturnValue(strObjectLocation.begin(), strObjectLocation.end()); + return vchReturnValue; +} + +bool CDomainEntry::ValidateValues(std::string& errorMessage) +{ + smatch sMatch; + std::string regExWithDot = "^((?!-)[a-z0-9-]{2," + std::to_string(MAX_OBJECT_NAME_LENGTH) + "}(? MAX_COMMON_NAME_LENGTH) + { + errorMessage = "Invalid BDAP common name. Can not have more than " + std::to_string(MAX_COMMON_NAME_LENGTH) + " characters."; + return false; + } + + // check object organization name component + if (OrganizationName.size() > MAX_ORG_NAME_LENGTH) + { + errorMessage = "Invalid BDAP organization name. Can not have more than " + std::to_string(MAX_ORG_NAME_LENGTH) + " characters."; + return false; + } + + if (WalletAddress.size() > MAX_WALLET_ADDRESS_LENGTH) + { + errorMessage = "Invalid BDAP wallet address. Can not have more than " + std::to_string(MAX_WALLET_ADDRESS_LENGTH) + " characters."; + return false; + } + else { + std::string strWalletAddress = stringFromVch(WalletAddress); + CDynamicAddress entryAddress(strWalletAddress); + if (!entryAddress.IsValid()) { + errorMessage = "Invalid BDAP wallet address. Wallet address failed IsValid check."; + return false; + } + } + + if (LinkAddress.size() > MAX_WALLET_ADDRESS_LENGTH) + { + errorMessage = "Invalid BDAP link address. Can not have more than " + std::to_string(MAX_WALLET_ADDRESS_LENGTH) + " characters."; + return false; + } + else { + if (LinkAddress.size() > 0) { + std::string strLinkAddress = stringFromVch(LinkAddress); + CTxDestination destLink = DecodeDestination(strLinkAddress); + if (destLink.type() == typeid(CKeyID)) { + CDynamicAddress entryLinkAddress(strLinkAddress); + if (!entryLinkAddress.IsValid()) { + errorMessage = "Invalid BDAP public link address. Link wallet address failed IsValid check."; + return false; + } + } + else if (destLink.type() == typeid(CStealthAddress)) { + CStealthAddress sxAddr; + if (!sxAddr.SetEncoded(strLinkAddress)) { + errorMessage = "Invalid BDAP stealth link address. Link wallet address failed SetEncoded check."; + return false; + } + } + } + } + + if (DHTPublicKey.size() > MAX_KEY_LENGTH) + { + errorMessage = "Invalid BDAP encryption public key. Can not have more than " + std::to_string(MAX_KEY_LENGTH) + " characters."; + return false; + } + //TODO (BDAP): validate Ed25519 public key if possible. + /* + else { + if (DHTPublicKey.size() > 0) { + CPubKey entryDHTPublicKey(DHTPublicKey); + if (!entryDHTPublicKey.IsFullyValid()) { + errorMessage = "Invalid BDAP encryption public key. Encryption public key failed IsFullyValid check."; + return false; + } + } + } + */ + return true; +} + +/** Checks if BDAP transaction exists in the memory pool */ +bool CDomainEntry::CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& errorMessage) +{ + for (const CTxMemPoolEntry& e : pool.mapTx) { + const CTransactionRef& tx = e.GetSharedTx(); + for (const CTxOut& txOut : tx->vout) { + if (IsBDAPDataOutput(txOut)) { + CDomainEntry domainEntry(tx); + if (this->GetFullObjectPath() == domainEntry.GetFullObjectPath()) { + errorMessage = "CheckIfExistsInMemPool: A BDAP domain entry transaction for " + GetFullObjectPath() + " is already in the memory pool!"; + return true; + } + } + } + } + return false; +} + +/** Checks if the domain entry transaction uses the entry's UTXO */ +bool CDomainEntry::TxUsesPreviousUTXO(const CTransactionRef& tx) +{ + int nIn = GetBDAPOperationOutIndex(tx); + COutPoint entryOutpoint = COutPoint(txHash, nIn); + for (const CTxIn& txIn : tx->vin) { + if (txIn.prevout == entryOutpoint) + return true; + } + return false; +} + +/** Generate unique OID when using the root BDAP OID prefix */ +std::string CDomainEntry::GenerateOID() const +{ + std::string strOID; + if (RootOID == vchDefaultOIDPrefix) + { + // BDAP generated OID: 2.16.840.1.114564.block-height.tx-ordinal + std::string strTxOrdinal = "?"; + std::string strHeight = "?"; + if (nHeight > 0) + { + strHeight = std::to_string(nHeight); + } + if (!txHash.IsNull() && !IsInitialBlockDownload()) + { + CTransactionRef txRef; + uint256 hashBlock; + const Consensus::Params& consensusParams = Params().GetConsensus(); + if (GetTransaction(txHash, txRef, consensusParams, hashBlock, true)) + { + if (!hashBlock.IsNull()) + { + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hashBlock]; + if (pblockindex && ReadBlockFromDisk(block, pblockindex, consensusParams)) + { + int nTxOrdinal = 0; + for (const auto& tx : block.vtx) { + if (tx->GetHash() == txHash) + { + strTxOrdinal = std::to_string(nTxOrdinal); + break; + } + nTxOrdinal++; + } + } + } + } + } + strOID = strprintf("%s.%s.%s", stringFromVch(RootOID), strHeight, strTxOrdinal); + } + else + { + strOID = stringFromVch(RootOID); + } + return strOID; +} + +bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) +{ + bool expired = false; + int64_t expired_time = 0; + int64_t nTime = 0; + if (!fAbridged) { + oName.push_back(Pair("oid", entry.GenerateOID())); + oName.push_back(Pair("version", entry.nVersion)); + oName.push_back(Pair("domain_component", stringFromVch(entry.DomainComponent))); + oName.push_back(Pair("common_name", stringFromVch(entry.CommonName))); + oName.push_back(Pair("organizational_unit", stringFromVch(entry.OrganizationalUnit))); + oName.push_back(Pair("organization_name", stringFromVch(entry.DomainComponent))); + oName.push_back(Pair("object_id", stringFromVch(entry.ObjectID))); + oName.push_back(Pair("object_full_path", entry.GetFullObjectPath())); + oName.push_back(Pair("object_type", entry.ObjectTypeString())); + oName.push_back(Pair("wallet_address", stringFromVch(entry.WalletAddress))); + oName.push_back(Pair("public", (int)entry.fPublicObject)); + oName.push_back(Pair("dht_publickey", stringFromVch(entry.DHTPublicKey))); + oName.push_back(Pair("link_address", stringFromVch(entry.LinkAddress))); + oName.push_back(Pair("txid", entry.txHash.GetHex())); + if ((unsigned int)chainActive.Height() >= entry.nHeight) { + CBlockIndex *pindex = chainActive[entry.nHeight]; + if (pindex) { + nTime = pindex->GetBlockTime(); + } + } + oName.push_back(Pair("time", nTime)); + //oName.push_back(Pair("height", entry.nHeight)); + expired_time = entry.nExpireTime; + if(expired_time <= (unsigned int)chainActive.Tip()->GetBlockTime()) + { + expired = true; + } + oName.push_back(Pair("expires_on", expired_time)); + oName.push_back(Pair("expired", expired)); + } + else { + oName.push_back(Pair("common_name", stringFromVch(entry.CommonName))); + oName.push_back(Pair("object_full_path", stringFromVch(entry.vchFullObjectPath()))); + oName.push_back(Pair("wallet_address", stringFromVch(entry.WalletAddress))); + oName.push_back(Pair("dht_publickey", stringFromVch(entry.DHTPublicKey))); + oName.push_back(Pair("link_address", stringFromVch(entry.LinkAddress))); + oName.push_back(Pair("object_type", entry.ObjectTypeString())); + } + return true; +} \ No newline at end of file diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h new file mode 100644 index 0000000000..82d025a5ea --- /dev/null +++ b/src/bdap/domainentry.h @@ -0,0 +1,170 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_DOMAINENTRY_H +#define DYNAMIC_BDAP_DOMAINENTRY_H + +#include "bdap.h" +#include "bdap/utils.h" +#include "amount.h" +#include "consensus/params.h" +#include "primitives/transaction.h" +#include "script/script.h" +#include "serialize.h" +#include "sync.h" + +#include + +class CDynamicAddress; +struct CRecipient; +class CTxMemPool; + +/* Blockchain Directory Access Framework + + ***** Design Notes ***** +- BDAP root DNS entry is bdap.io. It hosts the root public and admin domains for the BDAP system. +- Modeling after X.500 Directory and LDAP (RFC 4512): https://docs.ldap.com/specs/rfc4512.txt +- Top level domain objects do not have an ObjectID and are considered controlers. +- OID canonical identifiers like 1.23.456.7.89 +- Sub level directory objects need permission from parent domain object. +- Top level domain objects can run side chains, sub level can with permission from parent +- Torrent network link used to store and transmit sharded and encrypted data. +- Side chains secured by Proof of Stake tokens issued by directory domain owner/creator +- Top level domains require collateral and more expensive than +- Recommended to store lower level domain object data as encrypted shards on Torrent network and not on the chain. +- The basic operations of DAP: Bind, Read, List, Search, Compare, Modify, Add, Delete and ModifyRDN +- Implement file sharing using IPFS +*/ + +using namespace BDAP; + +class CDomainEntryDefaultParameters { +public: + void InitialiseAdminOwners(); //DEFAULT_ADMIN_DOMAIN + void InitialisePublicDomain(); //DEFAULT_PUBLIC_DOMAIN +}; + +// See LDAP Distinguished Name +class CDomainEntry { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + CharString RootOID; // Canonical Object ID + //CN=John Smith,OU=Public,DC=BDAP,DC=IO, O=Duality Blockchain Solutions, UID=johnsmith21 + CharString DomainComponent; // DC. Like DC=bdap.io. required. controls child objects + CharString CommonName; // CN. Like CN=John Smith + CharString OrganizationalUnit; // OU. Like OU=sales. blank for top level domain directories + CharString OrganizationName; // O. Like Duality Blockchain Solutions + CharString ObjectID; // UID. Like johnsmith21. blank for top level domain directories + unsigned int nObjectType; // see enum above + CharString WalletAddress; // used to send collateral funds for this directory record. + int8_t fPublicObject; // public and private visibility is relative to other objects in its domain directory + CharString DHTPublicKey; // used to save data in the DHT and encrypt data for this entry. + CharString LinkAddress; // used to send link requests. should use a stealth address. + + uint256 txHash; + + unsigned int nHeight; + uint64_t nExpireTime; + + CDomainEntry() { + SetNull(); + } + + CDomainEntry(const CTransactionRef& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CDomainEntry::CURRENT_VERSION; + RootOID.clear(); + DomainComponent.clear(); + CommonName.clear(); + OrganizationalUnit.clear(); + OrganizationName.clear(); + ObjectID.clear(); + nObjectType = 0; + WalletAddress.clear(); + fPublicObject = 0; // by default set to private visibility. + DHTPublicKey.clear(); + LinkAddress.clear(); + txHash.SetNull(); + nHeight = 0; + nExpireTime = 0; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(RootOID); + READWRITE(DomainComponent); + READWRITE(CommonName); + READWRITE(OrganizationalUnit); + READWRITE(OrganizationName); + READWRITE(ObjectID); + READWRITE(VARINT(nObjectType)); + READWRITE(WalletAddress); + READWRITE(VARINT(fPublicObject)); + READWRITE(DHTPublicKey); + READWRITE(LinkAddress); + READWRITE(VARINT(nHeight)); + READWRITE(txHash); + READWRITE(VARINT(nExpireTime)); + } + + inline friend bool operator==(const CDomainEntry& a, const CDomainEntry& b) { + return (a.RootOID == b.RootOID && a.DomainComponent == b.DomainComponent && a.OrganizationalUnit == b.OrganizationalUnit && a.nObjectType == b.nObjectType); + } + + inline friend bool operator!=(const CDomainEntry& a, const CDomainEntry& b) { + return !(a == b); + } + + inline CDomainEntry operator=(const CDomainEntry& b) { + RootOID = b.RootOID; + DomainComponent = b.DomainComponent; + CommonName = b.CommonName; + OrganizationalUnit = b.OrganizationalUnit; + OrganizationName = b.OrganizationName; + ObjectID = b.ObjectID; + nObjectType = b.nObjectType; + WalletAddress = b.WalletAddress; + fPublicObject = b.fPublicObject; + DHTPublicKey = b.DHTPublicKey; + LinkAddress = b.LinkAddress; + txHash = b.txHash; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (DomainComponent.empty()); } + bool UnserializeFromTx(const CTransactionRef& tx); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + void Serialize(std::vector& vchData); + + CDynamicAddress GetWalletAddress() const; + CDynamicAddress GetLinkAddress() const; + std::string DHTPubKeyString() const; + std::string GetFullObjectPath() const; + std::string GetObjectLocation() const; + std::vector vchFullObjectPath() const; + std::vector vchObjectLocation() const; // OU . Domain Name + bool ValidateValues(std::string& errorMessage); + bool CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& errorMessage); + bool TxUsesPreviousUTXO(const CTransactionRef& tx); + BDAP::ObjectType ObjectType() const { return (BDAP::ObjectType)nObjectType; } + std::string ObjectTypeString() const { return BDAP::GetObjectTypeString(nObjectType); }; + std::string GenerateOID() const; + +}; + +bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged = false); + +#endif // DYNAMIC_BDAP_DOMAINENTRY_H \ No newline at end of file diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp new file mode 100644 index 0000000000..3ad1ba798c --- /dev/null +++ b/src/bdap/domainentrydb.cpp @@ -0,0 +1,767 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/domainentrydb.h" + +#include "amount.h" +#include "base58.h" +#include "bdap/fees.h" +#include "coins.h" +#include "bdap/utils.h" +#include "utilmoneystr.h" +#include "utiltime.h" +#include "validation.h" +#include "validationinterface.h" + +#include + +#include + + +CDomainEntryDB *pDomainEntryDB = NULL; + +bool GetDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry) +{ + if (!pDomainEntryDB || !pDomainEntryDB->ReadDomainEntry(vchObjectPath, entry)) + return false; + + return !entry.IsNull(); +} + +bool GetDomainEntryPubKey(const std::vector& vchPubKey, CDomainEntry& entry) +{ + if (!pDomainEntryDB || !pDomainEntryDB->ReadDomainEntryPubKey(vchPubKey, entry)) + return false; + + return !entry.IsNull(); +} + +bool AccountPubKeyExists(const std::vector& vchPubKey) +{ + CDomainEntry entry; + return GetDomainEntryPubKey(vchPubKey, entry); +} + +bool DomainEntryExists(const std::vector& vchObjectPath) +{ + if (!pDomainEntryDB) + return false; + + return pDomainEntryDB->DomainEntryExists(vchObjectPath); +} + +bool DeleteDomainEntry(const CDomainEntry& entry) +{ + if (!pDomainEntryDB) + return false; + + bool fEraseEntryResult = pDomainEntryDB->EraseDomainEntry(entry.vchFullObjectPath()); + bool fErasePubKeyResult = pDomainEntryDB->EraseDomainEntryPubKey(entry.DHTPublicKey); + return (fEraseEntryResult && fErasePubKeyResult); +} + +bool UndoAddDomainEntry(const CDomainEntry& entry) +{ + if (!pDomainEntryDB) + return false; + + bool fEraseEntryResult = pDomainEntryDB->EraseDomainEntry(entry.vchFullObjectPath()); + bool fErasePubKeyResult = pDomainEntryDB->EraseDomainEntryPubKey(entry.DHTPublicKey); + return (fEraseEntryResult && fErasePubKeyResult); +} + +bool UndoUpdateDomainEntry(const CDomainEntry& entry) +{ + if (!pDomainEntryDB) + return false; + // TODO (BDAP): Implement undo update domain entry used in DisconnectBlock to handle forks + return false; +} + +bool UndoDeleteDomainEntry(const CDomainEntry& entry) +{ + if (!pDomainEntryDB) + return false; + // TODO (BDAP): Implement undo delete domain entry used in DisconnectBlock to handle forks + return false; +} + +bool CDomainEntryDB::AddDomainEntry(const CDomainEntry& entry, const int op) +{ + bool writeState = false; + { + LOCK(cs_bdap_entry); + writeState = Write(make_pair(std::string("dc"), entry.vchFullObjectPath()), entry) + && Write(make_pair(std::string("pk"), entry.DHTPublicKey), entry); + } + if (writeState) + AddDomainEntryIndex(entry, op); + + return writeState; +} + +void CDomainEntryDB::AddDomainEntryIndex(const CDomainEntry& entry, const int op) +{ + UniValue oName(UniValue::VOBJ); + if (BuildBDAPJson(entry, oName)) { + CharString vchOperationType = vchFromString(BDAPFromOp(op)); + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), reinterpret_cast(vchOperationType.data())); + WriteDomainEntryIndexHistory(entry, op); + } +} + +bool CDomainEntryDB::ReadDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry) +{ + LOCK(cs_bdap_entry); + return CDBWrapper::Read(make_pair(std::string("dc"), vchObjectPath), entry); +} + +bool CDomainEntryDB::ReadDomainEntryPubKey(const std::vector& vchPubKey, CDomainEntry& entry) +{ + LOCK(cs_bdap_entry); + return CDBWrapper::Read(make_pair(std::string("pk"), vchPubKey), entry); +} + +bool CDomainEntryDB::EraseDomainEntry(const std::vector& vchObjectPath) +{ + LOCK(cs_bdap_entry); + CDomainEntry entry; + if (!ReadDomainEntry(vchObjectPath, entry)) { + LogPrintf("CDomainEntryDB::%s -- ReadDomainEntry failed. vchObjectPath = %s\n", __func__, stringFromVch(vchObjectPath)); + return false; + } + + return CDBWrapper::Erase(make_pair(std::string("dc"), vchObjectPath)); +} + +bool CDomainEntryDB::EraseDomainEntryPubKey(const std::vector& vchPubKey) +{ + LOCK(cs_bdap_entry); + CDomainEntry entry; + if (!ReadDomainEntryPubKey(vchPubKey, entry)) + return false; + + return CDBWrapper::Erase(make_pair(std::string("pk"), vchPubKey)); +} + +bool CDomainEntryDB::DomainEntryExists(const std::vector& vchObjectPath) +{ + LOCK(cs_bdap_entry); + return CDBWrapper::Exists(make_pair(std::string("dc"), vchObjectPath)); +} + +bool CDomainEntryDB::DomainEntryExistsPubKey(const std::vector& vchPubKey) +{ + LOCK(cs_bdap_entry); + return CDBWrapper::Exists(make_pair(std::string("pk"), vchPubKey)); +} + +bool CDomainEntryDB::RemoveExpired(int& entriesRemoved) +{ + boost::scoped_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + CDomainEntry entry; + std::pair > key; + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + try { + if (pcursor->GetKey(key) && key.first == "dc") { + pcursor->GetValue(entry); + if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) + { + entriesRemoved++; + EraseDomainEntry(key.second); + } + } + else if (pcursor->GetKey(key) && key.first == "txid") { + std::vector value; + CDomainEntry entry; + pcursor->GetValue(value); + if (GetDomainEntry(value, entry) && (unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) + { + entriesRemoved++; + EraseDomainEntryPubKey(entry.DHTPublicKey); + } + } + pcursor->Next(); + } catch (std::exception &e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + +void CDomainEntryDB::WriteDomainEntryIndexHistory(const CDomainEntry& entry, const int op) +{ + if (IsArgSet("-zmqpubbdaphistory")) { + UniValue oName(UniValue::VOBJ); + BuildBDAPJson(entry, oName); + oName.push_back(Pair("op", BDAPFromOp(op))); + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_history"); + } +} + +void CDomainEntryDB::WriteDomainEntryIndex(const CDomainEntry& entry, const int op) +{ + if (IsArgSet("-zmqpubbdaprecord")) { + UniValue oName(UniValue::VOBJ); + CDynamicAddress address(EncodeBase58(entry.WalletAddress)); + oName.push_back(Pair("address", address.ToString())); + oName.push_back(Pair("expires_on", entry.nExpireTime)); + oName.push_back(Pair("dht_publickey", HexStr(entry.DHTPublicKey))); + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_record"); + } + WriteDomainEntryIndexHistory(entry, op); +} + +bool CDomainEntryDB::UpdateDomainEntry(const std::vector& vchObjectPath, const CDomainEntry& entry) +{ + LOCK(cs_bdap_entry); + + if (!EraseDomainEntry(vchObjectPath)) { + LogPrintf("CDomainEntryDB::%s -- EraseDomainEntry failed. vchObjectPath = %s\n", __func__, stringFromVch(vchObjectPath)); + return false; + } + if (!EraseDomainEntryPubKey(entry.DHTPublicKey)) { + LogPrintf("CDomainEntryDB::%s -- EraseDomainEntryPubKey failed. vchObjectPath = %s\n", __func__, stringFromVch(entry.DHTPublicKey)); + return false; + } + + bool writeState = false; + writeState = Update(make_pair(std::string("dc"), entry.vchFullObjectPath()), entry) + && Update(make_pair(std::string("pk"), entry.DHTPublicKey), entry); + if (writeState) + AddDomainEntryIndex(entry, OP_BDAP_MODIFY); + + return writeState; +} + +// Removes expired records from databases. +bool CDomainEntryDB::CleanupLevelDB(int& nRemoved) +{ + boost::scoped_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + CDomainEntry dirEntry; + std::pair > key; + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + try { + if (pcursor->GetKey(key) && key.first == "dc") + { + pcursor->GetValue(dirEntry); + if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= dirEntry.nExpireTime) + { + nRemoved++; + EraseDomainEntry(key.second); + } + } + else if (pcursor->GetKey(key) && key.first == "pk") + { + pcursor->GetValue(dirEntry); + if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= dirEntry.nExpireTime) + { + nRemoved++; + EraseDomainEntryPubKey(dirEntry.DHTPublicKey); + } + } + pcursor->Next(); + } catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + +// Lists active entries by domain name with paging support +bool CDomainEntryDB::ListDirectories(const std::vector& vchObjectLocation, const unsigned int& nResultsPerPage, const unsigned int& nPage, UniValue& oDomainEntryList, const BDAP::ObjectType& accountType, const std::string searchString) +{ + // TODO: (bdap) implement paging + // if vchObjectLocation is empty, list entries from all domains + int index = 0; + bool addEntry = true; + std::pair key; + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CDomainEntry entry; + try { + if (pcursor->GetKey(key) && key.first == "dc") { + pcursor->GetValue(entry); + //filter by accountType, unless DEFAULT + if ((entry.nObjectType == GetObjectTypeInt(accountType)) || (accountType == DEFAULT_ACCOUNT_TYPE)) { + if (vchObjectLocation.empty() || entry.vchObjectLocation() == vchObjectLocation) + { + addEntry = true; //always reset to true + + if (searchString.size() > 0) { + //compare to ObjectID and Common Name + std::string compareString(entry.ObjectID.begin(), entry.ObjectID.end()); + std::string compareCommonString(entry.CommonName.begin(), entry.CommonName.end()); + std::size_t found = compareString.find(searchString); + std::size_t foundCommon = compareCommonString.find(searchString); + + if ((found==std::string::npos) && (foundCommon==std::string::npos)) + addEntry = false; + } + + if (addEntry) + { + UniValue oDomainEntryEntry(UniValue::VOBJ); + BuildBDAPJson(entry, oDomainEntryEntry, false); + oDomainEntryList.push_back(oDomainEntryEntry); + index++; + } + } + } //if entry.nObjectType + } + pcursor->Next(); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } //try-catch + + } + return true; +} + +bool CDomainEntryDB::GetDomainEntryInfo(const std::vector& vchFullObjectPath, UniValue& oDomainEntryInfo) +{ + CDomainEntry entry; + if (!ReadDomainEntry(vchFullObjectPath, entry)) { + return false; + } + + if (!BuildBDAPJson(entry, oDomainEntryInfo, false)) { + return false; + } + + return true; +} + +bool CDomainEntryDB::GetDomainEntryInfo(const std::vector& vchFullObjectPath, CDomainEntry& entry) +{ + if (!ReadDomainEntry(vchFullObjectPath, entry)) { + return false; + } + + return true; +} + +bool CheckDomainEntryDB() +{ + if (!pDomainEntryDB) + return false; + + return true; +} + +bool FlushLevelDB() +{ + { + LOCK(cs_bdap_entry); + if (pDomainEntryDB != NULL) + { + if (!pDomainEntryDB->Flush()) { + LogPrintf("Failed to write to BDAP database!"); + return false; + } + } + } + return true; +} + +void CleanupLevelDB(int& nRemoved) +{ + if(pDomainEntryDB != NULL) + pDomainEntryDB->CleanupLevelDB(nRemoved); + FlushLevelDB(); +} + +static bool CommonDataCheck(const CDomainEntry& entry, const vchCharString& vvchOpParameters, std::string& errorMessage) +{ + if (entry.IsNull() == true) + { + errorMessage = "CommonDataCheck failed! DomainEntry is null."; + return false; + } + + if (vvchOpParameters.size() == 0) + { + errorMessage = "CommonDataCheck failed! Invalid parameters."; + return false; + } + + if (vvchOpParameters.size() != 3) + { + errorMessage = "CommonDataCheck failed! Not enough parameters."; + return false; + } + + if (entry.GetFullObjectPath() != stringFromVch(vvchOpParameters[0])) + { + errorMessage = "CommonDataCheck failed! Script operation parameter does not match account entry object."; + return false; + } + + if (entry.DHTPublicKey != vvchOpParameters[1]) + { + errorMessage = "CommonDataCheck failed! DHT public key mismatch."; + return false; + } + + if (vvchOpParameters[2].size() > 10) + { + errorMessage = "CommonDataCheck failed! Expire date or expire months invalid."; + return false; + } + + if (entry.DomainComponent != vchDefaultDomainName) + { + errorMessage = "CommonDataCheck failed! Must use default domain."; + return false; + } + + if (entry.OrganizationalUnit == vchDefaultAdminOU) + { + errorMessage = "CommonDataCheck failed! Can not use default admin domain."; + return false; + } + + if (entry.OrganizationalUnit != vchDefaultPublicOU) + { + errorMessage = "CommonDataCheck failed! Must use default public organizational unit."; + return false; + } + + return true; +} + +static bool CheckNewDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash, + std::string& errorMessage, bool fJustCheck) +{ + if (!CommonDataCheck(entry, vvchOpParameters, errorMessage)) + return error(errorMessage.c_str()); + + if (fJustCheck) + return true; + + CDomainEntry getDomainEntry; + if (GetDomainEntry(entry.vchFullObjectPath(), getDomainEntry)) + { + if (entry.txHash != txHash) { + errorMessage = "CheckNewDomainEntryTxInputs: - The entry " + getDomainEntry.GetFullObjectPath() + " already exists. Add new entry failed!"; + return error(errorMessage.c_str()); + } + else { + LogPrintf("%s -- Already have entry %s in local database. Skipping add entry step.\n", __func__, entry.GetFullObjectPath()); + return true; + } + } + + if (!pDomainEntryDB) + { + errorMessage = "CheckNewDomainEntryTxInputs failed! Can not open LevelDB BDAP entry database."; + return error(errorMessage.c_str()); + } + int op = OP_BDAP_NEW; + if (!pDomainEntryDB->AddDomainEntry(entry, op)) + { + errorMessage = "CheckNewDomainEntryTxInputs failed! Error adding new account entry request to LevelDB."; + return error(errorMessage.c_str()); + } + + return FlushLevelDB(); +} + +static bool CheckDeleteDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, + std::string& errorMessage, bool fJustCheck) +{ + if (vvchOpParameters.size() == 0) { + errorMessage = "CheckDeleteDomainEntryTxInputs: - Invalid delete operation parameters. This delete operation failed!"; + return error(errorMessage.c_str()); + } + if (fJustCheck) + return true; + + std::vector vchFullObjectPath = vvchOpParameters[0]; + CDomainEntry prevDomainEntry; + if (!GetDomainEntry(vchFullObjectPath, prevDomainEntry)) + { + errorMessage = "CheckDeleteDomainEntryTxInputs: - Can not find " + prevDomainEntry.GetFullObjectPath() + " entry; this delete operation failed!"; + return error(errorMessage.c_str()); + } + + CTxDestination bdapDest; + if (!ExtractDestination(scriptOp, bdapDest)) + { + errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("Cannot extract destination of BDAP input; this delete operation failed!"); + return error(errorMessage.c_str()); + } + else + { + CTransactionRef prevTx = MakeTransactionRef(); + uint256 hashBlock; + if (!GetTransaction(prevDomainEntry.txHash, prevTx, Params().GetConsensus(), hashBlock, true)) { + errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("Cannot extract previous transaction from BDAP output; this delete operation failed!"); + return error(errorMessage.c_str()); + } + // Get current wallet address used for BDAP tx + CDynamicAddress txAddress = GetScriptAddress(scriptOp); + // Get previous wallet address used for BDAP tx + CScript prevScriptPubKey; + GetBDAPOpScript(prevTx, prevScriptPubKey); + CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); + if (txAddress.ToString() != prevAddress.ToString()) + { + //check if previous wallet address is used for update and delete txs + errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("Delete must use the previous wallet address; this delete operation failed!"); + return error(errorMessage.c_str()); + } + } + + //Remove PubKey entry also (2 records in LevelDB for each domainentry) + pDomainEntryDB->EraseDomainEntryPubKey(prevDomainEntry.DHTPublicKey); + + if (!pDomainEntryDB->EraseDomainEntry(vchFullObjectPath)) + { + errorMessage = "CheckDeleteDomainEntryTxInputs: - Error deleting account entry in LevelDB; this delete operation failed!"; + return error(errorMessage.c_str()); + } + + return FlushLevelDB(); +} + +static bool CheckUpdateDomainEntryTxInputs(CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash, const int& nMonths, const uint32_t& nBlockTime, + std::string& errorMessage, bool fJustCheck) +{ + //if exists, check for owner's signature + if (!CommonDataCheck(entry, vvchOpParameters, errorMessage)) + return error(errorMessage.c_str()); + + if (fJustCheck) + return true; + + CDomainEntry prevDomainEntry; + if (!GetDomainEntry(entry.vchFullObjectPath(), prevDomainEntry)) + { + if (entry.txHash != txHash) { + errorMessage = "CheckUpdateDomainEntryTxInputs: - Can not find " + prevDomainEntry.GetFullObjectPath() + " entry; this update operation failed!"; + return error(errorMessage.c_str()); + } + else { + LogPrintf("%s -- Already have entry %s in local database. Skipping update entry step.\n", __func__, entry.GetFullObjectPath()); + return true; + } + } + + CTxDestination bdapDest; + if (!ExtractDestination(scriptOp, bdapDest)) + { + errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("Cannot extract destination of BDAP input; this update operation failed!"); + return error(errorMessage.c_str()); + } + else + { + CTransactionRef prevTx = MakeTransactionRef(); + uint256 hashBlock; + if (!GetTransaction(prevDomainEntry.txHash, prevTx, Params().GetConsensus(), hashBlock, true)) { + errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("Cannot extract previous transaction from BDAP output; this update operation failed!"); + return error(errorMessage.c_str()); + } + // Get current wallet address used for BDAP tx + CDynamicAddress txAddress = GetScriptAddress(scriptOp); + // Get previous wallet address used for BDAP tx + CScript prevScriptPubKey; + GetBDAPOpScript(prevTx, prevScriptPubKey); + CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); + if (txAddress.ToString() != prevAddress.ToString()) + { + //check if previous wallet address is used for update and delete txs + errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("Update must use the previous wallet address; this update operation failed!"); + return error(errorMessage.c_str()); + } + } + entry.nExpireTime = AddMonthsToBlockTime(prevDomainEntry.nExpireTime, nMonths); + LogPrint("bdap", "%s -- prevDomainEntry.nExpireTime = %d, AddMonthsToBlockTime() = %d, nMonths = %d\n", __func__, + prevDomainEntry.nExpireTime, AddMonthsToBlockTime(prevDomainEntry.nExpireTime, nMonths), nMonths); + if (!pDomainEntryDB->UpdateDomainEntry(entry.vchFullObjectPath(), entry)) + { + errorMessage = "CheckUpdateDomainEntryTxInputs: - Error updating entry in LevelDB; this update operation failed!"; + return error(errorMessage.c_str()); + } + + return FlushLevelDB(); +} + +static bool CheckMoveDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, + std::string& errorMessage, bool fJustCheck) +{ + //check name in operation matches entry data in leveldb + //check if exists already + //if exists, check for owner's signature + return false; +} + +bool CheckDomainEntryTx(const CTransactionRef& tx, const CScript& scriptOp, const int& op1, const int& op2, const std::vector >& vvchArgs, + const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage) +{ + if (tx->IsCoinBase() && !fJustCheck && !bSanityCheck) + { + LogPrintf("*Trying to add BDAP entry in coinbase transaction, skipping..."); + return true; + } + + LogPrint("bdap", "%s -- BDAP nHeight=%d, chainActive.Tip()=%d, op1=%s, op2=%s, hash=%s justcheck=%s\n", __func__, nHeight, chainActive.Tip()->nHeight, BDAPFromOp(op1).c_str(), BDAPFromOp(op2).c_str(), tx->GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); + + // unserialize BDAP from txn, check if the entry is valid and does not conflict with a previous entry + CDomainEntry entry; + std::vector vchData; + std::vector vchHash; + int nDataOut; + const std::string strOperationType = GetBDAPOpTypeString(op1, op2); + if (strOperationType != "bdap_delete_account") { + bool bData = GetBDAPData(tx, vchData, vchHash, nDataOut); + if(bData && !entry.UnserializeFromData(vchData, vchHash)) + { + errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3601 - " + _("UnserializeFromData data in tx failed!"); + LogPrintf("%s -- %s \n", __func__, errorMessage); + return error(errorMessage.c_str()); + } + + if(!entry.ValidateValues(errorMessage)) + { + errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3602 - " + errorMessage; + LogPrintf("%s -- %s \n", __func__, errorMessage); + return error(errorMessage.c_str()); + } + + entry.txHash = tx->GetHash(); + entry.nHeight = nHeight; + } + + CAmount monthlyFee, oneTimeFee, depositFee; + if (strOperationType == "bdap_new_account") { + if (vvchArgs.size() != 3) { + errorMessage = "Failed to get fees to add a new BDAP account"; + return false; + } + std::string strMonths = stringFromVch(vvchArgs[2]); + std::size_t foundMonth = strMonths.find("Month"); + if (foundMonth != std::string::npos) + strMonths.replace(foundMonth, 5, ""); + + uint32_t nMonths; + ParseUInt32(strMonths, &nMonths); + if (nMonths > MAX_REGISTRATION_MONTHS) + nMonths = MAX_REGISTRATION_MONTHS; + + if (!GetBDAPFees(OP_BDAP_NEW, OP_BDAP_ACCOUNT_ENTRY, entry.ObjectType(), (uint16_t)nMonths, monthlyFee, oneTimeFee, depositFee)) { + errorMessage = "Failed to get fees to add a new BDAP account"; + return false; + } + LogPrint("bdap", "%s -- nMonths %d, monthlyFee %d, oneTimeFee %d, depositFee %d\n", __func__, + nMonths, FormatMoney(monthlyFee), FormatMoney(oneTimeFee), FormatMoney(depositFee)); + // extract amounts from tx. + CAmount dataAmount, opAmount; + if (!ExtractAmountsFromTx(tx, dataAmount, opAmount)) { + errorMessage = "Unable to extract BDAP amounts from transaction"; + return false; + } + LogPrint("bdap", "%s -- dataAmount %d, opAmount %d\n", __func__, FormatMoney(dataAmount), FormatMoney(opAmount)); + if (monthlyFee > dataAmount) { + LogPrintf("%s -- Invalid BDAP monthly registration fee amount for new BDAP account. Monthly paid %d but should be %d\n", __func__, + FormatMoney(dataAmount), FormatMoney(monthlyFee)); + errorMessage = "Invalid BDAP monthly registration fee amount for new BDAP account"; + return false; + } + else { + LogPrint("bdap", "%s -- Valid BDAP monthly registration fee amount for new BDAP account. Monthly paid %d, should be %d.\n", __func__, + FormatMoney(dataAmount), FormatMoney(monthlyFee)); + } + if (depositFee > opAmount) { + LogPrintf("%s -- Invalid BDAP deposit fee amount for new BDAP account. Deposit paid %d but should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + errorMessage = "Invalid BDAP deposit fee amount for new BDAP account"; + return false; + } + else { + LogPrint("bdap", "%s -- Valid BDAP deposit fee amount for new BDAP account. Deposit paid %d, should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + } + entry.nExpireTime = AddMonthsToBlockTime(nBlockTime, nMonths); + + return CheckNewDomainEntryTxInputs(entry, scriptOp, vvchArgs, tx->GetHash(), errorMessage, fJustCheck); + } + else if (strOperationType == "bdap_delete_account") { + uint16_t nMonths = 0; + if (!GetBDAPFees(OP_BDAP_DELETE, OP_BDAP_ACCOUNT_ENTRY, entry.ObjectType(), nMonths, monthlyFee, oneTimeFee, depositFee)) { + errorMessage = "Failed to get fees to delete a BDAP account"; + return false; + } + + return CheckDeleteDomainEntryTxInputs(entry, scriptOp, vvchArgs, errorMessage, fJustCheck); + } + else if (strOperationType == "bdap_update_account") { + if (vvchArgs.size() != 3) { + errorMessage = "Failed to get fees to add a new BDAP account"; + return false; + } + std::string strMonths = stringFromVch(vvchArgs[2]); + std::size_t foundMonth = strMonths.find("Month"); + if (foundMonth != std::string::npos) + strMonths.replace(foundMonth, 5, ""); + + uint32_t nMonths; + ParseUInt32(strMonths, &nMonths); + if (nMonths > MAX_REGISTRATION_MONTHS) + nMonths = MAX_REGISTRATION_MONTHS; + + if (!GetBDAPFees(OP_BDAP_MODIFY, OP_BDAP_ACCOUNT_ENTRY, entry.ObjectType(), (uint16_t)nMonths, monthlyFee, oneTimeFee, depositFee)) { + errorMessage = "Failed to get fees to add a new BDAP account"; + return false; + } + + LogPrint("bdap", "%s -- nMonths %d, monthlyFee %d, oneTimeFee %d, depositFee %d\n", __func__, + nMonths, FormatMoney(monthlyFee), FormatMoney(oneTimeFee), FormatMoney(depositFee)); + // extract amounts from tx. + CAmount dataAmount, opAmount; + if (!ExtractAmountsFromTx(tx, dataAmount, opAmount)) { + errorMessage = "Unable to extract BDAP amounts from transaction"; + return false; + } + LogPrint("bdap", "%s -- dataAmount %d, opAmount %d\n", __func__, FormatMoney(dataAmount), FormatMoney(opAmount)); + if (monthlyFee > dataAmount) { + LogPrintf("%s -- Invalid BDAP data fee amount for updated BDAP account. Total paid %d but should be %d\n", __func__, + dataAmount, monthlyFee); + errorMessage = "Invalid BDAP deposit fee amount for updated BDAP account"; + return false; + } else { + LogPrint("bdap", "%s -- Valid BDAP data fee amount for updated BDAP account. Total paid %d, should be %d\n", __func__, + FormatMoney(dataAmount), FormatMoney(monthlyFee)); + } + if (oneTimeFee > opAmount) { + LogPrintf("%s -- Invalid BDAP one-time fee amount for updated BDAP account. Total paid %d but should be %d\n", __func__, + FormatMoney(dataAmount), FormatMoney(monthlyFee)); + errorMessage = "Invalid BDAP one-time fee amount for updated BDAP account"; + return false; + } else { + LogPrint("bdap", "%s -- Valid BDAP one-time fee amount for updated BDAP account. Total paid %d, should be %d\n", __func__, + FormatMoney(dataAmount), FormatMoney(monthlyFee)); + } + // Add previous expire date plus additional months + return CheckUpdateDomainEntryTxInputs(entry, scriptOp, vvchArgs, tx->GetHash(), nMonths, nBlockTime, errorMessage, fJustCheck); + } + else if (strOperationType == "bdap_move_account") { + uint16_t nMonths = 0; + if (!GetBDAPFees(OP_BDAP_MOVE, OP_BDAP_ACCOUNT_ENTRY, entry.ObjectType(), nMonths, monthlyFee, oneTimeFee, depositFee)) { + errorMessage = "Failed to get fees to move a BDAP account to another domain"; + return false; + } + + return CheckMoveDomainEntryTxInputs(entry, scriptOp, vvchArgs, errorMessage, fJustCheck); + } + + return false; +} diff --git a/src/bdap/domainentrydb.h b/src/bdap/domainentrydb.h new file mode 100644 index 0000000000..1e68ac00c1 --- /dev/null +++ b/src/bdap/domainentrydb.h @@ -0,0 +1,58 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_DOMAINENTRYDB_H +#define DYNAMIC_BDAP_DOMAINENTRYDB_H + +#include "bdap/domainentry.h" +#include "dbwrapper.h" +#include "sync.h" + +class CCoinsViewCache; + +static CCriticalSection cs_bdap_entry; + +const BDAP::ObjectType DEFAULT_ACCOUNT_TYPE = BDAP::ObjectType::BDAP_DEFAULT_TYPE; + +class CDomainEntryDB : public CDBWrapper { +public: + CDomainEntryDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "blocks" / "bdap-entries", nCacheSize, fMemory, fWipe, obfuscate) { + } + + // Add, Read, Modify, ModifyRDN, Delete, List, Search, Bind, and Compare + bool AddDomainEntry(const CDomainEntry& entry, const int op); + void AddDomainEntryIndex(const CDomainEntry& entry, const int op); + bool ReadDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry); + bool ReadDomainEntryPubKey(const std::vector& vchPubKey, CDomainEntry& entry); + bool EraseDomainEntry(const std::vector& vchObjectPath); + bool EraseDomainEntryPubKey(const std::vector& vchPubKey); + bool DomainEntryExists(const std::vector& vchObjectPath); + bool DomainEntryExistsPubKey(const std::vector& vchPubKey); + bool RemoveExpired(int& entriesRemoved); + void WriteDomainEntryIndex(const CDomainEntry& entry, const int op); + void WriteDomainEntryIndexHistory(const CDomainEntry& entry, const int op); + bool UpdateDomainEntry(const std::vector& vchObjectPath, const CDomainEntry& entry); + bool CleanupLevelDB(int& nRemoved); + bool ListDirectories(const std::vector& vchObjectLocation, const unsigned int& nResultsPerPage, const unsigned int& nPage, UniValue& oDomainEntryList, const BDAP::ObjectType& accountType = DEFAULT_ACCOUNT_TYPE, const std::string searchString = ""); + bool GetDomainEntryInfo(const std::vector& vchFullObjectPath, UniValue& oDomainEntryInfo); + bool GetDomainEntryInfo(const std::vector& vchFullObjectPath, CDomainEntry& entry); +}; + +bool GetDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry); +bool GetDomainEntryPubKey(const std::vector& vchPubKey, CDomainEntry& entry); +bool AccountPubKeyExists(const std::vector& vchPubKey); +bool DomainEntryExists(const std::vector& vchObjectPath); +bool DeleteDomainEntry(const CDomainEntry& entry); +bool UndoAddDomainEntry(const CDomainEntry& entry); +bool UndoUpdateDomainEntry(const CDomainEntry& entry); +bool UndoDeleteDomainEntry(const CDomainEntry& entry); +bool CheckDomainEntryDB(); +bool FlushLevelDB(); +void CleanupLevelDB(int& nRemoved); +bool CheckDomainEntryTx(const CTransactionRef& tx, const CScript& scriptOp, const int& op1, const int& op2, const std::vector >& vvchArgs, + const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage); + +extern CDomainEntryDB *pDomainEntryDB; + +#endif // DYNAMIC_BDAP_DOMAINENTRYDB_H \ No newline at end of file diff --git a/src/bdap/entrycheckpoints.cpp b/src/bdap/entrycheckpoints.cpp new file mode 100644 index 0000000000..e89dc8a608 --- /dev/null +++ b/src/bdap/entrycheckpoints.cpp @@ -0,0 +1,94 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/entrycheckpoints.h" + +#include "bdap/utils.h" +#include "hash.h" +#include "script/script.h" +#include "streams.h" + +void CEntryCheckpoints::Serialize(std::vector& vchData) +{ + CDataStream dsEntryCheckpoints(SER_NETWORK, PROTOCOL_VERSION); + dsEntryCheckpoints << *this; + vchData = std::vector(dsEntryCheckpoints.begin(), dsEntryCheckpoints.end()); +} + +bool CEntryCheckpoints::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsEntryCheckpoints(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsEntryCheckpoints >> *this; + + std::vector vchEntryLinkData; + Serialize(vchEntryLinkData); + const uint256 &calculatedHash = Hash(vchEntryLinkData.begin(), vchEntryLinkData.end()); + const std::vector &vchRandEntryLink = vchFromValue(calculatedHash.GetHex()); + if(vchRandEntryLink != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CEntryCheckpoints::UnserializeFromTx(const CTransactionRef& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetBDAPData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +bool CEntryCheckpoints::ValidateValues(std::string& errorMessage) +{ + // check certificate owner path + std::string strOwnerFullPath = stringFromVch(OwnerFullPath); + if (strOwnerFullPath.length() > MAX_OBJECT_FULL_PATH_LENGTH) // object + { + errorMessage = "Invalid BDAP owner full path name. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + + // check max checkpoints per transaction + if (CheckPointHashes.size() > MAX_NUMBER_CHECKPOINTS) + { + errorMessage = "Invalid number of BDAP checkpoints. Can not have more than " + std::to_string(MAX_NUMBER_CHECKPOINTS) + " checkpoints per transaction."; + return false; + } + + // check length of checkpoint hashes + for (unsigned int i = 0; i < CheckPointHashes.size(); i++) { + std::string strCheckpointHash = stringFromVch(CheckPointHashes[i].second); + if (strCheckpointHash.length() > MAX_CHECKPOINT_HASH_LENGTH) // object + { + errorMessage = "Invalid BDAP checkpoint hash length. Can not have more than " + std::to_string(MAX_CHECKPOINT_HASH_LENGTH) + " characters."; + return false; + } + } + + return true; +} + +void CEntryCheckpoints::AddCheckpoint(const uint32_t& height, const CharString& vchHash) +{ + CheckPoint pairNewCheckpoint; + pairNewCheckpoint.first = height; + pairNewCheckpoint.second = vchHash; + CheckPointHashes.push_back(pairNewCheckpoint); +} \ No newline at end of file diff --git a/src/bdap/entrycheckpoints.h b/src/bdap/entrycheckpoints.h new file mode 100644 index 0000000000..6c4b3c0c78 --- /dev/null +++ b/src/bdap/entrycheckpoints.h @@ -0,0 +1,84 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_ENTRYCHECKPOINT_H +#define DYNAMIC_BDAP_ENTRYCHECKPOINT_H + +#include "bdap.h" +#include "bdap/domainentry.h" +#include "serialize.h" +#include "uint256.h" + +class CTransaction; + +class CEntryCheckpoints { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + CharString OwnerFullPath; // name of the owner's full domain entry path + vCheckPoints CheckPointHashes; // vector of checkpoints containing the entry's channel or sub-chain block height and hash + unsigned int nHeight; + //uint64_t nExpireTime; // not sure if needed. checkpoint will expire when owner channel expires + uint256 txHash; + CDomainEntry* OwnerDomainEntry; + + CEntryCheckpoints() { + SetNull(); + } + + CEntryCheckpoints(const CTransactionRef& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CEntryCheckpoints::CURRENT_VERSION; + OwnerFullPath.clear(); + CheckPointHashes.clear(); + nHeight = 0; + txHash.SetNull(); + OwnerDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(OwnerFullPath); + READWRITE(CheckPointHashes); + READWRITE(VARINT(nHeight)); + READWRITE(txHash); + } + + inline friend bool operator==(const CEntryCheckpoints& a, const CEntryCheckpoints& b) { + return (a.OwnerFullPath == b.OwnerFullPath && a.CheckPointHashes == b.CheckPointHashes && a.nHeight == b.nHeight); + } + + inline friend bool operator!=(const CEntryCheckpoints& a, const CEntryCheckpoints& b) { + return !(a == b); + } + + inline CEntryCheckpoints operator=(const CEntryCheckpoints& b) { + OwnerFullPath = b.OwnerFullPath; + + for (unsigned int i = 0; i < b.CheckPointHashes.size(); i++) + CheckPointHashes.push_back(b.CheckPointHashes[i]); + + nHeight = b.nHeight; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (OwnerFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransactionRef& tx); + + bool ValidateValues(std::string& errorMessage); + void AddCheckpoint(const uint32_t& height, const CharString& vchHash); +}; + +#endif // DYNAMIC_BDAP_ENTRYCHECKPOINT_H \ No newline at end of file diff --git a/src/bdap/fees.cpp b/src/bdap/fees.cpp new file mode 100644 index 0000000000..776f1ef7af --- /dev/null +++ b/src/bdap/fees.cpp @@ -0,0 +1,197 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/fees.h" + +#include "bdap/bdap.h" // for SECONDS_PER_DAY +#include "bdap/utils.h" // for GetObjectTypeString +#include "util.h" // for LogPrintf + +#include +#include + +// Default BDAP Monthly Fees +std::map mapDefaultMonthlyFees = { + {BDAP_MONTHY_USER_FEE, CFeeItem(BDAP_MONTHY_USER_FEE, 15 * BDAP_CREDIT, 0, std::numeric_limits::max())}, + {BDAP_MONTHY_GROUP_FEE, CFeeItem(BDAP_MONTHY_GROUP_FEE, 60 * BDAP_CREDIT, 0, std::numeric_limits::max())}, + {BDAP_MONTHY_CERTIFICATE_FEE, CFeeItem(BDAP_MONTHY_CERTIFICATE_FEE, 30 * BDAP_CREDIT, 0, std::numeric_limits::max())}, + {BDAP_MONTHY_SIDECHAIN_FEE, CFeeItem(BDAP_MONTHY_SIDECHAIN_FEE, 300 * BDAP_CREDIT, 0, std::numeric_limits::max())}, +}; + +// Default BDAP One Time Fees +std::multimap mapOneTimeFees = { + {BDAP_ONE_TIME_REQUEST_LINK_FEE, CFeeItem(BDAP_ONE_TIME_REQUEST_LINK_FEE, 30 * BDAP_CREDIT, 0, std::numeric_limits::max())}, + {BDAP_ONE_TIME_ACCEPT_LINK_FEE, CFeeItem(BDAP_ONE_TIME_ACCEPT_LINK_FEE, 30 * BDAP_CREDIT, 0, std::numeric_limits::max())}, + {BDAP_ONE_TIME_AUDIT_RECORD_FEE, CFeeItem(BDAP_ONE_TIME_AUDIT_RECORD_FEE, 30 * BDAP_CREDIT, 0, std::numeric_limits::max())}, +}; + +// Default BDAP Non-Refundable Security Deposit Fees +std::map mapNoRefundDeposits = { + {BDAP_NON_REFUNDABLE_USER_DEPOSIT, CFeeItem(BDAP_NON_REFUNDABLE_USER_DEPOSIT, 300 * BDAP_CREDIT, 0, std::numeric_limits::max())}, + {BDAP_NON_REFUNDABLE_GROUP_DEPOSIT, CFeeItem(BDAP_NON_REFUNDABLE_GROUP_DEPOSIT, 3000 * BDAP_CREDIT, 0, std::numeric_limits::max())}, + {BDAP_NON_REFUNDABLE_CERTIFICATE_DEPOSIT, CFeeItem(BDAP_NON_REFUNDABLE_CERTIFICATE_DEPOSIT, 1500 * BDAP_CREDIT, 0, std::numeric_limits::max())}, + {BDAP_NON_REFUNDABLE_SIDECHAIN_DEPOSIT, CFeeItem(BDAP_NON_REFUNDABLE_SIDECHAIN_DEPOSIT, 7500 * BDAP_CREDIT, 0, std::numeric_limits::max())}, +}; + +bool GetBDAPFees(const opcodetype& opCodeAction, const opcodetype& opCodeObject, const BDAP::ObjectType objType, const uint16_t nQuantity, CAmount& monthlyFee, CAmount& oneTimeFee, CAmount& depositFee) +{ + std::string strObjectType = BDAP::GetObjectTypeString((unsigned int)objType); + LogPrint("bdap", "%s -- strObjectType = %s, OpAction %d, OpObject %d\n", __func__, strObjectType, opCodeAction, opCodeObject); + if (opCodeAction == OP_BDAP_NEW && opCodeObject == OP_BDAP_ACCOUNT_ENTRY && objType == BDAP::ObjectType::BDAP_USER) { + // Fees for a new BDAP user account + oneTimeFee = 0; + CFeeItem feeMonthly; + std::multimap::iterator iMonthly = mapDefaultMonthlyFees.find(BDAP_MONTHY_USER_FEE); + if (iMonthly != mapDefaultMonthlyFees.end()) { + feeMonthly = iMonthly->second; + monthlyFee = (nQuantity * feeMonthly.Fee); + } + CFeeItem feeDeposit; + std::multimap::iterator iDeposit = mapNoRefundDeposits.find(BDAP_NON_REFUNDABLE_USER_DEPOSIT); + if (iDeposit != mapNoRefundDeposits.end()) { + feeDeposit = iDeposit->second; + depositFee = feeDeposit.Fee; + } + + } else if (opCodeAction == OP_BDAP_NEW && opCodeObject == OP_BDAP_ACCOUNT_ENTRY && objType == BDAP::ObjectType::BDAP_GROUP) { + // Fees for a new BDAP group account + oneTimeFee = 0; + CFeeItem feeMonthly; + std::multimap::iterator iMonthly = mapDefaultMonthlyFees.find(BDAP_MONTHY_GROUP_FEE); + if (iMonthly != mapDefaultMonthlyFees.end()) { + feeMonthly = iMonthly->second; + monthlyFee = (nQuantity * feeMonthly.Fee); + } + CFeeItem feeDeposit; + std::multimap::iterator iDeposit = mapNoRefundDeposits.find(BDAP_NON_REFUNDABLE_GROUP_DEPOSIT); + if (iDeposit != mapNoRefundDeposits.end()) { + feeDeposit = iDeposit->second; + depositFee = feeDeposit.Fee; + } + + } else if ((opCodeAction == OP_BDAP_NEW || opCodeAction == OP_BDAP_MODIFY) && opCodeObject == OP_BDAP_CERTIFICATE && objType == BDAP::ObjectType::BDAP_CERTIFICATE) { + // Fees for a new BDAP certificate + oneTimeFee = 0; + CFeeItem feeMonthly; + std::multimap::iterator iMonthly = mapDefaultMonthlyFees.find(BDAP_MONTHY_CERTIFICATE_FEE); + if (iMonthly != mapDefaultMonthlyFees.end()) { + feeMonthly = iMonthly->second; + monthlyFee = (nQuantity * feeMonthly.Fee); + } + CFeeItem feeDeposit; + std::multimap::iterator iDeposit = mapNoRefundDeposits.find(BDAP_NON_REFUNDABLE_CERTIFICATE_DEPOSIT); + if (iDeposit != mapNoRefundDeposits.end()) { + feeDeposit = iDeposit->second; + depositFee = feeDeposit.Fee; + } + + } else if (opCodeAction == OP_BDAP_NEW && opCodeObject == OP_BDAP_SIDECHAIN && objType == BDAP::ObjectType::BDAP_SIDECHAIN) { + // Fees for a new BDAP sidechain entry + oneTimeFee = 0; + CFeeItem feeMonthly; + std::multimap::iterator iMonthly = mapDefaultMonthlyFees.find(BDAP_MONTHY_SIDECHAIN_FEE); + if (iMonthly != mapDefaultMonthlyFees.end()) { + feeMonthly = iMonthly->second; + monthlyFee = (nQuantity * feeMonthly.Fee); + } + CFeeItem feeDeposit; + std::multimap::iterator iDeposit = mapNoRefundDeposits.find(BDAP_NON_REFUNDABLE_SIDECHAIN_DEPOSIT); + if (iDeposit != mapNoRefundDeposits.end()) { + feeDeposit = iDeposit->second; + depositFee = feeDeposit.Fee; + } + + } else if (opCodeAction == OP_BDAP_NEW && opCodeObject == OP_BDAP_LINK_REQUEST && objType == BDAP::ObjectType::BDAP_LINK_REQUEST) { + // Fees for a new BDAP link request + CFeeItem feeOneTime; + std::multimap::iterator iOneTime = mapOneTimeFees.find(BDAP_ONE_TIME_REQUEST_LINK_FEE); + if (iOneTime != mapOneTimeFees.end()) { + feeOneTime = iOneTime->second; + oneTimeFee = feeOneTime.Fee; + } + monthlyFee = 0; + depositFee = BDAP_CREDIT; + + } else if (opCodeAction == OP_BDAP_NEW && opCodeObject == OP_BDAP_LINK_ACCEPT && objType == BDAP::ObjectType::BDAP_LINK_ACCEPT) { + // Fees for a new BDAP link accept + CFeeItem feeOneTime; + std::multimap::iterator iOneTime = mapOneTimeFees.find(BDAP_ONE_TIME_ACCEPT_LINK_FEE); + if (iOneTime != mapOneTimeFees.end()) { + feeOneTime = iOneTime->second; + oneTimeFee = feeOneTime.Fee; + } + monthlyFee = 0; + depositFee = BDAP_CREDIT; + + } else if (opCodeAction == OP_BDAP_NEW && opCodeObject == OP_BDAP_AUDIT && objType == BDAP::ObjectType::BDAP_AUDIT) { + // Fees for a new BDAP audit record + CFeeItem feeOneTime; + std::multimap::iterator iOneTime = mapOneTimeFees.find(BDAP_ONE_TIME_AUDIT_RECORD_FEE); + if (iOneTime != mapOneTimeFees.end()) { + feeOneTime = iOneTime->second; + oneTimeFee = feeOneTime.Fee; + } + monthlyFee = 0; + depositFee = BDAP_CREDIT; + + } else if (opCodeAction == OP_BDAP_MODIFY && opCodeObject == OP_BDAP_ACCOUNT_ENTRY && objType == BDAP::ObjectType::BDAP_USER) { + // Fees for an update BDAP user account entry + oneTimeFee = BDAP_CREDIT; + CFeeItem feeMonthly; + std::multimap::iterator iMonthly = mapDefaultMonthlyFees.find(BDAP_MONTHY_USER_FEE); + if (iMonthly != mapDefaultMonthlyFees.end()) { + feeMonthly = iMonthly->second; + monthlyFee = (nQuantity * feeMonthly.Fee); + } + if (monthlyFee == 0) + monthlyFee = BDAP_CREDIT; + depositFee = 0; + + } else if (opCodeAction == OP_BDAP_MODIFY && opCodeObject == OP_BDAP_ACCOUNT_ENTRY && objType == BDAP::ObjectType::BDAP_GROUP) { + // Fees for an update BDAP group account entry + oneTimeFee = BDAP_CREDIT; + CFeeItem feeMonthly; + std::multimap::iterator iMonthly = mapDefaultMonthlyFees.find(BDAP_MONTHY_GROUP_FEE); + if (iMonthly != mapDefaultMonthlyFees.end()) { + feeMonthly = iMonthly->second; + monthlyFee = (nQuantity * feeMonthly.Fee); + } + if (monthlyFee == 0) + monthlyFee = BDAP_CREDIT; + depositFee = 0; + + } else if (opCodeAction == OP_BDAP_NEW && opCodeObject == OP_BDAP_AUDIT && objType == BDAP::ObjectType::BDAP_AUDIT) { + // Fees for an add BDAP audit entry + oneTimeFee = BDAP_CREDIT * nQuantity; + monthlyFee = 0; + depositFee = 0; + + } else { + oneTimeFee = BDAP_CREDIT; + monthlyFee = 0; + depositFee = BDAP_CREDIT; + LogPrintf("%s -- BDAP operation code pair (%d and %d) for %s not found or unsupported.\n", __func__, opCodeAction, opCodeObject, strObjectType); + } + + return true; +} + +bool ExtractAmountsFromTx(const CTransactionRef& ptx, CAmount& dataAmount, CAmount& opAmount) +{ + bool fDataFound = false, fOpFound = false; + for (const CTxOut& out : ptx->vout) { + if (out.scriptPubKey.IsUnspendable() && out.scriptPubKey.size() > 40) + { + dataAmount = out.nValue; + fDataFound = true; + } + int op1, op2; + std::vector> vOpArgs; + if (DecodeBDAPScript(out.scriptPubKey, op1, op2, vOpArgs)) { + opAmount = out.nValue; + fOpFound = true; + } + } + return (fDataFound && fOpFound); +} \ No newline at end of file diff --git a/src/bdap/fees.h b/src/bdap/fees.h new file mode 100644 index 0000000000..b7a74918ee --- /dev/null +++ b/src/bdap/fees.h @@ -0,0 +1,54 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_FEES_H +#define DYNAMIC_BDAP_FEES_H + +#include "amount.h" +#include "bdap/bdap.h" +#include "primitives/transaction.h" +#include "script/script.h" + +#include + +static const int32_t BDAP_MONTHY_USER_FEE = 5001; +static const int32_t BDAP_MONTHY_GROUP_FEE = 5002; +static const int32_t BDAP_MONTHY_CERTIFICATE_FEE = 5003; +static const int32_t BDAP_MONTHY_SIDECHAIN_FEE = 5004; + +static const int32_t BDAP_ONE_TIME_REQUEST_LINK_FEE = 6001; +static const int32_t BDAP_ONE_TIME_ACCEPT_LINK_FEE = 6002; +static const int32_t BDAP_ONE_TIME_AUDIT_RECORD_FEE = 6003; +static const int32_t BDAP_ONE_TIME_UPDATE_USER_FEE = 6004; +static const int32_t BDAP_ONE_TIME_DELETE_USER_FEE = 6005; +static const int32_t BDAP_ONE_TIME_UPDATE_GROUP_FEE = 6006; +static const int32_t BDAP_ONE_TIME_DELETE_GROUP_FEE = 6007; +static const int32_t BDAP_ONE_TIME_UPDATE_LINK_FEE = 6008; +static const int32_t BDAP_ONE_TIME_DELETE_LINK_FEE = 6009; +static const int32_t BDAP_ONE_TIME_UPDATE_CERTIFICATE_FEE = 6010; +static const int32_t BDAP_ONE_TIME_DELETE_CERTIFICATE_FEE = 6011; +static const int32_t BDAP_ONE_TIME_UPDATE_SIDECHAIN_FEE = 6012; +static const int32_t BDAP_ONE_TIME_DELETE_SIDECHAIN_FEE = 6013; + +static const int32_t BDAP_NON_REFUNDABLE_USER_DEPOSIT = 7001; +static const int32_t BDAP_NON_REFUNDABLE_GROUP_DEPOSIT = 7002; +static const int32_t BDAP_NON_REFUNDABLE_CERTIFICATE_DEPOSIT = 7003; +static const int32_t BDAP_NON_REFUNDABLE_SIDECHAIN_DEPOSIT = 7004; + +class CFeeItem { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + int32_t nType; + CAmount Fee; + unsigned int nStartHeight; + unsigned int nEndHeight; + CFeeItem() : nVersion(CURRENT_VERSION), nType(0), Fee(0), nStartHeight(0), nEndHeight(0) {} + CFeeItem(const int32_t& type, const CAmount& fee, const unsigned int& start, const unsigned int& end) : nVersion(CURRENT_VERSION), nType(type), Fee(fee), nStartHeight(start), nEndHeight(end) {} +}; + +bool GetBDAPFees(const opcodetype& opCodeAction, const opcodetype& opCodeObject, const BDAP::ObjectType objType, const uint16_t nQuantity, CAmount& monthlyFee, CAmount& oneTimeFee, CAmount& depositFee); +bool ExtractAmountsFromTx(const CTransactionRef& ptx, CAmount& dataAmount, CAmount& opAmount); + +#endif // DYNAMIC_BDAP_FEES_H \ No newline at end of file diff --git a/src/bdap/identity.cpp b/src/bdap/identity.cpp new file mode 100644 index 0000000000..2e4021c18e --- /dev/null +++ b/src/bdap/identity.cpp @@ -0,0 +1,101 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/identity.h" + +#include "bdap/utils.h" +#include "hash.h" +#include "streams.h" + +void CIdentity::Serialize(std::vector& vchData) +{ + CDataStream dsIdentity(SER_NETWORK, PROTOCOL_VERSION); + dsIdentity << *this; + vchData = std::vector(dsIdentity.begin(), dsIdentity.end()); +} + +bool CIdentity::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsIdentity(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsIdentity >> *this; + + std::vector vchIdentityData; + Serialize(vchIdentityData); + const uint256 &calculatedHash = Hash(vchIdentityData.begin(), vchIdentityData.end()); + const std::vector &vchRandIdentity = vchFromValue(calculatedHash.GetHex()); + if(vchRandIdentity != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CIdentity::UnserializeFromTx(const CTransactionRef& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetBDAPData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +void CIdentityVerification::Serialize(std::vector& vchData) +{ + CDataStream dsIdentityVerification(SER_NETWORK, PROTOCOL_VERSION); + dsIdentityVerification << *this; + vchData = std::vector(dsIdentityVerification.begin(), dsIdentityVerification.end()); +} + +bool CIdentityVerification::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsIdentityVerification(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsIdentityVerification >> *this; + + std::vector vchIdentityVerification; + Serialize(vchIdentityVerification); + const uint256 &calculatedHash = Hash(vchIdentityVerification.begin(), vchIdentityVerification.end()); + const std::vector &vchRandIdentityVerification = vchFromValue(calculatedHash.GetHex()); + if(vchRandIdentityVerification != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CIdentityVerification::UnserializeFromTx(const CTransactionRef& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetBDAPData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} \ No newline at end of file diff --git a/src/bdap/identity.h b/src/bdap/identity.h new file mode 100644 index 0000000000..6108d12f7a --- /dev/null +++ b/src/bdap/identity.h @@ -0,0 +1,151 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_IDENTITY_H +#define DYNAMIC_BDAP_IDENTITY_H + +#include "bdap.h" +#include "domainentry.h" +#include "primitives/transaction.h" +#include "serialize.h" +#include "uint256.h" + +class CIdentity { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + CharString OwnerFullPath; // name of the owner's full domain entry path + CharString VerificationData; + unsigned int nHeight; + + uint256 txHash; + + CDomainEntry* OwnerDomainEntry; + + CIdentity() { + SetNull(); + } + + CIdentity(const CTransactionRef& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CIdentity::CURRENT_VERSION; + OwnerFullPath.clear(); + VerificationData.clear(); + nHeight = 0; + txHash.SetNull(); + OwnerDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(OwnerFullPath); + READWRITE(VerificationData); + READWRITE(VARINT(nHeight)); + READWRITE(txHash); + } + + inline friend bool operator==(const CIdentity& a, const CIdentity& b) { + return (a.OwnerFullPath == b.OwnerFullPath && a.VerificationData == b.VerificationData); + } + + inline friend bool operator!=(const CIdentity& a, const CIdentity& b) { + return !(a == b); + } + + inline CIdentity operator=(const CIdentity& b) { + OwnerFullPath = b.OwnerFullPath; + VerificationData = b.VerificationData; + nHeight = b.nHeight; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (OwnerFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransactionRef& tx); +}; + +class CIdentityVerification { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + CharString VerifierFullPath; // name of the verifier's full domain entry path + CIdentity Identity; + CharString VerificationData; + unsigned int nHeight; + uint64_t nExpireTime; + + uint256 txHash; + + CDomainEntry* VerifierDomainEntry; + + CIdentityVerification() { + SetNull(); + } + + CIdentityVerification(const CTransactionRef& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CIdentityVerification::CURRENT_VERSION; + VerifierFullPath.clear(); + Identity.SetNull(); + VerificationData.clear(); + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + VerifierDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(VerifierFullPath); + READWRITE(Identity); + READWRITE(VerificationData); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CIdentityVerification& a, const CIdentityVerification& b) { + return (a.VerifierFullPath == b.VerifierFullPath && a.Identity == b.Identity && a.VerificationData == b.VerificationData && a.nExpireTime == b.nExpireTime); + } + + inline friend bool operator!=(const CIdentityVerification& a, const CIdentityVerification& b) { + return !(a == b); + } + + inline CIdentityVerification operator=(const CIdentityVerification& b) { + VerifierFullPath = b.VerifierFullPath; + Identity = b.Identity; + VerificationData = b.VerificationData; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (VerifierFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransactionRef& tx); + +}; + +#endif // DYNAMIC_BDAP_DOMAINENTRY_H \ No newline at end of file diff --git a/src/bdap/linking.cpp b/src/bdap/linking.cpp new file mode 100644 index 0000000000..1e2c4bce82 --- /dev/null +++ b/src/bdap/linking.cpp @@ -0,0 +1,447 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/linking.h" + +#include "base58.h" +#include "bdap/domainentry.h" +#include "bdap/utils.h" +#include "hash.h" +#include "key.h" +#include "pubkey.h" +#include "script/script.h" +#include "streams.h" +#include "txmempool.h" +#include "utilstrencodings.h" // For EncodeBase64 +#include "validation.h" // For strMessageMagic + +#include // For std::find + +bool CLinkRequest::UnserializeFromTx(const CTransactionRef& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetBDAPData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData)) + { + return false; + } + return true; +} + +void CLinkRequest::Serialize(std::vector& vchData) +{ + CDataStream dsLinkRequest(SER_NETWORK, PROTOCOL_VERSION); + dsLinkRequest << *this; + vchData = std::vector(dsLinkRequest.begin(), dsLinkRequest.end()); +} + +bool CLinkRequest::UnserializeFromData(const std::vector& vchData) +{ + try { + CDataStream dsLinkRequest(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsLinkRequest >> *this; + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CLinkRequest::ValidateValues(std::string& errorMessage) +{ + // check object requestor FQDN size + if (RequestorFullObjectPath.size() > MAX_OBJECT_FULL_PATH_LENGTH) + { + errorMessage = "Invalid BDAP link requestor FQDN. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + // check object recipient FQDN size + if (RecipientFullObjectPath.size() > MAX_OBJECT_FULL_PATH_LENGTH) + { + errorMessage = "Invalid BDAP link recipient FQDN. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + // check requestor pubkey size + if (RequestorPubKey.size() != DHT_HEX_PUBLIC_KEY_LENGTH) + { + errorMessage = "Invalid BDAP link requestor public key. DHT pubkey are " + std::to_string(DHT_HEX_PUBLIC_KEY_LENGTH) + " characters."; + return false; + } + // check shared pubkey size + if (SharedPubKey.size() != DHT_HEX_PUBLIC_KEY_LENGTH) + { + errorMessage = "Invalid BDAP link shared public key. DHT pubkey are " + std::to_string(DHT_HEX_PUBLIC_KEY_LENGTH) + " characters."; + return false; + } + // check link message size + if (LinkMessage.size() > MAX_BDAP_LINK_MESSAGE) + { + errorMessage = "Invalid invite message length. The maximum invite message length is " + std::to_string(MAX_BDAP_LINK_MESSAGE) + " characters."; + return false; + } + // check signature proof size + if (SignatureProof.size() > MAX_BDAP_SIGNATURE_PROOF) + { + errorMessage = "Invalid signature proof length. The maximum signature proof length is " + std::to_string(MAX_BDAP_SIGNATURE_PROOF) + " characters."; + return false; + } + return true; +} + +std::string CLinkRequest::RequestorPubKeyString() const +{ + return stringFromVch(RequestorPubKey); +} + +std::string CLinkRequest::SharedPubKeyString() const +{ + return stringFromVch(SharedPubKey); +} + +std::string CLinkRequest::SignatureProofString() const +{ + return EncodeBase64(&SignatureProof[0], SignatureProof.size()); +} + +std::string CLinkRequest::RequestorFQDN() const +{ + return stringFromVch(RequestorFullObjectPath); +} + +std::string CLinkRequest::RecipientFQDN() const +{ + return stringFromVch(RecipientFullObjectPath); +} + +std::set CLinkRequest::SortedAccounts() const +{ + std::set sortedAccounts; + sortedAccounts.insert(RequestorFQDN()); + sortedAccounts.insert(RecipientFQDN()); + return sortedAccounts; +} + +bool CLinkRequest::Matches(const std::string& strRequestorFQDN, const std::string& strRecipientFQDN) const +{ + std::set sortedAccounts; + sortedAccounts.insert(strRequestorFQDN); + sortedAccounts.insert(strRecipientFQDN); + if (sortedAccounts == SortedAccounts()) + return true; + + return false; +} + +CharString CLinkRequest::LinkPath() const +{ + std::vector vchSeparator = {':'}; + std::set sorted = SortedAccounts(); + std::set::iterator it = sorted.begin(); + std::vector vchLink1 = vchFromString(*it); + std::advance(it, 1); + std::vector vchLink2 = vchFromString(*it); + vchLink1.insert(vchLink1.end(), vchSeparator.begin(), vchSeparator.end()); + vchLink1.insert(vchLink1.end(), vchLink2.begin(), vchLink2.end()); + return vchLink1; +} + +std::string CLinkRequest::LinkPathString() const +{ + return stringFromVch(LinkPath()); +} + +std::string CLinkRequest::ToString() const +{ + return strprintf( + "CLinkRequest(\n" + " nVersion = %d\n" + " RequestorFullObjectPath = %s\n" + " RecipientFullObjectPath = %s\n" + " RequestorPubKey = %s\n" + " SharedRequestPubKey = %s\n" + " LinkMessage = %s\n" + " SignatureProof = %s\n" + " nHeight = %d\n" + " nExpireTime = %d\n" + " txHash = %s\n" + ")\n", + nVersion, + stringFromVch(RequestorFullObjectPath), + stringFromVch(RecipientFullObjectPath), + stringFromVch(RequestorPubKey), + stringFromVch(SharedPubKey), + stringFromVch(LinkMessage), + CharVectorToHexString(SignatureProof), + nHeight, + nExpireTime, + txHash.ToString() + ); +} + +bool CLinkAccept::UnserializeFromTx(const CTransactionRef& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetBDAPData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData)) + { + return false; + } + return true; +} + +void CLinkAccept::Serialize(std::vector& vchData) +{ + CDataStream dsAcceptLink(SER_NETWORK, PROTOCOL_VERSION); + dsAcceptLink << *this; + vchData = std::vector(dsAcceptLink.begin(), dsAcceptLink.end()); +} + +bool CLinkAccept::UnserializeFromData(const std::vector& vchData) +{ + try { + CDataStream dsAcceptLink(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsAcceptLink >> *this; + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CLinkAccept::ValidateValues(std::string& errorMessage) +{ + // check object requestor FQDN size + if (RequestorFullObjectPath.size() > MAX_OBJECT_FULL_PATH_LENGTH) + { + errorMessage = "Invalid BDAP link requestor FQDN. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + // check object recipient FQDN size + if (RecipientFullObjectPath.size() > MAX_OBJECT_FULL_PATH_LENGTH) + { + errorMessage = "Invalid BDAP link recipient FQDN. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + // check recipient pubkey size + if (RecipientPubKey.size() != DHT_HEX_PUBLIC_KEY_LENGTH) + { + errorMessage = "Invalid BDAP link recipient pubkey. DHT pubkey are " + std::to_string(DHT_HEX_PUBLIC_KEY_LENGTH) + " characters."; + return false; + } + // check shared pubkey size + if (SharedPubKey.size() != DHT_HEX_PUBLIC_KEY_LENGTH) + { + errorMessage = "Invalid BDAP link shared pubkey. DHT pubkey are " + std::to_string(DHT_HEX_PUBLIC_KEY_LENGTH) + " characters."; + return false; + } + // check signature proof size + if (SignatureProof.size() > MAX_BDAP_SIGNATURE_PROOF) + { + errorMessage = "Invalid signature proof length. The maximum signature proof length is " + std::to_string(MAX_BDAP_SIGNATURE_PROOF) + " characters."; + return false; + } + return true; +} + +std::string CLinkAccept::RecipientPubKeyString() const +{ + return stringFromVch(RecipientPubKey); +} + +std::string CLinkAccept::SharedPubKeyString() const +{ + return stringFromVch(SharedPubKey); +} + +std::string CLinkAccept::SignatureProofString() const +{ + return EncodeBase64(&SignatureProof[0], SignatureProof.size()); +} + +std::string CLinkAccept::RequestorFQDN() const +{ + return stringFromVch(RequestorFullObjectPath); +} + +std::string CLinkAccept::RecipientFQDN() const +{ + return stringFromVch(RecipientFullObjectPath); +} + +std::set CLinkAccept::SortedAccounts() const +{ + std::set sortedAccounts; + sortedAccounts.insert(RequestorFQDN()); + sortedAccounts.insert(RecipientFQDN()); + return sortedAccounts; +} + +bool CLinkAccept::Matches(const std::string& strRequestorFQDN, const std::string& strRecipientFQDN) const +{ + std::set sortedAccounts; + sortedAccounts.insert(strRequestorFQDN); + sortedAccounts.insert(strRecipientFQDN); + if (sortedAccounts == SortedAccounts()) + return true; + + return false; +} + +CharString CLinkAccept::LinkPath() const +{ + std::vector vchSeparator = {':'}; + std::set sorted = SortedAccounts(); + std::set::iterator it = sorted.begin(); + std::vector vchLink1 = vchFromString(*it); + std::advance(it, 1); + std::vector vchLink2 = vchFromString(*it); + vchLink1.insert(vchLink1.end(), vchSeparator.begin(), vchSeparator.end()); + vchLink1.insert(vchLink1.end(), vchLink2.begin(), vchLink2.end()); + return vchLink1; +} + +std::string CLinkAccept::LinkPathString() const +{ + return stringFromVch(LinkPath()); +} + +std::string CLinkAccept::ToString() const +{ + return strprintf( + "CLinkAccept(\n" + " nVersion = %d\n" + " RequestorFullObjectPath = %s\n" + " RecipientFullObjectPath = %s\n" + " txLinkRequestHash = %s\n" + " RecipientPubKey = %s\n" + " SharedPubKey = %s\n" + " SignatureProof = %s\n" + " nHeight = %d\n" + " nExpireTime = %d\n" + " txHash = %s\n" + ")\n", + nVersion, + stringFromVch(RequestorFullObjectPath), + stringFromVch(RecipientFullObjectPath), + txLinkRequestHash.ToString(), + stringFromVch(RecipientPubKey), + stringFromVch(SharedPubKey), + CharVectorToHexString(SignatureProof), + nHeight, + nExpireTime, + txHash.ToString() + ); +} + +CLinkDenyList::CLinkDenyList(const std::vector& vchData) +{ + if (!UnserializeFromData(vchData)) + throw std::runtime_error("Failed to unserialize from data\n"); +} + +void CLinkDenyList::Serialize(std::vector& vchData) +{ + CDataStream dsLinkDenyList(SER_NETWORK, PROTOCOL_VERSION); + dsLinkDenyList << *this; + vchData = std::vector(dsLinkDenyList.begin(), dsLinkDenyList.end()); +} + +bool CLinkDenyList::UnserializeFromData(const std::vector& vchData) +{ + try { + CDataStream dsLinkDenyList(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsLinkDenyList >> *this; + } catch (std::exception& e) { + SetNull(); + return false; + } + return true; +} + +void CLinkDenyList::Add(const std::string& addAccount, const uint32_t timestamp) +{ + vDenyAccounts.push_back(addAccount); + vTimestamps.push_back(timestamp); +} + +bool CLinkDenyList::Find(const std::string& searchAccount) +{ + return std::find(vDenyAccounts.begin(), vDenyAccounts.end(), searchAccount) != vDenyAccounts.end(); +} + +bool CLinkDenyList::Remove(const std::string& account) +{ + if (!Find(account)) + return false; + // TODO (BDAP): implement remove account from deny list. + return true; +} +/** Checks if BDAP link request pubkey exists in the memory pool */ +bool LinkPubKeyExistsInMemPool(const CTxMemPool& pool, const std::vector& vchPubKey, const std::string& strOpType, std::string& errorMessage) +{ + for (const CTxMemPoolEntry& e : pool.mapTx) { + const CTransactionRef& tx = e.GetSharedTx(); + for (const CTxOut& txOut : tx->vout) { + if (IsBDAPDataOutput(txOut)) { + std::vector vchMemPoolPubKey; + std::string strGetOpType; + if (!ExtractOpTypeValue(txOut.scriptPubKey, strGetOpType, vchMemPoolPubKey)) + continue; + if (vchPubKey == vchMemPoolPubKey && strOpType == strGetOpType) { + errorMessage = "CheckIfExistsInMemPool: A BDAP link request public key " + stringFromVch(vchPubKey) + " transaction is already in the memory pool!"; + return true; + } + } + } + } + return false; +} + +// Signs the FQDN with the input private key +bool CreateSignatureProof(const CKey& key, const std::string& strFQDN, std::vector& vchSignatureProof) +{ + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strFQDN; + + if (!key.SignCompact(ss.GetHash(), vchSignatureProof)) { + CDynamicAddress addr(key.GetPubKey().GetID()); + LogPrint("bdap", "%s -- Failed to sign BDAP account %s with the %s wallet address\n", __func__, strFQDN, addr.ToString()); + return false; + } + return true; +} + +// Verifies that the signature for the FQDN matches the input address +bool SignatureProofIsValid(const CDynamicAddress& addr, const std::string& strFQDN, const std::vector& vchSig) +{ + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strFQDN; + + CPubKey pubkey; + if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) { + LogPrint("bdap", "%s -- Failed to get pubkey from signature data. Address = %s, vchSig size = %u\n", __func__, addr.ToString(), vchSig.size()); + return false; + } + + if (!(CDynamicAddress(pubkey.GetID()) == addr)) { + CDynamicAddress sigAddress(pubkey.GetID()); + LogPrint("bdap", "%s -- Signature address %s does not match input address = %s\n", __func__, sigAddress.ToString(), addr.ToString()); + return false; + } + return true; +} \ No newline at end of file diff --git a/src/bdap/linking.h b/src/bdap/linking.h new file mode 100644 index 0000000000..cceeda7d59 --- /dev/null +++ b/src/bdap/linking.h @@ -0,0 +1,296 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_LINKING_H +#define DYNAMIC_BDAP_LINKING_H + +#include "bdap.h" +#include "primitives/transaction.h" +#include "serialize.h" +#include "uint256.h" + +class CDynamicAddress; +class CKey; +class CTxMemPool; +class CTransaction; + +// Entry linking is a type of DAP binding operation. This class is used to +// manage domain entry link requests. When linking entries, we want +// to use stealth addresses so the linkage requests are not public. + +// CLinkRequest are stored serilzed and encrypted in a BDAP OP_RETURN transaction. +// The link request recipient can decrypt the BDAP OP_RETURN transaction +// and get the needed information to accept the link request +// It is used to bootstrap the linkage relationship with a new set of public keys + +// OP_RETURN Format: std::vector GetEncryptedMessage(Serialize(CLinkRequest)) + +namespace BDAP { + + enum LinkFilterType + { + BOTH = 0, + REQUEST = 1, + RECIPIENT = 2 + }; +} + +class CLinkRequest { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + CharString RequestorFullObjectPath; // Requestor's BDAP object path + CharString RecipientFullObjectPath; // Recipient's BDAP object path + CharString RequestorPubKey; // ed25519 public key new/unique for this link + CharString SharedPubKey; // ed25519 shared public key. RequestorPubKey + Recipient's BDAP DHT PubKey + CharString LinkMessage; // Link message to recipient + CharString SignatureProof; // Requestor's BDAP account ownership proof by signing the recipient's object path with their wallet pub key. + + unsigned int nHeight; + uint64_t nExpireTime; + uint256 txHash; + + CLinkRequest() { + SetNull(); + } + + CLinkRequest(const CTransactionRef& tx) { + SetNull(); + UnserializeFromTx(tx); + txHash = tx->GetHash(); + } + + CLinkRequest(const std::vector& vchData, const uint256& hash) { + SetNull(); + UnserializeFromData(vchData); + txHash = hash; + } + + inline void SetNull() + { + nVersion = CLinkRequest::CURRENT_VERSION; + RequestorFullObjectPath.clear(); + RecipientFullObjectPath.clear(); + RequestorPubKey.clear(); + SharedPubKey.clear(); + LinkMessage.clear(); + SignatureProof.clear(); + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(RequestorFullObjectPath); + READWRITE(RecipientFullObjectPath); + READWRITE(RequestorPubKey); + READWRITE(SharedPubKey); + READWRITE(LinkMessage); + READWRITE(SignatureProof); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CLinkRequest &a, const CLinkRequest &b) { + return (a.RequestorPubKey == b.RequestorPubKey && a.SharedPubKey == b.SharedPubKey && a.LinkMessage == b.LinkMessage); + } + + inline friend bool operator!=(const CLinkRequest &a, const CLinkRequest &b) { + return !(a == b); + } + + inline CLinkRequest operator=(const CLinkRequest &b) { + nVersion = b.nVersion; + RequestorFullObjectPath = b.RequestorFullObjectPath; + RecipientFullObjectPath = b.RecipientFullObjectPath; + RequestorPubKey = b.RequestorPubKey; + SharedPubKey = b.SharedPubKey; + LinkMessage = b.LinkMessage; + SignatureProof = b.SignatureProof; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (RequestorFullObjectPath.empty()); } + bool UnserializeFromTx(const CTransactionRef& tx); + bool UnserializeFromData(const std::vector& vchData); + void Serialize(std::vector& vchData); + + bool ValidateValues(std::string& errorMessage); + std::string RequestorPubKeyString() const; + std::string SharedPubKeyString() const; + std::string SignatureProofString() const; + std::string RequestorFQDN() const; + std::string RecipientFQDN() const; + std::set SortedAccounts() const; + bool Matches(const std::string& strRequestorFQDN, const std::string& strRecipientFQDN) const; + CharString LinkPath() const; + std::string LinkPathString() const; + std::string ToString() const; + +}; + +// OP_RETURN Format: std::vector GetEncryptedMessage(Serialize(CLinkAccept)) +class CLinkAccept { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + CharString RequestorFullObjectPath; // Requestor's BDAP object path + CharString RecipientFullObjectPath; // Recipient's BDAP object path + uint256 txLinkRequestHash; // transaction hash for the link request. + CharString RecipientPubKey; // ed25519 public key new/unique for this link + CharString SharedPubKey; // ed25519 shared public key using the requestor and recipient keys + CharString SignatureProof; // Acceptor's BDAP account ownership proof by signing the requestor's object path with their wallet pub key. + + unsigned int nHeight; + uint64_t nExpireTime; + uint256 txHash; + + CLinkAccept() { + SetNull(); + } + + CLinkAccept(const CTransactionRef& tx) { + SetNull(); + UnserializeFromTx(tx); + txHash = tx->GetHash(); + } + + CLinkAccept(const std::vector& vchData, const uint256& hash) { + SetNull(); + UnserializeFromData(vchData); + txHash = hash; + } + + inline void SetNull() + { + nVersion = CLinkAccept::CURRENT_VERSION; + RequestorFullObjectPath.clear(); + RecipientFullObjectPath.clear(); + txLinkRequestHash.SetNull(); + RecipientPubKey.clear(); + SharedPubKey.clear(); + SignatureProof.clear(); + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(RequestorFullObjectPath); + READWRITE(RecipientFullObjectPath); + READWRITE(txLinkRequestHash); + READWRITE(RecipientPubKey); + READWRITE(SharedPubKey); + READWRITE(SignatureProof); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CLinkAccept &a, const CLinkAccept &b) { + return (a.SignatureProof == b.SignatureProof && a.RecipientPubKey == b.RecipientPubKey && a.SharedPubKey == b.SharedPubKey); + } + + inline friend bool operator!=(const CLinkAccept &a, const CLinkAccept &b) { + return !(a == b); + } + + inline CLinkAccept operator=(const CLinkAccept &b) { + nVersion = b.nVersion; + RequestorFullObjectPath = b.RequestorFullObjectPath; + RecipientFullObjectPath = b.RecipientFullObjectPath; + RecipientPubKey = b.RecipientPubKey; + SharedPubKey = b.SharedPubKey; + SignatureProof = b.SignatureProof; + txLinkRequestHash = b.txLinkRequestHash; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (RequestorFullObjectPath.empty()); } + bool UnserializeFromTx(const CTransactionRef& tx); + bool UnserializeFromData(const std::vector& vchData); + void Serialize(std::vector& vchData); + + bool ValidateValues(std::string& errorMessage); + std::string RecipientPubKeyString() const; + std::string SharedPubKeyString() const; + std::string SignatureProofString() const; + std::string RequestorFQDN() const; + std::string RecipientFQDN() const; + std::set SortedAccounts() const; + bool Matches(const std::string& strRequestorFQDN, const std::string& strRecipientFQDN) const; + CharString LinkPath() const; + std::string LinkPathString() const; + std::string ToString() const; + +}; + +class CLinkDenyList +{ +public: + std::vector vDenyAccounts; + std::vector vTimestamps; + + CLinkDenyList() {} + CLinkDenyList(const std::vector& vchData); + + inline void SetNull() + { + vDenyAccounts.clear(); + vTimestamps.clear(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(vDenyAccounts); + READWRITE(vTimestamps); + } + + inline friend bool operator==(const CLinkDenyList& a, const CLinkDenyList& b) { + return (a.vDenyAccounts == b.vDenyAccounts && a.vTimestamps == b.vTimestamps); + } + + inline friend bool operator!=(const CLinkDenyList& a, const CLinkDenyList& b) { + return !(a == b); + } + + inline CLinkDenyList operator=(const CLinkDenyList& b) { + vDenyAccounts = b.vDenyAccounts; + vTimestamps = b.vTimestamps; + return *this; + } + + inline bool IsNull() const { return (vDenyAccounts.size() == 0); } + + void Add(const std::string& addAccount, const uint32_t timestamp); + bool Find(const std::string& searchAccount); + bool Remove(const std::string& account); + + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData); + +}; + +bool LinkPubKeyExistsInMemPool(const CTxMemPool& pool, const std::vector& vchPubKey, const std::string& strOpType, std::string& errorMessage); +bool CreateSignatureProof(const CKey& key, const std::string& strFQDN, std::vector& vchSignatureProof); +bool SignatureProofIsValid(const CDynamicAddress& addr, const std::string& strFQDN, const std::vector& vchSig); + +#endif // DYNAMIC_BDAP_LINKING_H \ No newline at end of file diff --git a/src/bdap/linkingdb.cpp b/src/bdap/linkingdb.cpp new file mode 100644 index 0000000000..fa12143f14 --- /dev/null +++ b/src/bdap/linkingdb.cpp @@ -0,0 +1,313 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/linkingdb.h" + +#include "amount.h" +#include "bdap/fees.h" +#include "bdap/utils.h" +#include "base58.h" +#include "utilmoneystr.h" +#include "validation.h" +#include "validationinterface.h" + +#include + +CLinkDB *pLinkDB = NULL; + +bool UndoLinkData(const std::vector& vchPubKey, const std::vector& vchSharedPubKey) +{ + if (!pLinkDB) + return false; + + return pLinkDB->EraseLinkIndex(vchPubKey, vchSharedPubKey); +} + +bool CLinkDB::AddLinkIndex(const vchCharString& vvchOpParameters, const uint256& txid) +{ + bool writeState = false; + { + LOCK(cs_link); + writeState = Write(make_pair(std::string("pubkey"), stringFromVch(vvchOpParameters[0])), txid); + if (writeState && vvchOpParameters.size() > 1) + writeState = Write(make_pair(std::string("pubkey"), stringFromVch(vvchOpParameters[1])), txid); + } + + return writeState; +} + +bool CLinkDB::ReadLinkIndex(const std::vector& vchPubKey, uint256& txid) +{ + LOCK(cs_link); + return CDBWrapper::Read(make_pair(std::string("pubkey"), vchPubKey), txid); +} + +bool CLinkDB::EraseLinkIndex(const std::vector& vchPubKey, const std::vector& vchSharedPubKey) +{ + if (!LinkExists(vchPubKey)) + return false; + if (!LinkExists(vchSharedPubKey)) + return false; + + bool result = false; + LOCK(cs_link); + result = CDBWrapper::Erase(make_pair(std::string("pubkey"), vchPubKey)); + if (!result) + return false; + + return CDBWrapper::Erase(make_pair(std::string("pubkey"), vchSharedPubKey)); +} + +bool CLinkDB::LinkExists(const std::vector& vchPubKey) +{ + LOCK(cs_link); + return CDBWrapper::Exists(make_pair(std::string("pubkey"), vchPubKey)); +} + +bool GetLinkIndex(const std::vector& vchPubKey, uint256& txid) +{ + txid.SetNull(); + if (!pLinkDB || !pLinkDB->ReadLinkIndex(vchPubKey, txid)) { + return false; + } + return !txid.IsNull(); +} + +bool CheckLinkDB() +{ + if (!pLinkDB) + return false; + + return true; +} + +bool FlushLinkDB() +{ + { + LOCK(cs_link); + if (pLinkDB != NULL) + { + if (!pLinkDB->Flush()) { + LogPrintf("%s -- Failed to flush link leveldb!\n", __func__); + return false; + } + } + } + return true; +} + +static bool CommonLinkParameterCheck(const vchCharString& vvchOpParameters, std::string& errorMessage) +{ + if (vvchOpParameters.size() > 3) + { + errorMessage = "CommonLinkParameterCheck failed! Invalid parameters."; + return false; + } + // check pubkey size + if (vvchOpParameters[0].size() > DHT_HEX_PUBLIC_KEY_LENGTH) + { + errorMessage = "CommonLinkParameterCheck failed! Incorrect pubkey size."; + return false; + } + // check shared pubkey size + if (vvchOpParameters.size() > 1 && vvchOpParameters[1].size() > DHT_HEX_PUBLIC_KEY_LENGTH) + { + errorMessage = "CommonLinkParameterCheck failed! Incorrect shared pubkey size."; + return false; + } + // check expiration time is not greater than 10 digits + if (vvchOpParameters.size() > 2 && vvchOpParameters[2].size() > 10) + { + errorMessage = "CommonLinkParameterCheck failed! Incorrect expiration time."; + return false; + } + + return true; +} + +static bool CheckNewLinkTx(const CScript& scriptData, const vchCharString& vvchOpParameters, const uint256& txid, std::string& errorMessage, bool fJustCheck) +{ + if (!CommonLinkParameterCheck(vvchOpParameters, errorMessage)) + return error(errorMessage.c_str()); + + if (!scriptData.IsUnspendable()) { + errorMessage = "CheckNewLinkTx failed! Data script should be unspendable."; + return error(errorMessage.c_str()); + } + CTxOut txout(0, scriptData); + size_t nSize = GetSerializeSize(txout, SER_DISK,0)+148u; + LogPrint("bdap", "%s -- scriptData.size() = %u, Serialize Size = %u \n", __func__, scriptData.size(), nSize); + if (nSize > MAX_BDAP_LINK_DATA_SIZE) { + errorMessage = "CheckNewLinkTx failed! Data script is too large."; + return error(errorMessage.c_str()); + } + if (fJustCheck) + return true; + + if (!pLinkDB) + { + errorMessage = "CheckNewLinkTx failed! Can not open LevelDB BDAP link database."; + return error(errorMessage.c_str()); + } + if (!pLinkDB->AddLinkIndex(vvchOpParameters, txid)) + { + errorMessage = "CheckNewLinkTx failed! Error adding link index to LevelDB."; + return error(errorMessage.c_str()); + } + if (!FlushLinkDB()) + { + errorMessage = "CheckNewLinkTx failed! Error flushing link LevelDB."; + return error(errorMessage.c_str()); + } + return true; +} + +bool CheckLinkTx(const CTransactionRef& tx, const int& op1, const int& op2, const std::vector >& vvchArgs, + const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage) +{ + if (tx->IsCoinBase() && !fJustCheck && !bSanityCheck) { + LogPrintf("%s -- Trying to add BDAP link in coinbase transaction, skipping...\n", __func__); + return true; + } + + LogPrint("bdap", "%s -- *** BDAP link nHeight=%d, chainActive.Tip()=%d, op1=%s, op2=%s, hash=%s justcheck=%s\n", __func__, nHeight, chainActive.Tip()->nHeight, BDAPFromOp(op1).c_str(), BDAPFromOp(op2).c_str(), tx->GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); + + CScript scriptData; + if (!GetBDAPDataScript(tx, scriptData)) + return false; + + // extract amounts from tx. + CAmount dataAmount, opAmount; + if (!ExtractAmountsFromTx(tx, dataAmount, opAmount)) { + errorMessage = "Unable to extract BDAP amounts from transaction"; + return false; + } + + const std::string strOperationType = GetBDAPOpTypeString(op1, op2); + + CAmount monthlyFee, oneTimeFee, depositFee; + if (strOperationType == "bdap_new_link_request") { + uint16_t nMonths = 0; + if (!GetBDAPFees(OP_BDAP_NEW, OP_BDAP_LINK_REQUEST, BDAP::ObjectType::BDAP_LINK_REQUEST, nMonths, monthlyFee, oneTimeFee, depositFee)) { + errorMessage = "Failed to get BDAP fees for new link request"; + return false; + } + if (oneTimeFee > dataAmount) { + LogPrintf("%s -- Invalid BDAP one-time fee amount for a new BDAP link request. Total paid %d but should be %d\n", __func__, + FormatMoney(dataAmount), FormatMoney(oneTimeFee)); + errorMessage = "Invalid BDAP fee amount for a new BDAP link request"; + return false; + } + else { + LogPrint("bdap", "%s -- Valid BDAP one-time fee amount for new BDAP request link. One-time paid %d, should be %d.\n", __func__, + FormatMoney(dataAmount), FormatMoney(oneTimeFee)); + } + if (depositFee > opAmount) { + LogPrintf("%s -- Invalid BDAP deposit amount for a new BDAP link request. Total paid %d but should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + errorMessage = "Invalid BDAP fee amount for a new BDAP link request"; + return false; + } else { + LogPrint("bdap", "%s -- Valid BDAP deposit fee amount for new BDAP request link. Deposit paid %d, should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + } + return CheckNewLinkTx(scriptData, vvchArgs, tx->GetHash(), errorMessage, fJustCheck); + } + else if (strOperationType == "bdap_new_link_accept") { + uint16_t nMonths = 0; + if (!GetBDAPFees(OP_BDAP_NEW, OP_BDAP_LINK_ACCEPT, BDAP::ObjectType::BDAP_LINK_ACCEPT, nMonths, monthlyFee, oneTimeFee, depositFee)) { + errorMessage = "Failed to get BDAP fees for new link accept"; + return false; + } + if (oneTimeFee > dataAmount) { + LogPrintf("%s -- Invalid BDAP one-time fee amount for a new BDAP link accept. Total paid %d but should be %d\n", __func__, + FormatMoney(dataAmount), FormatMoney(oneTimeFee)); + errorMessage = "Invalid BDAP fee amount for a new BDAP link accept"; + return false; + } else { + LogPrint("bdap", "%s -- Valid BDAP one-time fee amount for new BDAP accept link. One-time paid %d, should be %d.\n", __func__, + FormatMoney(dataAmount), FormatMoney(oneTimeFee)); + } + if (depositFee > opAmount) { + LogPrintf("%s -- Invalid BDAP deposit amount for a new BDAP link accept. Total paid %d but should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + errorMessage = "Invalid BDAP fee amount for a new BDAP link accept"; + return false; + } else { + LogPrint("bdap", "%s -- Valid BDAP deposit fee amount for new BDAP accept link. Deposit paid %d, should be %d\n", __func__, + FormatMoney(opAmount), FormatMoney(depositFee)); + } + return CheckNewLinkTx(scriptData, vvchArgs, tx->GetHash(), errorMessage, fJustCheck); + } + + return false; +} + +bool CheckPreviousLinkInputs(const std::string& strOpType, const CScript& scriptOp, const std::vector>& vvchOpParameters, std::string& errorMessage, bool fJustCheck) +{ + // finds the previous link txid and makes sure this operation is coming from the same wallet address as the new or update entry + CTxDestination bdapDest; + if (!ExtractDestination(scriptOp, bdapDest)) + { + errorMessage = "CheckPreviousLinkInputs: - " + _("Cannot extract destination of BDAP input; this delete operation failed!"); + return error(errorMessage.c_str()); + } + else + { + std::vector vchPubKey = vvchOpParameters[0]; + uint256 prevTxId; + if (strOpType == "bdap_delete_link_request") { + if (!GetLinkIndex(vchPubKey, prevTxId)) { + errorMessage = "CheckPreviousLinkInputs: - " + _("Cannot get previous link request txid; this delete operation failed!"); + return error(errorMessage.c_str()); + } + } + else if (strOpType == "bdap_delete_link_accept") { + if (!GetLinkIndex(vchPubKey, prevTxId)) { + errorMessage = "CheckPreviousLinkInputs: - " + _("Cannot get previous link accept txid; this delete operation failed!"); + return error(errorMessage.c_str()); + } + } + CTransactionRef prevTx; + if (!GetPreviousTxRefById(prevTxId, prevTx)) { + errorMessage = "CheckPreviousLinkInputs: - " + _("Cannot extract previous transaction from BDAP link output; this delete operation failed!"); + return error(errorMessage.c_str()); + } + // Get current wallet address used for BDAP tx + CDynamicAddress txAddress = GetScriptAddress(scriptOp); + // Get previous wallet address used for BDAP tx + CScript prevScriptPubKey; + GetBDAPOpScript(prevTx, prevScriptPubKey); + CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); + if (txAddress.ToString() != prevAddress.ToString()) + { + //check if previous wallet address is used for update and delete txs + errorMessage = "CheckPreviousLinkInputs: - " + _("Changes to link data must use the previous wallet address; this delete operation failed!"); + return error(errorMessage.c_str()); + } + if (fJustCheck) + return true; + + std::vector vchSharedPubKey; + // TODO (BDAP): make sure the DHT pubkeys have not changed before allowing a global delete. + if (vvchOpParameters.size() > 1) + vchSharedPubKey = vvchOpParameters[1]; + + if (strOpType == "bdap_delete_link_request") { + pLinkDB->EraseLinkIndex(vchPubKey, vchSharedPubKey); + } + else if (strOpType == "bdap_delete_link_accept") { + pLinkDB->EraseLinkIndex(vchPubKey, vchSharedPubKey); + } + } + return true; +} + +bool LinkPubKeyExists(const std::vector& vchPubKey) +{ + if (!CheckLinkDB()) + return false; + + return pLinkDB->LinkExists(vchPubKey); +} \ No newline at end of file diff --git a/src/bdap/linkingdb.h b/src/bdap/linkingdb.h new file mode 100644 index 0000000000..24dfcd5c5f --- /dev/null +++ b/src/bdap/linkingdb.h @@ -0,0 +1,41 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_LINKINGDB_H +#define DYNAMIC_BDAP_LINKINGDB_H + +#include "bdap/linking.h" +#include "dbwrapper.h" +#include "sync.h" + +class uint256; + +static CCriticalSection cs_link; + +class CLinkDB : public CDBWrapper { +public: + CLinkDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "blocks" / "links", nCacheSize, fMemory, fWipe, obfuscate) { + } + + bool AddLinkIndex(const vchCharString& vvchOpParameters, const uint256& txid); + bool ReadLinkIndex(const std::vector& vchPubKey, uint256& txid); + bool EraseLinkIndex(const std::vector& vchPubKey, const std::vector& vchSharedPubKey); + bool LinkExists(const std::vector& vchPubKey); + //bool CleanupIndexLinkDB(int& nRemoved); +}; + +bool UndoLinkData(const std::vector& vchPubKey, const std::vector& vchSharedPubKey); +bool GetLinkIndex(const std::vector& vchPubKey, uint256& txid); +bool CheckLinkDB(); +bool FlushLinkDB(); +bool CheckLinkTx(const CTransactionRef& tx, const int& op1, const int& op2, const std::vector >& vvchArgs, + const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage); + +bool CheckPreviousLinkInputs(const std::string& strOpType, const CScript& scriptOp, const std::vector>& vvchOpParameters, std::string& errorMessage, bool fJustCheck); + +bool LinkPubKeyExists(const std::vector& vchPubKey); + +extern CLinkDB *pLinkDB; + +#endif // DYNAMIC_BDAP_LINKINGDB_H \ No newline at end of file diff --git a/src/bdap/linkmanager.cpp b/src/bdap/linkmanager.cpp new file mode 100644 index 0000000000..4faea4ab3c --- /dev/null +++ b/src/bdap/linkmanager.cpp @@ -0,0 +1,998 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/linkmanager.h" + +#include "bdap/domainentry.h" +#include "bdap/domainentrydb.h" +#include "bdap/linking.h" +#include "bdap/utils.h" +#include "bdap/vgp/include/encryption.h" // for VGP DecryptBDAPData +#include "dht/ed25519.h" +#include "pubkey.h" +#include "wallet/wallet.h" + +CLinkManager* pLinkManager = NULL; + +//#ifdef ENABLE_WALLET + +std::string CLink::LinkState() const +{ + if (nLinkState == 0) { + return "Unknown"; + } + else if (nLinkState == 1) { + return "Pending"; + } + else if (nLinkState == 2) { + return "Complete"; + } + else if (nLinkState == 3) { + return "Deleted"; + } + return "Undefined"; +} + +std::string CLink::ToString() const +{ + return strprintf( + "CLink(\n" + " nVersion = %d\n" + " LinkID = %s\n" + " fRequestFromMe = %s\n" + " fAcceptFromMe = %s\n" + " LinkState = %s\n" + " RequestorFullObjectPath = %s\n" + " RecipientFullObjectPath = %s\n" + " RequestorPubKey = %s\n" + " RecipientPubKey = %s\n" + " SharedRequestPubKey = %s\n" + " SharedAcceptPubKey = %s\n" + " LinkMessage = %s\n" + " nHeightRequest = %d\n" + " nExpireTimeRequest = %d\n" + " txHashRequest = %s\n" + " nHeightAccept = %d\n" + " nExpireTimeAccept = %d\n" + " txHashAccept = %s\n" + " SubjectID = %s\n" + " RequestorWalletAddress = %s\n" + " RecipientWalletAddress = %s\n" + ")\n", + nVersion, + LinkID.ToString(), + fRequestFromMe ? "true" : "false", + fAcceptFromMe ? "true" : "false", + LinkState(), + stringFromVch(RequestorFullObjectPath), + stringFromVch(RecipientFullObjectPath), + stringFromVch(RequestorPubKey), + stringFromVch(RecipientPubKey), + stringFromVch(SharedRequestPubKey), + stringFromVch(SharedAcceptPubKey), + stringFromVch(LinkMessage), + nHeightRequest, + nExpireTimeRequest, + txHashRequest.ToString(), + nHeightAccept, + nExpireTimeAccept, + txHashAccept.ToString(), + SubjectID.ToString(), + stringFromVch(RequestorWalletAddress), + stringFromVch(RecipientWalletAddress) + ); +} + +std::string CLink::RequestorFQDN() const +{ + return stringFromVch(RequestorFullObjectPath); +} + +std::string CLink::RecipientFQDN() const +{ + return stringFromVch(RecipientFullObjectPath); +} + +std::string CLink::RequestorPubKeyString() const +{ + return stringFromVch(RequestorPubKey); +} + +std::string CLink::RecipientPubKeyString() const +{ + return stringFromVch(RecipientPubKey); +} + +#ifdef ENABLE_WALLET +bool CLinkManager::IsLinkFromMe(const std::vector& vchLinkPubKey) +{ + if (!pwalletMain) + return false; + + CKeyID keyID(Hash160(vchLinkPubKey.begin(), vchLinkPubKey.end())); + CKeyEd25519 keyOut; + if (pwalletMain->GetDHTKey(keyID, keyOut)) + return true; + + return false; +} + +bool CLinkManager::IsLinkForMe(const std::vector& vchLinkPubKey, const std::vector& vchSharedPubKey) +{ + if (!pwalletMain) + return false; + + std::vector> vvchMyDHTPubKeys; + if (!pwalletMain->GetDHTPubKeys(vvchMyDHTPubKeys)) + return false; + + if (vvchMyDHTPubKeys.size() == 0) + return false; + + for (const std::vector& vchMyDHTPubKey : vvchMyDHTPubKeys) { + CKeyID keyID(Hash160(vchMyDHTPubKey.begin(), vchMyDHTPubKey.end())); + CKeyEd25519 dhtKey; + if (pwalletMain->GetDHTKey(keyID, dhtKey)) { + std::vector vchGetSharedPubKey = GetLinkSharedPubKey(dhtKey, vchLinkPubKey); + if (vchGetSharedPubKey == vchSharedPubKey) + return true; + } + } + + return false; +} + +bool CLinkManager::GetLinkPrivateKey(const std::vector& vchSenderPubKey, const std::vector& vchSharedPubKey, std::array& sharedSeed, std::string& strErrorMessage) +{ + if (!pwalletMain) + return false; + + std::vector> vvchDHTPubKeys; + if (!pwalletMain->GetDHTPubKeys(vvchDHTPubKeys)) { + strErrorMessage = "Failed to get DHT key vector."; + return false; + } + // loop through each account key to check if it matches the shared key + for (const std::vector& vchPubKey : vvchDHTPubKeys) { + CDomainEntry entry; + if (pDomainEntryDB->ReadDomainEntryPubKey(vchPubKey, entry)) { + CKeyEd25519 dhtKey; + CKeyID keyID(Hash160(vchPubKey.begin(), vchPubKey.end())); + if (pwalletMain->GetDHTKey(keyID, dhtKey)) { + if (vchSharedPubKey == GetLinkSharedPubKey(dhtKey, vchSenderPubKey)) { + sharedSeed = GetLinkSharedPrivateKey(dhtKey, vchSenderPubKey); + return true; + } + } + else { + strErrorMessage = strErrorMessage + "Error getting DHT private key.\n"; + } + } + } + return false; +} +#endif // ENABLE_WALLET + +bool CLinkManager::FindLink(const uint256& id, CLink& link) +{ + if (m_Links.count(id) > 0) { + link = m_Links.at(id); + return true; + } + return false; +} + +bool CLinkManager::FindLinkBySubjectID(const uint256& subjectID, CLink& getLink) +{ + for (const std::pair& link : m_Links) + { + if (link.second.SubjectID == subjectID) // pending request + { + getLink = link.second; + return true; + } + } + return false; +} + +#ifdef ENABLE_WALLET +void CLinkManager::ProcessQueue() +{ + if (!pwalletMain) + return; + + if (pwalletMain->IsLocked()) + return; + + // make sure we are not stuck in an infinite loop + size_t size = QueueSize(); + size_t counter = 0; + LogPrintf("CLinkManager::%s -- Start links in queue = %d\n", __func__, size); + while (!linkQueue.empty() && size > counter) + { + // TODO (BDAP): Do we need to lock the queue while processing? + CLinkStorage storage = linkQueue.front(); + ProcessLink(storage); + linkQueue.pop(); + counter++; + } + LogPrintf("CLinkManager::%s -- Finished links in queue = %d\n", __func__, QueueSize()); +} +#else +void CLinkManager::ProcessQueue() +{ + return; +} +#endif // ENABLE_WALLET + + + +bool CLinkManager::ListMyPendingRequests(std::vector& vchLinks) +{ + for (const std::pair& link : m_Links) + { + if (link.second.nLinkState == 1 && link.second.fRequestFromMe) // pending request + { + vchLinks.push_back(link.second); + } + } + return true; +} + +bool CLinkManager::ListMyPendingAccepts(std::vector& vchLinks) +{ + for (const std::pair& link : m_Links) + { + //LogPrintf("%s -- link:\n%s\n", __func__, link.second.ToString()); + if (link.second.nLinkState == 1 && (!link.second.fRequestFromMe || (link.second.fRequestFromMe && link.second.fAcceptFromMe))) // pending accept + { + vchLinks.push_back(link.second); + } + } + return true; +} + +bool CLinkManager::ListMyCompleted(std::vector& vchLinks) +{ + for (const std::pair& link : m_Links) + { + if (link.second.nLinkState == 2 && !link.second.txHashRequest.IsNull()) // completed link + { + vchLinks.push_back(link.second); + } + } + return true; +} + +bool CLinkManager::ProcessLink(const CLinkStorage& storage, const bool fStoreInQueueOnly) +{ + +#ifndef ENABLE_WALLET + linkQueue.push(storage); + return true; +#else + if (!pwalletMain) { + linkQueue.push(storage); + return true; + } + + if (fStoreInQueueOnly || pwalletMain->IsLocked()) { + linkQueue.push(storage); + return true; + } + int nDataVersion = -1; + if (!storage.Encrypted()) + { + if (storage.nType == 1) // Clear text link request + { + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + CLinkRequest link(vchData, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + link.nHeight = storage.nHeight; + link.txHash = storage.txHash; + link.nExpireTime = storage.nExpireTime; + CDomainEntry entry; + if (GetDomainEntry(link.RequestorFullObjectPath, entry)) { + if (SignatureProofIsValid(entry.GetWalletAddress(), link.RecipientFQDN(), link.SignatureProof)) { + bool fIsLinkFromMe = IsLinkFromMe(storage.vchLinkPubKey); + LogPrint("bdap", "%s -- Link request from me found with a valid signature proof. Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fRequestFromMe = fIsLinkFromMe; + if (record.nHeightAccept > 0) { + record.nLinkState = 2; + } + else { + record.nLinkState = 1; + } + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RequestorPubKey = link.RequestorPubKey; + record.SharedRequestPubKey = link.SharedPubKey; + record.LinkMessage = link.LinkMessage; + record.nHeightRequest = link.nHeight; + record.nExpireTimeRequest = link.nExpireTime; + record.txHashRequest = link.txHash; + record.RequestorWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- link request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Clear text link request added to map id = %s\n", __func__, linkID.ToString()); + m_Links[linkID] = record; + + } + else + LogPrintf("%s ***** Warning. Link request found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + } + else { + LogPrintf("%s -- Link request GetDomainEntry failed.\n", __func__); + return false; + } + } + else if (storage.nType == 2) // Clear text accept + { + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + CLinkAccept link(vchData, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + link.nHeight = storage.nHeight; + link.txHash = storage.txHash; + link.nExpireTime = storage.nExpireTime; + CDomainEntry entry; + if (GetDomainEntry(link.RecipientFullObjectPath, entry)) { + if (SignatureProofIsValid(entry.GetWalletAddress(), link.RequestorFQDN(), link.SignatureProof)) { + bool fIsLinkFromMe = IsLinkFromMe(storage.vchLinkPubKey); + //bool fIsLinkForMe = IsLinkForMe(storage.vchLinkPubKey, storage.vchSharedPubKey); + LogPrint("bdap", "%s -- Link accept from me found with a valid signature proof. Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fAcceptFromMe = fIsLinkFromMe; + record.nLinkState = 2; + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RecipientPubKey = link.RecipientPubKey; + record.SharedAcceptPubKey = link.SharedPubKey; + record.nHeightAccept = link.nHeight; + record.nExpireTimeAccept = link.nExpireTime; + record.txHashAccept = link.txHash; + record.RecipientWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- link accept = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Clear text accept added to map id = %s, %s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else + LogPrintf("%s -- Warning! Link accept found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + } + else { + LogPrintf("%s -- Link accept GetDomainEntry failed.\n", __func__); + return false; + } + } + } + else if (storage.Encrypted() && !pwalletMain->IsLocked()) + { + bool fIsLinkFromMe = IsLinkFromMe(storage.vchLinkPubKey); + bool fIsLinkForMe = IsLinkForMe(storage.vchLinkPubKey, storage.vchSharedPubKey); + if (!fIsLinkFromMe && !fIsLinkForMe) { + // This happens if you lose your DHT private key but have the BDAP account link wallet private key. + LogPrintf("%s -- ** Warning: Encrypted link received but can not process it: TxID = %s\n", __func__, storage.txHash.ToString()); + return false; + } + + if (storage.nType == 1 && fIsLinkFromMe) // Encrypted link request from me + { + //LogPrintf("%s -- Version 1 link request from me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); + CKeyEd25519 privDHTKey; + CKeyID keyID(Hash160(storage.vchLinkPubKey.begin(), storage.vchLinkPubKey.end())); + if (pwalletMain->GetDHTKey(keyID, privDHTKey)) { + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + std::string strMessage = ""; + std::vector dataDecrypted; + if (DecryptBDAPData(privDHTKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { + std::vector vchData, vchHash; + CScript scriptData; + scriptData << OP_RETURN << dataDecrypted; + if (GetBDAPData(scriptData, vchData, vchHash)) { + CLinkRequest link(dataDecrypted, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + CDomainEntry entry; + if (!GetDomainEntry(link.RequestorFullObjectPath, entry)) { + LogPrintf("%s -- Failed to get link requestor %s\n", __func__, stringFromVch(link.RequestorFullObjectPath)); + return false; + } + if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RecipientFQDN(), link.SignatureProof)) { + LogPrintf("%s ***** Warning. Link request found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + return false; + } + link.nHeight = storage.nHeight; + link.nExpireTime = storage.nExpireTime; + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fRequestFromMe = fIsLinkFromMe; + record.fAcceptFromMe = (fIsLinkFromMe && fIsLinkForMe); + if (record.nHeightAccept > 0) { + record.nLinkState = 2; + } + else { + record.nLinkState = 1; + } + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RequestorPubKey = link.RequestorPubKey; + record.SharedRequestPubKey = link.SharedPubKey; + record.LinkMessage = link.LinkMessage; + record.nHeightRequest = link.nHeight; + record.nExpireTimeRequest = link.nExpireTime; + record.txHashRequest = link.txHash; + record.RequestorWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- link request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Encrypted link request from me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else { + LogPrintf("%s -- Link request GetBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link request DecryptBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link request GetDHTKey failed.\n", __func__); + return false; + } + } + else if (storage.nType == 1 && !fIsLinkFromMe && fIsLinkForMe) // Encrypted link request for me + { + //LogPrintf("%s -- Version 1 link request for me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); + CKeyEd25519 sharedDHTKey; + std::array sharedSeed; + std::string strErrorMessage; + if (GetLinkPrivateKey(storage.vchLinkPubKey, storage.vchSharedPubKey, sharedSeed, strErrorMessage)) { + CKeyEd25519 sharedKey(sharedSeed); + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + std::string strMessage = ""; + std::vector dataDecrypted; + if (DecryptBDAPData(sharedKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { + std::vector vchData, vchHash; + CScript scriptData; + scriptData << OP_RETURN << dataDecrypted; + if (GetBDAPData(scriptData, vchData, vchHash)) { + CLinkRequest link(dataDecrypted, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + CDomainEntry entry; + if (!GetDomainEntry(link.RequestorFullObjectPath, entry)) { + LogPrintf("%s -- Failed to get link requestor %s\n", __func__, stringFromVch(link.RequestorFullObjectPath)); + return false; + } + if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RecipientFQDN(), link.SignatureProof)) { + LogPrintf("%s ***** Warning. Link request found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + return false; + } + link.nHeight = storage.nHeight; + link.nExpireTime = storage.nExpireTime; + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + + record.LinkID = linkID; + record.fRequestFromMe = fIsLinkFromMe; + if (record.nHeightAccept > 0) { + record.nLinkState = 2; + } + else { + record.nLinkState = 1; + } + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RequestorPubKey = link.RequestorPubKey; + record.SharedRequestPubKey = link.SharedPubKey; + record.LinkMessage = link.LinkMessage; + record.nHeightRequest = link.nHeight; + record.nExpireTimeRequest = link.nExpireTime; + record.txHashRequest = link.txHash; + record.RequestorWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- link request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Encrypted link request for me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else { + LogPrintf("%s -- Link request GetBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link request DecryptBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link request GetLinkPrivateKey failed.\n", __func__); + return false; + } + } + else if (storage.nType == 2 && fIsLinkFromMe) // Link accept from me + { + //LogPrintf("%s -- Version 1 encrypted link accept from me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); + CKeyEd25519 privDHTKey; + CKeyID keyID(Hash160(storage.vchLinkPubKey.begin(), storage.vchLinkPubKey.end())); + if (pwalletMain->GetDHTKey(keyID, privDHTKey)) { + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + std::string strMessage = ""; + std::vector dataDecrypted; + if (DecryptBDAPData(privDHTKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { + std::vector vchData, vchHash; + CScript scriptData; + scriptData << OP_RETURN << dataDecrypted; + if (GetBDAPData(scriptData, vchData, vchHash)) { + CLinkAccept link(dataDecrypted, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + CDomainEntry entry; + if (!GetDomainEntry(link.RecipientFullObjectPath, entry)) { + LogPrintf("%s -- Failed to get link recipient %s\n", __func__, stringFromVch(link.RecipientFullObjectPath)); + return false; + } + if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RequestorFQDN(), link.SignatureProof)) { + LogPrintf("%s ***** Warning. Link accept found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + return false; + } + link.nHeight = storage.nHeight; + link.nExpireTime = storage.nExpireTime; + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fRequestFromMe = (fIsLinkFromMe && fIsLinkForMe); + record.fAcceptFromMe = fIsLinkFromMe; + record.nLinkState = 2; + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RecipientPubKey = link.RecipientPubKey; + record.SharedAcceptPubKey = link.SharedPubKey; + record.nHeightAccept = link.nHeight; + record.nExpireTimeAccept = link.nExpireTime; + record.txHashAccept = link.txHash; + record.RecipientWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- accept request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Encrypted link accept from me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else { + LogPrintf("%s -- Link accept GetBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link accept DecryptBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link accept GetDHTKey failed.\n", __func__); + return false; + } + } + else if (storage.nType == 2 && !fIsLinkFromMe && fIsLinkForMe) // Link accept for me + { + //LogPrintf("%s -- Version 1 link accept for me found! vchLinkPubKey = %s\n", __func__, stringFromVch(storage.vchLinkPubKey)); + CKeyEd25519 sharedDHTKey; + std::array sharedSeed; + std::string strErrorMessage; + if (GetLinkPrivateKey(storage.vchLinkPubKey, storage.vchSharedPubKey, sharedSeed, strErrorMessage)) { + CKeyEd25519 sharedKey(sharedSeed); + std::vector vchData = RemoveVersionFromLinkData(storage.vchRawData, nDataVersion); + std::string strMessage = ""; + std::vector dataDecrypted; + if (DecryptBDAPData(sharedKey.GetPrivSeedBytes(), vchData, dataDecrypted, strMessage)) { + std::vector vchData, vchHash; + CScript scriptData; + scriptData << OP_RETURN << dataDecrypted; + if (GetBDAPData(scriptData, vchData, vchHash)) { + CLinkAccept link(dataDecrypted, storage.txHash); + LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + CDomainEntry entry; + if (!GetDomainEntry(link.RecipientFullObjectPath, entry)) { + LogPrintf("%s -- Failed to get link recipient %s\n", __func__, stringFromVch(link.RecipientFullObjectPath)); + return false; + } + if (!SignatureProofIsValid(entry.GetWalletAddress(), link.RequestorFQDN(), link.SignatureProof)) { + LogPrintf("%s ***** Warning. Link accept found with an invalid signature proof! Link requestor = %s, recipient = %s, pubkey = %s\n", __func__, link.RequestorFQDN(), link.RecipientFQDN(), stringFromVch(storage.vchLinkPubKey)); + return false; + } + link.nHeight = storage.nHeight; + link.nExpireTime = storage.nExpireTime; + uint256 linkID = GetLinkID(link); + CLink record; + std::map::iterator it = m_Links.find(linkID); + if (it != m_Links.end()) { + record = it->second; + } + record.LinkID = linkID; + record.fAcceptFromMe = fIsLinkFromMe; + record.nLinkState = 2; + record.RequestorFullObjectPath = link.RequestorFullObjectPath; + record.RecipientFullObjectPath = link.RecipientFullObjectPath; + record.RecipientPubKey = link.RecipientPubKey; + record.SharedAcceptPubKey = link.SharedPubKey; + record.nHeightAccept = link.nHeight; + record.nExpireTimeAccept = link.nExpireTime; + record.txHashAccept = link.txHash; + record.RecipientWalletAddress = entry.WalletAddress; + if (record.SharedAcceptPubKey.size() > 0 && record.SharedRequestPubKey.size() > 0) + { + std::string strErrorMessage = ""; + if (!GetMessageInfo(record, strErrorMessage)) + { + LogPrintf("%s -- Error getting message info %s\n", __func__, strErrorMessage); + } + else + { + pwalletMain->WriteLinkMessageInfo(record.SubjectID, record.vchSecretPubKeyBytes); + m_LinkMessageInfo[record.SubjectID] = record.vchSecretPubKeyBytes; + } + //LogPrintf("%s -- accept request = %s\n", __func__, record.ToString()); + } + LogPrint("bdap", "%s -- Encrypted link accept for me added to map id = %s\n%s\n", __func__, linkID.ToString(), record.ToString()); + m_Links[linkID] = record; + } + else { + LogPrintf("%s -- Link accept GetBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link accept DecryptBDAPData failed.\n", __func__); + return false; + } + } + else { + LogPrintf("%s -- Link accept GetLinkPrivateKey failed.\n", __func__); + return false; + } + } + else + { + linkQueue.push(storage); + } + } + return true; +#endif // ENABLE_WALLET +} + +std::vector CLinkManager::GetCompletedLinkInfo(const std::vector& vchFullObjectPath) +{ + std::vector vchLinkInfo; + for(const std::pair& link : m_Links) + { + if (link.second.nLinkState == 2) // completed link + { + if (link.second.RequestorFullObjectPath == vchFullObjectPath) + { + CLinkInfo linkInfo(link.second.RecipientFullObjectPath, link.second.RecipientPubKey, link.second.RequestorPubKey); + vchLinkInfo.push_back(linkInfo); + } + else if (link.second.RecipientFullObjectPath == vchFullObjectPath) + { + CLinkInfo linkInfo(link.second.RequestorFullObjectPath, link.second.RequestorPubKey, link.second.RecipientPubKey); + vchLinkInfo.push_back(linkInfo); + } + } + } + return vchLinkInfo; +} + +int CLinkManager::IsMyMessage(const uint256& subjectID, const uint256& messageID, const int64_t& timestamp) +{ + std::vector vchPubKey; + if (GetLinkMessageInfo(subjectID, vchPubKey)) + { + if (messageID != GetMessageID(vchPubKey, timestamp)) + { + // Incorrect message id. Might be spoofed. + return -100; + } + return 1; + } + return 0; +} + +void CLinkManager::LoadLinkMessageInfo(const uint256& subjectID, const std::vector& vchPubKey) +{ + if (m_LinkMessageInfo.count(subjectID) == 0) + m_LinkMessageInfo[subjectID] = vchPubKey; +} + +bool CLinkManager::GetLinkMessageInfo(const uint256& subjectID, std::vector& vchPubKey) +{ + std::map>::iterator it = m_LinkMessageInfo.find(subjectID); + if (it != m_LinkMessageInfo.end()) { + vchPubKey = it->second; + return true; // found subjectID + } + return false; // doesn't exist +} + +uint256 GetLinkID(const CLinkRequest& request) +{ + std::vector vchLinkPath = request.LinkPath(); + return Hash(vchLinkPath.begin(), vchLinkPath.end()); +} + +uint256 GetLinkID(const CLinkAccept& accept) +{ + std::vector vchLinkPath = accept.LinkPath(); + return Hash(vchLinkPath.begin(), vchLinkPath.end()); +} + +uint256 GetLinkID(const std::string& account1, const std::string& account2) +{ + if (account1 != account2) { + std::vector vchSeparator = {':'}; + std::set sorted; + sorted.insert(account1); + sorted.insert(account2); + std::set::iterator it = sorted.begin(); + std::vector vchLink1 = vchFromString(*it); + std::advance(it, 1); + std::vector vchLink2 = vchFromString(*it); + vchLink1.insert(vchLink1.end(), vchSeparator.begin(), vchSeparator.end()); + vchLink1.insert(vchLink1.end(), vchLink2.begin(), vchLink2.end()); + return Hash(vchLink1.begin(), vchLink1.end()); + } + return uint256(); +} + +#ifdef ENABLE_WALLET +bool GetSharedPrivateSeed(const CLink& link, std::array& seed, std::string& strErrorMessage) +{ + if (!pwalletMain) + return false; + + if (link.nLinkState != 2) + return false; + + //LogPrint("bdap", "%s -- %s\n", __func__, link.ToString()); + std::array sharedSeed1; + std::array sharedSeed2; + CDomainEntry entry; + if (pDomainEntryDB->GetDomainEntryInfo(link.RecipientFullObjectPath, entry)) { + if (link.fRequestFromMe) // Requestor + { + // first key exchange: requestor link pubkey + recipient account pubkey + std::vector vchRecipientPubKey = entry.DHTPublicKey; + std::vector vchRequestorPubKey = link.RequestorPubKey; + CKeyEd25519 reqKey; + CKeyID reqKeyID(Hash160(vchRequestorPubKey.begin(), vchRequestorPubKey.end())); + if (pwalletMain->GetDHTKey(reqKeyID, reqKey)) { + std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(reqKey, vchRecipientPubKey); + if (link.SharedRequestPubKey == vchGetLinkSharedPubKey) + { + sharedSeed1 = GetLinkSharedPrivateKey(reqKey, vchRecipientPubKey); + } + else + { + strErrorMessage = strprintf("Requestor SharedRequestPubKey (%s) does not match derived shared request public key (%s).", + stringFromVch(link.SharedRequestPubKey), stringFromVch(vchGetLinkSharedPubKey)); + return false; + } + } + else { + strErrorMessage = strprintf("Failed to get reqKey %s DHT private key.", stringFromVch(vchRequestorPubKey)); + return false; + } + // second key exchange: recipient link pubkey + requestor account pubkey + CDomainEntry entryRequestor; + if (pDomainEntryDB->GetDomainEntryInfo(link.RequestorFullObjectPath, entryRequestor)) + { + std::vector vchReqPubKey = entryRequestor.DHTPublicKey; + std::vector vchLinkPubKey = link.RecipientPubKey; + CKeyEd25519 linkKey; + CKeyID linkKeyID(Hash160(vchReqPubKey.begin(), vchReqPubKey.end())); + if (pwalletMain->GetDHTKey(linkKeyID, linkKey)) { + std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(linkKey, vchLinkPubKey); + if (link.SharedAcceptPubKey == vchGetLinkSharedPubKey) + { + sharedSeed2 = GetLinkSharedPrivateKey(linkKey, vchLinkPubKey); + } + else + { + strErrorMessage = strprintf("Requestor SharedAcceptPubKey (%s) does not match derived shared link public key (%s).", + stringFromVch(link.SharedAcceptPubKey), stringFromVch(vchGetLinkSharedPubKey)); + return false; + } + } + else { + strErrorMessage = strprintf("Failed to get requestor link Key %s DHT private key.", stringFromVch(vchLinkPubKey)); + return false; + } + } + else + { + strErrorMessage = strprintf("Can not find %s link requestor record.", stringFromVch(link.RequestorFullObjectPath)); + return false; + } + } + else // Recipient + { + // first key exchange: requestor link pubkey + recipient account pubkey + std::vector vchRecipientPubKey = entry.DHTPublicKey; + std::vector vchRequestorPubKey = link.RequestorPubKey; + CKeyEd25519 recKey; + CKeyID recKeyID(Hash160(vchRecipientPubKey.begin(), vchRecipientPubKey.end())); + if (pwalletMain->GetDHTKey(recKeyID, recKey)) + { + std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(recKey, vchRequestorPubKey); + if (link.SharedRequestPubKey == vchGetLinkSharedPubKey) { + sharedSeed1 = GetLinkSharedPrivateKey(recKey, vchRequestorPubKey); + } + else + { + strErrorMessage = strprintf("Recipient SharedRequestPubKey (%s) does not match derived shared request public key (%s).", + stringFromVch(link.SharedRequestPubKey), stringFromVch(vchGetLinkSharedPubKey)); + return false; + } + } + else { + strErrorMessage = strprintf("Failed to get recKey %s DHT private key.", stringFromVch(vchRecipientPubKey)); + return false; + } + // second key exchange: recipient link pubkey + requestor account pubkey + CDomainEntry entryRequestor; + if (pDomainEntryDB->GetDomainEntryInfo(link.RequestorFullObjectPath, entryRequestor)) + { + std::vector vchLinkPubKey = link.RecipientPubKey; + std::vector vchReqPubKey = entryRequestor.DHTPublicKey; + CKeyEd25519 linkKey; + CKeyID linkKeyID(Hash160(vchLinkPubKey.begin(), vchLinkPubKey.end())); + if (pwalletMain->GetDHTKey(linkKeyID, linkKey)) + { + std::vector vchGetLinkSharedPubKey = GetLinkSharedPubKey(linkKey, vchReqPubKey); + if (link.SharedAcceptPubKey == vchGetLinkSharedPubKey) { + sharedSeed2 = GetLinkSharedPrivateKey(linkKey, vchReqPubKey); + } + else + { + strErrorMessage = strprintf("Recipient SharedAcceptPubKey (%s) does not match derived shared link public key (%s).", + stringFromVch(link.SharedAcceptPubKey), stringFromVch(vchGetLinkSharedPubKey)); + return false; + } + } + else { + strErrorMessage = strprintf("Failed to get recipient linkKey %s DHT private key.", stringFromVch(vchLinkPubKey)); + return false; + } + } + else + { + strErrorMessage = strprintf("Can not find %s link requestor record.", stringFromVch(link.RequestorFullObjectPath)); + return false; + } + } + } + else + { + strErrorMessage = strprintf("Can not find %s link recipient record.", stringFromVch(link.RecipientFullObjectPath)); + return false; + } + CKeyEd25519 sharedKey1(sharedSeed1); + CKeyEd25519 sharedKey2(sharedSeed2); + // third key exchange: shared link request pubkey + shared link accept pubkey + // Only the link recipient and requestor can derive this secret key. + // the third shared public key is not on the blockchain and should only be known by the participants. + seed = GetLinkSharedPrivateKey(sharedKey1, sharedKey2.GetPubKey()); + return true; +} + +bool GetMessageInfo(CLink& link, std::string& strErrorMessage) +{ + std::array seed; + if (!GetSharedPrivateSeed(link, seed, strErrorMessage)) + { + return false; + } + CKeyEd25519 key(seed); + link.vchSecretPubKeyBytes = key.GetPubKeyBytes(); + link.SubjectID = Hash(link.vchSecretPubKeyBytes.begin(), link.vchSecretPubKeyBytes.end()); + return true; +} +#endif // ENABLE_WALLET + +uint256 GetMessageID(const std::vector& vchPubKey, const int64_t& timestamp) +{ + CScript scriptMessage; + scriptMessage << vchPubKey << timestamp; + return Hash(scriptMessage.begin(), scriptMessage.end()); +} + +uint256 GetMessageID(const CKeyEd25519& key, const int64_t& timestamp) +{ + return GetMessageID(key.GetPubKeyBytes(), timestamp); +} + +//#endif // ENABLE_WALLET \ No newline at end of file diff --git a/src/bdap/linkmanager.h b/src/bdap/linkmanager.h new file mode 100644 index 0000000000..d559c0a436 --- /dev/null +++ b/src/bdap/linkmanager.h @@ -0,0 +1,189 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_LINKMANAGER_H +#define DYNAMIC_BDAP_LINKMANAGER_H + +#include "bdap/linkstorage.h" +#include "uint256.h" + +#include +#include +#include +#include +#include + +class CKeyEd25519; +class CLinkRequest; +class CLinkAccept; + +namespace BDAP { + + enum LinkState : std::uint8_t + { + unknown_state = 0, + pending_state = 1, + complete_state = 2, + deleted_state = 3 + }; +} + +class CLink { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + uint256 LinkID; + bool fRequestFromMe; + bool fAcceptFromMe; + uint8_t nLinkState; + std::vector RequestorFullObjectPath; // Requestor's BDAP object path + std::vector RecipientFullObjectPath; // Recipient's BDAP object path + std::vector RequestorPubKey; // ed25519 public key new/unique for this link + std::vector RecipientPubKey; // ed25519 public key new/unique for this link + std::vector SharedRequestPubKey; // ed25519 shared public key. RequestorPubKey + Recipient's BDAP DHT PubKey + std::vector SharedAcceptPubKey; // ed25519 shared public key. RecipientPubKey + RequestorPubKey's BDAP DHT PubKey + std::vector LinkMessage; // Link message to recipient + std::vector RequestorWalletAddress; // Requestor's BDAP wallet address + std::vector RecipientWalletAddress; // Recipient's BDAP wallet address + + uint64_t nHeightRequest; + uint64_t nExpireTimeRequest; + uint256 txHashRequest; + + uint64_t nHeightAccept; + uint64_t nExpireTimeAccept; + uint256 txHashAccept; + + + uint256 SubjectID; // Used to tell when a VGP message is for this link + std::vector vchSecretPubKeyBytes; // Used to derive the VGP message id for this link + + CLink() { + SetNull(); + } + + inline void SetNull() + { + nVersion = CLink::CURRENT_VERSION; + LinkID.SetNull(); + nLinkState = 0; + fRequestFromMe = false; + fAcceptFromMe = false; + RequestorFullObjectPath.clear(); + RecipientFullObjectPath.clear(); + RequestorPubKey.clear(); + RecipientPubKey.clear(); + SharedRequestPubKey.clear(); + SharedAcceptPubKey.clear(); + LinkMessage.clear(); + nHeightRequest = 0; + nExpireTimeRequest = 0; + txHashRequest.SetNull(); + nHeightAccept = 0; + nExpireTimeAccept = 0; + txHashAccept.SetNull(); + SubjectID.SetNull(); + vchSecretPubKeyBytes.clear(); + RequestorWalletAddress.clear(); + RecipientWalletAddress.clear(); + } + + inline friend bool operator==(const CLink &a, const CLink &b) { + return (a.txHashRequest == b.txHashRequest && a.txHashAccept == b.txHashAccept); + } + + inline friend bool operator!=(const CLink &a, const CLink &b) { + return !(a == b); + } + + inline CLink operator=(const CLink &b) { + nVersion = b.nVersion; + LinkID = b.LinkID; + nLinkState = b.nLinkState; + fRequestFromMe = b.fRequestFromMe; + fAcceptFromMe = b.fAcceptFromMe; + RequestorFullObjectPath = b.RequestorFullObjectPath; + RecipientFullObjectPath = b.RecipientFullObjectPath; + RequestorPubKey = b.RequestorPubKey; + RecipientPubKey = b.RecipientPubKey; + SharedRequestPubKey = b.SharedRequestPubKey; + SharedAcceptPubKey = b.SharedAcceptPubKey; + LinkMessage = b.LinkMessage; + nHeightRequest = b.nHeightRequest; + nExpireTimeRequest = b.nExpireTimeRequest; + txHashRequest = b.txHashRequest; + nHeightAccept = b.nHeightAccept; + nExpireTimeAccept = b.nExpireTimeAccept; + txHashAccept = b.txHashAccept; + SubjectID = b.SubjectID; + vchSecretPubKeyBytes = b.vchSecretPubKeyBytes; + RequestorWalletAddress = b.RequestorWalletAddress; + RecipientWalletAddress = b.RecipientWalletAddress; + return *this; + } + + std::string RequestorFQDN() const; + std::string RecipientFQDN() const; + std::string RequestorPubKeyString() const; + std::string RecipientPubKeyString() const; + + inline bool IsNull() const { return (nLinkState == 0 && RequestorFullObjectPath.empty() && RecipientFullObjectPath.empty()); } + + std::string LinkState() const; + std::string ToString() const; +}; + +class CLinkManager { +private: + std::queue linkQueue; + std::map m_Links; + std::map> m_LinkMessageInfo; + +public: + CLinkManager() { + SetNull(); + } + + inline void SetNull() + { + std::queue emptyQueue; + linkQueue = emptyQueue; + m_Links.clear(); + } + + std::size_t QueueSize() const { return linkQueue.size(); } + std::size_t LinkCount() const { return m_Links.size(); } + + bool ProcessLink(const CLinkStorage& storage, const bool fStoreInQueueOnly = false); + void ProcessQueue(); + + bool FindLink(const uint256& id, CLink& link); + bool FindLinkBySubjectID(const uint256& subjectID, CLink& getLink); + bool ListMyPendingRequests(std::vector& vchLinks); + bool ListMyPendingAccepts(std::vector& vchLinks); + bool ListMyCompleted(std::vector& vchLinks); + std::vector GetCompletedLinkInfo(const std::vector& vchFullObjectPath); + int IsMyMessage(const uint256& subjectID, const uint256& messageID, const int64_t& timestamp); + void LoadLinkMessageInfo(const uint256& subjectID, const std::vector& vchPubKey); + bool GetLinkMessageInfo(const uint256& subjectID, std::vector& vchPubKey); + bool GetAllMessagesByType(const std::vector vchMessageType); + +private: + bool IsLinkFromMe(const std::vector& vchLinkPubKey); + bool IsLinkForMe(const std::vector& vchLinkPubKey, const std::vector& vchSharedPubKey); + bool GetLinkPrivateKey(const std::vector& vchSenderPubKey, const std::vector& vchSharedPubKey, std::array& sharedSeed, std::string& strErrorMessage); +}; + +uint256 GetLinkID(const CLinkRequest& request); +uint256 GetLinkID(const CLinkAccept& accept); +uint256 GetLinkID(const std::string& account1, const std::string& account2); + +bool GetSharedPrivateSeed(const CLink& link, std::array& seed, std::string& strErrorMessage); +bool GetMessageInfo(CLink& link, std::string& strErrorMessage); +uint256 GetMessageID(const std::vector& vchPubKey, const int64_t& timestamp); +uint256 GetMessageID(const CKeyEd25519& key, const int64_t& timestamp); + +extern CLinkManager* pLinkManager; + +#endif // DYNAMIC_BDAP_LINKMANAGER_H \ No newline at end of file diff --git a/src/bdap/linkstorage.cpp b/src/bdap/linkstorage.cpp new file mode 100644 index 0000000000..8971f85717 --- /dev/null +++ b/src/bdap/linkstorage.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/linkstorage.h" + +#include "bdap/linkmanager.h" +#include "bdap/utils.h" +#include "hash.h" +#include "serialize.h" +#include "streams.h" +#include "tinyformat.h" +#include "version.h" + +void ProcessLink(const CLinkStorage& storage, const bool fStoreInQueueOnly) +{ + if (!pLinkManager) + throw std::runtime_error("pLinkManager is null.\n"); + + pLinkManager->ProcessLink(storage, fStoreInQueueOnly); +} + +void ProcessLinkQueue() +{ + if (!pLinkManager) + throw std::runtime_error("pLinkManager is null.\n"); + + pLinkManager->ProcessQueue(); +} + +void LoadLinkMessageInfo(const uint256& subjectID, const std::vector& vchPubKey) +{ + if (!pLinkManager) + throw std::runtime_error("pLinkManager is null.\n"); + + pLinkManager->LoadLinkMessageInfo(subjectID, vchPubKey); +} + +void CLinkStorage::Serialize(std::vector& vchData) +{ + CDataStream dsLinkStorage(SER_NETWORK, PROTOCOL_VERSION); + dsLinkStorage << *this; + vchData = std::vector(dsLinkStorage.begin(), dsLinkStorage.end()); +} + +bool CLinkStorage::UnserializeFromData(const std::vector& vchData) +{ + try { + CDataStream dsLinkStorage(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsLinkStorage >> *this; + std::vector vchLinkData; + Serialize(vchLinkData); + } catch (std::exception& e) { + SetNull(); + return false; + } + return true; +} + +int CLinkStorage::DataVersion() const +{ + if (vchRawData.size() == 0) + return -1; + + return GetLinkVersionFromData(vchRawData); +} + +bool CLinkStorage::Encrypted() const +{ + if (DataVersion() == 0 || vchRawData.size() == 0) + return false; + + return true; +} + +std::string CLinkInfo::ToString() const +{ + return strprintf("CLinkInfo(version=%u, full_path=%s, sender_pubkey=%s, receive_pubkey=%s)\n", + nVersion, stringFromVch(vchFullObjectPath), stringFromVch(vchSenderPubKey), stringFromVch(vchReceivePubKey)); +} + diff --git a/src/bdap/linkstorage.h b/src/bdap/linkstorage.h new file mode 100644 index 0000000000..290ba0c88d --- /dev/null +++ b/src/bdap/linkstorage.h @@ -0,0 +1,143 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_LINKSTORAGE_H +#define DYNAMIC_BDAP_LINKSTORAGE_H + +#include "serialize.h" +#include "uint256.h" + +#include +#include + +namespace BDAP { + + enum LinkType : std::uint8_t + { + UnknownType = 0, + RequestType = 1, + AcceptType = 2 + }; +} + +class CLinkStorage { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + std::vector vchRawData; + std::vector vchLinkPubKey; + std::vector vchSharedPubKey; + uint8_t nType; + uint64_t nHeight; + uint64_t nExpireTime; + uint64_t nTime; + uint256 txHash; + + CLinkStorage() + { + SetNull(); + } + + CLinkStorage(const std::vector& data, const std::vector& pubkey, const std::vector& sharedPubkey, const uint8_t type, + const uint64_t& height, const uint64_t& expire, const uint64_t& time, const uint256& txid) + : vchRawData(data), vchLinkPubKey(pubkey), vchSharedPubKey(sharedPubkey), nType(type), nHeight(height), nExpireTime(expire), nTime(time), txHash(txid) + { + } + + inline void SetNull() + { + nVersion = CLinkStorage::CURRENT_VERSION; + vchRawData.clear(); + vchLinkPubKey.clear(); + vchSharedPubKey.clear(); + nType = 0; + nHeight = 0; + nExpireTime = 0; + nTime = 0; + txHash.SetNull(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(vchRawData); + READWRITE(vchLinkPubKey); + READWRITE(vchSharedPubKey); + READWRITE(VARINT(nType)); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(VARINT(nTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CLinkStorage& a, const CLinkStorage& b) { + return (a.vchRawData == b.vchRawData && a.txHash == b.txHash); + } + + inline friend bool operator!=(const CLinkStorage& a, const CLinkStorage& b) { + return !(a == b); + } + + inline CLinkStorage operator=(const CLinkStorage& b) { + nVersion = b.nVersion; + vchRawData = b.vchRawData; + vchLinkPubKey = b.vchLinkPubKey; + vchSharedPubKey = b.vchSharedPubKey; + nType = b.nType; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + nTime = b.nTime; + txHash = b.txHash; + return *this; + } + + bool UnserializeFromData(const std::vector& vchData); + void Serialize(std::vector& vchData); + + inline bool IsNull() const { return (vchRawData.empty()); } + bool Encrypted() const; + int DataVersion() const; + +}; + +class CLinkInfo { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + std::vector vchFullObjectPath; + std::vector vchSenderPubKey; + std::vector vchReceivePubKey; + std::array arrReceivePrivateSeed; + + CLinkInfo() + { + SetNull(); + } + + CLinkInfo(const std::vector& fqdn, const std::vector& send_pubkey, const std::vector& receive_pubkey) + : vchFullObjectPath(fqdn), vchSenderPubKey(send_pubkey), vchReceivePubKey(receive_pubkey) + { + arrReceivePrivateSeed.fill(0); + } + + inline void SetNull() + { + nVersion = CLinkStorage::CURRENT_VERSION; + vchFullObjectPath.clear(); + vchSenderPubKey.clear(); + vchReceivePubKey.clear(); + arrReceivePrivateSeed.fill(0); + } + + std::string ToString() const; + +}; + +void ProcessLink(const CLinkStorage& storage, const bool fStoreInQueueOnly = false); +void ProcessLinkQueue(); +void LoadLinkMessageInfo(const uint256& subjectID, const std::vector& vchPubKey); + +#endif // DYNAMIC_BDAP_LINKSTORAGE_H \ No newline at end of file diff --git a/src/bdap/sidechain.cpp b/src/bdap/sidechain.cpp new file mode 100644 index 0000000000..d6256e8f40 --- /dev/null +++ b/src/bdap/sidechain.cpp @@ -0,0 +1,85 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/sidechain.h" + +#include "bdap/utils.h" +#include "hash.h" +#include "script/script.h" +#include "streams.h" + +void CSideChain::Serialize(std::vector& vchData) +{ + CDataStream dsSideChain(SER_NETWORK, PROTOCOL_VERSION); + dsSideChain << *this; + vchData = std::vector(dsSideChain.begin(), dsSideChain.end()); +} + +bool CSideChain::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsSideChain(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsSideChain >> *this; + + std::vector vchSideChainData; + Serialize(vchSideChainData); + const uint256 &calculatedHash = Hash(vchSideChainData.begin(), vchSideChainData.end()); + const std::vector &vchRandSideChain = vchFromValue(calculatedHash.GetHex()); + if(vchRandSideChain != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CSideChain::UnserializeFromTx(const CTransactionRef& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetBDAPData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +bool CSideChain::ValidateValues(std::string& errorMessage) +{ + // check sidechain owner path + std::string strOwnerFullPath = stringFromVch(OwnerFullPath); + if (strOwnerFullPath.length() > MAX_OBJECT_FULL_PATH_LENGTH) // object + { + errorMessage = "Invalid BDAP owner full path name. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + + // check sidechain description + std::string strDescription = stringFromVch(Description); + if (strDescription.length() > MAX_DESCRIPTION_LENGTH) + { + errorMessage = "Invalid sidechain description. Can not have more than " + std::to_string(MAX_DESCRIPTION_LENGTH) + " characters."; + return false; + } + + // check sidechain resource pointer + std::string strResourcePointer = stringFromVch(ResourcePointer); + if (strResourcePointer.length() > MAX_RESOURCE_POINTER_LENGTH) // object + { + errorMessage = "Invalid BDAP resource pointer. Can not have more than " + std::to_string(MAX_RESOURCE_POINTER_LENGTH) + " characters."; + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/bdap/sidechain.h b/src/bdap/sidechain.h new file mode 100644 index 0000000000..8cafecc838 --- /dev/null +++ b/src/bdap/sidechain.h @@ -0,0 +1,118 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_SIDECHAIN_H +#define DYNAMIC_BDAP_SIDECHAIN_H + +#include "amount.h" +#include "bdap.h" +#include "bdap/domainentry.h" +#include "serialize.h" +#include "uint256.h" + +class CTransaction; + +enum ResourcePointerType { + OTHER = 0, + IPFS = 1, + LIBTORRENT = 2, + CLOUDSTORAGE = 3 +}; + +class CSideChain { +public: + static const int CURRENT_VERSION = 1; + int nVersion; + CharString OwnerFullPath; // name of the owner's full domain entry path + CharString Description; + CharString ResourcePointer; // used to point to a domain shared resource like a stream (video, audio, file sharing), P2P storage (LibTorrent or IPFS network), or private cloud storage + ResourcePointerType ResourceType; + CAmount InitialTransactionFee; + CAmount InitialRegistrationFeePerDay; + CAmount InitialSupply; + CAmount InitialBlockReward; + unsigned int nTargetSpacing; + unsigned int nHeight; + uint64_t nExpireTime; + + uint256 txHash; + + CDomainEntry* OwnerDomainEntry; + + CSideChain() { + SetNull(); + } + + CSideChain(const CTransactionRef& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CSideChain::CURRENT_VERSION; + OwnerFullPath.clear(); + Description.clear(); + ResourcePointer.clear(); + ResourceType = ResourcePointerType::OTHER; + InitialTransactionFee = 0; + InitialRegistrationFeePerDay = 0; + InitialSupply = 0; + nTargetSpacing = 0; + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + OwnerDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(OwnerFullPath); + READWRITE(Description); + READWRITE(ResourcePointer); + //READWRITE(ResourceType); //TODO: (bdap) serialize this enum. + READWRITE(InitialTransactionFee); + READWRITE(InitialRegistrationFeePerDay); + READWRITE(InitialSupply); + READWRITE(VARINT(nTargetSpacing)); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CSideChain& a, const CSideChain& b) { + return (a.OwnerFullPath == b.OwnerFullPath && a.ResourcePointer == b.ResourcePointer && a.Description == b.Description && a.nHeight == b.nHeight); + } + + inline friend bool operator!=(const CSideChain& a, const CSideChain& b) { + return !(a == b); + } + + inline CSideChain operator=(const CSideChain& b) { + OwnerFullPath = b.OwnerFullPath; + Description = b.Description; + ResourcePointer = b.ResourcePointer; + ResourceType = b.ResourceType; + InitialTransactionFee = b.InitialTransactionFee; + InitialRegistrationFeePerDay = b.InitialRegistrationFeePerDay; + InitialSupply = b.InitialSupply; + nTargetSpacing = b.nTargetSpacing; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (OwnerFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransactionRef& tx); + + bool ValidateValues(std::string& errorMessage); +}; + +#endif // DYNAMIC_BDAP_SIDECHAIN_H \ No newline at end of file diff --git a/src/bdap/stealth.cpp b/src/bdap/stealth.cpp new file mode 100644 index 0000000000..f18285ca6f --- /dev/null +++ b/src/bdap/stealth.cpp @@ -0,0 +1,523 @@ +// Copyright (c) 2019-2021 Duality Blockchain Solutions Developers +// Copyright (c) 2017-2018 The Particl Core developers +// Copyright (c) 2014 The ShadowCoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include