diff --git a/.arclint b/.arclint index 8ab842816b..c098c39bda 100644 --- a/.arclint +++ b/.arclint @@ -1,154 +1,158 @@ { "linters": { "generated": { "type": "generated" }, "clang-format": { "type": "clang-format", "version": ">=7.0", "bin": ["clang-format-7", "clang-format"], "include": "(^src/.*\\.(h|c|cpp|mm)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ] }, "autopep8": { "type": "autopep8", "version": ">=1.3.4", "include": "(\\.py$)" }, "flake8": { "type": "flake8", "include": "(\\.py$)", "flags": [ "--select=E112,E113,E115,E116,E125,E131,E133,E223,E224,E242,E266,E271,E272,E273,E274,E275,E304,E306,E401,E402,E502,E701,E702,E703,E714,E721,E741,E742,E743,E901,E902,F401,F402,F403,F404,F405,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F821,F822,F823,F831,F841,W292,W293,W601,W602,W603,W604,W605,W606" ] }, "lint-format-strings": { "type": "lint-format-strings", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ] }, "check-doc": { "type": "check-doc", "include": "(^src/.*\\.(h|c|cpp)$)" }, "lint-tests": { "type": "lint-tests", "include": "(^src/(rpc/|wallet/)?test/.*\\.(cpp)$)" }, "lint-python-format": { "type": "lint-python-format", "include": "(\\.py$)", "exclude": [ "(^test/lint/lint-python-format\\.py$)" ] }, "phpcs": { "type": "phpcs", "include": "(\\.php$)", "exclude": [ "(^arcanist/__phutil_library_.+\\.php$)" ], "phpcs.standard": "arcanist/phpcs.xml" }, "lint-locale-dependence": { "type": "lint-locale-dependence", "include": "(^src/.*\\.(h|cpp)$)", "exclude": [ "(^src/(crypto/ctaes/|leveldb/|secp256k1/|seeder/|tinyformat.h|univalue/))" ] }, "lint-cheader": { "type": "lint-cheader", "include": "(^src/.*\\.(h|cpp)$)", "exclude": [ "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)" ] }, "spelling": { "type": "spelling", "exclude": [ "(^build-aux/m4/)", "(^depends/)", "(^doc/release-notes/)", "(^src/(qt/locale|secp256k1|univalue|leveldb)/)", "(^test/lint/dictionary/)" ], "spelling.dictionaries": [ "test/lint/dictionary/english.json" ] }, "lint-assert-with-side-effects": { "type": "lint-assert-with-side-effects", "include": "(^src/.*\\.(h|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ] }, "lint-include-quotes": { "type": "lint-include-quotes", "include": "(^src/.*\\.(h|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ] }, "lint-include-guard": { "type": "lint-include-guard", "include": "(^src/.*\\.h$)", "exclude": [ "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)", "(^src/tinyformat.h$)" ] }, "lint-include-source": { "type": "lint-include-source", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ] }, "lint-stdint": { "type": "lint-stdint", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ] }, "lint-source-filename": { "type": "lint-source-filename", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ] }, "lint-boost-dependencies": { "type": "lint-boost-dependencies", "include": "(^src/.*\\.(h|cpp)$)" }, "check-rpc-mappings": { "type": "check-rpc-mappings", "include": "(^src/(rpc/|wallet/rpc).*\\.cpp$)" }, "lint-python-encoding": { "type": "lint-python-encoding", "include": "(\\.py$)" }, "lint-python-shebang": { "type": "lint-python-shebang", "include": "(\\.py$)", "exclude": [ "(__init__\\.py$)" ] }, + "lint-bash-shebang": { + "type": "lint-bash-shebang", + "include": "(\\.sh$)" + }, "shellcheck": { "type": "shellcheck", "include": "(\\.sh$)", "exclude": [ "(^src/(secp256k1|univalue)/)" ] } } } diff --git a/arcanist/.phutil_module_cache b/arcanist/.phutil_module_cache index 48891034c9..ef8052d8c7 100644 --- a/arcanist/.phutil_module_cache +++ b/arcanist/.phutil_module_cache @@ -1 +1 @@ -{"__symbol_cache_version__":11,"ae5b7d3d6b8cf9598ce4abaf0cd56b21":{"have":{"class":{"ExtendedConfigurationDrivenLintEngine":19}},"need":{"function":{"newv":159,"pht":933},"class":{"ArcanistLintEngine":65,"ArcanistConfigurationDrivenLintEngine":171,"PhutilConsole":866},"class\/interface":{"ILintOnce":634}},"xmap":{"ExtendedConfigurationDrivenLintEngine":["ArcanistLintEngine"]}},"2809b09d2021203b43c57da33d1fe8bf":{"have":{"class":{"AssertWithSideEffectsLinter":210}},"need":{"function":{"pht":439},"class":{"ArcanistLinter":246,"ArcanistLintSeverity":926,"Filesystem":1170}},"xmap":{"AssertWithSideEffectsLinter":["ArcanistLinter"]}},"90a8b110dc475955f15bb81d37268cb5":{"have":{"class":{"AutoPEP8FormatLinter":75}},"need":{"function":{"pht":297,"execx":769,"id":1903},"class":{"ArcanistExternalLinter":104,"ArcanistLintMessage":1910,"Filesystem":1754,"ArcanistLinter":2017,"ArcanistLintSeverity":2095}},"xmap":{"AutoPEP8FormatLinter":["ArcanistExternalLinter"]}},"5ea58c19df0397ed8ee0f463d90d6c72":{"have":{"class":{"BoostDependenciesLinter":145}},"need":{"function":{"pht":330,"id":1440},"class":{"GlobalExternalLinter":177,"ArcanistLintMessage":1447,"Filesystem":609,"ArcanistLinter":1524,"ArcanistLintSeverity":1624}},"xmap":{"BoostDependenciesLinter":["GlobalExternalLinter"]}},"38f0c676bff5192a344464142caaa253":{"have":{"class":{"CHeaderLinter":99}},"need":{"function":{"pht":611},"class":{"ArcanistLinter":121,"ArcanistLintSeverity":1060,"Filesystem":1307}},"xmap":{"CHeaderLinter":["ArcanistLinter"]}},"9bb48ec0fe2e9ced8e27d42540d0571c":{"have":{"class":{"CheckDocLinter":106}},"need":{"function":{"pht":321,"id":1845},"class":{"GlobalExternalLinter":129,"ArcanistLintMessage":1852,"Filesystem":729,"ArcanistLinter":1900,"ArcanistLintSeverity":1986}},"xmap":{"CheckDocLinter":["GlobalExternalLinter"]}},"63d19a8745cb2e1200cc26488dc7ad25":{"have":{"class":{"CheckRpcMappingsLinter":131}},"need":{"function":{"pht":310,"id":1386},"class":{"GlobalExternalLinter":162,"ArcanistLintMessage":1393,"Filesystem":573,"ArcanistLinter":1443,"ArcanistLintSeverity":1544}},"xmap":{"CheckRpcMappingsLinter":["GlobalExternalLinter"]}},"1c03a4631b02b8e1ebcc3a078dc1e4af":{"have":{"class":{"ClangFormatLinter":79}},"need":{"function":{"pht":302,"execx":781,"id":2235},"class":{"ArcanistExternalLinter":105,"ArcanistLintMessage":2242,"Filesystem":2086,"ArcanistLinter":2349,"ArcanistLintSeverity":2427}},"xmap":{"ClangFormatLinter":["ArcanistExternalLinter"]}},"75579a609dd975aa0226add52700c622":{"have":{"class":{"FileNameLinter":103}},"need":{"function":{"pht":307},"class":{"ArcanistLinter":126,"ArcanistLintSeverity":662,"Filesystem":968}},"xmap":{"FileNameLinter":["ArcanistLinter"]}},"9285ad9415f8ebe564f7119e5a72c559":{"have":{"class":{"FormatStringLinter":146}},"need":{"function":{"pht":377,"csprintf":1492,"id":1872},"class":{"ArcanistExternalLinter":173,"ArcanistLintMessage":1879,"Filesystem":827,"ArcanistLinter":1956,"ArcanistLintSeverity":2044}},"xmap":{"FormatStringLinter":["ArcanistExternalLinter"]}},"2e11dd9ad67e594f863bc46ac59ea37e":{"have":{"class":{"GlobalExternalLinter":199}},"need":{"class":{"ArcanistExternalLinter":228},"interface":{"ILintOnce":262}},"xmap":{"GlobalExternalLinter":["ArcanistExternalLinter","ILintOnce"]}},"b2403124ec3e8be6cb4d10bf0f6c4134":{"have":{"interface":{"ILintOnce":69}},"need":[],"xmap":[]},"1f9bac7956f4f948a187828dcc6ba2d0":{"have":{"class":{"IncludeGuardLinter":98}},"need":{"function":{"pht":368},"class":{"ArcanistLinter":125,"ArcanistLintSeverity":721,"Filesystem":970}},"xmap":{"IncludeGuardLinter":["ArcanistLinter"]}},"2cbb6e7228d81557f777ad648704f343":{"have":{"class":{"IncludeQuotesLinter":100}},"need":{"function":{"pht":306},"class":{"ArcanistLinter":128,"ArcanistLintSeverity":663,"Filesystem":964}},"xmap":{"IncludeQuotesLinter":["ArcanistLinter"]}},"f151089cf79fdb8257b2272ed4782d88":{"have":{"class":{"IncludeSourceLinter":99}},"need":{"function":{"pht":391},"class":{"ArcanistLinter":127,"ArcanistLintSeverity":699,"Filesystem":938}},"xmap":{"IncludeSourceLinter":["ArcanistLinter"]}},"6f2f22dd0f259fb2eaa284b4fab3bc29":{"have":{"class":{"PythonFormatLinter":123}},"need":{"function":{"pht":353,"id":1838},"class":{"ArcanistExternalLinter":150,"ArcanistLintMessage":1845,"Filesystem":776,"ArcanistLinter":1970,"ArcanistLintSeverity":2053}},"xmap":{"PythonFormatLinter":["ArcanistExternalLinter"]}},"03cf226fe177a9fce7dc046816cc466b":{"have":{"class":{"PythonOpenFileEncodingLinter":111}},"need":{"function":{"pht":325},"class":{"ArcanistLinter":148,"ArcanistLintSeverity":687,"Filesystem":991}},"xmap":{"PythonOpenFileEncodingLinter":["ArcanistLinter"]}},"454160ed72e88797129d84ee589de304":{"have":{"class":{"PythonShebangLinter":87}},"need":{"function":{"pht":290},"class":{"ArcanistLinter":115,"ArcanistLintSeverity":614,"Filesystem":854}},"xmap":{"PythonShebangLinter":["ArcanistLinter"]}},"09a933fbbf135320585be52750d93831":{"have":{"class":{"StdintLinter":90}},"need":{"function":{"pht":280},"class":{"ArcanistLinter":111,"ArcanistLintSeverity":589,"Filesystem":897}},"xmap":{"StdintLinter":["ArcanistLinter"]}},"25781df78f6eebfb223296b8265e9d19":{"have":{"class":{"TestsLinter":103}},"need":{"function":{"pht":318,"id":2629},"class":{"ArcanistExternalLinter":123,"ArcanistLintMessage":2636,"Filesystem":776,"ArcanistLinter":2684,"ArcanistLintSeverity":2792}},"xmap":{"TestsLinter":["ArcanistExternalLinter"]}},"899b8be78da0be470965682eaa31f00a":{"have":{"class":{"ShellCheckLinter":95}},"need":{"function":{"pht":1835,"id":3051},"class":{"ArcanistExternalLinter":120,"ArcanistLintMessage":3058,"ArcanistLintSeverity":1560,"ArcanistLinter":3106}},"xmap":{"ShellCheckLinter":["ArcanistExternalLinter"]}},"8a0f2ba683e96feeb9d9564af01fe3e7":{"have":{"class":{"LocaleDependenceLinter":160}},"need":{"function":{"pht":5460},"class":{"ArcanistLinter":191,"ArcanistLintSeverity":5963,"Filesystem":6209}},"xmap":{"LocaleDependenceLinter":["ArcanistLinter"]}}} \ No newline at end of file +{"__symbol_cache_version__":11,"ae5b7d3d6b8cf9598ce4abaf0cd56b21":{"have":{"class":{"ExtendedConfigurationDrivenLintEngine":19}},"need":{"function":{"newv":159,"pht":933},"class":{"ArcanistLintEngine":65,"ArcanistConfigurationDrivenLintEngine":171,"PhutilConsole":866},"class\/interface":{"ILintOnce":634}},"xmap":{"ExtendedConfigurationDrivenLintEngine":["ArcanistLintEngine"]}},"2809b09d2021203b43c57da33d1fe8bf":{"have":{"class":{"AssertWithSideEffectsLinter":210}},"need":{"function":{"pht":439},"class":{"ArcanistLinter":246,"ArcanistLintSeverity":926,"Filesystem":1170}},"xmap":{"AssertWithSideEffectsLinter":["ArcanistLinter"]}},"90a8b110dc475955f15bb81d37268cb5":{"have":{"class":{"AutoPEP8FormatLinter":75}},"need":{"function":{"pht":297,"execx":769,"id":1903},"class":{"ArcanistExternalLinter":104,"ArcanistLintMessage":1910,"Filesystem":1754,"ArcanistLinter":2017,"ArcanistLintSeverity":2095}},"xmap":{"AutoPEP8FormatLinter":["ArcanistExternalLinter"]}},"5ea58c19df0397ed8ee0f463d90d6c72":{"have":{"class":{"BoostDependenciesLinter":145}},"need":{"function":{"pht":330,"id":1440},"class":{"GlobalExternalLinter":177,"ArcanistLintMessage":1447,"Filesystem":609,"ArcanistLinter":1524,"ArcanistLintSeverity":1624}},"xmap":{"BoostDependenciesLinter":["GlobalExternalLinter"]}},"38f0c676bff5192a344464142caaa253":{"have":{"class":{"CHeaderLinter":99}},"need":{"function":{"pht":611},"class":{"ArcanistLinter":121,"ArcanistLintSeverity":1060,"Filesystem":1307}},"xmap":{"CHeaderLinter":["ArcanistLinter"]}},"9bb48ec0fe2e9ced8e27d42540d0571c":{"have":{"class":{"CheckDocLinter":106}},"need":{"function":{"pht":321,"id":1845},"class":{"GlobalExternalLinter":129,"ArcanistLintMessage":1852,"Filesystem":729,"ArcanistLinter":1900,"ArcanistLintSeverity":1986}},"xmap":{"CheckDocLinter":["GlobalExternalLinter"]}},"63d19a8745cb2e1200cc26488dc7ad25":{"have":{"class":{"CheckRpcMappingsLinter":131}},"need":{"function":{"pht":310,"id":1386},"class":{"GlobalExternalLinter":162,"ArcanistLintMessage":1393,"Filesystem":573,"ArcanistLinter":1443,"ArcanistLintSeverity":1544}},"xmap":{"CheckRpcMappingsLinter":["GlobalExternalLinter"]}},"1c03a4631b02b8e1ebcc3a078dc1e4af":{"have":{"class":{"ClangFormatLinter":79}},"need":{"function":{"pht":302,"execx":781,"id":2235},"class":{"ArcanistExternalLinter":105,"ArcanistLintMessage":2242,"Filesystem":2086,"ArcanistLinter":2349,"ArcanistLintSeverity":2427}},"xmap":{"ClangFormatLinter":["ArcanistExternalLinter"]}},"75579a609dd975aa0226add52700c622":{"have":{"class":{"FileNameLinter":103}},"need":{"function":{"pht":307},"class":{"ArcanistLinter":126,"ArcanistLintSeverity":662,"Filesystem":968}},"xmap":{"FileNameLinter":["ArcanistLinter"]}},"9285ad9415f8ebe564f7119e5a72c559":{"have":{"class":{"FormatStringLinter":146}},"need":{"function":{"pht":377,"csprintf":1492,"id":1872},"class":{"ArcanistExternalLinter":173,"ArcanistLintMessage":1879,"Filesystem":827,"ArcanistLinter":1956,"ArcanistLintSeverity":2044}},"xmap":{"FormatStringLinter":["ArcanistExternalLinter"]}},"2e11dd9ad67e594f863bc46ac59ea37e":{"have":{"class":{"GlobalExternalLinter":199}},"need":{"class":{"ArcanistExternalLinter":228},"interface":{"ILintOnce":262}},"xmap":{"GlobalExternalLinter":["ArcanistExternalLinter","ILintOnce"]}},"b2403124ec3e8be6cb4d10bf0f6c4134":{"have":{"interface":{"ILintOnce":69}},"need":[],"xmap":[]},"1f9bac7956f4f948a187828dcc6ba2d0":{"have":{"class":{"IncludeGuardLinter":98}},"need":{"function":{"pht":368},"class":{"ArcanistLinter":125,"ArcanistLintSeverity":721,"Filesystem":970}},"xmap":{"IncludeGuardLinter":["ArcanistLinter"]}},"2cbb6e7228d81557f777ad648704f343":{"have":{"class":{"IncludeQuotesLinter":100}},"need":{"function":{"pht":306},"class":{"ArcanistLinter":128,"ArcanistLintSeverity":663,"Filesystem":964}},"xmap":{"IncludeQuotesLinter":["ArcanistLinter"]}},"f151089cf79fdb8257b2272ed4782d88":{"have":{"class":{"IncludeSourceLinter":99}},"need":{"function":{"pht":391},"class":{"ArcanistLinter":127,"ArcanistLintSeverity":699,"Filesystem":938}},"xmap":{"IncludeSourceLinter":["ArcanistLinter"]}},"8a0f2ba683e96feeb9d9564af01fe3e7":{"have":{"class":{"LocaleDependenceLinter":160}},"need":{"function":{"pht":5460},"class":{"ArcanistLinter":191,"ArcanistLintSeverity":5963,"Filesystem":6209}},"xmap":{"LocaleDependenceLinter":["ArcanistLinter"]}},"6f2f22dd0f259fb2eaa284b4fab3bc29":{"have":{"class":{"PythonFormatLinter":123}},"need":{"function":{"pht":353,"id":1838},"class":{"ArcanistExternalLinter":150,"ArcanistLintMessage":1845,"Filesystem":776,"ArcanistLinter":1970,"ArcanistLintSeverity":2053}},"xmap":{"PythonFormatLinter":["ArcanistExternalLinter"]}},"03cf226fe177a9fce7dc046816cc466b":{"have":{"class":{"PythonOpenFileEncodingLinter":111}},"need":{"function":{"pht":325},"class":{"ArcanistLinter":148,"ArcanistLintSeverity":687,"Filesystem":991}},"xmap":{"PythonOpenFileEncodingLinter":["ArcanistLinter"]}},"454160ed72e88797129d84ee589de304":{"have":{"class":{"PythonShebangLinter":87}},"need":{"function":{"pht":290},"class":{"ArcanistLinter":115,"ArcanistLintSeverity":614,"Filesystem":854}},"xmap":{"PythonShebangLinter":["ArcanistLinter"]}},"899b8be78da0be470965682eaa31f00a":{"have":{"class":{"ShellCheckLinter":95}},"need":{"function":{"pht":1835,"id":3051},"class":{"ArcanistExternalLinter":120,"ArcanistLintMessage":3058,"ArcanistLintSeverity":1560,"ArcanistLinter":3106}},"xmap":{"ShellCheckLinter":["ArcanistExternalLinter"]}},"09a933fbbf135320585be52750d93831":{"have":{"class":{"StdintLinter":90}},"need":{"function":{"pht":280},"class":{"ArcanistLinter":111,"ArcanistLintSeverity":589,"Filesystem":897}},"xmap":{"StdintLinter":["ArcanistLinter"]}},"25781df78f6eebfb223296b8265e9d19":{"have":{"class":{"TestsLinter":103}},"need":{"function":{"pht":318,"id":2629},"class":{"ArcanistExternalLinter":123,"ArcanistLintMessage":2636,"Filesystem":776,"ArcanistLinter":2684,"ArcanistLintSeverity":2792}},"xmap":{"TestsLinter":["ArcanistExternalLinter"]}},"4c4adcac26dddfa5e350b85a40097755":{"have":{"class":{"BashShebangLinter":82}},"need":{"function":{"pht":281},"class":{"ArcanistLinter":108,"ArcanistLintSeverity":597,"Filesystem":837}},"xmap":{"BashShebangLinter":["ArcanistLinter"]}}} \ No newline at end of file diff --git a/arcanist/__phutil_library_map__.php b/arcanist/__phutil_library_map__.php index edb9a66490..cb005ed93a 100644 --- a/arcanist/__phutil_library_map__.php +++ b/arcanist/__phutil_library_map__.php @@ -1,62 +1,64 @@ 2, 'class' => array( 'AssertWithSideEffectsLinter' => 'linter/AssertWithSideEffectsLinter.php', 'AutoPEP8FormatLinter' => 'linter/AutoPEP8Linter.php', + 'BashShebangLinter' => 'linter/BashShebangLinter.php', 'BoostDependenciesLinter' => 'linter/BoostDependenciesLinter.php', 'CHeaderLinter' => 'linter/CHeaderLinter.php', 'CheckDocLinter' => 'linter/CheckDocLinter.php', 'CheckRpcMappingsLinter' => 'linter/CheckRpcMappingsLinter.php', 'ClangFormatLinter' => 'linter/ClangFormatLinter.php', 'ExtendedConfigurationDrivenLintEngine' => 'engine/ExtendedConfigurationDrivenLintEngine.php', 'FileNameLinter' => 'linter/FileNameLinter.php', 'FormatStringLinter' => 'linter/FormatStringLinter.php', 'GlobalExternalLinter' => 'linter/GlobalExternalLinter.php', 'ILintOnce' => 'linter/ILintOnce.php', 'IncludeGuardLinter' => 'linter/IncludeGuardLinter.php', 'IncludeQuotesLinter' => 'linter/IncludeQuotesLinter.php', 'IncludeSourceLinter' => 'linter/IncludeSourceLinter.php', 'LocaleDependenceLinter' => 'linter/LocaleDependenceLinter.php', 'PythonFormatLinter' => 'linter/PythonFormatLinter.php', 'PythonOpenFileEncodingLinter' => 'linter/PythonOpenFileEncodingLinter.php', 'PythonShebangLinter' => 'linter/PythonShebangLinter.php', 'ShellCheckLinter' => 'linter/ShellCheckLinter.php', 'StdintLinter' => 'linter/StdintLinter.php', 'TestsLinter' => 'linter/TestsLinter.php', ), 'function' => array(), 'xmap' => array( 'AssertWithSideEffectsLinter' => 'ArcanistLinter', 'AutoPEP8FormatLinter' => 'ArcanistExternalLinter', + 'BashShebangLinter' => 'ArcanistLinter', 'BoostDependenciesLinter' => 'GlobalExternalLinter', 'CHeaderLinter' => 'ArcanistLinter', 'CheckDocLinter' => 'GlobalExternalLinter', 'CheckRpcMappingsLinter' => 'GlobalExternalLinter', 'ClangFormatLinter' => 'ArcanistExternalLinter', 'ExtendedConfigurationDrivenLintEngine' => 'ArcanistLintEngine', 'FileNameLinter' => 'ArcanistLinter', 'FormatStringLinter' => 'ArcanistExternalLinter', 'GlobalExternalLinter' => array( 'ArcanistExternalLinter', 'ILintOnce', ), 'IncludeGuardLinter' => 'ArcanistLinter', 'IncludeQuotesLinter' => 'ArcanistLinter', 'IncludeSourceLinter' => 'ArcanistLinter', 'LocaleDependenceLinter' => 'ArcanistLinter', 'PythonFormatLinter' => 'ArcanistExternalLinter', 'PythonOpenFileEncodingLinter' => 'ArcanistLinter', 'PythonShebangLinter' => 'ArcanistLinter', 'ShellCheckLinter' => 'ArcanistExternalLinter', 'StdintLinter' => 'ArcanistLinter', 'TestsLinter' => 'ArcanistExternalLinter', ), )); diff --git a/arcanist/linter/BashShebangLinter.php b/arcanist/linter/BashShebangLinter.php new file mode 100644 index 0000000000..5a67320fa1 --- /dev/null +++ b/arcanist/linter/BashShebangLinter.php @@ -0,0 +1,48 @@ + ArcanistLintSeverity::SEVERITY_ERROR, + ); + } + + public function getLintNameMap() { + return array( + self::BAD_SHEBANG_FOUND => pht('Missing or unexpected shebang.'), + ); + } + + public function lintPath($path) { + $absPath = Filesystem::resolvePath($path, $this->getProjectRoot()); + $fileContent = Filesystem::readFile($absPath); + + if (!preg_match_all("%^#!(/usr/bin/env bash|/bin/sh)%", $fileContent)) { + return $this->raiseLintAtPath( + self::BAD_SHEBANG_FOUND, + pht("Shebang should be `#!/usr/bin/env bash` or `#!/bin/sh`")); + } + } +} diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 163c36168f..36bf4a9f06 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,188 +1,188 @@ --- name: "bitcoin-abc-0.20-linux" enable_cache: true distro: "debian" suites: - "stretch" architectures: - "amd64" multiarch: - "i386" packages: - "curl" - "gperf" - "g++-aarch64-linux-gnu" - "gcc-aarch64-linux-gnu" - "binutils-aarch64-linux-gnu" - "g++-arm-linux-gnueabihf" - "gcc-arm-linux-gnueabihf" - "binutils-arm-linux-gnueabihf" - "binutils-gold" - "build-essential" - "git" - "pkg-config" - "autoconf" - "libtool" - "automake" - "faketime" - "bsdmainutils" - "ca-certificates" - "python" - "lib32stdc++-6-dev" - "libc6-dev:i386" remotes: - "url": "https://github.com/Bitcoin-ABC/bitcoin-abc.git" "dir": "bitcoin" files: [] script: | WRAP_DIR=$HOME/wrapped HOSTS="i686-pc-linux-gnu x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu" CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests" FAKETIME_HOST_PROGS="" FAKETIME_PROGS="date ar ranlib nm" HOST_CFLAGS="-O2 -g" HOST_CXXFLAGS="-O2 -g" HOST_LDFLAGS=-static-libstdc++ export QT_RCC_TEST=1 export QT_RCC_SOURCE_DATE_OVERRIDE=1 export GZIP="-9n" export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" export TZ="UTC" export BUILD_DIR=`pwd` mkdir -p ${WRAP_DIR} if test -n "$GBUILD_CACHE_ENABLED"; then export SOURCES_PATH=${GBUILD_COMMON_CACHE} export BASE_CACHE=${GBUILD_PACKAGE_CACHE} mkdir -p ${BASE_CACHE} ${SOURCES_PATH} fi function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done } function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done } # Faketime for depends so intermediate results are comparable export PATH_orig=${PATH} create_global_faketime_wrappers "2000-01-01 12:00:00" create_per-host_faketime_wrappers "2000-01-01 12:00:00" export PATH=${WRAP_DIR}:${PATH} EXTRA_INCLUDES_BASE=$WRAP_DIR/extra_includes mkdir -p $EXTRA_INCLUDES_BASE # x86 needs /usr/include/i386-linux-gnu/asm pointed to /usr/include/x86_64-linux-gnu/asm, # but we can't write there. Instead, create a link here and force it to be included in the # search paths by wrapping gcc/g++. mkdir -p $EXTRA_INCLUDES_BASE/i686-pc-linux-gnu rm -f $WRAP_DIR/extra_includes/i686-pc-linux-gnu/asm ln -s /usr/include/x86_64-linux-gnu/asm $EXTRA_INCLUDES_BASE/i686-pc-linux-gnu/asm for prog in gcc g++; do rm -f ${WRAP_DIR}/${prog} cat << EOF > ${WRAP_DIR}/${prog} - #!/bin/bash + #!/usr/bin/env bash REAL="`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1`" for var in "\$@" do if [ "\$var" = "-m32" ]; then export C_INCLUDE_PATH="$EXTRA_INCLUDES_BASE/i686-pc-linux-gnu" export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES_BASE/i686-pc-linux-gnu" break fi done \$REAL \$@ EOF chmod +x ${WRAP_DIR}/${prog} done cd bitcoin BASEPREFIX=`pwd`/depends # Build dependencies for each host for i in $HOSTS; do EXTRA_INCLUDES="$EXTRA_INCLUDES_BASE/$i" if [ -d "$EXTRA_INCLUDES" ]; then export HOST_ID_SALT="$EXTRA_INCLUDES" fi make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" unset HOST_ID_SALT done # Faketime for binaries export PATH=${PATH_orig} create_global_faketime_wrappers "${REFERENCE_DATETIME}" create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" export PATH=${WRAP_DIR}:${PATH} # Create the release tarball using (arbitrarily) the first host ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist SOURCEDIST=`echo bitcoin-abc-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` # Correct tar file order mkdir -p temp pushd temp tar xf ../$SOURCEDIST find bitcoin-abc-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS}; do export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} mkdir -p distsrc-${i} cd distsrc-${i} INSTALLPATH=`pwd`/installed/${DISTNAME} mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" LDFLAGS="${HOST_LDFLAGS}" make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security #TODO: This is a quick hack that disables symbol checking for arm. # Instead, we should investigate why these are popping up. # For aarch64, we'll need to bump up the min GLIBC version, as the abi # support wasn't introduced until 2.17. case $i in aarch64-*) : ;; arm-*) : ;; *) make ${MAKEOPTS} -C src check-symbols ;; esac make install DESTDIR=${INSTALLPATH} cd installed find . -name "lib*.la" -delete find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig find ${DISTNAME}/bin -type f -executable -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \; find ${DISTNAME}/lib -type f -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \; find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz find ${DISTNAME} -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}-debug.tar.gz cd ../../ rm -rf distsrc-${i} done mkdir -p $OUTDIR/src mv $SOURCEDIST $OUTDIR/src diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index feb616f385..57c423bbb7 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -1,38 +1,38 @@ --- name: "bitcoin-dmg-signer" distro: "debian" suites: - "stretch" architectures: - "amd64" packages: - "faketime" remotes: - "url": "https://github.com/bitcoin-core/bitcoin-detached-sigs.git" "dir": "signature" files: - "bitcoin-osx-unsigned.tar.gz" script: | WRAP_DIR=$HOME/wrapped mkdir -p ${WRAP_DIR} export PATH=`pwd`:$PATH FAKETIME_PROGS="dmg genisoimage" # Create global faketime wrappers for prog in ${FAKETIME_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done UNSIGNED=bitcoin-osx-unsigned.tar.gz SIGNED=bitcoin-osx-signed.dmg tar -xf ${UNSIGNED} OSX_VOLNAME="$(cat osx_volname)" ./detached-sig-apply.sh ${UNSIGNED} signature/osx ${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "${OSX_VOLNAME}" -no-pad -r -dir-mode 0755 -apple -o uncompressed.dmg signed-app ${WRAP_DIR}/dmg dmg uncompressed.dmg ${OUTDIR}/${SIGNED} diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index e554bff8bf..998ed39991 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,161 +1,161 @@ --- name: "bitcoin-abc-0.20-osx" enable_cache: true distro: "debian" suites: - "stretch" architectures: - "amd64" packages: - "ca-certificates" - "curl" - "g++" - "git" - "pkg-config" - "autoconf" - "librsvg2-bin" - "libtiff-tools" - "libtool" - "automake" - "faketime" - "bsdmainutils" - "cmake" - "ninja-build" - "imagemagick" - "libcap-dev" - "libz-dev" - "libbz2-dev" - "python" - "python-dev" - "python-setuptools" - "fonts-tuffy" remotes: - "url": "https://github.com/Bitcoin-ABC/bitcoin-abc.git" "dir": "bitcoin" files: - "MacOSX10.11.sdk.tar.gz" script: | WRAP_DIR=$HOME/wrapped HOSTS="x86_64-apple-darwin14" CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests GENISOIMAGE=$WRAP_DIR/genisoimage" FAKETIME_HOST_PROGS="" FAKETIME_PROGS="ar ranlib date dmg genisoimage" export QT_RCC_TEST=1 export QT_RCC_SOURCE_DATE_OVERRIDE=1 export GZIP="-9n" export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" export TZ="UTC" export BUILD_DIR=`pwd` mkdir -p ${WRAP_DIR} if test -n "$GBUILD_CACHE_ENABLED"; then export SOURCES_PATH=${GBUILD_COMMON_CACHE} export BASE_CACHE=${GBUILD_PACKAGE_CACHE} mkdir -p ${BASE_CACHE} ${SOURCES_PATH} fi export ZERO_AR_DATE=1 function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done } function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done } # Faketime for depends so intermediate results are comparable export PATH_orig=${PATH} create_global_faketime_wrappers "2000-01-01 12:00:00" create_per-host_faketime_wrappers "2000-01-01 12:00:00" export PATH=${WRAP_DIR}:${PATH} cd bitcoin BASEPREFIX=`pwd`/depends mkdir -p ${BASEPREFIX}/SDKs tar -C ${BASEPREFIX}/SDKs -xf ${BUILD_DIR}/MacOSX10.11.sdk.tar.gz # Build dependencies for each host for i in $HOSTS; do make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done # Faketime for binaries export PATH=${PATH_orig} create_global_faketime_wrappers "${REFERENCE_DATETIME}" create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" export PATH=${WRAP_DIR}:${PATH} # Create the release tarball using (arbitrarily) the first host ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist SOURCEDIST=`echo bitcoin-abc-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` # Correct tar file order mkdir -p temp pushd temp tar xf ../$SOURCEDIST find bitcoin-abc-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS}; do export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} mkdir -p distsrc-${i} cd distsrc-${i} INSTALLPATH=`pwd`/installed/${DISTNAME} mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} make ${MAKEOPTS} make install-strip DESTDIR=${INSTALLPATH} make osx_volname make deploydir OSX_VOLNAME="$(cat osx_volname)" mkdir -p unsigned-app-${i} cp osx_volname unsigned-app-${i}/ cp contrib/macdeploy/detached-sig-apply.sh unsigned-app-${i} cp contrib/macdeploy/detached-sig-create.sh unsigned-app-${i} cp ${BASEPREFIX}/${i}/native/bin/dmg ${BASEPREFIX}/${i}/native/bin/genisoimage unsigned-app-${i} cp ${BASEPREFIX}/${i}/native/bin/${i}-codesign_allocate unsigned-app-${i}/codesign_allocate cp ${BASEPREFIX}/${i}/native/bin/${i}-pagestuff unsigned-app-${i}/pagestuff mv dist unsigned-app-${i} pushd unsigned-app-${i} find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-osx-unsigned.tar.gz popd make deploy ${WRAP_DIR}/dmg dmg "${OSX_VOLNAME}.dmg" ${OUTDIR}/${DISTNAME}-osx-unsigned.dmg cd installed find . -name "lib*.la" -delete find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig find ${DISTNAME} | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz cd ../../ done mkdir -p $OUTDIR/src mv $SOURCEDIST $OUTDIR/src mv ${OUTDIR}/${DISTNAME}-x86_64-*.tar.gz ${OUTDIR}/${DISTNAME}-osx64.tar.gz diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 7775dc5b9d..4156c4d923 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,171 +1,171 @@ --- name: "bitcoin-abc-0.20-win" enable_cache: true distro: "debian" suites: - "stretch" architectures: - "amd64" packages: - "curl" - "g++" - "git" - "pkg-config" - "autoconf" - "libtool" - "automake" - "faketime" - "bsdmainutils" - "mingw-w64" - "g++-mingw-w64" - "nsis" - "zip" - "ca-certificates" - "python" - "rename" remotes: - "url": "https://github.com/Bitcoin-ABC/bitcoin-abc.git" "dir": "bitcoin" files: [] script: | WRAP_DIR=$HOME/wrapped HOSTS="i686-w64-mingw32 x86_64-w64-mingw32" CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests --without-seeder" FAKETIME_HOST_PROGS="ar ranlib nm windres strip objcopy" FAKETIME_PROGS="date makensis zip" HOST_CFLAGS="-O2 -g" HOST_CXXFLAGS="-O2 -g" export QT_RCC_TEST=1 export QT_RCC_SOURCE_DATE_OVERRIDE=1 export GZIP="-9n" export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" export TZ="UTC" export BUILD_DIR=`pwd` mkdir -p ${WRAP_DIR} if test -n "$GBUILD_CACHE_ENABLED"; then export SOURCES_PATH=${GBUILD_COMMON_CACHE} export BASE_CACHE=${GBUILD_PACKAGE_CACHE} mkdir -p ${BASE_CACHE} ${SOURCES_PATH} fi function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done } function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done } function create_per-host_linker_wrapper { # This is only needed for trusty, as the mingw linker leaks a few bytes of # heap, causing non-determinism. See discussion in https://github.com/bitcoin/bitcoin/pull/6900 for i in $HOSTS; do mkdir -p ${WRAP_DIR}/${i} for prog in collect2; do - echo '#!/bin/bash' > ${WRAP_DIR}/${i}/${prog} + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}/${prog} REAL=$(${i}-gcc -print-prog-name=${prog}) echo "export MALLOC_PERTURB_=255" >> ${WRAP_DIR}/${i}/${prog} echo "${REAL} \$@" >> $WRAP_DIR/${i}/${prog} chmod +x ${WRAP_DIR}/${i}/${prog} done for prog in gcc g++; do echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog}-posix | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "export COMPILER_PATH=${WRAP_DIR}/${i}" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done } # Faketime for depends so intermediate results are comparable export PATH_orig=${PATH} create_global_faketime_wrappers "2000-01-01 12:00:00" create_per-host_faketime_wrappers "2000-01-01 12:00:00" create_per-host_linker_wrapper "2000-01-01 12:00:00" export PATH=${WRAP_DIR}:${PATH} cd bitcoin BASEPREFIX=`pwd`/depends # Build dependencies for each host for i in $HOSTS; do make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done # Faketime for binaries export PATH=${PATH_orig} create_global_faketime_wrappers "${REFERENCE_DATETIME}" create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" create_per-host_linker_wrapper "${REFERENCE_DATETIME}" export PATH=${WRAP_DIR}:${PATH} # Create the release tarball using (arbitrarily) the first host ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist SOURCEDIST=`echo bitcoin-abc-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` # Correct tar file order mkdir -p temp pushd temp tar xf ../$SOURCEDIST find bitcoin-abc-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST mkdir -p $OUTDIR/src cp ../$SOURCEDIST $OUTDIR/src popd ORIGPATH="$PATH" # Extract the release tarball into a dir for each host and build for i in ${HOSTS}; do export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} mkdir -p distsrc-${i} cd distsrc-${i} INSTALLPATH=`pwd`/installed/${DISTNAME} mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security make deploy make install DESTDIR=${INSTALLPATH} cp -f bitcoin-abc-*setup*.exe $OUTDIR/ cd installed mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ find . -name "lib*.la" -delete find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig find ${DISTNAME}/bin -type f -executable -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; find ${DISTNAME}/lib -type f -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; find ${DISTNAME} -not -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}.zip find ${DISTNAME} -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}-debug.zip cd ../../ rm -rf distsrc-${i} done cd $OUTDIR rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe find . -name "*-setup-unsigned.exe" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip mv ${OUTDIR}/${DISTNAME}-i686-*.zip ${OUTDIR}/${DISTNAME}-win32.zip diff --git a/contrib/gitian-signing/check-keys.sh b/contrib/gitian-signing/check-keys.sh index 82afe51666..a6ad1d08f6 100755 --- a/contrib/gitian-signing/check-keys.sh +++ b/contrib/gitian-signing/check-keys.sh @@ -1,5 +1,6 @@ +#!/usr/bin/env bash # Fetch latest signers' keys. We do this in order to check if a key was revoked. while read fingerprint _ do gpg --recv-keys ${fingerprint} done < ./keys.txt diff --git a/contrib/gitian/provisioner.sh b/contrib/gitian/provisioner.sh index da2d99fb77..eebc3f82e6 100644 --- a/contrib/gitian/provisioner.sh +++ b/contrib/gitian/provisioner.sh @@ -1,64 +1,66 @@ -#!/bin/bash -e +#!/usr/bin/env bash + +set -e # User to setup for building. Vagrant is the default export BUILDUSER=${BUILDUSER:-vagrant} apt-get update apt-get install -y git ruby sudo apt-cacher-ng qemu-utils debootstrap \ lxc python-cheetah parted kpartx bridge-utils make curl # the version of lxc-start in Debian needs to run as root, so make sure # that the build script can execute it without providing a password echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-start" > /etc/sudoers.d/gitian-lxc echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-execute" >> /etc/sudoers.d/gitian-lxc # make sure that USE_LXC is always set when logging in as vagrant, # and configure LXC IP addresses { echo 'export USE_LXC=1' echo 'export LXC_BRIDGE=lxcbr0' echo 'export GITIAN_HOST_IP=10.0.3.1' echo 'export LXC_GUEST_IP=10.0.3.5' } >> /home/${BUILDUSER}/.profile # Setup bridge echo 'USE_LXC_BRIDGE="true"' > /etc/default/lxc-net { echo 'lxc.network.type = veth' echo 'lxc.network.link = lxcbr0' echo 'lxc.network.flags = up' echo 'lxc.network.hwaddr = 00:16:3e:xx:xx:xx' } > /etc/lxc/default.conf service lxc-net restart # chdir into build user home directory cd /home/${BUILDUSER}/ ## Install vm-builder wget http://archive.ubuntu.com/ubuntu/pool/universe/v/vm-builder/vm-builder_0.12.4+bzr494.orig.tar.gz echo "76cbf8c52c391160b2641e7120dbade5afded713afaa6032f733a261f13e6a8e vm-builder_0.12.4+bzr494.orig.tar.gz" | sha256sum -c # (verification -- must return OK) tar -zxvf vm-builder_0.12.4+bzr494.orig.tar.gz cd vm-builder-0.12.4+bzr494 sudo python setup.py install cd .. ## Install Gitian git clone https://github.com/devrandom/gitian-builder.git cd gitian-builder git config --global user.email "vagrant@vagrant.com" git config --global user.name "vagrant" chown -R ${BUILDUSER}:${BUILDUSER} /home/${BUILDUSER} echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo "!!! Provisioning Complete !!!!" echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo echo "As the user ${BUILDUSER} run the following commands to produce a linux build:" echo "export COMMIT=v0.18.3" echo "export URL=https://github.com/Bitcoin-ABC/bitcoin-abc.git" echo "cd gitian-builder" echo './bin/make-base-vm --lxc --distro debian --suite stretch --arch amd64' echo './bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} /vagrant/contrib/gitian-descriptors/gitian-linux.yml' diff --git a/contrib/init/bitcoind.init b/contrib/init/bitcoind.init index db5061874b..0c95baf3a1 100644 --- a/contrib/init/bitcoind.init +++ b/contrib/init/bitcoind.init @@ -1,67 +1,67 @@ -#!/bin/bash +#!/usr/bin/env bash # # bitcoind The bitcoin core server. # # # chkconfig: 345 80 20 # description: bitcoind # processname: bitcoind # # Source function library. . /etc/init.d/functions # you can override defaults in /etc/sysconfig/bitcoind, see below if [ -f /etc/sysconfig/bitcoind ]; then . /etc/sysconfig/bitcoind fi RETVAL=0 prog=bitcoind # you can override the lockfile via BITCOIND_LOCKFILE in /etc/sysconfig/bitcoind lockfile=${BITCOIND_LOCKFILE-/var/lock/subsys/bitcoind} # bitcoind defaults to /usr/bin/bitcoind, override with BITCOIND_BIN bitcoind=${BITCOIND_BIN-/usr/bin/bitcoind} # bitcoind opts default to -disablewallet, override with BITCOIND_OPTS bitcoind_opts=${BITCOIND_OPTS--disablewallet} start() { echo -n $"Starting $prog: " daemon $DAEMONOPTS $bitcoind $bitcoind_opts RETVAL=$? echo [ $RETVAL -eq 0 ] && touch $lockfile return $RETVAL } stop() { echo -n $"Stopping $prog: " killproc $prog RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f $lockfile return $RETVAL } case "$1" in start) start ;; stop) stop ;; status) status $prog ;; restart) stop start ;; *) echo "Usage: service $prog {start|stop|status|restart}" exit 1 ;; esac diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh index ff9fbd58df..956cd2aa35 100755 --- a/contrib/macdeploy/extract-osx-sdk.sh +++ b/contrib/macdeploy/extract-osx-sdk.sh @@ -1,33 +1,33 @@ -#!/bin/bash +#!/usr/bin/env 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.11.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/qos/tc.sh b/contrib/qos/tc.sh index 0d1dd65b4f..f3e64ca826 100644 --- a/contrib/qos/tc.sh +++ b/contrib/qos/tc.sh @@ -1,59 +1,61 @@ +#!/usr/bin/env bash +# # Copyright (c) 2017 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. #network interface on which to limit traffic IF="eth0" #limit of the network interface in question LINKCEIL="1gbit" #limit outbound Bitcoin protocol traffic to this rate LIMIT="160kbit" #defines the IPv4 address space for which you wish to disable rate limiting LOCALNET_V4="192.168.0.0/16" #defines the IPv6 address space for which you wish to disable rate limiting LOCALNET_V6="fe80::/10" #delete existing rules tc qdisc del dev ${IF} root #add root class tc qdisc add dev ${IF} root handle 1: htb default 10 #add parent class tc class add dev ${IF} parent 1: classid 1:1 htb rate ${LINKCEIL} ceil ${LINKCEIL} #add our two classes. one unlimited, another limited tc class add dev ${IF} parent 1:1 classid 1:10 htb rate ${LINKCEIL} ceil ${LINKCEIL} prio 0 tc class add dev ${IF} parent 1:1 classid 1:11 htb rate ${LIMIT} ceil ${LIMIT} prio 1 #add handles to our classes so packets marked with go into the class with "... handle fw ..." tc filter add dev ${IF} parent 1: protocol ip prio 1 handle 1 fw classid 1:10 tc filter add dev ${IF} parent 1: protocol ip prio 2 handle 2 fw classid 1:11 if [ ! -z "${LOCALNET_V6}" ] ; then # v6 cannot have the same priority value as v4 tc filter add dev ${IF} parent 1: protocol ipv6 prio 3 handle 1 fw classid 1:10 tc filter add dev ${IF} parent 1: protocol ipv6 prio 4 handle 2 fw classid 1:11 fi #delete any existing rules #disable for now #ret=0 #while [ $ret -eq 0 ]; do # iptables -t mangle -D OUTPUT 1 # ret=$? #done #limit outgoing traffic to and from port 8333. but not when dealing with a host on the local network # (defined by $LOCALNET_V4 and $LOCALNET_V6) # --set-mark marks packages matching these criteria with the number "2" (v4) # --set-mark marks packages matching these criteria with the number "4" (v6) # these packets are filtered by the tc filter with "handle 2" # this filter sends the packages into the 1:11 class, and this class is limited to ${LIMIT} iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 8333 ! -d ${LOCALNET_V4} -j MARK --set-mark 0x2 iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 8333 ! -d ${LOCALNET_V4} -j MARK --set-mark 0x2 if [ ! -z "${LOCALNET_V6}" ] ; then ip6tables -t mangle -A OUTPUT -p tcp -m tcp --dport 8333 ! -d ${LOCALNET_V6} -j MARK --set-mark 0x4 ip6tables -t mangle -A OUTPUT -p tcp -m tcp --sport 8333 ! -d ${LOCALNET_V6} -j MARK --set-mark 0x4 fi diff --git a/contrib/teamcity/build-configurations.sh b/contrib/teamcity/build-configurations.sh index dff8062736..5b4a1a43f8 100755 --- a/contrib/teamcity/build-configurations.sh +++ b/contrib/teamcity/build-configurations.sh @@ -1,40 +1,40 @@ -#!/bin/bash +#!/usr/bin/env bash set -e if [ -z "$ABC_BUILD_NAME" ]; then echo "Error: Environment variable ABC_BUILD_NAME must be set" exit 1 fi echo "Running build configuration '${ABC_BUILD_NAME}'..." TOPLEVEL=`git rev-parse --show-toplevel` cd "${TOPLEVEL}/contrib/teamcity" case "$ABC_BUILD_NAME" in build-asan) export CONFIGURE_FLAGS="--enable-debug --with-sanitizers=address --disable-ccache" ./build.sh ;; build-ubsan) export CONFIGURE_FLAGS="--enable-debug --with-sanitizers=undefined --disable-ccache CC=clang CXX=clang++" ./build.sh ;; build-default) ./build.sh ./build-secp256k1.sh ;; build-without-wallet) export DISABLE_WALLET=1 ./build.sh ;; *) echo "Error: Invalid build name '${ABC_BUILD_NAME}'" exit 2 ;; esac diff --git a/contrib/teamcity/build-secp256k1.sh b/contrib/teamcity/build-secp256k1.sh index 3f997d15f0..df2c4f9549 100755 --- a/contrib/teamcity/build-secp256k1.sh +++ b/contrib/teamcity/build-secp256k1.sh @@ -1,31 +1,31 @@ -#!/bin/bash +#!/usr/bin/env bash set -eu TOPLEVEL=`git rev-parse --show-toplevel` if [[ -z "${TOPLEVEL}" ]]; then echo "No .git directory found, assuming pwd" TOPLEVEL=`pwd -P` fi SECP_DIR="${TOPLEVEL}/src/secp256k1" # Generate necessary autoconf files cd ${SECP_DIR} ./autogen.sh # Setup build directory BUILD_DIR="${SECP_DIR}/build" mkdir -p ${BUILD_DIR} cd ${BUILD_DIR} # Determine the number of build threads THREADS=$(nproc || sysctl -n hw.ncpu) ../configure --enable-jni --enable-experimental --enable-module-ecdh # Run build make -j ${THREADS} # Run Java tests make check-java diff --git a/contrib/teamcity/build.sh b/contrib/teamcity/build.sh index dcf50897ab..f29ad29705 100755 --- a/contrib/teamcity/build.sh +++ b/contrib/teamcity/build.sh @@ -1,88 +1,88 @@ -#!/bin/bash +#!/usr/bin/env bash set -eu TOPLEVEL=`git rev-parse --show-toplevel` if [[ -z "${TOPLEVEL}" ]]; then echo "No .git directory found, assuming pwd" TOPLEVEL=`pwd -P` fi BUILD_DIR="${TOPLEVEL}/build" mkdir -p ${BUILD_DIR} ## Generate necessary autoconf files cd ${TOPLEVEL} ./autogen.sh cd ${BUILD_DIR} rm -f build.status test_bitcoin.xml ## Determine the number of build threads THREADS=$(nproc || sysctl -n hw.ncpu) # Default to nothing : ${DISABLE_WALLET:=} : ${CONFIGURE_FLAGS:=} CONFIGURE_FLAGS=($CONFIGURE_FLAGS "--prefix=`pwd`") if [[ ! -z "${DISABLE_WALLET}" ]]; then echo "*** Building without wallet" CONFIGURE_FLAGS+=("--disable-wallet") fi ../configure "${CONFIGURE_FLAGS[@]}" # Base directories for sanitizer related files SAN_SUPP_DIR="${TOPLEVEL}/test/sanitizer_suppressions" SAN_LOG_DIR="${BUILD_DIR}/sanitizer_logs" # Create the log directory if it doesn't exist and clear it mkdir -p "${SAN_LOG_DIR}" rm -rf "${SAN_LOG_DIR:?}"/* # Sanitizers options, not used if sanitizers are not enabled export ASAN_OPTIONS="malloc_context_size=0:log_path=${SAN_LOG_DIR}/asan.log" export LSAN_OPTIONS="suppressions=${SAN_SUPP_DIR}/lsan:log_path=${SAN_LOG_DIR}/lsan.log" export TSAN_OPTIONS="suppressions=${SAN_SUPP_DIR}/tsan:log_path=${SAN_LOG_DIR}/tsan.log" export UBSAN_OPTIONS="suppressions=${SAN_SUPP_DIR}/ubsan:print_stacktrace=1:halt_on_error=1:log_path=${SAN_LOG_DIR}/ubsan.log" function print_sanitizers_log() { for log in "${SAN_LOG_DIR}"/*.log.* do echo "*** Output of ${log} ***" cat "${log}" done } # Run build make -j ${THREADS} # Default to nothing : ${DISABLE_TESTS:=} # If DISABLE_TESTS is unset (default), run the tests if [[ -z "${DISABLE_TESTS}" ]]; then echo "*** Running tests" # Run unit tests make -j ${THREADS} check || (print_sanitizers_log && exit 1) mkdir -p output/ BRANCH=$(git rev-parse --abbrev-ref HEAD) JUNIT_DEFAULT="junit_results_default.xml" JUNIT_NEXT_UPGRADE="junit_results_next_upgrade.xml" if [[ ! -z "${DISABLE_WALLET}" ]]; then echo "Skipping rpc testing due to disabled wallet functionality." elif [[ "${BRANCH}" == "master" ]]; then ./test/functional/test_runner.py -J="${JUNIT_DEFAULT}" --cutoff=600 --tmpdirprefix=output ./test/functional/test_runner.py -J="${JUNIT_NEXT_UPGRADE}" --cutoff=600 --tmpdirprefix=output --with-gravitonactivation else ./test/functional/test_runner.py -J="${JUNIT_DEFAULT}" --tmpdirprefix=output ./test/functional/test_runner.py -J="${JUNIT_NEXT_UPGRADE}" --tmpdirprefix=output --with-gravitonactivation fi else echo "*** Tests have been skipped" fi diff --git a/contrib/teamcity/buildAgent-autostart b/contrib/teamcity/buildAgent-autostart index 52f46c1894..6eb7972aaa 100644 --- a/contrib/teamcity/buildAgent-autostart +++ b/contrib/teamcity/buildAgent-autostart @@ -1,32 +1,32 @@ -#!/bin/sh +#!/usr/bin/env bash ### BEGIN INIT INFO # Provides: TeamCity Build Agent # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start build agent daemon at boot time # Description: Enable service provided by daemon. ### END INIT INFO #Provide the correct user name: USER="teamcity" AGENT_PATH="~/buildAgent/bin" case "$1" in start) su - $USER -c "cd ${AGENT_PATH} ; ./agent.sh start" ;; stop) su - $USER -c "cd ${AGENT_PATH} ; ./agent.sh stop" ;; status) su - $USER -c "cd ${AGENT_PATH} ; ./agent.sh status" ;; *) echo "usage start/stop" exit 1 ;; esac exit 0 diff --git a/contrib/teamcity/gitian.sh b/contrib/teamcity/gitian.sh index f35d10dac7..e478aaee16 100755 --- a/contrib/teamcity/gitian.sh +++ b/contrib/teamcity/gitian.sh @@ -1,33 +1,35 @@ -#!/bin/bash -e +#!/usr/bin/env bash + +set -e cd "$(dirname "$0")" COMMIT=`git rev-parse HEAD` export COMMIT PROJECT_ROOT=`git rev-parse --show-toplevel` export PROJECT_ROOT export USE_LXC=1 export GITIAN_HOST_IP=10.0.3.1 export LXC_BRIDGE=lxcbr0 export LXC_GUEST_IP=10.0.3.5 cd ~/gitian-builder if [[ "${OS_NAME}" == "osx" ]]; then wget https://storage.googleapis.com/f4936e83b2dcbca742be51fb9692b153/MacOSX10.11.sdk.tar.gz echo "4732b52b5ebe300c8c91cbeed6d19d59c1ff9c56c7a1dd6cfa518b9c2c72abde MacOSX10.11.sdk.tar.gz" | sha256sum -c mkdir -p inputs echo "Downloaded" mv MacOSX10.11.sdk.tar.gz inputs fi ## Determine the number of build threads THREADS=$(nproc || sysctl -n hw.ncpu) ./bin/gbuild -j${THREADS} -m3500 --commit bitcoin=${COMMIT} --url bitcoin="${PROJECT_ROOT}" "${PROJECT_ROOT}/contrib/gitian-descriptors/gitian-${OS_NAME}.yml" RESULT_DIR="${PROJECT_ROOT}/gitian-results/${OS_NAME}" mkdir -p "${RESULT_DIR}" mv var/build.log "${PROJECT_ROOT}/gitian-results/" mv result/*.yml "${RESULT_DIR}/" mv build/out/* "${RESULT_DIR}/" diff --git a/contrib/teamcity/ibd.sh b/contrib/teamcity/ibd.sh index b95c041291..ddf0317845 100755 --- a/contrib/teamcity/ibd.sh +++ b/contrib/teamcity/ibd.sh @@ -1,74 +1,74 @@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail ### # Initial Block Download script. # # Runs a bitcoind process until initial block download is complete. # Forwards the exit code from bitcoind onward. ### MYPID=$$ # Setup DATA_DIR="ibd" mkdir -p "${DATA_DIR}" DEBUG_LOG="${DATA_DIR}/debug.log" touch "${DEBUG_LOG}" chmod +x bitcoind # Launch bitcoind using this script's parameters ./bitcoind "-datadir=${DATA_DIR}" $* & BITCOIND_PID=$! cleanup() { # Cleanup background processes spawned by this script. pkill -P ${MYPID} tail || true } trap "cleanup" EXIT # Show some progress tail -f "${DEBUG_LOG}" | grep 'UpdateTip' | awk 'NR % 10000 == 0' & # Wait for IBD to finish and kill the daemon ( ( # Ignore the broken pipe when tail tries to write pipe closed by grep set +o pipefail tail -f "${DEBUG_LOG}" | grep -m 1 'progress=1.000000' ) echo "Initial block download complete." # TODO Add more checks to see if IBD completed as expected, # These checks will exit the subshell with a non-zero exit code. ) & IBD_PID=$! # When the IBD subshell finishes, kill bitcoind ( while [ -e /proc/${IBD_PID} ]; do sleep 0.1; done echo "Cleaning up bitcoin daemon (PID: ${BITCOIND_PID})." kill ${BITCOIND_PID} ) & # Wait for bitcoind to exit, whether it exited on its own or IBD finished wait ${BITCOIND_PID} BITCOIND_EXIT_CODE=$? if [ "${BITCOIND_EXIT_CODE}" -ne "0" ]; then echo "bitcoind exited unexpectedly with code: ${BITCOIND_EXIT_CODE}" exit ${BITCOIND_EXIT_CODE} fi # Get the exit code for the IBD subshell, which should have exited already wait ${IBD_PID} IBD_EXIT_CODE=$? # The IBD subshell should only exit with a non-zero code if one of the tests # failed. if [ "${IBD_EXIT_CODE}" -ne "0" ]; then echo "IBD tests failed with code: ${IBD_EXIT_CODE}" exit ${IBD_EXIT_CODE} fi diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh index df68ba433d..95f714d34a 100755 --- a/contrib/verifybinaries/verify.sh +++ b/contrib/verifybinaries/verify.sh @@ -1,125 +1,125 @@ -#!/bin/bash +#!/usr/bin/env 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. ### This script attempts to download the signature file SHA256SUMS.asc from bitcoin.org ### It first checks if the signature passes, and then downloads the files specified in ### the file, and checks if the hashes of these files match those that are specified ### in the signature file. ### The script returns 0 if everything passes the checks. It returns 1 if either the ### signature check or the hash check doesn't pass. If an error occurs the return value is 2 function clean_up { for file in $* do rm "$file" 2> /dev/null done } WORKINGDIR="/tmp/bitcoin_verify_binaries" TMPFILE="hashes.tmp" SIGNATUREFILENAME="SHA256SUMS.asc" RCSUBDIR="test" BASEDIR="https://bitcoin.org/bin/" VERSIONPREFIX="bitcoin-core-" RCVERSIONSTRING="rc" if [ ! -d "$WORKINGDIR" ]; then mkdir "$WORKINGDIR" fi cd "$WORKINGDIR" || exit 1 #test if a version number has been passed as an argument if [ -n "$1" ]; then #let's also check if the version number includes the prefix 'bitcoin-', # and add this prefix if it doesn't if [[ $1 == "$VERSIONPREFIX"* ]]; then VERSION="$1" else VERSION="$VERSIONPREFIX$1" fi #now let's see if the version string contains "rc", and strip it off if it does # and simultaneously add RCSUBDIR to BASEDIR, where we will look for SIGNATUREFILENAME if [[ $VERSION == *"$RCVERSIONSTRING"* ]]; then BASEDIR="$BASEDIR${VERSION/%-$RCVERSIONSTRING*}/" BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSIONSTRING${VERSION: -1}/" else BASEDIR="$BASEDIR$VERSION/" fi else echo "Error: need to specify a version on the command line" exit 2 fi #first we fetch the file containing the signature WGETOUT=$(wget -N "$BASEDIR$SIGNATUREFILENAME" 2>&1) #and then see if wget completed successfully if [ $? -ne 0 ]; then echo "Error: couldn't fetch signature file. Have you specified the version number in the following format?" echo "[$VERSIONPREFIX]-[$RCVERSIONSTRING[0-9]] (example: ${VERSIONPREFIX}0.10.4-${RCVERSIONSTRING}1)" echo "wget output:" echo "$WGETOUT"|sed 's/^/\t/g' exit 2 fi #then we check it GPGOUT=$(gpg --yes --decrypt --output "$TMPFILE" "$SIGNATUREFILENAME" 2>&1) #return value 0: good signature #return value 1: bad signature #return value 2: gpg error RET="$?" if [ $RET -ne 0 ]; then if [ $RET -eq 1 ]; then #and notify the user if it's bad echo "Bad signature." elif [ $RET -eq 2 ]; then #or if a gpg error has occurred echo "gpg error. Do you have the Bitcoin Core binary release signing key installed?" fi echo "gpg output:" echo "$GPGOUT"|sed 's/^/\t/g' clean_up $SIGNATUREFILENAME $TMPFILE exit "$RET" fi #here we extract the filenames from the signature file FILES=$(awk '{print $2}' "$TMPFILE") #and download these one by one for file in $FILES do wget --quiet -N "$BASEDIR$file" done #check hashes DIFF=$(diff <(sha256sum $FILES) "$TMPFILE") if [ $? -eq 1 ]; then echo "Hashes don't match." echo "Offending files:" echo "$DIFF"|grep "^<"|awk '{print "\t"$3}' exit 1 elif [ $? -gt 1 ]; then echo "Error executing 'diff'" exit 2 fi if [ -n "$2" ]; then echo "Clean up the binaries" clean_up $FILES $SIGNATUREFILENAME $TMPFILE else echo "Keep the binaries in $WORKINGDIR" clean_up $TMPFILE fi echo -e "Verified hashes of \n$FILES" exit 0 diff --git a/doc/developer-notes.md b/doc/developer-notes.md index dfd499c6c0..17668ca9d9 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -1,842 +1,860 @@ Developer Notes =============== **Table of Contents** - [Developer Notes](#developer-notes) - [Coding Style](#coding-style) - [Doxygen comments](#doxygen-comments) - [Development tips and tricks](#development-tips-and-tricks) - [Compiling for debugging](#compiling-for-debugging) - [Compiling for gprof profiling](#compiling-for-gprof-profiling) - [debug.log](#debuglog) - [Writing tests](#writing-tests) - [Writing script integration tests](#writing-script-integration-tests) - [Testnet and Regtest modes](#testnet-and-regtest-modes) - [DEBUG_LOCKORDER](#debug_lockorder) - [Valgrind suppressions file](#valgrind-suppressions-file) - [Compiling for test coverage](#compiling-for-test-coverage) - [Sanitizers](#sanitizers) - [Locking/mutex usage notes](#lockingmutex-usage-notes) - [Threads](#threads) - [Ignoring IDE/editor files](#ignoring-ideeditor-files) - [Development guidelines](#development-guidelines) - [Wallet](#wallet) - [General C++](#general-c) - [C++ data structures](#c-data-structures) - [Strings and formatting](#strings-and-formatting) - [Variable names](#variable-names) - [Threads and synchronization](#threads-and-synchronization) + - [Scripts](#scripts) + - [Shebang](#shebang) - [Source code organization](#source-code-organization) - [GUI](#gui) - [Unit tests](#unit-tests) - [Subtrees](#subtrees) - [Git and GitHub tips](#git-and-github-tips) - [RPC interface guidelines](#rpc-interface-guidelines) Coding Style --------------- Various coding styles have been used during the history of the codebase, and the result is not very consistent. However, we're now trying to converge to a single style, so please use it in new code. Old code will be converted gradually and you are encouraged to use the provided [clang-format-diff script](/contrib/devtools/README.md#clang-format-diffpy) to clean up the patch automatically before submitting a pull request. - Basic rules specified in [src/.clang-format](/src/.clang-format). - Braces on new lines for namespaces, classes, functions, methods. - Braces on the same line for everything else. - 4 space indentation (no tabs) for every block except namespaces. - No indentation for `public`/`protected`/`private` or for `namespace`. - No extra spaces inside parenthesis; don't do ( this ) - No space after function names; one space after `if`, `for` and `while`. - Always add braces for block statements (e.g. `if`, `for`, `while`). - `++i` is preferred over `i++`. - `static_assert` is preferred over `assert` where possible. Generally; compile-time checking is preferred over run-time checking. - Use CamelCase for functions/methods, and lowerCamelCase for variables. - GLOBAL_CONSTANTS should use UPPER_SNAKE_CASE. - namespaces should use lower_snake_case. - Function names should generally start with an English command-form verb (e.g. `ValidateTransaction`, `AddTransactionToMempool`, `ConnectBlock`) - Variable names should generally be nouns or past/future tense verbs. (e.g. `canDoThing`, `signatureOperations`, `didThing`) - Avoid using globals, remove existing globals whenever possible. - Class member variable names should be prepended with `m_` - DO choose easily readable identifier names. - DO favor readability over brevity. - DO NOT use Hungarian notation. - DO NOT use abbreviations or contractions within identifiers. - WRONG: mempool - RIGHT: MemoryPool - WRONG: ChangeDir - RIGHT: ChangeDirectory - DO NOT use obscure acronyms, DO uppercase any acronyms. - FINALLY, do not migrate existing code unless refactoring. It makes forwarding-porting from Bitcoin Core more difficult. The naming convention roughly mirrors [Microsoft Naming Conventions](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/general-naming-conventions) C++ Coding Standards should strive to follow the [LLVM Coding Standards](https://llvm.org/docs/CodingStandards.html) Code style example: ```c++ // namespaces should be lower_snake_case namespace foo_bar_bob { /** * Class is used for doing classy things. All classes should * have a doxygen comment describing their PURPOSE. That is to say, * why they exist. Functional details can be determined from the code. * @see PerformTask() */ class Class { private: //! memberVariable's name should be lowerCamelCase, and be a noun. int m_memberVariable; public: /** * The documentation before a function or class method should follow Doxygen * spec. The name of the function should start with an english verb which * indicates the intended purpose of this code. * * The function name should be should be CamelCase. * * @param[in] s A description * @param[in] n Another argument description * @pre Precondition for function... */ bool PerformTask(const std::string& s, int n) { // Use lowerChamelCase for local variables. bool didMore = false; // Comment summarizing the intended purpose of this section of code for (int i = 0; i < n; ++i) { if (!DidSomethingFail()) { return false; } ... if (IsSomethingElse()) { DoMore(); didMore = true; } else { DoLess(); } } return didMore; } } } // namespace foo ``` Doxygen comments ----------------- To facilitate the generation of documentation, use doxygen-compatible comment blocks for functions, methods and fields. For example, to describe a function use: ```c++ /** * ... text ... * @param[in] arg1 A description * @param[in] arg2 Another argument description * @pre Precondition for function... */ bool function(int arg1, const char *arg2) ``` A complete list of `@xxx` commands can be found at http://www.stack.nl/~dimitri/doxygen/manual/commands.html. As Doxygen recognizes the comments by the delimiters (`/**` and `*/` in this case), you don't *need* to provide any commands for a comment to be valid; just a description text is fine. To describe a class use the same construct above the class definition: ```c++ /** * Alerts are for notifying old versions if they become too obsolete and * need to upgrade. The message is displayed in the status bar. * @see GetWarnings() */ class CAlert { ``` To describe a member or variable use: ```c++ int var; //!< Detailed description after the member ``` or ```cpp //! Description before the member int var; ``` Also OK: ```c++ /// /// ... text ... /// bool function2(int arg1, const char *arg2) ``` Not OK (used plenty in the current source, but not picked up): ```c++ // // ... text ... // ``` A full list of comment syntaxes picked up by doxygen can be found at http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html, but if possible use one of the above styles. To build doxygen locally to test changes to the Doxyfile or visualize your comments before landing changes: ``` # In the build directory, call: doxygen doc/Doxyfile # output goes to doc/doxygen/html/ ``` Development tips and tricks --------------------------- ### Compiling for debugging Run configure with `--enable-debug` to add additional compiler flags that produce better debugging builds. ### Compiling for gprof profiling Run configure with the `--enable-gprof` option, then make. ### debug.log If the code is behaving strangely, take a look in the debug.log file in the data directory; error and debugging messages are written there. The `-debug=...` command-line option controls debugging; running with just `-debug` or `-debug=1` will turn on all categories (and give you a very large debug.log file). The Qt code routes `qDebug()` output to debug.log under category "qt": run with `-debug=qt` to see it. ### Writing tests For details on unit tests, see `unit-tests.md` For details on functional tests, see `functional-tests.md` ### Writing script integration tests Script integration tests are built using `src/test/script_tests.cpp`: 1. Uncomment the line with `#define UPDATE_JSON_TESTS` 2. Add a new TestBuilder to the `script_build` test to cover your test case. 3. `make && ./src/test/test_bitcoin --run_test=script_tests` 4. Copy your newly generated test JSON from `/src/script_tests.json.gen` to `src/test/data/script_tests.json`. Please commit your TestBuilder along with your generated test JSON and cleanup the uncommented #define before code review. ### Testnet and Regtest modes Run with the `-testnet` option to run with "play bitcoins" on the test network, if you are testing multi-machine code that needs to operate across the internet. If you are testing something that can run on one machine, run with the `-regtest` option. In regression test mode, blocks can be created on-demand; see [test/functional/](/test/functional) for tests that run in `-regtest` mode. ### DEBUG_LOCKORDER Bitcoin ABC is a multi-threaded application, and deadlocks or other multi-threading bugs can be very difficult to track down. The `--enable-debug` configure option adds `-DDEBUG_LOCKORDER` to the compiler flags. This inserts run-time checks to keep track of which locks are held, and adds warnings to the debug.log file if inconsistencies are detected. ### Valgrind suppressions file Valgrind is a programming tool for memory debugging, memory leak detection, and profiling. The repo contains a Valgrind suppressions file ([`valgrind.supp`](contrib/valgrind.supp)) which includes known Valgrind warnings in our dependencies that cannot be fixed in-tree. Example use: ```shell $ valgrind --suppressions=contrib/valgrind.supp src/test/test_bitcoin $ valgrind --suppressions=contrib/valgrind.supp --leak-check=full \ --show-leak-kinds=all src/test/test_bitcoin --log_level=test_suite $ valgrind -v --leak-check=full src/bitcoind -printtoconsole ``` ### Compiling for test coverage LCOV can be used to generate a test coverage report based upon `make check` execution. LCOV must be installed on your system (e.g. the `lcov` package on Debian/Ubuntu). To enable LCOV report generation during test runs: ```shell ./configure --enable-lcov make make cov # A coverage report will now be accessible at `./test_bitcoin.coverage/index.html`. ``` ### Sanitizers Bitcoin ABC can be compiled with various "sanitizers" enabled, which add instrumentation for issues regarding things like memory safety, thread race conditions, or undefined behavior. This is controlled with the `--with-sanitizers` configure flag, which should be a comma separated list of sanitizers to enable. The sanitizer list should correspond to supported `-fsanitize=` options in your compiler. These sanitizers have runtime overhead, so they are most useful when testing changes or producing debugging builds. Some examples: ```bash # Enable both the address sanitizer and the undefined behavior sanitizer ./configure --with-sanitizers=address,undefined # Enable the thread sanitizer ./configure --with-sanitizers=thread ``` If you are compiling with GCC you will typically need to install corresponding "san" libraries to actually compile with these flags, e.g. libasan for the address sanitizer, libtsan for the thread sanitizer, and libubsan for the undefined sanitizer. If you are missing required libraries, the configure script will fail with a linker error when testing the sanitizer flags. The test suite should pass cleanly with the `thread` and `undefined` sanitizers, but there are a number of known problems when using the `address` sanitizer. The address sanitizer is known to fail in [sha256_sse4::Transform](/src/crypto/sha256_sse4.cpp) which makes it unusable unless you also use `--disable-asm` when running configure. We would like to fix sanitizer issues, so please send pull requests if you can fix any errors found by the address sanitizer (or any other sanitizer). Not all sanitizer options can be enabled at the same time, e.g. trying to build with `--with-sanitizers=address,thread` will fail in the configure script as these sanitizers are mutually incompatible. Refer to your compiler manual to learn more about these options and which sanitizers are supported by your compiler. Additional resources: * [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) * [LeakSanitizer](https://clang.llvm.org/docs/LeakSanitizer.html) * [MemorySanitizer](https://clang.llvm.org/docs/MemorySanitizer.html) * [ThreadSanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html) * [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) * [GCC Instrumentation Options](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html) * [Google Sanitizers Wiki](https://github.com/google/sanitizers/wiki) * [Issue #12691: Enable -fsanitize flags in Travis](https://github.com/bitcoin/bitcoin/issues/12691) Locking/mutex usage notes ------------------------- The code is multi-threaded, and uses mutexes and the `LOCK` and `TRY_LOCK` macros to protect data structures. Deadlocks due to inconsistent lock ordering (thread 1 locks `cs_main` and then `cs_wallet`, while thread 2 locks them in the opposite order: result, deadlock as each waits for the other to release its lock) are a problem. Compile with `-DDEBUG_LOCKORDER` (or use `--enable-debug`) to get lock order inconsistencies reported in the debug.log file. Re-architecting the core code so there are better-defined interfaces between the various components is a goal, with any necessary locking done by the components (e.g. see the self-contained `CBasicKeyStore` class and its `cs_KeyStore` lock for example). Threads ------- - ThreadScriptCheck : Verifies block scripts. - ThreadImport : Loads blocks from blk*.dat files or bootstrap.dat. - StartNode : Starts other threads. - ThreadDNSAddressSeed : Loads addresses of peers from the DNS. - ThreadMapPort : Universal plug-and-play startup/shutdown - ThreadSocketHandler : Sends/Receives data from peers on port 8333. - ThreadOpenAddedConnections : Opens network connections to added nodes. - ThreadOpenConnections : Initiates new connections to peers. - ThreadMessageHandler : Higher-level message handling (sending and receiving). - DumpAddresses : Dumps IP addresses of nodes to peers.dat. - ThreadRPCServer : Remote procedure call handler, listens on port 8332 for connections and services them. - Shutdown : Does an orderly shutdown of everything. Ignoring IDE/editor files -------------------------- In closed-source environments in which everyone uses the same IDE it is common to add temporary files it produces to the project-wide `.gitignore` file. However, in open source software such as Bitcoin Core, where everyone uses their own editors/IDE/tools, it is less common. Only you know what files your editor produces and this may change from version to version. The canonical way to do this is thus to create your local gitignore. Add this to `~/.gitconfig`: ``` [core] excludesfile = /home/.../.gitignore_global ``` (alternatively, type the command `git config --global core.excludesfile ~/.gitignore_global` on a terminal) Then put your favourite tool's temporary filenames in that file, e.g. ``` # NetBeans nbproject/ ``` Another option is to create a per-repository excludes file `.git/info/exclude`. These are not committed but apply only to one repository. If a set of tools is used by the build system or scripts the repository (for example, lcov) it is perfectly acceptable to add its files to `.gitignore` and commit them. Development guidelines ============================ A few non-style-related recommendations for developers, as well as points to pay attention to for reviewers of Bitcoin Core code. Wallet ------- - Make sure that no crashes happen with run-time option `-disablewallet`. - *Rationale*: In RPC code that conditionally uses the wallet (such as `validateaddress`) it is easy to forget that global pointer `pwalletMain` can be NULL. See `test/functional/disablewallet.py` for functional tests exercising the API with `-disablewallet` - Include `db_cxx.h` (BerkeleyDB header) only when `ENABLE_WALLET` is set - *Rationale*: Otherwise compilation of the disable-wallet build will fail in environments without BerkeleyDB General C++ ------------- - Assertions should not have side-effects - *Rationale*: Even though the source code is set to refuse to compile with assertions disabled, having side-effects in assertions is unexpected and makes the code harder to understand - If you use the `.h`, you must link the `.cpp` - *Rationale*: Include files define the interface for the code in implementation files. Including one but not linking the other is confusing. Please avoid that. Moving functions from the `.h` to the `.cpp` should not result in build errors - Use the RAII (Resource Acquisition Is Initialization) paradigm where possible. For example by using `unique_ptr` for allocations in a function. - *Rationale*: This avoids memory and resource leaks, and ensures exception safety C++ data structures -------------------- - Never use the `std::map []` syntax when reading from a map, but instead use `.find()` - *Rationale*: `[]` does an insert (of the default element) if the item doesn't exist in the map yet. This has resulted in memory leaks in the past, as well as race conditions (expecting read-read behavior). Using `[]` is fine for *writing* to a map - Do not compare an iterator from one data structure with an iterator of another data structure (even if of the same type) - *Rationale*: Behavior is undefined. In C++ parlor this means "may reformat the universe", in practice this has resulted in at least one hard-to-debug crash bug - Watch out for out-of-bounds vector access. `&vch[vch.size()]` is illegal, including `&vch[0]` for an empty vector. Use `vch.data()` and `vch.data() + vch.size()` instead. - Vector bounds checking is only enabled in debug mode. Do not rely on it - Make sure that constructors initialize all fields. If this is skipped for a good reason (i.e., optimization on the critical path), add an explicit comment about this - *Rationale*: Ensure determinism by avoiding accidental use of uninitialized values. Also, static analyzers balk about this. - Use explicitly signed or unsigned `char`s, or even better `uint8_t` and `int8_t`. Do not use bare `char` unless it is to pass to a third-party API. This type can be signed or unsigned depending on the architecture, which can lead to interoperability problems or dangerous conditions such as out-of-bounds array accesses - Prefer explicit constructions over implicit ones that rely on 'magical' C++ behavior - *Rationale*: Easier to understand what is happening, thus easier to spot mistakes, even for those that are not language lawyers - Initialize all non-static class members where they are defined - *Rationale*: Initializing the members in the declaration makes it easy to spot uninitialized ones, and avoids accidentally reading uninitialized memory ```cpp class A { uint32_t m_count{0}; } ``` Strings and formatting ------------------------ - Use `std::string`, avoid C string manipulation functions - *Rationale*: C++ string handling is marginally safer, less scope for buffer overflows and surprises with `\0` characters. Also some C string manipulations tend to act differently depending on platform, or even the user locale - Use `ParseInt32`, `ParseInt64`, `ParseUInt32`, `ParseUInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing - *Rationale*: These functions do overflow checking, and avoid pesky locale issues Variable names -------------- The shadowing warning (`-Wshadow`) is enabled by default. It prevents issues rising from using a different variable with the same name. E.g. in member initializers, prepend `_` to the argument name shadowing the member name: ```c++ class AddressBookPage { Mode m_mode; } AddressBookPage::AddressBookPage(Mode _mode) : m_mode(_mode) ... ``` When using nested cycles, do not name the inner cycle variable the same as in upper cycle etc. Please name variables so that their names do not shadow variables defined in the source code. Threads and synchronization ---------------------------- - Build and run tests with `-DDEBUG_LOCKORDER` to verify that no potential deadlocks are introduced. As of 0.12, this is defined by default when configuring with `--enable-debug` - When using `LOCK`/`TRY_LOCK` be aware that the lock exists in the context of the current scope, so surround the statement and the code that needs the lock with braces OK: ```c++ { TRY_LOCK(cs_vNodes, lockNodes); ... } ``` Wrong: ```c++ TRY_LOCK(cs_vNodes, lockNodes); { ... } ``` +Scripts +-------------------------- +### Shebang +- Use `#!/usr/bin/env bash` instead of obsolete `#!/bin/bash`. + - [*Rationale*](https://github.com/dylanaraps/pure-bash-bible#shebang): + `#!/bin/bash` assumes it is always installed to /bin/ which can cause issues; + `#!/usr/bin/env bash` searches the user's PATH to find the bash binary. + OK: +```bash +#!/usr/bin/env bash +``` + Wrong: +```bash +#!/bin/bash +``` + Source code organization -------------------------- - Implementation code should go into the `.cpp` file and not the `.h`, unless necessary due to template usage or when performance due to inlining is critical - *Rationale*: Shorter and simpler header files are easier to read, and reduce compile time - Use only the lowercase alphanumerics (`a-z0-9`), underscore (`_`) and hyphen (`-`) in source code filenames. - *Rationale*: `grep`:ing and auto-completing filenames is easier when using a consistent naming pattern. Potential problems when building on case-insensitive filesystems are avoided when using only lowercase characters in source code filenames. - Don't import anything into the global namespace (`using namespace ...`). Use fully specified types such as `std::string`. - *Rationale*: Avoids symbol conflicts - Terminate namespaces with a comment (`// namespace mynamespace`). The comment should be placed on the same line as the brace closing the namespace, e.g. ```c++ namespace mynamespace { ... } // namespace mynamespace namespace { ... } // namespace ``` - *Rationale*: Avoids confusion about the namespace context Header Inclusions ----------------- - Header inclusions should use angle brackets (`#include <>`). The include path should be relative to the `src` folder. e.g.: `#include ` - Native C++ headers should be preferred over C compatibility headers. e.g.: use `` instead of `` - In order to make the code consistent, header files should be included in the following order, with each section separated by a newline: 1. In a .cpp file, the associated .h is in first position. In a test source, this is the header file under test. 2. The project headers. 3. The test headers. 4. The 3rd party libraries headers. Different libraries should be in different sections. 5. The system libraries. All headers should be lexically ordered inside their block. - Use include guards to avoid the problem of double inclusion. The header file `foo/bar.h` should use the include guard identifier `BITCOIN_FOO_BAR_H`, e.g. ```c++ #ifndef BITCOIN_FOO_BAR_H #define BITCOIN_FOO_BAR_H ... #endif // BITCOIN_FOO_BAR_H ``` GUI ----- - Do not display or manipulate dialogs in model code (classes `*Model`) - *Rationale*: Model classes pass through events and data from the core, they should not interact with the user. That's where View classes come in. The converse also holds: try to not directly access core data structures from Views. - Avoid adding slow or blocking code in the GUI thread. In particular do not add new `interface::Node` and `interface::Wallet` method calls, even if they may be fast now, in case they are changed to lock or communicate across processes in the future. Prefer to offload work from the GUI thread to worker threads (see `RPCExecutor` in console code as an example) or take other steps (see https://doc.qt.io/archives/qq/qq27-responsive-guis.html) to keep the GUI responsive. - *Rationale*: Blocking the GUI thread can increase latency, and lead to hangs and deadlocks. Unit Tests ----------- - Test suite naming convention: The Boost test suite in file `src/test/foo_tests.cpp` should be named `foo_tests`. Test suite names must be unique. Subtrees ---------- Several parts of the repository are subtrees of software maintained elsewhere. Some of these are maintained by active developers of Bitcoin Core, in which case changes should probably go directly upstream without being PRed directly against the project. They will be merged back in the next subtree merge. Others are external projects without a tight relationship with our project. Changes to these should also be sent upstream but bugfixes may also be prudent to PR against Bitcoin Core so that they can be integrated quickly. Cosmetic changes should be purely taken upstream. There is a tool in `test/lint/git-subtree-check.sh` to check a subtree directory for consistency with its upstream repository. Current subtrees include: - src/leveldb - Upstream at https://github.com/google/leveldb ; Maintained by Google, but open important PRs to Core to avoid delay - src/libsecp256k1 - Upstream at https://github.com/bitcoin-core/secp256k1/ ; actively maintaned by Core contributors. - src/crypto/ctaes - Upstream at https://github.com/bitcoin-core/ctaes ; actively maintained by Core contributors. - src/univalue - Upstream at https://github.com/jgarzik/univalue ; report important PRs to Core to avoid delay. Git and GitHub tips --------------------- - Github is not typically the source of truth for pull requests. See CONTRIBUTING.md for instructions on setting up your repo correctly. - Similarly, your git remote origin should be set to: `ssh://vcs@reviews.bitcoinabc.org:2221/source/bitcoin-abc.git` instead of github.com. See CONTRIBUTING.md for details. - For resolving merge/rebase conflicts, it can be useful to enable diff3 style using `git config merge.conflictstyle diff3`. Instead of <<< yours === theirs >>> you will see <<< yours ||| original === theirs >>> This may make it much clearer what caused the conflict. In this style, you can often just look at what changed between *original* and *theirs*, and mechanically apply that to *yours* (or the other way around). - When reviewing patches which change indentation in C++ files, use `git diff -w` and `git show -w`. This makes the diff algorithm ignore whitespace changes. This feature is also available on github.com, by adding `?w=1` at the end of any URL which shows a diff. - When reviewing patches that change symbol names in many places, use `git diff --word-diff`. This will instead of showing the patch as deleted/added *lines*, show deleted/added *words*. - When reviewing patches that move code around, try using `git diff --patience commit~:old/file.cpp commit:new/file/name.cpp`, and ignoring everything except the moved body of code which should show up as neither `+` or `-` lines. In case it was not a pure move, this may even work when combined with the `-w` or `--word-diff` options described above. - When looking at other's pull requests, it may make sense to add the following section to your `.git/config` file: [remote "upstream-pull"] fetch = +refs/pull/*:refs/remotes/upstream-pull/* url = git@github.com:bitcoin/bitcoin.git This will add an `upstream-pull` remote to your git repository, which can be fetched using `git fetch --all` or `git fetch upstream-pull`. Afterwards, you can use `upstream-pull/NUMBER/head` in arguments to `git show`, `git checkout` and anywhere a commit id would be acceptable to see the changes from pull request NUMBER. RPC interface guidelines -------------------------- A few guidelines for introducing and reviewing new RPC interfaces: - Method naming: use consecutive lower-case names such as `getrawtransaction` and `submitblock` - *Rationale*: Consistency with existing interface. - Argument naming: use snake case `fee_delta` (and not, e.g. camel case `feeDelta`) - *Rationale*: Consistency with existing interface. - Use the JSON parser for parsing, don't manually parse integers or strings from arguments unless absolutely necessary. - *Rationale*: Introduces hand-rolled string manipulation code at both the caller and callee sites, which is error prone, and it is easy to get things such as escaping wrong. JSON already supports nested data structures, no need to re-invent the wheel. - *Exception*: AmountFromValue can parse amounts as string. This was introduced because many JSON parsers and formatters hard-code handling decimal numbers as floating point values, resulting in potential loss of precision. This is unacceptable for monetary values. **Always** use `AmountFromValue` and `ValueFromAmount` when inputting or outputting monetary values. The only exceptions to this are `prioritisetransaction` and `getblocktemplate` because their interface is specified as-is in BIP22. - Missing arguments and 'null' should be treated the same: as default values. If there is no default value, both cases should fail in the same way. The easiest way to follow this guideline is detect unspecified arguments with `params[x].isNull()` instead of `params.size() <= x`. The former returns true if the argument is either null or missing, while the latter returns true if is missing, and false if it is null. - *Rationale*: Avoids surprises when switching to name-based arguments. Missing name-based arguments are passed as 'null'. - Try not to overload methods on argument type. E.g. don't make `getblock(true)` and `getblock("hash")` do different things. - *Rationale*: This is impossible to use with `bitcoin-cli`, and can be surprising to users. - *Exception*: Some RPC calls can take both an `int` and `bool`, most notably when a bool was switched to a multi-value, or due to other historical reasons. **Always** have false map to 0 and true to 1 in this case. - Don't forget to fill in the argument names correctly in the RPC command table. - *Rationale*: If not, the call can not be used with name-based arguments. - Set okSafeMode in the RPC command table to a sensible value: safe mode is when the blockchain is regarded to be in a confused state, and the client deems it unsafe to do anything irreversible such as send. Anything that just queries should be permitted. - *Rationale*: Troubleshooting a node in safe mode is difficult if half the RPCs don't work. - Add every non-string RPC argument `(method, idx, name)` to the table `vRPCConvertParams` in `rpc/client.cpp`. - *Rationale*: `bitcoin-cli` and the GUI debug console use this table to determine how to convert a plaintext command line to JSON. If the types don't match, the method can be unusable from there. - A RPC method must either be a wallet method or a non-wallet method. Do not introduce new methods such as `signrawtransaction` that differ in behavior based on presence of a wallet. - *Rationale*: as well as complicating the implementation and interfering with the introduction of multi-wallet, wallet and non-wallet code should be separated to avoid introducing circular dependencies between code units. - Try to make the RPC response a JSON object. - *Rationale*: If a RPC response is not a JSON object then it is harder to avoid API breakage if new data in the response is needed. - Wallet RPCs call BlockUntilSyncedToCurrentChain to maintain consistency with `getblockchaininfo`'s state immediately prior to the call's execution. Wallet RPCs whose behavior does *not* depend on the current chainstate may omit this call. - *Rationale*: In previous versions of Bitcoin Core, the wallet was always in-sync with the chainstate (by virtue of them all being updated in the same cs_main lock). In order to maintain the behavior that wallet RPCs return results as of at least the highest best-known block an RPC client may be aware of prior to entering a wallet RPC call, we must block until the wallet is caught up to the chainstate as of the RPC call's entry. This also makes the API much easier for RPC clients to reason about. diff --git a/src/qt/res/movies/makespinner.sh b/src/qt/res/movies/makespinner.sh index d0deb1238c..d0413efbb9 100755 --- a/src/qt/res/movies/makespinner.sh +++ b/src/qt/res/movies/makespinner.sh @@ -1,11 +1,13 @@ +#!/usr/bin/env bash + # Copyright (c) 2014-2015 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. FRAMEDIR=$(dirname $0) for i in {0..35} do frame=$(printf "%03d" $i) angle=$(($i * 10)) convert $FRAMEDIR/../src/spinner.png -background "rgba(0,0,0,0.0)" -distort SRT $angle $FRAMEDIR/spinner-$frame.png done