diff options
-rw-r--r-- | .travis.yml | 4 | ||||
-rw-r--r-- | ci/test/00_setup_env_arm.sh | 5 | ||||
-rwxr-xr-x | ci/test/06_script_b.sh | 20 | ||||
-rw-r--r-- | doc/benchmarking.md | 2 | ||||
-rw-r--r-- | src/compat/stdin.cpp | 2 | ||||
-rw-r--r-- | src/psbt.h | 29 | ||||
-rw-r--r-- | src/qt/transactionrecord.cpp | 10 | ||||
-rw-r--r-- | src/qt/transactiontablemodel.cpp | 1 | ||||
-rw-r--r-- | test/functional/data/rpc_psbt.json | 10 |
9 files changed, 63 insertions, 20 deletions
diff --git a/.travis.yml b/.travis.yml index 0810e7ef3c..f59c7fc7e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -111,12 +111,12 @@ jobs: - set -o errexit; source ./ci/lint/06_script.sh - stage: test - name: 'ARM [GOAL: install] [no unit or functional tests]' + name: 'ARM [GOAL: install] [unit tests, no functional tests]' env: >- FILE_ENV="./ci/test/00_setup_env_arm.sh" - stage: test - name: 'Win64 [GOAL: deploy] [no gui or functional tests]' + name: 'Win64 [GOAL: deploy] [unit tests, no gui, no functional tests]' env: >- FILE_ENV="./ci/test/00_setup_env_win64.sh" diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh index db640015b1..9335f0b337 100644 --- a/ci/test/00_setup_env_arm.sh +++ b/ci/test/00_setup_env_arm.sh @@ -7,9 +7,10 @@ export LC_ALL=C.UTF-8 export HOST=arm-linux-gnueabihf -export PACKAGES="python3 g++-arm-linux-gnueabihf busybox" +export QEMU_USER_CMD="qemu-arm -L /usr/arm-linux-gnueabihf/" +export PACKAGES="python3 g++-arm-linux-gnueabihf busybox qemu-user" export USE_BUSY_BOX=true -export RUN_UNIT_TESTS=false +export RUN_UNIT_TESTS=true export RUN_FUNCTIONAL_TESTS=false export GOAL="install" # -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1" diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh index ea7beae85f..1a5217277a 100755 --- a/ci/test/06_script_b.sh +++ b/ci/test/06_script_b.sh @@ -8,8 +8,28 @@ export LC_ALL=C.UTF-8 cd "build/bitcoin-$HOST" || (echo "could not enter distdir build/bitcoin-$HOST"; exit 1) +if [ -n "$QEMU_USER_CMD" ]; then + BEGIN_FOLD wrap-qemu + echo "Prepare to run functional tests for HOST=$HOST" + # Generate all binaries, so that they can be wrapped + DOCKER_EXEC make $MAKEJOBS -C src/secp256k1 VERBOSE=1 + DOCKER_EXEC make $MAKEJOBS -C src/univalue VERBOSE=1 + for b_name in {"${BASE_OUTDIR}/bin"/*,src/secp256k1/*tests,src/univalue/{no_nul,test_json,unitester,object}}; do + # shellcheck disable=SC2044 + for b in $(find "${BASE_ROOT_DIR}" -executable -type f -name $(basename $b_name)); do + echo "Wrap $b ..." + DOCKER_EXEC mv "$b" "${b}_orig" + DOCKER_EXEC echo "\#\!/usr/bin/env bash" \> "$b" + DOCKER_EXEC echo "$QEMU_USER_CMD \\\"${b}_orig\\\" \\\"\\\$@\\\"" \>\> "$b" + DOCKER_EXEC chmod +x "$b" + done + done + END_FOLD +fi + if [ "$RUN_UNIT_TESTS" = "true" ]; then BEGIN_FOLD unit-tests + bash -c "while sleep 500; do echo .; done" & # Print dots in case the unit tests take a long time to run DOCKER_EXEC LD_LIBRARY_PATH=$BASE_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1 END_FOLD fi diff --git a/doc/benchmarking.md b/doc/benchmarking.md index 8e3d88ab7a..b1a06009b5 100644 --- a/doc/benchmarking.md +++ b/doc/benchmarking.md @@ -11,7 +11,7 @@ Running For benchmarks purposes you only need to compile `bitcoin_bench`. Beware of configuring without `--enable-debug` as this would impact benchmarking by unlatching log printers and lock analysis. - make -C src bench_bitcoin + make -C src bitcoin_bench After compiling bitcoin-core, the benchmarks can be run with: diff --git a/src/compat/stdin.cpp b/src/compat/stdin.cpp index 4f2ba1e9c4..98d406cca8 100644 --- a/src/compat/stdin.cpp +++ b/src/compat/stdin.cpp @@ -14,7 +14,7 @@ #else #include <termios.h> // for SetStdinEcho() #include <unistd.h> // for SetStdinEcho(), isatty() -#include <sys/poll.h> // for StdinReady() +#include <poll.h> // for StdinReady() #endif #include <compat/stdin.h> diff --git a/src/psbt.h b/src/psbt.h index 6d77db0c6f..802a7c5ba7 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -126,6 +126,9 @@ struct PSBTInput template <typename Stream> inline void Unserialize(Stream& s) { + // Used for duplicate key detection + std::set<std::vector<unsigned char>> key_lookup; + // Read loop bool found_sep = false; while(!s.empty()) { @@ -147,7 +150,7 @@ struct PSBTInput switch(type) { case PSBT_IN_NON_WITNESS_UTXO: { - if (non_witness_utxo) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, input non-witness utxo already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Non-witness utxo key is more than one byte type"); @@ -158,7 +161,7 @@ struct PSBTInput break; } case PSBT_IN_WITNESS_UTXO: - if (!witness_utxo.IsNull()) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, input witness utxo already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Witness utxo key is more than one byte type"); @@ -189,7 +192,7 @@ struct PSBTInput break; } case PSBT_IN_SIGHASH: - if (sighash_type > 0) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, input sighash type already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Sighash type key is more than one byte type"); @@ -198,7 +201,7 @@ struct PSBTInput break; case PSBT_IN_REDEEMSCRIPT: { - if (!redeem_script.empty()) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, input redeemScript already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Input redeemScript key is more than one byte type"); @@ -208,7 +211,7 @@ struct PSBTInput } case PSBT_IN_WITNESSSCRIPT: { - if (!witness_script.empty()) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, input witnessScript already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Input witnessScript key is more than one byte type"); @@ -223,7 +226,7 @@ struct PSBTInput } case PSBT_IN_SCRIPTSIG: { - if (!final_script_sig.empty()) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, input final scriptSig already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Final scriptSig key is more than one byte type"); @@ -233,7 +236,7 @@ struct PSBTInput } case PSBT_IN_SCRIPTWITNESS: { - if (!final_script_witness.IsNull()) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, input final scriptWitness already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Final scriptWitness key is more than one byte type"); @@ -309,6 +312,9 @@ struct PSBTOutput template <typename Stream> inline void Unserialize(Stream& s) { + // Used for duplicate key detection + std::set<std::vector<unsigned char>> key_lookup; + // Read loop bool found_sep = false; while(!s.empty()) { @@ -330,7 +336,7 @@ struct PSBTOutput switch(type) { case PSBT_OUT_REDEEMSCRIPT: { - if (!redeem_script.empty()) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, output redeemScript already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Output redeemScript key is more than one byte type"); @@ -340,7 +346,7 @@ struct PSBTOutput } case PSBT_OUT_WITNESSSCRIPT: { - if (!witness_script.empty()) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, output witnessScript already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Output witnessScript key is more than one byte type"); @@ -448,6 +454,9 @@ struct PartiallySignedTransaction throw std::ios_base::failure("Invalid PSBT magic bytes"); } + // Used for duplicate key detection + std::set<std::vector<unsigned char>> key_lookup; + // Read global data bool found_sep = false; while(!s.empty()) { @@ -469,7 +478,7 @@ struct PartiallySignedTransaction switch(type) { case PSBT_GLOBAL_UNSIGNED_TX: { - if (tx) { + if (!key_lookup.emplace(key).second) { throw std::ios_base::failure("Duplicate Key, unsigned tx already provided"); } else if (key.size() != 1) { throw std::ios_base::failure("Global unsigned tx key is more than one byte type"); diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 9de90759fa..08ba030d65 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -93,10 +93,14 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface if (fAllFromMe && fAllToMe) { // Payment to self - CAmount nChange = wtx.change; + std::string address; + for (auto it = wtx.txout_address.begin(); it != wtx.txout_address.end(); ++it) { + if (it != wtx.txout_address.begin()) address += ", "; + address += EncodeDestination(*it); + } - parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", - -(nDebit - nChange), nCredit - nChange)); + CAmount nChange = wtx.change; + parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, address, -(nDebit - nChange), nCredit - nChange)); parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument } else if (fAllFromMe) diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 8d0cb54151..fed55577ca 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -394,6 +394,7 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, b case TransactionRecord::SendToOther: return QString::fromStdString(wtx->address) + watchAddress; case TransactionRecord::SendToSelf: + return lookupAddress(wtx->address, tooltip) + watchAddress; default: return tr("(n/a)") + watchAddress; } diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json index 57f2608ee9..0f6cd97fd8 100644 --- a/test/functional/data/rpc_psbt.json +++ b/test/functional/data/rpc_psbt.json @@ -18,7 +18,15 @@ "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", - "cHNidP8BAHMCAAAAAbiWoY6pOQepFsEGhUPXaulX9rvye2NH+NrdlAHg+WgpAQAAAAD/////AkBLTAAAAAAAF6kUqWwXCcLM5BN2zoNqMNT5qMlIi7+HQEtMAAAAAAAXqRSVF/in2XNxAlN1OSxkyp0z+Wtg2YcAAAAAAAEBIBNssgAAAAAAF6kUamsvautR8hRlMRY6OKNTx03DK96HAQcXFgAUo8u1LWpHprjt/uENAwBpGZD0UH0BCGsCRzBEAiAONfH3DYiw67ZbylrsxCF/XXpVwyWBRgofyRbPslzvwgIgIKCsWw5sHSIPh1icNvcVLZLHWj6NA7Dk+4Os2pOnMbQBIQPGStfYHPtyhpV7zIWtn0Q4GXv5gK1zy/tnJ+cBXu4iiwABABYAFMwmJQEz+HDpBEEabxJ5PogPsqZRAAEAFgAUyCrGc3h3FYCmiIspbv2pSTKZ5jU" + "cHNidP8BAHMCAAAAAbiWoY6pOQepFsEGhUPXaulX9rvye2NH+NrdlAHg+WgpAQAAAAD/////AkBLTAAAAAAAF6kUqWwXCcLM5BN2zoNqMNT5qMlIi7+HQEtMAAAAAAAXqRSVF/in2XNxAlN1OSxkyp0z+Wtg2YcAAAAAAAEBIBNssgAAAAAAF6kUamsvautR8hRlMRY6OKNTx03DK96HAQcXFgAUo8u1LWpHprjt/uENAwBpGZD0UH0BCGsCRzBEAiAONfH3DYiw67ZbylrsxCF/XXpVwyWBRgofyRbPslzvwgIgIKCsWw5sHSIPh1icNvcVLZLHWj6NA7Dk+4Os2pOnMbQBIQPGStfYHPtyhpV7zIWtn0Q4GXv5gK1zy/tnJ+cBXu4iiwABABYAFMwmJQEz+HDpBEEabxJ5PogPsqZRAAEAFgAUyCrGc3h3FYCmiIspbv2pSTKZ5jU", + "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAQEAAQEBagA=", + "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAQAAAQABagA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJ//////////8AAQEJAADK/gAAAAAAAA==", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQMErd7f7gEDBAEAAAAA", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQQAAQQBagA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQUAAQUBUQA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQcAAQcBUQA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQgBAAEIAwEBUQA=" ], "valid" : [ "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA", |